shithub: zelda3

Download patch

ref: 43db8cc0f529a2b8004a684526d91582d0d6d5d7
parent: a23632ae6cec5474ec77deb6e21e08ccbf913d8f
author: Snesrev <[email protected]>
date: Wed Aug 16 22:56:21 EDT 2023

Move around files

--- a/.gitignore
+++ b/.gitignore
@@ -7,24 +7,24 @@
 *.aps
 /obj/
 /bin/
-/tables/overworld/*.yaml
-/tables/dungeon/*.yaml
-/tables/img/
-/tables/old/
-/tables/zelda3.sfc
-/tables/zelda3.smc
+/assets/overworld/*.yaml
+/assets/dungeon/*.yaml
+/assets/img/
+/assets/old/
+/zelda3.sfc
+/zelda3.smc
 /saves/*.sav
 /saves/sram.dat
 /saves/sram.bak
 /zelda3
 __pycache__
-/*.o
+/src/*.o
 /*.exe
 /*.out
 /snes/*.o
 /msu/
 /tmp/
-/tables/zelda3_assets.dat
+/zelda3_assets.dat
 /SDL2.dll
 /zelda3.*.ini
 /zelda3.wiki
--- a/Makefile
+++ b/Makefile
@@ -1,9 +1,9 @@
 TARGET_EXEC:=zelda3
 ROM:=tables/zelda3.sfc
-SRCS:=$(wildcard *.c snes/*.c) third_party/gl_core/gl_core_3_1.c third_party/opus-1.3.1-stripped/opus_decoder_amalgam.c
+SRCS:=$(wildcard src/*.c snes/*.c) third_party/gl_core/gl_core_3_1.c third_party/opus-1.3.1-stripped/opus_decoder_amalgam.c
 OBJS:=$(SRCS:%.c=%.o)
 PYTHON:=/usr/bin/env python3
-CFLAGS:=$(if $(CFLAGS),$(CFLAGS),-O2 -Werror)
+CFLAGS:=$(if $(CFLAGS),$(CFLAGS),-O2 -Werror) -I .
 CFLAGS:=${CFLAGS} $(shell sdl2-config --cflags) -DSYSTEM_VOLUME_MIXER_AVAILABLE=0
 
 ifeq (${OS},Windows_NT)
@@ -16,23 +16,23 @@
 
 .PHONY: all clean clean_obj clean_gen
 
-all: $(TARGET_EXEC) tables/zelda3_assets.dat
+all: $(TARGET_EXEC) zelda3_assets.dat
 $(TARGET_EXEC): $(OBJS) $(RES)
 	$(CC) $^ -o $@ $(LDFLAGS) $(SDLFLAGS)
 %.o : %.c
 	$(CC) -c $(CFLAGS) $< -o $@
 
-$(RES): platform/win32/zelda3.rc
+$(RES): src/platform/win32/zelda3.rc
 	@echo "Generating Windows resources"
 	@$(WINDRES) $< -O coff -o $@
 
-tables/zelda3_assets.dat:
+zelda3_assets.dat:
 	@echo "Extracting game resources"
-	@cd tables; $(PYTHON) restool.py --extract-from-rom -r ../$(ROM)
+	$(PYTHON) assets/restool.py --extract-from-rom
 
 clean: clean_obj clean_gen
 clean_obj:
 	@$(RM) $(OBJS) $(TARGET_EXEC)
 clean_gen:
-	@$(RM) $(RES) tables/zelda3_assets.dat tables/*.txt tables/*.png tables/sprites/*.png tables/*.yaml
+	@$(RM) $(RES) zelda3_assets.dat tables/zelda3_assets.dat tables/*.txt tables/*.png tables/sprites/*.png tables/*.yaml
 	@rm -rf tables/__pycache__ tables/dungeon tables/img tables/overworld tables/sound
--- a/README.md
+++ b/README.md
@@ -49,17 +49,15 @@
 ## Compiling on Windows with TCC (1mb Tiny C Compiler)
 1. Download the project by clicking "Code > Download ZIP" on the github page
 2. Extract the ZIP to your hard drive
-3. Place the USA rom named `zelda3.sfc` in the "\tables" subfolder
-4. Open the command prompt and navigate to that folder
-5. Type `python restool.py --extract-from-rom` and hit enter
-6. Close the command prompt
-7. Download [TCC](https://github.com/FitzRoyX/tinycc/releases/download/tcc_20221020/tcc_20221020.zip) and extract to the "\third_party" subfolder
-8. Download [SDL2](https://github.com/libsdl-org/SDL/releases/download/release-2.26.3/SDL2-devel-2.26.3-VC.zip) and extract to the "\third_party" subfolder
-9. Double-click `run_with_tcc.bat` in the main dir to create `zelda3.exe` in that same dir
-10. Configure with `zelda3.ini` in the main dir
+3. Place the USA rom named `zelda3.sfc` in the root directory.
+4. Double-click `extract_assets.bat` in the main dir to create `zelda3_assets.dat` in that same dir
+5. Download [TCC](https://github.com/FitzRoyX/tinycc/releases/download/tcc_20221020/tcc_20221020.zip) and extract to the "\third_party" subfolder
+6. Download [SDL2](https://github.com/libsdl-org/SDL/releases/download/release-2.26.3/SDL2-devel-2.26.3-VC.zip) and extract to the "\third_party" subfolder
+7. Double-click `run_with_tcc.bat` in the main dir to create `zelda3.exe` in that same dir
+8. Configure with `zelda3.ini` in the main dir
 
 ## Compiling on Windows with Visual Studio (4.5gb IDE and compiler)
-Same Steps 1-7 above<br/>
+Same Steps 1-4 above<br/>
 8. Double-click `Zelda3.sln`<br/>
 9. Install the **Desktop development with C++** workload with the VS Installer if you don't have it already (it should prompt you to do this).<br/>
 10. Change "debug" to "release" in the top dropdown<br/>
@@ -88,7 +86,7 @@
 * macOS: `brew install sdl2` (you can get homebrew [here](https://brew.sh/))
 
 ## Compiling on Linux/MacOS
-1. Place your US ROM file named `zelda3.sfc` in `zelda3/tables`
+1. Place your US ROM file named `zelda3.sfc` in `zelda3`
 2. Compile
 ```sh
 make
@@ -124,7 +122,7 @@
 The ROM needs to be named `zelda3.sfc` and has to be from the US region with this exact SHA256 hash
 `66871d66be19ad2c34c927d6b14cd8eb6fc3181965b6e517cb361f7316009cfb`
 
-In case you're planning to move the executable to a different location, please include the file `tables/zelda3_assets.dat`.
+In case you're planning to move the executable to a different location, please include the file `zelda3_assets.dat`.
 
 ## Usage and controls
 
--- a/ancilla.c
+++ /dev/null
@@ -1,7156 +1,0 @@
-#include "ancilla.h"
-#include "variables.h"
-#include "sprite.h"
-#include "hud.h"
-#include "load_gfx.h"
-#include "tagalong.h"
-#include "overworld.h"
-#include "tile_detect.h"
-#include "player.h"
-#include "misc.h"
-#include "dungeon.h"
-#include "sprite_main.h"
-#include "assets.h"
-
-static const uint8 kAncilla_Pflags[68] = {
-  0,    8,  0xc, 0x10, 0x10,    4, 0x10, 0x18,    8,    8,    8,    0, 0x14, 0, 0x10, 0x28,
-  0x18, 0x10, 0x10, 0x10, 0x10,  0xc,    8,    8, 0x50,    0, 0x10,    8, 0x40, 0,  0xc, 0x24,
-  0x10,  0xc,    8, 0x10, 0x10,    4,  0xc, 0x1c,    0, 0x10, 0x14, 0x14, 0x10, 8, 0x20, 0x10,
-  0x10, 0x10,    4,    0, 0x80, 0x10,    4, 0x30, 0x14, 0x10,    0, 0x10,    0, 0,    8,    0,
-  0x10,    8, 0x78, 0x80,
-};
-static const int8 kFireRod_Xvel2[12] = {0, 0, -40, 40, 0, 0, -48, 48, 0, 0, -64, 64};
-static const int8 kFireRod_Yvel2[12] = {-40, 40, 0, 0, -48, 48, 0, 0, -64, 64, 0, 0};
-static const uint8 kTagalongLayerBits[4] = {0x20, 0x10, 0x30, 0x20};
-static const uint8 kBombos_Sfx[8] = {0x80, 0x80, 0x80, 0, 0, 0x40, 0x40, 0x40};
-const uint8 kBomb_Tab0[11] = {0xA0, 6, 4, 4, 4, 4, 4, 6, 6, 6, 6};
-
-#define swordbeam_temp_x (*(uint16*)(g_ram+0x1580E))
-#define swordbeam_temp_y (*(uint16*)(g_ram+0x15810))
-#define swordbeam_arr ((uint8*)(g_ram+0x15800))
-#define swordbeam_var1 (*(uint8*)(g_ram+0x15804))
-#define swordbeam_var2 (*(uint8*)(g_ram+0x15808))
-static const int8 kAncilla_TileColl_Attrs[256] = {
-  0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0,
-  1, 1, 1, 1, 0, 0, 0, 0, 2, 2, 2, 2, 0, 3, 3, 3,
-  0, 0, 0, 0, 0, 0, 1, 1, 4, 4, 4, 4, 4, 4, 4, 4,
-  1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 3, 3, 3,
-  0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4,
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1,
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1,
-  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-};
-static const uint8 kAncilla_TileColl0_Attrs[256] = {
-  0, 1, 0, 3, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0,
-  1, 1, 1, 1, 0, 0, 0, 0, 2, 2, 2, 2, 0, 3, 3, 3,
-  0, 0, 0, 0, 0, 0, 1, 1, 4, 4, 4, 4, 4, 4, 4, 4,
-  1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 3, 3, 3,
-  0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4,
-  0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0,
-  0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1,
-  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-  0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1,
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-};
-static const uint8 kBomb_Draw_Tab0[12] = {0, 1, 2, 3, 2, 3, 4, 5, 6, 7, 8, 9};
-static const uint8 kBomb_Draw_Tab2[11] = {1, 4, 4, 4, 4, 4, 5, 4, 6, 6, 6};
-
-static const uint8 kMagicPowder_Tab0[40] = {
-  13, 14, 15, 0,  1,  2,  3, 4, 5, 6, 10, 11, 12, 0, 1, 2,
-  3,  4,  5, 6, 16, 17, 18, 0, 1, 2,  3,  4,  5, 6, 7, 8,
-  9,  0,  1, 2,  3,  4,  5, 6,
-};
-#define ether_arr1 ((uint8*)(g_ram+0x15800))
-#define ether_var2 (*(uint8*)(g_ram+0x15808))
-#define ether_y2 (*(uint16*)(g_ram+0x1580A))
-#define ether_y_adjusted (*(uint16*)(g_ram+0x1580C))
-#define ether_x2 (*(uint16*)(g_ram+0x1580E))
-#define ether_y3 (*(uint16*)(g_ram+0x15810))
-#define ether_var1 (*(uint8*)(g_ram+0x15812))
-#define ether_y (*(uint16*)(g_ram+0x15813))
-#define ether_x (*(uint16*)(g_ram+0x15815))
-static const uint8 kEther_BlitzOrb_Char[8] = {0x48, 0x48, 0x4a, 0x4a, 0x4c, 0x4c, 0x4e, 0x4e};
-static const uint8 kEther_BlitzOrb_Flags[8] = {0x3c, 0x7c, 0x3c, 0x7c, 0x3c, 0x7c, 0x3c, 0x7c};
-static const uint8 kEther_BlitzSegment_Char[4] = {0x40, 0x42, 0x44, 0x46};
-#define bombos_arr1 ((uint8*)(g_ram+0x15800))
-#define bombos_arr2 ((uint8*)(g_ram+0x15810))
-static const uint8 kBombosBlasts_Tab[72] = {
-  0xb6, 0x5d, 0xa1, 0x30, 0x69, 0xb5, 0xa3, 0x24, 0x96, 0xac, 0x73, 0x5f, 0x92, 0x48, 0x52, 0x81,
-  0x39, 0x95, 0x7f, 0x20, 0x88, 0x5d, 0x34, 0x98, 0xbc, 0xd2, 0x51, 0x77, 0xa2, 0x47, 0x94, 0xb2,
-  0x34, 0xda, 0x30, 0x62, 0x9f, 0x76, 0x51, 0x46, 0x98, 0x5c, 0x9b, 0x61, 0x58, 0x95, 0x4c, 0xba,
-  0x7e, 0xcb, 0x12, 0xd0, 0x70, 0xa6, 0x46, 0xbf, 0x40, 0x50, 0x7e, 0x8c, 0x2d, 0x61, 0xac, 0x88,
-  0x20, 0x6a, 0x72, 0x5f, 0xd2, 0x28, 0x52, 0x80,
-};
-static const uint8 kQuake_Tab1[5] = {0x17, 0x16, 0x17, 0x16, 0x10};
-static const uint8 kQuakeDrawGroundBolts_Char[15] = { 0x40, 0x42, 0x44, 0x46, 0x48, 0x4a, 0x4c, 0x4e, 0x60, 0x62, 0x64, 0x66, 0x68, 0x6a, 0x63 };
-typedef struct QuakeItem {
-  int8 x, y;
-  uint8 f;
-} QuakeItem;
-static const QuakeItem kQuakeItems[] = {
-  {0, -16, 0x00},
-  {0, -16, 0x01},
-  {0, -16, 0x02},
-  {0, -16, 0x03},
-  {0, -16, 0x43},
-  {0, -16, 0x42},
-  {0, -16, 0x41},
-  {0, -16, 0x40},
-  {0, -16, 0x40}, {14, -8, 0x84},
-  {29, -8, 0x44}, {13, -7, 0x84},
-  {31, -7, 0x44}, {47, -4, 0x84},
-  {49, -11, 0x06}, {63, -5, 0x44}, {47, -4, 0x84},
-  {36, -17, 0x08}, {49, -11, 0x06}, {63, -5, 0x44}, {78, 4, 0x08},
-  {22, -31, 0x08}, {36, -17, 0x08}, {78, 4, 0x08}, {93, 20, 0x08},
-  {7, -46, 0x08}, {23, -45, 0x48}, {22, -31, 0x08}, {93, 20, 0x08}, {93, 36, 0x48},
-  {-7, -61, 0x08}, {37, -59, 0x48}, {7, -46, 0x08}, {23, -45, 0x48}, {93, 36, 0x48}, {93, 52, 0x08},
-  {-22, -75, 0x08}, {47, -74, 0x01}, {-8, -61, 0x08}, {36, -60, 0x48}, {93, 52, 0x08}, {108, 67, 0x08},
-  {-37, -90, 0x08}, {-22, -75, 0x08}, {47, -74, 0x01}, {59, -62, 0x81}, {108, 67, 0x08}, {121, 80, 0x08},
-  {-44, -104, 0xc9}, {-37, -90, 0x08}, {73, -74, 0x48}, {59, -62, 0x81}, {121, 80, 0x08},
-  {-44, -120, 0x09}, {-44, -104, 0xc9}, {87, -89, 0x48}, {73, -74, 0x48},
-  {-44, -120, 0x09}, {102, -104, 0x48}, {87, -89, 0x48},
-  {102, -104, 0x48}, {87, -89, 0x48},
-  {112, -116, 0x48}, {102, -104, 0x48},
-  {112, -116, 0x48},
-  {-13, -16, 0x00},
-  {-13, -16, 0x01},
-  {-13, -16, 0x02},
-  {-13, -16, 0x03},
-  {-11, -16, 0x43},
-  {-11, -16, 0x42},
-  {-11, -16, 0x41},
-  {-11, -16, 0x40}, {-24, -10, 0x04},
-  {-38, -18, 0x08}, {-24, -10, 0x04}, {-40, -7, 0xc4},
-  {-45, -33, 0xc9}, {-38, -18, 0x08}, {-57, -7, 0x04}, {-40, -7, 0xc4},
-  {-48, -45, 0x07}, {-45, -33, 0xc9}, {-57, -7, 0x04}, {-71, 2, 0x48},
-  {-48, -45, 0x06}, {-71, 2, 0x48}, {-70, 18, 0x08},
-  {-48, -45, 0x05}, {-70, 18, 0x08}, {-56, 33, 0x08},
-  {-48, -45, 0x07}, {-54, 34, 0x08}, {-54, 49, 0x88},
-  {-48, -45, 0x06}, {-54, 49, 0x88}, {-69, 64, 0x88},
-  {-48, -45, 0x07}, {-69, 64, 0x88}, {-85, 73, 0xc4},
-  {-48, -45, 0x05}, {-101, 73, 0x04}, {-85, 73, 0xc4},
-  {-60, -53, 0x08}, {-48, -45, 0x06}, {-101, 73, 0x04}, {-116, 77, 0xc4},
-  {-75, -67, 0x08}, {-60, -53, 0x08}, {-128, 76, 0x04}, {-116, 77, 0xc4},
-  {-90, -82, 0x08}, {-75, -67, 0x08}, {-128, 76, 0x04},
-  {-105, -97, 0x08}, {-90, -82, 0x08},
-  {-120, -111, 0x08}, {-105, -97, 0x08},
-  {-120, -111, 0x08},
-  {0, -5, 0x0a},
-  {0, -5, 0x0b},
-  {2, -3, 0x0c},
-  {1, -3, 0x0d},
-  {0, -3, 0x8d},
-  {1, -3, 0x8c},
-  {1, -3, 0x8b},
-  {1, -3, 0x8a}, {-6, 12, 0x89},
-  {-6, 12, 0x89}, {-10, 28, 0xc9},
-  {-10, 28, 0x49}, {-8, 44, 0x89},
-  {-8, 44, 0x89}, {-10, 56, 0x02},
-  {-10, 56, 0x02}, {-23, 70, 0x48}, {5, 70, 0x08},
-  {-23, 70, 0x48}, {5, 70, 0x08}, {-38, 85, 0x48}, {19, 85, 0x08},
-  {-38, 85, 0x48}, {19, 85, 0x08}, {-52, 99, 0x48}, {33, 101, 0x08},
-  {-52, 99, 0x48}, {33, 101, 0x08}, {-66, 113, 0x48}, {47, 115, 0x08},
-  {-66, 113, 0x48}, {47, 115, 0x08},
-};
-static const uint8 kQuakeItemPos[] = {
-  0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 17, 21, 25, 30,
-  36, 42, 48, 53, 57, 60, 62, 64, 65, 66, 67, 68, 69, 70, 71, 72, 74, 77, 81, 85, 88, 91, 94, 97, 100, 103, 107, 111, 114, 116, 118, 119, 120, 121, 122, 123, 124, 125, 126, 128, 130, 132, 134, 137, 141, 145, 149, 151
-};
-static const QuakeItem kQuakeItems2[] = {
-  {-96, 112, 0x20},
-  {-96, 112, 0x21},
-  {-96, 112, 0x66},
-  {-96, 112, 0x22},
-  {-96, 112, 0x23},
-  {-96, 112, 0x63},
-  {-96, 112, 0x62},
-  {-96, 112, 0x26},
-  {-96, 112, 0x27}, {-86, 124, 0x28},
-  {-86, 124, 0x28}, {-72, -117, 0x28},
-  {-72, -117, 0x28}, {-59, -102, 0xa1},
-  {-59, -102, 0xa1}, {-44, -116, 0x68},
-  {-44, -116, 0x68}, {-29, 126, 0x68},
-  {-29, 126, 0x68},
-  {-19, 125, 0xc5},
-  {-112, 96, 0x2a},
-  {-112, 96, 0x2b},
-  {-112, 96, 0x2c},
-  {-112, 96, 0x2d},
-  {-119, 82, 0x29}, {-112, 96, 0x2a},
-  {-123, 66, 0xe9}, {-119, 82, 0x29},
-  {-121, 50, 0x29}, {-123, 66, 0xe9},
-  {126, 34, 0x28}, {-115, 34, 0x68}, {-121, 50, 0x29},
-  {-106, 18, 0xa9}, {111, 19, 0x28}, {126, 34, 0x28}, {-115, 34, 0x68},
-  {-100, 2, 0x68}, {102, 4, 0xe9}, {-106, 18, 0xa9}, {111, 19, 0x28},
-  {-91, -14, 0xa9}, {95, -11, 0x28}, {-100, 2, 0x68}, {102, 4, 0xe9},
-  {96, 112, 0x60},
-  {96, 112, 0x61},
-  {96, 112, 0x26},
-  {96, 112, 0x62},
-  {96, 112, 0x63},
-  {96, 112, 0x23},
-  {96, 112, 0x22},
-  {96, 112, 0x66},
-  {85, 111, 0xe8}, {96, 112, 0x67},
-  {70, 104, 0x24}, {85, 111, 0xe8},
-  {70, 104, 0x24}, {54, 108, 0xe4},
-  {40, 100, 0x28}, {38, 107, 0x24}, {54, 108, 0xe4},
-  {25, 85, 0x28}, {40, 100, 0x28}, {38, 107, 0x24}, {22, 110, 0xe4},
-  {11, 70, 0x28}, {25, 85, 0x28}, {7, 108, 0x24}, {22, 110, 0xe4},
-  {11, 70, 0x28}, {7, 108, 0x24},
-  {112, 112, 0x2a},
-  {112, 112, 0x2b},
-  {112, 112, 0x2c},
-  {112, 112, 0x2d},
-  {112, 112, 0x2a}, {108, 125, 0x29},
-  {108, 125, 0x29}, {114, -116, 0x28},
-  {114, -116, 0x28}, {124, -100, 0x29},
-  {124, -100, 0x29}, {123, -84, 0xe9},
-  {123, -84, 0xe9}, {117, -74, 0xe4}, {-124, -69, 0x28},
-  {117, -74, 0xe4}, {-124, -69, 0x28}, {103, -67, 0x68}, {-110, -54, 0x28},
-  {103, -67, 0x68}, {-110, -54, 0x28}, {95, -52, 0x69}, {-102, -39, 0x29},
-  {95, -52, 0x69}, {-102, -39, 0x29}, {96, -36, 0xe9}, {-102, -24, 0xe9},
-  {96, -36, 0xe9}, {-102, -24, 0xe9},
-  {-123, -14, 0x29}, {-115, -14, 0x2e}, {49, -12, 0x28},
-};
-static const uint8 kQuakeItemPos2[] = {
-  0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 18, 19, 20, 21, 22, 23, 24, 26, 28, 30, 33, 37, 41, 45, 46, 47, 48, 49, 50, 51, 52, 53, 55, 57, 59, 62, 66, 70, 72, 73, 74, 75, 76, 78, 80, 82, 84, 87, 91, 95, 99, 101, 104
-};
-static const uint8 kReceiveItem_Tab4[3] = {9, 5, 5};
-static const uint8 kReceiveItem_Tab5[3] = {0x24, 0x25, 0x26};
-static const uint8 kReceiveItem_Tab0[3] = {5, 1, 4};
-static const int16 kReceiveItemMsgs[76] = {
-  -1, 0x70, 0x77, 0x52,   -1, 0x78,  0x78, 0x62, 0x61, 0x66, 0x69, 0x53, 0x52, 0x56,   -1,  0x64,
-  0x63, 0x65, 0x51, 0x54, 0x67, 0x68,  0x6b, 0x77, 0x79, 0x55, 0x6e, 0x58, 0x6d, 0x5d, 0x57,  0x5e,
-  -1, 0x74, 0x75, 0x76,   -1, 0x5f, 0x158,   -1, 0x6a, 0x5c, 0x8f, 0x71, 0x72, 0x73, 0x71,  0x72,
-  0x73, 0x6a, 0x6c, 0x60,   -1,   -1,    -1, 0x59, 0x84, 0x5a,   -1,   -1,   -1,   -1,   -1, 0x159,
-  -1,   -1,   -1,   -1,   -1,   -1,    -1,   -1,   -1, 0xdb, 0x67, 0x7c,
-};
-static const int16 kReceiveItemMsgs2[2] = {0x5b, 0x83};
-static const int16 kReceiveItemMsgs3[4] = {-1, 0x155, 0x156, 0x157};
-static const uint8 kTravelBird_DmaStuffs[4] = {0, 0x20, 0x40, 0xe0};
-static const int8 kTravelBird_Draw_X[3] = {0, -9, -9};
-static const int8 kTravelBird_Draw_Y[3] = {0, 12, 20};
-static const uint8 kTravelBird_Draw_Char[3] = {0xe, 0, 2};
-static const uint8 kTravelBird_Draw_Flags[3] = {0x22, 0x2e, 0x2e};
-static const int8 kSomarianBlock_Coll_X[12] = {0, 0, -8, 8, 0, 0, 0, 0, 8, -8, -8, 8};
-static const int8 kSomarianBlock_Coll_Y[12] = {-8, 8, 0, 0, 0, 0, 0, 0, -8, 8, -8, 8};
-static HandlerFuncK *const kAncilla_Funcs[67] = {
-  &Ancilla01_SomariaBullet,
-  &Ancilla02_FireRodShot,
-  &Ancilla_Empty,
-  &Ancilla04_BeamHit,
-  &Ancilla05_Boomerang,
-  &Ancilla06_WallHit,
-  &Ancilla07_Bomb,
-  &Ancilla08_DoorDebris,
-  &Ancilla09_Arrow,
-  &Ancilla0A_ArrowInTheWall,
-  &Ancilla0B_IceRodShot,
-  &Ancilla_SwordBeam,
-  &Ancilla0D_SpinAttackFullChargeSpark,
-  &Ancilla33_BlastWallExplosion,
-  &Ancilla33_BlastWallExplosion,
-  &Ancilla33_BlastWallExplosion,
-  &Ancilla11_IceRodWallHit,
-  &Ancilla33_BlastWallExplosion,
-  &Ancilla13_IceRodSparkle,
-  &Ancilla_Unused_14,
-  &Ancilla15_JumpSplash,
-  &Ancilla16_HitStars,
-  &Ancilla17_ShovelDirt,
-  &Ancilla18_EtherSpell,
-  &Ancilla19_BombosSpell,
-  &Ancilla1A_PowderDust,
-  &Ancilla_SwordWallHit,
-  &Ancilla1C_QuakeSpell,
-  &Ancilla1D_ScreenShake,
-  &Ancilla1E_DashDust,
-  &Ancilla1F_Hookshot,
-  &Ancilla20_Blanket,
-  &Ancilla21_Snore,
-  &Ancilla22_ItemReceipt,
-  &Ancilla23_LinkPoof,
-  &Ancilla24_Gravestone,
-  &Ancilla_Unused_25,
-  &Ancilla26_SwordSwingSparkle,
-  &Ancilla27_Duck,
-  &Ancilla28_WishPondItem,
-  &Ancilla29_MilestoneItemReceipt,
-  &Ancilla2A_SpinAttackSparkleA,
-  &Ancilla2B_SpinAttackSparkleB,
-  &Ancilla2C_SomariaBlock,
-  &Ancilla2D_SomariaBlockFizz,
-  &Ancilla2E_SomariaBlockFission,
-  &Ancilla2F_LampFlame,
-  &Ancilla30_ByrnaWindupSpark,
-  &Ancilla31_ByrnaSpark,
-  &Ancilla32_BlastWallFireball,
-  &Ancilla33_BlastWallExplosion,
-  &Ancilla34_SkullWoodsFire,
-  &Ancilla35_MasterSwordReceipt,
-  &Ancilla36_Flute,
-  &Ancilla37_WeathervaneExplosion,
-  &Ancilla38_CutsceneDuck,
-  &Ancilla39_SomariaPlatformPoof,
-  &Ancilla3A_BigBombExplosion,
-  &Ancilla3B_SwordUpSparkle,
-  &Ancilla3C_SpinAttackChargeSparkle,
-  &Ancilla3D_ItemSplash,
-  &Ancilla_RisingCrystal,
-  &Ancilla3F_BushPoof,
-  &Ancilla40_DwarfPoof,
-  &Ancilla41_WaterfallSplash,
-  &Ancilla42_HappinessPondRupees,
-  &Ancilla43_GanonsTowerCutscene,
-};
-uint16 Ancilla_GetX(int k) {
-  return ancilla_x_lo[k] | ancilla_x_hi[k] << 8;
-}
-
-uint16 Ancilla_GetY(int k) {
-  return ancilla_y_lo[k] | ancilla_y_hi[k] << 8;
-}
-
-void Ancilla_SetX(int k, uint16 x) {
-  ancilla_x_lo[k] = x;
-  ancilla_x_hi[k] = x >> 8;
-}
-
-void Ancilla_SetY(int k, uint16 y) {
-  ancilla_y_lo[k] = y;
-  ancilla_y_hi[k] = y >> 8;
-}
-
-int Ancilla_AllocHigh() {
-  for (int k = 9; k >= 0; k--) {
-    if (ancilla_type[k] == 0)
-      return k;
-  }
-  return -1;
-}
-
-static void Ancilla_SetOam(OamEnt *oam, uint16 x, uint16 y, uint8 charnum, uint8 flags, uint8 big) {
-  uint8 yval = 0xf0;
-  int xt = enhanced_features0 & kFeatures0_ExtendScreen64 ? 0x40 : 0;
-  if ((uint16)(x + xt) < 256 + xt * 2 && y < 256) {
-    big |= (x >> 8) & 1;
-    oam->x = x;
-    if (y < 0xf0)
-      yval = y;
-  }
-  oam->y = yval;
-  oam->charnum = charnum;
-  oam->flags = flags;
-  bytewise_extended_oam[oam - oam_buf] = big;
-}
-
-static void Ancilla_SetOam_Safe(OamEnt *oam, uint16 x, uint16 y, uint8 charnum, uint8 flags, uint8 big) {
-  uint8 yval = 0xf0;
-  oam->x = x;
-  int xt = enhanced_features0 & kFeatures0_ExtendScreen64 ? 0x48 : 0;
-  if ((uint16)(x + 0x80) < (0x180 + xt)) {
-    big |= (x >> 8) & 1;
-    if ((uint16)(y + 0x10) < 0x100)
-      yval = y;
-  }
-  oam->y = yval;
-  oam->charnum = charnum;
-  oam->flags = flags;
-  bytewise_extended_oam[oam - oam_buf] = big;
-}
-
-void Ancilla_Empty(int k) {
-}
-
-void Ancilla_Unused_14(int k) {
-  assert(0);
-}
-
-void Ancilla_Unused_25(int k) {
-  assert(0);
-}
-
-void SpinSpark_Draw(int k, int offs) {
-  static const uint8 kInitialSpinSpark_Char[32] = {
-    0x92, 0xff, 0xff, 0xff, 0x8c, 0x8c, 0x8c, 0x8c, 0xd6, 0xd6, 0xd6, 0xd6, 0x93, 0x93, 0x93, 0x93,
-    0xd6, 0xd6, 0xd6, 0xd6, 0xd7, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x22, 0xff, 0xff, 0xff,  // wtf oob
-  };
-  static const uint8 kInitialSpinSpark_Flags[29] = {
-    0x22, 0xff, 0xff, 0xff, 0x22, 0x62, 0xa2, 0xe2, 0x24, 0x64, 0xa4, 0xe4, 0x22, 0x62, 0xa2, 0xe2,
-    0x22, 0x62, 0xa2, 0xe2, 0x22, 0xff, 0xff, 0xff, 0x22, 0xff, 0xff, 0xff,
-    0xfc,
-  };
-  static const int8 kInitialSpinSpark_Y[29] = {
-    -4,  0, 0, 0, -8, -8, 0, 0, -8, -8, 0, 0, -8, -8, 0, 0,
-    -8, -8, 0, 0, -4,  0, 0, 0, -4,  0, 0, 0,
-    -4,
-  };
-  static const int16 kInitialSpinSpark_X[29] = {
-    -4, 0,  0, 0, -8, 0, -8, 0, -8, 0, -8, 0, -8, 0, -8, 0,
-    -8, 0, -8, 0, -4, 0,  0, 0, -4, 0,  0, 0,
-    0x11a5
-  };
-  Point16U info;
-  Ancilla_PrepOamCoord(k, &info);
-  OamEnt *oam = GetOamCurPtr();
-  int t = (ancilla_item_to_link[k] + offs) * 4;
-  assert(t < 32);
-  for(int i = 0; i < 4; i++, t++) {
-    if (kInitialSpinSpark_Char[t] != 0xff) {
-      Ancilla_SetOam(oam, info.x + kInitialSpinSpark_X[t], info.y + kInitialSpinSpark_Y[t],
-                     kInitialSpinSpark_Char[t], kInitialSpinSpark_Flags[t] & ~0x30 | HIBYTE(oam_priority_value), 0);
-      oam++;
-    }
-  }
-}
-
-bool SomarianBlock_CheckEmpty(OamEnt *oam) {
-  for (int i = 0; i != 4; i++) {
-    if (oam[i].y == 0xf0)
-      continue;
-    for (i = 0; i < 4; i++)
-      if (!(bytewise_extended_oam[oam + i - oam_buf] & 1))
-        return false;
-    break;
-  }
-  return true;
-}
-
-void AddDashingDustEx(uint8 a, uint8 y, uint8 flag) {
-  static const int8 kAddDashingDust_X[4] = {4, 4, 6, 0};
-  static const int8 kAddDashingDust_Y[4] = {20, 4, 16, 16};
-  int k = Ancilla_AddAncilla(a, y);
-  if (k >= 0) {
-    ancilla_step[k] = flag;
-    ancilla_item_to_link[k] = 0;
-    ancilla_timer[k] = 3;
-    int j = link_direction_facing >> 1;
-    ancilla_dir[k] = j;
-    if (!flag) {
-      Ancilla_SetXY(k, link_x_coord, link_y_coord + 20);
-    } else {
-      Ancilla_SetXY(k, link_x_coord + kAddDashingDust_X[j], link_y_coord + kAddDashingDust_Y[j]);
-    }
-  }
-}
-
-void AddBirdCommon(int k) {
-  ancilla_y_vel[k] = 0;
-  ancilla_item_to_link[k] = 0;
-  ancilla_aux_timer[k] = 1;
-  ancilla_x_vel[k] = 56;
-  ancilla_arr3[k] = 3;
-  ancilla_K[k] = 0;
-  ancilla_G[k] = 0;
-
-  int xt = (enhanced_features0 & kFeatures0_ExtendScreen64) ? 0x40 : 0;
-  Ancilla_SetXY(k, BG2HOFS_copy2 - 16 - xt, link_y_coord - 8);
-}
-
-ProjectSpeedRet Bomb_ProjectSpeedTowardsPlayer(int k, uint16 x, uint16 y, uint8 vel) {  // 84eb63
-  uint16 old_x = Sprite_GetX(0), old_y = Sprite_GetY(0), old_z = sprite_z[0];
-  Sprite_SetX(0, x);
-  Sprite_SetY(0, y);
-  sprite_z[0] = 0;
-  ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLink(0, vel);
-  sprite_z[0] = old_z;
-  Sprite_SetX(0, old_x);
-  Sprite_SetY(0, old_y);
-  return pt;
-}
-
-void Boomerang_CheatWhenNoOnesLooking(int k, ProjectSpeedRet *pt) {  // 86809f
-  uint16 x = link_x_coord - Ancilla_GetX(k) + 0xf0;
-  uint16 y = link_y_coord - Ancilla_GetY(k) + 0xf0;
-  if (x >= 0x1e0) {
-    pt->x = sign16(x - 0x1e0) ? 0x90 : 0x70;
-  } else if (y >= 0x1e0) {
-    pt->y = sign16(y - 0x1e0) ? 0x90 : 0x70;
-  }
-}
-
-void Medallion_CheckSpriteDamage(int k) {  // 86ec5c
-  tmp_counter = ancilla_type[k];
-  for (int j = 15; j >= 0; j--) {
-    if (sprite_state[j] >= 9 && !(sprite_ignore_projectile[j] | sprite_pause[j])) {
-      Ancilla_CheckDamageToSprite_aggressive(j, tmp_counter);
-    }
-  }
-}
-
-void Ancilla_CheckDamageToSprite(int k, uint8 type) {  // 86ecb7
-  if (!sign8(sprite_hit_timer[k]))
-    Ancilla_CheckDamageToSprite_aggressive(k, type);
-}
-
-void Ancilla_CheckDamageToSprite_aggressive(int k, uint8 type) {  // 86ecbd
-  static const uint8 kAncilla_Damage[57] = {
-    6, 1, 11, 0, 0, 0, 0, 8,  0,  6, 0, 12,  1, 0, 0,  0,
-    0, 1,  0, 0, 0, 0, 0, 0, 14, 13, 0,  0, 15, 0, 0,  7,
-    1, 1,  1, 1, 1, 1, 1, 1,  1,  1, 1,  1,  1, 1, 1, 11,
-    0, 1,  1, 1, 1, 1, 1, 1,  1,
-  };
-  uint8 dmg = kAncilla_Damage[type];
-  if (dmg == 6 && link_item_bow >= 3) {
-    if (sprite_type[k] == 0xd7)
-      sprite_delay_aux4[k] = 32;
-    dmg = 9;
-  }
-  Ancilla_CheckDamageToSprite_preset(k, dmg);
-}
-
-void CallForDuckIndoors() {  // 87a45f
-  Ancilla_Sfx2_Near(0x13);
-  AncillaAdd_Duck_take_off(0x27, 4);
-}
-
-void Ancilla_Sfx1_Pan(int k, uint8 v) {  // 888020
-  byte_7E0CF8 = v;
-  sound_effect_ambient = v | Ancilla_CalculateSfxPan(k);
-}
-
-void Ancilla_Sfx2_Pan(int k, uint8 v) {  // 888027
-  byte_7E0CF8 = v;
-  sound_effect_1 = v | Ancilla_CalculateSfxPan(k);
-}
-
-void Ancilla_Sfx3_Pan(int k, uint8 v) {  // 88802e
-  byte_7E0CF8 = v;
-  sound_effect_2 = v | Ancilla_CalculateSfxPan(k);
-}
-
-void AncillaAdd_FireRodShot(uint8 type, uint8 y) {  // 8880b3
-  static const int8 kFireRod_X[4] = {0, 0, -8, 16};
-  static const int8 kFireRod_Y[4] = {-8, 16, 3, 3};
-  static const int8 kFireRod_Xvel[4] = {0, 0, -64, 64};
-  static const int8 kFireRod_Yvel[4] = {-64, 64, 0, 0};
-
-  y = 1;
-  int j= Ancilla_AllocInit(type, 1);
-  if (j < 0) {
-    if (type != 1)
-      Refund_Magic(0);
-    return;
-  }
-
-  if (type != 1)
-    Ancilla_Sfx2_Near(0xe);
-
-  ancilla_type[j] = type;
-  ancilla_numspr[j] = kAncilla_Pflags[type];
-  ancilla_timer[j] = 3;
-  ancilla_step[j] = 0;
-  ancilla_item_to_link[j] = 0;
-  ancilla_objprio[j] = 0;
-  ancilla_U[j] = 0;
-  int i = link_direction_facing >> 1;
-  ancilla_dir[j] = i;
-
-  if (Ancilla_CheckInitialTile_A(j) < 0) {
-    Ancilla_SetXY(j, link_x_coord + kFireRod_X[i], link_y_coord + kFireRod_Y[i]);
-    if (type != 1) {
-      ancilla_x_vel[j] = kFireRod_Xvel[i];
-      ancilla_y_vel[j] = kFireRod_Yvel[i];
-    } else {
-      i += (link_sword_type - 2) * 4;
-      ancilla_x_vel[j] = kFireRod_Xvel2[i];
-      ancilla_y_vel[j] = kFireRod_Yvel2[i];
-    }
-    ancilla_floor[j] = link_is_on_lower_level;
-    ancilla_floor2[j] = link_is_on_lower_level_mirror;
-  } else {
-    if (type == 1) {
-      ancilla_type[j] = 4;
-      ancilla_timer[j] = 7;
-      ancilla_numspr[j] = 16;
-    } else {
-      ancilla_step[j] = 1;
-      ancilla_timer[j] = 31;
-      ancilla_numspr[j] = 8;
-      j = link_direction_facing >> 1; // wtf
-      Ancilla_Sfx2_Pan(j, 0x2a);
-    }
-  }
-}
-
-void SomariaBlock_SpawnBullets(int k) {  // 8881a7
-  static const int8 kSpawnCentrifugalQuad_X[4] = {-8, -8, -9, -4};
-  static const int8 kSpawnCentrifugalQuad_Y[4] = {-15, -4, -8, -8};
-
-  uint8 z = (ancilla_z[k] == 0xff) ? 0 : ancilla_z[k];
-  uint16 x = Ancilla_GetX(k);
-  uint16 y = Ancilla_GetY(k) - z;
-
-  for (int i = 3; i >= 0; i--) {
-    int j = Ancilla_AllocInit(1, 4);
-    if (j >= 0) {
-      ancilla_type[j] = 0x1;
-      ancilla_numspr[j] = kAncilla_Pflags[0x1];
-      ancilla_step[j] = 4;
-      ancilla_item_to_link[j] = 0;
-      ancilla_objprio[j] = 0;
-      ancilla_dir[j] = i;
-      Ancilla_SetXY(j, x + kSpawnCentrifugalQuad_X[i], y + kSpawnCentrifugalQuad_Y[i]);
-      Ancilla_TerminateIfOffscreen(j);
-      ancilla_x_vel[j] = kFireRod_Xvel2[i];
-      ancilla_y_vel[j] = kFireRod_Yvel2[i];
-      ancilla_floor[j] = ancilla_floor[k];
-      ancilla_floor2[j] = link_is_on_lower_level_mirror;
-    }
-  }
-  tmp_counter = 0xff;
-}
-
-void Ancilla_Main() {  // 888242
-  Ancilla_WeaponTink();
-  Ancilla_ExecuteAll();
-}
-
-ProjectSpeedRet Ancilla_ProjectReflexiveSpeedOntoSprite(int k, uint16 x, uint16 y, uint8 vel) {  // 88824d
-  uint16 old_x = link_x_coord, old_y = link_y_coord;
-  link_x_coord = x;
-  link_y_coord = y;
-  ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLink(k, vel);
-  link_x_coord = old_x;
-  link_y_coord = old_y;
-  return pt;
-}
-
-void Bomb_CheckSpriteDamage(int k) {  // 888287
-  for (int j = 15; j >= 0; j--) {
-    if ((j ^ frame_counter) & 3 | sprite_hit_timer[j] | sprite_ignore_projectile[j])
-      continue;
-    if (sprite_floor[j] != ancilla_floor[k] || sprite_state[j] < 9)
-      continue;
-    SpriteHitBox hb;
-    int ax = Ancilla_GetX(k) - 24;
-    int ay = Ancilla_GetY(k) - 24 - ancilla_z[k];
-    hb.r0_xlo = ax;
-    hb.r8_xhi = ax >> 8;
-    hb.r1_ylo = ay;
-    hb.r9_yhi = ay >> 8;
-    hb.r2 = 48;
-    hb.r3 = 48;
-    Sprite_SetupHitBox(j, &hb);
-    if (!CheckIfHitBoxesOverlap(&hb))
-      continue;
-    if (sprite_type[j] == 0x92 && sprite_C[j] >= 3)
-      continue;
-    Ancilla_CheckDamageToSprite(j, ancilla_type[k]);
-    ProjectSpeedRet pt = Ancilla_ProjectReflexiveSpeedOntoSprite(j, Ancilla_GetX(k), Ancilla_GetY(k), 64);
-    sprite_x_recoil[j] = -pt.x;
-    sprite_y_recoil[j] = -pt.y;
-  }
-}
-
-void Ancilla_ExecuteAll() {  // 88832b
-  for (int i = 9; i >= 0; i--) {
-    cur_object_index = i;
-    if (ancilla_type[i])
-      Ancilla_ExecuteOne(ancilla_type[i], i);
-  }
-}
-
-void Ancilla_ExecuteOne(uint8 type, int k) {  // 88833c
-  if (k < 6) {
-    ancilla_oam_idx[k] = Ancilla_AllocateOamFromRegion_A_or_D_or_F(k, ancilla_numspr[k]);
-  }
-
-  if (submodule_index == 0 && ancilla_timer[k] != 0)
-    ancilla_timer[k]--;
-
-  kAncilla_Funcs[type - 1](k);
-}
-
-void Ancilla13_IceRodSparkle(int k) {  // 888435
-  static const uint8 kIceShotSparkle_X[16] = {2, 7, 6, 1, 1, 7, 7, 1, 0, 7, 8, 1, 4, 9, 4, 0xff};
-  static const uint8 kIceShotSparkle_Y[16] = {2, 3, 8, 7, 1, 1, 7, 7, 1, 0, 7, 8, 0xff, 4, 9, 4};
-  static const uint8 kIceShotSparkle_Char[16] = {0x83, 0x83, 0x83, 0x83, 0xb6, 0x80, 0xb6, 0x80, 0xb7, 0xb6, 0xb7, 0xb6, 0xb7, 0xb6, 0xb7, 0xb6};
-
-  if (!ancilla_timer[k])
-    ancilla_type[k] = 0;
-  if (!submodule_index) {
-    Ancilla_MoveX(k);
-    Ancilla_MoveY(k);
-  }
-  AncillaOamInfo info;
-  if (Ancilla_ReturnIfOutsideBounds(k, &info))
-    return;
-
-  int j;
-  for (j = 4; j >= 0 && ancilla_type[j] != 0xb; j--) {}
-  if (j >= 0 && ancilla_objprio[j])
-    info.flags = 0x30;
-
-  if (sort_sprites_setting) {
-    if (ancilla_floor[k])
-      Oam_AllocateFromRegionE(0x10);
-    else
-      Oam_AllocateFromRegionD(0x10);
-  } else {
-    Oam_AllocateFromRegionA(0x10);
-  }
-
-  OamEnt *oam = GetOamCurPtr();
-  j = ancilla_timer[k] & 0x1c;
-  for (int i = 3; i >= 0; i--, oam++)
-    SetOamPlain(oam, info.x + kIceShotSparkle_X[i + j], info.y + kIceShotSparkle_Y[i + j], kIceShotSparkle_Char[i + j], info.flags | 4, 0);
-}
-
-void AncillaAdd_IceRodSparkle(int k) {  // 8884c8
-  static const int8 kIceShotSparkle_Xvel[4] = {0, 0, -4, 4};
-  static const int8 kIceShotSparkle_Yvel[4] = {-4, 4, 0, 0};
-
-  if (submodule_index || !sign8(--ancilla_arr4[k]))
-    return;
-
-  ancilla_arr4[k] = 5;
-  int j = Ancilla_AllocHigh();
-  if (j >= 0) {
-    ancilla_type[j] = 0x13;
-    ancilla_timer[j] = 15;
-
-    int i = ancilla_dir[k];
-    ancilla_x_vel[j] = kIceShotSparkle_Xvel[i];
-    ancilla_y_vel[j] = kIceShotSparkle_Yvel[i];
-
-    ancilla_x_lo[j] = ancilla_x_lo[k];
-    ancilla_y_lo[j] = ancilla_y_lo[k];
-    ancilla_floor[j] = ancilla_floor[k];
-    ancilla_numspr[j] = 0;
-  }
-
-}
-
-void Ancilla01_SomariaBullet(int k) {  // 88851b
-  static const uint8 kSomarianBlast_Mask[6] = {7, 3, 1, 0, 0, 0};
-
-  if (!submodule_index) {
-    if (!(frame_counter & kSomarianBlast_Mask[ancilla_step[k]])) {
-      Ancilla_MoveX(k);
-      Ancilla_MoveY(k);
-    }
-    if (ancilla_timer[k] == 0) {
-      ancilla_timer[k] = 3;
-      uint8 a = ancilla_step[k] + 1;
-      if (a >= 6)
-        a = 4;
-      ancilla_step[k] = a;
-    }
-    if (Ancilla_CheckSpriteCollision(k) >= 0 || Ancilla_CheckTileCollision_staggered(k)) {
-      ancilla_type[k] = 4;
-      ancilla_timer[k] = 7;
-      ancilla_numspr[k] = 16;
-    }
-  }
-  SomarianBlast_Draw(k);
-}
-
-bool Ancilla_ReturnIfOutsideBounds(int k, AncillaOamInfo *info) {  // 88862a
-  static const uint8 kAncilla_FloorFlags[2] = {0x20, 0x10};
-  info->flags = kAncilla_FloorFlags[ancilla_floor[k]];
-  if ((info->x = ancilla_x_lo[k] - BG2HOFS_copy2) >= 0xf4 ||
-      (info->y = ancilla_y_lo[k] - BG2VOFS_copy2) >= 0xf0) {
-    ancilla_type[k] = 0;
-    return true;
-  }
-  return false;
-}
-
-void SomarianBlast_Draw(int k) {  // 888650
-  static const uint8 kSomarianBlast_Flags[2] = {2, 6};
-  AncillaOamInfo info;
-  if (Ancilla_ReturnIfOutsideBounds(k, &info))
-    return;
-  info.flags |= kSomarianBlast_Flags[ancilla_item_to_link[k]];
-  if (ancilla_objprio[k])
-    info.flags |= 0x30;
-  static const int8 kSomarianBlast_Draw_X0[24] = {
-    0, 0, 0, 0, 4, 4, 0, 0, 0, 0, 4, 4, 0, 0, 0, 0,
-    0, 0, 0, 0, 0, 0, 0, 0,
-  };
-  static const int8 kSomarianBlast_Draw_X1[24] = {
-    8, 8, 8, 8, 4, 4, 8, 8, 8, 8, 4, 4, 0, 0, 0, 0,
-    8, 8, 0, 0, 0, 0, 8, 8,
-  };
-  static const uint8 kSomarianBlast_Draw_Y0[24] = {
-    0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    4, 4, 0, 0, 0, 0, 4, 4,
-  };
-  static const uint8 kSomarianBlast_Draw_Y1[24] = {
-    0, 0,    0, 0, 8, 8, 0x80, 0, 0, 0, 8, 8, 0x80, 8, 8, 8,
-    4, 4, 0x80, 8, 8, 8,    4, 4,
-  };
-  static const uint8 kSomarianBlast_Draw_Flags0[24] = {
-    0xc0, 0xc0, 0xc0, 0xc0, 0x80, 0xc0, 0x40, 0x40, 0x40, 0x40, 0, 0x40, 0x40, 0x40, 0x40, 0x40,
-    0x40, 0xc0,    0,    0,    0,    0,    0, 0x80,
-  };
-  static const uint8 kSomarianBlast_Draw_Flags1[24] = {
-    0x80, 0x80, 0x80, 0x80, 0x80, 0xc0, 0,    0, 0, 0, 0, 0x40, 0xc0, 0xc0, 0xc0, 0xc0,
-    0x40, 0xc0, 0x80, 0x80, 0x80, 0x80, 0, 0x80,
-  };
-  static const uint8 kSomarianBlast_Draw_Char0[24] = {
-    0x50, 0x50, 0x44, 0x44, 0x52, 0x52, 0x50, 0x50, 0x44, 0x44, 0x51, 0x51, 0x43, 0x43, 0x42, 0x42,
-    0x41, 0x41, 0x43, 0x43, 0x42, 0x42, 0x40, 0x40,
-  };
-  static const uint8 kSomarianBlast_Draw_Char1[24] = {
-    0x50, 0x50, 0x44, 0x44, 0x51, 0x51, 0x50, 0x50, 0x44, 0x44, 0x52, 0x52, 0x43, 0x43, 0x42, 0x42,
-    0x40, 0x40, 0x43, 0x43, 0x42, 0x42, 0x41, 0x41,
-  };
-  OamEnt *oam = GetOamCurPtr();
-  int j = ancilla_dir[k] * 6 + ancilla_step[k];
-  SetOamPlain(oam + 0, info.x + kSomarianBlast_Draw_X0[j], sign8(kSomarianBlast_Draw_Y0[j]) ? 0xf0 : info.y + kSomarianBlast_Draw_Y0[j],
-              0x82 + kSomarianBlast_Draw_Char0[j], info.flags | kSomarianBlast_Draw_Flags0[j], 0);
-  SetOamPlain(oam + 1, info.x + kSomarianBlast_Draw_X1[j], sign8(kSomarianBlast_Draw_Y1[j]) ? 0xf0 : info.y + kSomarianBlast_Draw_Y1[j],
-              0x82 + kSomarianBlast_Draw_Char1[j], info.flags | kSomarianBlast_Draw_Flags1[j], 0);
-}
-
-void Ancilla02_FireRodShot(int k) {  // 8886d2
-  if (ancilla_step[k] == 0) {
-    if (!submodule_index) {
-      ancilla_L[k] = 0;
-      Ancilla_MoveX(k);
-      Ancilla_MoveY(k);
-      uint8 coll = Ancilla_CheckSpriteCollision(k) >= 0;
-      if (!coll) {
-        ancilla_dir[k] |= 8;
-        coll = Ancilla_CheckTileCollision(k);
-        ancilla_L[k] = ancilla_tile_attr[k];
-        if (!coll) {
-          ancilla_dir[k] |= 12;
-          uint8 bak = ancilla_U[k];
-          coll = Ancilla_CheckTileCollision(k);
-          ancilla_U[k] = bak;
-        }
-      }
-      if (coll) {
-        ancilla_step[k]++;
-        ancilla_timer[k] = 31;
-        ancilla_numspr[k] = 8;
-        Ancilla_Sfx2_Pan(k, 0x2a);
-      }
-      ancilla_item_to_link[k]++;
-      ancilla_dir[k] &= ~0xC;
-      if (((byte_7E0333 = ancilla_L[k]) & 0xf0) == 0xc0 || ((byte_7E0333 = ancilla_tile_attr[k]) & 0xf0) == 0xc0)
-        Dungeon_LightTorch();
-    }
-    FireShot_Draw(k);
-  } else {
-    AncillaOamInfo info;
-    Ancilla_CheckBasicSpriteCollision(k);
-    if (Ancilla_ReturnIfOutsideBounds(k, &info))
-      return;
-    OamEnt *oam = GetOamCurPtr();
-    if (!ancilla_timer[k]) {
-      uint8 old_type = ancilla_type[k];
-      ancilla_type[k] = 0;
-      if (old_type != 0x2f && BYTE(overworld_screen_index) == 64 && ancilla_tile_attr[k] == 0x43)
-        FireRodShot_BecomeSkullWoodsFire(k);
-      return;
-    }
-    int j = ancilla_timer[k] >> 3;
-    if (j != 0) {
-      static const uint8 kFireShot_Draw_Char[3] = {0xa2, 0xa0, 0x8e};
-      SetOamPlain(oam, info.x, info.y, kFireShot_Draw_Char[j - 1], info.flags | 2, 2);
-    } else {
-      SetOamPlain(oam + 0, info.x + 0, info.y - 3, 0xa4, info.flags | 2, 0);
-      SetOamPlain(oam + 1, info.x + 8, info.y - 3, 0xa5, info.flags | 2, 0);
-    }
-  }
-}
-
-void FireShot_Draw(int k) {  // 88877c
-  static const uint8 kFireShot_Draw_X2[16] = {7, 0, 8, 0, 8, 4, 0, 0, 2, 8, 0, 0, 1, 4, 9, 0};
-  static const uint8 kFireShot_Draw_Y2[16] = {1, 4, 9, 0, 7, 0, 8, 0, 8, 4, 0, 0, 2, 8, 0, 0};
-  static const uint8 kFireShot_Draw_Char2[3] = {0x8d, 0x9d, 0x9c};
-  AncillaOamInfo info;
-  if (Ancilla_ReturnIfOutsideBounds(k, &info))
-    return;
-  if (ancilla_objprio[k])
-    info.flags |= 0x30;
-
-  OamEnt *oam = GetOamCurPtr();
-  int j = ancilla_item_to_link[k] & 0xc;
-  for (int i = 2; i >= 0; i--, oam++)
-    SetOamPlain(oam, info.x + kFireShot_Draw_X2[j + i], info.y + kFireShot_Draw_Y2[j + i], kFireShot_Draw_Char2[i], info.flags | 2, 0);
-}
-
-uint8 Ancilla_CheckTileCollision_staggered(int k) {  // 88897b
-  if ((frame_counter ^ k) & 1)
-    return Ancilla_CheckTileCollision(k);
-  return 0;
-}
-
-uint8 Ancilla_CheckTileCollision(int k) {  // 888981
-  if (!player_is_indoors && ancilla_objprio[k]) {
-    ancilla_tile_attr[k] = 0;
-    return 0;
-  }
-  if (!dung_hdr_collision)
-    return Ancilla_CheckTileCollisionOneFloor(k);
-  uint16 x = 0, y = 0;
-  if (dung_hdr_collision < 3) {
-    x = BG1HOFS_copy2 - BG2HOFS_copy2;
-    y = BG1VOFS_copy2 - BG2VOFS_copy2;
-  }
-  uint16 oldx = Ancilla_GetX(k), oldy = Ancilla_GetY(k);
-  Ancilla_SetX(k, oldx + x);
-  Ancilla_SetY(k, oldy + y);
-  ancilla_floor[k] = 1;
-  uint8 b = Ancilla_CheckTileCollisionOneFloor(k);
-  ancilla_floor[k] = 0;
-  Ancilla_SetX(k, oldx);
-  Ancilla_SetY(k, oldy);
-  return (b << 1) | (uint8)Ancilla_CheckTileCollisionOneFloor(k);
-}
-
-bool Ancilla_CheckTileCollisionOneFloor(int k) {  // 888a03
-  static const int8 kAncilla_CheckTileColl0_X[20] = {
-    8, 8, 0, 16, 4, 4, 0, 16, 4, 4, 4, 12, 12, 12, 4, 12, 0, 0, 0, 0,
-  };
-  static const int8 kAncilla_CheckTileColl0_Y[20] = {
-    0, 16, 5, 5, 0, 16, 4, 4, 4, 12, 5, 5, 4, 12, 12, 12, 0, 0, 0, 0,
-  };
-  uint16 x = Ancilla_GetX(k) + kAncilla_CheckTileColl0_X[ancilla_dir[k]];
-  uint16 y = Ancilla_GetY(k) + kAncilla_CheckTileColl0_Y[ancilla_dir[k]];
-  return Ancilla_CheckTileCollision_targeted(k, x, y);
-}
-
-bool Ancilla_CheckTileCollision_targeted(int k, uint16 x, uint16 y) {  // 888a26
-  if ((uint16)(y - BG2VOFS_copy2) >= 224 || (uint16)(x - BG2HOFS_copy2) >= 256)
-    return 0;
-  uint8 tile_attr;
-  if (!player_is_indoors) {
-    x >>= 3;
-    tile_attr = Overworld_GetTileAttributeAtLocation(x, y);
-  } else {
-    tile_attr = GetTileAttribute(ancilla_floor[k], &x, y);
-  }
-
-  ancilla_tile_attr[k] = tile_attr;
-  if (tile_attr == 3 && ancilla_floor2[k])
-    return 0;
-
-  uint8 t = kAncilla_TileColl0_Attrs[tile_attr];
-
-  if (ancilla_type[k] == 2 && (tile_attr & 0xf0) == 0xc0)
-    t = 0;
-
-  if (!ancilla_objprio[k]) {
-    if (t == 0)
-      return false;
-    if (t == 1)
-      goto return_true_set_alert;
-    if (t == 2)
-      return Entity_CheckSlopedTileCollision(x, y);
-    if (t == 3) {
-      if (ancilla_floor2[k])
-        goto return_true_set_alert;
-      return 0;
-    }
-  }
-  if (sign8(--ancilla_U[k])) {
-    ancilla_U[k] = 0;
-    if (t == 4) {
-      ancilla_U[k] = 6;
-      ancilla_objprio[k] ^= 1;
-    }
-  }
-  return 0;
-
-return_true_set_alert:
-  sprite_alert_flag = 3;
-  return 1;
-}
-
-bool Ancilla_CheckTileCollision_Class2(int k) {  // 888bcf
-  if (!dung_hdr_collision)
-    return Ancilla_CheckTileCollision_Class2_Inner(k);
-  uint16 x = 0, y = 0;
-  if (dung_hdr_collision < 3) {
-    x = BG1HOFS_copy2 - BG2HOFS_copy2;
-    y = BG1VOFS_copy2 - BG2VOFS_copy2;
-  }
-  uint16 oldx = Ancilla_GetX(k), oldy = Ancilla_GetY(k);
-  Ancilla_SetX(k, oldx + x);
-  Ancilla_SetY(k, oldy + y);
-  ancilla_floor[k] = 1;
-  bool b = Ancilla_CheckTileCollision_Class2_Inner(k);
-  ancilla_floor[k] = 0;
-  Ancilla_SetX(k, oldx);
-  Ancilla_SetY(k, oldy);
-  return (b | Ancilla_CheckTileCollision_Class2_Inner(k)) != 0;
-}
-
-bool Ancilla_CheckTileCollision_Class2_Inner(int k) {  // 888c43
-  static const int8 kAncilla_CheckTileColl_Y[4] = {-8, 8, 0, 0};
-  static const int8 kAncilla_CheckTileColl_X[4] = {0, 0, -8, 8};
-
-  uint16 x = Ancilla_GetX(k) + kAncilla_CheckTileColl_X[ancilla_dir[k]];
-  uint16 y = Ancilla_GetY(k) + kAncilla_CheckTileColl_Y[ancilla_dir[k]];
-
-  if ((uint16)(y - BG2VOFS_copy2) >= 224 || (uint16)(x - BG2HOFS_copy2) >= 256)
-    return false;
-  uint8 tile_attr;
-  if (!player_is_indoors) {
-    x >>= 3;
-    tile_attr = Overworld_GetTileAttributeAtLocation(x, y);
-  } else {
-    tile_attr = GetTileAttribute(ancilla_floor[k], &x, y);
-  }
-
-  ancilla_tile_attr[k] = tile_attr;
-  if (tile_attr == 3 && ancilla_floor2[k])
-    return false;
-
-  uint8 t = kAncilla_TileColl_Attrs[tile_attr];
-  if (t == 0)
-    return false;
-  if (t == 2)
-    return Entity_CheckSlopedTileCollision(x, y);
-  if (t == 4) {
-    if (ancilla_floor2[k])
-      return true;
-    ancilla_objprio[k] = 1;
-    return false;
-  }
-  if (t == 3)
-    return ancilla_floor2[k] != 0;
-  return true;
-}
-
-void Ancilla04_BeamHit(int k) {  // 888d19
-  static const int8 kBeamHit_X[16] = {-12, 20, -12, 20, -8, 16, -8, 16, -4, 12, -4, 12, 0, 8, 0, 8};
-  static const int8 kBeamHit_Y[16] = {-12, -12, 20, 20, -8, -8, 16, 16, -4, -4, 12, 12, 0, 0, 8, 8};
-  static const uint8 kBeamHit_Char[16] = {0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x54, 0x54, 0x54, 0x54};
-  static const uint8 kBeamHit_Flags[16] = {0x40, 0, 0xc0, 0x80, 0x40, 0, 0xc0, 0x80, 0x40, 0, 0xc0, 0x80, 0, 0x40, 0x80, 0xc0};
-  AncillaOamInfo info;
-  if (Ancilla_ReturnIfOutsideBounds(k, &info))
-    return;
-  if (!ancilla_timer[k]) {
-    ancilla_type[k] = 0;
-    return;
-  }
-  OamEnt *oam = GetOamCurPtr();
-  int j = ancilla_timer[k] >> 1;
-  uint16 ancilla_x = Ancilla_GetX(k);
-  uint16 ancilla_y = Ancilla_GetY(k);
-  uint8 r7 = ancilla_x - BG2HOFS_copy2;
-  uint8 r6 = ancilla_y - BG2VOFS_copy2;
-  for (int i = 3; i >= 0; i--, oam++) {
-    int m = j * 4 + i;
-    uint8 x = info.x + kBeamHit_X[m];
-    uint8 y = info.y + kBeamHit_Y[m];
-    uint16 x_adj = (uint16)(ancilla_x + (int8)(x - r7) - BG2HOFS_copy2);
-    uint16 y_adj = (uint16)(ancilla_y + (int8)(y - r6) - BG2VOFS_copy2 + 0x10);
-    SetOamPlain(oam, x, (y_adj >= 0x100) ? 0xf0 : y,
-                kBeamHit_Char[m] + 0x82, kBeamHit_Flags[m] | 2 | info.flags, (x_adj >= 0x100) ? 1 : 0);
-  }
-}
-
-int Ancilla_CheckSpriteCollision(int k) {  // 888d68
-  for (int j = 15; j >= 0; j--) {
-    if (ancilla_type[k] == 9 || ancilla_type[k] == 0x1f || ((j ^ frame_counter) & 3 | sprite_pause[j]) == 0) {
-      if ((sprite_state[j] >= 9 && (sprite_defl_bits[j] & 2 || !ancilla_objprio[k])) && ancilla_floor[k] == sprite_floor[j]) {
-        if (Ancilla_CheckSpriteCollision_Single(k, j))
-          return j;
-      }
-    }
-  }
-  return -1;
-}
-
-bool Ancilla_CheckSpriteCollision_Single(int k, int j) {  // 888dae
-  int i;
-  SpriteHitBox hb;
-  Ancilla_SetupHitBox(k, &hb);
-
-  Sprite_SetupHitBox(j, &hb);
-  if (!CheckIfHitBoxesOverlap(&hb))
-    return false;
-
-  bool return_value = true;
-  if (sprite_flags[j] & 8 && ancilla_type[k] == 9) {
-    if (sprite_type[j] != 0x1b) {
-      Sprite_CreateDeflectedArrow(k);
-      return false;
-    }
-    if (link_item_bow < 3) {
-      Sprite_CreateDeflectedArrow(k);
-    } else {
-      return_value = false;
-    }
-  }
-
-  if (sprite_defl_bits[j] & 0x10) {
-    static const uint8 kAncilla_CheckSpriteColl_Dir[4] = {2, 3, 0, 1};
-    ancilla_dir[k] &= 3;
-    if (ancilla_dir[k] == kAncilla_CheckSpriteColl_Dir[ancilla_dir[k]])
-      goto return_true_set_alert;
-  }
-
-  if (ancilla_type[k] == 5 || ancilla_type[k] == 0x1f) {
-    if (ancilla_type[k] == 0x1f && sprite_type[j] == 0x8d)
-      goto skip;
-    if (sprite_hit_timer[j])
-      goto return_true_set_alert;
-    if (sprite_defl_bits[j] & 2) {
-skip:
-      sprite_B[j] = k + 1;
-      sprite_unk2[j] = ancilla_type[k];
-      goto return_true_set_alert;
-    }
-  }
-
-  if (!sprite_ignore_projectile[j]) {
-    static const int8 kAncilla_CheckSpriteColl_RecoilX[4] = {0, 0, -64, 64};
-    static const int8 kAncilla_CheckSpriteColl_RecoilY[4] = {-64, 64, 0, 0};
-    if (sprite_type[j] == 0x92 && sprite_C[j] < 3)
-      goto return_true_set_alert;
-    i = ancilla_dir[k] & 3;
-    sprite_x_recoil[j] = kAncilla_CheckSpriteColl_RecoilX[i];
-    sprite_y_recoil[j] = kAncilla_CheckSpriteColl_RecoilY[i];
-    byte_7E0FB6 = k;
-    Ancilla_CheckDamageToSprite(j, ancilla_type[k]);
-return_true_set_alert:
-    sprite_unk2[j] = ancilla_type[k];
-    sprite_alert_flag = 3;
-    return return_value;
-  }
-  return false;
-}
-
-void Ancilla_SetupHitBox(int k, SpriteHitBox *hb) {  // 888ead
-  static const int8 kAncilla_HitBox_X[12] = {4, 4, 4, 4, 3, 3, 2, 11, -16, -16, -1, -8};
-  static const int8 kAncilla_HitBox_Y[12] = {4, 4, 4, 4, 2, 11, 3, 3, -1, -8, -16, -16};
-  static const uint8 kAncilla_HitBox_W[12] = {8, 8, 8, 8, 1, 1, 1, 1, 32, 32, 8, 8};
-  static const uint8 kAncilla_HitBox_H[12] = {8, 8, 8, 8, 1, 1, 1, 1, 8, 8, 32, 32};
-  int j = ancilla_dir[k];
-  if (ancilla_type[k] == 0xc)
-    j |= 8;
-  int x = Ancilla_GetX(k) + kAncilla_HitBox_X[j];
-  hb->r0_xlo = x;
-  hb->r8_xhi = x >> 8;
-  int y = Ancilla_GetY(k) + kAncilla_HitBox_Y[j];
-  hb->r1_ylo = y;
-  hb->r9_yhi = y >> 8;
-  hb->r2 = kAncilla_HitBox_W[j];
-  hb->r3 = kAncilla_HitBox_H[j];
-}
-
-ProjectSpeedRet Ancilla_ProjectSpeedTowardsPlayer(int k, uint8 vel) {  // 888eed
-  if (vel == 0) {
-    ProjectSpeedRet rv = { 0, 0, 0, 0 };
-    return rv;
-  }
-  PairU8 below = Ancilla_IsBelowLink(k);
-  uint8 r12 = sign8(below.b) ? -below.b : below.b;
-
-  PairU8 right = Ancilla_IsRightOfLink(k);
-  uint8 r13 = sign8(right.b) ? -right.b : right.b;
-  uint8 t;
-  bool swapped = false;
-  if (r13 < r12) {
-    swapped = true;
-    t = r12, r12 = r13, r13 = t;
-  }
-  uint8 xvel = vel, yvel = 0;
-  t = 0;
-  do {
-    t += r12;
-    if (t >= r13)
-      t -= r13, yvel++;
-  } while (--vel);
-  if (swapped)
-    t = xvel, xvel = yvel, yvel = t;
-  ProjectSpeedRet rv = {
-    (uint8)(right.a ? -xvel : xvel),
-    (uint8)(below.a ? -yvel : yvel),
-    right.b,
-    below.b
-  };
-  return rv;
-}
-
-PairU8 Ancilla_IsRightOfLink(int k) {  // 888f5c
-  uint16 x = link_x_coord - Ancilla_GetX(k);
-  PairU8 rv = { (uint8)(sign16(x) ? 1 : 0), (uint8)x };
-  return rv;
-}
-
-PairU8 Ancilla_IsBelowLink(int k) {  // 888f6f
-  int y = link_y_coord - Ancilla_GetY(k);
-  PairU8 rv = { (uint8)(sign16(y) ? 1 : 0), (uint8)y };
-  return rv;
-}
-
-void Ancilla_WeaponTink() {  // 888f89
-  if (!repulsespark_timer)
-    return;
-  sprite_alert_flag = 2;
-  if (sign8(--repulsespark_anim_delay)) {
-    repulsespark_timer--;
-    repulsespark_anim_delay = 1;
-  }
-
-  if (sort_sprites_setting) {
-    if (repulsespark_floor_status)
-      Oam_AllocateFromRegionF(0x10);
-    else
-      Oam_AllocateFromRegionD(0x10);
-  } else {
-    Oam_AllocateFromRegionA(0x10);
-  }
-
-  uint8 x = repulsespark_x_lo - BG2HOFS_copy2;
-  uint8 y = repulsespark_y_lo - BG2VOFS_copy2;
-
-  if (x >= 0xf8 || y >= 0xf0) {
-    repulsespark_timer = 0;
-    return;
-  }
-
-  OamEnt *oam = GetOamCurPtr();
-  static const uint8 kRepulseSpark_Flags[4] = {0x22, 0x12, 0x22, 0x22};
-  uint8 flags = kRepulseSpark_Flags[repulsespark_floor_status];
-  if (repulsespark_timer >= 3) {
-    SetOamPlain(oam, x, y, (repulsespark_timer < 9) ? 0x92 : 0x80, flags, 0);
-    return;
-  }
-  static const uint8 kRepulseSpark_Char[3] = { 0x93, 0x82, 0x81 };
-  uint8 c = kRepulseSpark_Char[repulsespark_timer];
-  SetOamPlain(oam + 0, x - 4, y - 4, c, flags | 0x00, 0);
-  SetOamPlain(oam + 1, x + 4, y - 4, c, flags | 0x40, 0);
-  SetOamPlain(oam + 2, x - 4, y + 4, c, flags | 0x80, 0);
-  SetOamPlain(oam + 3, x + 4, y + 4, c, flags | 0xc0, 0);
-}
-
-void Ancilla_MoveX(int k) {  // 889080
-  uint32 t = ancilla_x_subpixel[k] + (ancilla_x_lo[k] << 8) + (ancilla_x_hi[k] << 16) + ((int8)ancilla_x_vel[k] << 4);
-  ancilla_x_subpixel[k] = t, ancilla_x_lo[k] = t >> 8, ancilla_x_hi[k] = t >> 16;
-}
-
-void Ancilla_MoveY(int k) {  // 88908b
-  uint32 t = ancilla_y_subpixel[k] + (ancilla_y_lo[k] << 8) + (ancilla_y_hi[k] << 16) + ((int8)ancilla_y_vel[k] << 4);
-  ancilla_y_subpixel[k] = t, ancilla_y_lo[k] = t >> 8, ancilla_y_hi[k] = t >> 16;
-}
-
-void Ancilla_MoveZ(int k) {  // 8890b7
-  uint32 t = ancilla_z_subpixel[k] + (ancilla_z[k] << 8) + ((int8)ancilla_z_vel[k] << 4);
-  ancilla_z_subpixel[k] = t, ancilla_z[k] = t >> 8;
-}
-
-void Ancilla05_Boomerang(int k) {  // 8890fc
-  int hit_spr;
-  static const int8 kBoomerang_X0[8] = {0, 0, -8, 8, 8, 8, -8, -8};
-  static const int8 kBoomerang_Y0[8] = {-16, 6, 0, 0, -8, 8, -8, 8};
-
-  for (int j = 4; j >= 0; j--) {
-    if (ancilla_type[j] == 0x22)
-      goto exit_and_draw;
-  }
-  if (submodule_index)
-    goto exit_and_draw;
-
-  if (!(frame_counter & 7))
-    Ancilla_Sfx2_Pan(k, 0x9);
-
-  if (!ancilla_aux_timer[k]) {
-    if (button_b_frames < 9 && player_handler_timer == 0) {
-      if (link_is_bunny_mirror || link_auxiliary_state || link_item_in_hand == 0 && (enhanced_features0 & kFeatures0_MiscBugFixes)) {
-        Boomerang_Terminate(k);
-        return;
-      }
-      goto exit_and_draw;
-    }
-    int j = ancilla_arr23[k] >> 1;
-    Ancilla_SetXY(k, link_x_coord + kBoomerang_X0[j], link_y_coord + 8 + kBoomerang_Y0[j]);
-    ancilla_aux_timer[k]++;
-  }
-  // endif_2
-  if (ancilla_G[k] && !(frame_counter & 1))
-    AncillaAdd_SwordChargeSparkle(k);
-
-  if (ancilla_item_to_link[k]) {
-    if (ancilla_K[k])
-      ancilla_K[k]++;
-    WORD(ancilla_A[k]) = link_y_coord;
-    link_y_coord += 8;
-    ProjectSpeedRet pt = Ancilla_ProjectSpeedTowardsPlayer(k, ancilla_H[k]);
-    Boomerang_CheatWhenNoOnesLooking(k, &pt);
-    ancilla_x_vel[k] = pt.x;
-    ancilla_y_vel[k] = pt.y;
-    link_y_coord = WORD(ancilla_A[k]);
-  }
-
-  if (ancilla_y_vel[k])
-    ancilla_y_vel[k] += ancilla_K[k];
-  Ancilla_MoveY(k);
-
-  if (ancilla_x_vel[k])
-    ancilla_x_vel[k] += ancilla_K[k];
-  Ancilla_MoveX(k);
-  hit_spr = Ancilla_CheckSpriteCollision(k);
-
-  if (!ancilla_item_to_link[k]) {
-    if (hit_spr >= 0) {
-      ancilla_item_to_link[k] ^= 1;
-    } else if (Ancilla_CheckTileCollision(k)) {
-      AncillaAdd_BoomerangWallClink(k);
-      Ancilla_Sfx2_Pan(k, (ancilla_tile_attr[k] == 0xf0) ? 6 : 5);
-      ancilla_item_to_link[k] ^= 1;
-    } else if (Boomerang_ScreenEdge(k) || --ancilla_step[k] == 0) {
-      ancilla_item_to_link[k] ^= 1;
-    } else {
-      if (ancilla_step[k] < 5)
-        ancilla_K[k]--;
-    }
-  } else {
-    uint8 bak0 = ancilla_objprio[k];
-    uint8 bak1 = ancilla_floor[k];
-    ancilla_floor[k] = 0;
-    Ancilla_CheckTileCollision(k);
-    ancilla_floor[k] = bak1;
-    ancilla_objprio[k] = bak0;
-    Boomerang_StopOffScreen(k);
-  }
-
-exit_and_draw:
-  Boomerang_Draw(k);
-}
-
-bool Boomerang_ScreenEdge(int k) {  // 88924b
-  uint16 x = Ancilla_GetX(k), y = Ancilla_GetY(k);
-  if (hookshot_effect_index & 3) {
-    uint16 t = x + (hookshot_effect_index & 1 ? 16 : 0) - BG2HOFS_copy2;
-    if (t >= 0x100)
-      return true;
-  }
-  if (hookshot_effect_index & 12) {
-    uint16 t = y + (hookshot_effect_index & 4 ? 16 : 0) - BG2VOFS_copy2;
-    if (t >= 0xe2)
-      return true;
-  }
-  return false;
-}
-
-void Boomerang_StopOffScreen(int k) {  // 8892ab
-  uint16 x = Ancilla_GetX(k) + 8, y = Ancilla_GetY(k) + 8;
-  if (x >= link_x_coord && x < (uint16)(link_x_coord + 16) &&
-      y >= link_y_coord && y < (uint16)(link_y_coord + 24))
-    Boomerang_Terminate(k);
-}
-
-void Boomerang_Terminate(int k) {  // 8892f5
-  ancilla_type[k] = 0;
-  flag_for_boomerang_in_place = 0;
-  if (link_item_in_hand & 0x80) {
-    link_item_in_hand = 0;
-    button_mask_b_y &= ~0x40;
-    if (!(button_mask_b_y & 0x80))
-      link_cant_change_direction &= ~1;
-  }
-}
-
-void Boomerang_Draw(int k) {  // 889338
-  static const uint8 kBoomerang_Flags[8] = {0xa4, 0xe4, 0x64, 0x24, 0xa2, 0xe2, 0x62, 0x22};
-  static const int8 kBoomerang_Draw_XY[8] = {2, -2, 2, 2, -2, 2, -2, -2};
-  static const uint16 kBoomerang_Draw_OamIdx[2] = {0x180, 0xd0};
-  static const uint8 kBoomerang_Draw_Tab0[2] = {3, 2};
-  Point16U info;
-  Ancilla_PrepOamCoord(k, &info);
-
-  if (ancilla_item_to_link[k]) {
-    ancilla_floor[k] = link_is_on_lower_level;
-    oam_priority_value = kTagalongLayerBits[link_is_on_lower_level] << 8;
-  }
-
-  if (ancilla_objprio[k])
-    oam_priority_value = 0x3000;
-
-  if (!submodule_index && ancilla_aux_timer[k] && sign8(--ancilla_arr3[k])) {
-    ancilla_arr3[k] = kBoomerang_Draw_Tab0[ancilla_G[k]];
-    ancilla_arr1[k] = (ancilla_arr1[k] + (ancilla_S[k] ? -1 : 1)) & 3;
-  }
-
-  int j = ancilla_arr1[k];
-  uint16 x = info.x + kBoomerang_Draw_XY[j * 2 + 1];
-  uint16 y = info.y + kBoomerang_Draw_XY[j * 2 + 0];
-  if (!ancilla_aux_timer[k]) {
-    int i = kBoomerang_Draw_OamIdx[sort_sprites_setting];
-    oam_ext_cur_ptr = (i >> 2) + 0xa20;
-    oam_cur_ptr = i + 0x800;
-  }
-  Ancilla_SetOam_Safe(GetOamCurPtr(), x, y, 0x26, kBoomerang_Flags[ancilla_G[k] * 4 + j] & ~0x30 | HIBYTE(oam_priority_value), 2);
-}
-
-void Ancilla06_WallHit(int k) {  // 8893e8
-  if (sign8(--ancilla_arr3[k])) {
-    uint8 t = ancilla_item_to_link[k] + 1;
-    if (t == 5) {
-      ancilla_type[k] = 0;
-      return;
-    }
-    ancilla_item_to_link[k] = t;
-    ancilla_arr3[k] = 1;
-  }
-  WallHit_Draw(k);
-}
-
-void Ancilla_SwordWallHit(int k) {  // 8893ff
-  sprite_alert_flag = 3;
-  if (sign8(--ancilla_aux_timer[k])) {
-    uint8 t = ancilla_item_to_link[k] + 1;
-    if (t == 8) {
-      ancilla_type[k] = 0;
-      return;
-    }
-    ancilla_item_to_link[k] = t;
-    ancilla_aux_timer[k] = 1;
-  }
-  WallHit_Draw(k);
-}
-
-void WallHit_Draw(int k) {  // 8894df
-  static const int8 kWallHit_X[32] = {
-    -4, 0,  0, 0, -4, 0, 0, 0, -8, 0, -8, 0, -8, 0, -8, 0,
-    -8, 0, -8, 0, -4, 0, 0, 0, -4, 0,  0, 0, -8, 0,  0, 0,
-  };
-  static const int8 kWallHit_Y[32] = {
-    -4,  0, 0, 0, -4, 0, 0, 0, -8, -8, 0, 0, -8, -8, 0, 0,
-    -8, -8, 0, 0, -4, 0, 0, 0, -4,  0, 0, 0, -8,  0, 0, 0,
-  };
-  static const uint8 kWallHit_Char[32] = {
-    0x80,    0,    0,    0, 0x92, 0, 0, 0, 0x81, 0x81, 0x81, 0x81, 0x82, 0x82, 0x82, 0x82,
-    0x93, 0x93, 0x93, 0x93, 0x92, 0, 0, 0, 0xb9,    0,    0,    0, 0x90, 0x90,    0,    0,
-  };
-  static const uint8 kWallHit_Flags[32] = {
-    0x32,    0,    0,    0, 0x32, 0, 0, 0, 0x32, 0x72, 0xb2, 0xf2, 0x32, 0x72, 0xb2, 0xf2,
-    0x32, 0x72, 0xb2, 0xf2, 0x32, 0, 0, 0, 0x72,    0,    0,    0, 0x32, 0xf2,    0,    0,
-  };
-  Point16U info;
-  Ancilla_PrepOamCoord(k, &info);
-
-  int t = ancilla_item_to_link[k] * 4;
-
-  OamEnt *oam = GetOamCurPtr();
-  for (int n = 3; n >= 0; n--, t++) {
-    if (kWallHit_Char[t] != 0) {
-      Ancilla_SetOam(oam, info.x + kWallHit_X[t], info.y + kWallHit_Y[t], kWallHit_Char[t],
-                     kWallHit_Flags[t] & ~0x30 | HIBYTE(oam_priority_value), 0);
-      oam++;
-    }
-    oam = Ancilla_AllocateOamFromCustomRegion(oam);
-  }
-
-}
-
-void Ancilla07_Bomb(int k) {  // 88955a
-  if (submodule_index) {
-    if (submodule_index == 8 || submodule_index == 16) {
-      Ancilla_HandleLiftLogic(k);
-    } else if (k + 1 == flag_is_ancilla_to_pick_up && ancilla_K[k] != 0) {
-      if (ancilla_K[k] != 3) {
-        Ancilla_LatchLinkCoordinates(k, 3);
-        Ancilla_LatchAltitudeAboveLink(k);
-        ancilla_K[k] = 3;
-      }
-      Ancilla_LatchCarriedPosition(k);
-    }
-    Bomb_Draw(k);
-    return;
-  }
-  Ancilla_HandleLiftLogic(k);
-
-  uint16 old_y = Ancilla_LatchYCoordToZ(k);
-  uint8 s1a = ancilla_dir[k];
-  uint8 s1b = ancilla_objprio[k];
-  ancilla_objprio[k] = 0;
-  bool flag = Ancilla_CheckTileCollision_Class2(k);
-
-  if (player_is_indoors && ancilla_L[k] && ancilla_tile_attr[k] == 0x1c)
-    ancilla_T[k] = 1;
-
-label1:
-  if (flag && (!(link_state_bits & 0x80) || link_picking_throw_state)) {
-    if (!s1b && !ancilla_arr4[k]) {
-      ancilla_arr4[k] = 1;
-      int qq = (ancilla_dir[k] == 1) ? 16 : 4;
-      if (ancilla_y_vel[k])
-        ancilla_y_vel[k] = sign8(ancilla_y_vel[k]) ? qq : -qq;
-      if (ancilla_x_vel[k])
-        ancilla_x_vel[k] = sign8(ancilla_x_vel[k]) ? 4 : -4;
-      if (ancilla_dir[k] == 1 && ancilla_z[k]) {
-        ancilla_y_vel[k] = -4;
-        ancilla_L[k] = 2;
-      }
-    }
-  } else if (!((k + 1 == flag_is_ancilla_to_pick_up) && (link_state_bits & 0x80)) && (ancilla_z[k] == 0 || ancilla_z[k] == 0xff)) {
-    ancilla_dir[k] = 16;
-    uint8 bak0 = ancilla_objprio[k];
-    Ancilla_CheckTileCollision(k);
-    ancilla_objprio[k] = bak0;
-    uint8 a = ancilla_tile_attr[k];
-    if (a == 0x26) {
-      flag = true;
-      goto label1;
-    } else if (a == 0xc || a == 0x1c) {
-      if (dung_hdr_collision != 3) {
-        if (ancilla_floor[k] == 0 && ancilla_z[k] != 0 && ancilla_z[k] != 0xff)
-          ancilla_floor[k] = 1;
-      } else {
-        old_y = Ancilla_GetY(k) + dung_floor_y_vel;
-        Ancilla_SetX(k, Ancilla_GetX(k) + dung_floor_x_vel);
-      }
-    } else if (a == 0x20 || (a & 0xf0) == 0xb0 && a != 0xb6 && a != 0xbc) {
-      if (!(link_state_bits & 0x80)) {
-        if (k + 1 == flag_is_ancilla_to_pick_up)
-          flag_is_ancilla_to_pick_up = 0;
-        if (!ancilla_timer[k]) {
-          ancilla_type[k] = 0;
-          return;
-        }
-      }
-    } else if (a == 8) {
-      if (k + 1 == flag_is_ancilla_to_pick_up)
-        flag_is_ancilla_to_pick_up = 0;
-      if (ancilla_timer[k] == 0) {
-        Ancilla_SetY(k, Ancilla_GetY(k) - 24);
-        Ancilla_TransmuteToSplash(k);
-        return;
-      }
-    } else if (a == 0x68 || a == 0x69 || a == 0x6a || a == 0x6b) {
-      Ancilla_ApplyConveyor(k);
-      old_y = Ancilla_GetY(k);
-    } else {
-      ancilla_timer[k] = ancilla_L[k] ? 0 : 2;
-    }
-  }
-  // endif_3
-
-  Ancilla_SetY(k, old_y);
-  ancilla_dir[k] = s1a;
-  ancilla_objprio[k] |= s1b;
-  Bomb_CheckSpriteAndPlayerDamage(k);
-  if (!--ancilla_arr3[k]) {
-    if (++ancilla_item_to_link[k] == 1) {
-      Ancilla_Sfx2_Pan(k, 0xc);
-      if (k + 1 == flag_is_ancilla_to_pick_up) {
-        flag_is_ancilla_to_pick_up = 0;
-        if (link_state_bits & 0x80) {
-          link_state_bits = 0;
-          link_cant_change_direction = 0;
-        }
-      }
-    }
-
-    if (ancilla_item_to_link[k] == 11) {
-      // transmute to door debris?
-      ancilla_type[k] = ancilla_step[k] ? 8 : 0;
-      return;
-    }
-    ancilla_arr3[k] = kBomb_Tab0[ancilla_item_to_link[k]];
-  }
-
-  if (ancilla_item_to_link[k] == 7 && ancilla_arr3[k] == 2) {
-    // check whether the bomb causes any door debris, the bomb
-    // will transmute to debris later on.
-    door_debris_x[k] = 0;
-    Bomb_CheckForDestructibles(Ancilla_GetX(k), Ancilla_GetY(k), k);
-    if (door_debris_x[k])
-      ancilla_step[k] = 1;
-  }
-  Bomb_Draw(k);
-}
-
-void Ancilla_ApplyConveyor(int k) {  // 8897be
-  static const int8 kAncilla_Belt_Xvel[4] = {0, 0, -8, 8};
-  static const int8 kAncilla_Belt_Yvel[4] = {-8, 8, 0, 0};
-  int j = ancilla_tile_attr[k] - 0x68;
-  ancilla_y_vel[k] = kAncilla_Belt_Yvel[j];
-  ancilla_x_vel[k] = kAncilla_Belt_Xvel[j];
-  Ancilla_MoveY(k);
-  Ancilla_MoveX(k);
-}
-
-void Bomb_CheckSpriteAndPlayerDamage(int k) {  // 889815
-  static const uint8 kBomb_Dmg_Speed[16] = {32, 32, 32, 32, 32, 32, 28, 28, 28, 28, 28, 28, 24, 24, 24, 24};
-  static const uint8 kBomb_Dmg_Zvel[16] = {16, 16, 16, 16, 16, 16, 12, 12, 12, 12, 8, 8, 8, 8, 8, 8};
-  static const uint8 kBomb_Dmg_Delay[16] = {32, 32, 32, 32, 32, 32, 24, 24, 24, 24, 24, 24, 16, 16, 16, 16};
-  static const uint8 kBomb_Dmg_ToLink[3] = {8, 4, 2};
-
-  if (ancilla_item_to_link[k] == 0 || ancilla_item_to_link[k] >= 9)
-    return;
-  Bomb_CheckSpriteDamage(k);
-  if (link_disable_sprite_damage) {
-    if (k + 1 == flag_is_ancilla_to_pick_up && link_state_bits & 0x80) {
-      link_state_bits &= ~0x80;
-      link_cant_change_direction = 0;
-    }
-    return;
-  }
-
-  if (link_auxiliary_state || link_incapacitated_timer || ancilla_floor[k] != link_is_on_lower_level)
-    return;
-
-  SpriteHitBox hb;
-  hb.r0_xlo = link_x_coord;
-  hb.r8_xhi = link_x_coord >> 8;
-  hb.r1_ylo = link_y_coord;
-  hb.r9_yhi = link_y_coord >> 8;
-  hb.r2 = 0x10;
-  hb.r3 = 0x18;
-
-  int ax = Ancilla_GetX(k) - 16, ay = Ancilla_GetY(k) - 16;
-  hb.r6_spr_xsize = 32;
-  hb.r7_spr_ysize = 32;
-  hb.r4_spr_xlo = ax;
-  hb.r10_spr_xhi = ax >> 8;
-  hb.r5_spr_ylo = ay;
-  hb.r11_spr_yhi = ay >> 8;
-
-  if (!CheckIfHitBoxesOverlap(&hb))
-    return;
-
-  int x = Ancilla_GetX(k) - 8, y = Ancilla_GetY(k) - 12;
-
-  int j = Bomb_GetDisplacementFromLink(k);
-  ProjectSpeedRet pt = Bomb_ProjectSpeedTowardsPlayer(k, x, y, kBomb_Dmg_Speed[j]);
-  if (countdown_for_blink || flag_block_link_menu == 2)
-    return;
-  link_actual_vel_x = pt.x;
-  link_actual_vel_y = pt.y;
-
-  link_actual_vel_z_copy = link_actual_vel_z = kBomb_Dmg_Zvel[j];
-  link_incapacitated_timer = kBomb_Dmg_Delay[j];
-  link_auxiliary_state = 1;
-  countdown_for_blink = 58;
-  if (!(dung_savegame_state_bits & 0x8000))
-    link_give_damage = kBomb_Dmg_ToLink[link_armor];
-
-}
-
-void Ancilla_HandleLiftLogic(int k) {  // 889976
-  static const uint8 kAncilla_Liftable_Delay[3] = {16, 8, 9};
-
-  if (ancilla_R[k]) {
-label_6:
-    if (ancilla_item_to_link[k])
-      return;
-    if (ancilla_K[k] == 3) {
-      ancilla_z_vel[k] -= 2;
-      Ancilla_MoveZ(k);
-      if (ancilla_z[k] && ancilla_z[k] < 252)
-        return;
-      ancilla_z[k] = 0;
-      if (++ancilla_R[k] != 3) {
-        ancilla_z_vel[k] = 24;
-        return;
-      }
-      ancilla_K[k] = 0;
-    }
-    ancilla_R[k] = 0;
-    link_speed_setting = 0;
-    return;
-  }
-  if (!ancilla_L[k]) {
-    if (!flag_is_ancilla_to_pick_up) {
-clear_pickup_item:
-      flag_is_ancilla_to_pick_up = 0;
-      CheckPlayerCollOut coll;
-      if (ancilla_item_to_link[k] || link_state_bits || !Ancilla_CheckLinkCollision(k, 0, &coll) || ancilla_floor[k] != link_is_on_lower_level)
-        return;
-      if (coll.r8 >= 16 || coll.r10 >= 12) {
-        int j = (coll.r8 >= coll.r10) ? (sign8(coll.r4) ? 1 : 0) : (sign8(coll.r6) ? 3 : 2);
-        if (j * 2 != link_direction_facing)
-          return;
-      }
-      flag_is_ancilla_to_pick_up = k + 1;
-      ancilla_K[k] = 0;
-      ancilla_aux_timer[k] = kAncilla_Liftable_Delay[0];
-      ancilla_L[k] = 0;
-      ancilla_z[k] = 0;
-      return;
-    }
-
-    if (flag_is_ancilla_to_pick_up != k + 1)
-      return;
-    if (!link_disable_sprite_damage && link_incapacitated_timer || byte_7E03FD || link_auxiliary_state == 1) {
-      ancilla_R[k] = 1;
-      ancilla_z_vel[k] = 0;
-      flag_is_ancilla_to_pick_up = 0;
-      ancilla_arr4[k] = 0;
-      goto label_6;
-    }
-    if (!(link_state_bits & 0x80))
-      goto clear_pickup_item;
-    int j = ancilla_K[k];
-    if (link_picking_throw_state != 2 && flag_is_ancilla_to_pick_up != 0 && j != 3) {
-      if (j == 0 && ancilla_aux_timer[k] == 16)
-        Ancilla_Sfx2_Pan(k, 0x1d);
-      if (sign8(--ancilla_aux_timer[k])) {
-        ancilla_K[k] = ++j;
-        ancilla_aux_timer[k] = j == 3 ? -2 : kAncilla_Liftable_Delay[j];
-        if (j == 3) {
-          Ancilla_LatchAltitudeAboveLink(k);
-          return;
-        }
-      }
-      Ancilla_LatchLinkCoordinates(k, j);
-      return;
-    }
-    if (j != 3)
-      return;
-
-    if (link_picking_throw_state != 2 && (submodule_index != 0 || !((filtered_joypad_L | filtered_joypad_H) & 0x80))) {
-      if (ancilla_item_to_link[k])
-        return;
-      if (player_near_pit_state >= 2) {
-        link_speed_setting = 0;
-        if (k + 1 == flag_is_ancilla_to_pick_up) {
-          flag_is_ancilla_to_pick_up = 0;
-          ancilla_type[k] = 0;
-        }
-        return;
-      }
-      if (!(link_is_in_deep_water | link_is_bunny_mirror)) {
-        Ancilla_LatchCarriedPosition(k);
-        return;
-      }
-      link_state_bits = 0;
-    }
-    static const int8 kAncilla_Liftable_Yvel[4] = {-32, 32, 0, 0};
-    static const int8 kAncilla_Liftable_Xvel[4] = {0, 0, -32, 32};
-    j = link_direction_facing >> 1;
-    ancilla_dir[k] = j;
-    ancilla_z_vel[k] = 24;
-    ancilla_y_vel[k] = kAncilla_Liftable_Yvel[j];
-    ancilla_x_vel[k] = kAncilla_Liftable_Xvel[j];
-    link_picking_throw_state = 2;
-    ancilla_L[k] = 1;
-    flag_is_ancilla_to_pick_up = 0;
-    ancilla_arr4[k] = 0;
-    ancilla_K[k] = 0;
-    ancilla_objprio[k] = 0;
-    Ancilla_Sfx3_Pan(k, 0x13);
-  }
-  // endif_1
-  if (!ancilla_item_to_link[k]) {
-    ancilla_z_vel[k] -= 2;
-    Ancilla_MoveY(k);
-    Ancilla_MoveX(k);
-    uint8 old_z = ancilla_z[k];
-    Ancilla_MoveZ(k);
-    if (ancilla_arr4[k] && ancilla_dir[k] == 1 && !sign8(ancilla_z[k]))
-      Ancilla_SetY(k, Ancilla_GetY(k) + (int8)(ancilla_z[k] - old_z));
-    if (!sign8(ancilla_z[k]) || ancilla_z[k] == 0xff)
-      return;
-    ancilla_z[k] = 0;
-    Ancilla_Sfx2_Pan(k, 0x21);
-    if (++ancilla_L[k] != 3) {
-      ancilla_y_vel[k] = (int8)ancilla_y_vel[k] / 2;
-      ancilla_x_vel[k] = (int8)ancilla_x_vel[k] / 2;
-      ancilla_z_vel[k] = 16;
-      ancilla_arr4[k] = 0;
-    } else {
-      ancilla_z[k] = 0;
-      ancilla_L[k] = 0;
-      ancilla_arr4[k] = 0;
-      link_speed_setting = 0;
-      ancilla_y_vel[k] = 0;
-      ancilla_x_vel[k] = 0;
-      ancilla_z_vel[k] = 0;
-      if (ancilla_T[k]) {
-        ancilla_floor[k] = ancilla_T[k];
-        ancilla_T[k] = 0;
-      }
-    }
-  }
-}
-
-void Ancilla_LatchAltitudeAboveLink(int k) {  // 889a4f
-  ancilla_z[k] = 17;
-  Ancilla_SetY(k, Ancilla_GetY(k) + 17);
-  ancilla_objprio[k] = 0;
-}
-
-void Ancilla_LatchLinkCoordinates(int k, int j) {  // 889a6a
-  static const int8 kAncilla_Func3_X[12] = {8, 8, -4, 20, 8, 8, 8, 8, 8, 8, 8, 8};
-  static const int8 kAncilla_Func3_Y[12] = {16, 8, 4, 4, 8, 2, -1, -1, 2, 2, -1, -1};
-  j = j * 4 + (link_direction_facing >> 1);
-  Ancilla_SetXY(k,
-      link_x_coord + kAncilla_Func3_X[j],
-      link_y_coord + kAncilla_Func3_Y[j]);
-}
-
-void Ancilla_LatchCarriedPosition(int k) {  // 889bef
-  static const int8 kAncilla_Func2_Y[6] = {-2, -1, 0, -2, -1, 0};
-  link_speed_setting = 12;
-  ancilla_floor[k] = link_is_on_lower_level;
-  ancilla_floor2[k] = link_is_on_lower_level_mirror;
-  uint16 z = link_z_coord;
-  if (z == 0xffff)
-    z = 0;
-  Ancilla_SetXY(k,
-    link_x_coord + 8,
-    link_y_coord - z + 18 + kAncilla_Func2_Y[link_animation_steps]);
-}
-
-uint16 Ancilla_LatchYCoordToZ(int k) {  // 889c7f
-  uint16 y = Ancilla_GetY(k);
-  int8 z = ancilla_z[k];
-  if (ancilla_dir[k] == 1 && z != -1)
-    Ancilla_SetY(k, y - z);
-  return y;
-}
-
-int Bomb_GetDisplacementFromLink(int k) {  // 889cce
-  int x = Ancilla_GetX(k), y = Ancilla_GetY(k);
-  return ((abs16(link_x_coord + 8 - x) + abs16(link_y_coord + 12 - y)) & 0xfc) >> 2;
-}
-
-void Bomb_Draw(int k) {  // 889e9e
-  Point16U pt;
-  Ancilla_PrepAdjustedOamCoord(k, &pt);
-
-  int z = (int8)ancilla_z[k];
-  if (z != 0 && z != -1 && ancilla_K[k] != 3 && ancilla_objprio[k])
-    oam_priority_value = 0x3000;
-  pt.y -= z;
-  int j = kBomb_Draw_Tab0[ancilla_item_to_link[k]] * 6;
-
-  uint8 r11 = 2;
-  if (ancilla_item_to_link[k] == 0) {
-    r11 = (ancilla_arr3[k] < 0x20) ? ancilla_arr3[k] & 0xe : 4;
-  }
-
-  if (ancilla_item_to_link[k] == 0) {
-    if (ancilla_L[k] == 0 && (sprite_type[0] == 0x92 || k + 1 == flag_is_ancilla_to_pick_up ) && (!(link_state_bits & 0x80) || ancilla_K[k] != 3 && link_direction_facing == 0)) {
-      Ancilla_AllocateOamFromRegion_B_or_E(12);
-    } else if (sort_sprites_setting && ancilla_floor[k] && (ancilla_L[k] || k + 1 == flag_is_ancilla_to_pick_up && (link_state_bits & 0x80))) {
-      oam_cur_ptr = 0x800 + 0x34 * 4;
-      oam_ext_cur_ptr = 0xa20 + 0x34;
-    }
-  }
-
-  OamEnt *oam = GetOamCurPtr(), *oam_org = oam;
-  uint8 numframes = kBomb_Draw_Tab2[ancilla_item_to_link[k]];
-
-  oam += (ancilla_item_to_link[k] == 0 && (ancilla_tile_attr[k] == 9 || ancilla_tile_attr[k] == 0x40)) ? 2 : 0;
-
-  AncillaDraw_Explosion(oam, j, 0, numframes, r11, pt.x, pt.y);
-  oam += numframes;
-
-  uint8 r10;
-  if (!Bomb_CheckUndersideSpriteStatus(k, &pt, &r10)) {
-    if (oam != oam_org + 1)
-      oam = oam_org;
-    AncillaDraw_Shadow(oam, r10, pt.x, pt.y, HIBYTE(oam_priority_value));
-  }
-}
-
-void Ancilla08_DoorDebris(int k) {  // 889fb6
-  DoorDebris_Draw(k);
-  if (sign8(--ancilla_arr26[k])) {
-    ancilla_arr26[k] = 7;
-    if (++ancilla_arr25[k] == 4)
-      ancilla_type[k] = 0;
-  }
-}
-
-void DoorDebris_Draw(int k) {  // 88a091
-  static const uint16 kDoorDebris_XY[64] = {
-     4,  7,  3, 17,  8,  8,  7, 17, 11,  7, 10, 16, 16,  7, 17, 17,
-    20,  7, 21, 17, 16,  8, 17, 17, 13,  7, 14, 16,  8,  7,  7, 17,
-     7,  4, 17,  3,  8,  8, 17,  7,  7, 11, 16, 10,  7, 16, 17, 17,
-     7, 20, 17, 21,  8, 16, 17, 17,  7, 13, 16, 14,  7,  8, 17,  7,
-  };
-  static const uint16 kDoorDebris_CharFlags[32] = {
-    0x205e, 0xe05e, 0xa05e, 0x605e, 0x204f, 0x204f, 0x204f, 0x204f, 0x605e, 0x605e, 0x205e, 0xe05e, 0x604f, 0x604f, 0x604f, 0x604f,
-    0x205e, 0xe05e, 0xa05e, 0x605e, 0x204f, 0xe04f, 0x204f, 0x204f, 0x605e, 0x605e, 0x205e, 0xe05e, 0x604f, 0x604f, 0x604f, 0x604f,
-  };
-  Point16U pt;
-  Ancilla_PrepAdjustedOamCoord(k, &pt);
-  OamEnt *oam = GetOamCurPtr();
-  int y = door_debris_y[k] - BG2VOFS_copy2;
-  int x = door_debris_x[k] - BG2HOFS_copy2;
-  int j = ancilla_arr25[k] + door_debris_direction[k] * 4;
-
-  for (int i = 0; i != 2; i++) {
-    int t = j * 2 + i;
-    //kDoorDebris_XY
-    uint16 d = kDoorDebris_CharFlags[t];
-    Ancilla_SetOam(oam, x + kDoorDebris_XY[t * 2 + 1], y + kDoorDebris_XY[t * 2 + 0],
-                   d, (d >> 8) & 0xc0 | HIBYTE(oam_priority_value), 0);
-    oam = Ancilla_AllocateOamFromCustomRegion(oam + 1);
-  }
-}
-
-void Ancilla09_Arrow(int k) {  // 88a131
-  static const int8 kArrow_Y[4] = {-4, 2, 0, 0};
-  static const int8 kArrow_X[4] = {0, 0, -4, 4};
-  int j;
-
-  if (submodule_index != 0) {
-    Arrow_Draw(k);
-    return;
-  }
-
-  if (!sign8(--ancilla_item_to_link[k])) {
-    if (ancilla_item_to_link[k] >= 4)
-      return;
-  } else {
-    ancilla_item_to_link[k] = 0xff;
-  }
-  Ancilla_MoveY(k);
-  Ancilla_MoveX(k);
-  if (link_item_bow & 4 && !(frame_counter & 1))
-    AncillaAdd_SilverArrowSparkle(k);
-  ancilla_S[k] = 255;
-  if ((j = Ancilla_CheckSpriteCollision(k)) >= 0) {
-    ancilla_x_vel[k] = ancilla_x_lo[k] - sprite_x_lo[j];
-    ancilla_y_vel[k] = ancilla_y_lo[k] - sprite_y_lo[j] + sprite_z[j];
-    ancilla_S[k] = j;
-    if (sprite_type[j] == 0x65) {
-      if (sprite_A[j] == 1) {
-        sound_effect_2 = 0x2d;
-        sprite_delay_aux2[j] = 0x80;
-        sprite_delay_aux4[0] = 128;
-        if (byte_7E0B88 < 9)
-          byte_7E0B88++;
-        sprite_B[j] = byte_7E0B88;
-        sprite_G[j] += 1;
-      } else {
-        sprite_delay_aux3[j] = 4;
-        byte_7E0B88 = 0;
-      }
-    } else {
-      byte_7E0B88 = 0;
-    }
-  } else if ((j = Ancilla_CheckTileCollision(k)) != 0) {
-    ancilla_H[k] = j >> 1;
-    j = ancilla_dir[k] & 3;
-    Ancilla_SetX(k, Ancilla_GetX(k) + kArrow_X[j]);
-    Ancilla_SetY(k, Ancilla_GetY(k) + kArrow_Y[j]);
-    byte_7E0B88 = 0;
-  } else {
-    Arrow_Draw(k);
-    return;
-  }
-  if (sprite_type[j] != 0x1b)
-    Ancilla_Sfx2_Pan(k, 8);
-  ancilla_item_to_link[k] = 0;
-  ancilla_type[k] = 10;
-  ancilla_aux_timer[k] = 1;
-  if (ancilla_H[k]) {
-    ancilla_x_lo[k] += BG1HOFS_copy2 - BG2HOFS_copy2;
-    ancilla_y_lo[k] += BG1VOFS_copy2 - BG2VOFS_copy2;
-  }
-  Arrow_Draw(k);
-}
-
-void Arrow_Draw(int k) {  // 88a36e
-  static const uint8 kArrow_Draw_Char[48] = {
-    0x2b, 0x2a, 0x2a, 0x2b, 0x3d, 0x3a, 0x3a, 0x3d, 0x2b, 0xff, 0x2b, 0xff, 0x3d, 0xff, 0x3d, 0xff,
-    0x3c, 0x2c, 0x3c, 0x2a, 0x3c, 0x2c, 0x3c, 0x2a, 0x2c, 0x3c, 0x2a, 0x3c, 0x2c, 0x3c, 0x2a, 0x3c,
-    0x3b, 0x2d, 0x3b, 0x3a, 0x3b, 0x2d, 0x3b, 0x3a, 0x2d, 0x3b, 0x3a, 0x3b, 0x2d, 0x3b, 0x3a, 0x3b,
-  };
-  static const uint8 kArrow_Draw_Flags[48] = {
-    0xa4, 0xa4, 0x24, 0x24, 0x64, 0x64, 0x24, 0x24, 0xa4, 0xff, 0x24, 0xff, 0x64, 0xff, 0x24, 0xff,
-    0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xe4, 0xa4, 0xa4, 0x24, 0x24, 0x24, 0x24, 0x64, 0x24, 0x24, 0x24,
-    0x64, 0x64, 0x64, 0xe4, 0x64, 0xe4, 0x64, 0xe4, 0x24, 0x24, 0x24, 0xa4, 0xa4, 0x24, 0x24, 0xa4,
-  };
-  static const int8 kArrow_Draw_Y[48] = {
-    0,  8, 0, 8, 0, 0, 0, 0,  0,  0, 0, 0, 0, 0, 0, 0,
-    0,  8, 0, 8, 0, 8, 0, 8,  0,  8, 0, 8, 0, 8, 0, 8,
-    -1, -1, 0, 0, 0, 1, 0, 0, -1, -1, 0, 0, 1, 0, 0, 0,
-  };
-  static const int8 kArrow_Draw_X[48] = {
-    0, 0, 0, 0,  0,  8, 0, 8, 0, 0, 0, 0,  0,  0, 0, 0,
-    1, 1, 0, 0, -1, -2, 0, 0, 1, 1, 0, 0, -2, -1, 0, 0,
-    0, 8, 0, 8,  0,  8, 0, 8, 0, 8, 0, 8,  0,  8, 0, 8,
-  };
-  Point16U pt;
-  Ancilla_PrepAdjustedOamCoord(k, &pt);
-  if (ancilla_objprio[k])
-    HIBYTE(oam_priority_value) = 0x30;
-  uint16 x = pt.x, y = pt.y;
-  if (ancilla_H[k] != 0) {
-    x += BG2VOFS_copy2 - BG1VOFS_copy2;
-    y += BG2HOFS_copy2 - BG1HOFS_copy2;
-  }
-  uint8 r7 = ancilla_item_to_link[k];
-  int j = ancilla_dir[k] & ~4;
-  if (ancilla_type[k] == 0xa) {
-    j = j * 4 + 8 + ((r7 & 8) ? 1 : (r7 & 3));
-  } else if (!sign8(r7)) {
-    j |= 4;
-  }
-
-  j *= 2;
-
-  OamEnt *oam = GetOamCurPtr(), *oam_org = oam;
-  uint8 flags = (link_item_bow & 4) ? 2 : 4;
-  for (int i = 0; i != 2; i++, j++) {
-    if (kArrow_Draw_Char[j] != 0xff) {
-      Ancilla_SetOam(oam, x + kArrow_Draw_X[j], y + kArrow_Draw_Y[j],
-                     kArrow_Draw_Char[j], kArrow_Draw_Flags[j] & ~0x3E | flags | HIBYTE(oam_priority_value), 0);
-      oam++;
-    }
-  }
-
-  if (oam_org[0].y == 0xf0 && oam_org[1].y == 0xf0)
-    ancilla_type[k] = 0;
-}
-
-void Ancilla0A_ArrowInTheWall(int k) {  // 88a45b
-  int j = ancilla_S[k];
-  if (!sign8(j)) {
-    if (sprite_state[j] < 9 || sign8(sprite_z[j]) || sprite_ignore_projectile[j] || sprite_defl_bits[j] & 2) {
-      ancilla_type[k] = 0;
-      return;
-    }
-    Ancilla_SetX(k, Sprite_GetX(j) + (int8)ancilla_x_vel[k]);
-    Ancilla_SetY(k, Sprite_GetY(j) + (int8)ancilla_y_vel[k] - sprite_z[j]);
-  }
-  if (submodule_index == 0 && --ancilla_aux_timer[k] == 0) {
-    ancilla_aux_timer[k] = 2;
-    if (++ancilla_item_to_link[k] == 9) {
-      ancilla_type[k] = 0;
-      return;
-    } else if (ancilla_item_to_link[k] & 8) {
-      ancilla_aux_timer[k] = 0x80;
-    }
-  }
-  Arrow_Draw(k);
-}
-
-void Ancilla0B_IceRodShot(int k) {  // 88a4dd
-  if (submodule_index == 0) {
-    if (sign8(--ancilla_aux_timer[k])) {
-      if (++ancilla_item_to_link[k] & ~1) {
-        ancilla_step[k] = 1;
-        ancilla_item_to_link[k] = ancilla_item_to_link[k] & 7 | 4;
-      }
-      ancilla_aux_timer[k] = 3;
-    }
-    if (ancilla_step[k]) {
-      AncillaOamInfo info;
-      if (Ancilla_ReturnIfOutsideBounds(k, &info))
-        return;
-      Ancilla_MoveY(k);
-      Ancilla_MoveX(k);
-      if (Ancilla_CheckSpriteCollision(k) >= 0 || Ancilla_CheckTileCollision(k)) {
-        ancilla_type[k] = 0x11;
-        ancilla_numspr[k] = kAncilla_Pflags[0x11];
-        ancilla_item_to_link[k] = 0;
-        ancilla_aux_timer[k] = 4;
-      }
-    }
-  }
-  AncillaAdd_IceRodSparkle(k);
-}
-
-void Ancilla11_IceRodWallHit(int k) {  // 88a536
-  if (sign8(--ancilla_aux_timer[k])) {
-    ancilla_aux_timer[k] = 7;
-    if (++ancilla_item_to_link[k] == 2) {
-      ancilla_type[k] = 0;
-      return;
-    }
-  }
-  IceShotSpread_Draw(k);
-}
-
-void IceShotSpread_Draw(int k) {  // 88a571
-  static const uint8 kIceShotSpread_CharFlags[16] = {0xcf, 0x24, 0xcf, 0x24, 0xcf, 0x24, 0xcf, 0x24, 0xdf, 0x24, 0xdf, 0x24, 0xdf, 0x24, 0xdf, 0x24};
-  static const uint8 kIceShotSpread_XY[16] = {0, 0, 0, 8, 8, 0, 8, 8, 0xf8, 0xf8, 0xf8, 0x10, 0x10, 0xf8, 0x10, 0x10};
-
-  Point16U info;
-  Ancilla_PrepOamCoord(k, &info);
-
-  Ancilla_AllocateOamFromRegion_A_or_D_or_F(k, ancilla_numspr[k]);
-  OamEnt *oam = GetOamCurPtr();
-  int j = ancilla_item_to_link[k] * 4;
-  for (int i = 0; i != 4; i++, j++) {
-    uint16 y = info.y + (int8)kIceShotSpread_XY[j * 2 + 0];
-    uint16 x = info.x + (int8)kIceShotSpread_XY[j * 2 + 1];
-    uint8 yv = 0xf0;
-    if (x < 256 && y < 256) {
-      oam->x = x;
-      if (y < 224)
-        yv = y;
-    }
-    oam->y = yv;
-    oam->charnum = kIceShotSpread_CharFlags[j * 2 + 0];
-    oam->flags = kIceShotSpread_CharFlags[j * 2 + 1] & ~0x30 | HIBYTE(oam_priority_value);
-    bytewise_extended_oam[oam - oam_buf] = 0;
-    oam = Ancilla_AllocateOamFromCustomRegion(oam + 1);
-  }
-  oam = GetOamCurPtr();
-  if (oam[0].y == 0xf0 && oam[1].y == 0xf0)
-    ancilla_type[k] = 0;
-}
-
-void Ancilla33_BlastWallExplosion(int k) {  // 88a60e
-  if (submodule_index == 0) {
-    if (blastwall_var5[k]) {
-      if (--blastwall_var6[k] == 0) {
-        if (++blastwall_var5[k] != 0 && blastwall_var5[k] < 9) {
-          AncillaAdd_BlastWallFireball(0x32, 10, k * 4);
-        }
-        if (blastwall_var5[k] == 11) {
-          blastwall_var5[k] = 0;
-          blastwall_var6[k] = 0;
-        } else {
-          blastwall_var6[k] = 3;
-        }
-      }
-    } else if ((k ^= 1), blastwall_var5[k] == 6 && blastwall_var6[k] == 2 && (uint8)(ancilla_item_to_link[0] + 1) < 7) {
-      ancilla_item_to_link[0]++;
-      blastwall_var5[k] = 1;
-      blastwall_var6[k] = 3;
-      for (int i = 3; i >= 0; i--) {
-        int8 arr[2] = { 0, 0 };
-        int j = blastwall_var7 < 4 ? 1 : 0;
-        arr[j] = (i & 2) ? -13 : 13;
-        j = k * 4 + i;
-        blastwall_var10[j] += arr[0];
-        blastwall_var11[j] += arr[1];
-        uint16 x = blastwall_var11[j] - BG2HOFS_copy2;
-        if (x < 256)
-          sound_effect_1 = kBombos_Sfx[x >> 5] | 0xc;
-      }
-    }
-  }
-
-  if (blastwall_var5[ancilla_K[0]]) {
-    int i = (ancilla_K[0] == 1) ? 7 : 3;
-    do {
-      AncillaDraw_BlastWallBlast(ancilla_K[0], blastwall_var11[i], blastwall_var10[i]);
-    } while ((--i & 3) != 3);
-  }
-  if (ancilla_item_to_link[0] == 6) {
-    if (blastwall_var5[0] == 0 && blastwall_var5[1] == 0) {
-      ancilla_type[0] = 0;
-      ancilla_type[1] = 0;
-      flag_custom_spell_anim_active = 0;
-    }
-  }
-}
-
-void AncillaDraw_BlastWallBlast(int k, int x, int y) {  // 88a756
-  oam_priority_value = 0x3000;
-  if (sort_sprites_setting)
-    Oam_AllocateFromRegionD(0x18);
-  else
-    Oam_AllocateFromRegionA(0x18);
-  OamEnt *oam = GetOamCurPtr();
-  int i = blastwall_var5[k];
-  AncillaDraw_Explosion(oam, kBomb_Draw_Tab0[i] * 6, 0, kBomb_Draw_Tab2[i], 0x32,
-      x - BG2HOFS_copy2, y - BG2VOFS_copy2);
-}
-
-OamEnt *AncillaDraw_Explosion(OamEnt *oam, int frame, int idx, int idx_end, uint8 r11, int x, int y) {  // 88a7ab
-  static const int8 kBomb_DrawExplosion_XY[108] = {
-     -8,  -8,   0,   0,   0,   0,   0,   0,   0,   0,   0,  0,  -8,  -8,  -8,  0,
-      0,  -8,   0,   0,   0,   0,   0,   0, -16, -16, -16,  0,   0, -16,   0,  0,
-      0,   0,   0,   0, -16, -16, -16,   0,   0, -16,   0,  0,   0,   0,   0,  0,
-     -8,  -8, -21, -22, -21,   8,   9, -22,   9,   8,   0,  0,  -6, -15,   0, -1,
-    -16,  -2,  -8,  -7,   0,   0,   0,   0,  -9,  -4, -21, -5, -12, -18, -11,  7,
-      0, -15,   4,  -2,  -9,  -4, -22,  -5, -13, -20, -11,  8,   1, -16,   5, -2,
-    -20,   4, -12, -19,  -9,  16,  -5,  -2,   2,  -9,  10,  6,
-  };
-  static const uint8 kBomb_DrawExplosion_CharFlags[108] = {
-    0x6e, 0x26, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x8c, 0x22, 0x8c, 0x62,
-    0x8c, 0xa2, 0x8c, 0xe2, 0xff, 0xff, 0xff, 0xff, 0x84, 0x22, 0x84, 0x62, 0x84, 0xa2, 0x84, 0xe2,
-    0xff, 0xff, 0xff, 0xff, 0x88, 0x22, 0x88, 0x62, 0x88, 0xa2, 0x88, 0xe2, 0xff, 0xff, 0xff, 0xff,
-    0x86, 0x22, 0x88, 0x22, 0x88, 0x62, 0x88, 0xa2, 0x88, 0xe2, 0xff, 0xff, 0x86, 0x22, 0x86, 0x62,
-    0x86, 0xe2, 0x86, 0xe2, 0xff, 0xff, 0xff, 0xff, 0x86, 0xe2, 0x86, 0x22, 0x86, 0x22, 0x86, 0x62,
-    0x86, 0xa2, 0x86, 0xa2, 0x8a, 0xa2, 0x8a, 0x62, 0x8a, 0x22, 0x8a, 0x62, 0x8a, 0x62, 0x8a, 0xe2,
-    0x9b, 0x22, 0x9b, 0xa2, 0x9b, 0x62, 0x9b, 0xe2, 0x9b, 0xa2, 0x9b, 0x22,
-  };
-  static const uint8 kBomb_DrawExplosion_Ext[54] = {
-    2, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 2, 2, 2, 2,
-    1, 1, 2, 2, 2, 2, 1, 1, 2, 2, 2, 2, 2, 1, 2, 2,
-    2, 2, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-    0, 0, 0, 0, 0, 0,
-  };
-  int base_frame = frame;
-  do {
-    if (kBomb_DrawExplosion_CharFlags[frame * 2] != 0xff) {
-      int i = idx + base_frame;
-      Ancilla_SetOam_Safe(oam, x + kBomb_DrawExplosion_XY[i * 2 + 1], y + kBomb_DrawExplosion_XY[i * 2 + 0],
-                          kBomb_DrawExplosion_CharFlags[frame * 2],
-                          kBomb_DrawExplosion_CharFlags[frame * 2 + 1] & ~0x3E | HIBYTE(oam_priority_value) | r11,
-                          kBomb_DrawExplosion_Ext[frame]);
-      oam++;
-    }
-  } while (frame++, ++idx != idx_end);
-  return oam;
-}
-
-void Ancilla15_JumpSplash(int k) {  // 88a80f
-  static const uint8 kAncilla_JumpSplash_Char[2] = {0xac, 0xae};
-
-  if (!submodule_index) {
-    if (sign8(--ancilla_aux_timer[k])) {
-      ancilla_aux_timer[k] = 0;
-      ancilla_item_to_link[k] = 1;
-    }
-    if (ancilla_item_to_link[k]) {
-      ancilla_x_vel[k] = ancilla_y_vel[k] = ancilla_y_vel[k] - 4;
-      if (ancilla_y_vel[k] < 232) {
-        ancilla_type[k] = 0;
-        if ((link_is_bunny_mirror || link_player_handler_state == kPlayerState_Swimming) && link_is_in_deep_water)
-          CheckAbilityToSwim();
-        return;
-      }
-      Ancilla_MoveX(k);
-      Ancilla_MoveY(k);
-    }
-  }
-  Point16U pt;
-  Ancilla_PrepOamCoord(k, &pt);
-  OamEnt *oam = GetOamCurPtr();
-  int ax = Ancilla_GetX(k);
-  int x8 = link_x_coord * 2 - ax - BG2HOFS_copy2;
-  int x6 = ax + 12 - BG2HOFS_copy2;
-  int j = ancilla_item_to_link[k];
-  uint8 flags = 0;
-  for (int i = 0; i < 2; i++) {
-    Ancilla_SetOam(oam, pt.x, pt.y, kAncilla_JumpSplash_Char[j], 0x24 | flags, 2);
-    oam = Ancilla_AllocateOamFromCustomRegion(oam + 1);
-    pt.x = x8;
-    flags = 0x40;
-  }
-  Ancilla_SetOam(oam, x6, pt.y, 0xc0, 0x24, ((j == 1) ? 1 : 2));
-}
-
-void Ancilla16_HitStars(int k) {  // 88a8e5
-  static const uint8 kAncilla_HitStars_Char[2] = {0x90, 0x91};
-
-  if (!sign8(--ancilla_arr3[k]))
-    return;
-
-  ancilla_arr3[k] = 0;
-  if (!submodule_index) {
-    if (sign8(--ancilla_aux_timer[k])) {
-      ancilla_aux_timer[k] = 0;
-      ancilla_item_to_link[k] = 1;
-    }
-    if (ancilla_item_to_link[k]) {
-      ancilla_x_vel[k] = (ancilla_y_vel[k] -= 4);
-      if (ancilla_y_vel[k] < 232) {
-        ancilla_type[k] = 0;
-        return;
-      }
-      Ancilla_MoveY(k);
-      Ancilla_MoveX(k);
-    }
-  }
-  Point16U info;
-  Ancilla_PrepOamCoord(k, &info);
-
-  uint16 ax = Ancilla_GetX(k);
-  uint16 tt = ancilla_B[k] << 8 | ancilla_A[k];
-
-  uint16 r8 = 2 * tt - ax - 8 - BG2HOFS_copy2;
-
-  if (ancilla_step[k] == 2)
-    Ancilla_AllocateOamFromRegion_B_or_E(8);
-
-  OamEnt *oam = GetOamCurPtr();
-  uint16 x = info.x, y = info.y;
-  uint8 flags = 0;
-  for (int i = 1; i >= 0; i--) {
-    Ancilla_SetOam(oam, x, y,
-                   kAncilla_HitStars_Char[ancilla_item_to_link[k]],
-                   HIBYTE(oam_priority_value) | 4 | flags, 0);
-    flags = 0x40;
-    BYTE(x) = r8;
-    oam = HitStars_UpdateOamBufferPosition(oam + 1);
-  }
-}
-
-void Ancilla17_ShovelDirt(int k) {  // 88a9a9
-  static const int8 kShovelDirt_XY[8] = {18, -13, -9, 4, 18, 13, -9, -11};
-  static const int8 kShovelDirt_Char[2] = {0x40, 0x50};
-  Point16U pt;
-  Ancilla_PrepOamCoord(k, &pt);
-  OamEnt *oam = GetOamCurPtr();
-  if (!ancilla_timer[k]) {
-    ancilla_timer[k] = 8;
-    if (++ancilla_item_to_link[k] == 2) {
-      ancilla_type[k] = 0;
-      return;
-    }
-  }
-  int b = ancilla_item_to_link[k];
-  int j = b + ((link_direction_facing == 4) ? 0 : 2);
-  pt.x += kShovelDirt_XY[j * 2 + 1];
-  pt.y += kShovelDirt_XY[j * 2 + 0];
-  for (int i = 0; i < 2; i++) {
-    Ancilla_SetOam(oam, pt.x + i * 8, pt.y, kShovelDirt_Char[b] + i, 4 | HIBYTE(oam_priority_value), 0);
-    oam = Ancilla_AllocateOamFromCustomRegion(oam + 1);
-  }
-}
-
-void Ancilla32_BlastWallFireball(int k) {  // 88aa35
-  static const uint8 kBlastWallFireball_Char[3] = {0x9d, 0x9c, 0x8d};
-
-  if (!submodule_index) {
-    ancilla_item_to_link[k] += 2;
-    ancilla_y_vel[k] += ancilla_item_to_link[k];
-    Ancilla_MoveY(k);
-    Ancilla_MoveX(k);
-    if (sign8(--blastwall_var12[k])) {
-      ancilla_type[k] = 0;
-      return;
-    }
-  }
-
-  if (sort_sprites_setting)
-    Oam_AllocateFromRegionD(4);
-  else
-    Oam_AllocateFromRegionA(4);
-
-  Point16U pt;
-  Ancilla_PrepOamCoord(k, &pt);
-  Ancilla_SetOam(GetOamCurPtr(), pt.x, pt.y, kBlastWallFireball_Char[blastwall_var12[k] & 8 ? 0 : blastwall_var12[k] & 4 ? 1 : 2], 0x22, 0);
-}
-
-void Ancilla18_EtherSpell(int k) {  // 88aaa0
-  if (submodule_index)
-    return;
-
-  if (ancilla_step[k] != 0) {
-    uint8 flag;
-
-    if (step_counter_for_spin_attack == 0) {
-      flag = (++ancilla_arr4[k] & 4) == 0;
-    } else {
-      flag = step_counter_for_spin_attack == 11;
-    }
-    if (flag) {
-      Palette_ElectroThemedGear();
-      Filter_Majorly_Whiten_Bg();
-    } else {
-      LoadActualGearPalettes();
-      Palette_Restore_BG_From_Flash();
-    }
-  }
-
-  if (ancilla_step[k] == 2) {
-    if (sign8(--ancilla_aux_timer[k])) {
-      ancilla_aux_timer[k] = 2;
-      if (++ancilla_item_to_link[k] == 2) {
-        ancilla_item_to_link[k]--;
-        ancilla_x_vel[k] = 16;
-        ancilla_step[k] = 3;
-      }
-    }
-    ancilla_x_vel[k] += 1;
-    EtherSpell_HandleRadialSpin(k);
-    return;
-  } else {
-    if (sign8(--ancilla_aux_timer[k])) {
-      ancilla_aux_timer[k] = 2;
-      ancilla_item_to_link[k] ^= 1;
-    }
-    if (ancilla_step[k] == 0) {
-      EtherSpell_HandleLightningStroke(k);
-    } else if (ancilla_step[k] == 1) {
-      EtherSpell_HandleOrbPulse(k);
-    } else if (ancilla_step[k] == 3) {
-      EtherSpell_HandleRadialSpin(k);
-    } else if (ancilla_step[k] == 4) {
-      if (!--ether_var1)
-        ancilla_step[k] = 5;
-      EtherSpell_HandleRadialSpin(k);
-    } else {
-      uint8 vel = ancilla_x_vel[k] + 0x10;
-      if (sign8(vel)) vel = 0x7f;
-      ancilla_x_vel[k] = vel;
-      EtherSpell_HandleRadialSpin(k);
-    }
-  }
-}
-
-void EtherSpell_HandleLightningStroke(int k) {  // 88ab63
-  Ancilla_MoveY(k);
-  uint16 y = Ancilla_GetY(k);
-
-  if (BYTE(ether_y_adjusted) != (y & 0xf0)) {
-    BYTE(ether_y_adjusted) = y & 0xf0;
-    ancilla_arr25[k]++;
-  }
-  if (y < 0xe000 && ether_y2 < 0xe000 && ether_y2 <= y) {
-    ancilla_step[k] = 1;
-  }
-  AncillaDraw_EtherBlitz(k);
-}
-
-void EtherSpell_HandleOrbPulse(int k) {  // 88aba7
-  if (!sign8(ancilla_arr25[k])) {
-    if (!sign8(--ancilla_arr3[k])) {
-      AncillaDraw_EtherBlitz(k);
-      return;
-    }
-    ancilla_arr3[k] = 3;
-    if (!sign8(--ancilla_arr25[k])) {
-      AncillaDraw_EtherBlitz(k);
-      return;
-    }
-    ancilla_arr3[k] = 9;
-  }
-  if (sign8(--ancilla_arr3[k])) {
-    ancilla_step[k] = 2;
-    ancilla_y_vel[k] = 0;
-    ancilla_x_vel[k] = 16;
-    ancilla_item_to_link[k] = 0;
-    ancilla_aux_timer[k] = 2;
-    if (step_counter_for_spin_attack)
-      Medallion_CheckSpriteDamage(k);
-  }
-  AncillaDraw_EtherOrb(k, GetOamCurPtr());
-}
-
-void EtherSpell_HandleRadialSpin(int k) {  // 88abef
-  if (ancilla_step[k] == 4) {
-    if ((frame_counter & 7) == 0)
-      sound_effect_2 = 0x2a;
-    else if ((frame_counter & 7) == 4)
-      sound_effect_2 = 0xaa;
-    else if ((frame_counter & 7) == 7)
-      sound_effect_2 = 0x6a;
-  } else {
-    ancilla_x_lo[k] = ether_var2;
-    ancilla_x_hi[k] = 0;
-    Ancilla_MoveX(k);
-    ether_var2 = ancilla_x_lo[k];
-    if (ether_var2 == 0x40)
-      ancilla_step[k] = 4;
-  }
-
-  uint8 sb = ancilla_step[k];
-  uint8 sa = ancilla_item_to_link[k];
-  OamEnt *oam = GetOamCurPtr();
-  for (int i = 7; i >= 0; i--) {
-    if (sb != 2 && sb != 5) {
-      ether_arr1[i] = (ether_arr1[i] + 1) & 0x3f;
-    }
-    AncillaRadialProjection arp = Ancilla_GetRadialProjection(ether_arr1[i], ether_var2);
-    if (sb != 2)
-      oam = AncillaDraw_EtherBlitzBall(oam, &arp, sa);
-    else
-      oam = AncillaDraw_EtherBlitzSegment(oam, &arp, sa, i);
-  }
-  if (ether_var2 < 0xf0) {
-    OamEnt *oam = GetOamCurPtr();
-    for (int i = 0; i != 8; i++) {
-      if (oam[i].y != 0xf0)
-        return;
-    }
-  }
-  ancilla_type[k] = 0;
-  load_chr_halfslot_even_odd = 1;
-  byte_7E0324 = 0;
-  state_for_spin_attack = 0;
-  step_counter_for_spin_attack = 0;
-  link_cant_change_direction = 0;
-  flag_unk1 = 0;
-
-  if (BYTE(overworld_screen_index) == 0x70 && !(save_ow_event_info[0x70] & 0x20) && Ancilla_CheckForEntranceTrigger(2)) {
-    trigger_special_entrance = 3;
-    subsubmodule_index = 0;
-    BYTE(R16) = 0;
-  }
-
-  if (link_player_handler_state != kPlayerState_ReceivingEther) {
-    link_player_handler_state = kPlayerState_Ground;
-    link_delay_timer_spin_attack = 0;
-    button_mask_b_y = button_b_frames ? (joypad1H_last & 0x80) : 0;
-  }
-  link_speed_setting = 0;
-  byte_7E0325 = 0;
-  LoadActualGearPalettes();
-  Palette_Restore_BG_And_HUD();
-}
-
-OamEnt *AncillaDraw_EtherBlitzBall(OamEnt *oam, const AncillaRadialProjection *arp, int s) {  // 88aced
-  static const uint8 kEther_BlitzBall_Char[2] = {0x68, 0x6a};
-  int x = (arp->r6 ? -arp->r4 : arp->r4) + ether_x2 - 8 - BG2HOFS_copy2;
-  int y = (arp->r2 ? -arp->r0 : arp->r0) + ether_y3 - 8 - BG2VOFS_copy2;
-  Ancilla_SetOam(oam, x, y, kEther_BlitzBall_Char[s], 0x3c, 2);
-  return Ancilla_AllocateOamFromCustomRegion(oam + 1);
-}
-
-OamEnt *AncillaDraw_EtherBlitzSegment(OamEnt *oam, const AncillaRadialProjection *arp, int s, int k) {  // 88adc9
-  static const int8 kEther_SpllittingBlitzSegment_X[16] = {-8, -16, -24, -16, -8, 0, 8, -16, -8, -16, -24, -16, -8, 0, 8, 0};
-  static const int8 kEther_SpllittingBlitzSegment_Y[16] = {8, 0, -8, -16, -24, -16, -8, -16, 8, 0, -8, -16, -24, -16, -8, 0};
-  static const uint8 kEther_SpllittingBlitzSegment_Char[32] = {
-    0x40, 0x42, 0x66, 0x64, 0x62, 0x60, 0x64, 0x66, 0x42, 0x40, 0x66, 0x64, 0x60, 0x62, 0x64, 0x66,
-    0x68, 0x42, 0x68, 0x64, 0x68, 0x60, 0x68, 0x64, 0x68, 0x40, 0x68, 0x66, 0x68, 0x62, 0x68, 0x64,
-  };
-  static const uint8 kEther_SpllittingBlitzSegment_Flags[32] = {
-    0x3c, 0x3c, 0xfc, 0xfc, 0x3c, 0x3c, 0xbc, 0xbc, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x7c, 0x7c,
-    0x3c, 0x7c, 0x3c, 0x3c, 0x3c, 0xbc, 0x3c, 0x7c, 0x3c, 0x7c, 0x3c, 0xfc, 0x3c, 0xbc, 0x3c, 0xbc,
-  };
-  int x = (arp->r6 ? -arp->r4 : arp->r4);
-  int y = (arp->r2 ? -arp->r0 : arp->r0);
-  int t = s * 8 + k;
-  Ancilla_SetOam(oam, x + ether_x2 - 8 - BG2HOFS_copy2, y + ether_y3 - 8 - BG2VOFS_copy2,
-                 kEther_SpllittingBlitzSegment_Char[t * 2], kEther_SpllittingBlitzSegment_Flags[t * 2], 2);
-  Ancilla_SetOam(oam + 1,
-      x + ether_x2 + kEther_SpllittingBlitzSegment_X[t] - BG2HOFS_copy2,
-      y + ether_y3 + kEther_SpllittingBlitzSegment_Y[t] - BG2VOFS_copy2,
-      kEther_SpllittingBlitzSegment_Char[t * 2 + 1],
-      kEther_SpllittingBlitzSegment_Flags[t * 2 + 1], 2);
-  return Ancilla_AllocateOamFromCustomRegion(oam + 2);
-}
-
-void AncillaDraw_EtherBlitz(int k) {  // 88ae87
-  Point16U info;
-  Ancilla_PrepOamCoord(k, &info);
-  OamEnt *oam = GetOamCurPtr();
-  int t = ancilla_item_to_link[k];
-  int i = ancilla_arr25[k];
-  int m = 0;
-  do {
-    Ancilla_SetOam(oam, info.x, info.y,
-                   kEther_BlitzSegment_Char[t * 2 + m],
-                   kEther_BlitzOrb_Flags[0] | HIBYTE(oam_priority_value), 2);
-    info.y -= 16;
-    oam++;
-    m ^= 1;
-  } while (--i >= 0);
-  if (ancilla_step[k] == 1)
-    AncillaDraw_EtherOrb(k, oam);
-}
-
-void AncillaDraw_EtherOrb(int k, OamEnt *oam) {  // 88aedd
-  uint16 y = ether_y - 1 - BG2VOFS_copy2;
-  uint16 x = ether_x - 8 - BG2HOFS_copy2;
-  int t = ancilla_item_to_link[k] * 4;
-
-  for (int i = 0; i < 4; i++) {
-    Ancilla_SetOam(oam, x, y, kEther_BlitzOrb_Char[t + i], kEther_BlitzOrb_Flags[t + i], 2);
-    oam++;
-    oam = Ancilla_AllocateOamFromCustomRegion(oam);
-    x += 16;
-    if (i == 1)
-      x -= 32, y += 16;
-  }
-}
-
-void AncillaAdd_BombosSpell(uint8 a, uint8 y) {  // 88af66
-  int k = AncillaAdd_AddAncilla_Bank08(a, y);
-  if (k < 0)
-    return;
-  for (int i = 0; i < 10; i++) {
-    bombos_arr2[i] = 0;
-    bombos_arr1[i] = 3;
-  }
-  for (int i = 0; i < 8; i++) {
-    bombos_arr3[i] = 0;
-    bombos_arr4[i] = 3;
-  }
-  bombos_var4 = 0;
-  bombos_var2 = 0;
-  bombos_var3 = 0x80;
-  bombos_arr7[0] = 0x10;
-  load_chr_halfslot_even_odd = 11;
-  flag_custom_spell_anim_active = 1;
-  ancilla_step[k] = 0;
-  ancilla_item_to_link[k] = 0;
-  Ancilla_Sfx2_Near(0x2a);
-
-  uint8 t = kGeneratedBombosArr[frame_counter];
-  t = (t < 0xe0) ? t : t & 0x7f;
-  bombos_x_coord[0] = link_x_coord & ~0xff | t;
-  bombos_y_coord[0] = link_y_coord & ~0xff | t;
-
-  static const int16 kBombos_YDelta[4] = {16, 24, -128, -16};
-  static const int16 kBombos_XDelta[4] = {-16, -128, 0, 128};
-
-  for (int i = 0; i < 1 ; i++) {
-    bombos_x_coord2[i] = link_x_coord + kBombos_XDelta[i];
-    bombos_y_coord2[i] = link_y_coord + kBombos_YDelta[i];
-    bombos_var1 = 16;
-    AncillaRadialProjection arp = Ancilla_GetRadialProjection(bombos_arr7[i], 16);
-    int x = (arp.r6 ? -arp.r4 : arp.r4) + bombos_x_coord2[i];
-    int y = (arp.r2 ? -arp.r0 : arp.r0) + bombos_y_coord2[i];
-    bombos_x_lo[i] = (uint8)x;
-    bombos_x_hi[i] = x >> 8;
-    bombos_y_lo[i] = (uint8)y;
-    bombos_y_hi[i] = y >> 8;
-  }
-}
-
-void Ancilla19_BombosSpell(int k) {  // 88b0ce
-  if (bombos_var4 == 0) {
-    if (submodule_index == 0) {
-      BombosSpell_ControlFireColumns(k);
-      return;
-    }
-    for (int i = 9; i >= 0; i--)
-      AncillaDraw_BombosFireColumn(i);
-  } else if (bombos_var4 != 2) {
-    if (submodule_index == 0) {
-      BombosSpell_FinishFireColumns(k);
-      return;
-    }
-    for (int i = 9; i >= 0; i--)
-      AncillaDraw_BombosFireColumn(i);
-  } else {
-    if (submodule_index == 0) {
-      BombosSpell_ControlBlasting(k);
-      return;
-    }
-    int i = ancilla_step[k];
-    do {
-      AncillaDraw_BombosBlast(i);
-    } while (--i >= 0);
-  }
-}
-
-void BombosSpell_ControlFireColumns(int k) {  // 88b10a
-  uint8 sa = ancilla_item_to_link[k];
-  uint8 sb = ancilla_step[k];
-
-  int j, i = sb;
-  do {
-    if (bombos_arr2[i] == 13)
-      continue;
-
-    if (sign8(--bombos_arr1[i])) {
-      bombos_arr1[i] = 3;
-      if (++bombos_arr2[i] == 13)
-        continue;
-
-      if (bombos_arr2[i] == 2) {
-        if (sa)
-          continue;
-
-        // pushed x
-        if (sb == 9) {
-          for (j = 9; j >= 0; j--) {
-            if (bombos_arr2[j] == 13) {
-              bombos_arr2[j] = 0;
-              goto exit_loop;
-            }
-          }
-        }
-        sb = j = (sb + 1) != 10 ? sb + 1 : 9;
-exit_loop:
-        bombos_var1 = (bombos_var1 + 3 >= 207) ? 207 : bombos_var1 + 3;
-        bombos_arr7[0] += 6;
-        AncillaRadialProjection arp = Ancilla_GetRadialProjection(bombos_arr7[0] & 0x3f, bombos_var1);
-        int x = (arp.r6 ? -arp.r4 : arp.r4) + bombos_x_coord2[0];
-        int y = (arp.r2 ? -arp.r0 : arp.r0) + bombos_y_coord2[0];
-        bombos_x_lo[j] = (uint8)x;
-        bombos_x_hi[j] = x >> 8;
-        bombos_y_lo[j] = (uint8)y;
-        bombos_y_hi[j] = y >> 8;
-
-        uint16 t = x - BG2HOFS_copy2 + 8;
-        if (t < 256)
-          sound_effect_1 = kBombos_Sfx[t >> 5] | 0x2a;
-      }
-    }
-    AncillaDraw_BombosFireColumn(i);
-
-  } while (--i >= 0);
-  if (bombos_arr7[0] >= 0x80)
-    bombos_var4 = 1;
-  ancilla_step[k] = sb;
-}
-
-void BombosSpell_FinishFireColumns(int kk) {  // 88b236
-  int k = ancilla_step[kk];
-  do {
-    if (sign8(--bombos_arr1[k])) {
-      bombos_arr1[k] = 3;
-      if (++bombos_arr2[k] >= 13)
-        bombos_arr2[k] = 13;
-    }
-    AncillaDraw_BombosFireColumn(k);
-  } while (--k >= 0);
-  for (int k = 9; k >= 0; k--) {
-    if (bombos_arr2[k] != 13)
-      return;
-  }
-  bombos_var4 = 2;
-  Medallion_CheckSpriteDamage(kk);
-  ancilla_step[kk] = 0;
-}
-
-void AncillaDraw_BombosFireColumn(int kk) {  // 88b373
-  static const int8 kBombosSpell_FireColumn_X[39] = {
-     0, -1, -1,  0, 0, -1,  0, 0, -1, 0, 0, -1, 0, 0, -1, 0,
-     0,  0,  0,  0, 0,  0,  0, 0,  0, 0, 0,  0, 0, 0,  0, 0,
-    -1,  1, -1, -1, 2, -1, -1,
-  };
-  static const int8 kBombosSpell_FireColumn_Y[39] = {
-     0,  -1, -1,  0,  -4, -1,   0,  -8, -1,   0, -12, -1,   0, -16,  -1,   0,
-    -4, -20,  0, -8, -24,  0, -12, -28,  0, -16, -32,  0, -16, -32, -18, -34,
-    -1, -35, -1, -1, -36, -1,  -1,
-  };
-  static const uint8 kBombosSpell_FireColumn_Flags[39] = {
-    0x3c, 0xff, 0xff, 0x3c, 0x3c, 0xff, 0x3c, 0x3c, 0xff, 0x7c, 0x7c, 0xff, 0x3c, 0x7c, 0xff, 0x3c,
-    0x3c, 0x3c, 0xbc, 0x3c, 0x3c, 0x7c, 0x3c, 0x3c, 0x3c, 0x3c, 0x7c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c,
-    0xff, 0x3c, 0xff, 0xff, 0x3c, 0xff, 0xff,
-  };
-  static const uint8 kBombosSpell_FireColumn_Char[39] = {
-    0x40, 0xff, 0xff, 0x42, 0x44, 0xff, 0x42, 0x44, 0xff, 0x42, 0x44, 0xff, 0x42, 0x44, 0xff, 0x40,
-    0x46, 0x44, 0x4a, 0x4a, 0x48, 0x4c, 0x4c, 0x4a, 0x4e, 0x4c, 0x4a, 0x4e, 0x6a, 0x4c, 0x4e, 0x68,
-    0xff, 0x6a, 0xff, 0xff, 0x4e, 0xff, 0xff,
-  };
-  Ancilla_AllocateOamFromRegion_A_or_D_or_F(kk, 0x10);
-  OamEnt *oam = GetOamCurPtr();
-  for (int i = 0; i < 1; i++) {
-    int k = bombos_arr2[kk];
-    if (k == 13)
-      continue;
-    k = k * 3 + 2;
-    for (int j = 0; j < 3; j++, k--) {
-      if (kBombosSpell_FireColumn_Char[k] != 0xff) {
-        uint16 x = bombos_x_lo[kk] | bombos_x_hi[kk] << 8;
-        uint16 y = bombos_y_lo[kk] | bombos_y_hi[kk] << 8;
-        y += kBombosSpell_FireColumn_Y[k] - BG2VOFS_copy2;
-        x += kBombosSpell_FireColumn_X[k] - BG2HOFS_copy2;
-        Ancilla_SetOam(oam, x, y,
-                       kBombosSpell_FireColumn_Char[k],
-                       kBombosSpell_FireColumn_Flags[k], 2);
-        oam++;
-      }
-      oam = Ancilla_AllocateOamFromCustomRegion(oam);
-    }
-  }
-}
-
-void BombosSpell_ControlBlasting(int kk) {  // 88b40d
-  int k = ancilla_step[kk], sb = k;
-  for (; k >= 0; k--) {
-    if (bombos_arr3[k] != 8 && sign8(--bombos_arr4[k])) {
-      bombos_arr4[k] = 3;
-      if (++bombos_arr3[k] == 1 && !bombos_var2) {
-        int j = sb;
-        if (j != 15) {
-          j = ++sb;
-        } else {
-          for (; j >= 0 && bombos_arr3[j] != 8; j--) {}
-        }
-        bombos_arr3[j] = 0;
-        bombos_arr4[j] = 3;
-
-        uint16 y = kBombosBlasts_Tab[frame_counter & 0x3f];
-        uint16 x = kBombosBlasts_Tab[(frame_counter & 0x3f) + 3];
-        bombos_y_coord[j] = y + BG2VOFS_copy2;
-        bombos_x_coord[j] = x + BG2HOFS_copy2;
-
-        sound_effect_1 = 0xc | kBombos_Sfx[bombos_x_coord[j] >> 5 & 7];
-      }
-    }
-    AncillaDraw_BombosBlast(k);
-  }
-
-  for (int j = 15; j >= 0; j--) {
-    if (bombos_arr3[j] != 8) {
-      ancilla_step[kk] = sb;
-      goto getout;
-    }
-  }
-  ancilla_type[kk] = 0;
-  load_chr_halfslot_even_odd = 1;
-  byte_7E0324 = 0;
-  state_for_spin_attack = 0;
-  step_counter_for_spin_attack = 0;
-  link_cant_change_direction = 0;
-  flag_unk1 = 0;
-  if (link_player_handler_state != kPlayerState_ReceivingBombos) {
-    link_player_handler_state = kPlayerState_Ground;
-    link_delay_timer_spin_attack = 0;
-    button_mask_b_y = button_b_frames ? (joypad1H_last & 0x80) : 0;
-  }
-  link_speed_setting = 0;
-  byte_7E0325 = 0;
-getout:
-  if (--bombos_var3 == 0)
-    bombos_var2 = bombos_var3 = 1;
-}
-
-void AncillaDraw_BombosBlast(int k) {  // 88b5e1
-  static const int8 kBombosSpell_DrawBlast_X[32] = {
-     -8, -1,  -1, -1, -12, -4, -12, -4, -16, 0, -16, 0, -16, 0, -16, 0,
-    -17,  1, -17,  1, -19,  3, -19,  3, -19, 3, -19, 3, -19, 3, -19, 3,
-  };
-  static const int8 kBombosSpell_DrawBlast_Y[32] = {
-     -8,  -1, -1, -1, -12, -12, -4, -4, -16, -16, 0, 0, -16, -16, 0, 0,
-    -17, -17,  1,  1, -19, -19,  3,  3, -19, -19, 3, 3, -19, -19, 3, 3,
-  };
-  static const uint8 kBombosSpell_DrawBlast_Flags[32] = {
-    0x3c, 0xff, 0xff, 0xff, 0x3c, 0x7c, 0xbc, 0xfc, 0x3c, 0x7c, 0xbc, 0xfc, 0x3c, 0x7c, 0xbc, 0xfc,
-    0x3c, 0x7c, 0xbc, 0xfc, 0x3c, 0x7c, 0xbc, 0xfc, 0x3c, 0x7c, 0xbc, 0xfc, 0x3c, 0x7c, 0xbc, 0xfc,
-  };
-  static const uint8 kBombosSpell_DrawBlast_Char[32] = {
-    0x60, 0xff, 0xff, 0xff, 0x62, 0x62, 0x62, 0x62, 0x64, 0x64, 0x64, 0x64, 0x66, 0x66, 0x66, 0x66,
-    0x68, 0x68, 0x68, 0x68, 0x68, 0x68, 0x68, 0x68, 0x6a, 0x6a, 0x6a, 0x6a, 0x4e, 0x4e, 0x4e, 0x4e,
-  };
-  uint16 x = bombos_x_coord[k];
-  uint16 y = bombos_y_coord[k];
-  if (bombos_arr3[k] == 8)
-    return;
-
-  Ancilla_AllocateOamFromRegion_A_or_D_or_F(k, 0x10);
-  OamEnt *oam = GetOamCurPtr();
-
-  int t = bombos_arr3[k] * 4 + 3;
-  for (int j = 0; j < 4; j++, t--) {
-    if (kBombosSpell_DrawBlast_Char[t] != 0xff) {
-      Ancilla_SetOam(oam,
-        x + kBombosSpell_DrawBlast_X[t] - BG2HOFS_copy2,
-        y + kBombosSpell_DrawBlast_Y[t] - BG2VOFS_copy2,
-        kBombosSpell_DrawBlast_Char[t],
-        kBombosSpell_DrawBlast_Flags[t], 2);
-      oam++;
-    }
-    oam = Ancilla_AllocateOamFromCustomRegion(oam);
-  }
-
-}
-
-void Ancilla1C_QuakeSpell(int k) {  // 88b66a
-  if (submodule_index != 0) {
-    if (quake_arr2[4] != kQuake_Tab1[4])
-      AncillaDraw_QuakeInitialBolts(k);
-    return;
-  }
-  if (ancilla_step[k] != 2) {
-    QuakeSpell_ShakeScreen(k);
-    QuakeSpell_ControlBolts(k);
-    QuakeSpell_SpreadBolts(k);
-    return;
-  }
-  Medallion_CheckSpriteDamage(k);
-  Prepare_ApplyRumbleToSprites();
-  ancilla_type[k] = 0;
-  link_player_handler_state = 0;
-  load_chr_halfslot_even_odd = 1;
-  byte_7E0324 = 0;
-  state_for_spin_attack = 0;
-  step_counter_for_spin_attack = 0;
-  link_cant_change_direction = 0;
-  link_delay_timer_spin_attack = 0;
-  flag_unk1 = 0;
-  bg1_x_offset = 0;
-  bg1_y_offset = 0;
-  if (BYTE(overworld_screen_index) == 0x47 && !(save_ow_event_info[0x47] & 0x20) && Ancilla_CheckForEntranceTrigger(3)) {
-    trigger_special_entrance = 4;
-    subsubmodule_index = 0;
-    BYTE(R16) = 0;
-  }
-  button_mask_b_y = button_b_frames ? (joypad1H_last & 0x80) : 0;
-  link_speed_setting = 0;
-  byte_7E0325 = 0;
-}
-
-void QuakeSpell_ShakeScreen(int k) {  // 88b6f7
-  bg1_y_offset = quake_var3;
-  quake_var3 = -quake_var3;
-  link_y_vel += bg1_y_offset;
-}
-
-void QuakeSpell_ControlBolts(int k) {  // 88b718
-  quake_var4 = ancilla_step[k];
-  int j = quake_var5;
-  do {
-    if (quake_arr2[j] == kQuake_Tab1[j])
-      continue;
-
-    if (sign8(--quake_arr1[j])) {
-      quake_arr1[j] = 1;
-      if (++quake_arr2[j] == kQuake_Tab1[j])
-        continue;
-
-      if (j == 0 && quake_arr2[j] == 2) {
-        Ancilla_Sfx2_Near(0xc);
-        quake_var5 = 1;
-      } else if (j == 1 && quake_arr2[j] == 2) {
-        quake_var5 = 4;
-      } else if (j == 4 && quake_arr2[j] == 7) {
-        quake_var4 = 1;
-      }
-    }
-    AncillaDraw_QuakeInitialBolts(j);
-  } while (--j >= 0);
-  ancilla_step[k] = quake_var4;
-}
-
-void AncillaDraw_QuakeInitialBolts(int k) {  // 88b793
-  static const uint8 kQuakeDrawGroundBolts_Tab[5] = {0, 0x18, 0, 0x18, 0x2f};
-
-  int t = quake_arr2[k] + kQuakeDrawGroundBolts_Tab[k];
-  OamEnt *oam = GetOamCurPtr();
-  int idx = kQuakeItemPos[t], num = kQuakeItemPos[t + 1] - idx;
-  const QuakeItem *p = &kQuakeItems[idx], *pend = p + num;
-  do {
-    uint16 x = p->x + quake_var2 - BG2HOFS_copy2;
-    uint16 y = p->y + quake_var1 - BG2VOFS_copy2;
-
-    uint8 xval = oam->x, yval = 0xf0;
-    if (x < 256 && y < 256) {
-      xval = x;
-      if (y < 0xf0)
-        yval = y;
-    }
-    SetOamPlain(oam, xval, yval, kQuakeDrawGroundBolts_Char[p->f & 0x0f], p->f & 0xc0 | 0x3c, 2);
-    oam++, oam_cur_ptr += 4, oam_ext_cur_ptr += 1;
-  } while (++p != pend);
-}
-
-void QuakeSpell_SpreadBolts(int k) {  // 88b84f
-  if (ancilla_step[k] != 1)
-    return;
-  if (ancilla_timer[k] == 0) {
-    ancilla_timer[k] = 2;
-    if (++ancilla_item_to_link[k] == 55) {
-      ancilla_step[k] = 2;
-      return;
-    }
-  }
-  int t = ancilla_item_to_link[k];
-  int idx = kQuakeItemPos2[t], num = kQuakeItemPos2[t + 1] - idx;
-  const QuakeItem *p = &kQuakeItems2[idx], *pend = p + num;
-  OamEnt *oam = GetOamCurPtr();
-  do {
-    SetOamPlain(oam, p->x, p->y, kQuakeDrawGroundBolts_Char[p->f & 0x0f], p->f & 0xc0 | 0x3c, p->f >> 4 & 3);
-    oam_cur_ptr += 4, oam_ext_cur_ptr += 1;
-    oam = Ancilla_AllocateOamFromCustomRegion(oam + 1);
-  } while (++p != pend);
-}
-
-void Ancilla1A_PowderDust(int k) {  // 88bab0
-  if (submodule_index == 0) {
-    Powder_ApplyDamageToSprites(k);
-    if (sign8(--ancilla_aux_timer[k])) {
-      ancilla_aux_timer[k] = 1;
-      int j = ancilla_dir[k];
-      if (ancilla_item_to_link[k] == 9) {
-        ancilla_type[k] = 0;
-        byte_7E0333 = 0;
-        return;
-      }
-      ancilla_arr25[k] = kMagicPowder_Tab0[++ancilla_item_to_link[k] + j * 10];
-    }
-  }
-  Ancilla_AllocateOamFromRegion_B_or_E(ancilla_numspr[k]);
-  Ancilla_MagicPowder_Draw(k);
-}
-
-void Ancilla_MagicPowder_Draw(int k) {  // 88baeb
-  static const int8 kMagicPowder_DrawX[76] = {
-    -5, -12,  2,  -9, -7, -10, -6, -2, -6, -12,  1, -6,  -6, -12,   1,  -6,
-    -6, -12,  1,  -6, -6, -12,  1, -6, -6, -12,  1, -6, -17, -23, -14, -19,
-    -11, -18, -9, -13, -4, -13, -1, -8, -3,  -9,  0, -5,  -3, -10,  -1,  -5,
-    -4, -13, -1,  -8, -3,  -9,  0, -5, -3, -10, -1, -5,  -3, -13,  -1,  -8,
-    9,  15,  6,  11,  3,  10,  1,  5, -4,   5, -7,  0,
-  };
-  static const int8 kMagicPowder_DrawY[76] = {
-    -20, -15, -13,  -7, -18, -13, -13, -13, -20, -13, -13,  -8, -20, -13, -13,  -8,
-    -19, -12, -12,  -7, -18, -11, -11,  -6, -17, -10, -10,  -5, -16, -14, -12,  -9,
-    -17, -14, -12,  -8, -18, -14, -13,  -6, -33, -31, -29, -26, -28, -25, -23, -19,
-    -22, -18, -17, -10,  -2,   0,   2,   5,  -9,  -6,  -4,   0, -16, -12, -11,  -4,
-    -16, -14, -12,  -9, -17, -14, -12,  -8, -18, -14, -13,  -6,
-  };
-  static const uint8 kMagicPowder_Draw_Char[19] = {
-    9, 10, 10, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
-  };
-  static const uint8 kMagicPowder_Draw_Flags[76] = {
-    0x68, 0x24, 0xa2, 0x28, 0x68, 0xe2, 0x28, 0xa4, 0x68, 0xe2, 0xa4, 0x28, 0x22, 0xa4, 0xe8, 0x62,
-    0x24, 0xa8, 0xe2, 0x64, 0x28, 0xa2, 0xe4, 0x68, 0x22, 0xa4, 0xe8, 0x62, 0xe2, 0xa4, 0xe8, 0x64,
-    0xe8, 0xa8, 0xe4, 0x62, 0xe4, 0xa8, 0xe2, 0x68, 0xe2, 0xa4, 0xe8, 0x64, 0xe8, 0xa8, 0xe4, 0x62,
-    0xe4, 0xa8, 0xe2, 0x68, 0xe2, 0xa4, 0xe8, 0x64, 0xe8, 0xa8, 0xe4, 0x62, 0xe4, 0xa8, 0xe2, 0x68,
-    0xe2, 0xa4, 0xe8, 0x64, 0xe8, 0xa8, 0xe4, 0x62, 0xe4, 0xa8, 0xe2, 0x68,
-  };
-  Point16U info;
-  Ancilla_PrepOamCoord(k, &info);
-  OamEnt *oam = GetOamCurPtr();
-  int b = ancilla_arr25[k];
-  for (int i = 0; i < 4; i++, oam++) {
-    Ancilla_SetOam(oam, info.x + kMagicPowder_DrawX[b * 4 + i], info.y + kMagicPowder_DrawY[b * 4 + i],
-                   kMagicPowder_Draw_Char[b], kMagicPowder_Draw_Flags[b * 4 + i] & ~0x30 | HIBYTE(oam_priority_value), 0);
-  }
-}
-
-void Powder_ApplyDamageToSprites(int k) {  // 88bb58
-  uint8 a;
-  for (int j = 15; j >= 0; j--) {
-    if ((frame_counter ^ j) & 3 || sprite_state[j] != 9 || sprite_bump_damage[j] & 0x20)
-      continue;
-    SpriteHitBox hb;
-    Ancilla_SetupBasicHitBox(k, &hb);
-    Sprite_SetupHitBox(j, &hb);
-    if (!CheckIfHitBoxesOverlap(&hb))
-      continue;
-
-    if ((a = sprite_type[j]) != 0xb || (a = player_is_indoors) == 0 || (a = dungeon_room_index2 - 1) != 0) {
-      if (a != 0xd) {
-        Ancilla_CheckDamageToSprite_preset(j, 10);
-        continue;
-      }
-      if (sprite_head_dir[j] != 0)
-        continue;
-    }
-    sprite_head_dir[j] = 1;
-    Sprite_SpawnPoofGarnish(j);
-  }
-}
-
-void Ancilla1D_ScreenShake(int k) {  // 88bbbc
-  if (submodule_index == 0) {
-    if (sign8(--ancilla_item_to_link[k])) {
-      bg1_x_offset = 0;
-      bg1_y_offset = 0;
-      ancilla_type[k] = 0;
-      return;
-    }
-    int offs = DashTremor_TwiddleOffset(k);
-    int j = ancilla_dir[k];
-    if (j == 0) {
-      bg1_x_offset = offs;
-      link_x_vel += offs;
-    } else {
-      bg1_y_offset = offs;
-      link_y_vel += offs;
-    }
-  }
-  sprite_alert_flag = 3;
-}
-
-void Ancilla1E_DashDust(int k) {  // 88bc92
-  if (ancilla_step[k]) {
-    DashDust_Motive(k);
-    return;
-  }
-  if (!ancilla_timer[k]) {
-    ancilla_timer[k] = 3;
-    if (++ancilla_item_to_link[k] == 5)
-      return;
-    if (ancilla_item_to_link[k] == 6) {
-      ancilla_type[k] = 0;
-      return;
-    }
-  }
-  if (ancilla_item_to_link[k] == 5)
-    return;
-
-  Point16U info;
-  Ancilla_PrepOamCoord(k, &info);
-  OamEnt *oam = GetOamCurPtr();
-
-  static const int8 kDashDust_Draw_X1[4] = {0, 0, 4, -4};
-  static const int16 kDashDust_Draw_X[30] = {
-    10,  5, -1,  0, 10, 5, 0,  5, -1,  0, -1, -1,  9, -1, -1, 10,
-    5, -1,  0, 10,  5, 0, 5, -1,  0, -1, -1,  9, -1, -1,
-  };
-  static const int16 kDashDust_Draw_Y[30] = {
-    -2,  0, -1, -3, -2,  0, -3,  0, -1, -3, -1, -1, -2, -1, -1, -2,
-    0, -1, -3, -2,  0, -3,  0, -1, -3, -1, -1, -2, -1, -1,
-  };
-  static const uint8 kDashDust_Draw_Char[30] = {
-    0xcf, 0xa9, 0xff, 0xa9, 0xdf, 0xcf, 0xcf, 0xdf, 0xff, 0xdf, 0xff, 0xff, 0xa9, 0xff, 0xff, 0xcf,
-    0xcf, 0xff, 0xcf, 0xdf, 0xcf, 0xcf, 0xdf, 0xff, 0xdf, 0xff, 0xff, 0xcf, 0xff, 0xff,
-  };
-  int r12 = kDashDust_Draw_X1[link_direction_facing >> 1];
-  int t = 3 * (ancilla_item_to_link[k] + (draw_water_ripples_or_grass == 1 ? 5 : 0));
-
-  for (int n = 2; n >= 0; n--, t++) {
-    if (kDashDust_Draw_Char[t] != 0xff) {
-      Ancilla_SetOam(oam, info.x + r12 + kDashDust_Draw_X[t], info.y + kDashDust_Draw_Y[t], kDashDust_Draw_Char[t], 4 | HIBYTE(oam_priority_value), 0);
-      oam++;
-    }
-  }
-}
-
-void Ancilla1F_Hookshot(int k) {  // 88bd74
-  if (submodule_index != 0)
-    goto do_draw;
-
-  if (!ancilla_timer[k]) {
-    ancilla_timer[k] = 7;
-    Ancilla_Sfx2_Pan(k, 0xa);
-  }
-
-  if (related_to_hookshot)
-    goto do_draw;
-  Ancilla_MoveY(k);
-  Ancilla_MoveX(k);
-  if (ancilla_step[k]) {
-    if (sign8(--ancilla_item_to_link[k])) {
-      ancilla_type[k] = 0;
-      return;
-    }
-    goto do_draw;
-  }
-
-  if (++ancilla_item_to_link[k] == 32) {
-    ancilla_step[k] = 1;
-    ancilla_x_vel[k] = -ancilla_x_vel[k];
-    ancilla_y_vel[k] = -ancilla_y_vel[k];
-  }
-
-  if (Hookshot_ShouldIEvenBotherWithTiles(k))
-    goto do_draw;
-
-  if (!ancilla_L[k] && !ancilla_step[k] && Ancilla_CheckSpriteCollision(k) >= 0 && !ancilla_step[k]) {
-    ancilla_step[k] = 1;
-    ancilla_y_vel[k] = -ancilla_y_vel[k];
-    ancilla_x_vel[k] = -ancilla_x_vel[k];
-  }
-
-  Hookshot_CheckTileCollision(k);
-
-  uint8 r0;
-
-  r0 = 0;
-
-  if (player_is_indoors) {
-    if (!(ancilla_dir[k] & 2)) {
-      r0 = (tiledetect_vertical_ledge | (tiledetect_vertical_ledge >> 4)) & 3;
-    } else {
-      r0 = detection_of_ledge_tiles_horiz_uphoriz & 3;
-    }
-    if (r0 == 0)
-      goto endif_7;
-  } else {
-    if (!((detection_of_ledge_tiles_horiz_uphoriz & 3 | tiledetect_vertical_ledge | detection_of_unknown_tile_types) & 0x33))
-      goto endif_7;
-  }
-  if (sign8(--ancilla_G[k])) {
-    if (ancilla_K[k] && ((r0 & 3) || ancilla_K[k] != BYTE(index_of_interacting_tile))) {
-      ancilla_G[k] = 2;
-      if (sign8(--ancilla_L[k]))
-        ancilla_L[k] = 0;
-    } else {
-      ancilla_L[k]++;
-      ancilla_K[k] = index_of_interacting_tile;
-      ancilla_G[k] = 1;
-    }
-  }
-endif_7:
-  if (ancilla_L[k])
-    goto do_draw;
-  if (!sign8(ancilla_G[k])) {
-    ancilla_G[k]--;
-    goto do_draw;
-  }
-
-  if ((R14 >> 4 | R14 | tiledetect_stair_tile | R12) & 3 && !ancilla_step[k]) {
-    ancilla_step[k] = 1;
-    ancilla_y_vel[k] = -ancilla_y_vel[k];
-    ancilla_x_vel[k] = -ancilla_x_vel[k];
-    if (!(tiledetect_misc_tiles & 3)) {
-      AncillaAdd_HookshotWallClink(k, 6, 1);
-      Ancilla_Sfx2_Pan(k, (tiledetect_misc_tiles & 0x30) ? 6 : 5);
-    }
-  }
-
-  if (tiledetect_misc_tiles & 3) {
-    if (ancilla_item_to_link[k] < 4) {
-      ancilla_type[k] = 0;
-      return;
-    }
-    related_to_hookshot = 1;
-    hookshot_effect_index = k;
-  }
-
-  static const int8 kHookShot_Move_X[4] = {0, 0, 8, -8};
-  static const int8 kHookShot_Move_Y[4] = {8, -9, 0, 0};
-  static const uint8 kHookShot_Draw_Flags[12] = {0, 0, 0xff, 0x80, 0x80, 0xff, 0x40, 0xff, 0x40, 0, 0xff, 0};
-  static const uint8 kHookShot_Draw_Char[12] = {9, 0xa, 0xff, 9, 0xa, 0xff, 9, 0xff, 0xa, 9, 0xff, 0xa};
-
-  Point16U info;
-do_draw:
-  Ancilla_PrepOamCoord(k, &info);
-  if (ancilla_L[k])
-    oam_priority_value = 0x3000;
-  OamEnt *oam = GetOamCurPtr();
-
-  int j = ancilla_dir[k] * 3;
-  int x = info.x, y = info.y;
-  for (int i = 2; i >= 0; i--, j++) {
-    if (kHookShot_Draw_Char[j] != 0xff) {
-      Ancilla_SetOam(oam, x, y, kHookShot_Draw_Char[j], kHookShot_Draw_Flags[j] | 2 | HIBYTE(oam_priority_value), 0);
-      oam++;
-    }
-    if (i == 1)
-      x -= 8, y += 8;
-    else
-      x += 8;
-  }
-
-  int r10 = 0;
-  int n = ancilla_item_to_link[k] >> 1;
-  if (n >= 7) {
-    r10 = n - 7;
-    n = 6;
-  }
-  if (n == 0)
-    return;
-  if (ancilla_dir[k] & 1)
-    r10 = -r10;
-  x = info.x, y = info.y;
-  j = ancilla_dir[k];
-  if (kHookShot_Move_Y[j] == 0)
-    y += 4;
-  if (kHookShot_Move_X[j] == 0)
-    x += 4;
-  do {
-    if (kHookShot_Move_Y[j])
-      y += kHookShot_Move_Y[j] + r10;
-    if (kHookShot_Move_X[j])
-      x += kHookShot_Move_X[j] + r10;
-    if (!Hookshot_CheckProximityToLink(x, y)) {
-      Ancilla_SetOam(oam, x, y, 0x19, (frame_counter & 2) << 6 | 2 | HIBYTE(oam_priority_value), 0);
-      oam++;
-    }
-  } while (--n >= 0);
-}
-
-void Ancilla20_Blanket(int k) {  // 88c013
-  static const uint8 kBedSpread_Char[8] = {0xa, 0xa, 0xa, 0xa, 0xc, 0xc, 0xa, 0xa};
-  static const uint8 kBedSpread_Flags[8] = {0, 0x60, 0xa0, 0xe0, 0, 0x60, 0xa0, 0xe0};
-  Point16U pt;
-  Ancilla_PrepOamCoord(k, &pt);
-
-  if (!link_pose_during_opening) {
-    Oam_AllocateFromRegionB(0x10);
-  } else {
-    Oam_AllocateFromRegionA(0x10);
-  }
-
-  OamEnt *oam = GetOamCurPtr();
-  int j = link_pose_during_opening ? 4 : 0;
-  uint16 x = pt.x, y = pt.y;
-  for (int i = 3; i >= 0; i--, j++, oam++) {
-    Ancilla_SetOam(oam, x, y, kBedSpread_Char[j], kBedSpread_Flags[j] | 0xd | HIBYTE(oam_priority_value), 2);
-    x += 16;
-    if (i == 2)
-      x -= 32, y += 8;
-  }
-}
-
-void Ancilla21_Snore(int k) {  // 88c094
-  static const uint8 kBedSpread_Dma[3] = {0x44, 0x43, 0x42};
-  if (sign8(--ancilla_aux_timer[k])) {
-    if (ancilla_item_to_link[k] != 2)
-      ancilla_item_to_link[k]++;
-    ancilla_aux_timer[k] = 7;
-  }
-  ancilla_x_vel[k] += ancilla_step[k];
-  if (abs8(ancilla_x_vel[k]) >= 8)
-    ancilla_step[k] = -ancilla_step[k];
-  Ancilla_MoveY(k);
-  Ancilla_MoveX(k);
-  if (Ancilla_GetY(k) <= (uint16)(link_y_coord - 24))
-    ancilla_type[k] = 0;
-  link_dma_var5 = kBedSpread_Dma[ancilla_item_to_link[k]];
-  Point16U pt;
-  Ancilla_PrepOamCoord(k, &pt);
-  Ancilla_SetOam(GetOamCurPtr(), pt.x, pt.y, 9, 0x24, 0);
-}
-
-void Ancilla3B_SwordUpSparkle(int k) {  // 88c167
-  static const int8 kAncilla_VictorySparkle_X[16] = {16, 0, 0, 0, 8, 16, 8, 16, 9, 15, 0, 0, 12, 0, 0, 0};
-  static const int8 kAncilla_VictorySparkle_Y[16] = {-7, 0, 0, 0, -11, -11, -3, -3, -7, -7, 0, 0, -7, 0, 0, 0};
-  static const uint8 kAncilla_VictorySparkle_Char[16] = {0x92, 0xff, 0xff, 0xff, 0x93, 0x93, 0x93, 0x93, 0xf9, 0xf9, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff};
-  static const uint8 kAncilla_VictorySparkle_Flags[16] = {0, 0xff, 0xff, 0xff, 0, 0x40, 0x80, 0xc0, 0, 0x40, 0xff, 0xff, 0, 0xff, 0xff, 0xff};
-
-  if (ancilla_aux_timer[k]) {
-    ancilla_aux_timer[k]--;
-    return;
-  }
-
-  if (sign8(--ancilla_arr3[k])) {
-    ancilla_arr3[k] = 1;
-    if (++ancilla_item_to_link[k] == 4) {
-      ancilla_type[k] = 0;
-      ancilla_aux_timer[k]--;
-      return;
-    }
-  }
-  Point16U pt;
-  Ancilla_PrepOamCoord(k, &pt);
-  OamEnt *oam = GetOamCurPtr();
-  int j = ancilla_item_to_link[k] * 4;
-  for (int i = 0; i < 4; i++, j++) {
-    if (kAncilla_VictorySparkle_Char[j] != 0xff) {
-      Ancilla_SetOam(oam,
-                     link_x_coord + kAncilla_VictorySparkle_X[j] - BG2HOFS_copy2,
-                     link_y_coord + kAncilla_VictorySparkle_Y[j] - BG2VOFS_copy2,
-                     kAncilla_VictorySparkle_Char[j],
-                     kAncilla_VictorySparkle_Flags[j] | 4 | HIBYTE(oam_priority_value), 0);
-      oam++;
-    }
-  }
-}
-
-void Ancilla3C_SpinAttackChargeSparkle(int k) {  // 88c1ea
-  static const uint8 kSwordChargeSpark_Char[3] = {0xb7, 0x80, 0x83};
-  static const uint8 kSwordChargeSpark_Flags[3] = {4, 4, 0x84};
-
-  if (!submodule_index && !ancilla_timer[k]) {
-    ancilla_timer[k] = 4;
-    if (++ancilla_item_to_link[k] == 3) {
-      ancilla_type[k] = 0;
-      return;
-    }
-  }
-  ancilla_oam_idx[k] = Ancilla_AllocateOamFromRegion_A_or_D_or_F(k, 4);
-  Point16U info;
-  Ancilla_PrepOamCoord(k, &info);
-  int j = ancilla_item_to_link[k];
-  Ancilla_SetOam(GetOamCurPtr(), info.x, info.y,
-                 kSwordChargeSpark_Char[j], kSwordChargeSpark_Flags[j] | HIBYTE(oam_priority_value), 0);
-}
-
-void Ancilla35_MasterSwordReceipt(int k) {  // 88c25f
-  static const int8 kSwordCeremony_X[8] = {-1, 8, -1, 8, 0, 7, 0, 7};
-  static const int8 kSwordCeremony_Y[8] = {1, 1, 9, 9, 1, 1, 9, 9};
-  static const uint8 kSwordCeremony_Char[8] = {0x86, 0x86, 0x96, 0x96, 0x87, 0x87, 0x97, 0x97};
-  static const uint8 kSwordCeremony_Flags[8] = {1, 0x41, 1, 0x41, 1, 0x41, 1, 0x41};
-
-  if (!ancilla_timer[k]) {
-    ancilla_type[k] = 0;
-    return;
-  }
-  if (sign8(--ancilla_aux_timer[k])) {
-    ancilla_item_to_link[k] = (ancilla_item_to_link[k] == 2) ? 0 : ancilla_item_to_link[k] + 1;
-  }
-
-  Point16U pt;
-  Ancilla_PrepOamCoord(k, &pt);
-  OamEnt *oam = GetOamCurPtr();
-  int j = (ancilla_item_to_link[k] - 1) * 4;
-  if (j < 0)
-    return;
-
-  for (int i = 0; i < 4; i++, j++, oam++) {
-    Ancilla_SetOam(oam, pt.x + kSwordCeremony_X[j], pt.y + kSwordCeremony_Y[j],
-                   kSwordCeremony_Char[j], kSwordCeremony_Flags[j] & ~0x30 | 4 | HIBYTE(oam_priority_value), 0);
-  }
-}
-
-void Ancilla22_ItemReceipt(int k) {  // 88c38a
-  uint8 a;
-
-  if (flag_is_link_immobilized == 2)
-    goto endif_1;
-  if (submodule_index != 0 && submodule_index != 43 && submodule_index != 9) {
-    if (submodule_index == 2)
-      ancilla_timer[k] = 16;
-    goto endif_1;
-  }
-  flag_unk1++;
-
-  if (ancilla_step[k] != 0 && ancilla_step[k] != 3) {
-    if (sign8(--ancilla_aux_timer[k]))
-      goto endif_11;
-
-    if (ancilla_aux_timer[k] == 0)
-      goto endif_6;
-
-    if (ancilla_aux_timer[k] == 40 && ancilla_step[k] != 2) {
-      if (Ancilla_AddRupees(k) || ancilla_item_to_link[k] != 0x17)
-        Ancilla_Sfx3_Near(0xf);
-    }
-    goto label_b;
-  }
-
-  if (ancilla_item_to_link[k] == 1 && ancilla_step[k] != 2) {
-    if (ancilla_timer[k] == 0)
-      goto label_a;
-    if (ancilla_timer[k] != 17)
-      goto endif_1;
-    word_7E02CD = 0xDF3;
-    follower_indicator = 0xe;
-    goto endif_6;
-  }
-
-  a = --ancilla_aux_timer[k];
-  if (a == 0)
-    goto label_a;
-  if (a == 1) {
-    if (ancilla_item_to_link[k] != 0x37 && ancilla_item_to_link[k] != 0x38 && ancilla_item_to_link[k] != 0x39 || zelda_read_apui00() == 0)
-      goto endif_6;
-    ancilla_aux_timer[k]++;
-  }
-  goto endif_1;
-
-label_a:
-  if (ancilla_item_to_link[k] == 1 && !ancilla_step[k]) {
-    sound_effect_ambient = 5;
-    music_control = 2;
-  }
-  link_player_handler_state = link_is_in_deep_water ? kPlayerState_Swimming : 0;
-  link_receiveitem_index = 0;
-  link_pose_for_item = 0;
-  link_disable_sprite_damage = 0;
-  Ancilla_AddRupees(k);
-endif_11:
-  item_receipt_method = 0;
-  a = ancilla_item_to_link[k];
-  if (a == 23 && link_heart_pieces == 0) {
-    Link_ReceiveItem(0x26, 0);
-    ancilla_type[k] = 0;
-    flag_unk1 = 0;
-    return;
-  }
-
-  if (a == 0x26 || a == 0x3f) {
-    if (link_health_capacity != 0xa0) {
-      link_health_capacity += 8;
-      link_hearts_filler += link_health_capacity - link_health_current;
-      Ancilla_Sfx3_Near(0xd);
-    }
-  } else if (a == 0x3e) {
-    flag_is_link_immobilized = 0;
-    if (link_health_capacity != 0xa0) {
-      link_health_capacity += 8;
-      link_hearts_filler += 8;
-      Ancilla_Sfx3_Near(0xd);
-    }
-  } else if (a == 0x42) {
-    link_hearts_filler += 8;
-  } else if (a == 0x45) {
-    link_magic_filler += 16;
-  } else if (a == 0x22 || a == 0x23) {
-    Palette_Load_LinkArmorAndGloves();
-  }
-
-  ancilla_type[k] = 0;
-  flag_unk1 = 0;
-  a = ancilla_item_to_link[k];
-  if (ancilla_step[k] == 3 && a != 0x10 && a != 0x26 && a != 0xf && a != 0x20) {
-    PrepareDungeonExitFromBossFight();
-  }
-
-  if (ancilla_step[k] != 2)
-    flag_is_link_immobilized = 0;
-  return;
-
-endif_6:
-  if (player_is_indoors) {
-    int room = dungeon_room_index;
-    if (room == 0xff || room == 0x10f || room == 0x110 || room == 0x112 || room == 0x11f)
-      goto label_b;
-  }
-  int msg;
-  msg = -1;
-  if (ancilla_item_to_link[k] == 0x38 || ancilla_item_to_link[k] == 0x39) {
-    if ((link_which_pendants & 7) == 7)
-      msg = kReceiveItemMsgs2[ancilla_item_to_link[k] - 0x38];
-    else
-      msg = kReceiveItemMsgs[ancilla_item_to_link[k]];
-  } else if (ancilla_step[k] != 2) {
-    if (ancilla_item_to_link[k] == 0x17)
-      msg = kReceiveItemMsgs3[link_heart_pieces];
-    else
-      msg = kReceiveItemMsgs[ancilla_item_to_link[k]];
-  }
-  if (msg != -1) {
-    dialogue_message_index = msg;
-    if (msg == 0x70)
-      sound_effect_ambient = 9;
-    Main_ShowTextMessage();
-  }
-  goto endif_1;
-
-label_b:
-  if (ancilla_aux_timer[k] >= 24) {
-    a = ancilla_y_vel[k] - 1;
-    if (a >= 248)
-      ancilla_y_vel[k] = a;
-    Ancilla_MoveY(k);
-  }
-endif_1:
-
-  if (ancilla_item_to_link[k] == 0x20) {
-    ancilla_z[k] = 0;
-    AncillaAdd_OccasionalSparkle(k);
-    if (zelda_read_apui00() == 0) {
-      music_control = 0x1a;
-      ItemReceipt_TransmuteToRisingCrystal(k);
-      return;
-    }
-  } else if (ancilla_item_to_link[k] == 0x1) {
-    ancilla_arr4[k] = kReceiveItem_Tab0[0];
-    if (ancilla_step[k] != 2) {
-      if (ancilla_timer[k] < 16) {
-        a = 0;
-      } else {
-        if (!sign8(--ancilla_arr3[k]))
-          goto skipit;
-        ancilla_arr3[k] = 2;
-        a = ancilla_arr1[k] + 1;
-        if (a == 3)
-          a = 0;
-      }
-      ancilla_arr1[k] = a;
-      ancilla_arr4[k] = kReceiveItem_Tab0[a];
-skipit:;
-    }
-  }
-
-  if ((ancilla_item_to_link[k] == 0x34 || ancilla_item_to_link[k] == 0x35 || ancilla_item_to_link[k] == 0x36) && sign8(--ancilla_arr3[k])) {
-    a = ancilla_arr1[k] + 1;
-    if (a == 3)
-      a = 0;
-    ancilla_arr1[k] = a;
-    ancilla_arr3[k] = kReceiveItem_Tab4[a];
-    WriteTo4BPPBuffer_at_7F4000(kReceiveItem_Tab5[a]);
-  }
-  Point16U pt;
-  Ancilla_PrepAdjustedOamCoord(k, &pt);
-  Ancilla_ReceiveItem_Draw(k, pt.x, pt.y);
-}
-
-OamEnt *Ancilla_ReceiveItem_Draw(int k, int x, int y) {  // 88c690
-  OamEnt *oam = GetOamCurPtr();
-  int j = ancilla_item_to_link[k];
-  oam->charnum = 0x24;
-  uint8 a = kWishPond2_OamFlags[j];
-  if (sign8(a))
-    a = ancilla_arr4[k];
-  Ancilla_SetOam(oam, x, y, 0x24, a * 2 | 0x30, kReceiveItem_Tab1[j]);
-  oam++;
-  if (kReceiveItem_Tab1[j] == 0) {
-    Ancilla_SetOam(oam, x, y + 8, 0x34, a * 2 | 0x30, 0);
-    oam++;
-  }
-  return oam;
-}
-
-void Ancilla28_WishPondItem(int k) {  // 88c6f2
-  Ancilla_AllocateOamFromRegion_A_or_D_or_F(k, 0x10);
-
-  if (submodule_index == 0 && ancilla_timer[k] == 0) {
-    link_picking_throw_state = 2;
-    link_state_bits = 0;
-    ancilla_z_vel[k] -= 2;
-    Ancilla_MoveZ(k);
-    Ancilla_MoveY(k);
-    Ancilla_MoveX(k);
-    if (sign8(ancilla_z[k]) && ancilla_z[k] < 228) {
-      ancilla_z[k] = 228;
-      Ancilla_SetXY(k,
-          Ancilla_GetX(k) + (kGeneratedWishPondItem[ancilla_item_to_link[k]] ? 8 : 4), // wtf
-          Ancilla_GetY(k) + 18);
-      Ancilla_TransmuteToSplash(k);
-      return;
-    }
-  }
-  WishPondItem_Draw(k);
-}
-
-void WishPondItem_Draw(int k) {  // 88c760
-  Point16U pt;
-  Ancilla_PrepAdjustedOamCoord(k, &pt);
-
-  if (ancilla_item_to_link[k] == 1)
-    ancilla_arr4[k] = 5;
-
-  OamEnt *oam = Ancilla_ReceiveItem_Draw(k, pt.x, pt.y - (int8)ancilla_z[k]);
-
-  if (link_picking_throw_state != 2 || !sign8(ancilla_z_vel[k]) && ancilla_z_vel[k] >= 2)
-    return;
-
-  uint8 xx = kGeneratedWishPondItem[ancilla_item_to_link[k]];
-  AncillaDraw_Shadow(oam,
-    (xx == 2) ? 1 : 2,
-    pt.x - (xx == 2 ? 0 : 4),
-    pt.y + 40, HIBYTE(oam_priority_value));
-}
-
-void Ancilla42_HappinessPondRupees(int k) {  // 88c7de
-  link_picking_throw_state = 2;
-  link_state_bits = 0;
-  for (int i = 9; i >= 0; i--) {
-    if (happiness_pond_arr1[i]) {
-      HapinessPondRupees_ExecuteRupee(k, i);
-      if (happiness_pond_step[i] == 2)
-        happiness_pond_arr1[i] = 0;
-    }
-  }
-  for (int i = 9; i >= 0; i--) {
-    if (happiness_pond_arr1[i])
-      return;
-  }
-  ancilla_type[k] = 0;
-}
-
-void HapinessPondRupees_ExecuteRupee(int k, int i) {  // 88c819
-  Ancilla_AllocateOamFromRegion_A_or_D_or_F(k, 0x10);
-  HapinessPondRupees_GetState(k, i);
-
-  if (ancilla_step[k]) {
-    if (!submodule_index && !ancilla_timer[k]) {
-      ancilla_timer[k] = 6;
-      if (++ancilla_item_to_link[k] == 5) {
-        ancilla_step[k]++;
-      } else {
-        ObjectSplash_Draw(k);
-      }
-    } else {
-      ObjectSplash_Draw(k);
-    }
-  } else if (submodule_index == 0 && ancilla_timer[k] == 0) {
-    ancilla_z_vel[k] -= 2;
-    Ancilla_MoveY(k);
-    Ancilla_MoveX(k);
-    Ancilla_MoveZ(k);
-    if (!sign8(ancilla_z[k]) || ancilla_z[k] >= 0xe4)
-      goto else_label;
-    ancilla_z[k] = 0xe4;
-    Ancilla_SetXY(k, Ancilla_GetX(k) - 4, Ancilla_GetY(k) + 30);
-    ancilla_item_to_link[k] = 0;
-    ancilla_timer[k] = 6;
-    Ancilla_Sfx2_Pan(k, 0x28);
-    ancilla_step[k]++;
-    ObjectSplash_Draw(k);
-  } else {
-else_label:
-    ancilla_arr4[k] = 2;
-    ancilla_floor[k] = 0;
-    WishPondItem_Draw(k);
-  }
-  HapinessPondRupees_SaveState(i, k);
-}
-
-void HapinessPondRupees_GetState(int j, int k) {  // 88c8be
-  ancilla_y_lo[j] = happiness_pond_y_lo[k];
-  ancilla_y_hi[j] = happiness_pond_y_hi[k];
-  ancilla_x_lo[j] = happiness_pond_x_lo[k];
-  ancilla_x_hi[j] = happiness_pond_x_hi[k];
-  ancilla_z[j] = happiness_pond_z[k];
-  ancilla_y_vel[j] = happiness_pond_y_vel[k];
-  ancilla_x_vel[j] = happiness_pond_x_vel[k];
-  ancilla_z_vel[j] = happiness_pond_z_vel[k];
-  ancilla_y_subpixel[j] = happiness_pond_y_subpixel[k];
-  ancilla_x_subpixel[j] = happiness_pond_x_subpixel[k];
-  ancilla_z_subpixel[j] = happiness_pond_z_subpixel[k];
-  ancilla_item_to_link[j] = happiness_pond_item_to_link[k];
-  ancilla_step[j] = happiness_pond_step[k];
-  ancilla_timer[j] = happiness_pond_timer[k] ? happiness_pond_timer[k] - 1 : 0;
-}
-
-void HapinessPondRupees_SaveState(int k, int j) {  // 88c924
-  happiness_pond_y_lo[k] = ancilla_y_lo[j];
-  happiness_pond_y_hi[k] = ancilla_y_hi[j];
-  happiness_pond_x_lo[k] = ancilla_x_lo[j];
-  happiness_pond_x_hi[k] = ancilla_x_hi[j];
-  happiness_pond_z[k] = ancilla_z[j];
-  happiness_pond_y_vel[k] = ancilla_y_vel[j];
-  happiness_pond_x_vel[k] = ancilla_x_vel[j];
-  happiness_pond_z_vel[k] = ancilla_z_vel[j];
-  happiness_pond_y_subpixel[k] = ancilla_y_subpixel[j];
-  happiness_pond_x_subpixel[k] = ancilla_x_subpixel[j];
-  happiness_pond_z_subpixel[k] = ancilla_z_subpixel[j];
-  happiness_pond_item_to_link[k] = ancilla_item_to_link[j];
-  happiness_pond_timer[k] = ancilla_timer[j];
-  happiness_pond_step[k] = ancilla_step[j];
-}
-
-void Ancilla_TransmuteToSplash(int k) {  // 88c9cd
-  ancilla_type[k] = 0x3d;
-  ancilla_item_to_link[k] = 0;
-  ancilla_timer[k] = 6;
-  Ancilla_SetXY(k, Ancilla_GetX(k) - 8, Ancilla_GetY(k) + 12);
-  Ancilla_Sfx2_Pan(k, 0x28);
-  Ancilla3D_ItemSplash(k);
-}
-
-void Ancilla3D_ItemSplash(int k) {  // 88ca01
-  Ancilla_AllocateOamFromRegion_A_or_D_or_F(k, 8);
-  if (!submodule_index && !ancilla_timer[k]) {
-    ancilla_timer[k] = 6;
-    if (++ancilla_item_to_link[k] == 5) {
-      ancilla_type[k] = 0;
-      return;
-    }
-  }
-  ObjectSplash_Draw(k);
-}
-
-void ObjectSplash_Draw(int k) {  // 88ca22
-  static const int8 kObjectSplash_Draw_X[10] = {0, 0, 0, 0, 11, -3, 15, -7, 15, -7};
-  static const int8 kObjectSplash_Draw_Y[10] = {0, 0, -6, 0, -13, -8, -17, -4, -17, -4};
-  static const uint8 kObjectSplash_Draw_Char[10] = {0xc0, 0xff, 0xe7, 0xff, 0xaf, 0xbf, 0x80, 0x80, 0x83, 0x83};
-  static const uint8 kObjectSplash_Draw_Flags[10] = {0, 0xff, 0, 0xff, 0x40, 0, 0x40, 0, 0xc0, 0x80};
-  static const uint8 kObjectSplash_Draw_Ext[10] = {2, 0, 2, 0, 0, 0, 0, 0, 0, 0};
-  Point16U pt;
-  Ancilla_PrepOamCoord(k, &pt);
-  OamEnt *oam = GetOamCurPtr();
-  int j = ancilla_item_to_link[k] * 2;
-  for (int i = 0; i != 2; i++, j++) {
-    if (kObjectSplash_Draw_Char[j] != 0xff) {
-      Ancilla_SetOam(oam, pt.x + kObjectSplash_Draw_X[j], pt.y + kObjectSplash_Draw_Y[j],
-                     kObjectSplash_Draw_Char[j], kObjectSplash_Draw_Flags[j] | 0x24, 
-                     kObjectSplash_Draw_Ext[j]);
-      oam++;
-    }
-  }
-}
-
-void Ancilla29_MilestoneItemReceipt(int k) {  // 88ca8c
-  if (ancilla_item_to_link[k] != 0x10 && ancilla_item_to_link[k] != 0x0f) {
-    if (dung_savegame_state_bits & 0x4000) {
-      ancilla_type[k] = 0;
-      return;
-    }
-
-    if (!(dung_savegame_state_bits & 0x8000))
-      return;
-
-    if (byte_7E04C2 != 0) {
-      if (byte_7E04C2 == 1) {
-        if (ancilla_item_to_link[k] == 0x20) {
-          sound_effect_ambient = 0x0f;
-          DecodeAnimatedSpriteTile_variable(0x28);
-        } else {
-          DecodeAnimatedSpriteTile_variable(0x23);
-        }
-      }
-      byte_7E04C2--;
-      return;
-    }
-    if (!ancilla_arr3[k] && ancilla_item_to_link[k] == 0x20) {
-      ancilla_arr3[k] = 1;
-      palette_sp6r_indoors = 4;
-      overworld_palette_aux_or_main = 0x200;
-      Palette_Load_SpriteEnvironment_Dungeon();
-      flag_update_cgram_in_nmi++;
-    }
-  } else {
-    if (ancilla_G[k]) {
-      ancilla_G[k]--;
-      return;
-    }
-  }
-
-  if (ancilla_item_to_link[k] == 0x20)
-    AncillaAdd_OccasionalSparkle(k);
-
-  if (submodule_index == 0) {
-    CheckPlayerCollOut coll_out;
-    if (ancilla_z[k] < 24 && Ancilla_CheckLinkCollision(k, 2, &coll_out) && related_to_hookshot == 0 && link_auxiliary_state == 0) {
-      ancilla_type[k] = 0;
-      if (link_player_handler_state == kPlayerState_ReceivingEther || link_player_handler_state == kPlayerState_ReceivingBombos) {
-        flag_custom_spell_anim_active = 0;
-        link_force_hold_sword_up = 0;
-        link_player_handler_state = 0;
-      }
-      item_receipt_method = 3;
-      Link_ReceiveItem(ancilla_item_to_link[k], 0);
-      return;
-    }
-
-    if (ancilla_step[k] != 2) {
-      if (ancilla_step[k] != 0) {
-        ancilla_z_vel[k]--;
-      }
-      Ancilla_MoveZ(k);
-      if (ancilla_z[k] >= 0xf8) {
-        ancilla_step[k]++;
-        ancilla_z_vel[k] = 0x18;
-        ancilla_z[k] = 0;
-      }
-    }
-  }
-
-  Point16U pt;
-  Ancilla_PrepAdjustedOamCoord(k, &pt);
-  OamEnt *oam = Ancilla_ReceiveItem_Draw(k, pt.x, pt.y - ancilla_z[k]);
-
-  if (sign8(--ancilla_aux_timer[k])) {
-    ancilla_aux_timer[k] = 9;
-    if (++ancilla_L[k] == 3)
-      ancilla_L[k] = 0;
-  }
-
-  int t;
-  if (ancilla_z[k] == 0) {
-    t = (dungeon_room_index == 6) ? ancilla_L[k] + 4 : 0;
-  } else {
-    t = ancilla_z[k] < 0x20 ? 1 : 2;
-  }
-  AncillaDraw_Shadow(oam, t, pt.x, pt.y + 12, 0x20);
-}
-
-void ItemReceipt_TransmuteToRisingCrystal(int k) {  // 88cbe4
-  ancilla_type[k] = 0x3e;
-  ancilla_y_vel[k] = 0;
-  ancilla_x_vel[k] = 0;
-  ancilla_y_subpixel[k] = 0;
-  Ancilla_RisingCrystal(k);
-}
-
-void Ancilla_RisingCrystal(int k) {  // 88cbf2
-  ancilla_z[k] = 0;
-  AncillaAdd_OccasionalSparkle(k);
-  uint8 yy = ancilla_y_vel[k] - 1;
-  if (yy < 0xf0)
-    yy = 0xf0;
-  ancilla_y_vel[k] = yy;
-  Ancilla_MoveY(k);
-
-  uint16 y = Ancilla_GetY(k) - BG2VOFS_copy;
-  if (y < 0x49) {
-    Ancilla_SetY(k, 0x49 + BG2VOFS_copy);
-    if (!submodule_index) {
-      link_has_crystals |= kDungeonCrystalPendantBit[BYTE(cur_palace_index_x2) >> 1];
-      submodule_index = 0x18;
-      subsubmodule_index = 0;
-      memset(aux_palette_buffer + 0x20, 0, sizeof(uint16) * 0x60);
-      palette_filter_countdown = 0;
-      darkening_or_lightening_screen = 0;
-    }
-  }
-
-  Point16U pt;
-  Ancilla_PrepAdjustedOamCoord(k, &pt);
-  Ancilla_ReceiveItem_Draw(k, pt.x, pt.y);
-}
-
-void AncillaAdd_OccasionalSparkle(int k) {  // 88cc93
-  if (!(frame_counter & 7))
-    AncillaAdd_SwordChargeSparkle(k);
-}
-
-void Ancilla43_GanonsTowerCutscene(int k) {  // 88cca0
-  OamEnt *oam = GetOamCurPtr();
-  if (!ancilla_step[k]) {
-    uint8 yy = ancilla_y_vel[k] - 1;
-    ancilla_y_vel[k] = (yy < 0xf0) ? 0xf0 : yy;
-    Ancilla_MoveY(k);
-    uint16 x = Ancilla_GetX(k), y = Ancilla_GetY(k);
-    if ((uint16)(y - BG2VOFS_copy) >= 0x38)
-      goto lbl_else;
-    breaktowerseal_y = 0x38 + 8 + BG2VOFS_copy;
-    breaktowerseal_x = x + 8;
-    Ancilla_SetY(k, 0x38 + BG2VOFS_copy);
-    ancilla_step[k]++;
-    sound_effect_ambient = 5;
-    music_control = 0xf1;
-    dialogue_message_index = 0x13b;
-    Main_ShowTextMessage();
-    goto label_a;
-  }
-lbl_else:
-  if (ancilla_step[k] == 1 && submodule_index == 0) {
-    ancilla_x_vel[k] = 16;
-    uint8 bak0 = ancilla_x_lo[k];
-    uint8 bak1 = ancilla_x_hi[k];
-    ancilla_x_lo[k] = breaktowerseal_var4;
-    ancilla_x_hi[k] = 0;
-    Ancilla_MoveX(k);
-    breaktowerseal_var4 = ancilla_x_lo[k];
-    ancilla_x_lo[k] = bak0;
-    ancilla_x_hi[k] = bak1;
-    if (breaktowerseal_var4 >= 48) {
-      breaktowerseal_var4 = 48;
-      ancilla_step[k]++;
-    }
-  }
-  if (submodule_index)
-    goto label_b;
-  if (ancilla_step[k] == 0)
-    goto label_a;
-  if (ancilla_step[k] == 1)
-    goto label_b;
-  if (ancilla_step[k] == 2) {
-    if (--breaktowerseal_var5 == 0) {
-      trigger_special_entrance = 5;
-      subsubmodule_index = 0;
-      BYTE(R16) = 0;
-      ancilla_step[k]++;
-    }
-  } else {
-    ancilla_x_vel[k] = 48;
-    uint8 bak0 = ancilla_x_lo[k];
-    uint8 bak1 = ancilla_x_hi[k];
-    ancilla_x_lo[k] = breaktowerseal_var4;
-    ancilla_x_hi[k] = 0;
-    Ancilla_MoveX(k);
-    breaktowerseal_var4 = ancilla_x_lo[k];
-    ancilla_x_lo[k] = bak0;
-    ancilla_x_hi[k] = bak1;
-    if (breaktowerseal_var4 >= 240) {
-      palette_sp6r_indoors = 0;
-      overworld_palette_aux_or_main = 0x200;
-      Palette_Load_SpriteEnvironment_Dungeon();
-      flag_update_cgram_in_nmi++;
-      ancilla_type[k] = 0;
-      return;
-    }
-  }
-  uint8 astep;
-label_b:
-
-
-  astep = ancilla_step[k];
-  if (astep != 0)
-    oam = GTCutscene_SparkleALot(oam);
-
-  for (int j = 6; j >= 0; j--) {
-    if (submodule_index == 0 && astep != 1 && !(frame_counter & 1))
-      breaktowerseal_var3[j] = breaktowerseal_var3[j] + 1 & 63;
-    AncillaRadialProjection arp = Ancilla_GetRadialProjection(breaktowerseal_var3[j], breaktowerseal_var4);
-    int x = (arp.r6 ? -arp.r4 : arp.r4) + breaktowerseal_x - 8 - BG2HOFS_copy;
-    int y = (arp.r2 ? -arp.r0 : arp.r0) + breaktowerseal_y - 8 - BG2VOFS_copy;
-
-    breaktowerseal_base_sparkle_x_lo[j] = x;
-    breaktowerseal_base_sparkle_x_hi[j] = x >> 8;
-
-    breaktowerseal_base_sparkle_y_lo[j] = y;
-    breaktowerseal_base_sparkle_y_hi[j] = y >> 8;
-
-    AncillaDraw_GTCutsceneCrystal(oam, x, y);
-    oam++;
-  }
-  Point16U info;
-label_a:
-  Ancilla_PrepAdjustedOamCoord(k, &info);
-
-  breaktowerseal_base_sparkle_x_lo[7] = info.x;
-  breaktowerseal_base_sparkle_x_hi[7] = info.x >> 8;
-  breaktowerseal_base_sparkle_y_lo[7] = info.y;
-  breaktowerseal_base_sparkle_y_hi[7] = info.y >> 8;
-
-  AncillaDraw_GTCutsceneCrystal(oam, info.x, info.y);
-
-  if (!ancilla_step[k])
-    AncillaAdd_OccasionalSparkle(k);
-  else if (!submodule_index)
-    GTCutscene_ActivateSparkle();
-}
-
-void AncillaDraw_GTCutsceneCrystal(OamEnt *oam, int x, int y) {  // 88ceaa
-  Ancilla_SetOam_Safe(oam, x, y, 0x24, 0x3c, 2);
-}
-
-void GTCutscene_ActivateSparkle() {  // 88cec7
-  for (int k = 0x17; k >= 0; k--) {
-    if (breaktowerseal_sparkle_var1[k] == 0xff) {
-      breaktowerseal_sparkle_var1[k] = 0;
-      breaktowerseal_sparkle_var2[k] = 4;
-      int r = GetRandomNumber();
-      int x = breaktowerseal_base_sparkle_x_hi[k & 7] << 8 | breaktowerseal_base_sparkle_x_lo[k & 7];
-      int y = breaktowerseal_base_sparkle_y_hi[k & 7] << 8 | breaktowerseal_base_sparkle_y_lo[k & 7];
-      x += r >> 4;
-      y += r & 0xf;
-      breaktowerseal_sparkle_x_lo[k] = x;
-      breaktowerseal_sparkle_x_hi[k] = x >> 8;
-      breaktowerseal_sparkle_y_lo[k] = y;
-      breaktowerseal_sparkle_y_hi[k] = y >> 8;
-      return;
-    }
-  }
-}
-
-OamEnt *GTCutscene_SparkleALot(OamEnt *oam) {  // 88cf35
-  static const uint8 kSwordChargeSpark_Char[3] = {0xb7, 0x80, 0x83};
-  static const uint8 kSwordChargeSpark_Flags[3] = {4, 4, 0x84};
-  for (int k = 0x17; k >= 0; k--) {
-    if (breaktowerseal_sparkle_var1[k] == 0xff)
-      continue;
-
-    if (sign8(--breaktowerseal_sparkle_var2[k])) {
-      breaktowerseal_sparkle_var2[k] = 4;
-      if (++breaktowerseal_sparkle_var1[k] == 3) {
-        breaktowerseal_sparkle_var1[k] = 0xff;
-        continue;
-      }
-    }
-
-    int x = breaktowerseal_sparkle_x_hi[k] << 8 | breaktowerseal_sparkle_x_lo[k];
-    int y = breaktowerseal_sparkle_y_hi[k] << 8 | breaktowerseal_sparkle_y_lo[k];
-    int j = breaktowerseal_sparkle_var1[k];
-    Ancilla_SetOam(oam, x, y, kSwordChargeSpark_Char[j], kSwordChargeSpark_Flags[j] | 0x30, 0);
-    oam++;
-  }
-  return oam;
-}
-
-void Ancilla36_Flute(int k) {  // 88cfaa
-  static const uint8 kFlute_Vels[4] = {0x18, 0x10, 0xa, 0};
-
-  if (!submodule_index) {
-    if (ancilla_step[k] != 3) {
-      ancilla_z_vel[k] -= 2;
-      Ancilla_MoveX(k);
-      Ancilla_MoveZ(k);
-      if (sign8(ancilla_z[k]) || ancilla_z[k] >= 0xf0) {
-        ancilla_z_vel[k] = kFlute_Vels[++ancilla_step[k]];
-        ancilla_z[k] = 0;
-      }
-    } else {
-      CheckPlayerCollOut coll_out;
-      if (Ancilla_CheckLinkCollision(k, 2, &coll_out) && !related_to_hookshot && link_auxiliary_state == 0) {
-        ancilla_type[k] = 0;
-        item_receipt_method = 0;
-        Link_ReceiveItem(0x14, 0);
-        return;
-      }
-    }
-  }
-
-  Point16U pt;
-  Ancilla_PrepAdjustedOamCoord(k, &pt);
-  OamEnt *oam = GetOamCurPtr();
-  Ancilla_SetOam(oam, pt.x, pt.y - (int8)ancilla_z[k], 0x24, HIBYTE(oam_priority_value) | 4, 2);
-  if (oam->y == 0xf0)
-    ancilla_type[k] = 0;
-}
-
-void Ancilla37_WeathervaneExplosion(int k) {  // 88d03d
-  if (--weathervane_var2)
-    return;
-  weathervane_var2 = 1;
-  if (!weathervane_var1) {
-    weathervane_var1 = 1;
-    music_control = 0xf3;
-  }
-  if (--ancilla_G[k])
-    return;
-  ancilla_G[k] = 1;
-  if (!ancilla_arr3[k]) {
-    ancilla_arr3[k] += 1;
-    Ancilla_Sfx2_Near(0xc);
-  }
-  if (!ancilla_step[k] && sign8(--ancilla_aux_timer[k])) {
-    ancilla_step[k] = 1;
-    Overworld_AlterWeathervane();
-    AncillaAdd_CutsceneDuck(0x38, 0);
-  }
-  weathervane_var13 = k;
-  weathervane_var14 = 0;
-  for (int i = 11; i >= 0; i--) {
-    if (weathervane_arr12[i] == 0xff)
-      continue;
-    if (sign8(--weathervane_arr11[i])) {
-      weathervane_arr11[i] = 1;
-      weathervane_arr12[i] ^= 1;
-    }
-
-    ancilla_item_to_link[k] = weathervane_arr12[i];
-    ancilla_y_lo[k] = weathervane_arr6[i];
-    ancilla_y_hi[k] = weathervane_arr7[i];
-    ancilla_x_lo[k] = weathervane_arr8[i];
-    ancilla_x_hi[k] = weathervane_arr9[i];
-    ancilla_z[k] = weathervane_arr10[i];
-    ancilla_y_vel[k] = weathervane_arr3[i];
-    ancilla_x_vel[k] = weathervane_arr4[i];
-    weathervane_arr5[i] = ancilla_z_vel[k] = weathervane_arr5[i] - 1;
-
-    Ancilla_MoveY(k);
-    Ancilla_MoveX(k);
-    Ancilla_MoveZ(k);
-
-    uint8 c = (ancilla_z[k] < 0xf0) ? 0 : 0xff;
-    AncillaDraw_WeathervaneExplosionWoodDebris(k);
-    if (sign8(c))
-      weathervane_arr12[i] = c;
-    weathervane_arr6[i] = ancilla_y_lo[k];
-    weathervane_arr7[i] = ancilla_y_hi[k];
-    weathervane_arr8[i] = ancilla_x_lo[k];
-    weathervane_arr9[i] = ancilla_x_hi[k];
-    weathervane_arr10[i] = ancilla_z[k];
-  }
-  for (int i = 11; i >= 0; i--) {
-    if (weathervane_arr12[i] != 0xff)
-      return;
-  }
-  ancilla_type[k] = 0;
-}
-
-void AncillaDraw_WeathervaneExplosionWoodDebris(int k) {  // 88d188
-  static const uint8 kWeathervane_Explode_Char[2] = {0x4e, 0x4f};
-  Point16U pt;
-  Ancilla_PrepOamCoord(k, &pt);
-  pt.y -= (int8)ancilla_z[k];
-  int i = ancilla_item_to_link[k];
-  if (sign8(i))
-    return;
-  Ancilla_SetOam(GetOamCurPtr() + (weathervane_var14 >> 2), pt.x, pt.y, kWeathervane_Explode_Char[i], 0x3c, 0);
-  weathervane_var14 += 4;
-}
-
-void Ancilla38_CutsceneDuck(int k) {  // 88d1d8
-  static const uint8 kTravelBirdIntro_Tab0[2] = {0x40, 0};
-  static const uint8 kTravelBirdIntro_Tab1[2] = {28, 60};
-
-  if (!(frame_counter & 31))
-    Ancilla_Sfx3_Pan(k, 0x1e);
-
-  if (sign8(--ancilla_arr3[k])) {
-    ancilla_arr3[k] = 3;
-    ancilla_K[k] ^= 1;
-  }
-
-  if (!--ancilla_aux_timer[k]) {
-    ancilla_aux_timer[k] = 1;
-    if (!ancilla_L[k]) {
-      if (!sign8(--ancilla_item_to_link[k])) {
-        ancilla_z_vel[k] += ancilla_step[k] ? 1 : -1;
-        if (abs8(ancilla_z_vel[k]) >= 12)
-          ancilla_step[k] ^= 1;
-        goto after_stuff;
-      }
-      ancilla_item_to_link[k] = 0;
-      ancilla_step[k] = 0;
-      ancilla_x_vel[k] = kTravelBirdIntro_Tab1[0];
-      ancilla_z_vel[k] = -16;
-      ancilla_L[k]++;
-      ancilla_step[k] = 3;
-    }
-    ancilla_x_vel[k] += (ancilla_step[k] & 1) == 0 ? 1 : -1;
-    uint8 absx = abs8(ancilla_x_vel[k]);
-    if (absx == 0 && ++ancilla_L[k] == 7)
-      ancilla_S[k] = 1;
-    if (absx >= kTravelBirdIntro_Tab1[ancilla_S[k]]) {
-      ancilla_step[k] ^= 3;
-    }
-    ancilla_dir[k] = sign8(ancilla_x_vel[k]) ? 2 : 3;
-    uint8 t = (uint8)(kTravelBirdIntro_Tab1[ancilla_S[k]] - absx) >> 1;
-    ancilla_z_vel[k] = (ancilla_step[k] & 2) ? -t : t;
-  }
-after_stuff:
-  Ancilla_MoveX(k);
-  Ancilla_MoveZ(k);
-  BYTE(flag_travel_bird) = kTravelBird_DmaStuffs[ancilla_K[k] + 1];
-  Point16U info;
-  Ancilla_PrepOamCoord(k, &info);
-  OamEnt *oam = GetOamCurPtr();
-  Ancilla_SetOam(oam, info.x + kTravelBird_Draw_X[0], info.y + (int8)ancilla_z[k] + kTravelBird_Draw_Y[0],
-                 kTravelBird_Draw_Char[0],
-                 kTravelBird_Draw_Flags[0] | 0x30 | kTravelBirdIntro_Tab0[ancilla_dir[k] & 1], 2);
-  oam++;
-  AncillaDraw_Shadow(oam, 1, info.x, info.y + 48, 0x30);
-  if (!sign16(info.x) && info.x >= 248) {
-    ancilla_type[k] = 0;
-    submodule_index = 0;
-    link_item_flute = 3;
-  }
-}
-
-void Ancilla23_LinkPoof(int k) {  // 88d3bc
-  if (sign8(--ancilla_aux_timer[k])) {
-    ancilla_aux_timer[k] = 7;
-    if (++ancilla_item_to_link[k] == 3) {
-      ancilla_type[k] = 0;
-      link_is_transforming = 0;
-      link_cant_change_direction = 0;
-      if (!ancilla_step[k]) {
-        link_animation_steps = 0;
-        link_visibility_status = 0;
-        link_is_bunny = link_is_bunny_mirror = BYTE(overworld_screen_index) & 0x40 ? 1 : 0;
-        if (link_is_bunny)
-          LoadGearPalettes_bunny();
-        else
-          LoadActualGearPalettes();
-      }
-      return;
-    }
-  }
-  MorphPoof_Draw(k);
-}
-
-void MorphPoof_Draw(int k) {  // 88d3fd
-  static const int8 kMorphPoof_X[12] = {0, 0, 0, 0, 0, 8, 0, 8, -4, 12, -4, 12};
-  static const int8 kMorphPoof_Y[12] = {0, 0, 0, 0, 0, 0, 8, 8, -4, -4, 12, 12};
-  static const uint8 kMorphPoof_Flags[12] = {0, 0xff, 0xff, 0xff, 0x40, 0, 0xc0, 0x80, 0, 0x40, 0x80, 0xc0};
-  static const uint8 kMorphPoof_Char[3] = {0x86, 0xa9, 0x9b};
-  static const uint8 kMorphPoof_Ext[3] = {2, 0, 0};
-  if (sort_sprites_setting && ancilla_floor[k] && (!flag_for_boomerang_in_place || !(frame_counter & 1))) {
-    oam_cur_ptr = 0x8d0;
-    oam_ext_cur_ptr = 0xa20 + (0xd0 >> 2);
-  }
-  Point16U info;
-  Ancilla_PrepOamCoord(k, &info);
-  OamEnt *oam = GetOamCurPtr();
-  int j = ancilla_item_to_link[k];
-  uint8 ext = kMorphPoof_Ext[j];
-  uint8 chr = kMorphPoof_Char[j];
-  for (int i = 0; i < 4; i++, oam++) {
-    Ancilla_SetOam(oam, info.x + kMorphPoof_X[j * 4 + i], info.y + kMorphPoof_Y[j * 4 + i], chr,
-                   kMorphPoof_Flags[j * 4 + i] | 4 | HIBYTE(oam_priority_value), ext);
-    if (ext == 2)
-      break;
-  }
-}
-
-void Ancilla40_DwarfPoof(int k) {  // 88d49a
-  if (sign8(--ancilla_aux_timer[k])) {
-    ancilla_aux_timer[k] = 7;
-    if (++ancilla_item_to_link[k] == 3) {
-      ancilla_type[k] = 0;
-      tagalong_var5 = 0;
-      return;
-    }
-  }
-  MorphPoof_Draw(k);
-}
-
-void Ancilla3F_BushPoof(int k) {  // 88d519
-  static const int8 kBushPoof_Draw_X[16] = {0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, -2, 10, -2, 10};
-  static const int8 kBushPoof_Draw_Y[16] = {0, 0, 8, 8, 0, 0, 8, 8, 0, 0, 8, 8, -2, -2, 10, 10};
-  static const uint8 kBushPoof_Draw_Char[16] = {0x86, 0x87, 0x96, 0x97, 0xa9, 0xa9, 0xa9, 0xa9, 0x8a, 0x8b, 0x9a, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b};
-  static const uint8 kBushPoof_Draw_Flags[16] = {0, 0, 0, 0, 0, 0x40, 0x80, 0xc0, 0, 0, 0, 0, 0xc0, 0x80, 0x40, 0};
-
-  if (ancilla_timer[k] == 0) {
-    ancilla_timer[k] = 7;
-    if (++ancilla_item_to_link[k] == 4) {
-      ancilla_type[k] = 0;
-      return;
-    }
-  }
-  Oam_AllocateFromRegionC(0x10);
-  Point16U pt;
-  Ancilla_PrepOamCoord(k, &pt);
-  OamEnt *oam = GetOamCurPtr();
-
-  int j = ancilla_item_to_link[k] * 4;
-  for (int i = 0; i < 4; i++, j++, oam++) {
-    Ancilla_SetOam(oam, pt.x + kBushPoof_Draw_X[j], pt.y + kBushPoof_Draw_Y[j],
-                   kBushPoof_Draw_Char[j], kBushPoof_Draw_Flags[j] | 4 | HIBYTE(oam_priority_value), 0);
-  }
-}
-
-void Ancilla26_SwordSwingSparkle(int k) {  // 88d65a
-  static const int8 kSwordSwingSparkle_X[48] = {
-    5,  10, -1,  5, 10, -4,  5, 10,  -4,  -4, -1,  -1,   0,   5,  -1,   0,
-    5,  14,  0,  5, 14, 14, -1, -1, -23, -27, -1, -23, -27, -22, -23, -27,
-    -22, -22, -1, -1, 32, 35, -1, 32,  35,  30, 32,  35,  30,  30,  -1,  -1,
-  };
-  static const int8 kSwordSwingSparkle_Y[48] = {
-    -22, -18, -1, -22, -18, -17, -22, -18, -17, -17, -1, -1, 35, 40, -1, 35,
-    40,  37, 35,  40,  37,  37,  -1,  -1,   2,   7, -1,  2,  7, 19,  2,  7,
-    19,  19, -1,  -1,   2,   7,  -1,   2,   7,  19,  2,  7, 19, 19, -1, -1,
-  };
-  static const uint8 kSwordSwingSparkle_Char[48] = {
-    0xb7, 0xb7, 0xff, 0x80, 0x80, 0xb7, 0x83, 0x83, 0x80, 0x83, 0xff, 0xff, 0xb7, 0xb7, 0xff, 0x80,
-    0x80, 0xb7, 0x83, 0x83, 0x80, 0x83, 0xff, 0xff, 0xb7, 0xb7, 0xff, 0x80, 0x80, 0xb7, 0x83, 0x83,
-    0x80, 0x83, 0xff, 0xff, 0xb7, 0xb7, 0xff, 0x80, 0x80, 0xb7, 0x83, 0x83, 0x80, 0x83, 0xff, 0xff,
-  };
-  static const uint8 kSwordSwingSparkle_Flags[48] = {
-    0,    0, 0xff,    0, 0,    0, 0x80, 0x80, 0, 0x80, 0xff, 0xff, 0,    0, 0xff,    0,
-    0,    0, 0x80, 0x80, 0, 0x80, 0xff, 0xff, 0,    0, 0xff,    0, 0,    0, 0x80, 0x80,
-    0, 0x80, 0xff, 0xff, 0,    0, 0xff,    0, 0,    0, 0x80, 0x80, 0, 0x80, 0xff, 0xff,
-  };
-  if (sign8(--ancilla_aux_timer[k])) {
-    ancilla_aux_timer[k] = 0;
-    if (++ancilla_item_to_link[k] == 4) {
-      ancilla_type[k] = 0;
-      return;
-    }
-  }
-  Ancilla_SetXY(k, link_x_coord, link_y_coord);
-
-  Point16U info;
-  Ancilla_PrepOamCoord(k, &info);
-
-  k = ancilla_item_to_link[k] * 3 + ancilla_dir[k] * 12;
-
-  OamEnt *oam = GetOamCurPtr();
-  for (int n = 2; n >= 0; n--, k++, oam++) {
-    uint8 chr = kSwordSwingSparkle_Char[k];
-    if (chr == 0xff)
-      continue;
-    Ancilla_SetOam(oam, info.x + kSwordSwingSparkle_X[k], info.y + kSwordSwingSparkle_Y[k],
-                   chr, kSwordSwingSparkle_Flags[k] | 0x4 | (oam_priority_value >> 8), 0);
-  }
-}
-
-void Ancilla2A_SpinAttackSparkleA(int k) {  // 88d7b2
-  static const uint8 kInitialSpinSpark_Timer[6] = {4, 2, 3, 3, 2, 1};
-  if (!submodule_index && sign8(--ancilla_aux_timer[k])) {
-    ancilla_aux_timer[k] = 0;
-    if (!ancilla_timer[k]) {
-      int j = ++ancilla_item_to_link[k];
-      ancilla_timer[k] = kInitialSpinSpark_Timer[j];
-      if (j == 5) {
-        if (ancilla_step[k])
-          AddSwordBeam(j);
-        else
-          SpinAttackSparkleA_TransmuteToNextSpark(k);
-        return;
-      }
-    }
-  }
-  if (!ancilla_item_to_link[k])
-    return;
-  SpinSpark_Draw(k, -1);
-}
-
-void SpinAttackSparkleA_TransmuteToNextSpark(int k) {  // 88d86d
-  static const uint8 kTransmuteSpinSpark_Arr[16] = {0x21, 0x20, 0x1f, 0x1e, 3, 2, 1, 0, 0x12, 0x11, 0x10, 0xf, 0x31, 0x30, 0x2f, 0x2e};
-  static const int8 kTransmuteSpinSpark_X[4] = {-3, 21, 25, -8};
-  static const int8 kTransmuteSpinSpark_Y[4] = {28, -2, 24, 6};
-
-  ancilla_type[k] = 0x2b;
-  int j = link_direction_facing * 2;
-  swordbeam_arr[0] = kTransmuteSpinSpark_Arr[j + 0];
-  swordbeam_arr[1] = kTransmuteSpinSpark_Arr[j + 1];
-  swordbeam_arr[2] = kTransmuteSpinSpark_Arr[j + 2];
-  swordbeam_arr[3] = swordbeam_var1 = kTransmuteSpinSpark_Arr[j + 3];
-  ancilla_aux_timer[k] = 2;
-  ancilla_item_to_link[k] = 0x4c;
-  ancilla_arr3[k] = 8;
-  ancilla_step[k] = 0;
-  ancilla_L[k] = 0;
-  ancilla_arr1[k] = 255;
-  swordbeam_var2 = 20;
-
-  swordbeam_temp_x = link_x_coord + 8;
-  swordbeam_temp_y = link_y_coord + 12;
-
-  j = link_direction_facing>>1;
-  Ancilla_SetXY(k,
-      link_x_coord + kTransmuteSpinSpark_X[j],
-      link_y_coord + kTransmuteSpinSpark_Y[j]);
-  Ancilla2B_SpinAttackSparkleB(k);
-}
-
-void Ancilla2B_SpinAttackSparkleB(int k) {  // 88d8fd
-  static const uint8 kSpinSpark_Char[4] = {0xd7, 0xb7, 0x80, 0x83};
-
-  if (ancilla_L[k]) {
-    SpinAttackSparkleB_Closer(k);
-    return;
-  }
-  uint8 flags = 2;
-  if (!submodule_index) {
-    uint8 t = (ancilla_item_to_link[k] -= 3);
-    if (t < 13) {
-      ancilla_aux_timer[k] = 1;
-      ancilla_L[k] = 1;
-      ancilla_item_to_link[k] = 0;
-      SpinAttackSparkleB_Closer(k);
-      return;
-    }
-    ancilla_step[k] = (t < 0x42) ? 3 : (t == 0x46) ? 1 : (t == 0x43) ? 2 : 0;
-    if (sign8(--ancilla_aux_timer[k])) {
-      flags = 4;
-      ancilla_aux_timer[k] = 2;
-    }
-  }
-  OamEnt *oam = GetOamCurPtr(), *oam_org = oam;
-  int i = ancilla_step[k];
-  do {
-    if (submodule_index == 0)
-      swordbeam_arr[i] = (swordbeam_arr[i] + 4) & 0x3f;
-    Point16U pt = Sparkle_PrepOamFromRadial(Ancilla_GetRadialProjection(swordbeam_arr[i], swordbeam_var2));
-    Ancilla_SetOam(oam, pt.x, pt.y, kSpinSpark_Char[i], flags | HIBYTE(oam_priority_value), 0);
-  } while (oam++, --i >= 0);
-
-  if (submodule_index == 0) {
-    if (!sign8(--ancilla_arr3[k]))
-      goto endif_2;
-
-    ancilla_arr3[k] = 0;
-    ancilla_arr1[k] = (ancilla_arr1[k] + 1) & 3;
-    if (ancilla_arr1[k] == 3)
-      swordbeam_var1 = (swordbeam_var1 + 9) & 0x3f;
-  }
-
-  uint8 t;
-
-  t = ancilla_arr1[k];
-  if (t != 3) {
-    static const uint8 kSpinSpark_Char2[3] = {0xb7, 0x80, 0x83};
-    Point16U pt = Sparkle_PrepOamFromRadial(Ancilla_GetRadialProjection(swordbeam_var1, swordbeam_var2));
-    Ancilla_SetOam(oam, pt.x, pt.y, kSpinSpark_Char2[t], 4 | HIBYTE(oam_priority_value), 0);
-  }
-endif_2:
-  if (ancilla_item_to_link[k] == 7)
-    bytewise_extended_oam[oam_org - oam_buf + 3] = 1;
-}
-
-Point16U Sparkle_PrepOamFromRadial(AncillaRadialProjection p) {  // 88da17
-  Point16U pt;
-  pt.y = (p.r2 ? -p.r0 : p.r0) + swordbeam_temp_y - 4 - BG2VOFS_copy2;
-  pt.x = (p.r6 ? -p.r4 : p.r4) + swordbeam_temp_x - 4 - BG2HOFS_copy2;
-  return pt;
-}
-
-void SpinAttackSparkleB_Closer(int k) {  // 88da4c
-  if (sign8(--ancilla_aux_timer[k])) {
-    ancilla_aux_timer[k] = 1;
-    if (++ancilla_item_to_link[k] == 3)
-      ancilla_type[k] = 0;
-  }
-  SpinSpark_Draw(k, 4);
-}
-
-void Ancilla30_ByrnaWindupSpark(int k) {  // 88db24
-  static const int8 kInitialCaneSpark_X[16] = {3, 1, 0, 0, 13, 16, 12, 12, 24, 7, -4, -10, -8, 9, 22, 26};
-  static const int8 kInitialCaneSpark_Y[16] = {5, 0, -3, -6, -8, -3, 12, 28, 5, 0, 8, 16, 5, 0, 8, 16};
-  static const int8 kInitialCaneSpark_Draw_X[16] = {-4, 0, 0, 0, -8, 0, -8, 0, -8, 0, -8, 0, -8, 0, -8, 0};
-  static const int8 kInitialCaneSpark_Draw_Y[16] = {-4, 0, 0, 0, -8, -8, 0, 0, -8, -8, 0, 0, -8, -8, 0, 0};
-  static const uint8 kInitialCaneSpark_Draw_Char[16] = {0x92, 0xff, 0xff, 0xff, 0x8c, 0x8c, 0x8c, 0x8c, 0xd6, 0xd6, 0xd6, 0xd6, 0x93, 0x93, 0x93, 0x93};
-  static const uint8 kInitialCaneSpark_Draw_Flags[16] = {0x22, 0xff, 0xff, 0xff, 0x22, 0x62, 0xa2, 0xe2, 0x24, 0x64, 0xa4, 0xe4, 0x22, 0x62, 0xa2, 0xe2};
-
-  if (!submodule_index && sign8(--ancilla_aux_timer[k])) {
-    ancilla_aux_timer[k] = 1;
-    if (++ancilla_item_to_link[k] == 17) {
-      ByrnaWindupSpark_TransmuteToNormal(k);
-      return;
-    }
-  }
-  if (!ancilla_item_to_link[k])
-    return;
-
-  int j = player_handler_timer;
-  if (j == 2) {
-    uint8 a = ancilla_arr3[k] - 1;
-    if (sign8(a))
-      a = 0, j = 3;
-    ancilla_arr3[k] = a;
-  }
-  j += link_direction_facing * 2;
-  Ancilla_SetXY(k, link_x_coord + kInitialCaneSpark_X[j], link_y_coord + kInitialCaneSpark_Y[j]);
-  Point16U pt;
-  Ancilla_PrepOamCoord(k, &pt);
-
-  uint8 a = (ancilla_item_to_link[k] - 1) & 0xf;
-  j = 0;
-  if (a != 0)
-    j = 4 * ((a != 15) ? (a & 1) + 1 : 3);
-
-  OamEnt *oam = GetOamCurPtr();
-  for (int i = 0; i < 4; i++, j++) {
-    if (kInitialCaneSpark_Draw_Char[j] != 255) {
-      Ancilla_SetOam(oam, pt.x + kInitialCaneSpark_Draw_X[j], pt.y + kInitialCaneSpark_Draw_Y[j],
-                     kInitialCaneSpark_Draw_Char[j],
-                     kInitialCaneSpark_Draw_Flags[j] & ~0x30 | HIBYTE(oam_priority_value), 0);
-      oam++;
-    }
-  }
-}
-
-void ByrnaWindupSpark_TransmuteToNormal(int k) {  // 88dc21
-  static const uint8 kCaneSpark_Transmute_Tab[16] = {0x34, 0x33, 0x32, 0x31, 0x16, 0x15, 0x14, 0x13, 0x2a, 0x29, 0x28, 0x27, 0x10, 0xf, 0xe, 0xd};
-
-  ancilla_type[k] = 0x31;
-  int j = link_direction_facing << 1;
-  swordbeam_arr[0] = kCaneSpark_Transmute_Tab[j + 0];
-  swordbeam_arr[1] = kCaneSpark_Transmute_Tab[j + 1];
-  swordbeam_arr[2] = kCaneSpark_Transmute_Tab[j + 2];
-  swordbeam_arr[3] = kCaneSpark_Transmute_Tab[j + 3];
-  ancilla_aux_timer[k] = 0x17;
-  ancilla_G[k] = 0;
-  ancilla_item_to_link[k] = 0;
-  ancilla_arr3[k] = 8;
-  ancilla_step[k] = 0;
-  ancilla_L[k] = 0;
-  ancilla_arr1[k] = 2;
-  ancilla_timer[k] = 21;
-  swordbeam_var2 = 20;
-  Ancilla_Sfx3_Near(0x30);
-  Ancilla31_ByrnaSpark(k);
-}
-
-void Ancilla31_ByrnaSpark(int k) {  // 88dc70
-  static const uint8 kCaneSpark_Magic[3] = {4, 2, 1};
-
-  uint8 flags = 2;
-  if (submodule_index == 0) {
-    if (current_item_y != 13) {
-kill_me:
-      link_disable_sprite_damage = 0;
-      ancilla_type[k] = 0;
-      link_give_damage = 0;
-      return;
-    }
-    link_disable_sprite_damage = 1;
-    if (!--ancilla_aux_timer[k]) {
-      ancilla_aux_timer[k] = 1;
-      uint8 r0 = kCaneSpark_Magic[link_magic_consumption];
-      if (!link_magic_power || (uint8)(r0 = link_magic_power - r0) >= 0x80)
-        goto kill_me;
-
-      if (sign8(--ancilla_G[k])) {
-        ancilla_G[k] = 0x17;
-        link_magic_power = r0;
-      }
-      if (filtered_joypad_H & 0x40)
-        goto kill_me;
-    }
-    if (ancilla_step[k] != 3) {
-      uint8 a = ++ancilla_item_to_link[k];
-      ancilla_step[k] = (a >= 4) ? 3 : (a == 2) ? 1 : (a == 3) ? 2 : 0;
-    }
-    if (sign8(--ancilla_arr1[k])) {
-      ancilla_arr1[k] = 2;
-      flags = 4;
-    }
-  }
-
-  int z = (int8)link_z_coord;
-  if (z == -1)
-    z = 0;
-  swordbeam_temp_y = link_y_coord + 12 - z;
-  swordbeam_temp_x = link_x_coord + 8;
-  if (!ancilla_timer[k]) {
-    ancilla_timer[k] = 21;
-    Ancilla_Sfx3_Near(0x30);
-  }
-  OamEnt *oam = GetOamCurPtr();
-  int i = ancilla_step[k];
-  do {
-    static const uint8 kCaneSpark_Char[4] = {0xd7, 0xb7, 0x80, 0x83};
-    if (!submodule_index)
-      swordbeam_arr[i] = (swordbeam_arr[i] + 3) & 0x3f;
-    Point16U pt = Sparkle_PrepOamFromRadial(Ancilla_GetRadialProjection(swordbeam_arr[i], swordbeam_var2));
-    Ancilla_SetOam(oam, pt.x, pt.y, kCaneSpark_Char[i], flags | HIBYTE(oam_priority_value), 0);
-    Ancilla_SetXY(k, pt.x + BG2HOFS_copy2, pt.y + BG2VOFS_copy2);
-    ancilla_dir[k] = 0;
-    Ancilla_CheckSpriteCollision(k);
-  } while (oam++, --i >= 0);
-}
-
-void Ancilla_SwordBeam(int k) {  // 88ddc5
-  uint8 flags = 2;
-
-  if (!submodule_index) {
-    Ancilla_SetXY(k, swordbeam_temp_x, swordbeam_temp_y);
-    Ancilla_MoveX(k);
-    Ancilla_MoveY(k);
-    swordbeam_temp_x = Ancilla_GetX(k);
-    swordbeam_temp_y = Ancilla_GetY(k);
-
-    if ((ancilla_G[k]++ & 0xf) == 0) {
-      sound_effect_2 = Ancilla_CalculateSfxPan(k) | 1;
-    }
-
-    if (Ancilla_CheckSpriteCollision(k) >= 0 || Ancilla_CheckTileCollision(k)) {
-      static const int8 kSwordBeam_Yvel2[4] = {0, 0, -6, -6};
-      static const int8 kSwordBeam_Xvel2[4] = {-8, -10, 0, 0};
-      int j = ancilla_dir[k];
-      Ancilla_SetXY(k,
-          Ancilla_GetX(k) + kSwordBeam_Xvel2[j],
-          Ancilla_GetY(k) + kSwordBeam_Yvel2[j]);
-      ancilla_type[k] = 4;
-      ancilla_timer[k] = 7;
-      ancilla_numspr[k] = 0x10;
-      return;
-    }
-    if (sign8(--ancilla_aux_timer[k])) {
-      flags = 4;
-      ancilla_aux_timer[k] = 2;
-    }
-  }
-
-  OamEnt *oam = GetOamCurPtr();
-  uint8 s = ancilla_S[k];
-  for (int i = 3; i >= 0; i--, oam++) {
-    static const uint8 kSwordBeam_Char[4] = {0xd7, 0xb7, 0x80, 0x83};
-    if (submodule_index == 0)
-      swordbeam_arr[i] = (swordbeam_arr[i] + s) & 0x3f;
-    Point16U pt = Sparkle_PrepOamFromRadial(Ancilla_GetRadialProjection(swordbeam_arr[i], swordbeam_var2));
-    Ancilla_SetOam(oam, pt.x, pt.y, kSwordBeam_Char[i], flags | HIBYTE(oam_priority_value), 0);
-  }
-
-  if (submodule_index == 0) {
-    if (!sign8(--ancilla_arr3[k]))
-      goto endif_2;
-
-    ancilla_arr3[k] = 0;
-    ancilla_arr1[k] = (ancilla_arr1[k] + 1) & 3;
-    if (ancilla_arr1[k] == 3)
-      swordbeam_var1 = (swordbeam_var1 + s) & 0x3f;
-  }
-
-  uint8 t;
-
-  t = ancilla_arr1[k];
-  if (t != 3) {
-    static const uint8 kSwordBeam_Char2[3] = {0xb7, 0x80, 0x83};
-    Point16U pt = Sparkle_PrepOamFromRadial(Ancilla_GetRadialProjection(swordbeam_var1, swordbeam_var2));
-    Ancilla_SetOam(oam, pt.x, pt.y, kSwordBeam_Char2[t], 4 | HIBYTE(oam_priority_value), 0);
-  }
-endif_2:
-  oam -= 4;
-  for (int i = 0; i < 4; i++) {
-    if (oam[i].y != 0xf0)
-      return;
-  }
-  ancilla_type[k] = 0;
-}
-
-void Ancilla0D_SpinAttackFullChargeSpark(int k) {  // 88ddca
-  static const int8 kSwordFullChargeSpark_Y[4] = {-8, 27, 12, 12};
-  static const int8 kSwordFullChargeSpark_X[4] = {4, 4, -13, 20};
-  static const uint8 kSwordFullChargeSpark_Flags[4] = {0x20, 0x10, 0x30, 0x20};
-
-  ancilla_oam_idx[k] = Ancilla_AllocateOamFromRegion_A_or_D_or_F(k, 4);
-
-  if (!ancilla_timer[k]) {
-    ancilla_type[k] = 0;
-    return;
-  }
-
-  int j = link_direction_facing >> 1;
-
-  uint16 x = link_x_coord + kSwordFullChargeSpark_X[j] - BG2HOFS_copy2;
-  uint16 y = link_y_coord + kSwordFullChargeSpark_Y[j] - BG2VOFS_copy2;
-
-  oam_priority_value = kSwordFullChargeSpark_Flags[ancilla_floor[k]] << 8;
-  OamEnt *oam = GetOamCurPtr();
-  Ancilla_SetOam(oam, x, y, 0xd7, HIBYTE(oam_priority_value) | 2, 0);
-}
-
-void Ancilla27_Duck(int k) {  // 88dde8
-  CheckPlayerCollOut coll;
-  int j;
-
-  if (submodule_index)
-    goto endif_1;
-
-  if (ancilla_timer[k]) {
-    int xt = (enhanced_features0 & kFeatures0_ExtendScreen64) ? 0x40 : 0;
-    Ancilla_SetXY(k, BG2HOFS_copy2 - 16 - xt, link_y_coord - 8);
-    return;
-  }
-
-  if (sign8(--ancilla_G[k])) {
-    ancilla_G[k] = 0x28;
-    Ancilla_Sfx3_Pan(k, 0x1e);
-  }
-
-  if (ancilla_L[k] || ancilla_step[k] && (flag_unk1++, true)) {
-    ancilla_z_vel[k]--;
-    Ancilla_MoveZ(k);
-  }
-  Ancilla_MoveX(k);
-
-
-  if (ancilla_L[k]) {
-    uint16 x = Ancilla_GetX(k);
-    if (ancilla_step[k])
-      flag_unk1++;
-    if (!sign16(x) && x >= link_x_coord) {
-      if (ancilla_step[k]) {
-        ancilla_step[k] = 0;
-        link_visibility_status = 0;
-        tagalong_var5 = 0;
-        link_pose_for_item = 0;
-        ancilla_y_vel[k] = 0;
-        flag_is_link_immobilized = 0;
-        link_disable_sprite_damage = 0;
-        byte_7E03FD = 0;
-        countdown_for_blink = 144;
-        if (!((follower_indicator == 12 || follower_indicator == 13) && follower_dropped)) {
-          Follower_Initialize();
-        }
-      }
-    } else if ((uint16)(link_x_coord - x) < 48) {
-      j = 3;
-      goto endif_5;
-    }
-    goto endif_1;
-  }
-
-  if (!Ancilla_CheckLinkCollision(k, 1, &coll) || main_module_index == 15)
-    goto endif_1;
-
-  if (!player_is_indoors) {
-    if (link_player_handler_state == 8 || link_player_handler_state == 9 || link_player_handler_state == 10 ||
-        player_near_pit_state == 2 ||
-        (link_pose_for_item | related_to_hookshot | link_force_hold_sword_up | link_disable_sprite_damage) ||
-        (link_state_bits & 0x80))
-      goto endif_1;
-    for (int i = 4; i >= 0; i--) {
-      uint8 a = ancilla_type[i];
-      if (a == 0x2a || a == 0x1f || a == 0x30 || a == 0x31 || a == 0x41)
-        ancilla_type[i] = 0;
-    }
-    if (follower_indicator == 9) {
-      follower_indicator = 0;
-      tagalong_var5 = 0;
-    }
-  }
-  link_state_bits = 0;
-  link_picking_throw_state = 0;
-
-  bg1_x_offset = 0;
-  bg1_y_offset = 0;
-  Link_ResetProperties_A();
-  link_is_in_deep_water = 0;
-  link_need_for_pullforrupees_sprite = 0;
-  link_visibility_status = 12;
-  link_player_handler_state = 0;
-  link_pose_for_item = 1;
-  flag_is_link_immobilized = 1;
-  link_disable_sprite_damage = 1;
-  tagalong_var5 = 1;
-  ancilla_step[k] = 2;
-  flag_unk1++;
-  link_give_damage = 0;
-  if (player_is_indoors)
-    byte_7E03FD = player_is_indoors;
-endif_1:
-  if (sign8(--ancilla_arr3[k])) {
-    ancilla_arr3[k] = 3;
-    if (++ancilla_K[k] == 3)
-      ancilla_K[k] = 0;
-  }
-  j = ancilla_K[k];
-endif_5:
-  BYTE(flag_travel_bird) = kTravelBird_DmaStuffs[j];
-
-  Point16U info;
-  Ancilla_PrepOamCoord(k, &info);
-
-  OamEnt *oam = GetOamCurPtr();
-  int z = ancilla_z[k] ? ancilla_z[k] | ~0xff : 0;
-  int i = 0, n = ancilla_step[k] + 1;
-  do {
-    Ancilla_SetOam(oam, info.x + (int8)kTravelBird_Draw_X[i], info.y + z + (int8)kTravelBird_Draw_Y[i],
-                   kTravelBird_Draw_Char[i], kTravelBird_Draw_Flags[i] | 0x30, 2);
-    oam++;
-  } while (++i != n);
-
-  AncillaDraw_Shadow(oam, 1, info.x, info.y + 28, 0x30);
-  oam += 2;
-  if (ancilla_step[k])
-    AncillaDraw_Shadow(oam, 1, info.x - 7, info.y + 28, 0x30);
-
-  if (!sign16(info.x) && info.x >= 0x130) {
-    ancilla_type[k] = 0;
-    if (!ancilla_L[k] && ancilla_step[k]) {
-      submodule_index = 10;
-      saved_module_for_menu = main_module_index;
-      main_module_index = 14;
-    }
-  }
-}
-
-int AncillaAdd_SomariaBlock(uint8 type, uint8 y) {  // 88e078
-  int k = AncillaAdd_AddAncilla_Bank08(type, y);
-  if (k < 0)
-    return k;
-  for (int j = 4; j >= 0; j--) {
-    if (j == k || ancilla_type[j] != 0x2c)
-      continue;
-    if (j == flag_is_ancilla_to_pick_up - 1)
-      flag_is_ancilla_to_pick_up = 0;
-    AncillaAdd_ExplodingSomariaBlock(j);
-    ancilla_type[k] = 0;
-    dung_flag_somaria_block_switch = 0;
-    if (link_speed_setting == 0x12) {
-      bitmask_of_dragstate = 0;
-      link_speed_setting = 0;
-    }
-    return k;
-  }
-
-  Ancilla_Sfx3_Near(0x2a);
-  ancilla_step[k] = 0;
-  ancilla_y_vel[k] = 0;
-  ancilla_x_vel[k] = 0;
-  ancilla_item_to_link[k] = 0;
-  ancilla_aux_timer[k] = 0;
-  ancilla_arr3[k] = 0;
-  ancilla_arr1[k] = 0;
-  ancilla_H[k] = 0;
-  ancilla_G[k] = 12;
-  ancilla_timer[k] = 18;
-  ancilla_L[k] = 0;
-  ancilla_z[k] = 0;
-  ancilla_K[k] = 0;
-  ancilla_R[k] = 0;
-  ancilla_arr4[k] = 0;
-  ancilla_S[k] = 9;
-  ancilla_T[k] = 0;
-  ancilla_dir[k] = link_direction_facing >> 1;
-  if (Ancilla_CheckInitialTileCollision_Class2(k)) {
-    Ancilla_SetX(k, link_x_coord + 8);
-    Ancilla_SetY(k, link_y_coord + 16);
-  } else {
-    static const int8 kCaneOfSomaria_Y[4] = { -8, 31, 17, 17 };
-    static const int8 kCaneOfSomaria_X[4] = { 8, 8, -8, 23 };
-    int j = link_direction_facing >> 1;
-    Ancilla_SetX(k, link_x_coord + kCaneOfSomaria_X[j]);
-    Ancilla_SetY(k, link_y_coord + kCaneOfSomaria_Y[j]);
-    SomariaBlock_CheckForTransitTile(k);
-  }
-  return k;
-}
-
-void SomariaBlock_CheckForTransitTile(int k) {  // 88e191
-  static const int8 kSomariaTransitLine_X[12] = { -8, 0, 8, -8, 0, 8, -16, -16, -16, 16, 16, 16 };
-  static const int8 kSomariaTransitLine_Y[12] = { -16, -16, -16, 16, 16, 16, -8, 0, 8, -8, 0, 8 };
-  if (!dung_unk6)
-    return;
-  for (int j = 11; j >= 0; j--) {
-    uint16 x = Ancilla_GetX(k) + kSomariaTransitLine_X[j];
-    uint16 y = Ancilla_GetY(k) + kSomariaTransitLine_Y[j];
-    uint8 bak = ancilla_objprio[k];
-    Ancilla_CheckTileCollision_targeted(k, x, y);
-    ancilla_objprio[k] = bak;
-    if (ancilla_tile_attr[k] == 0xb6 || ancilla_tile_attr[k] == 0xbc) {
-      Ancilla_SetX(k, x);
-      Ancilla_SetY(k, y);
-      AncillaAdd_SomariaPlatformPoof(k);
-      return;
-    }
-  }
-}
-
-int Ancilla_CheckBasicSpriteCollision(int k) {  // 88e1f9
-  for (int j = 15; j >= 0; j--) {
-    if (((j ^ frame_counter) & 3 | sprite_pause[j] | sprite_hit_timer[j]) != 0)
-      continue;
-    if (sprite_state[j] < 9 || !(sprite_defl_bits[j] & 2) && ancilla_objprio[k])
-      continue;
-    if (ancilla_floor[k] != sprite_floor[j])
-      continue;
-    if (ancilla_type[k] == 0x2c && (sprite_type[j] == 0x1e || sprite_type[j] == 0x90))
-      continue;
-    if (Ancilla_CheckBasicSpriteCollision_Single(k, j))
-      return j;
-  }
-  return -1;
-}
-
-bool Ancilla_CheckBasicSpriteCollision_Single(int k, int j) {  // 88e23d
-  SpriteHitBox hb;
-  Ancilla_SetupBasicHitBox(k, &hb);
-  Sprite_SetupHitBox(j, &hb);
-  if (!CheckIfHitBoxesOverlap(&hb))
-    return false;
-  if (sprite_type[j] == 0x92 && sprite_C[j] < 3)
-    return true;
-  if (sprite_type[j] == 0x80 && sprite_delay_aux4[j] == 0) {
-    sprite_delay_aux4[j] = 24;
-    sprite_D[j] ^= 1;
-  }
-  if (sprite_ignore_projectile[j])
-    return false;
-
-  int x = Ancilla_GetX(k) - 8, y = Ancilla_GetY(k) - 8 - ancilla_z[k];
-  ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLocation(j, x, y, 80);
-  sprite_y_recoil[j] = ~pt.y;
-  sprite_x_recoil[j] = ~pt.x;
-  Ancilla_CheckDamageToSprite(j, ancilla_type[k]);
-  return true;
-}
-
-void Ancilla_SetupBasicHitBox(int k, SpriteHitBox *hb) {  // 88e2ca
-  int x = Ancilla_GetX(k) - 8;
-  hb->r0_xlo = x;
-  hb->r8_xhi = x >> 8;
-  int y = Ancilla_GetY(k) - 8 - ancilla_z[k];
-  hb->r1_ylo = y;
-  hb->r9_yhi = y >> 8;
-  hb->r2 = 15;
-  hb->r3 = 15;
-}
-
-void Ancilla2C_SomariaBlock(int k) {  // 88e365
-  if (!sign8(--ancilla_G[k]))
-    return;
-  ancilla_G[k] = 0;
-
-  if (ancilla_H[k])
-    goto label_1;
-  if (submodule_index == 0 || submodule_index == 8 || submodule_index == 16) {
-    Ancilla_HandleLiftLogic(k);
-  } else if (k + 1 == flag_is_ancilla_to_pick_up && ancilla_K[k] != 0) {
-    if (ancilla_K[k] != 3) {
-      Ancilla_LatchLinkCoordinates(k, 3);
-      Ancilla_LatchAltitudeAboveLink(k);
-      ancilla_K[k] = 3;
-    }
-    Ancilla_LatchCarriedPosition(k);
-  }
-  if (player_is_indoors) {
-    if (!ancilla_K[k] && !(link_state_bits & 0x80) && (ancilla_z[k] == 0 || ancilla_z[k] == 0xff)) {
-      if (dung_unk6) {
-        int j = frame_counter & 3;
-        do {
-          uint8 bak = ancilla_objprio[k];
-          uint16 x = Ancilla_GetX(k) + kSomarianBlock_Coll_X[j];
-          uint16 y = Ancilla_GetY(k) + kSomarianBlock_Coll_Y[j];
-          Ancilla_CheckTileCollision_targeted(k, x, y);
-          ancilla_objprio[k] = bak;
-          if (ancilla_tile_attr[k] == 0xb6 || ancilla_tile_attr[k] == 0xbc) {
-            Ancilla_SetXY(k, x, y);
-            AncillaAdd_SomariaPlatformPoof(k);
-            if (k + 1 == flag_is_ancilla_to_pick_up)
-              flag_is_ancilla_to_pick_up = 0;
-            return;
-          }
-        } while ((j += 4) < 12);
-      } else {
-        if (!SomariaBlock_CheckForSwitch(k) && (ancilla_z[k] == 0 || ancilla_z[k] == 0xff))
-          dung_flag_somaria_block_switch++;
-      }
-    } else {
-label_1:
-      if (flag_is_ancilla_to_pick_up == k + 1)
-        dung_flag_somaria_block_switch = 0;
-    }
-  }
-
-  uint16 old_y = Ancilla_LatchYCoordToZ(k);
-  uint8 s1a = ancilla_dir[k];
-  uint8 s1b = ancilla_objprio[k];
-  ancilla_objprio[k] = 0;
-  bool flag = Ancilla_CheckTileCollision_Class2(k);
-
-  if (player_is_indoors && ancilla_L[k] && ancilla_tile_attr[k] == 0x1c)
-    ancilla_T[k] = 1;
-
-label1:
-  if (flag && (!(link_state_bits & 0x80) || link_picking_throw_state)) {
-    if (!s1b && !ancilla_arr4[k] && ancilla_z[k]) {
-      ancilla_arr4[k] = 1;
-      int qq = (ancilla_dir[k] == 1) ? 16 : 4;
-      if (ancilla_y_vel[k])
-        ancilla_y_vel[k] = sign8(ancilla_y_vel[k]) ? qq : -qq;
-      if (ancilla_x_vel[k])
-        ancilla_x_vel[k] = sign8(ancilla_x_vel[k]) ? 4 : -4;
-      if (ancilla_dir[k] == 1 && ancilla_z[k]) {
-        ancilla_y_vel[k] = -4;
-        ancilla_L[k] = 2;
-      }
-    }
-  } else if (!(link_state_bits & 0x80) && (ancilla_z[k] == 0 || ancilla_z[k] == 0xff)) {
-    ancilla_dir[k] = 16;
-    uint8 bak0 = ancilla_objprio[k];
-    Ancilla_CheckTileCollision(k);
-    ancilla_objprio[k] = bak0;
-    uint8 a = ancilla_tile_attr[k];
-    if (a == 0x26) {
-      flag = true;
-      goto label1;
-    } else if (a == 0xc || a == 0x1c) {
-      if (dung_hdr_collision != 3) {
-        if (ancilla_floor[k] == 0 && ancilla_z[k] != 0 && ancilla_z[k] != 0xff)
-          ancilla_floor[k] = 1;
-      } else {
-        old_y = Ancilla_GetY(k) + dung_floor_y_vel;
-        Ancilla_SetX(k, Ancilla_GetX(k) + dung_floor_x_vel);
-      }
-    } else if (a == 0x20 || (a & 0xf0) == 0xb0 && a != 0xb6 && a != 0xbc) {
-      if (!(link_state_bits & 0x80)) {
-        if (k + 1 == flag_is_ancilla_to_pick_up)
-          flag_is_ancilla_to_pick_up = 0;
-        if (!ancilla_timer[k]) {
-          if (link_speed_setting == 18) {
-            link_speed_setting = 0;
-            bitmask_of_dragstate = 0;
-          }
-          ancilla_type[k] = 0;
-          return;
-        }
-      }
-    } else if (a == 8) {
-      if (k + 1 == flag_is_ancilla_to_pick_up)
-        flag_is_ancilla_to_pick_up = 0;
-      if (ancilla_timer[k] == 0) {
-        Ancilla_SetY(k, Ancilla_GetY(k) - 24);
-        Ancilla_TransmuteToSplash(k);
-        return;
-      }
-    } else if (a == 0x68 || a == 0x69 || a == 0x6a || a == 0x6b) {
-      Ancilla_ApplyConveyor(k);
-      old_y = Ancilla_GetY(k);
-    } else {
-      ancilla_timer[k] = (ancilla_L[k] | ancilla_H[k]) ? 0 : 2;
-    }
-  }
-  // endif_3
-  s1b |= ancilla_objprio[k];
-
-  if (!(link_state_bits & 0x80) && !--ancilla_S[k]) {
-    ancilla_S[k] = 1;
-    ancilla_objprio[k] = 0;
-    if (Ancilla_CheckBasicSpriteCollision(k) >= 0) {
-      ancilla_S[k] = 7;
-      if (++ancilla_step[k] == 5) {
-        SomariaBlock_FizzleAway(k);
-        return;
-      }
-    }
-  }
-  Ancilla_SetY(k, old_y);
-  ancilla_dir[k] = s1a;
-  ancilla_objprio[k] = s1b;
-
-  AncillaDraw_SomariaBlock(k);
-}
-
-void AncillaDraw_SomariaBlock(int k) {  // 88e61b
-  static const int8 kSomarianBlock_Draw_X[12] = {-8, 0, -8, 0, 0, 0, 0, 0, 0, 0, 0, 0};
-  static const int8 kSomarianBlock_Draw_Y[12] = {-8, -8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
-  static const uint8 kSomarianBlock_Draw_Flags[12] = {0, 0x40, 0x80, 0xc0, 0, 0x40, 0x80, 0xc0, 0, 0x40, 0x80, 0xc0};
-
-  if (k + 1 == flag_is_ancilla_to_pick_up && link_state_bits & 0x80 && ancilla_K[k] != 3 && link_direction_facing == 0) {
-    Ancilla_AllocateOamFromRegion_B_or_E(ancilla_numspr[k]);
-  } else if (sort_sprites_setting && ancilla_floor[k] && (ancilla_L[k] || k + 1 == flag_is_ancilla_to_pick_up && (link_state_bits & 0x80))) {
-    oam_cur_ptr = 0x8d0;
-    oam_ext_cur_ptr = 0xa20 + 0x34;
-  }
-
-  Point16U pt;
-  Ancilla_PrepAdjustedOamCoord(k, &pt);
-  OamEnt *oam = GetOamCurPtr(), *oam_org = oam;
-  int z = (int8)ancilla_z[k];
-  if (z != 0 && z != -1 && ancilla_K[k] != 3 && ancilla_objprio[k])
-    oam_priority_value = 0x3000;
-  pt.y -= z;
-  int j = ancilla_arr1[k] * 4;
-  int r8 = 0;
-  do {
-    Ancilla_SetOam_Safe(oam, pt.x + kSomarianBlock_Draw_X[j], pt.y + kSomarianBlock_Draw_Y[j], 0xe9,
-                        kSomarianBlock_Draw_Flags[j] & ~0x30 | 2 | HIBYTE(oam_priority_value), 0);
-    oam++;
-  } while (j++, ++r8 & 3);
-
-  if (SomarianBlock_CheckEmpty(oam_org)) {
-    dung_flag_somaria_block_switch = 0;
-    ancilla_type[k] = 0;
-    if (k + 1 == flag_is_ancilla_to_pick_up) {
-      flag_is_ancilla_to_pick_up = 0;
-      if (link_state_bits & 128)
-        link_state_bits = 0;
-    }
-  }
-}
-
-bool SomariaBlock_CheckForSwitch(int k) {  // 88e75c
-  static const int8 kSomarianBlock_CheckCover_X[4] = {0, 0, -4, 4};
-  static const int8 kSomarianBlock_CheckCover_Y[4] = {-4, 4, 0, 0};
-  dung_flag_somaria_block_switch = 0;
-  ancilla_arr24[k] = 0;
-  for (int j = 3; j >= 0; j--) {
-    uint16 y = Ancilla_GetY(k) + kSomarianBlock_CheckCover_Y[j];
-    uint16 x = Ancilla_GetX(k) + kSomarianBlock_CheckCover_X[j];
-    uint8 bak = ancilla_objprio[k];
-    Ancilla_CheckTileCollision_targeted(k, x, y);
-    ancilla_objprio[k] = bak;
-    uint8 a = ancilla_tile_attr[k];
-    if (a == 0x23 || a == 0x24 || a == 0x25 || a == 0x3b)
-      ancilla_arr24[k]++;
-  }
-  return ancilla_arr24[k] != 4;
-}
-
-void SomariaBlock_FizzleAway(int k) {  // 88e9b2
-  if (link_speed_setting == 18) {
-    bitmask_of_dragstate = 0;
-    link_speed_setting = 0;
-  }
-  dung_flag_somaria_block_switch = 0;
-  ancilla_type[k] = 0x2d;
-  ancilla_aux_timer[k] = 0;
-  ancilla_step[k] = 0;
-  ancilla_item_to_link[k] = 0;
-  ancilla_arr3[k] = 0;
-  ancilla_arr1[k] = 0;
-  ancilla_R[k] = 0;
-  if (k + 1 == flag_is_ancilla_to_pick_up) {
-    flag_is_ancilla_to_pick_up = 0;
-    link_state_bits &= 0x80;
-  }
-  Ancilla2D_SomariaBlockFizz(k);
-}
-
-void Ancilla2D_SomariaBlockFizz(int k) {  // 88e9e8
-  static const int8 kSomariaBlockFizzle_X[6] = {-4, -1, -8, 0, -6, -2};
-  static const int8 kSomariaBlockFizzle_Y[6] = {-4, -1, -4, -4, -4, -4};
-  static const uint8 kSomariaBlockFizzle_Char[6] = {0x92, 0xff, 0xf9, 0xf9, 0xf9, 0xf9};
-  static const uint8 kSomariaBlockFizzle_Flags[6] = {6, 0xff, 0x86, 0xc6, 0x86, 0xc6};
-  if (sign8(--ancilla_aux_timer[k])) {
-    ancilla_aux_timer[k] = 3;
-    if (++ancilla_item_to_link[k] == 3) {
-      ancilla_type[k] = 0;
-      return;
-    }
-  }
-  Point16U pt;
-  Ancilla_PrepAdjustedOamCoord(k, &pt);
-  OamEnt *oam = GetOamCurPtr();
-  uint8 z = ancilla_z[k];
-  if (z == 0xff)
-    z = 0;
-  int x = pt.x, y = pt.y - (int8)z;
-  int j = ancilla_item_to_link[k] * 2;
-  for (int i = 0; i < 2; i++, j++, oam++) {
-    if (kSomariaBlockFizzle_Char[j] != 0xff) {
-      Ancilla_SetOam(oam, x + kSomariaBlockFizzle_X[j], y + kSomariaBlockFizzle_Y[j],
-                     kSomariaBlockFizzle_Char[j],
-                     kSomariaBlockFizzle_Flags[j] & ~0x30 | HIBYTE(oam_priority_value), 0);
-    }
-  }
-}
-
-void Ancilla39_SomariaPlatformPoof(int k) {  // 88ea83
-  static const uint8 kSomarianPlatformPoof_Tab0[4] = {1, 0, 3, 2};
-  if (!sign8(--ancilla_aux_timer[k]))
-    return;
-  ancilla_type[k] = 0;
-  SpriteSpawnInfo info;
-  int x = Ancilla_GetX(k) & ~7 | 4, y = Ancilla_GetY(k) & ~7 | 4;
-  uint8 floor = ancilla_floor[k];
-  int j = Sprite_SpawnDynamically(k, 0xed, &info);  // wtf
-  if (j >= 0) {
-    player_on_somaria_platform = 0;
-    Sprite_SetX(j, x);
-    Sprite_SetY(j, y);
-
-    int pos = ((x & 0x1f8) >> 3) + ((y & 0x1f8) << 3) + (floor >= 1 ? 0x1000 : 0);
-
-    int t = 0;
-    if ((dung_bg2_attr_table[pos + XY(0, -1)] & 0xf0) != 0xb0) {
-      t += 1;
-      if ((dung_bg2_attr_table[pos + XY(0, 1)] & 0xf0) != 0xb0) {
-        t += 1;
-        if ((dung_bg2_attr_table[pos + XY(-1, 0)] & 0xf0) != 0xb0) {
-          t += 1;
-        }
-      }
-    }
-    sprite_D[j] = kSomarianPlatformPoof_Tab0[t];
-    sprite_floor[j] = 0;
-  } else {
-    AncillaDraw_SomariaBlock(k);
-  }
-}
-
-void Ancilla2E_SomariaBlockFission(int k) {  // 88eb3e
-  static const int8 kSomarianBlockDivide_X[16] = {-8, 0, -8, 0, -10, -10, 2, 2, -8, 0, -8, 0, -12, -12, 4, 4};
-  static const int8 kSomarianBlockDivide_Y[16] = {-10, -10, 2, 2, -8, 0, -8, 0, -12, -12, 4, 4, -8, 0, -8, 0};
-  static const uint8 kSomarianBlockDivide_Char[16] = {0xc6, 0xc6, 0xc6, 0xc6, 0xc4, 0xc4, 0xc4, 0xc4, 0xd2, 0xd2, 0xd2, 0xd2, 0xc5, 0xc5, 0xc5, 0xc5};
-  static const uint8 kSomarianBlockDivide_Flags[16] = {0xc6, 0x86, 0x46, 6, 0x46, 0xc6, 6, 0x86, 0xc6, 0x86, 0x46, 6, 0x46, 0xc6, 6, 0x86};
-
-  if (sign8(--ancilla_aux_timer[k])) {
-    ancilla_aux_timer[k] = 3;
-    if (++ancilla_item_to_link[k] == 2) {
-      ancilla_type[k] = 0;
-      SomariaBlock_SpawnBullets(k);
-      return;
-    }
-  }
-  Point16U pt;
-  Ancilla_PrepAdjustedOamCoord(k, &pt);
-  OamEnt *oam = GetOamCurPtr();
-
-  int8 z = ancilla_z[k] + (ancilla_K[k] == 3 && BYTE(link_z_coord) != 0xff ? BYTE(link_z_coord) : 0);
-  int j = ancilla_item_to_link[k] * 8;
-  for (int i = 0; i != 8; i++, j++, oam++) {
-    Ancilla_SetOam(oam, pt.x + kSomarianBlockDivide_X[j], pt.y + kSomarianBlockDivide_Y[j] - z,
-                   kSomarianBlockDivide_Char[j], kSomarianBlockDivide_Flags[j] & ~0x30 | HIBYTE(oam_priority_value), 0);
-  }
-}
-
-void Ancilla2F_LampFlame(int k) {  // 88ec13
-  static const uint8 kLampFlame_Draw_Char[12] = {0x9c, 0x9c, 0xff, 0xff, 0xa4, 0xa5, 0xb2, 0xb3, 0xe3, 0xf3, 0xff, 0xff};
-  static const int8 kLampFlame_Draw_Y[12] = {-3, 0, 0, 0, 0, 0, 8, 8, 0, 8, 0, 0};
-  static const int8 kLampFlame_Draw_X[12] = {4, 10, 0, 0, 1, 9, 2, 7, 4, 4, 0, 0};
-
-  Point16U pt;
-  Ancilla_PrepAdjustedOamCoord(k, &pt);
-  OamEnt *oam = GetOamCurPtr();
-  if (!ancilla_timer[k]) {
-    ancilla_type[k] = 0;
-    return;
-  }
-  int j = (ancilla_timer[k] & 0xf8) >> 1;
-  do {
-    if (kLampFlame_Draw_Char[j] != 0xff) {
-      Ancilla_SetOam(oam, pt.x + kLampFlame_Draw_X[j], pt.y + kLampFlame_Draw_Y[j], kLampFlame_Draw_Char[j], HIBYTE(oam_priority_value) | 2, 0);
-      oam++;
-    }
-  } while (++j & 3);
-}
-
-void Ancilla41_WaterfallSplash(int k) {  // 88ecaf
-  if (!Ancilla_CheckForEntranceTrigger(player_is_indoors ? 0 : 1)) {
-    ancilla_type[k] = 0;
-    return;
-  }
-
-  if (!submodule_index && !(frame_counter & 7))
-    Ancilla_Sfx2_Near(0x1c);
-
-  draw_water_ripples_or_grass = 1;
-  if (!sign8(link_animation_steps - 6))
-    link_animation_steps -= 6;
-
-  if (!ancilla_timer[k]) {
-    ancilla_timer[k] = 2;
-    ancilla_item_to_link[k] = (ancilla_item_to_link[k] + 1) & 3;
-  }
-
-  if (player_is_indoors && BYTE(link_y_coord) < 0x38) {
-    Ancilla_SetY(k, 0xd38);
-  } else {
-    Ancilla_SetY(k, link_y_coord);
-  }
-  Ancilla_SetX(k, link_x_coord);
-
-  static const int8 kWaterfallSplash_X[8] = {0, 0, -4, 4, -7, 7, -9, 17};
-  static const int8 kWaterfallSplash_Y[8] = {-4, 0, -5, -5, -3, -3, 12, 12};
-  static const uint8 kWaterfallSplash_Char[8] = {0xc0, 0xff, 0xac, 0xac, 0xae, 0xae, 0xbf, 0xbf};
-  static const uint8 kWaterfallSplash_Flags[8] = {0x84, 0xff, 0x84, 0xc4, 0x84, 0xc4, 0x84, 0xc4};
-  static const uint8 kWaterfallSplash_Ext[8] = {2, 0xff, 2, 2, 2, 2, 0, 0};
-
-  Point16U pt;
-  Ancilla_PrepAdjustedOamCoord(k, &pt);
-  OamEnt *oam = GetOamCurPtr();
-
-  uint8 z = link_z_coord;
-  pt.y -= (sign8(z) ? 0 : z);
-
-  int j = ancilla_item_to_link[k] * 2;
-  for (int i = 0; i != 2; i++, j++, oam++) {
-    if (kWaterfallSplash_Char[j] != 0xff) {
-      Ancilla_SetOam(oam, pt.x + kWaterfallSplash_X[j], pt.y + kWaterfallSplash_Y[j], kWaterfallSplash_Char[j],
-                     kWaterfallSplash_Flags[j] | 0x30, kWaterfallSplash_Ext[j]);
-    }
-  }
-}
-
-void Ancilla24_Gravestone(int k) {  // 88ee01
-  static const uint8 kAncilla_Gravestone_Char[4] = {0xc8, 0xc8, 0xd8, 0xd8};
-  static const uint8 kAncilla_Gravestone_Flags[4] = {0, 0x40, 0, 0x40};
-  Point16U pt;
-  Ancilla_PrepAdjustedOamCoord(k, &pt);
-  Oam_AllocateFromRegionB(16);
-  OamEnt *oam = GetOamCurPtr();
-  uint16 x = pt.x, y = pt.y;
-  for (int i = 0; i < 4; i++, oam++) {
-    Ancilla_SetOam(oam, x, y, kAncilla_Gravestone_Char[i], kAncilla_Gravestone_Flags[i] | 0x3d, 2);
-    x += 16;
-    if (i == 1)
-      x -= 32, y += 8;
-  }
-}
-
-void Ancilla34_SkullWoodsFire(int k) {  // 88ef9a
-  static const int8 kSkullWoodsFire_Draw_Y[4] = {0, 0, 0, -3};
-  static const uint8 kSkullWoodsFire_Draw_Char[4] = {0x8e, 0xa0, 0xa2, 0xa4};
-  static const uint8 kSkullWoodsFire_Draw_Ext[4] = {2, 2, 2, 0};
-  static const int8 kSkullWoodsFire_Draw2_X[24] = {
-    -13, -21, -10, -1,  -1,  -1, -16, -27, -4, -16, -6, -25, -16, -27, -4, -16,
-    -6, -25, -13, -5, -27, -11, -22,  -3,
-  };
-  static const int8 kSkullWoodsFire_Draw2_Y[24] = {
-    -31, -24, -22,  -1,  -1,  -1, -37, -32, -32, -23, -16, -14, -37, -32, -32, -23,
-    -16, -14, -35, -29, -28, -20, -13, -11,
-  };
-  static const uint8 kSkullWoodsFire_Draw2_Char[24] = {
-    0x86, 0x86, 0x86, 0xff, 0xff, 0xff, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x8a, 0x8a, 0x8a, 0x8a,
-    0x8a, 0x8a, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b,
-  };
-  static const uint8 kSkullWoodsFire_Draw2_Flags[24] = {
-    0, 0,    0,    0,    0,    0,    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    0, 0, 0x80, 0x40, 0x40, 0x80, 0x40, 0,
-  };
-  static const uint8 kSkullWoodsFire_Draw2_Ext[24] = {
-    2, 2, 2, 2, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-    2, 2, 0, 0, 0, 0, 0, 0,
-  };
-  if (skullwoodsfire_var4 && ancilla_item_to_link[k] != 4 && sign8(--ancilla_aux_timer[k])) {
-    ancilla_aux_timer[k] = 5;
-    ancilla_item_to_link[k]++;
-  }
-  OamEnt *oam = GetOamCurPtr();
-  for(int k = 3; k >= 0; k--) {
-    if (sign8(--skullwoodsfire_var5[k])) {
-      skullwoodsfire_var5[k] = 5;
-      if (skullwoodsfire_var0[k] == 128)
-        goto endif_2;
-      if (++skullwoodsfire_var0[k] != 0) {
-        if (skullwoodsfire_var0[k] != 4)
-          goto endif_2;
-        skullwoodsfire_var0[k] = 0;
-      }
-      skullwoodsfire_var9 -= 8;
-      if (skullwoodsfire_var9 < 200 && skullwoodsfire_var4 != 1) {
-        skullwoodsfire_var4 = 1;
-        sound_effect_1 = kBombos_Sfx[(uint8)(0x98 - BG2HOFS_copy2) >> 5] | 0xc;
-      }
-      if (skullwoodsfire_var9 < 168)
-        skullwoodsfire_var0[k] = 128;
-      skullwoodsfire_x_arr[k] = skullwoodsfire_var11;
-      skullwoodsfire_y_arr[k] = skullwoodsfire_var9;
-      if (sound_effect_1 == 0)
-        sound_effect_1 = kBombos_Sfx[(uint8)(skullwoodsfire_var11 - BG2HOFS_copy2) >> 5] | 0x2a;
-    }
-endif_2:
-    if (!sign8(skullwoodsfire_var0[k])) {
-      int j = skullwoodsfire_var0[k];
-      uint16 x = skullwoodsfire_x_arr[k] - BG2HOFS_copy2;
-      uint16 y = skullwoodsfire_y_arr[k] - BG2VOFS_copy2 + kSkullWoodsFire_Draw_Y[j];
-      Ancilla_SetOam(oam, x, y, kSkullWoodsFire_Draw_Char[j], 0x32, kSkullWoodsFire_Draw_Ext[j]);
-      oam++;
-      if (kSkullWoodsFire_Draw_Ext[j] != 2) {
-        Ancilla_SetOam(oam, x + 8, y, kSkullWoodsFire_Draw_Char[j] + 1, 0x32, kSkullWoodsFire_Draw_Ext[j]);
-        oam++;
-      }
-    }
-  }
-
-  for (int i = 3; sign8(skullwoodsfire_var0[i]); ) {
-    if (--i < 0) {
-      ancilla_type[k] = 0;
-      return;
-    }
-  }
-
-  if (skullwoodsfire_var4 == 0 || ancilla_item_to_link[k] == 4)
-    return;
-
-  int j = ancilla_item_to_link[k] * 6;
-  for (int i = 0; i < 6; i++, j++) {
-    if (kSkullWoodsFire_Draw2_Char[j] != 0xff) {
-      Ancilla_SetOam(oam,
-          168 - BG2HOFS_copy2 + kSkullWoodsFire_Draw2_X[j],
-          200 - BG2VOFS_copy2 + kSkullWoodsFire_Draw2_Y[j],
-          kSkullWoodsFire_Draw2_Char[j],
-          kSkullWoodsFire_Draw2_Flags[j] | 0x32, kSkullWoodsFire_Draw2_Ext[j]);
-      oam++;
-    }
-  }
-}
-
-void Ancilla3A_BigBombExplosion(int k) {  // 88f18d
-  static const int8 kSuperBombExplode_X[9] = {0, -16, 0, 16, -24, 24, -16, 0, 16};
-  static const int8 kSuperBombExplode_Y[9] = {0, -16, -24, -16, 0, 0, 16, 24, 16};
-
-  if (!submodule_index && !--ancilla_arr3[k]) {
-    if (++ancilla_item_to_link[k] == 2)
-      Ancilla_Sfx2_Pan(k, 0xc);
-    if (ancilla_item_to_link[k] == 11) {
-      ancilla_type[k] = 0;
-      return;
-    }
-    ancilla_arr3[k] = kBomb_Tab0[ancilla_item_to_link[k]];
-  }
-  oam_priority_value = 0x3000;
-  uint8 numframes = kBomb_Draw_Tab2[ancilla_item_to_link[k]];
-  int j = kBomb_Draw_Tab0[ancilla_item_to_link[k]] * 6;
-  ancilla_step[k] = j * 2;
-
-  int yy = 0;
-  for (int i = 8; i >= 0; i--) {
-    uint16 x = Ancilla_GetX(k) + kSuperBombExplode_X[i] - BG2HOFS_copy2;
-    uint16 y = Ancilla_GetY(k) + kSuperBombExplode_Y[i] - BG2VOFS_copy2;
-    if (x < 256 && y < 256) {
-      Ancilla_AllocateOamFromRegion_A_or_D_or_F((uint8)(j * 2), 0x18); // wtf
-      OamEnt *oam = GetOamCurPtr() + yy;
-      yy += AncillaDraw_Explosion(oam, j, 0, numframes, 0x32, x, y) - oam;
-
-    }
-  }
-  if (ancilla_item_to_link[k] == 3 && ancilla_arr3[k] == 1) {
-    // Changed so this is reset elsewhere. Some code depends on the value 13.
-    uint8 old = (enhanced_features0 & kFeatures0_MiscBugFixes) ? follower_indicator : 0;
-    follower_indicator = 13;
-    Bomb_CheckForDestructibles(Ancilla_GetX(k), Ancilla_GetY(k), 0); // r14?
-    follower_indicator = old;
-  }
-}
-
-void RevivalFairy_Main() {  // 88f283
-  static const uint8 kAncilla_RevivalFaerie_Tab0[2] = {0, 0x90};
-  static const uint8 kAncilla_RevivalFaerie_Tab1[5] = {0x4b, 0x4d, 0x49, 0x47, 0x49};
-
-  int k = 0;
-  switch (ancilla_step[k]) {
-  case 0:
-    if (!--ancilla_arr3[k]) {
-      ancilla_arr3[k] = kAncilla_RevivalFaerie_Tab0[++ancilla_step[k]];
-      ancilla_K[k] = 0;
-      ancilla_z_vel[k] = 0;
-    } else {
-      Ancilla_MoveZ(k);
-    }
-    break;
-  case 1:
-    if (!--ancilla_arr3[k]) {
-      ancilla_step[k]++;
-      ancilla_z_vel[k] = 0;
-      ancilla_x_vel[k] = 0;
-    } else {
-      if (ancilla_arr3[k] == 0x4f || ancilla_arr3[k] == 0x8f) {
-        ancilla_L[k]++;
-        Ancilla_Sfx2_Pan(k, 0x31);
-      }
-      if (ancilla_L[k] != 0 && sign8(--ancilla_G[k])) {
-        ancilla_G[k] = 5;
-        if (++ancilla_item_to_link[k] == 3) {
-          ancilla_item_to_link[k] = 0;
-          ancilla_L[k] = 0;
-        }
-      }
-      ancilla_z_vel[k] += ancilla_K[k] ? 1 : -1;
-      if (abs8(ancilla_z_vel[k]) == 8)
-        ancilla_K[k] ^= 1;
-      Ancilla_MoveZ(k);
-    }
-    break;
-  case 2:
-    if (ancilla_z_vel[k] < 24)
-      ancilla_z_vel[k] += 1;
-    if (ancilla_x_vel[k] < 16)
-      ancilla_x_vel[k] += 1;
-    Ancilla_MoveX(k);
-    Ancilla_MoveZ(k);
-    break;
-  case 3:
-    goto skip_draw;
-  }
-
-  {
-    Oam_AllocateFromRegionC(12);
-    Point16U pt;
-    Ancilla_PrepOamCoord(k, &pt);
-    OamEnt *oam = GetOamCurPtr();
-    int t = (ancilla_step[k] == 1 && ancilla_L[k]) ? ancilla_item_to_link[k] + 1 : 0;
-    if (t != 0)
-      t += 1;
-    else
-      t = (frame_counter >> 2) & 1;
-    Ancilla_SetOam(oam, pt.x, pt.y - (int8)ancilla_z[k], kAncilla_RevivalFaerie_Tab1[t], 0x74, 2);
-    if (oam->y == 0xf0) {
-      ancilla_step[k] = 3;
-      submodule_index++;
-      TM_copy = mapbak_TM;
-    }
-  }
-skip_draw:
-  RevivalFairy_Dust();
-  RevivalFairy_MonitorHP();
-}
-
-void RevivalFairy_Dust() {  // 88f3cf
-  int k = 2;
-  if (ancilla_step[0] == 0 || ancilla_step[k] == 2 || !sign8(--ancilla_arr3[k]))
-    return;
-  ancilla_arr3[k] = 0;
-  if (!sort_sprites_setting)
-    Oam_AllocateFromRegionA(16);
-  else
-    Oam_AllocateFromRegionD(16);
-  if (sign8(--ancilla_aux_timer[k])) {
-    ancilla_aux_timer[k] = 3;
-    if (ancilla_item_to_link[k] == 9) {
-      ancilla_arr3[k] = 32;
-      ancilla_step[k]++;
-      ancilla_item_to_link[k] = 2;
-      return;
-    }
-    ancilla_arr25[k] = kMagicPowder_Tab0[30 + ++ancilla_item_to_link[k]];
-  }
-  Ancilla_MagicPowder_Draw(k);
-}
-
-void RevivalFairy_MonitorHP() {  // 88f430
-  if ((link_health_current == link_health_capacity || link_health_current == 0x38) && !is_doing_heart_animation) {
-    if (link_is_in_deep_water) {
-      link_some_direction_bits = 4;
-      link_player_handler_state = kPlayerState_Swimming;
-    } else if (link_is_bunny) {
-      link_player_handler_state = kPlayerState_PermaBunny;
-      link_is_bunny_mirror = 1;
-      //bugfix: dying as permabunny doesn't restore link palette during death animation
-      if (enhanced_features0 & kFeatures0_MiscBugFixes)
-        LoadGearPalettes_bunny();
-    } else {
-      link_player_handler_state = kPlayerState_Ground;
-    }
-    link_auxiliary_state = 0;
-    player_unk1 = 0;
-    link_var30d = 0;
-    some_animation_timer_steps = 0;
-    BYTE(link_z_coord) = 0;
-    link_incapacitated_timer = 0;
-    for(int i = 0; i < 5; i++)
-      ancilla_type[i] = 0;
-    return;
-  }
-  int k = 1;
-  if (!ancilla_step[k]) {
-    if (!--ancilla_arr3[k]) {
-      ancilla_arr3[k]++;
-      ancilla_z_vel[k] = 4;
-      Ancilla_MoveZ(k);
-      if (ancilla_z[k] >= 16) {
-        ancilla_step[k]++;
-        ancilla_z_vel[k] = 2;
-      }
-    }
-  } else {
-    if (sign8(--ancilla_K[k])) {
-      ancilla_K[k] = 32;
-      ancilla_z_vel[k] = -ancilla_z_vel[k];
-    }
-    Ancilla_MoveZ(k);
-  }
-  BYTE(link_z_coord) = ancilla_z[k];
-}
-
-void GameOverText_Draw() {  // 88f5c4
-  static const uint8 kGameOverText_Chars[16] = {0x40, 0x50, 0x41, 0x51, 0x42, 0x52, 0x43, 0x53, 0x44, 0x54, 0x45, 0x55, 0x43, 0x53, 0x46, 0x56};
-  oam_cur_ptr = 0x800;
-  oam_ext_cur_ptr = 0xa20;
-  OamEnt *oam = GetOamCurPtr();
-  int k = flag_for_boomerang_in_place;
-  do {
-    Ancilla_SetOam(oam + 0, Ancilla_GetX(k), 0x57, kGameOverText_Chars[k * 2 + 0], 0x3c, 0);
-    Ancilla_SetOam(oam + 1, Ancilla_GetX(k), 0x5f, kGameOverText_Chars[k * 2 + 1], 0x3c, 0);
-  } while (oam += 2, --k >= 0);
-}
-
-int AncillaAdd_AddAncilla_Bank08(uint8 type, uint8 y) {  // 88f631
-  int k = Ancilla_AllocInit(type, y);
-  if (k >= 0) {
-    ancilla_type[k] = type;
-    ancilla_numspr[k] = kAncilla_Pflags[type];
-    ancilla_floor[k] = link_is_on_lower_level;
-    ancilla_floor2[k] = link_is_on_lower_level_mirror;
-    ancilla_y_vel[k] = 0;
-    ancilla_x_vel[k] = 0;
-    ancilla_objprio[k] = 0;
-    ancilla_U[k] = 0;
-  }
-  return k;
-}
-
-void Ancilla_PrepOamCoord(int k, Point16U *info) {  // 88f671
-  oam_priority_value = kTagalongLayerBits[ancilla_floor[k]] << 8;
-  info->x = Ancilla_GetX(k) - BG2HOFS_copy2;
-  info->y = Ancilla_GetY(k) - BG2VOFS_copy2;
-}
-
-void Ancilla_PrepAdjustedOamCoord(int k, Point16U *info) {  // 88f6a4
-  oam_priority_value = kTagalongLayerBits[ancilla_floor[k]] << 8;
-  info->x = Ancilla_GetX(k) - BG2HOFS_copy;
-  info->y = Ancilla_GetY(k) - BG2VOFS_copy;
-}
-
-bool Ancilla_CheckLinkCollision(int k, int j, CheckPlayerCollOut *out) {  // 88f76b
-  static const int16 kAncilla_Coll_Yoffs[5] = {0, 8, 8, 8, 0};
-  static const int16 kAncilla_Coll_Xoffs[5] = {0, 8, 8, 8, 0};
-  static const int16 kAncilla_Coll_H[5] = {20, 20, 8, 28, 14};
-  static const int16 kAncilla_Coll_W[5] = {20, 3, 8, 24, 14};
-  static const int16 kAncilla_Coll_LinkYoffs[5] = {12, 12, 12, 12, 12};
-  static const int16 kAncilla_Coll_LinkXoffs[5] = {8, 8, 8, 12, 8};
-  uint16 x = Ancilla_GetX(k), y = Ancilla_GetY(k);
-  y += kAncilla_Coll_Yoffs[j] + (int8)ancilla_z[k];
-  x += kAncilla_Coll_Xoffs[j];
-  out->r4 = link_y_coord + kAncilla_Coll_LinkYoffs[j] - y;
-  out->r8 = abs16(out->r4);
-  out->r6 = link_x_coord + kAncilla_Coll_LinkXoffs[j] - x;
-  out->r10 = abs16(out->r6);
-  return out->r8 < kAncilla_Coll_H[j] && out->r10 < kAncilla_Coll_W[j];
-}
-
-bool Hookshot_CheckProximityToLink(int x, int y) {  // 88f7dc
-  return abs16(link_y_coord - BG2VOFS_copy2 + 12 - y - 4) < 12 &&
-         abs16(link_x_coord - BG2HOFS_copy2 +  8 - x - 4) < 12;
-}
-
-bool Ancilla_CheckForEntranceTrigger(int what) {  // 88f844
-  static const uint16 kEntranceTrigger_BaseY[4] = {0xd40, 0x210, 0xcfc, 0x100};
-  static const uint16 kEntranceTrigger_BaseX[4] = {0xd80, 0xe68, 0x130, 0xf10};
-  static const uint8 kEntranceTrigger_SizeY[4] = {11, 32, 16, 12};
-  static const uint8 kEntranceTrigger_SizeX[4] = {16, 16, 16, 16};
-  return
-    abs16(link_y_coord + 12 - kEntranceTrigger_BaseY[what]) < kEntranceTrigger_SizeY[what] &&
-    abs16(link_x_coord + 8 - kEntranceTrigger_BaseX[what]) < kEntranceTrigger_SizeX[what];
-}
-
-void AncillaDraw_Shadow(OamEnt *oam, int k, int x, int y, uint8 pal) {  // 88f897
-  static const uint8 kAncilla_DrawShadow_Char[14] = {0x6c, 0x6c, 0x28, 0x28, 0x38, 0xff, 0xc8, 0xc8, 0xd8, 0xd8, 0xd9, 0xd9, 0xda, 0xda};
-  static const uint8 kAncilla_DrawShadow_Flags[14] = {0x28, 0x68, 0x28, 0x68, 0x28, 0xff, 0x22, 0x22, 0x24, 0x64, 0x24, 0x64, 0x24, 0x64};
-
-  if (k == 2)
-    x += 4;
-  Ancilla_SetOam_Safe(oam, x, y,
-                      kAncilla_DrawShadow_Char[k * 2],
-                      kAncilla_DrawShadow_Flags[k * 2] & ~0x30 | pal, 0);
-  uint8 ch = kAncilla_DrawShadow_Char[k * 2 + 1];
-  if (ch != 0xff) {
-    x += 8;
-    Ancilla_SetOam_Safe(oam + 1, x, y, ch, kAncilla_DrawShadow_Flags[k * 2 + 1] & ~0x30 | pal, 0);
-  }
-}
-
-void Ancilla_AllocateOamFromRegion_B_or_E(uint8 size) {  // 88f90a
-  if (!sort_sprites_setting)
-    Oam_AllocateFromRegionB(size);
-  else
-    Oam_AllocateFromRegionE(size);
-}
-
-OamEnt *Ancilla_AllocateOamFromCustomRegion(OamEnt *oam) {  // 88f9ba
-  int a = (uint8 *)oam - g_ram;
-  if (sort_sprites_setting) {
-    if (a < 0x900) {
-      if (a < 0x8e0)
-        return oam;
-      a = 0x820;
-    } else {
-      if (a < 0x9d0)
-        return oam;
-      a = 0x940;
-    }
-  } else {
-    if (a < 0x990)
-      return oam;
-    a = 0x820;
-  }
-  oam_cur_ptr = a;
-  oam_ext_cur_ptr = ((a - 0x800) >> 2) + 0xa20;
-  return GetOamCurPtr();
-}
-
-OamEnt *HitStars_UpdateOamBufferPosition(OamEnt *oam) {  // 88fa00
-  int a = (uint8 *)oam - g_ram;
-  if (!sort_sprites_setting && a >= 0x9d0) {
-    oam_cur_ptr = 0x820;
-    oam_ext_cur_ptr = 0xa20 + (0x20 >> 2);
-    oam = GetOamCurPtr();
-  }
-  return oam;
-}
-
-bool Hookshot_ShouldIEvenBotherWithTiles(int k) {  // 88fa2d
-  uint16 x = Ancilla_GetX(k), y = Ancilla_GetY(k);
-  if (!player_is_indoors) {
-    if (!(ancilla_dir[k] & 2)) {
-      uint16 t = y - kOverworld_OffsetBaseY[BYTE(current_area_of_player) >> 1];
-      return (t < 4) || (t >= overworld_right_bottom_bound_for_scroll);
-    } else {
-      uint16 t = x - kOverworld_OffsetBaseX[BYTE(current_area_of_player) >> 1];
-      return (t < 6) || (t >= overworld_right_bottom_bound_for_scroll);
-    }
-  }
-  if (!(ancilla_dir[k] & 2)) {
-    return (y & 0x1ff) < 4 || (y & 0x1ff) >= 0x1e8 || (y & 0x200) != (link_y_coord & 0x200);
-  } else {
-    return (x & 0x1ff) < 4 || (x & 0x1ff) >= 0x1f0 || (x & 0x200) != (link_x_coord & 0x200);
-  }
-}
-
-AncillaRadialProjection Ancilla_GetRadialProjection(uint8 a, uint8 r8) {  // 88fadd
-  static const uint8 kRadialProjection_Tab0[64] = {
-    255, 254, 251, 244, 236, 225, 212, 197, 181, 162, 142, 120,  97,  74,  49,  25,
-      0,  25,  49,  74,  97, 120, 142, 162, 181, 197, 212, 225, 236, 244, 251, 254,
-    255, 254, 251, 244, 236, 225, 212, 197, 181, 162, 142, 120,  97,  74,  49,  25,
-      0,  25,  49,  74,  97, 120, 142, 162, 181, 197, 212, 225, 236, 244, 251, 254,
-  };
-  static const uint8 kRadialProjection_Tab2[64] = {
-      0,  25,  49,  74,  97, 120, 142, 162, 181, 197, 212, 225, 236, 244, 251, 254,
-    255, 254, 251, 244, 236, 225, 212, 197, 181, 162, 142, 120,  97,  74,  49,  25,
-      0,  25,  49,  74,  97, 120, 142, 162, 181, 197, 212, 225, 236, 244, 251, 254,
-    255, 254, 251, 244, 236, 225, 212, 197, 181, 162, 142, 120,  97,  74,  49,  25,
-  };
-  static const uint8 kRadialProjection_Tab1[64] = {
-    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-  };
-  static const uint8 kRadialProjection_Tab3[64] = {
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-  };
-  AncillaRadialProjection rv;
-  int p0 = kRadialProjection_Tab0[a] * r8;
-  int p1 = kRadialProjection_Tab2[a] * r8;
-  rv.r0 = (p0 >> 8) + (p0 >> 7 & 1);
-  rv.r2 = kRadialProjection_Tab1[a];
-  rv.r4 = (p1 >> 8) + (p1 >> 7 & 1);
-  rv.r6 = kRadialProjection_Tab3[a];
-  return rv;
-}
-
-int Ancilla_AllocateOamFromRegion_A_or_D_or_F(int k, uint8 size) {  // 88fb2b
-  if (sort_sprites_setting) {
-    if (ancilla_floor[k])
-      return Oam_AllocateFromRegionF(size);
-    else
-      return Oam_AllocateFromRegionD(size);
-  } else {
-    return Oam_AllocateFromRegionA(size);
-  }
-}
-
-void Ancilla_AddHitStars(uint8 a, uint8 y) {  // 898024
-  static const int8 kShovelHitStars_XY[12] = {21, -11, 21, 11, 3, -6, 21, 5, 16, -14, 16, 14};
-  static const int8 kShovelHitStars_X2[6] = {-3, 19, 2, 13, -6, 22};
-  int k = Ancilla_AddAncilla(a, y);
-  if (k >= 0) {
-    ancilla_item_to_link[k] = 0;
-    ancilla_aux_timer[k] = 2;
-    ancilla_arr3[k] = 1;
-    ancilla_y_vel[k] = 0;
-    ancilla_x_vel[k] = 0;
-    int j = a;
-    if (link_item_in_hand) {
-      j = (link_direction_facing >> 1) + 2;
-    } else if (link_position_mode) {
-      j = link_direction_facing != 4 ? 1 : 0;
-    }
-    ancilla_step[k] = j;
-    int t = link_x_coord + kShovelHitStars_X2[j];
-    ancilla_A[k] = t;
-    ancilla_B[k] = t >> 8;
-    Ancilla_SetXY(k, link_x_coord + kShovelHitStars_XY[j * 2 + 1], link_y_coord + kShovelHitStars_XY[j * 2 + 0]);
-  }
-}
-
-void AncillaAdd_Blanket(uint8 a) {  // 898091
-  int k = 0;
-  ancilla_type[k] = a;
-  ancilla_numspr[k] = kAncilla_Pflags[a];
-  ancilla_floor[k] = link_is_on_lower_level;
-  ancilla_floor2[k] = link_is_on_lower_level_mirror;
-  ancilla_objprio[k] = 0;
-  Ancilla_SetXY(k, 0x938, 0x2162);
-}
-
-void AncillaAdd_Snoring(uint8 a, uint8 y) {  // 8980c8
-  int k = Ancilla_AddAncilla(a, y);
-  if (k >= 0) {
-    ancilla_item_to_link[k] = 0;
-    ancilla_y_vel[k] = -8;
-    ancilla_aux_timer[k] = 7;
-    ancilla_x_vel[k] = 8;
-    ancilla_step[k] = 255;
-    Ancilla_SetXY(k, link_x_coord + 16, link_y_coord + 4);
-  }
-}
-
-void AncillaAdd_Bomb(uint8 a, uint8 y) {  // 89811f
-  static const int8 kBomb_Place_X0[4] = {8, 8, 0, 16};
-  static const int8 kBomb_Place_Y0[4] = {0, 24, 12, 12};
-  static const int8 kBomb_Place_X1[4] = {8, 8, -6, 22};
-  static const int8 kBomb_Place_Y1[4] = {4, 28, 12, 12};
-
-  int k = Ancilla_AddAncilla(a, y);
-  if (k < 0)
-    return;
-  if (link_item_bombs == 0) {
-    ancilla_type[k] = 0;
-    return;
-  }
-
-  if (--link_item_bombs == 0)
-    Hud_RefreshIcon();
-
-  ancilla_R[k] = 0;
-  ancilla_step[k] = 0;
-  ancilla_item_to_link[k] = 0;
-  ancilla_L[k] = 0;
-  ancilla_arr3[k] = kBomb_Tab0[0];
-
-  // These are not used directly by bombs, but used by door debris
-  ancilla_arr25[k] = 0;
-  ancilla_arr26[k] = 7;
-
-  ancilla_z[k] = 0;
-  ancilla_timer[k] = 8;
-  ancilla_dir[k] = link_direction_facing >> 1;
-  ancilla_T[k] = 0;
-  ancilla_arr23[k] = 0;
-  ancilla_arr22[k] = 0;
-  if (Ancilla_CheckInitialTileCollision_Class2(k)) {
-    int j = link_direction_facing >> 1;
-    Ancilla_SetXY(k, link_x_coord + kBomb_Place_X0[j], link_y_coord + kBomb_Place_Y0[j]);
-  } else {
-    int j = link_direction_facing >> 1;
-    Ancilla_SetXY(k, link_x_coord + kBomb_Place_X1[j], link_y_coord + kBomb_Place_Y1[j]);
-  }
-  sound_effect_1 = Link_CalculateSfxPan() | 0xb;
-}
-
-uint8 AncillaAdd_Boomerang(uint8 a, uint8 y) {  // 89820f
-  static const uint8 kBoomerang_Tab0[4] = {0x20, 0x18, 0x30, 0x28};
-  static const uint8 kBoomerang_Tab1[2] = {0x20, 0x60};
-  static const uint8 kBoomerang_Tab2[2] = {3, 2};
-  static const uint8 kBoomerang_Tab3[4] = {8, 4, 2, 1};
-  static const uint8 kBoomerang_Tab4[8] = {8, 4, 2, 1, 9, 5, 10, 6};
-  static const uint8 kBoomerang_Tab5[8] = {2, 3, 3, 2, 2, 3, 3, 3};
-  static const int8 kBoomerang_Tab6[8] = {-10, -8, -9, -9, -10, -8, -9, -9};
-  static const int8 kBoomerang_Tab7[8] = {-10, 11, 8, -8, -10, 11, 8, -8};
-  static const int8 kBoomerang_Tab8[8] = {-16, 6, 0, 0, -8, 8, -8, 8};
-  static const int8 kBoomerang_Tab9[8] = {0, 0, -8, 8, 8, 8, -8, -8};
-
-  int k = Ancilla_AddAncilla(a, y);
-  if (k < 0)
-    return 0;
-  ancilla_aux_timer[k] = 0;
-  ancilla_item_to_link[k] = 0;
-  ancilla_K[k] = 0;
-  ancilla_z[k] = 0;
-  ancilla_L[k] = ancilla_numspr[k];
-  flag_for_boomerang_in_place = 1;
-  int j = link_item_boomerang - 1;
-  ancilla_G[k] = j;
-  ancilla_step[k] = kBoomerang_Tab1[j];
-  ancilla_arr3[k] = kBoomerang_Tab2[j];
-
-  int s = ancilla_G[k] * 2 + ((joypad1H_last & 0xc) && (joypad1H_last & 3) ? 1 : 0);
-  uint8 r0 = kBoomerang_Tab0[s];
-  ancilla_H[k] = r0;
-
-  uint8 r1 = (joypad1H_last & 0xf) ? (joypad1H_last & 0xf) : kBoomerang_Tab3[link_direction_facing >> 1];
-  hookshot_effect_index = 0;
-
-  if (r1 & 0xc) {
-    ancilla_y_vel[k] = r1 & 8 ? -r0 : r0;
-    int i = sign8(ancilla_y_vel[k]) ? 0 : 1;
-    ancilla_dir[k] = i;
-    hookshot_effect_index = kBoomerang_Tab3[i];
-  }
-  ancilla_S[k] = 0;
-
-  if (r1 & 3) {
-    if (!(r1 & 2))
-      ancilla_S[k] = 1;
-    ancilla_x_vel[k] = (r1 & 2) ? -r0 : r0;
-    int i = sign8(ancilla_x_vel[k]) ? 2 : 3;
-    ancilla_dir[k] = i;
-    hookshot_effect_index |= kBoomerang_Tab3[i];
-  }
-
-  j = FindInByteArray(kBoomerang_Tab4, r1, 8);
-  if (j < 0)
-    j = 0;
-  ancilla_arr1[k] = kBoomerang_Tab5[j];
-  ancilla_arr23[k] = j << 1;
-  if (button_b_frames >= 9) {
-    ancilla_aux_timer[k]++;
-  } else {
-    if (s || !(joypad1H_last & 0xf))
-      j = link_direction_facing >> 1;
-  }
-  s = Ancilla_CheckInitialTile_A(k);
-  if (s < 0) {
-    if (ancilla_aux_timer[k]) {
-      Ancilla_SetXY(k, link_x_coord + kBoomerang_Tab9[j], link_y_coord + 8 + kBoomerang_Tab8[j]);
-    } else {
-      Ancilla_SetXY(k, link_x_coord + kBoomerang_Tab7[j], link_y_coord + 8 + kBoomerang_Tab6[j]);
-    }
-  } else {
-    ancilla_type[k] = 0;
-    flag_for_boomerang_in_place = 0;
-    if (ancilla_tile_attr[k] != 0xf0) {
-      sound_effect_1 = Ancilla_CalculateSfxPan(k) | 5;
-    } else {
-      sound_effect_1 = Ancilla_CalculateSfxPan(k) | 6;
-    }
-    AncillaAdd_BoomerangWallClink(k);
-  }
-  return s;
-}
-
-void AncillaAdd_TossedPondItem(uint8 a, uint8 xin, uint8 yin) {  // 898a32
-  static const uint8 kWishPondItem_X[76] = {
-    4, 4, 4, 4,  4, 0, 0, 4, 4, 4, 4, 4, 5, 0, 0, 0,
-    0, 0, 0, 4,  0, 4, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, 0, 11, 0, 0, 0, 2, 0, 5, 0, 0, 0, 0, 0,
-    0, 0, 0, 0,  4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    0, 0, 4, 4,  0, 4, 0, 0, 0, 4, 0, 0,
-  };
-  static const int8 kWishPondItem_Y[76] = {
-    -13, -13, -13, -13, -13, -12, -12, -13, -13, -12, -12, -12, -10, -12, -12, -12,
-    -12, -12, -12, -12, -12, -12, -12, -12, -12, -12, -12, -12, -12, -12, -12, -12,
-    -12, -12, -12, -13, -12, -12, -12, -12, -12, -12, -10, -12, -12, -12, -12, -12,
-    -12, -12, -12, -12, -12, -12, -12, -12, -12, -12, -12, -12, -12, -12, -12, -12,
-    -12, -12, -12, -12, -12, -12, -12, -12, -12, -13, -12, -12,
-  };
-
-  link_receiveitem_index = xin;
-  int k = Ancilla_AddAncilla(a, yin);
-  if (k >= 0) {
-    sound_effect_2 = Link_CalculateSfxPan() | 0x13;
-    uint8 sb = kReceiveItemGfx[xin];
-
-    if (sb != 0xff) {
-      if (sb == 0x20)
-        DecompressShieldGraphics();
-      DecodeAnimatedSpriteTile_variable(sb);
-    } else {
-      DecodeAnimatedSpriteTile_variable(0);
-    }
-    if (sb == 6)
-      DecompressSwordGraphics();
-
-    link_state_bits = 0x80;
-    link_picking_throw_state = 0;
-    link_direction_facing = 0;
-    link_animation_steps = 0;
-    ancilla_z_vel[k] = 20;
-    ancilla_y_vel[k] = -40;
-    ancilla_x_vel[k] = 0;
-    ancilla_z[k] = 0;
-    ancilla_timer[k] = 16;
-    ancilla_item_to_link[k] = link_receiveitem_index;
-    Ancilla_SetXY(k,
-      link_x_coord + kWishPondItem_X[link_receiveitem_index],
-      link_y_coord + kWishPondItem_Y[link_receiveitem_index]);
-  }
-}
-
-void AddHappinessPondRupees(uint8 arg) {  // 898ae0
-  int k = Ancilla_AddAncilla(0x42, 9);
-  if (k < 0)
-    return;
-  sound_effect_2 = Link_CalculateSfxPan() | 0x13;
-  uint8 sb = kReceiveItemGfx[0x35];
-  DecodeAnimatedSpriteTile_variable(sb);
-  link_state_bits = 0x80;
-  link_picking_throw_state = 0;
-  link_direction_facing = 0;
-  link_animation_steps = 0;
-
-  memset(happiness_pond_arr1, 0, 10);
-
-  static const int8 kHappinessPond_Start[4] = {0, 4, 4, 9};
-  static const int8 kHappinessPond_End[4] = {-1, 0, -1, -1};
-  static const int8 kHappinessPond_Xvel[10] = {0, -12, -6, 6, 12, -9, -5, 0, 5, 9};
-  static const int8 kHappinessPond_Yvel[10] = {-40, -40, -40, -40, -40, -32, -32, -32, -32, -32};
-  static const int8 kHappinessPond_Zvel[10] = {20, 20, 20, 20, 20, 16, 16, 16, 16, 16};
-
-  int j = kHappinessPond_Start[arg], j_end = kHappinessPond_End[arg];
-  k = 9;
-  do {
-    happiness_pond_arr1[k] = 1;
-    happiness_pond_z_vel[k] = kHappinessPond_Zvel[j];
-    happiness_pond_y_vel[k] = kHappinessPond_Yvel[j];
-    happiness_pond_x_vel[k] = kHappinessPond_Xvel[j];
-    happiness_pond_z[k] = 0;
-    happiness_pond_step[k] = 0;
-    happiness_pond_timer[k] = 16;
-    happiness_pond_item_to_link[k] = 53;
-    int x = link_x_coord + 4;
-    int y = link_y_coord - 12;
-    happiness_pond_x_lo[k] = x;
-    happiness_pond_x_hi[k] = x >> 8;
-    happiness_pond_y_lo[k] = y;
-    happiness_pond_y_hi[k] = y >> 8;
-  } while (--k, --j != j_end);
-}
-
-int AncillaAdd_FallingPrize(uint8 a, uint8 item_idx, uint8 yv) {  // 898bc1
-  static const int8 kFallingItem_Type[7] = {0x10, 0x37, 0x39, 0x38, 0x26, 0xf, 0x20};
-  static const int8 kFallingItem_G[7] = {0x40, 0, 0, 0, 0, -1, 0};
-  static const int16 kFallingItem_X[7] = {0x78, 0x78, 0x78, 0x78, 0x78, 0x80, 0x78};
-  static const int16 kFallingItem_Y[7] = {0x48, 0x78, 0x78, 0x78, 0x78, 0x68, 0x78};
-  static const uint8 kFallingItem_Z[7] = {0x60, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80};
-  link_receiveitem_index = item_idx;
-  int k = Ancilla_AddAncilla(a, yv);
-  if (k < 0)
-    return k;
-  uint8 item_type = kFallingItem_Type[item_idx];
-  ancilla_item_to_link[k] = item_type;
-  if (item_type == 0x10 || item_type == 0xf)
-    DecodeAnimatedSpriteTile_variable(kReceiveItemGfx[item_type]);
-
-  ancilla_z_vel[k] = -48;
-  ancilla_y_vel[k] = 0;
-  ancilla_x_vel[k] = 0;
-  ancilla_step[k] = 0;
-  ancilla_z[k] = kFallingItem_Z[item_idx];
-  ancilla_aux_timer[k] = 9;
-  ancilla_arr3[k] = 0;
-  ancilla_L[k] = 0;
-  ancilla_G[k] = kFallingItem_G[item_idx];
-  link_receiveitem_index = item_type;
-
-  int x, y;
-  if (item_idx != 0 && item_idx != 5) {
-    if (BYTE(cur_palace_index_x2) == 20) {
-      x = (link_x_coord & 0xff00) | 0x100;
-      y = (link_y_coord & 0xff00) | 0x100;
-    } else {
-      x = kFallingItem_X[item_idx] + BG2HOFS_copy2;
-      y = kFallingItem_Y[item_idx] + BG2VOFS_copy2;
-    }
-  } else {
-    x = link_x_coord;
-    y = kFallingItem_Y[item_idx] + BG2VOFS_copy2;
-  }
-  Ancilla_SetXY(k, x, y);
-  return k;
-}
-
-void AncillaAdd_ChargedSpinAttackSparkle() {  // 898cb1
-  for (int k = 9; k >= 0; k--) {
-    if (ancilla_type[k] == 0 || ancilla_type[k] == 0x3c) {
-      ancilla_type[k] = 13;
-      ancilla_floor[k] = link_is_on_lower_level;
-      ancilla_timer[k] = 6;
-      break;
-    }
-  }
-}
-
-void AncillaAdd_ExplodingWeatherVane(uint8 a, uint8 y) {  // 898d11
-  static const int8 kWeathervane_Tab4[12] = {8, 10, 9, 4, 11, 12, -10, -8, 4, -6, -10, -4};
-  static const int8 kWeathervane_Tab5[12] = {20, 22, 20, 20, 22, 20, 20, 22, 20, 22, 20, 20};
-  static const uint8 kWeathervane_Tab6[12] = {0xb0, 0xa3, 0xa0, 0xa2, 0xa0, 0xa8, 0xa0, 0xa0, 0xa8, 0xa1, 0xb0, 0xa0};
-  static const uint8 kWeathervane_Tab8[12] = {0, 2, 4, 6, 3, 8, 14, 8, 12, 7, 10, 8};
-  static const uint8 kWeathervane_Tab10[12] = {48, 18, 32, 20, 22, 24, 32, 20, 24, 22, 20, 32};
-
-  int k = Ancilla_AddAncilla(a, y);
-  if (k < 0)
-    return;
-
-  ancilla_aux_timer[k] = 10;
-  ancilla_G[k] = 128;
-  ancilla_step[k] = 0;
-  ancilla_arr3[k] = 0;
-  sound_effect_1 = 0;
-  music_control = 0xf2;
-  sound_effect_ambient = 0x17;
-
-  weathervane_var1 = 0;
-  weathervane_var2 = 0x280;
-
-  for (int i = 11; i >= 0; i--) {
-    weathervane_arr3[i] = 0;
-    weathervane_arr4[i] = kWeathervane_Tab4[i];
-    weathervane_arr5[i] = kWeathervane_Tab5[i];
-    weathervane_arr6[i] = kWeathervane_Tab6[i];
-    weathervane_arr7[i] = 7;
-    weathervane_arr8[i] = kWeathervane_Tab8[i];
-    weathervane_arr9[i] = 2;
-    weathervane_arr10[i] = kWeathervane_Tab10[i];
-    weathervane_arr11[i] = 1;
-    weathervane_arr12[i] = i & 1;
-  }
-}
-
-void AncillaAdd_CutsceneDuck(uint8 a, uint8 y) {  // 898d90
-  if (AncillaAdd_CheckForPresence(a))
-    return;
-  int k = Ancilla_AddAncilla(a, y);
-  if (k >= 0) {
-    ancilla_dir[k] = 2;
-    ancilla_arr3[k] = 3;
-    ancilla_step[k] = 0;
-    ancilla_aux_timer[k] = 32;
-    ancilla_item_to_link[k] = 116;
-    ancilla_z_vel[k] = 0;
-    ancilla_L[k] = 0;
-    ancilla_z[k] = 0;
-    ancilla_S[k] = 0;
-    Ancilla_SetXY(k, 0x200, 0x788);
-  }
-}
-
-void AncillaAdd_SomariaPlatformPoof(int k) {  // 898dd2
-  ancilla_type[k] = 0x39;
-  ancilla_aux_timer[k] = 7;
-  for (int j = 15; j >= 0; j--) {
-    if (sprite_type[j] == 0xed) {
-      sprite_state[j] = 0;
-      player_on_somaria_platform = 0;
-    }
-  }
-  Player_TileDetectNearby();
-}
-
-int AncillaAdd_SuperBombExplosion(uint8 a, uint8 y) {  // 898df9
-  int k = Ancilla_AddAncilla(a, y);
-  if (k >= 0) {
-    ancilla_R[k] = 0;
-    ancilla_step[k] = 0;
-    ancilla_arr25[k] = 0;
-    ancilla_L[k] = 0;
-    ancilla_arr3[k] = kBomb_Tab0[1];
-    ancilla_item_to_link[k] = 1;
-    int j = WORD(tagalong_var2);
-    int y = tagalong_y_lo[j] | tagalong_y_hi[j] << 8;
-    int x = tagalong_x_lo[j] | tagalong_x_hi[j] << 8;
-    Ancilla_SetXY(k, x + 8, y + 16);
-  }
-  return k;
-}
-
-void ConfigureRevivalAncillae() {  // 898e4e
-  link_dma_var5 = 80;
-  int k = 0;
-
-  ancilla_arr3[k] = 64;
-  ancilla_step[k] = 0;
-  ancilla_z_vel[k] = 8;
-  ancilla_L[k] = 0;
-  ancilla_G[k] = 5;
-  ancilla_item_to_link[k] = 0;
-  ancilla_K[k] = 0;
-  Ancilla_SetXY(k, link_x_coord, link_y_coord);
-  ancilla_z[k] = 0;
-  k += 1;
-
-  ancilla_z[k] = 0;
-  ancilla_arr3[k] = 240;
-  ancilla_step[k] = 0;
-  ancilla_K[k] = 0;
-  k += 1;
-
-  ancilla_item_to_link[k] = 2;
-  ancilla_aux_timer[k] = 3;
-  ancilla_arr3[k] = 8;
-  ancilla_step[k] = 0;
-  ancilla_dir[k] = 3;
-  ancilla_arr25[k] = kMagicPowder_Tab0[30 + ancilla_item_to_link[k]];
-
-  Ancilla_SetXY(k, link_x_coord + 20, link_y_coord + 2);
-}
-
-void AncillaAdd_LampFlame(uint8 a, uint8 y) {  // 898f1c
-  static const int8 kLampFlame_X[4] = {0, 0, -20, 18};
-  static const int8 kLampFlame_Y[4] = {-16, 24, 4, 4};
-  int k = Ancilla_AddAncilla(a, y);
-  if (k >= 0) {
-    ancilla_item_to_link[k] = 0;
-    ancilla_aux_timer[k] = 0;
-    ancilla_timer[k] = 23;
-    int j = link_direction_facing >> 1;
-    ancilla_dir[k] = j;
-    Ancilla_SetXY(k, link_x_coord + kLampFlame_X[j], link_y_coord + kLampFlame_Y[j]);
-    sound_effect_1 = Ancilla_CalculateSfxPan(k) | 42;
-  }
-}
-
-void AncillaAdd_MSCutscene(uint8 a, uint8 y) {  // 898f7c
-  int k = Ancilla_AddAncilla(a, y);
-  if (k >= 0) {
-    ancilla_item_to_link[k] = 0;
-    ancilla_aux_timer[k] = 2;
-    ancilla_timer[k] = 64;
-    Ancilla_SetXY(k, link_x_coord + 8, link_y_coord - 8);
-  }
-}
-
-void AncillaAdd_DashDust(uint8 a, uint8 y) {  // 898fba
-  AddDashingDustEx(a, y, 1);
-}
-
-void AncillaAdd_DashDust_charging(uint8 a, uint8 y) {  // 898fc1
-  AddDashingDustEx(a, y, 0);
-}
-
-void AncillaAdd_BlastWallFireball(uint8 a, uint8 y, int r4) {  // 899031
-  static const int8 kBlastWall_XY[32] = {
-    -64, 0, -22,  42, -38,  38, -42,  22, 0,  64,  22,  42,  38,  38,  42,  22,
-    64, 0,  22, -42,  38, -38,  42, -22, 0, -64, -22, -42, -38, -38, -42, -22,
-  };
-  for (int k = 10; k != 4; k--) {
-    if (ancilla_type[k] == 0) {
-      ancilla_type[k] = 0x32;
-      ancilla_floor[k] = link_is_on_lower_level;
-      blastwall_var12[k] = 16;
-      int j = frame_counter & 15;
-      ancilla_y_vel[k] = kBlastWall_XY[j * 2 + 0];
-      ancilla_x_vel[k] = kBlastWall_XY[j * 2 + 1];
-      Ancilla_SetXY(k, blastwall_var11[r4] + 16, blastwall_var10[r4] + 8);
-      return;
-    }
-  }
-
-}
-
-int AncillaAdd_Arrow(uint8 a, uint8 ax, uint8 ay, uint16 xcoord, uint16 ycoord) {  // 8990a4
-  static const int8 kShootBow_X[4] = {4, 4, 0, 4};
-  static const int8 kShootBow_Y[4] = {-4, 3, 4, 4};
-  static const int8 kShootBow_Xvel[4] = {0, 0, -48, 48};
-  static const int8 kShootBow_Yvel[4] = {-48, 48, 0, 0};
-
-  scratch_0 = ycoord;
-  scratch_1 = xcoord;
-  BYTE(index_of_interacting_tile) = ax;
-
-  if (AncillaAdd_CheckForPresence(a))
-    return -1;
-
-  int k = AncillaAdd_ArrowFindSlot(a, ay);
-
-  if (k >= 0) {
-    sound_effect_1 = Link_CalculateSfxPan() | 7;
-    ancilla_H[k] = 0;
-    ancilla_item_to_link[k] = 8;
-    int j = ax >> 1;
-    ancilla_dir[k] = j | 4;
-    ancilla_y_vel[k] = kShootBow_Yvel[j];
-    ancilla_x_vel[k] = kShootBow_Xvel[j];
-    Ancilla_SetXY(k, xcoord + kShootBow_X[j], ycoord + 8 +  kShootBow_Y[j]);
-  }
-  return k;
-}
-
-void AncillaAdd_BunnyPoof(uint8 a, uint8 y) {  // 899102
-  int k = Ancilla_AddAncilla(a, y);
-  if (k >= 0) {
-    link_visibility_status = 0xc;
-    ancilla_step[k] = 0;
-    if (!link_is_bunny_mirror)
-      sound_effect_1 = Link_CalculateSfxPan() | 0x14;
-    else
-      sound_effect_1 = Link_CalculateSfxPan() | 0x15;
-
-    ancilla_item_to_link[k] = 0;
-    ancilla_aux_timer[k] = 7;
-    Ancilla_SetXY(k, link_x_coord, link_y_coord + 4);
-  }
-}
-
-void AncillaAdd_CapePoof(uint8 a, uint8 y) {  // 89912c
-  int k = Ancilla_AddAncilla(a, y);
-  if (k >= 0) {
-    ancilla_step[k] = 1;
-    link_is_transforming = 1;
-    link_cant_change_direction |= 1;
-    link_direction = 0;
-    link_direction_last = 0;
-    ancilla_item_to_link[k] = 0;
-    ancilla_aux_timer[k] = 7;
-    Ancilla_SetXY(k, link_x_coord, link_y_coord + 4);
-  }
-}
-
-void AncillaAdd_DwarfPoof(uint8 ain, uint8 yin) {  // 89915f
-  int k = Ancilla_AddAncilla(ain, yin);
-  if (k < 0)
-    return;
-  if (follower_indicator == 8)
-    sound_effect_1 = Link_CalculateSfxPan() | 0x14;
-  else
-    sound_effect_1 = Link_CalculateSfxPan() | 0x15;
-
-  ancilla_item_to_link[k] = 0;
-  ancilla_step[k] = 0;
-  ancilla_aux_timer[k] = 7;
-  tagalong_var5 = 1;
-  int j = tagalong_var2;
-  int x = tagalong_x_lo[j] | tagalong_x_hi[j] << 8;
-  int y = tagalong_y_lo[j] | tagalong_y_hi[j] << 8;
-  Ancilla_SetXY(k, x, y + 4);
-}
-
-void AncillaAdd_BushPoof(uint16 x, uint16 y) {  // 8991c3
-  if (!(link_item_in_hand & 0x40))
-    return;
-  int k = Ancilla_AddAncilla(0x3f, 4);
-  if (k >= 0) {
-    ancilla_item_to_link[k] = 0;
-    ancilla_timer[k] = 7;
-    sound_effect_1 = Link_CalculateSfxPan() | 21;
-    Ancilla_SetXY(k, x, y - 2);
-  }
-}
-
-void AncillaAdd_EtherSpell(uint8 a, uint8 y) {  // 8991fc
-  int k = Ancilla_AddAncilla(a, y);
-  if (k >= 0) {
-    ancilla_item_to_link[k] = 0;
-    ancilla_arr25[k] = 0;
-    ancilla_step[k] = 0;
-    flag_custom_spell_anim_active = 1;
-    ancilla_aux_timer[k] = 2;
-    ancilla_arr3[k] = 3;
-    ancilla_y_vel[k] = 127;
-    ether_var2 = 40;
-    load_chr_halfslot_even_odd = 9;
-    ether_var1 = 0x40;
-    sound_effect_2 = Link_CalculateSfxPan() | 0x26;
-    for(int i = 0; i < 8; i++)
-      ether_arr1[i] = i * 8;
-    ether_y = link_y_coord;
-    uint16 y = BG2VOFS_copy2 - 16;
-    ether_y_adjusted = y & 0xf0;
-    ether_x = link_x_coord;
-    ether_x2 = ether_x + 8;
-    ether_y2 = link_y_coord - 16;
-    ether_y3 = ether_y2 + 0x24;
-    Ancilla_SetXY(k, link_x_coord, y);
-  }
-}
-
-void AncillaAdd_VictorySpin() {  // 8992ac
-  if ((link_sword_type + 1 & 0xfe) != 0) {
-    int k = Ancilla_AddAncilla(0x3b, 0);
-    if (k >= 0) {
-      ancilla_item_to_link[k] = 0;
-      ancilla_arr3[k] = 1;
-      ancilla_aux_timer[k] = 34;
-    }
-  }
-}
-
-void AncillaAdd_MagicPowder(uint8 a, uint8 y) {  // 8992f0
-  static const int8 kMagicPower_X[4] = {-2, -2, -12, 12};
-  static const int8 kMagicPower_Y[4] = {0, 20, 16, 16};
-  static const int8 kMagicPower_X1[4] = {10, 10, -8, 28};
-  static const int8 kMagicPower_Y1[4] = {1, 40, 22, 22};
-
-  int k = Ancilla_AddAncilla(a, y);
-  if (k >= 0) {
-    ancilla_item_to_link[k] = 0;
-    ancilla_z[k] = 0;
-    ancilla_aux_timer[k] = 1;
-    link_dma_var5 = 80;
-    int j = link_direction_facing >> 1;
-    ancilla_dir[k] = j;
-    ancilla_arr25[k] = kMagicPowder_Tab0[j * 10];
-    Ancilla_SetXY(k, link_x_coord + kMagicPower_X[j], link_y_coord + kMagicPower_Y[j]);
-    Ancilla_CheckTileCollision(k);
-    byte_7E0333 = ancilla_tile_attr[k];
-    if (current_item_active == 9) {
-      ancilla_type[k] = 0;
-      return;
-    }
-    sound_effect_1 = Link_CalculateSfxPan() | 0xd;
-    Ancilla_SetXY(k, link_x_coord + kMagicPower_X1[j], link_y_coord + kMagicPower_Y1[j]);
-  }
-}
-
-void AncillaAdd_WallTapSpark(uint8 a, uint8 y) {  // 899395
-  static const int8 kWallTapSpark_X[4] = {11, 10, -12, 29};
-  static const int8 kWallTapSpark_Y[4] = {-4, 32, 17, 17};
-  int k = Ancilla_AddAncilla(a, y);
-  if (k >= 0) {
-    ancilla_item_to_link[k] = 5;
-    ancilla_aux_timer[k] = 1;
-    int i = link_direction_facing >> 1;
-    Ancilla_SetXY(k, link_x_coord + kWallTapSpark_X[i], link_y_coord + kWallTapSpark_Y[i]);
-  }
-}
-
-void AncillaAdd_SwordSwingSparkle(uint8 a, uint8 y) {  // 8993c2
-  int k = Ancilla_AddAncilla(a, y);
-  if (k >= 0) {
-    ancilla_item_to_link[k] = 0;
-    ancilla_aux_timer[k] = 1;
-    ancilla_dir[k] = link_direction_facing >> 1;
-    Ancilla_SetXY(k, link_x_coord, link_y_coord);
-  }
-}
-
-void AncillaAdd_DashTremor(uint8 a, uint8 y) {  // 8993f3
-  static const uint8 kAddDashTremor_Dir[4] = {2, 2, 0, 0};
-  static const uint8 kAddDashTremor_Tab[2] = {0x80, 0x78};
-  if (AncillaAdd_CheckForPresence(a))
-    return;
-  int k = Ancilla_AddAncilla(a, y);
-  if (k >= 0) {
-    ancilla_item_to_link[k] = 16;
-    ancilla_L[k] = 0;
-    int j = link_direction_facing >> 1;
-    ancilla_dir[k] = j = kAddDashTremor_Dir[j];
-    uint8 y = link_y_coord - BG2VOFS_copy2;
-    uint8 x = link_x_coord - BG2HOFS_copy2;
-    Ancilla_SetY(k, (j ? y : x) < kAddDashTremor_Tab[j >> 1] ? 3 : -3);
-  }
-}
-
-void AncillaAdd_BoomerangWallClink(int k) {  // 899478
-  static const int8 kBoomerangWallHit_X[8] = {8, 8, 0, 10, 12, 8, 4, 0};
-  static const int8 kBoomerangWallHit_Y[8] = {0, 8, 8, 8, 4, 8, 12, 8};
-  static const uint8 kBoomerangWallHit_Tab0[16] = {0, 6, 4, 0, 2, 10, 12, 0, 0, 8, 14, 0, 0, 0, 0, 0};
-  boomerang_temp_x = Ancilla_GetX(k);
-  boomerang_temp_y = Ancilla_GetY(k);
-  k = Ancilla_AddAncilla(6, 1);
-  if (k >= 0) {
-    ancilla_item_to_link[k] = 0;
-    ancilla_arr3[k] = 1;
-    int j = kBoomerangWallHit_Tab0[hookshot_effect_index] >> 1;
-    Ancilla_SetXY(k, boomerang_temp_x + kBoomerangWallHit_X[j], boomerang_temp_y + kBoomerangWallHit_Y[j]);
-  }
-}
-
-void AncillaAdd_HookshotWallClink(int kin, uint8 a, uint8 y) {  // 8994c6
-  static const int8 kHookshotWallHit_X[8] = {8, 8, 0, 10, 12, 8, 4, 0};
-  static const int8 kHookshotWallHit_Y[8] = {0, 8, 8, 8, 4, 8, 12, 8};
-  int k = Ancilla_AddAncilla(a, y);
-  if (k >= 0) {
-    ancilla_item_to_link[k] = 0;
-    ancilla_arr3[k] = 1;
-    int j = ancilla_dir[kin];
-    Ancilla_SetXY(k, Ancilla_GetX(kin) + kHookshotWallHit_X[j], Ancilla_GetY(kin) + kHookshotWallHit_Y[j]);
-  }
-}
-
-void AncillaAdd_Duck_take_off(uint8 a, uint8 y) {  // 8994fe
-  if (AncillaAdd_CheckForPresence(a))
-    return;
-  int k = Ancilla_AddAncilla(a, y);
-  if (k >= 0) {
-    ancilla_timer[k] = 0x78;
-    ancilla_L[k] = 0;
-    ancilla_z_vel[k] = 0;
-    ancilla_z[k] = 0;
-    ancilla_step[k] = 0;
-    AddBirdCommon(k);
-  }
-}
-
-void AddBirdTravelSomething(uint8 a, uint8 y) {  // 89951d
-  if (AncillaAdd_CheckForPresence(a))
-    return;
-  int k = Ancilla_AddAncilla(a, y);
-  if (k >= 0) {
-    link_player_handler_state = 0;
-    link_speed_setting = 0;
-    button_mask_b_y &= ~0x81;
-    button_b_frames = 0;
-    link_delay_timer_spin_attack = 0;
-    link_cant_change_direction &= ~1;
-    ancilla_L[k] = 1;
-
-    if (enhanced_features0 & kFeatures0_ExtendScreen64) {
-      // todo: tune these better so the angle of attack is better
-      ancilla_z_vel[k] = 58;
-      ancilla_z[k] = -105;
-    } else {
-      ancilla_z_vel[k] = 40;
-      ancilla_z[k] = -51;
-    }
-    ancilla_step[k] = 2;
-    AddBirdCommon(k);
-  }
-}
-
-void AncillaAdd_QuakeSpell(uint8 a, uint8 y) {  // 899589
-  int k = Ancilla_AddAncilla(a, y);
-  if (k >= 0) {
-    ancilla_step[k] = 0;
-    ancilla_item_to_link[k] = 0;
-    load_chr_halfslot_even_odd = 13;
-    sound_effect_1 = 0x35;
-    for(int i = 0; i < 5; i++)
-      quake_arr2[i] = 0;
-    quake_var5 = 0;
-    for(int i = 0; i < 5; i++)
-      quake_arr1[i] = 1;
-    flag_custom_spell_anim_active = 1;
-    ancilla_timer[k] = 2;
-    quake_var1 = link_y_coord + 26;
-    quake_var2 = link_x_coord + 8;
-    quake_var3 = 3;
-  }
-}
-
-void AncillaAdd_SpinAttackInitSpark(uint8 a, uint8 x, uint8 y) {  // 89960b
-  static const int8 kSpinAttackStartSparkle_Y[4] = {32, -8, 10, 20};
-  static const int8 kSpinAttackStartSparkle_X[4] = {10, 7, 28, -10};
-
-  int k = Ancilla_AddAncilla(a, y);
-  for (int i = 4; i >= 0; i--) {
-    if (ancilla_type[i] == 0x31)
-      ancilla_type[i] = 0;
-  }
-  ancilla_item_to_link[k] = 0;
-  ancilla_step[k] = x;
-  ancilla_timer[k] = 4;
-  ancilla_aux_timer[k] = 3;
-  int j = link_direction_facing >> 1;
-  Ancilla_SetXY(k,
-      link_x_coord + kSpinAttackStartSparkle_X[j],
-      link_y_coord + kSpinAttackStartSparkle_Y[j]);
-}
-
-void AncillaAdd_BlastWall() {  // 899692
-  static const int8 kBlastWall_Tab3[4] = {-16, 16, 0, 0};
-  static const int8 kBlastWall_Tab4[4] = {0, 0, -16, 16};
-  static const int8 kBlastWall_Tab5[16] = {-8, 0, -8, 16, 16, 0, 16, 16, 0, -8, 16, -8, 0, 16, 16, 16};
-
-  ancilla_type[0] = 0x33;
-  ancilla_type[1] = 0x33;
-  ancilla_type[2] = 0;
-  ancilla_type[3] = 0;
-  ancilla_type[4] = 0;
-  ancilla_type[5] = 0;
-
-  ancilla_item_to_link[0] = 0;
-  flag_is_ancilla_to_pick_up = 0;
-  link_state_bits = 0;
-  link_cant_change_direction = 0;
-  ancilla_K[0] = 0;
-  ancilla_floor[0] = link_is_on_lower_level;
-  ancilla_floor[1] = link_is_on_lower_level;
-  ancilla_floor2[0] = link_is_on_lower_level_mirror;
-  blastwall_var1 = 0;
-  blastwall_var6[1] = 0;
-  blastwall_var5[1] = 0;
-  blastwall_var4 = 0;
-  blastwall_var5[0] = 1;
-  flag_custom_spell_anim_active = 1;
-  blastwall_var6[0] = 3;
-  int j = blastwall_var7;
-  blastwall_var8 += kBlastWall_Tab3[j];
-  blastwall_var9 += kBlastWall_Tab4[j];
-  j = (j < 4) ? 4 : 0;
-  for (int k = 3; k >= 0; k--, j++) {
-    blastwall_var10[k] = blastwall_var8 + kBlastWall_Tab5[j * 2 + 0];
-    blastwall_var11[k] = blastwall_var9 + kBlastWall_Tab5[j * 2 + 1];
-    uint16 x = blastwall_var11[k] - BG2HOFS_copy2;
-    if (x < 256)
-      sound_effect_1 = kBombos_Sfx[x >> 5] | 0xc;
-  }
-  // In dark world forest castle hole outside door
-
-}
-
-void AncillaAdd_SwordChargeSparkle(int k) {  // 899757
-  int j;
-  for (j = 9; ancilla_type[j] != 0; ) {
-    if (--j < 0)
-      return;
-  }
-  ancilla_type[j] = 60;
-  ancilla_floor[j] = link_is_on_lower_level;
-  ancilla_item_to_link[j] = 0;
-  ancilla_timer[j] = 4;
-
-  uint8 rand = GetRandomNumber();
-
-  uint8 z = ancilla_z[k];
-  if (z >= 0xF8)
-    z = 0;
-  Ancilla_SetXY(j, Ancilla_GetX(k) + 2 + (rand >> 5), Ancilla_GetY(k) - 2 - z + (rand & 0xf));
-}
-
-void AncillaAdd_SilverArrowSparkle(int kin) {  // 8997de
-  static const int8 kSilverArrowSparkle_X[4] = {-4, -4, 0, 2};
-  static const int8 kSilverArrowSparkle_Y[4] = {0, 2, -4, -4};
-  int k = Ancilla_AllocHigh();
-  if (k >= 0) {
-    ancilla_type[k] = 0x3c;
-    ancilla_item_to_link[k] = 0;
-    ancilla_timer[k] = 4;
-    ancilla_floor[k] = link_is_on_lower_level;
-    int m = GetRandomNumber();
-    int j = ancilla_dir[kin] & 3;
-    Ancilla_SetXY(k,
-      Ancilla_GetX(kin) + kSilverArrowSparkle_X[j] + (m >> 4 & 7),
-      Ancilla_GetY(kin) + kSilverArrowSparkle_Y[j] + (m & 7));
-  }
-}
-
-void AncillaAdd_IceRodShot(uint8 a, uint8 y) {  // 899863
-  static const int8 kIceRod_X[4] = {0, 0, -20, 20};
-  static const int8 kIceRod_Y[4] = {-16, 24, 8, 8};
-  static const int8 kIceRod_Xvel[4] = {0, 0, -48, 48};
-  static const int8 kIceRod_Yvel[4] = {-48, 48, 0, 0};
-
-  int k = Ancilla_AddAncilla(a, y);
-  if (k < 0) {
-    Refund_Magic(0);
-    return;
-  }
-  sound_effect_1 = Link_CalculateSfxPan() | 15;
-  ancilla_step[k] = 0;
-  ancilla_arr25[k] = 0;
-  ancilla_item_to_link[k] = 255;
-  ancilla_L[k] = 1;
-  ancilla_aux_timer[k] = 3;
-  ancilla_arr3[k] = 6;
-  int j = link_direction_facing >> 1;
-  ancilla_dir[k] = j;
-  ancilla_y_vel[k] = kIceRod_Yvel[j];
-  ancilla_x_vel[k] = kIceRod_Xvel[j];
-
-  if (Ancilla_CheckInitialTile_A(k) < 0) {
-    uint16 x = link_x_coord + kIceRod_X[j];
-    uint16 y = link_y_coord + kIceRod_Y[j];
-
-    if (((x - BG2HOFS_copy2) | (y - BG2VOFS_copy2)) & 0xff00) {
-      ancilla_type[k] = 0;
-      return;
-    }
-    Ancilla_SetXY(k, x, y);
-  } else {
-    ancilla_type[k] = 0x11;
-    ancilla_numspr[k] = kAncilla_Pflags[0x11];
-    ancilla_item_to_link[k] = 0;
-    ancilla_aux_timer[k] = 4;
-  }
-}
-
-bool AncillaAdd_Splash(uint8 a, uint8 y) {  // 8998fc
-  int k = Ancilla_AddAncilla(a, y);
-  if (k >= 0) {
-    sound_effect_1 = Link_CalculateSfxPan() | 0x24;
-    ancilla_item_to_link[k] = 0;
-    ancilla_aux_timer[k] = 2;
-    if (player_is_indoors && !link_is_in_deep_water)
-      link_is_on_lower_level = 0;
-    Ancilla_SetXY(k, link_x_coord - 11, link_y_coord + 8);
-  }
-  return k < 0;
-}
-
-void AncillaAdd_GraveStone(uint8 ain, uint8 yin) {  // 8999e9
-  static const uint16 kMoveGravestone_Y[8] = {0x550, 0x540, 0x530, 0x520, 0x500, 0x4e0, 0x4c0, 0x4b0};
-  static const uint16 kMoveGravestone_X[15] = {0x8b0, 0x8f0, 0x910, 0x950, 0x970, 0x9a0, 0x850, 0x870, 0x8b0, 0x8f0, 0x920, 0x950, 0x880, 0x990, 0x840};
-  static const uint16 kMoveGravestone_Y1[15] = {0x540, 0x530, 0x530, 0x530, 0x520, 0x520, 0x510, 0x510, 0x4f0, 0x4f0, 0x4f0, 0x4f0, 0x4d0, 0x4b0, 0x4a0};
-  static const uint16 kMoveGravestone_X1[15] = {0x8b0, 0x8f0, 0x910, 0x950, 0x970, 0x9a0, 0x850, 0x870, 0x8b0, 0x8f0, 0x920, 0x950, 0x880, 0x990, 0x840};
-  static const uint16 kMoveGravestone_Pos[15] = {0xa16, 0x99e, 0x9a2, 0x9aa, 0x92e, 0x934, 0x88a, 0x88e, 0x796, 0x79e, 0x7a4, 0x7aa, 0x690, 0x5b2, 0x508};
-  static const uint8 kMoveGravestone_Ctr[15] = {0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x38, 0x58};
-  static const uint8 kMoveGravestone_Idx[9] = {0, 1, 4, 6, 8, 12, 13, 14, 15};
-
-  int k = Ancilla_AddAncilla(ain, yin);
-  if (k < 0)
-    return;
-  int t = ((link_y_coord & 0xf) < 7 ? link_y_coord : link_y_coord + 16) & ~0xf;
-
-  int i = 7;
-  while (kMoveGravestone_Y[i] != t) {
-    if (--i < 0) {
-      ancilla_type[k] = 0;
-      return;
-    }
-  }
-
-  int j = kMoveGravestone_Idx[i];
-  int end = kMoveGravestone_Idx[i + 1];
-  do {
-    int x = kMoveGravestone_X[j];
-    if (x < link_x_coord && (uint16)(x + 15) >= link_x_coord) {
-      if (j == 13 ? !link_is_running : link_is_running)
-        break;
-
-      int pos = kMoveGravestone_Pos[j];
-      big_rock_starting_address = pos;
-      door_open_closed_counter = kMoveGravestone_Ctr[j];
-      if (door_open_closed_counter == 0x58) {
-        sound_effect_2 = Link_CalculateSfxPan() | 0x1b;
-      } else if (door_open_closed_counter == 0x38) {
-        save_ow_event_info[BYTE(overworld_screen_index)] |= 0x20;
-        sound_effect_2 = Link_CalculateSfxPan() | 0x1b;
-      }
-
-      ((uint8 *)door_debris_y)[k] = (pos - 0x80);
-      ((uint8 *)door_debris_x)[k] = (pos - 0x80) >> 8;
-
-      Overworld_DoMapUpdate32x32_B();
-
-      if ((sound_effect_2 & 0x3f) != 0x1b)
-        sound_effect_1 = Link_CalculateSfxPan() | 0x22;
-
-      int yy = kMoveGravestone_Y1[j];
-      int xx = kMoveGravestone_X1[j];
-      bitmask_of_dragstate = 4;
-      link_something_with_hookshot = 1;
-      ancilla_A[k] = (yy - 18);
-      ancilla_B[k] = (yy - 18) >> 8;
-      Ancilla_SetXY(k, xx, yy - 2);
-      return;
-    }
-  } while (++j != end);
-  ancilla_type[k] = 0;
-}
-
-void AncillaAdd_WaterfallSplash() {  // 899b68
-  if (AncillaAdd_CheckForPresence(0x41))
-    return;
-  int k = Ancilla_AddAncilla(0x41, 4);
-  if (k >= 0) {
-    ancilla_timer[k] = 2;
-    ancilla_item_to_link[k] = 0;
-  }
-}
-
-void AncillaAdd_GTCutscene() {  // 899b83
-  if (link_state_bits & 0x80 | link_auxiliary_state ||
-     (link_has_crystals & 0x7f) != 0x7f ||
-      save_ow_event_info[0x43] & 0x20)
-    return;
-
-  Ancilla_TerminateSparkleObjects();
-
-  if (AncillaAdd_CheckForPresence(0x43))
-    return;
-
-  int k = Ancilla_AddAncilla(0x43, 4);
-  if (k < 0)
-    return;
-
-  for (int i = 15; i >= 0; i--) {
-    if (sprite_type[i] == 0x37)
-      sprite_state[i] = 0;
-  }
-
-  for (int i = 0x17; i >= 0; i--)
-    breaktowerseal_sparkle_var1[i] = 0xff;
-  DecodeAnimatedSpriteTile_variable(0x28);
-  palette_sp6r_indoors = 4;
-  overworld_palette_aux_or_main = 0x200;
-  Palette_Load_SpriteEnvironment_Dungeon();
-  flag_update_cgram_in_nmi++;
-  flag_is_link_immobilized = 1;
-  ancilla_y_subpixel[k] = 0;
-  ancilla_x_subpixel[k] = 0;
-  ancilla_step[k] = 0;
-  breaktowerseal_var5 = 240;
-  breaktowerseal_var4 = 0;
-
-  breaktowerseal_var3[0] = 0;
-
-  breaktowerseal_var3[1] = 10;
-  breaktowerseal_var3[2] = 22;
-  breaktowerseal_var3[3] = 32;
-  breaktowerseal_var3[4] = 42;
-  breaktowerseal_var3[5] = 54;
-
-  Ancilla_SetXY(k, link_x_coord, link_y_coord - 16);
-}
-
-int AncillaAdd_DoorDebris() {  // 899c38
-  int k = Ancilla_AddAncilla(8, 1);
-  if (k >= 0) {
-    ancilla_arr25[k] = 0;
-    ancilla_arr26[k] = 7;
-  }
-  return k;
-}
-
-void FireRodShot_BecomeSkullWoodsFire(int k) {  // 899c4f
-  if (player_is_indoors || !(BYTE(overworld_screen_index) & 0x40))
-    return;
-
-  ancilla_type[0] = 0x34;
-  ancilla_type[1] = 0;
-  ancilla_type[2] = 0;
-  ancilla_type[3] = 0;
-  ancilla_type[4] = 0;
-  ancilla_type[5] = 0;
-  flag_for_boomerang_in_place = 0;
-  ancilla_numspr[0] = kAncilla_Pflags[0x34];
-  skullwoodsfire_var0[0] = 253;
-  skullwoodsfire_var0[1] = 254;
-  skullwoodsfire_var0[2] = 255;
-  skullwoodsfire_var0[3] = 0;
-  skullwoodsfire_var4 = 0;
-  skullwoodsfire_var5[0] = 5;
-  skullwoodsfire_var5[1] = 5;
-  skullwoodsfire_var5[2] = 5;
-  skullwoodsfire_var5[3] = 5;
-  ancilla_aux_timer[0] = 5;
-  skullwoodsfire_var9 = 0x100;
-  skullwoodsfire_var10 = 0x100;
-  skullwoodsfire_var11 = 0x98;
-  skullwoodsfire_var12 = 0x98;
-
-  trigger_special_entrance = 2;
-  subsubmodule_index = 0;
-  BYTE(R16) = 0;
-  ancilla_floor[0] = link_is_on_lower_level;
-  ancilla_floor2[0] = link_is_on_lower_level_mirror;
-  ancilla_item_to_link[0] = 0;
-  ancilla_step[0] = 0;
-
-}
-
-int Ancilla_AddAncilla(uint8 a, uint8 y) {  // 899ce2
-  int k = Ancilla_AllocInit(a, y);
-  if (k >= 0) {
-    ancilla_type[k] = a;
-    ancilla_floor[k] = link_is_on_lower_level;
-    ancilla_floor2[k] = link_is_on_lower_level_mirror;
-    ancilla_y_vel[k] = 0;
-    ancilla_x_vel[k] = 0;
-    ancilla_objprio[k] = 0;
-    ancilla_U[k] = 0;
-    ancilla_numspr[k] = kAncilla_Pflags[a];
-  }
-  return k;
-}
-
-bool AncillaAdd_CheckForPresence(uint8 a) {  // 899d20
-  for (int k = 5; k >= 0; k--) {
-    if (ancilla_type[k] == a)
-      return true;
-  }
-  return false;
-}
-
-int AncillaAdd_ArrowFindSlot(uint8 type, uint8 ay) {  // 899d36
-  int k, n = 0;
-  for (k = 4; k >= 0; k--) {
-    if (ancilla_type[k] == 10)
-      n++;
-  }
-  if (n != ay + 1) {
-    for (k = 4; k >= 0; k--) {
-      if (ancilla_type[k] == 0)
-        break;
-    }
-  } else {
-    do {
-      if (sign8(--ancilla_alloc_rotate))
-        ancilla_alloc_rotate = 4;
-      k = ancilla_alloc_rotate;
-    } while (ancilla_type[k] != 10);
-  }
-  if (k >= 0) {
-    ancilla_type[k] = type;
-    ancilla_floor[k] = link_is_on_lower_level;
-    ancilla_floor2[k] = link_is_on_lower_level_mirror;
-    ancilla_y_vel[k] = 0;
-    ancilla_x_vel[k] = 0;
-    ancilla_objprio[k] = 0;
-    ancilla_U[k] = 0;
-    ancilla_numspr[k] = kAncilla_Pflags[type];
-  }
-  return k;
-}
-
-int Ancilla_CheckInitialTile_A(int k) {  // 899dd3
-  static const int8 kAncilla_Yoffs_Hb[12] = {8, 0, -8, 8, 16, 24, 8, 8, 8, 8, 8, 8};
-  static const int8 kAncilla_Xoffs_Hb[12] = {0, 0, 0, 0, 0, 0, 0, -8, -16, 0, 8, 16};
-  int j = ancilla_dir[k] * 3;
-  int i;
-  for (i = 2; i >= 0; i--, j++) {
-    uint16 x = link_x_coord + kAncilla_Xoffs_Hb[j];
-    uint16 y = link_y_coord + kAncilla_Yoffs_Hb[j];
-    Ancilla_SetXY(k, x, y);
-    if (Ancilla_CheckTileCollision(k))
-      break;
-  }
-  return i;
-}
-
-bool Ancilla_CheckInitialTileCollision_Class2(int k) {  // 899e44
-  static const int16 kAncilla_InitialTileColl_Y[9] = {15, 16, 28, 24, 12, 12, 12, 12, 8};
-  static const int16 kAncilla_InitialTileColl_X[9] = {8, 8, 8, 8, -1, 0, 17, 16, 0x4b8b}; // wtf
-  int j = ancilla_dir[k] * 2;
-  for (int n = 2; n >= 0; n--, j++) {
-    Ancilla_SetXY(k, link_x_coord + kAncilla_InitialTileColl_X[j],
-                     link_y_coord + kAncilla_InitialTileColl_Y[j]);
-    if (Ancilla_CheckTileCollision_Class2(k))
-      return true;
-  }
-  return false;
-}
-
-uint8 Ancilla_TerminateSelectInteractives(uint8 y) {  // 89ac6b
-  int i = 5;
-
-  do {
-    if (ancilla_type[i] == 0x3e) {
-      y = i;
-    }
-    else if (ancilla_type[i] == 0x2c) {
-      dung_flag_somaria_block_switch = 0;
-      if (bitmask_of_dragstate & 0x80) {
-        bitmask_of_dragstate = 0;
-        link_speed_setting = 0;
-      }
-    }
-
-    if (sign8(link_state_bits)) {
-      if (i + 1 != flag_is_ancilla_to_pick_up)
-        ancilla_type[i] = 0;
-    }
-    else {
-      if (i + 1 == flag_is_ancilla_to_pick_up)
-        flag_is_ancilla_to_pick_up = 0;
-      ancilla_type[i] = 0;
-    }
-  } while (--i >= 0);
-
-  if (link_position_mode & 0x10) {
-    link_incapacitated_timer = 0;
-    link_position_mode = 0;
-  }
-  flute_countdown = 0;
-  tagalong_event_flags = 0;
-  byte_7E02F3 = 0;
-  flag_for_boomerang_in_place = 0;
-  is_archer_or_shovel_game = 0;
-  link_disable_sprite_damage = 0;
-  byte_7E03FD = 0;
-  link_electrocute_on_touch = 0;
-  if (link_player_handler_state == 19) {
-    link_player_handler_state = 0;
-    button_mask_b_y &= ~0x40;
-    link_cant_change_direction &= ~1;
-    link_position_mode &= ~4;
-    related_to_hookshot = 0;
-  }
-  return y;
-}
-
-void Ancilla_SetXY(int k, uint16 x, uint16 y) {  // 89ad06
-  Ancilla_SetX(k, x);
-  Ancilla_SetY(k, y);
-}
-
-void AncillaAdd_ExplodingSomariaBlock(int k) {  // 89ad30
-  ancilla_type[k] = 0x2e;
-  ancilla_numspr[k] = kAncilla_Pflags[0x2e];
-  ancilla_aux_timer[k] = 3;
-  ancilla_step[k] = 0;
-  ancilla_item_to_link[k] = 0;
-  ancilla_arr3[k] = 0;
-  ancilla_arr1[k] = 0;
-  ancilla_R[k] = 0;
-  ancilla_objprio[k] = 0;
-  dung_flag_somaria_block_switch = 0;
-  sound_effect_2 = Ancilla_CalculateSfxPan(k) | 1;
-}
-
-bool Ancilla_AddRupees(int k) {  // 89ad6c
-  static const uint8 kGiveRupeeGift_Tab[5] = {1, 5, 20, 100, 50};
-  uint8 a = ancilla_item_to_link[k];
-  if (a == 0x34 || a == 0x35 || a == 0x36) {
-    link_rupees_goal += kGiveRupeeGift_Tab[a - 0x34];
-  } else if (a == 0x40 || a == 0x41) {
-    link_rupees_goal += kGiveRupeeGift_Tab[a - 0x40 + 3];
-  } else if (a == 0x46) {
-    link_rupees_goal += 300;
-  } else if (a == 0x47) {
-    link_rupees_goal += 20;
-  } else {
-    return false;
-  }
-  return true;
-}
-
-void DashDust_Motive(int k) {  // 89adf4
-  static const uint8 kMotiveDashDust_Draw_Char[3] = {0xa9, 0xcf, 0xdf};
-  if (!ancilla_timer[k]) {
-    ancilla_timer[k] = 3;
-    if (++ancilla_item_to_link[k] == 3) {
-      ancilla_type[k] = 0;
-      return;
-    }
-  }
-  if (link_direction_facing == 2)
-    Oam_AllocateFromRegionB(4);
-  Point16U info;
-  Ancilla_PrepOamCoord(k, &info);
-  Ancilla_SetOam(GetOamCurPtr(), info.x, info.y,
-                 kMotiveDashDust_Draw_Char[ancilla_item_to_link[k]], 4 | HIBYTE(oam_priority_value), 0);
-}
-
-uint8 Ancilla_CalculateSfxPan(int k) {  // 8dbb5e
-  return CalculateSfxPan(Ancilla_GetX(k));
-}
-
-int Ancilla_AllocInit(uint8 type, uint8 limit) {  // 8ff577
-  // snes bug: R14 is used in tile detection already
-  // unless this is here it the memcmp will fail when entering/leaving a water through steps quickly
-  if (g_ram[kRam_BugsFixed] >= kBugFix_PolyRenderer)
-    BYTE(R14) = limit + 1;
-
-  int n = 0;
-  for (int i = 0; i < 5; i++) {
-    if (ancilla_type[i] == type)
-      n++;
-  }
-  if (limit + 1 == n)
-    return -1;
-
-  // Try to reuse an empty ancilla slot
-  for (int j = (type == 7 || type == 8) ? limit : 4; j >= 0; j--) {
-    if (ancilla_type[j] == 0)
-      return j;
-  }
-  int k = ancilla_alloc_rotate;
-  do {
-    if (--k < 0)
-      k = limit;
-    uint8 old_type = ancilla_type[k];
-    // reuse slots for sparkles or arrows in wall
-    if (old_type == 0x3c || old_type == 0x13 || old_type == 0xa) {
-      ancilla_alloc_rotate = k;
-      return k;
-    }
-  } while (k != 0);
-  ancilla_alloc_rotate = 0;
-  return -1;
-}
-
-void AddSwordBeam(uint8 y) {  // 8ff67b
-  static const int8 kSwordBeam_X[4] = {-8, -10, -22, 4};
-  static const int8 kSwordBeam_Y[4] = {-24, 8, -6, -6};
-  static const int8 kSwordBeam_S[4] = {-8, -8, -8, 8};
-  static const uint8 kSwordBeam_Tab[16] = {0x21, 0x1d, 0x19, 0x15, 3, 0x3e, 0x3a, 0x36, 0x12, 0xe, 0xa, 6, 0x31, 0x2d, 0x29, 0x25};
-  static const int8 kSwordBeam_Yvel[4] = {-64, 64, 0, 0};
-  static const int8 kSwordBeam_Xvel[4] = {0, 0, -64, 64};
-
-  int k = Ancilla_AddAncilla(0xc, y);
-  if (k < 0)
-    return;
-  int j = link_direction_facing * 2;
-  swordbeam_arr[0] = kSwordBeam_Tab[j + 0];
-  swordbeam_arr[1] = kSwordBeam_Tab[j + 1];
-  swordbeam_arr[2] = kSwordBeam_Tab[j + 2];
-  swordbeam_arr[3] = swordbeam_var1 = kSwordBeam_Tab[j + 3];
-  ancilla_aux_timer[k] = 2;
-  ancilla_item_to_link[k] = 0x4c;
-  ancilla_arr3[k] = 8;
-  ancilla_step[k] = 0;
-  ancilla_L[k] = 0;
-  ancilla_G[k] = 0;
-  ancilla_arr1[k] = 0;
-  swordbeam_var2 = 14;
-  j = link_direction_facing >> 1;
-  ancilla_dir[k] = j;
-  ancilla_y_vel[k] = kSwordBeam_Yvel[j];
-  ancilla_x_vel[k] = kSwordBeam_Xvel[j];
-  ancilla_S[k] = kSwordBeam_S[j];
-
-  swordbeam_temp_y = link_y_coord + 12;
-  swordbeam_temp_x = link_x_coord + 8;
-
-  if (Ancilla_CheckInitialTile_A(k) >= 0) {
-    Ancilla_SetXY(k, swordbeam_temp_x + kSwordBeam_X[j], swordbeam_temp_y + kSwordBeam_Y[j]);
-    sound_effect_2 = 1 | Ancilla_CalculateSfxPan(k);
-    ancilla_type[k] = 4;
-    ancilla_timer[k] = 7;
-    ancilla_numspr[k] = 16;
-  }
-}
-
-void AncillaSpawn_SwordChargeSparkle() {  // 8ff979
-  static const uint8 kSwordChargeSparkle_A[4] = {0, 0, 7, 7};
-  static const uint8 kSwordChargeSparkle_B[4] = {0x70, 0x70, 0, 0};
-  static const uint8 kSwordChargeSparkle_X[4] = {0, 3, 4, 5};
-  static const uint8 kSwordChargeSparkle_Y[4] = {5, 12, 8, 8};
-  int k = Ancilla_AllocHigh();
-  if (k < 0)
-    return;
-  ancilla_type[k] = 0x3c;
-  ancilla_item_to_link[k] = 0;
-  ancilla_timer[k] = 4;
-  ancilla_floor[k] = link_is_on_lower_level;
-  int j = link_direction_facing >> 1;
-  int8 x = 0, y = 0;
-  uint8 m0 = kSwordChargeSparkle_A[j];
-  if (!m0) {
-    y = link_spin_attack_step_counter >> 2;
-    if (j == 0)
-      y = -y;
-  }
-  uint8 m1 = kSwordChargeSparkle_B[j];
-  if (!m1) {
-    x = link_spin_attack_step_counter >> 2;
-    if (j == 2)
-      x = -x;
-  }
-  uint8 r = GetRandomNumber();
-  Ancilla_SetXY(k,
-    link_x_coord + x + kSwordChargeSparkle_X[j] + ((r & m1) >> 4),
-    link_y_coord + y + kSwordChargeSparkle_Y[j] + (r & m0));
-}
-
-int DashTremor_TwiddleOffset(int k) {  // 8ffafe
-  int j = ancilla_dir[k];
-  uint16 y = -Ancilla_GetY(k);
-  Ancilla_SetY(k, y);
-  if (player_is_indoors)
-    return y;
-  if (j == 2) {
-    uint16 start = ow_scroll_vars0.ystart + 1;
-    uint16 end = ow_scroll_vars0.yend - 1;
-    uint16 a = y + BG2VOFS_copy2;
-    return (a <= start || a >= end) ? 0 : y;
-  } else {
-    uint16 start = ow_scroll_vars0.xstart + 1;
-    uint16 end = ow_scroll_vars0.xend - 1;
-    uint16 a = y + BG2HOFS_copy2;
-    return (a <= start || a >= end) ? 0 : y;
-  }
-}
-
-void Ancilla_TerminateIfOffscreen(int j) {  // 8ffd52
-  int xt = (enhanced_features0 & kFeatures0_ExtendScreen64) ? 0x40 : 0;
-  uint16 x = Ancilla_GetX(j) - BG2HOFS_copy2 + xt;
-  uint16 y = Ancilla_GetY(j) - BG2VOFS_copy2;
-  if (x >= 244 + xt * 2 || y >= 240)
-    ancilla_type[j] = 0;
-}
-
-bool Bomb_CheckUndersideSpriteStatus(int k, Point16U *out_pt, uint8 *out_r10) {  // 8ffdcf
-  if (ancilla_item_to_link[k] != 0)
-    return true;
-
-  uint8 r10 = 0;
-  if (ancilla_tile_attr[k] == 9) {
-    if (sign8(--ancilla_arr22[k])) {
-      ancilla_arr22[k] = 3;
-      if (++ancilla_arr23[k] == 3)
-        ancilla_arr23[k] = 0;
-    }
-    r10 = ancilla_arr23[k] + 4;
-    if ((sound_effect_1 & 0x3f) == 0xb || (sound_effect_1 & 0x3f) == 0x21)
-      sound_effect_1 = Ancilla_CalculateSfxPan(k) | 0x28;
-  } else if (ancilla_tile_attr[k] == 0x40) {
-    r10 = 3;
-  }
-
-  if (ancilla_z[k] >= 2 && ancilla_z[k] < 252)
-    r10 = 2;
-  if (k + 1 == flag_is_ancilla_to_pick_up && (link_state_bits & 0x80))
-    return true;
-  int z = (int8)ancilla_z[k];
-  out_pt->y += z + 2;
-  out_pt->x += -8;
-  *out_r10 = r10;
-  return false;
-}
-
-void Sprite_CreateDeflectedArrow(int k) {  // 9d8040
-  ancilla_type[k] = 0;
-  SpriteSpawnInfo info;
-  int j = Sprite_SpawnDynamically(k, 0x1b, &info);
-  if (j >= 0) {
-    sprite_x_lo[j] = ancilla_x_lo[k];
-    sprite_x_hi[j] = ancilla_x_hi[k];
-    sprite_y_lo[j] = ancilla_y_lo[k];
-    sprite_y_hi[j] = ancilla_y_hi[k];
-    sprite_state[j] = 6;
-    sprite_delay_main[j] = 31;
-    sprite_x_vel[j] = ancilla_x_vel[k];
-    sprite_y_vel[j] = ancilla_y_vel[k];
-    sprite_floor[j] = link_is_on_lower_level;
-    Sprite_PlaceWeaponTink(j);
-  }
-}
-
--- a/ancilla.h
+++ /dev/null
@@ -1,273 +1,0 @@
-#pragma once
-#include "types.h"
-#include "zelda_rtl.h"
-#include "sprite.h"
-
-typedef struct CheckPlayerCollOut {
-  uint16 r4, r6;
-  uint16 r8, r10;
-} CheckPlayerCollOut;
-
-typedef struct AncillaOamInfo {
-  uint8 x;
-  uint8 y;
-  uint8 flags;
-} AncillaOamInfo;
-
-typedef struct AncillaRadialProjection {
-  uint8 r0, r2, r4, r6;
-} AncillaRadialProjection;
-
-uint16 Ancilla_GetX(int k);
-uint16 Ancilla_GetY(int k);
-void Ancilla_SetX(int k, uint16 x);
-void Ancilla_SetY(int k, uint16 y);
-int Ancilla_AllocHigh();
-void Ancilla_Empty(int k);
-void Ancilla_Unused_14(int k);
-void Ancilla_Unused_25(int k);
-void SpinSpark_Draw(int k, int offs);
-bool SomarianBlock_CheckEmpty(OamEnt *oam);
-void AddDashingDustEx(uint8 a, uint8 y, uint8 flag);
-void AddBirdCommon(int k);
-ProjectSpeedRet Bomb_ProjectSpeedTowardsPlayer(int k, uint16 x, uint16 y, uint8 vel);
-void Boomerang_CheatWhenNoOnesLooking(int k, ProjectSpeedRet *pt);
-void Medallion_CheckSpriteDamage(int k);
-void Ancilla_CheckDamageToSprite(int k, uint8 type);
-void Ancilla_CheckDamageToSprite_aggressive(int k, uint8 type);
-void CallForDuckIndoors();
-void Ancilla_Sfx1_Pan(int k, uint8 v);
-void Ancilla_Sfx2_Pan(int k, uint8 v);
-void Ancilla_Sfx3_Pan(int k, uint8 v);
-void AncillaAdd_FireRodShot(uint8 type, uint8 y);
-void SomariaBlock_SpawnBullets(int k);
-void Ancilla_Main();
-ProjectSpeedRet Ancilla_ProjectReflexiveSpeedOntoSprite(int k, uint16 x, uint16 y, uint8 vel);
-void Bomb_CheckSpriteDamage(int k);
-void Ancilla_ExecuteAll();
-void Ancilla_ExecuteOne(uint8 type, int k);
-void Ancilla13_IceRodSparkle(int k);
-void AncillaAdd_IceRodSparkle(int k);
-void Ancilla01_SomariaBullet(int k);
-bool Ancilla_ReturnIfOutsideBounds(int k, AncillaOamInfo *info);
-void SomarianBlast_Draw(int k);
-void Ancilla02_FireRodShot(int k);
-void FireShot_Draw(int k);
-uint8 Ancilla_CheckTileCollision_staggered(int k);
-uint8 Ancilla_CheckTileCollision(int k);
-bool Ancilla_CheckTileCollisionOneFloor(int k);
-bool Ancilla_CheckTileCollision_targeted(int k, uint16 x, uint16 y);
-bool Ancilla_CheckTileCollision_Class2(int k);
-bool Ancilla_CheckTileCollision_Class2_Inner(int k);
-void Ancilla04_BeamHit(int k);
-int Ancilla_CheckSpriteCollision(int k);
-bool Ancilla_CheckSpriteCollision_Single(int k, int j);
-void Ancilla_SetupHitBox(int k, SpriteHitBox *hb);
-ProjectSpeedRet Ancilla_ProjectSpeedTowardsPlayer(int k, uint8 vel);
-PairU8 Ancilla_IsRightOfLink(int k);
-PairU8 Ancilla_IsBelowLink(int k);
-void Ancilla_WeaponTink();
-void Ancilla_MoveX(int k);
-void Ancilla_MoveY(int k);
-void Ancilla_MoveZ(int k);
-void Ancilla05_Boomerang(int k);
-bool Boomerang_ScreenEdge(int k);
-void Boomerang_StopOffScreen(int k);
-void Boomerang_Terminate(int k);
-void Boomerang_Draw(int k);
-void Ancilla06_WallHit(int k);
-void Ancilla_SwordWallHit(int k);
-void WallHit_Draw(int k);
-void Ancilla07_Bomb(int k);
-void Ancilla_ApplyConveyor(int k);
-void Bomb_CheckSpriteAndPlayerDamage(int k);
-void Ancilla_HandleLiftLogic(int k);
-void Ancilla_LatchAltitudeAboveLink(int k);
-void Ancilla_LatchLinkCoordinates(int k, int j);
-void Ancilla_LatchCarriedPosition(int k);
-uint16 Ancilla_LatchYCoordToZ(int k);
-int Bomb_GetDisplacementFromLink(int k);
-void Bomb_Draw(int k);
-void Ancilla08_DoorDebris(int k);
-void DoorDebris_Draw(int k);
-void Ancilla09_Arrow(int k);
-void Arrow_Draw(int k);
-void Ancilla0A_ArrowInTheWall(int k);
-void Ancilla0B_IceRodShot(int k);
-void Ancilla11_IceRodWallHit(int k);
-void IceShotSpread_Draw(int k);
-void Ancilla33_BlastWallExplosion(int k);
-void AncillaDraw_BlastWallBlast(int k, int x, int y);
-OamEnt *AncillaDraw_Explosion(OamEnt *oam, int frame, int idx, int idx_end, uint8 r11, int x, int y);
-void Ancilla15_JumpSplash(int k);
-void Ancilla16_HitStars(int k);
-void Ancilla17_ShovelDirt(int k);
-void Ancilla32_BlastWallFireball(int k);
-void Ancilla18_EtherSpell(int k);
-void EtherSpell_HandleLightningStroke(int k);
-void EtherSpell_HandleOrbPulse(int k);
-void EtherSpell_HandleRadialSpin(int k);
-OamEnt *AncillaDraw_EtherBlitzBall(OamEnt *oam, const AncillaRadialProjection *arp, int s);
-OamEnt *AncillaDraw_EtherBlitzSegment(OamEnt *oam, const AncillaRadialProjection *arp, int s, int k);
-void AncillaDraw_EtherBlitz(int k);
-void AncillaDraw_EtherOrb(int k, OamEnt *oam);
-void AncillaAdd_BombosSpell(uint8 a, uint8 y);
-void Ancilla19_BombosSpell(int k);
-void BombosSpell_ControlFireColumns(int k);
-void BombosSpell_FinishFireColumns(int kk);
-void AncillaDraw_BombosFireColumn(int kk);
-void BombosSpell_ControlBlasting(int kk);
-void AncillaDraw_BombosBlast(int k);
-void Ancilla1C_QuakeSpell(int k);
-void QuakeSpell_ShakeScreen(int k);
-void QuakeSpell_ControlBolts(int k);
-void AncillaDraw_QuakeInitialBolts(int k);
-void QuakeSpell_SpreadBolts(int k);
-void Ancilla1A_PowderDust(int k);
-void Ancilla_MagicPowder_Draw(int k);
-void Powder_ApplyDamageToSprites(int k);
-void Ancilla1D_ScreenShake(int k);
-void Ancilla1E_DashDust(int k);
-void Ancilla1F_Hookshot(int k);
-void Ancilla20_Blanket(int k);
-void Ancilla21_Snore(int k);
-void Ancilla3B_SwordUpSparkle(int k);
-void Ancilla3C_SpinAttackChargeSparkle(int k);
-void Ancilla35_MasterSwordReceipt(int k);
-void Ancilla22_ItemReceipt(int k);
-OamEnt *Ancilla_ReceiveItem_Draw(int k, int x, int y);
-void Ancilla28_WishPondItem(int k);
-void WishPondItem_Draw(int k);
-void Ancilla42_HappinessPondRupees(int k);
-void HapinessPondRupees_ExecuteRupee(int k, int i);
-void HapinessPondRupees_GetState(int j, int k);
-void HapinessPondRupees_SaveState(int k, int j);
-void Ancilla_TransmuteToSplash(int k);
-void Ancilla3D_ItemSplash(int k);
-void ObjectSplash_Draw(int k);
-void Ancilla29_MilestoneItemReceipt(int k);
-void ItemReceipt_TransmuteToRisingCrystal(int k);
-void Ancilla_RisingCrystal(int k);
-void AncillaAdd_OccasionalSparkle(int k);
-void Ancilla43_GanonsTowerCutscene(int k);
-void AncillaDraw_GTCutsceneCrystal(OamEnt *oam, int x, int y);
-void GTCutscene_ActivateSparkle();
-OamEnt *GTCutscene_SparkleALot(OamEnt *oam);
-void Ancilla36_Flute(int k);
-void Ancilla37_WeathervaneExplosion(int k);
-void AncillaDraw_WeathervaneExplosionWoodDebris(int k);
-void Ancilla38_CutsceneDuck(int k);
-void Ancilla23_LinkPoof(int k);
-void MorphPoof_Draw(int k);
-void Ancilla40_DwarfPoof(int k);
-void Ancilla3F_BushPoof(int k);
-void Ancilla26_SwordSwingSparkle(int k);
-void Ancilla2A_SpinAttackSparkleA(int k);
-void SpinAttackSparkleA_TransmuteToNextSpark(int k);
-void Ancilla2B_SpinAttackSparkleB(int k);
-Point16U Sparkle_PrepOamFromRadial(AncillaRadialProjection p);
-void SpinAttackSparkleB_Closer(int k);
-void Ancilla30_ByrnaWindupSpark(int k);
-void ByrnaWindupSpark_TransmuteToNormal(int k);
-void Ancilla31_ByrnaSpark(int k);
-void Ancilla_SwordBeam(int k);
-void Ancilla0D_SpinAttackFullChargeSpark(int k);
-void Ancilla27_Duck(int k);
-int AncillaAdd_SomariaBlock(uint8 type, uint8 y);
-void SomariaBlock_CheckForTransitTile(int k);
-int Ancilla_CheckBasicSpriteCollision(int k);
-bool Ancilla_CheckBasicSpriteCollision_Single(int k, int j);
-void Ancilla_SetupBasicHitBox(int k, SpriteHitBox *hb);
-void Ancilla2C_SomariaBlock(int k);
-void AncillaDraw_SomariaBlock(int k);
-bool SomariaBlock_CheckForSwitch(int k);
-void SomariaBlock_FizzleAway(int k);
-void Ancilla2D_SomariaBlockFizz(int k);
-void Ancilla39_SomariaPlatformPoof(int k);
-void Ancilla2E_SomariaBlockFission(int k);
-void Ancilla2F_LampFlame(int k);
-void Ancilla41_WaterfallSplash(int k);
-void Ancilla24_Gravestone(int k);
-void Ancilla34_SkullWoodsFire(int k);
-void Ancilla3A_BigBombExplosion(int k);
-void RevivalFairy_Main();
-void RevivalFairy_Dust();
-void RevivalFairy_MonitorHP();
-void GameOverText_Draw();
-int AncillaAdd_AddAncilla_Bank08(uint8 type, uint8 y);
-void Ancilla_PrepOamCoord(int k, Point16U *info);
-void Ancilla_PrepAdjustedOamCoord(int k, Point16U *info);
-bool Ancilla_CheckLinkCollision(int k, int j, CheckPlayerCollOut *out);
-bool Hookshot_CheckProximityToLink(int x, int y);
-bool Ancilla_CheckForEntranceTrigger(int what);
-void AncillaDraw_Shadow(OamEnt *oam, int k, int x, int y, uint8 pal);
-void Ancilla_AllocateOamFromRegion_B_or_E(uint8 size);
-OamEnt *Ancilla_AllocateOamFromCustomRegion(OamEnt *oam);
-OamEnt *HitStars_UpdateOamBufferPosition(OamEnt *oam);
-bool Hookshot_ShouldIEvenBotherWithTiles(int k);
-AncillaRadialProjection Ancilla_GetRadialProjection(uint8 a, uint8 r8);
-int Ancilla_AllocateOamFromRegion_A_or_D_or_F(int k, uint8 size);
-void Ancilla_AddHitStars(uint8 a, uint8 y);
-void AncillaAdd_Blanket(uint8 a);
-void AncillaAdd_Snoring(uint8 a, uint8 y);
-void AncillaAdd_Bomb(uint8 a, uint8 y);
-uint8 AncillaAdd_Boomerang(uint8 a, uint8 y);
-void AncillaAdd_TossedPondItem(uint8 a, uint8 xin, uint8 yin);
-void AddHappinessPondRupees(uint8 arg);
-int AncillaAdd_FallingPrize(uint8 a, uint8 item_idx, uint8 yv);
-void AncillaAdd_ChargedSpinAttackSparkle();
-void AncillaAdd_ExplodingWeatherVane(uint8 a, uint8 y);
-void AncillaAdd_CutsceneDuck(uint8 a, uint8 y);
-void AncillaAdd_SomariaPlatformPoof(int k);
-int AncillaAdd_SuperBombExplosion(uint8 a, uint8 y);
-void ConfigureRevivalAncillae();
-void AncillaAdd_LampFlame(uint8 a, uint8 y);
-void AncillaAdd_MSCutscene(uint8 a, uint8 y);
-void AncillaAdd_DashDust(uint8 a, uint8 y);
-void AncillaAdd_DashDust_charging(uint8 a, uint8 y);
-void AncillaAdd_BlastWallFireball(uint8 a, uint8 y, int r4);
-int AncillaAdd_Arrow(uint8 a, uint8 ax, uint8 ay, uint16 xcoord, uint16 ycoord);
-void AncillaAdd_BunnyPoof(uint8 a, uint8 y);
-void AncillaAdd_CapePoof(uint8 a, uint8 y);
-void AncillaAdd_DwarfPoof(uint8 ain, uint8 yin);
-void AncillaAdd_BushPoof(uint16 x, uint16 y);
-void AncillaAdd_EtherSpell(uint8 a, uint8 y);
-void AncillaAdd_VictorySpin();
-void AncillaAdd_MagicPowder(uint8 a, uint8 y);
-void AncillaAdd_WallTapSpark(uint8 a, uint8 y);
-void AncillaAdd_SwordSwingSparkle(uint8 a, uint8 y);
-void AncillaAdd_DashTremor(uint8 a, uint8 y);
-void AncillaAdd_BoomerangWallClink(int k);
-void AncillaAdd_HookshotWallClink(int kin, uint8 a, uint8 y);
-void AncillaAdd_Duck_take_off(uint8 a, uint8 y);
-void AddBirdTravelSomething(uint8 a, uint8 y);
-void AncillaAdd_QuakeSpell(uint8 a, uint8 y);
-void AncillaAdd_SpinAttackInitSpark(uint8 a, uint8 x, uint8 y);
-void AncillaAdd_BlastWall();
-void AncillaAdd_SwordChargeSparkle(int k);
-void AncillaAdd_SilverArrowSparkle(int kin);
-void AncillaAdd_IceRodShot(uint8 a, uint8 y);
-bool AncillaAdd_Splash(uint8 a, uint8 y);
-void AncillaAdd_GraveStone(uint8 ain, uint8 yin);
-void AncillaAdd_WaterfallSplash();
-void AncillaAdd_GTCutscene();
-int AncillaAdd_DoorDebris();
-void FireRodShot_BecomeSkullWoodsFire(int k);
-int Ancilla_AddAncilla(uint8 a, uint8 y);
-bool AncillaAdd_CheckForPresence(uint8 a);
-int AncillaAdd_ArrowFindSlot(uint8 type, uint8 ay);
-int Ancilla_CheckInitialTile_A(int k);
-bool Ancilla_CheckInitialTileCollision_Class2(int k);
-uint8 Ancilla_TerminateSelectInteractives(uint8 y);
-void Ancilla_SetXY(int k, uint16 x, uint16 y);
-void AncillaAdd_ExplodingSomariaBlock(int k);
-bool Ancilla_AddRupees(int k);
-void DashDust_Motive(int k);
-uint8 Ancilla_CalculateSfxPan(int k);
-int Ancilla_AllocInit(uint8 type, uint8 y);
-void AddSwordBeam(uint8 y);
-void AncillaSpawn_SwordChargeSparkle();
-int DashTremor_TwiddleOffset(int k);
-void Ancilla_TerminateIfOffscreen(int j);
-bool Bomb_CheckUndersideSpriteStatus(int k, Point16U *out_pt, uint8 *out_r10);
-void Sprite_CreateDeflectedArrow(int k);
--- a/assets.h
+++ /dev/null
@@ -1,332 +1,0 @@
-#pragma once
-#include "types.h"
-
-enum {
-  kNumberOfAssets = 165
-};
-extern const uint8 *g_asset_ptrs[kNumberOfAssets];
-extern uint32 g_asset_sizes[kNumberOfAssets];
-extern MemBlk FindInAssetArray(int asset, int idx);
-
-#define kSoundBank_intro ((uint8*)g_asset_ptrs[0])
-#define kSoundBank_intro_SIZE (g_asset_sizes[0])
-#define kSoundBank_indoor ((uint8*)g_asset_ptrs[1])
-#define kSoundBank_indoor_SIZE (g_asset_sizes[1])
-#define kSoundBank_ending ((uint8*)g_asset_ptrs[2])
-#define kSoundBank_ending_SIZE (g_asset_sizes[2])
-#define kDungeonRoom ((uint8*)g_asset_ptrs[3])
-#define kDungeonRoom_SIZE (g_asset_sizes[3])
-#define kDungeonRoomOffs ((uint16*)g_asset_ptrs[4])
-#define kDungeonRoomOffs_SIZE (g_asset_sizes[4])
-#define kDungeonRoomDoorOffs ((uint16*)g_asset_ptrs[5])
-#define kDungeonRoomDoorOffs_SIZE (g_asset_sizes[5])
-#define kDungeonRoomHeaders ((uint8*)g_asset_ptrs[6])
-#define kDungeonRoomHeaders_SIZE (g_asset_sizes[6])
-#define kDungeonRoomHeadersOffs ((uint16*)g_asset_ptrs[7])
-#define kDungeonRoomHeadersOffs_SIZE (g_asset_sizes[7])
-#define kDungeonRoomChests ((uint8*)g_asset_ptrs[8])
-#define kDungeonRoomChests_SIZE (g_asset_sizes[8])
-#define kDungeonRoomTeleMsg ((uint16*)g_asset_ptrs[9])
-#define kDungeonRoomTeleMsg_SIZE (g_asset_sizes[9])
-#define kDungeonPitsHurtPlayer ((uint16*)g_asset_ptrs[10])
-#define kDungeonPitsHurtPlayer_SIZE (g_asset_sizes[10])
-#define kEntranceData_rooms ((uint16*)g_asset_ptrs[11])
-#define kEntranceData_rooms_SIZE (g_asset_sizes[11])
-#define kEntranceData_relativeCoords ((uint8*)g_asset_ptrs[12])
-#define kEntranceData_relativeCoords_SIZE (g_asset_sizes[12])
-#define kEntranceData_scrollX ((uint16*)g_asset_ptrs[13])
-#define kEntranceData_scrollX_SIZE (g_asset_sizes[13])
-#define kEntranceData_scrollY ((uint16*)g_asset_ptrs[14])
-#define kEntranceData_scrollY_SIZE (g_asset_sizes[14])
-#define kEntranceData_playerX ((uint16*)g_asset_ptrs[15])
-#define kEntranceData_playerX_SIZE (g_asset_sizes[15])
-#define kEntranceData_playerY ((uint16*)g_asset_ptrs[16])
-#define kEntranceData_playerY_SIZE (g_asset_sizes[16])
-#define kEntranceData_cameraX ((uint16*)g_asset_ptrs[17])
-#define kEntranceData_cameraX_SIZE (g_asset_sizes[17])
-#define kEntranceData_cameraY ((uint16*)g_asset_ptrs[18])
-#define kEntranceData_cameraY_SIZE (g_asset_sizes[18])
-#define kEntranceData_blockset ((uint8*)g_asset_ptrs[19])
-#define kEntranceData_blockset_SIZE (g_asset_sizes[19])
-#define kEntranceData_floor ((int8*)g_asset_ptrs[20])
-#define kEntranceData_floor_SIZE (g_asset_sizes[20])
-#define kEntranceData_palace ((int8*)g_asset_ptrs[21])
-#define kEntranceData_palace_SIZE (g_asset_sizes[21])
-#define kEntranceData_doorwayOrientation ((uint8*)g_asset_ptrs[22])
-#define kEntranceData_doorwayOrientation_SIZE (g_asset_sizes[22])
-#define kEntranceData_startingBg ((uint8*)g_asset_ptrs[23])
-#define kEntranceData_startingBg_SIZE (g_asset_sizes[23])
-#define kEntranceData_quadrant1 ((uint8*)g_asset_ptrs[24])
-#define kEntranceData_quadrant1_SIZE (g_asset_sizes[24])
-#define kEntranceData_quadrant2 ((uint8*)g_asset_ptrs[25])
-#define kEntranceData_quadrant2_SIZE (g_asset_sizes[25])
-#define kEntranceData_doorSettings ((uint16*)g_asset_ptrs[26])
-#define kEntranceData_doorSettings_SIZE (g_asset_sizes[26])
-#define kEntranceData_musicTrack ((uint8*)g_asset_ptrs[27])
-#define kEntranceData_musicTrack_SIZE (g_asset_sizes[27])
-#define kStartingPoint_rooms ((uint16*)g_asset_ptrs[28])
-#define kStartingPoint_rooms_SIZE (g_asset_sizes[28])
-#define kStartingPoint_relativeCoords ((uint8*)g_asset_ptrs[29])
-#define kStartingPoint_relativeCoords_SIZE (g_asset_sizes[29])
-#define kStartingPoint_scrollX ((uint16*)g_asset_ptrs[30])
-#define kStartingPoint_scrollX_SIZE (g_asset_sizes[30])
-#define kStartingPoint_scrollY ((uint16*)g_asset_ptrs[31])
-#define kStartingPoint_scrollY_SIZE (g_asset_sizes[31])
-#define kStartingPoint_playerX ((uint16*)g_asset_ptrs[32])
-#define kStartingPoint_playerX_SIZE (g_asset_sizes[32])
-#define kStartingPoint_playerY ((uint16*)g_asset_ptrs[33])
-#define kStartingPoint_playerY_SIZE (g_asset_sizes[33])
-#define kStartingPoint_cameraX ((uint16*)g_asset_ptrs[34])
-#define kStartingPoint_cameraX_SIZE (g_asset_sizes[34])
-#define kStartingPoint_cameraY ((uint16*)g_asset_ptrs[35])
-#define kStartingPoint_cameraY_SIZE (g_asset_sizes[35])
-#define kStartingPoint_blockset ((uint8*)g_asset_ptrs[36])
-#define kStartingPoint_blockset_SIZE (g_asset_sizes[36])
-#define kStartingPoint_floor ((int8*)g_asset_ptrs[37])
-#define kStartingPoint_floor_SIZE (g_asset_sizes[37])
-#define kStartingPoint_palace ((int8*)g_asset_ptrs[38])
-#define kStartingPoint_palace_SIZE (g_asset_sizes[38])
-#define kStartingPoint_doorwayOrientation ((uint8*)g_asset_ptrs[39])
-#define kStartingPoint_doorwayOrientation_SIZE (g_asset_sizes[39])
-#define kStartingPoint_startingBg ((uint8*)g_asset_ptrs[40])
-#define kStartingPoint_startingBg_SIZE (g_asset_sizes[40])
-#define kStartingPoint_quadrant1 ((uint8*)g_asset_ptrs[41])
-#define kStartingPoint_quadrant1_SIZE (g_asset_sizes[41])
-#define kStartingPoint_quadrant2 ((uint8*)g_asset_ptrs[42])
-#define kStartingPoint_quadrant2_SIZE (g_asset_sizes[42])
-#define kStartingPoint_doorSettings ((uint16*)g_asset_ptrs[43])
-#define kStartingPoint_doorSettings_SIZE (g_asset_sizes[43])
-#define kStartingPoint_entrance ((uint8*)g_asset_ptrs[44])
-#define kStartingPoint_entrance_SIZE (g_asset_sizes[44])
-#define kStartingPoint_musicTrack ((uint8*)g_asset_ptrs[45])
-#define kStartingPoint_musicTrack_SIZE (g_asset_sizes[45])
-#define kDungeonRoomDefault ((uint8*)g_asset_ptrs[46])
-#define kDungeonRoomDefault_SIZE (g_asset_sizes[46])
-#define kDungeonRoomDefaultOffs ((uint16*)g_asset_ptrs[47])
-#define kDungeonRoomDefaultOffs_SIZE (g_asset_sizes[47])
-#define kDungeonRoomOverlay ((uint8*)g_asset_ptrs[48])
-#define kDungeonRoomOverlay_SIZE (g_asset_sizes[48])
-#define kDungeonRoomOverlayOffs ((uint16*)g_asset_ptrs[49])
-#define kDungeonRoomOverlayOffs_SIZE (g_asset_sizes[49])
-#define kDungeonSecrets ((uint8*)g_asset_ptrs[50])
-#define kDungeonSecrets_SIZE (g_asset_sizes[50])
-#define kDungAttrsForTile_Offs ((uint16*)g_asset_ptrs[51])
-#define kDungAttrsForTile_Offs_SIZE (g_asset_sizes[51])
-#define kDungAttrsForTile ((uint8*)g_asset_ptrs[52])
-#define kDungAttrsForTile_SIZE (g_asset_sizes[52])
-#define kMovableBlockDataInit ((uint16*)g_asset_ptrs[53])
-#define kMovableBlockDataInit_SIZE (g_asset_sizes[53])
-#define kTorchDataInit ((uint16*)g_asset_ptrs[54])
-#define kTorchDataInit_SIZE (g_asset_sizes[54])
-#define kTorchDataJunk ((uint16*)g_asset_ptrs[55])
-#define kTorchDataJunk_SIZE (g_asset_sizes[55])
-#define kEnemyDamageData ((uint8*)g_asset_ptrs[56])
-#define kEnemyDamageData_SIZE (g_asset_sizes[56])
-#define kLinkGraphics ((uint8*)g_asset_ptrs[57])
-#define kLinkGraphics_SIZE (g_asset_sizes[57])
-#define kDungeonSprites ((uint8*)g_asset_ptrs[58])
-#define kDungeonSprites_SIZE (g_asset_sizes[58])
-#define kDungeonSpriteOffs ((uint16*)g_asset_ptrs[59])
-#define kDungeonSpriteOffs_SIZE (g_asset_sizes[59])
-#define kMap32ToMap16_0 ((uint8*)g_asset_ptrs[60])
-#define kMap32ToMap16_0_SIZE (g_asset_sizes[60])
-#define kMap32ToMap16_1 ((uint8*)g_asset_ptrs[61])
-#define kMap32ToMap16_1_SIZE (g_asset_sizes[61])
-#define kMap32ToMap16_2 ((uint8*)g_asset_ptrs[62])
-#define kMap32ToMap16_2_SIZE (g_asset_sizes[62])
-#define kMap32ToMap16_3 ((uint8*)g_asset_ptrs[63])
-#define kMap32ToMap16_3_SIZE (g_asset_sizes[63])
-#define kSprGfx(idx) FindInAssetArray(64, idx)
-#define kBgGfx(idx) FindInAssetArray(65, idx)
-#define kOverworldMapGfx ((uint8*)g_asset_ptrs[66])
-#define kOverworldMapGfx_SIZE (g_asset_sizes[66])
-#define kLightOverworldTilemap ((uint8*)g_asset_ptrs[67])
-#define kLightOverworldTilemap_SIZE (g_asset_sizes[67])
-#define kDarkOverworldTilemap ((uint8*)g_asset_ptrs[68])
-#define kDarkOverworldTilemap_SIZE (g_asset_sizes[68])
-#define kPredefinedTileData ((uint16*)g_asset_ptrs[69])
-#define kPredefinedTileData_SIZE (g_asset_sizes[69])
-#define kMap16ToMap8 ((uint16*)g_asset_ptrs[70])
-#define kMap16ToMap8_SIZE (g_asset_sizes[70])
-#define kGeneratedWishPondItem ((uint8*)g_asset_ptrs[71])
-#define kGeneratedWishPondItem_SIZE (g_asset_sizes[71])
-#define kGeneratedBombosArr ((uint8*)g_asset_ptrs[72])
-#define kGeneratedBombosArr_SIZE (g_asset_sizes[72])
-#define kGeneratedEndSequence15 ((uint8*)g_asset_ptrs[73])
-#define kGeneratedEndSequence15_SIZE (g_asset_sizes[73])
-#define kEnding_Credits_Text ((uint8*)g_asset_ptrs[74])
-#define kEnding_Credits_Text_SIZE (g_asset_sizes[74])
-#define kEnding_Credits_Offs ((uint16*)g_asset_ptrs[75])
-#define kEnding_Credits_Offs_SIZE (g_asset_sizes[75])
-#define kEnding_MapData ((uint16*)g_asset_ptrs[76])
-#define kEnding_MapData_SIZE (g_asset_sizes[76])
-#define kEnding0_Offs ((uint16*)g_asset_ptrs[77])
-#define kEnding0_Offs_SIZE (g_asset_sizes[77])
-#define kEnding0_Data ((uint8*)g_asset_ptrs[78])
-#define kEnding0_Data_SIZE (g_asset_sizes[78])
-#define kPalette_DungBgMain ((uint16*)g_asset_ptrs[79])
-#define kPalette_DungBgMain_SIZE (g_asset_sizes[79])
-#define kPalette_MainSpr ((uint16*)g_asset_ptrs[80])
-#define kPalette_MainSpr_SIZE (g_asset_sizes[80])
-#define kPalette_ArmorAndGloves ((uint16*)g_asset_ptrs[81])
-#define kPalette_ArmorAndGloves_SIZE (g_asset_sizes[81])
-#define kPalette_Sword ((uint16*)g_asset_ptrs[82])
-#define kPalette_Sword_SIZE (g_asset_sizes[82])
-#define kPalette_Shield ((uint16*)g_asset_ptrs[83])
-#define kPalette_Shield_SIZE (g_asset_sizes[83])
-#define kPalette_SpriteAux3 ((uint16*)g_asset_ptrs[84])
-#define kPalette_SpriteAux3_SIZE (g_asset_sizes[84])
-#define kPalette_MiscSprite_Indoors ((uint16*)g_asset_ptrs[85])
-#define kPalette_MiscSprite_Indoors_SIZE (g_asset_sizes[85])
-#define kPalette_SpriteAux1 ((uint16*)g_asset_ptrs[86])
-#define kPalette_SpriteAux1_SIZE (g_asset_sizes[86])
-#define kPalette_OverworldBgMain ((uint16*)g_asset_ptrs[87])
-#define kPalette_OverworldBgMain_SIZE (g_asset_sizes[87])
-#define kPalette_OverworldBgAux12 ((uint16*)g_asset_ptrs[88])
-#define kPalette_OverworldBgAux12_SIZE (g_asset_sizes[88])
-#define kPalette_OverworldBgAux3 ((uint16*)g_asset_ptrs[89])
-#define kPalette_OverworldBgAux3_SIZE (g_asset_sizes[89])
-#define kPalette_PalaceMapBg ((uint16*)g_asset_ptrs[90])
-#define kPalette_PalaceMapBg_SIZE (g_asset_sizes[90])
-#define kPalette_PalaceMapSpr ((uint16*)g_asset_ptrs[91])
-#define kPalette_PalaceMapSpr_SIZE (g_asset_sizes[91])
-#define kHudPalData ((uint16*)g_asset_ptrs[92])
-#define kHudPalData_SIZE (g_asset_sizes[92])
-#define kOverworldMapPaletteData ((uint16*)g_asset_ptrs[93])
-#define kOverworldMapPaletteData_SIZE (g_asset_sizes[93])
-#define kDialogue(idx) FindInAssetArray(94, idx)
-#define kDialogueFont(idx) FindInAssetArray(95, idx)
-#define kDialogueMap(idx) FindInAssetArray(96, idx)
-#define kDungMap_FloorLayout(idx) FindInAssetArray(97, idx)
-#define kDungMap_Tiles(idx) FindInAssetArray(98, idx)
-#define kBgTilemap_0 ((uint8*)g_asset_ptrs[99])
-#define kBgTilemap_0_SIZE (g_asset_sizes[99])
-#define kBgTilemap_1 ((uint8*)g_asset_ptrs[100])
-#define kBgTilemap_1_SIZE (g_asset_sizes[100])
-#define kBgTilemap_2 ((uint8*)g_asset_ptrs[101])
-#define kBgTilemap_2_SIZE (g_asset_sizes[101])
-#define kBgTilemap_3 ((uint8*)g_asset_ptrs[102])
-#define kBgTilemap_3_SIZE (g_asset_sizes[102])
-#define kBgTilemap_4 ((uint8*)g_asset_ptrs[103])
-#define kBgTilemap_4_SIZE (g_asset_sizes[103])
-#define kBgTilemap_5 ((uint8*)g_asset_ptrs[104])
-#define kBgTilemap_5_SIZE (g_asset_sizes[104])
-#define kOverworld_Hibytes_Comp(idx) FindInAssetArray(105, idx)
-#define kOverworld_Lobytes_Comp(idx) FindInAssetArray(106, idx)
-#define kOverworldMapIsSmall ((uint8*)g_asset_ptrs[107])
-#define kOverworldMapIsSmall_SIZE (g_asset_sizes[107])
-#define kOverworldAuxTileThemeIndexes ((uint8*)g_asset_ptrs[108])
-#define kOverworldAuxTileThemeIndexes_SIZE (g_asset_sizes[108])
-#define kOverworldBgPalettes ((uint8*)g_asset_ptrs[109])
-#define kOverworldBgPalettes_SIZE (g_asset_sizes[109])
-#define kOverworld_SignText ((uint16*)g_asset_ptrs[110])
-#define kOverworld_SignText_SIZE (g_asset_sizes[110])
-#define kOwMusicSets ((uint8*)g_asset_ptrs[111])
-#define kOwMusicSets_SIZE (g_asset_sizes[111])
-#define kOwMusicSets2 ((uint8*)g_asset_ptrs[112])
-#define kOwMusicSets2_SIZE (g_asset_sizes[112])
-#define kBirdTravel_ScreenIndex ((uint16*)g_asset_ptrs[113])
-#define kBirdTravel_ScreenIndex_SIZE (g_asset_sizes[113])
-#define kBirdTravel_Map16LoadSrcOff ((uint16*)g_asset_ptrs[114])
-#define kBirdTravel_Map16LoadSrcOff_SIZE (g_asset_sizes[114])
-#define kBirdTravel_ScrollX ((uint16*)g_asset_ptrs[115])
-#define kBirdTravel_ScrollX_SIZE (g_asset_sizes[115])
-#define kBirdTravel_ScrollY ((uint16*)g_asset_ptrs[116])
-#define kBirdTravel_ScrollY_SIZE (g_asset_sizes[116])
-#define kBirdTravel_LinkXCoord ((uint16*)g_asset_ptrs[117])
-#define kBirdTravel_LinkXCoord_SIZE (g_asset_sizes[117])
-#define kBirdTravel_LinkYCoord ((uint16*)g_asset_ptrs[118])
-#define kBirdTravel_LinkYCoord_SIZE (g_asset_sizes[118])
-#define kBirdTravel_CameraXScroll ((uint16*)g_asset_ptrs[119])
-#define kBirdTravel_CameraXScroll_SIZE (g_asset_sizes[119])
-#define kBirdTravel_CameraYScroll ((uint16*)g_asset_ptrs[120])
-#define kBirdTravel_CameraYScroll_SIZE (g_asset_sizes[120])
-#define kBirdTravel_Unk1 ((int8*)g_asset_ptrs[121])
-#define kBirdTravel_Unk1_SIZE (g_asset_sizes[121])
-#define kBirdTravel_Unk3 ((int8*)g_asset_ptrs[122])
-#define kBirdTravel_Unk3_SIZE (g_asset_sizes[122])
-#define kWhirlpoolAreas ((uint16*)g_asset_ptrs[123])
-#define kWhirlpoolAreas_SIZE (g_asset_sizes[123])
-#define kOverworld_Entrance_Area ((uint16*)g_asset_ptrs[124])
-#define kOverworld_Entrance_Area_SIZE (g_asset_sizes[124])
-#define kOverworld_Entrance_Pos ((uint16*)g_asset_ptrs[125])
-#define kOverworld_Entrance_Pos_SIZE (g_asset_sizes[125])
-#define kOverworld_Entrance_Id ((uint8*)g_asset_ptrs[126])
-#define kOverworld_Entrance_Id_SIZE (g_asset_sizes[126])
-#define kFallHole_Area ((uint16*)g_asset_ptrs[127])
-#define kFallHole_Area_SIZE (g_asset_sizes[127])
-#define kFallHole_Pos ((uint16*)g_asset_ptrs[128])
-#define kFallHole_Pos_SIZE (g_asset_sizes[128])
-#define kFallHole_Entrances ((uint8*)g_asset_ptrs[129])
-#define kFallHole_Entrances_SIZE (g_asset_sizes[129])
-#define kExitData_ScreenIndex ((uint8*)g_asset_ptrs[130])
-#define kExitData_ScreenIndex_SIZE (g_asset_sizes[130])
-#define kExitDataRooms ((uint16*)g_asset_ptrs[131])
-#define kExitDataRooms_SIZE (g_asset_sizes[131])
-#define kExitData_Map16LoadSrcOff ((uint16*)g_asset_ptrs[132])
-#define kExitData_Map16LoadSrcOff_SIZE (g_asset_sizes[132])
-#define kExitData_ScrollX ((uint16*)g_asset_ptrs[133])
-#define kExitData_ScrollX_SIZE (g_asset_sizes[133])
-#define kExitData_ScrollY ((uint16*)g_asset_ptrs[134])
-#define kExitData_ScrollY_SIZE (g_asset_sizes[134])
-#define kExitData_XCoord ((uint16*)g_asset_ptrs[135])
-#define kExitData_XCoord_SIZE (g_asset_sizes[135])
-#define kExitData_YCoord ((uint16*)g_asset_ptrs[136])
-#define kExitData_YCoord_SIZE (g_asset_sizes[136])
-#define kExitData_CameraXScroll ((uint16*)g_asset_ptrs[137])
-#define kExitData_CameraXScroll_SIZE (g_asset_sizes[137])
-#define kExitData_CameraYScroll ((uint16*)g_asset_ptrs[138])
-#define kExitData_CameraYScroll_SIZE (g_asset_sizes[138])
-#define kExitData_NormalDoor ((uint16*)g_asset_ptrs[139])
-#define kExitData_NormalDoor_SIZE (g_asset_sizes[139])
-#define kExitData_FancyDoor ((uint16*)g_asset_ptrs[140])
-#define kExitData_FancyDoor_SIZE (g_asset_sizes[140])
-#define kExitData_Unk1 ((int8*)g_asset_ptrs[141])
-#define kExitData_Unk1_SIZE (g_asset_sizes[141])
-#define kExitData_Unk3 ((int8*)g_asset_ptrs[142])
-#define kExitData_Unk3_SIZE (g_asset_sizes[142])
-#define kSpExit_Top ((uint16*)g_asset_ptrs[143])
-#define kSpExit_Top_SIZE (g_asset_sizes[143])
-#define kSpExit_Bottom ((uint16*)g_asset_ptrs[144])
-#define kSpExit_Bottom_SIZE (g_asset_sizes[144])
-#define kSpExit_Left ((uint16*)g_asset_ptrs[145])
-#define kSpExit_Left_SIZE (g_asset_sizes[145])
-#define kSpExit_Right ((uint16*)g_asset_ptrs[146])
-#define kSpExit_Right_SIZE (g_asset_sizes[146])
-#define kSpExit_Tab4 ((int16*)g_asset_ptrs[147])
-#define kSpExit_Tab4_SIZE (g_asset_sizes[147])
-#define kSpExit_Tab5 ((int16*)g_asset_ptrs[148])
-#define kSpExit_Tab5_SIZE (g_asset_sizes[148])
-#define kSpExit_Tab6 ((int16*)g_asset_ptrs[149])
-#define kSpExit_Tab6_SIZE (g_asset_sizes[149])
-#define kSpExit_Tab7 ((int16*)g_asset_ptrs[150])
-#define kSpExit_Tab7_SIZE (g_asset_sizes[150])
-#define kSpExit_LeftEdgeOfMap ((uint16*)g_asset_ptrs[151])
-#define kSpExit_LeftEdgeOfMap_SIZE (g_asset_sizes[151])
-#define kSpExit_Dir ((uint8*)g_asset_ptrs[152])
-#define kSpExit_Dir_SIZE (g_asset_sizes[152])
-#define kSpExit_SprGfx ((uint8*)g_asset_ptrs[153])
-#define kSpExit_SprGfx_SIZE (g_asset_sizes[153])
-#define kSpExit_AuxGfx ((uint8*)g_asset_ptrs[154])
-#define kSpExit_AuxGfx_SIZE (g_asset_sizes[154])
-#define kSpExit_PalBg ((uint8*)g_asset_ptrs[155])
-#define kSpExit_PalBg_SIZE (g_asset_sizes[155])
-#define kSpExit_PalSpr ((uint8*)g_asset_ptrs[156])
-#define kSpExit_PalSpr_SIZE (g_asset_sizes[156])
-#define kOverworldSecrets_Offs ((uint16*)g_asset_ptrs[157])
-#define kOverworldSecrets_Offs_SIZE (g_asset_sizes[157])
-#define kOverworldSecrets ((uint8*)g_asset_ptrs[158])
-#define kOverworldSecrets_SIZE (g_asset_sizes[158])
-#define kOverworldSpriteOffs ((uint16*)g_asset_ptrs[159])
-#define kOverworldSpriteOffs_SIZE (g_asset_sizes[159])
-#define kOverworldSprites ((uint8*)g_asset_ptrs[160])
-#define kOverworldSprites_SIZE (g_asset_sizes[160])
-#define kOverworldSpriteGfx ((uint8*)g_asset_ptrs[161])
-#define kOverworldSpriteGfx_SIZE (g_asset_sizes[161])
-#define kOverworldSpritePalettes ((uint8*)g_asset_ptrs[162])
-#define kOverworldSpritePalettes_SIZE (g_asset_sizes[162])
-#define kMap8DataToTileAttr ((uint8*)g_asset_ptrs[163])
-#define kMap8DataToTileAttr_SIZE (g_asset_sizes[163])
-#define kSomeTileAttr ((uint8*)g_asset_ptrs[164])
-#define kSomeTileAttr_SIZE (g_asset_sizes[164])
-#define kAssets_Sig 90, 101, 108, 100, 97, 51, 95, 118, 48, 32, 32, 32, 32, 32, 10, 0, 27, 174, 233, 45, 74, 174, 252, 50, 49, 27, 153, 197, 27, 43, 216, 197, 132, 101, 173, 169, 36, 108, 15, 155, 176, 169, 57, 131, 174, 101, 51, 207
--- /dev/null
+++ b/assets/.gitignore
@@ -1,0 +1,14 @@
+zelda3.sfc
+dialogue*.txt
+generated_*.h
+linksprite.png
+map32_to_map16.txt
+music_info.yaml
+sfx.txt
+/sound
+sound_ending.txt
+sound_indoor.txt
+sound_intro.txt
+/hud_icons.png
+/font*.png
+
--- /dev/null
+++ b/assets/compile_music.py
@@ -1,0 +1,453 @@
+import array
+import sys
+import yaml
+import re
+import util
+
+class Song:
+  name = 'Song'
+  def __str__(self):
+    s = '[Song_0x%x idx=%d]\n' % (self.ea, self.index)
+    s += "".join(x.name + '\n' for x in self.phrases)
+    return s
+
+class Phrase:
+  name = 'Phrase'
+  def __str__(self):
+    s = '[%s]' % (self.name)
+    return s
+
+class PhraseLoop:
+  name = 'PhraseLoop'
+  def __init__(self, loops, jmp):
+    self.loops = loops
+    self.jmp = jmp
+    self.name = 'PhraseLoop %d %d' % (self.loops, self.jmp)
+  def __str__(self):
+    return self.name
+
+class Pattern:
+  name = 'Pattern'
+
+class SfxPattern:
+  name = 'SfxPattern'
+
+class SongList:
+  name = 'SongList'
+
+class SfxList:
+  name = 'SfxList'
+
+types_for_name = {}
+
+def get_type_for_name(nam, tp, is_create):
+  if nam == 'None':
+    assert not is_create
+    return None
+  a = types_for_name.get(nam)
+  if a != None:
+    if is_create:
+      if a.defined:
+        raise Exception('%s already defined' % nam)
+      a.defined = True
+    assert type(a) == tp, (nam, type(a), tp)
+    return a
+  a = tp()
+  a.name = nam
+  a.defined = is_create
+  types_for_name[nam] = a
+  a.ea = None
+  if '_0x' in nam:
+    a.ea = int(nam[nam.index('_0x') + 3:], 16)
+  return a
+
+def process_song(caption, args, lines):
+  song = get_type_for_name(caption, Song, True)
+  song.phrases = []
+  for line in lines:
+    line_cmd, *line_args = line.split(' ')
+    if line_cmd == 'PhraseLoop':
+      song.phrases.append(PhraseLoop(int(line_args[0]), int(line_args[1])))
+    else:
+      song.phrases.append(get_type_for_name(line_cmd, Phrase, False))
+  return song
+
+def process_song_list(caption, args, lines):
+  song_list = get_type_for_name(caption, SongList, True)
+  song_list.songs = [get_type_for_name(line, Song, False) for line in lines]
+  return song_list
+
+def process_phrase(caption, args, lines):
+  phrase = get_type_for_name(caption, Phrase, True)
+  assert len(lines)==8
+  phrase.patterns = [get_type_for_name(lines[i], Pattern, False) for i in range(8)]
+  return phrase
+  
+kEffectByteLength = [1, 1, 2, 3, 0, 1, 2, 1, 2, 1, 1, 3, 0, 1, 2, 3, 1, 3, 3, 0, 1, 3, 0, 3, 3, 3, 1]
+kEffectNames = ['Instrument', 'Pan', 'PanFade', 'Vibrato', 'VibratoOff',
+                'SongVolume', 'SongVolumeFade', 'Tempo', 'TempoFade',
+                'Transpose', 'ChannelTranpose', 'Tremolo', 'TremoloOff',
+                'Volume', 'VolumeFade', 'Call', 'VibratoFade',
+                'PitchEnvelopeTo', 'PitchEnvelopeFrom', 'PitchEnvelopeOff',
+                'FineTune', 'EchoEnable', 'EchoOff', 'EchoSetup', 'EchoVolumeFade',
+                'PitchSlide', 'PercussionDefine']
+kEffectNamesDict = {a:i for i, a in enumerate(kEffectNames)}
+kKeys  = ['C-', 'C#', 'D-', 'D#', 'E-', 'F-', 'F#', 'G-', 'G#', 'A-', 'A#', 'B-']
+kKeysDict = {a+str(j+1):i+j*12 for i, a in enumerate(kKeys) for j in range(6)}
+kKeysDict['-+-'] = 72
+kKeysDict['---'] = 73
+
+def process_pattern(caption, args, lines):
+  pattern = get_type_for_name(caption, Pattern, True)
+  pattern.lines = []
+  pattern.fallthrough = False
+  for line in lines:
+    assert not pattern.fallthrough
+    line_cmd, *line_args = line.split()
+    if line_cmd == 'Call':
+      assert len(line_args) == 2
+      pattern.lines.append(('Call', (get_type_for_name(line_args[0], Pattern, False),int(line_args[1]) ), None, None))
+    elif line_cmd == 'Fallthrough':
+      pattern.fallthrough = True
+    elif line_cmd in kEffectNamesDict:
+      line_args = [int(a) for a in line_args]
+      pattern.lines.append((line_cmd, line_args, None, None))
+    elif line_cmd in kKeysDict:
+      assert len(line_args) == 2, line_args
+      note_length = None if line_args[0] == '--' else int(line_args[0])
+      volstuff = None if line_args[1] == '--' else int(line_args[1], 16)
+      pattern.lines.append((line_cmd, line_args, note_length, volstuff))
+    else:
+      assert 0, repr(line_cmd)
+  return pattern
+
+def process_sfx_pattern(caption, args, lines):
+  pattern = get_type_for_name(caption, SfxPattern, True)
+  pattern.lines = lines
+  return pattern
+
+def write_sfx_pattern(serializer, o):
+#  print('# Creating %s (%x)' % ( o.name, serializer.addr))
+  for i,line in enumerate(o.lines):
+#    print(line)
+    line_cmd, *line_args = re.split(r' +', line)
+    if line_cmd == 'SetInstrument':
+      assert len(line_args) == 1
+      serializer.write([0xe0, int(line_args[0])])
+    elif line_cmd == 'Restart':
+      serializer.write([0xff])
+      assert i == len(o.lines) - 1
+      return
+    elif line_cmd == 'Fallthrough':
+      assert i == len(o.lines) - 1
+      return
+    elif line_cmd in kKeysDict or line_cmd == '.':
+      if line_args[0] != '--':
+        serializer.write((int(line_args[0]),))
+        if line_args[1] != '---':
+          serializer.write((int(line_args[1]),))
+          if line_args[2] != '---':
+            serializer.write((int(line_args[2]),))
+      if len(line_args) >= 4:
+        assert line_args[3] == 'PitchSlide'
+        if line_cmd == '.':
+          serializer.write([0xf1, int(line_args[4]), int(line_args[5]), int(line_args[6])])
+        else:
+          serializer.write([0xf9, kKeysDict[line_cmd] | 0x80, int(line_args[4]), int(line_args[5]), int(line_args[6])])
+      else:
+        serializer.write([kKeysDict[line_cmd] | 0x80])
+    else:
+      assert 0, repr(line_cmd)
+  serializer.write([0])
+
+def process_sfx_list(caption, args, lines):
+  sfx_list = get_type_for_name(caption, SfxList, True)
+  sfx_list.patterns = []
+  sfx_list.next = []
+  sfx_list.echo = []
+  for line in lines:
+    r = line.split(',')
+    sfx_list.patterns.append(get_type_for_name(r[0], SfxPattern, False))
+    sfx_list.next.append(int(r[1]))
+    if len(r) >= 3:
+      sfx_list.echo.append(int(r[2]))
+  assert len(sfx_list.echo) in (0, len(lines))
+  return sfx_list
+
+def write_sfx_list(serializer, o):
+  for line in o.patterns:
+    serializer.write_reloc_entry(line)
+  for next in o.next:
+    serializer.write([next])
+  for i in o.echo:
+    serializer.write([i])
+
+kGapStartAddrs = (0x2b00, 0x2880, 0xd000)
+
+class Serializer:
+  def __init__(self):
+    self.memory = [None] * 65536
+    self.relocs = []
+    self.addr = None
+
+  def write(self, data):
+    for d in data:
+      assert self.memory[self.addr] == None, '0x%x' % self.addr
+      self.memory[self.addr] = d
+      self.addr += 1
+
+  def write_at(self, a, data):
+    for d in data:
+      self.memory[a] = d
+      a += 1
+
+  def write_word(self, a, v):
+    self.memory[a] = v & 0xff
+    self.memory[a + 1] = v >> 8 & 0xff
+      
+
+  def write_reloc_entry(self, r):
+    self.write([0, 0])
+    if r:
+      self.relocs.append((self.addr - 2, r))
+    
+
+  def write_song(self, song):
+    for phrase in song.phrases:
+      if isinstance(phrase, PhraseLoop):
+        i = self.addr + phrase.jmp * 2
+        self.write([phrase.loops, 0])
+        self.write([i & 0xff, i >> 8])
+      else:
+        self.write_reloc_entry(phrase)
+    self.write([0, 0])
+
+  def write_phrase(self, phrase):
+    for i in range(8):
+      self.write_reloc_entry(phrase.patterns[i])
+
+  def write_song_list(self, song_list):
+    for song in song_list.songs:
+      self.write_reloc_entry(song)
+      
+  def write_pattern(self, patt):
+    for cmd, args, note_length, volstuff in patt.lines:
+      #print(cmd, args, note_length, volstuff)
+      if note_length != None: self.write((note_length, ))
+      if volstuff != None: self.write((volstuff, ))
+      if cmd in kKeysDict:
+        self.write((0x80 | kKeysDict[cmd], ))
+      elif cmd == 'Call':
+        self.write([0xef, 0, 0, int(args[1])])
+        self.relocs.append((self.addr - 3, args[0]))
+      elif cmd in kEffectNamesDict:
+        i = kEffectNamesDict[cmd]
+        assert len(args) == kEffectByteLength[i]
+        self.write([0xe0 + i])
+        self.write(args)
+    if not patt.fallthrough:
+      self.write((0, ))
+
+  def write_obj(self, what):
+ #   print(what.name, self.addr, what.ea)
+ #   print('Writing %s at 0x%x. Curr pos 0x%x' % (what.name, what.ea, 0 if self.addr == None else self.addr))
+    if what.ea != None:
+      
+      if self.addr == None or what.ea in kGapStartAddrs:# or True:#what.ea >= self.addr:
+        self.addr = what.ea
+      elif what.ea != self.addr:
+        print('%s: 0x%x != 0x%x' % (what.name, what.ea, self.addr))
+        assert(0)
+   
+    what.write_addr = self.addr
+    assert self.addr != None
+    if isinstance(what, Phrase):
+      self.write_phrase(what)
+    elif isinstance(what, Pattern):
+      self.write_pattern(what)
+    elif isinstance(what, Song):
+      self.write_song(what)
+    elif isinstance(what, SongList):
+      self.write_song_list(what)
+    elif isinstance(what, SfxPattern):
+      write_sfx_pattern(self, what)
+    elif isinstance(what, SfxList):
+      write_sfx_list(self, what)
+    else:
+      print(type(what))
+      assert(0)
+
+  def write_zeros(self, a, b):
+    while a < b:
+      self.memory[a] = 0
+      a += 1
+
+  def process_relocs(self):
+    for p, r in self.relocs:
+      self.memory[p + 0] = r.write_addr & 0xff
+      self.memory[p + 1] = r.write_addr >> 8
+
+def process_file(file):
+  sorted_ents = []
+  def add_collect(heading, collect):
+    caption, *args = heading.strip('[]').split(' ', 1)
+    if caption.startswith('Song_'):
+      r = process_song(caption, args, collect)
+    elif caption.startswith('Phrase_'):
+      r = process_phrase(caption, args, collect)
+    elif caption.startswith('Pattern_'):
+      r = process_pattern(caption, args, collect)
+    elif caption.startswith('SongList_'):
+      r = process_song_list(caption, args, collect)
+    elif caption.startswith('Sfx_'):
+      r = process_sfx_pattern(caption, args, collect)
+    elif caption.startswith('SfxPort'):
+      r = process_sfx_list(caption, args, collect)
+    else:
+      assert 0
+    sorted_ents.append(r)
+  collect = None
+  heading = None
+  for line in file:
+    line = line.strip()
+    if line == '' or line.startswith('#'): continue
+    if line.startswith('['):
+      if heading != None:
+        add_collect(heading, collect)
+      heading = line
+      collect = []
+      #
+      #print(caption, args)
+    else:
+      collect.append(line.strip('\n'))
+  if heading != None:
+    add_collect(heading, collect)
+  return sorted_ents
+
+def serialize_song(serializer, song, sorted_ents):
+  if song == 'intro':
+#    serializer.write_zeros(0x2a8b, 0x2b00)
+#    serializer.write_zeros(0x3188, 0x4000)
+ #   serializer.write_zeros(0xbaa0, 0xd000)
+ #   serializer.write_zeros(0xfdae, 0x10000)
+ #   serializer.write_zeros(0x2850, 0x2880)
+    serializer.addr = 0x4000
+    sample_to_addr = {}
+    music_info = yaml.safe_load(open('music_info.yaml', 'r'))
+    for i, info in enumerate(music_info['samples']):
+      if info['file'] not in sample_to_addr:
+        sample_to_addr[info['file']] = serializer.addr
+        serializer.write(open('%s.brr' % info['file'], 'rb').read())
+      addr = sample_to_addr[info['file']]
+      serializer.write_word(0x3c00 + i * 4, addr)
+      serializer.write_word(0x3c00 + i * 4 + 2, addr + info['repeat'] // 16 * 9 if 'repeat' in info else serializer.addr)
+    for i in range(6):
+      serializer.write_word(0x3c64 + i * 2, 0xffff)
+    
+    for i, info in enumerate(music_info['instruments']):
+      ea = 0x3d00 + i * 6
+      serializer.memory[ea + 0] = info['sample']
+      serializer.memory[ea + 1] = 0x80 | info['decay'] << 4 | info['attack']
+      serializer.memory[ea + 2] = info['sustain_level'] << 5 | info['sustain_rate']
+      serializer.memory[ea + 3] = info['vxgain']
+      serializer.memory[ea + 4] = info['pitch_base'] >> 8
+      serializer.memory[ea + 5] = info['pitch_base'] & 0xff
+
+    serializer.write_at(0x3D96, music_info['note_gate_off'])
+    serializer.write_at(0x3D9e, music_info['note_volume'])
+
+    for i, info in enumerate(music_info['sfx_instruments']):
+      ea = 0x3e00 + i * 9
+      serializer.memory[ea + 0] = info['voll']
+      serializer.memory[ea + 1] = info['volr']
+      serializer.write_word(ea + 2, info['pitch'])
+      serializer.memory[ea + 4] = info['sample']
+      serializer.memory[ea + 5] = 0x80 | info['decay'] << 4 | info['attack']
+      serializer.memory[ea + 6] = info['sustain_level'] << 5 | info['sustain_rate']
+      serializer.memory[ea + 7] = info['vxgain']
+      serializer.memory[ea + 8] = info['pitch_base']
+
+  serializer.addr = None
+  for e in sorted_ents:
+    serializer.write_obj(e)
+
+  if song == 'indoor':
+    t = types_for_name['Song_0x2880']
+    t.defined = True
+    t.write_addr = 0x2880
+
+
+  for e in types_for_name.values():
+    if not e.defined:
+      raise Exception('Symbol %s not defined' % e.name)
+
+  serializer.process_relocs()
+
+def compare_with_orig(serializer, song):
+  ranges=[]
+  ok = True
+  spc = open('sound/%s.spc' % song, 'rb').read()
+  for i in range(65536):
+    if serializer.memory[i] != None:
+      if serializer.memory[i]!= spc[i]:
+        print('0x%x: 0x%x != 0x%x' % (i, serializer.memory[i], spc[i]))
+        ok = False
+    else:
+#      serializer.memory[i] = spc[i]
+      if len(ranges) and ranges[-1][1] == i:
+        ranges[-1][1] = i + 1
+      else:
+        ranges.append([i, i + 1])
+  if __name__ == "__main__":
+    for a, b in ranges:
+      print('// undefined %x-%x' % (a, b))
+  return ok
+
+def produce_loadable_seq(serializer):
+  r = []
+  # count non zeros
+  start, i = 0, 0
+  while start < 0x10000:    
+    while i < 0x10000 and serializer.memory[i] != None:
+      i += 1
+    j = i
+    while i < 0x10000 and serializer.memory[i] == None:
+      i += 1
+    
+    if j == start:
+      start = i
+      continue
+    r.extend([(j - start) & 0xff, (j - start) >> 8, start & 0xff, start >> 8])
+    r.extend(serializer.memory[start:j])
+#    print('copy 0x%x - 0x%x (%d)' % (start, j, j - start))
+    start = i
+  r.extend([0, 0])
+  return r
+
+def print_song(song):
+  global types_for_name
+  types_for_name = {}
+
+  serializer = Serializer()
+
+  sorted_ents = process_file(open('sound_%s.txt' % song, 'r'))
+  if song == 'intro':
+    sorted_ents.extend(process_file(open('sfx.txt' , 'r')))
+
+  serialize_song(serializer, song, sorted(sorted_ents, key = lambda x: x.ea))
+
+  r = produce_loadable_seq(serializer)
+
+  result = 'kSoundBank_%s' % song, r
+
+  if not compare_with_orig(serializer, song):
+    raise Exception('compare failed')
+
+  return result
+
+if __name__ == "__main__":
+  if len(sys.argv) == 1:
+    for song in ['intro', 'indoor', 'ending']:
+      print_song(song, sys.stdout)  
+  else:
+    print_song(sys.argv[1], sys.stdout)
--- /dev/null
+++ b/assets/compile_resources.py
@@ -1,0 +1,827 @@
+import sys
+import text_compression
+import util
+from PIL import Image
+import yaml
+import tables
+import compile_music
+import array, hashlib, struct
+from util import cache
+import sprite_sheets
+import argparse
+import os
+
+def flatten(xss):
+    return [x for xs in xss for x in xs]
+  
+def invert_dict(xs):
+  return {s:i for i,s in xs.items()}
+
+assets = {}
+
+def add_asset_uint8(name, data):
+  assert name not in assets
+  assets[name] = ('uint8', bytes(array.array('B', data)))
+
+def add_asset_uint16(name, data):
+  assert name not in assets
+  assets[name] = ('uint16', bytes(array.array('H', data)))
+
+def add_asset_int8(name, data):
+  assert name not in assets
+  assets[name] = ('int8', bytes(array.array('b', data)))
+
+def add_asset_int16(name, data):
+  assert name not in assets
+  assets[name] = ('int16', bytes(array.array('h', data)))
+
+def add_asset_packed(name, data):
+  assert name not in assets
+  assets[name] = ('packed', pack_arrays(data))
+
+def print_map32_to_map16():
+  tab = {}
+  for line in open('map32_to_map16.txt'):
+    line = line.strip()
+    x, xs = line.split(':', 1)
+    tab[int(x)] = [int(t) for t in xs.split(',')]
+
+  def pack(*a):
+    res=[0] * 6
+    res[0] = a[0] & 0xff
+    res[1] = a[1] & 0xff
+    res[2] = a[2] & 0xff
+    res[3] = a[3] & 0xff
+    res[4] = (a[0] >> 8) << 4 | (a[1] >> 8)
+    res[5] = (a[2] >> 8) << 4 | (a[3] >> 8)
+    return res    
+
+  res = [[],[],[],[]]
+  for i in range(0, len(tab), 4):
+    for j in range(4):
+      res[j].extend(pack(tab[i][j], tab[i+1][j], tab[i+2][j], tab[i+3][j]))
+
+  add_asset_uint8('kMap32ToMap16_0', res[0])
+  add_asset_uint8('kMap32ToMap16_1', res[1])
+  add_asset_uint8('kMap32ToMap16_2', res[2])
+  add_asset_uint8('kMap32ToMap16_3', res[3])
+
+def compress_dialogue(fname, lang):
+  lines = []
+  for line in open(fname, encoding='utf8').read().splitlines():
+    a, b = line.split(': ', 1)
+    lines.append(b)
+  return text_compression.compress_strings(lines, lang)
+
+def compress_store(r):
+  rr = []
+  j, jend = 0, len(r)
+  while j < jend:
+    n = min(jend - j, 1024)
+    rr.append(0xe0 | (n - 1) >> 8)
+    rr.append((n - 1) & 0xff)
+    rr.extend(r[j:j+n])
+    j += n
+  rr.append(0xff)
+  return rr
+  
+# Pack arrays and determine automatically the index size
+def pack_arrays(arr):
+  if len(arr) == 0:
+    return b''
+  all_offs, offs = [], 0
+  for i in range(len(arr) - 1):
+    offs += len(arr[i])
+    all_offs.append(offs)
+  if offs < 65536 and len(arr) <= 8192:
+    return b''.join([struct.pack('H', i) for i in all_offs] + arr + [struct.pack('H', len(arr) - 1)])
+  else:
+    return b''.join([struct.pack('I', i) for i in all_offs] + arr + [struct.pack('H', 8192 + len(arr) - 1)])
+
+def print_images(args):
+  sprsheet = sprite_sheets.load_sprite_sheets() if args.sprites_from_png else None
+
+  all = []
+  for i in range(108):
+    if sprsheet != None and i < 103:
+      all.append(sprsheet.encode_sheet_in_snes_format(i))
+    elif i < 12:
+      all.append(bytes(ROM.get_bytes(tables.kCompSpritePtrs[i], 0x600)))   
+    else:
+      decomp, comp_len = util.decomp(tables.kCompSpritePtrs[i], ROM.get_byte, False, True)
+      all.append(bytes(ROM.get_bytes(tables.kCompSpritePtrs[i], comp_len)))
+  add_asset_packed('kSprGfx', all)
+
+  all = []
+  for i in range(len(tables.kCompBgPtrs)):
+    decomp, comp_len = util.decomp(tables.kCompBgPtrs[i], ROM.get_byte, False, True)
+    all.append(bytes(ROM.get_bytes(tables.kCompBgPtrs[i], comp_len)))
+  add_asset_packed('kBgGfx', all)
+
+def print_dialogue(args):
+  from text_compression import dialogue_filename, kLanguages
+
+  languages = ['us']
+  if args.languages:
+    for a in args.languages.split(','):
+      if a in languages or a not in kLanguages:
+        raise Exception(f'Language {a} is not valid')
+      name = dialogue_filename(a)
+      if not os.path.exists(name):
+        raise Exception(f'{name} not found. You need to extract it with --extract-dialogue using the ROM of that language.')
+      languages.append(a)
+
+  all_langs, all_fonts, mappings = [], [], []
+  for i, lang in enumerate(languages):
+    dict_packed = pack_arrays(text_compression.encode_dictionary(lang))
+    dialogue_packed = pack_arrays(compress_dialogue(dialogue_filename(lang), lang))
+    all_langs.append(pack_arrays([dict_packed, dialogue_packed]))
+    font_data, font_width = sprite_sheets.encode_font_from_png(lang)
+    all_fonts.append(pack_arrays([font_data, font_width]))
+    flags = text_compression.uses_new_format(lang)
+    if i != 0: flags |= 2 # no us rom match?
+    mappings.append(pack_arrays([lang.encode('utf8'), bytearray([i, i, flags])]))
+  add_asset_packed('kDialogue', all_langs)
+  add_asset_packed('kDialogueFont', all_fonts)
+  add_asset_packed('kDialogueMap', mappings)
+
+def print_misc(args):
+  add_asset_uint8('kOverworldMapGfx', ROM.get_bytes(0x18c000, 0x4000))
+  add_asset_uint8('kLightOverworldTilemap', ROM.get_bytes(0xac727, 4096))
+  add_asset_uint8('kDarkOverworldTilemap', ROM.get_bytes(0xaD727, 1024))
+
+  add_asset_uint16('kPredefinedTileData', ROM.get_words(0x9B52, 6438))
+
+  add_asset_uint16('kMap16ToMap8', ROM.get_words(0x8f8000, 3752 * 4))
+
+  add_asset_uint8('kGeneratedWishPondItem', ROM.get_bytes(0x888450, 256))
+  add_asset_uint8('kGeneratedBombosArr', ROM.get_bytes(0x8890FC, 256))
+
+  add_asset_uint8('kGeneratedEndSequence15', ROM.get_bytes(0x8ead25, 256))
+  add_asset_uint8('kEnding_Credits_Text', ROM.get_bytes(0x8EB178, 1989))
+  add_asset_uint16('kEnding_Credits_Offs', ROM.get_words(0x8EB93d, 394))
+  add_asset_uint16('kEnding_MapData', ROM.get_words(0x8EB038, 160))
+  add_asset_uint16('kEnding0_Offs', ROM.get_words(0x8EC2E1, 17))
+  add_asset_uint8('kEnding0_Data', ROM.get_bytes(0x8EBF4C, 917))
+
+  add_asset_uint16('kPalette_DungBgMain', ROM.get_words(0x9BD734, 1800))
+  add_asset_uint16('kPalette_MainSpr', ROM.get_words(0x9BD218, 120))
+
+  add_asset_uint16('kPalette_ArmorAndGloves', sprite_sheets.override_armor_palette or ROM.get_words(0x9BD308, 75))
+  add_asset_uint16('kPalette_Sword', ROM.get_words(0x9BD630, 12))
+  add_asset_uint16('kPalette_Shield', ROM.get_words(0x9BD648, 12))
+
+  add_asset_uint16('kPalette_SpriteAux3', ROM.get_words(0x9BD39E, 84))
+  add_asset_uint16('kPalette_MiscSprite_Indoors', ROM.get_words(0x9BD446, 77))
+  add_asset_uint16('kPalette_SpriteAux1', ROM.get_words(0x9BD4E0, 168))
+
+  add_asset_uint16('kPalette_OverworldBgMain', ROM.get_words(0x9BE6C8, 210))
+  add_asset_uint16('kPalette_OverworldBgAux12', ROM.get_words(0x9BE86C, 420))
+  add_asset_uint16('kPalette_OverworldBgAux3', ROM.get_words(0x9BE604, 98))
+  add_asset_uint16('kPalette_PalaceMapBg', ROM.get_words(0x9BE544, 96))
+  add_asset_uint16('kPalette_PalaceMapSpr', ROM.get_words(0x9BD70A, 21))
+  add_asset_uint16('kHudPalData', ROM.get_words(0x9BD660, 64))
+
+  add_asset_uint16('kOverworldMapPaletteData', ROM.get_words(0x8ADB27, 256))
+
+@cache
+def load_overworld_yaml(room):
+  return yaml.safe_load(open('overworld/overworld-%d.yaml' % room, 'r'))
+    
+def print_overworld():
+  r = []
+  for i in range(160):
+    addr = ROM.get_24(0x82F94D + i * 3)
+    decomp, comp_len = util.decomp(addr, ROM.get_byte, True, True)
+    r.append(bytes(ROM.get_bytes(addr, comp_len)))
+  add_asset_packed('kOverworld_Hibytes_Comp', r)
+
+  r = []
+  for i in range(160):
+    addr = ROM.get_24(0x82FB2D + i * 3)
+    decomp, comp_len = util.decomp(addr, ROM.get_byte, True, True)
+    r.append(bytes(ROM.get_bytes(addr, comp_len)))
+  add_asset_packed('kOverworld_Lobytes_Comp', r)
+
+def is_area_head(i):
+  return i >= 128 or ROM.get_byte(0x82A5EC + (i & 63)) == (i & 63)
+
+class OutArrays:
+  def __init__(self):
+    self.arrs = []
+  def add(self, type, name, size, initializer = None, items_per_line = 16):
+    t = [initializer] * size
+    self.arrs.append((type, name, t, items_per_line))
+    setattr(self, name, t)
+  def write(self):
+    for type, name, arr, items_per_line in self.arrs:
+      for i, j in enumerate(arr):
+        assert isinstance(j, int), (name, i, j, arr)
+      if type == 'uint8':
+        add_asset_uint8(name, arr)
+      elif type == 'uint16':
+        add_asset_uint16(name, arr)
+      elif type == 'int8':
+        add_asset_int8(name, arr)
+      elif type == 'int16':
+        add_asset_int16(name, arr)
+      else:
+        assert 0, type
+    
+def print_overworld_tables():
+  A = OutArrays()
+  
+  A.add('uint8', 'kOverworldMapIsSmall', 192, initializer = 0, items_per_line = 8)
+  A.add('uint8', 'kOverworldAuxTileThemeIndexes', 128, items_per_line = 8)
+  A.add('uint8', 'kOverworldBgPalettes', 136, items_per_line = 8)
+  A.add('uint16', 'kOverworld_SignText', 128, items_per_line = 8)
+  A.add('uint8', 'kOwMusicSets', 256, items_per_line = 8)
+  A.add('uint8', 'kOwMusicSets2', 96, items_per_line = 8)
+  
+  def get_music_byte(h, tag):
+    return tables.kMusicNamesRev[h['music'][tag]] | tables.kAmbientSoundNameRev[h['ambient'][tag]] << 4
+
+  def get_loadoffs(c, d):
+    x, y = c[0] >> 4, c[1] >> 4
+    x += d[0]
+    y += d[1]
+    return (y&0x3f) << 7 | (x&0x3f) << 1
+
+  def awrite(arr, area, key, value):
+    arr[key] = value
+    if area < 128 and not A.kOverworldMapIsSmall[area]:
+      arr[key + 1], arr[key + 8], arr[key + 9] = value, value, value
+      
+  loaded_areas = [(i, load_overworld_yaml(i)) for i in range(160) if is_area_head(i)]
+
+  for i,y in loaded_areas:
+    h = y['Header']
+    A.kOverworldMapIsSmall[i] = {'small':1, 'big':0}[h['size']]
+    if i < len(A.kOverworldAuxTileThemeIndexes): awrite(A.kOverworldAuxTileThemeIndexes, i, i, h['gfx'])
+    if i < len(A.kOverworldBgPalettes): awrite(A.kOverworldBgPalettes, i, i, h['palette'])
+    if i < len(A.kOverworld_SignText): awrite(A.kOverworld_SignText, i, i, h['sign_text'])
+    if i < 64:
+      awrite(A.kOwMusicSets, i, i, get_music_byte(h, 'beginning'))
+      awrite(A.kOwMusicSets, i, i + 64, get_music_byte(h, 'zelda'))
+      awrite(A.kOwMusicSets, i, i + 128, get_music_byte(h, 'sword'))
+      awrite(A.kOwMusicSets, i, i + 192, get_music_byte(h, 'agahnim'))
+    elif i < 64 + 96:
+      awrite(A.kOwMusicSets2, i, i - 64, get_music_byte(h, 'agahnim'))
+
+  for a in ['kBirdTravel_ScreenIndex', 'kBirdTravel_Map16LoadSrcOff', 'kBirdTravel_ScrollX',
+            'kBirdTravel_ScrollY', 'kBirdTravel_LinkXCoord', 'kBirdTravel_LinkYCoord',
+            'kBirdTravel_CameraXScroll', 'kBirdTravel_CameraYScroll']:
+    A.add('uint16', a, 17)
+  A.add('int8', 'kBirdTravel_Unk1', 17)
+  A.add('int8', 'kBirdTravel_Unk3', 17)
+  A.add('uint16', 'kWhirlpoolAreas', 8)
+
+  next_whirlpool_id = 0
+  for i, y in loaded_areas:
+    for t in y['Travel']:
+      if 'bird_travel_id' in t:
+        j = t['bird_travel_id']
+      else:
+        A.kWhirlpoolAreas[next_whirlpool_id] = t['whirlpool_src_area']
+        j = next_whirlpool_id + 9
+        next_whirlpool_id += 1
+      base_x, base_y = (i & 7) << 9, (i & 56) << 6
+      A.kBirdTravel_ScreenIndex[j] = i
+      A.kBirdTravel_Map16LoadSrcOff[j] = get_loadoffs(t['scroll_xy'], t['load_xy'])
+      A.kBirdTravel_ScrollX[j] = t['scroll_xy'][0] + base_x
+      A.kBirdTravel_ScrollY[j] = t['scroll_xy'][1] + base_y
+      A.kBirdTravel_LinkXCoord[j] = t['xy'][0] + base_x 
+      A.kBirdTravel_LinkYCoord[j] = t['xy'][1] + base_y
+      A.kBirdTravel_CameraXScroll[j] = t['camera_xy'][0] + base_x 
+      A.kBirdTravel_CameraYScroll[j] = t['camera_xy'][1] + base_y
+      A.kBirdTravel_Unk1[j] = t['unk'][0]
+      A.kBirdTravel_Unk3[j] = t['unk'][1]
+
+  A.add('uint16', 'kOverworld_Entrance_Area', 129)
+  A.add('uint16', 'kOverworld_Entrance_Pos', 129)
+  A.add('uint8', 'kOverworld_Entrance_Id', 129)
+
+  for i, y in loaded_areas:
+    for e in y['Entrances']:
+      j = e['index']
+      assert A.kOverworld_Entrance_Id[j] == None
+      A.kOverworld_Entrance_Area[j] = i
+      A.kOverworld_Entrance_Id[j] = e['entrance_id']
+      A.kOverworld_Entrance_Pos[j] = e['x'] << 1 | e['y'] << 7
+
+  A.add('uint16', 'kFallHole_Area', 19)
+  A.add('uint16', 'kFallHole_Pos', 19)
+  A.add('uint8', 'kFallHole_Entrances', 19)
+      
+  holes = []
+  for i, y in loaded_areas:
+    if 'Holes' not in y: continue
+    for e in y['Holes']:
+      x, y, j = e['x'], e['y'], e['entrance_id']
+      holes.append((j, x << 1 | ((y - 8) & 0x3f) << 7, i))
+  for i, (entrance, pos, area) in enumerate(sorted(holes)):
+    A.kFallHole_Area[i] = area
+    A.kFallHole_Pos[i] = pos
+    A.kFallHole_Entrances[i] = entrance
+
+  A.add('uint8', 'kExitData_ScreenIndex', 79)
+  for a in ['kExitDataRooms', 'kExitData_Map16LoadSrcOff', 'kExitData_ScrollX',
+            'kExitData_ScrollY', 'kExitData_XCoord', 'kExitData_YCoord',
+            'kExitData_CameraXScroll', 'kExitData_CameraYScroll']:
+    A.add('uint16', a, 79)
+  A.add('uint16', 'kExitData_NormalDoor', 79, initializer = 0)
+  A.add('uint16', 'kExitData_FancyDoor', 79, initializer = 0)
+  A.add('int8', 'kExitData_Unk1', 79)
+  A.add('int8', 'kExitData_Unk3', 79)
+
+  A.add('uint16', 'kSpExit_Top', 16, initializer = 0)
+  A.add('uint16', 'kSpExit_Bottom', 16, initializer = 0)
+  A.add('uint16', 'kSpExit_Left', 16, initializer = 0)
+  A.add('uint16', 'kSpExit_Right', 16, initializer = 0)
+  A.add('int16', 'kSpExit_Tab4', 16, initializer = 0)
+  A.add('int16', 'kSpExit_Tab5', 16, initializer = 0)
+  A.add('int16', 'kSpExit_Tab6', 16, initializer = 0)
+  A.add('int16', 'kSpExit_Tab7', 16, initializer = 0)
+  A.add('uint16', 'kSpExit_LeftEdgeOfMap', 16, initializer = 0)
+  A.add('uint8', 'kSpExit_Dir', 16, initializer = 0)
+  A.add('uint8', 'kSpExit_SprGfx', 16, initializer = 0)
+  A.add('uint8', 'kSpExit_AuxGfx', 16, initializer = 0)
+  A.add('uint8', 'kSpExit_PalBg', 16, initializer = 0)
+  A.add('uint8', 'kSpExit_PalSpr', 16, initializer = 0)
+  
+  for i, y in loaded_areas:
+    for e in y['Exits']:
+      j = e['index']
+      base_x, base_y = (i & 7) << 9, (i & 56) << 6
+      assert A.kExitData_ScreenIndex[j] == None
+      A.kExitData_ScreenIndex[j] = i
+      room = e['room']
+      A.kExitDataRooms[j] = e['room']
+      A.kExitData_Map16LoadSrcOff[j] = get_loadoffs(e['scroll_xy'], e['load_xy'])
+      A.kExitData_ScrollX[j] = e['scroll_xy'][0] + base_x
+      A.kExitData_ScrollY[j] = e['scroll_xy'][1] + base_y
+      A.kExitData_XCoord[j] = e['xy'][0] + base_x
+      A.kExitData_YCoord[j] = e['xy'][1] + base_y
+      A.kExitData_CameraXScroll[j] = e['camera_xy'][0] + base_x 
+      A.kExitData_CameraYScroll[j] = e['camera_xy'][1] + base_y
+      A.kExitData_Unk1[j] = e['unk'][0]
+      A.kExitData_Unk3[j] = e['unk'][1]
+      door = e.get('door')
+      if door != None:
+        if door[0] in ('bombable', 'wooden'):
+          A.kExitData_NormalDoor[j] = door[1] << 1 | door[2] << 7 | (0x8000 if door[0] == 'bombable' else 0)
+        elif door[0] in ('palace', 'sanctuary'):
+          A.kExitData_FancyDoor[j] = door[1] << 1 | door[2] << 7 | (0x8000 if door[0] == 'palace' else 0)
+        else:
+          assert e[0] == 'none'
+      se = e.get('special_exit')
+      if se:
+        j = room - 0x180
+        A.kSpExit_Dir[j] = se['dir'] * 2
+        A.kSpExit_SprGfx[j] = se['spr_gfx']
+        A.kSpExit_AuxGfx[j] = se['aux_gfx']
+        A.kSpExit_PalBg[j] = se['pal_bg']
+        A.kSpExit_PalSpr[j] = se['pal_spr']
+        A.kSpExit_Top[j] = se['top']
+        A.kSpExit_Bottom[j] = se['bottom']
+        A.kSpExit_Left[j] = se['left']
+        A.kSpExit_Right[j] = se['right']
+        A.kSpExit_LeftEdgeOfMap[j] = se['left_edge_of_map']
+        A.kSpExit_Tab4[j] = se['unk4']
+        A.kSpExit_Tab5[j] = se['unk5']
+        A.kSpExit_Tab6[j] = se['unk6']
+        A.kSpExit_Tab7[j] = se['unk7']
+
+
+  A.add('uint16', 'kOverworldSecrets_Offs', 128, initializer = None)
+  A.add('uint8', 'kOverworldSecrets', 0)
+  for i, y in loaded_areas:
+    if len(y['Items']):
+      assert i < 128
+      j = len(A.kOverworldSecrets)
+      awrite(A.kOverworldSecrets_Offs, i, i, j)
+      for e in y['Items']:
+        pos = e[0] << 1 | e[1] << 7
+        item = tables.kSecretNamesRev[e[2]]
+        A.kOverworldSecrets.extend([pos & 0xff, pos >> 8, item])
+      A.kOverworldSecrets.extend([0xff, 0xff])
+  for i in range(128):
+    if A.kOverworldSecrets_Offs[i] == None:
+      A.kOverworldSecrets_Offs[i] = len(A.kOverworldSecrets) - 2
+
+  A.add('uint16', 'kOverworldSpriteOffs', 144 * 3, initializer = 0)
+  A.add('uint8', 'kOverworldSprites', 0)
+  A.add('uint8', 'kOverworldSpriteGfx', 256)
+  A.add('uint8', 'kOverworldSpritePalettes', 256)
+  A.kOverworldSprites.append(0xff)
+  def do_sprite_range(start, end, stagename, sprite_stage_idxs, infostage):
+    for i, y in loaded_areas:
+      if i < start or i >= end: continue
+      info = y[stagename]['info']
+      if i < 128:
+        awrite(A.kOverworldSpriteGfx, i, (i & 63) + infostage * 64, info['gfx'])
+        awrite(A.kOverworldSpritePalettes, i, (i & 63) + infostage * 64, info['palette'])
+      if len(y[stagename]['sprites']):
+        for stage in sprite_stage_idxs:
+          A.kOverworldSpriteOffs[stage * 144 + i] = len(A.kOverworldSprites)
+        for e in y[stagename]['sprites']:
+          A.kOverworldSprites.extend([e[1], e[0], tables.kSpriteNamesRev[e[2]]])
+        A.kOverworldSprites.append(0xff)
+  do_sprite_range(0, 64, 'Sprites.Beginning', [0], 0)
+  do_sprite_range(0, 64, 'Sprites.FirstPart', [1], 1)
+  do_sprite_range(0, 64, 'Sprites.SecondPart', [2], 2)
+  do_sprite_range(64, 144, 'Sprites', [1, 2], 3)
+
+  A.write()
+  add_asset_uint8('kMap8DataToTileAttr', ROM.get_bytes(0x8E9459, 512))
+  add_asset_uint8('kSomeTileAttr', ROM.get_bytes(0x9bf110, 3824))
+
+
+def print_dungeon_map():
+  r, r2 = [], []
+  for i in range(14):
+    kSizes = [75, 125, 50, 75, 175, 75, 50, 75, 50, 200, 150, 75, 100, 200]
+    addr = 0xa0000 + ROM.get_word(0x8AF605 + i * 2)
+    b = ROM.get_bytes(addr, kSizes[i])
+    nonzero_bytes = len(b) - b.count(0xf)
+    r.append(bytes(b))
+    addr = 0xa0000 + ROM.get_word(0x8AFBE4 + i * 2)
+    b = ROM.get_bytes(addr, nonzero_bytes)
+    r2.append(bytes(b))
+    
+  add_asset_packed('kDungMap_FloorLayout', r)
+  add_asset_packed('kDungMap_Tiles', r2)
+
+
+@cache
+def load_dungeon_yaml(room):
+  return yaml.safe_load(open('dungeon/dungeon-%d.yaml' % room, 'r'))
+  
+def print_dungeon_sprites():
+  offsets=[0 for i in range(320)]
+  data = [0, 0xff]
+  for i in range(320):
+    y = load_dungeon_yaml(i)
+    sortmode = y['Header']['sort_sprites']
+    if len(y['Sprites']) == 0 and sortmode == 0:
+      continue
+    offsets[i] = len(data)
+    data.append(sortmode)
+    for s in y['Sprites']:
+      xx, yy, f, name = s[:4]
+      f = {'upper' : 0, 'lower' : 1}[f]
+      assert xx >= 0 and xx <= 0x1f
+      assert yy >= 0 and yy <= 0x1f
+
+      # parse out subcode
+      ss = 0
+      if len(name) > 2 and name[2] == '.':
+        j = name.index('-')
+        ss = int(name[3:j])
+        name = name[0:2] + name[j:]
+
+      name = tables.kSpriteName2Idx[name]
+      if name >= 0x100:
+        data.extend((f << 7 | 0 << 5 | yy, xx | 7 << 5, name & 0xff))
+      else:
+        data.extend((f << 7 | (ss >> 3) << 5 | yy, xx | (ss & 7) << 5, name))
+      if len(s) == 5:
+        kDropTypesToCode = {'drop_key' : [0xfe, 0, 0xe4], 'drop_big_key' : [0xfd, 0, 0xe4]}
+        data.extend(kDropTypesToCode[s[-1]])
+        
+    data.append(0xff)
+  add_asset_uint8('kDungeonSprites', data)
+  add_asset_uint16('kDungeonSpriteOffs', offsets)
+
+def print_dungeon_secrets():
+  result = [None] * 640
+  for i in range(320):
+    y = load_dungeon_yaml(i)
+    def fixone(s):
+      x, y, data = s[0], s[1], tables.kSecretNamesRev[s[2]]
+      pos = (x + y * 64) * 2
+      return [pos & 0xff, pos >> 8, data]
+    if len(y['Secrets']):
+      result[i*2+0] = len(result) & 0xff
+      result[i*2+1] = len(result) >> 8
+      for a in y['Secrets']:
+        result.extend(fixone(a))
+        
+      result.extend([0xff, 0xff])
+  for i in range(320):
+    if result[i*2+0] == None:
+      l = (len(result) - 2)
+      result[i*2+0] = l & 0xff
+      result[i*2+1] = l >> 8
+  add_asset_uint8('kDungeonSecrets', result)
+
+def append_scan_bytes(big, little):
+  for n in range(len(little), -1, -1):
+    if n == 0 or big[-n:] == little[:n]:
+      offset = len(big) - n
+      big.extend(little[n:])
+      return offset
+  
+def print_dungeon_rooms():
+  def print_layer(objs, doors):
+    door_offset = None
+    for o in objs:
+      if o['n'] in tables.kType0Names_rev:
+        index = tables.kType0Names_rev[o['n']] # 0 - 0xf7
+        w = int(o['s'][0])
+        h = int(o['s'][2])
+        assert w >= 0 and w <= 3 and h >= 0 and h <= 3
+        p0 = o['x'] * 4 + w
+        p1 = o['y'] * 4 + h
+        p2 = index
+      elif o['n'] in tables.kType1Names_rev:
+        index = tables.kType1Names_rev[o['n']]
+        p0 = o['x'] * 4 + (index >> 0 & 3)
+        p1 = o['y'] * 4 + (index >> 2 & 3)
+        p2 = (index >> 4) + 0xf8
+      elif o['n'] in tables.kType2Names_rev:
+        index = tables.kType2Names_rev[o['n']]
+        x, y = o['x'], o['y']
+        #111111xx xxxxyyyy yyiiiiii
+        p0 = 0xfc + (x >> 4 & 3)
+        p1 = (x << 4 & 0xf0) | (y >> 2 & 0x0f)
+        p2 = index | (y << 6 & 0xc0)
+      else:
+        raise Exception('item %s not found' % o['n'])
+      data.extend((p0, p1, p2))
+    if doors != None:
+      data.extend([0xf0, 0xff])
+      door_offset = len(data)
+      for d in doors:
+        data.extend((d['dir'] | d['pos'] << 4, d['type']))
+    data.extend([0xff, 0xff])
+    return door_offset
+
+  def get_room_header(y):
+    h = y['Header']
+    p7 = h['hole0_dest'][1] | h['stair0_dest'][1] << 2 | h['stair1_dest'][1] << 4 | h['stair2_dest'][1] << 6
+    p8 = h['stair3_dest'][1]
+    return [tables.kBg2_rev[h['bg2']] << 5 | tables.kCollisionNames_rev[h['collision']] << 2 | h['lights_out'],
+            h['palette'],
+            h['blockset'],
+            h['enemyblk'],
+            tables.kEffectNames_rev[h['effect']],
+            tables.kTagNames_rev[h['tag0']],
+            tables.kTagNames_rev[h['tag1']],
+            p7,
+            p8,
+            h['hole0_dest'][0],
+            h['stair0_dest'][0],
+            h['stair1_dest'][0],
+            h['stair2_dest'][0],
+            h['stair3_dest'][0]]
+
+  data = []
+  offsets = [0]*320
+  door_offsets = [0]*320
+  room_headers = []
+  header_offsets = [0] * 320
+  chests = []
+  entrances = [None] * 133
+  starting_points = [None] * 7
+  sign_texts = [0] * 320
+  pits_hurt_player = []
+  
+  for i in range(320):
+    y = load_dungeon_yaml(i)
+    h = y['Header']
+    if h['pits_hurt_player']: pits_hurt_player.append(i)
+    offsets[i]=len(data)
+    data.append(h['floor1'] + h['floor2'] * 16)
+    data.append(h['layout'] * 4 + h['start_quadrant'])
+    print_layer(y['Layer1'], y.get('Layer1.doors'))
+    print_layer(y['Layer2'], y.get('Layer2.doors'))
+    door_offsets[i] = print_layer(y['Layer3'], y.get('Layer3.doors') or [])
+    header_offsets[i] = append_scan_bytes(room_headers, get_room_header(y))
+    sign_texts[i] = h['tele_msg']
+    for a in y['Chests']:
+      if isinstance(a, int):
+        chests.extend([i & 0xff, i >> 8, a])
+      else:
+        assert a.endswith('!')
+        chests.extend([i & 0xff, (i >> 8) | 0x80, int(a[:-1])])
+    for e in y['Entrances']:
+      a = e['entrance_index']
+      e['room'] = i
+      assert entrances[a] == None
+      entrances[a] = e
+    if 'StartingPoints' in y:
+      for e in y['StartingPoints']:
+        a = e['starting_point_index']
+        e['room'] = i
+        assert starting_points[a] == None
+        starting_points[a] = e
+  for i in range(133):
+    if entrances[i] == None:
+      raise Exception('Entrance %d not defined' % i)
+  for i in range(7):
+    if starting_points[i] == None:
+      raise Exception('Starting point %d not defined' % i)
+
+  def print_entrance_info(entrances, prefix):
+    def get_rc(a):
+      rep, room, quads, xy = a.get('repair_scroll_bounds'), a['room'], a['quadrants'], a['player_xy']
+      if rep == None: rep = (0, 0, 0, 0, 0, 0, 0, 0)
+      base_x = (room & 0xf) * 2
+      base_y = (room >> 4) * 2
+      ym = (xy[1] & 0x100) >> 8
+      xm = (xy[0] & 0x100) >> 8
+      qqq = xm if room >= 242 and quads[0] == 'single_x' else 0
+      l = [base_y + ym, base_y, base_y + ym, base_y + 1,
+           base_x + xm, base_x + qqq, base_x + xm, base_x + qqq + 1]
+      return [a+b for a,b in zip(l, rep)]
+    def get_palace(a):
+      i = tables.kPalaceNames.index(a)
+      return -1 if i == 0 else (i - 1) * 2
+    def get_quadrant1(a):
+      return ['single_x', 'double_x'].index(a[0]) * 0x20 + ['single_y', 'double_y'].index(a[1]) * 0x2
+    def get_quadrant2(a):
+      kScrollNames = { 'upper_left' : 0, 'lower_left' : 2, 'upper_right' : 16, 'lower_right' : 18 }
+      return kScrollNames[a[2]]
+    def get_exit_door(a):
+      if a[0] == 'none': return 0
+      if a[0] == 'none_0xffff': return 65535
+      return ['wooden', 'bombable'].index(a[0]) << 15 | a[1] << 1 | a[2] << 7
+            
+    add_asset_uint16(prefix+'rooms', [a['room'] for a in entrances])
+    add_asset_uint8(prefix+'relativeCoords', flatten([get_rc(a) for a in entrances]))
+    def get_base_x(a): return ((a['room'] & 0x00f) << 9)
+    def get_base_y(a): return ((a['room'] & 0x1f0) << 5)
+    add_asset_uint16(prefix+'scrollX', [a['scroll_xy'][0] + get_base_x(a) for a in entrances])
+    add_asset_uint16(prefix+'scrollY', [a['scroll_xy'][1] + get_base_y(a) for a in entrances])
+    add_asset_uint16(prefix+'playerX', [a['player_xy'][0] + get_base_x(a) for a in entrances])
+    add_asset_uint16(prefix+'playerY', [a['player_xy'][1] + get_base_y(a) for a in entrances])
+    add_asset_uint16(prefix+'cameraX', [a['camera_xy'][0] for a in entrances])
+    add_asset_uint16(prefix+'cameraY', [a['camera_xy'][1] for a in entrances])
+    add_asset_uint8(prefix+'blockset', [a['blockset'] for a in entrances])
+    add_asset_int8(prefix+'floor', [a['floor'] for a in entrances])
+    add_asset_int8(prefix+'palace', [get_palace(a['palace']) for a in entrances])
+    add_asset_uint8(prefix+'doorwayOrientation', [a['doorway_orientation'] for a in entrances])
+    add_asset_uint8(prefix+'startingBg', [a['plane'] + a['ladder_level'] * 16 for a in entrances])
+    add_asset_uint8(prefix+'quadrant1', [get_quadrant1(a['quadrants']) for a in entrances])
+    add_asset_uint8(prefix+'quadrant2', [get_quadrant2(a['quadrants']) for a in entrances])
+    add_asset_uint16(prefix+'doorSettings', [get_exit_door(a['house_exit_door']) for a in entrances])
+    if prefix == 'kStartingPoint_':
+      add_asset_uint8(prefix+'entrance', [a['associated_entrance_index'] for a in entrances])
+    m = invert_dict(tables.kMusicNames)
+    add_asset_uint8(prefix+'musicTrack', [m[a['music']] for a in entrances])
+    
+
+  add_asset_uint8('kDungeonRoom', data)
+  add_asset_uint16('kDungeonRoomOffs', offsets)
+  add_asset_uint16('kDungeonRoomDoorOffs', door_offsets)
+  add_asset_uint8('kDungeonRoomHeaders', room_headers)
+  add_asset_uint16('kDungeonRoomHeadersOffs', header_offsets)
+  add_asset_uint8('kDungeonRoomChests', chests)
+  add_asset_uint16('kDungeonRoomTeleMsg', sign_texts)
+  add_asset_uint16('kDungeonPitsHurtPlayer', pits_hurt_player)
+  
+  print_entrance_info(entrances, 'kEntranceData_')
+  print_entrance_info(starting_points, 'kStartingPoint_')
+
+  data = []
+  offsets = [0] * 8
+  default_yaml = yaml.safe_load(open('dungeon/default_rooms.yaml', 'r'))
+  for i in range(len(offsets)):
+    offsets[i] = len(data)
+    print_layer(default_yaml['Default%d' % i], None)
+  add_asset_uint8('kDungeonRoomDefault', data)
+  add_asset_uint16('kDungeonRoomDefaultOffs', offsets)
+
+  data = []
+  offsets = [0] * 19
+  overlay_yaml = yaml.safe_load(open('dungeon/overlay_rooms.yaml', 'r'))
+  for i in range(len(offsets)):
+    offsets[i] = len(data)
+    print_layer(overlay_yaml['Overlay%d' % i], None)
+  add_asset_uint8('kDungeonRoomOverlay', data)
+  add_asset_uint16('kDungeonRoomOverlayOffs', offsets)
+
+  print_dungeon_secrets()
+
+  add_asset_uint16('kDungAttrsForTile_Offs', ROM.get_words(0x8e9000, 21))
+  add_asset_uint8('kDungAttrsForTile', ROM.get_bytes(0x8e902a, 1024))
+
+  add_asset_uint16('kMovableBlockDataInit', ROM.get_words(0x84f1de, 198))
+  add_asset_uint16('kTorchDataInit', ROM.get_words(0x84F36A, 144))
+  add_asset_uint16('kTorchDataJunk', ROM.get_words(0x84F48a, 48))
+ 
+def print_enemy_damage_data():
+  decomp, comp_len = util.decomp(0x83e800, ROM.get_byte, True, True)
+  add_asset_uint8('kEnemyDamageData', decomp)
+
+def print_tilemaps():
+  kSrcs = [0xcdd6d, 0xce7bf, 0xce2a8, 0xce63c, 0xce456, 0xeda9c]
+  def decode_one(p):
+    p_org = p
+    while not (ROM.get_byte(p) & 0x80):
+      is_memset = ROM.get_byte(p+2) & 0x40
+      len = ((ROM.get_byte(p+2)*256+ROM.get_byte(p+3))&0x3fff) + 1
+      p += 4
+      p += 2 if is_memset else len
+    return p - p_org + 1
+  for i,s in enumerate(kSrcs):
+    l = decode_one(s)
+    add_asset_uint8('kBgTilemap_%d' % i, ROM.get_bytes(s, l))
+
+def print_link_graphics():
+  image = Image.open('linksprite.png')
+  data = image.tobytes()
+  def encode_4bit_sprite(data, offset, pitch):
+    b = [0] * 32
+    for y in range(8):
+      for x in range(8):
+        v = data[offset + y * pitch + x]
+        b[y*2+0] |= (v & 1) << (7-x)
+        b[y*2+1] |= (v >> 1 & 1) << (7-x)
+        b[y*2+16] |= (v >> 2 & 1) << (7-x)
+        b[y*2+17] |= (v >> 3 & 1) << (7-x)
+    return bytes(b)
+  b = b''
+  for y in range(56):
+    for x in range(16):
+      b += encode_4bit_sprite(data, y * 128 * 8 + x * 8, 128)
+  add_asset_uint8('kLinkGraphics', b)
+
+def print_sound_banks():
+  for song in ['intro', 'indoor', 'ending']:
+    name, data = compile_music.print_song(song)
+    add_asset_uint8(name, data)
+
+def print_all(args):
+  print_sound_banks()
+  print_dungeon_rooms()
+  print_enemy_damage_data()
+  print_link_graphics()
+  print_dungeon_sprites()
+  print_map32_to_map16()
+  print_images(args)
+  print_misc(args)
+  print_dialogue(args)
+  print_dungeon_map()
+  print_tilemaps()
+  print_overworld()
+  print_overworld_tables()
+
+def write_assets_to_file(print_header = False):
+  key_sig = b''
+  all_data = []
+  if print_header:
+    print('''#pragma once
+#include "types.h"
+
+enum {
+  kNumberOfAssets = %d
+};
+extern const uint8 *g_asset_ptrs[kNumberOfAssets];
+extern uint32 g_asset_sizes[kNumberOfAssets];
+extern MemBlk FindInAssetArray(int asset, int idx);
+''' % len(assets))
+
+  for i, (k, (tp, data)) in enumerate(assets.items()):
+    if print_header:
+      if tp == 'packed':
+        print('#define %s(idx) FindInAssetArray(%d, idx)' % (k, i))
+      else:
+        print('#define %s ((%s*)g_asset_ptrs[%d])' % (k, tp, i))
+        print('#define %s_SIZE (g_asset_sizes[%d])' % (k, i))
+    key_sig += k.encode('utf8') + b'\0'
+    all_data.append(data)
+
+  assets_sig = b'Zelda3_v0     \n\0' + hashlib.sha256(key_sig).digest()
+
+  if print_header:
+    print('#define kAssets_Sig %s' % ", ".join((str(a) for a in assets_sig)))
+
+  hdr = assets_sig + b'\x00' * 32 + struct.pack('II', len(all_data), len(key_sig))
+
+  encoded_sizes = array.array('I', [len(i) for i in all_data])
+
+  file_data = hdr + encoded_sizes + key_sig
+
+  for v in all_data:
+    while len(file_data) & 3:
+      file_data += b'\0'
+    file_data += v
+
+  open('../zelda3_assets.dat', 'wb').write(file_data)
+
+def main(args):
+  print_all(args)
+  write_assets_to_file(args.print_assets_header)
+
+if __name__ == "__main__":
+  ROM = util.load_rom(sys.argv[1] if len(sys.argv) >= 2 else None)
+  class DefaultArgs:
+    sprites_from_png = False
+    languages = None
+    print_assets_header = False
+  main(DefaultArgs())
+else:
+  ROM = util.ROM
+
--- /dev/null
+++ b/assets/decode_music.py
@@ -1,0 +1,471 @@
+import hashlib
+import array
+import heapq, sys
+import yaml
+import time
+import util, brr_tools
+
+
+def load_sound_bank(rom, ea, mem_in = None):
+  memory = list(mem_in) if mem_in else [None]*65536
+  j =0 
+  while True:
+    numbytes = rom.get_word(ea)
+    target = rom.get_word(ea+2)
+    if numbytes==0:
+#      print('Entry point = 0x%x' % target)
+      return memory, target
+    print('# Copy %d bytes to 0x%x' % (numbytes, target))
+    ea += 4
+    for i in range(numbytes):
+      memory[target+i] = rom.get_byte(ea)
+      ea += 1
+      if (ea & 0xffff) < 0x8000:
+        ea += 0x8000
+    j += 1
+    if j > 256:
+      break
+
+def get_byte(ea):
+  return memory[ea]
+
+def get_word(ea):
+  return get_byte(ea) | get_byte(ea + 1) * 256
+
+
+# lightworld
+# Copy 11694 bytes to 0xd000
+# Copy 1672 bytes to 0x2b00
+
+
+# indoor
+# Copy 11455 bytes to 0xd000
+# Copy 1292 bytes to 0x2b00
+
+def to_str(s):
+  if isinstance(s, str):
+    return s
+  if isinstance(s, int):
+    return str(s)
+  return s.name
+
+
+class Song:
+  name = 'Song'
+  def __str__(self):
+    s = '# Song index %d\n' % self.index
+    s += '[Song_0x%x]\n' % (self.ea)
+    s += "".join(x.name + '\n' for x in self.phrases)
+    return s
+
+class SongList:
+  name = 'SongList'
+  def __str__(self):
+    s = '[SongList_0x%x]\n' % (self.ea)
+    s += "".join(('None' if x == None else x.name) + '\n' for x in self.songs)
+    return s
+
+class Phrase:
+  name = 'Phrase'
+  def __str__(self):
+    s = '[Phrase_0x%x]\n' % (self.ea)
+    s += "".join(('None' if x == None else x.name) + '\n' for x in self.patterns)
+    return s
+
+class Pattern:
+  name = 'Pattern'
+  def __str__(self):
+    r = '[Pattern_0x%x]\n' % (self.ea)
+    last_len = None
+    for a in self.lines:
+      s = ''
+      if len(a) == 4:
+        s += a[0] + " " + " ".join(map(to_str, a[1]))
+      else:
+        s += '%s' % (a[0])
+
+        if a[-2] != None:
+          s += ' %2d' % a[-2]
+          last_len = a[-2]
+        else:
+          s += ' --'# % last_len
+
+        if a[-1] != None:
+          s += ' %2x' % a[-1]
+        else:
+          s += ' --'
+
+      r += s + '\n'
+    return r
+  
+class PhraseLoop:
+  name = 'PhraseLoop'
+  def __init__(self, loops, jmp):
+    self.loops = loops
+    self.jmp = jmp
+    self.name = 'PhraseLoop %d %d' % (self.loops, self.jmp)
+  def __str__(self):
+    return self.name
+
+types_for_ea = {}
+pqueue_by_ea = []
+
+def reset_queues():
+  global types_for_ea, pqueue_by_ea
+  types_for_ea = {}
+  pqueue_by_ea = []
+
+def get_type_for_ea(ea, tp):
+  if ea == 0:
+    return None
+  assert(ea >= 256), ea
+  a = types_for_ea.get(ea)
+  if a != None:
+    assert type(a)==tp, (type(a), tp, '0x%x' % ea)
+    return a
+  a = tp()
+  a.ea = ea
+  a.name = '%s_0x%x' % (a.name, ea)
+  types_for_ea[ea] = a
+  if get_byte(ea) != None:
+    heapq.heappush(pqueue_by_ea, (ea, a))
+    a.is_imported = False
+  else:
+    a.is_imported = True
+  return a
+
+kEffectByteLength = [1, 1, 2, 3, 0, 1, 2, 1, 2, 1, 1, 3, 0, 1, 2, 3, 1, 3, 3, 0, 1, 3, 0, 3, 3, 3, 1]
+kEffectNames = ['Instrument', 'Pan', 'PanFade', 'Vibrato', 'VibratoOff',
+                'SongVolume', 'SongVolumeFade', 'Tempo', 'TempoFade',
+                'Transpose', 'ChannelTranpose', 'Tremolo', 'TremoloOff',
+                'Volume', 'VolumeFade', 'Call', 'VibratoFade',
+                'PitchEnvelopeTo', 'PitchEnvelopeFrom', 'PitchEnvelopeOff',
+                'FineTune', 'EchoEnable', 'EchoOff', 'EchoSetup', 'EchoVolumeFade',
+                'PitchSlide', 'PercussionDefine']
+assert(len(kEffectNames) == 27)
+
+def note_to_str(note):
+  kKeys  = ['C-', 'C#', 'D-', 'D#', 'E-', 'F-', 'F#', 'G-', 'G#', 'A-', 'A#', 'B-']
+  if note >= 72:
+    if note == 72:
+      return '-+-' # don't write kof
+    elif note == 73:
+      return '---' # want kof
+    else:
+      assert 0
+  octave = note / 12
+  key = note % 12
+  return '%s%d' % (kKeys[key], octave + 1)
+
+def get_pattern(ea):
+  if ea == 0:
+    return None
+  pattern = get_type_for_ea(ea, Pattern)
+  return pattern
+
+def get_song(ea, index):
+  song = get_type_for_ea(ea, Song)
+  if song:
+    song.index = index
+  return song
+
+def get_phrase(ea):
+  phrase = get_type_for_ea(ea, Phrase)
+  return phrase
+
+def decode_pattern(pattern, next_ea):
+  ea = pattern.ea
+  pattern.lines = []
+  start_ea = ea
+  while True:
+#    print('0x%x 0x%x' % (ea, start_ea))
+#    assert ea != 0x28f0
+    if ea != start_ea and ea == next_ea:
+      pattern.lines.append(('Fallthrough', (), None, None))
+      return
+    note_length, volstuff = None, None
+    cmd = get_byte(ea); ea += 1
+    if cmd == 0:
+      break
+    if not (cmd & 0x80):
+      note_length = cmd
+      cmd = get_byte(ea); ea += 1
+      if not (cmd & 0x80):
+        volstuff = cmd
+        cmd = get_byte(ea); ea += 1
+    if cmd == 0xef:
+      addr = get_word(ea)
+      loops = get_byte(ea + 2)
+      ea += 3
+      pattern.lines.append((kEffectNames[cmd-0xe0], (get_pattern(addr), loops), note_length, volstuff))
+    elif cmd >= 0xe0:
+      assert note_length == None and volstuff == None, (note_length, volstuff)
+      x = kEffectByteLength[cmd - 0xe0]
+      args = [get_byte(ea+i) for i in range(x)]
+      ea += x
+      pattern.lines.append((kEffectNames[cmd-0xe0], args, note_length, volstuff))
+    else:
+      assert(cmd & 0x80)
+      pattern.lines.append((note_to_str(cmd & 0x7f), note_length, volstuff))
+
+  return pattern
+
+def decode_phrase(phrase):
+  phrase.patterns = [get_pattern(get_word(phrase.ea + i * 2)) for i in range(8)]
+
+def decode_song(song):
+  ea = song.ea
+  song.phrases = []
+  ea_org = ea
+  eas_in_phrase = []
+  while True:
+    eas_in_phrase.append(ea)
+    phrase = get_word(ea)
+    if phrase == 0:
+      break
+    if phrase < 0x100:
+      assert phrase != 0x80 and phrase != 0x81
+      tgt = get_word(ea + 2)
+      assert tgt in eas_in_phrase
+      song.phrases.append(PhraseLoop(phrase, (tgt - ea) // 2))
+      ea += 4                                     
+    else:
+      song.phrases.append(get_phrase(phrase))
+      ea += 2
+  return song
+
+def decode_any(what, next_ea):
+  if isinstance(what, Song):
+    decode_song(what)
+  elif isinstance(what, SongList):
+    pass # no need
+  elif isinstance(what, Phrase):
+    decode_phrase(what)
+  elif isinstance(what, Pattern):
+    decode_pattern(what, next_ea)
+  else:
+    assert 0
+
+def get_song_list(ea, num):
+  song_list = get_type_for_ea(ea, SongList)
+  song_list.songs  = [get_song(get_word(ea + i * 2), i) for i in range(num)]    
+
+def load_song(ROM, song):
+  global memory, SONGS_IN_BANK
+  reset_queues()
+  if song == 'intro':
+    memory, entry_point = load_sound_bank(ROM, 0x998000) # intro
+    SONGS_IN_BANK = (get_word(0xd000) - 0xd000) // 2
+  elif song == 'lightworld':
+    memory, entry_point = load_sound_bank(ROM, 0x9a9ef5) # lw
+    SONGS_IN_BANK = (get_word(0xd000) - 0xd000) // 2
+  elif song == 'indoor':
+    memory, entry_point = load_sound_bank(ROM, 0x9b8000) # indoor
+    SONGS_IN_BANK = (0xd046 - 0xd000) // 2
+  elif song == 'ending':
+    memory, entry_point = load_sound_bank(ROM, 0x9ad380) # ending
+    SONGS_IN_BANK = (0xd046 - 0xd000) // 2
+
+
+def print_song(song, f):
+  get_song_list(0xd000, SONGS_IN_BANK)
+  if song in ('intro', 'lightworld'):
+    get_phrase(0xD878)
+    get_phrase(0xD8A8)
+    get_phrase(0xD8B8)
+    get_phrase(0xDf11)
+    get_phrase(0xe37c)
+  if song == 'indoor':
+    get_phrase(0xDc5e)
+    get_phrase(0xDc6e)
+    get_pattern(0xe905)
+    get_phrase(0xe94a)
+  if song == 'ending':
+    get_phrase(0x2a10)    
+  while len(pqueue_by_ea):
+    _, item = heapq.heappop(pqueue_by_ea)
+    decode_any(item, pqueue_by_ea[0][0] if len(pqueue_by_ea) else None)
+  for a, b in sorted(types_for_ea.items()):
+    if not b.is_imported:
+      print(b, file = f)
+
+
+def dump_brr_audio():
+  def decode_brr(snd):
+    start, loop_start = get_word(0x3c00 + snd * 4), get_word(0x3c00 + snd * 4 + 2)
+    r = brr_tools.decode_brr(lambda x: get_byte(start+x))
+    return r, [get_byte(start+x) for x in range(len(r)//16 * 9)], get_byte(start)&0x2 != 0
+  for audio_idx in range(25):
+    sound_data, brr_data, brr_repeat = decode_brr(audio_idx)
+    open('sound/sound%d.pcm.brr' % audio_idx, 'wb').write(bytes(brr_data))
+    open('sound/sound%d.pcm' % audio_idx, 'wb').write(sound_data)
+
+def dump_music_info():
+  music_info = {}
+  kDupSamples = {10 : 9, 20 : 19}
+  music_info['samples'] = []
+  for audio_idx in range(25):
+    start, rep = get_word(0x3c00 + audio_idx * 4), get_word(0x3c00 + audio_idx * 4 + 2)
+    sample_info = {
+      'file' : 'sound/sound%d.pcm' % kDupSamples.get(audio_idx, audio_idx)
+    }
+    if get_byte(start) & 2:
+      sample_info['repeat'] = (rep - start) // 9 * 16
+    music_info['samples'].append(sample_info)
+
+  def add_sustain_decay_etc(ea, info):
+    adsr1, adsr2, gain = get_byte(ea), get_byte(ea + 1), get_byte(ea + 2)
+    info['decay'] = (adsr1 >> 4) & 7
+    info['attack'] = adsr1 & 0xf
+    info['sustain_level'] = adsr2 >> 5
+    info['sustain_rate'] = adsr2 & 0x1f
+    info['vxgain'] = gain  
+
+  music_info['instruments'] = []
+  for i in range(25):
+    ea = 0x3d00 + i * 6
+    adsr1, adsr2 = get_byte(ea + 1), get_byte(ea + 2)
+    info = {
+      'sample' : get_byte(ea),
+    }
+    add_sustain_decay_etc(ea + 1, info)
+    info['pitch_base'] = get_byte(ea + 4) << 8 | get_byte(ea + 5)
+    music_info['instruments'].append(info)
+
+  music_info['note_gate_off'] = [get_byte(i) for i in range(0x3D96, 0x3D96 + 8)]
+  music_info['note_volume'] = [get_byte(i) for i in range(0x3D9E, 0x3D9E + 16)]
+
+  music_info['sfx_instruments'] = []
+
+  for i in range(25):
+    ea = 0x3e00 + i * 9
+    info = {
+      'voll' : get_byte(ea),
+      'volr' : get_byte(ea + 1),
+      'pitch' : get_word(ea + 2),
+      'sample' : get_byte(ea + 4)
+    }
+    add_sustain_decay_etc(ea + 5, info)
+    info['pitch_base'] = get_byte(ea + 8)
+    music_info['sfx_instruments'].append(info)  
+
+  s = yaml.dump(music_info, default_flow_style=None, sort_keys=False)
+  open('music_info.yaml', 'w').write(s)
+
+def decode_sfx(ea, next_addr):
+  r = []
+  while True:
+    if ea == next_addr:
+      r.append(('Fallthrough', ))
+      return r
+    b = get_byte(ea); ea += 1
+    if b == 0:
+      return r
+    note_length = None
+    volume_left, volume_right = None, None
+    if not (b & 0x80):
+      note_length = b
+      b = get_byte(ea); ea += 1
+      if not (b & 0x80):
+        volume_left, volume_right = b, None
+        b = get_byte(ea); ea += 1
+        if not b & 0x80:
+          volume_right = b
+          b = get_byte(ea); ea += 1
+    if b == 0xe0:
+      assert note_length == None and volume_left == None and volume_right == None, ea
+      b = get_byte(ea); ea += 1
+      r.append(('SetInstrument %d' % b, ))
+    elif b == 0xf9:
+      #assert note_length == None and volume_left == None and volume_right == None, ea
+      b = get_byte(ea); ea += 1
+      b0, b1, b2 = get_byte(ea), get_byte(ea+1), get_byte(ea+2); ea += 3
+      r.append(('PitchSlide %d %d %d' % (b0, b1, b2), note_to_str(b & 0x7f), note_length, volume_left, volume_right))
+    elif b == 0xf1:
+      #assert note_length == None and volume_left == None and volume_right == None, ea
+      b0, b1, b2 = get_byte(ea), get_byte(ea+1), get_byte(ea+2); ea += 3
+      r.append(('PitchSlide %d %d %d' % (b0, b1, b2), None, note_length, volume_left, volume_right))
+    elif b == 0xff:
+      assert note_length == None and volume_left == None and volume_right == None, ea
+      r.append(('Restart',))
+      return r
+    else:
+      r.append((None, note_to_str(b & 0x7f), note_length, volume_left, volume_right))
+
+def print_all_sfx(f):
+  items = set()
+  def add_sfx_top(base, num, name):
+    print('[%s_0x%x]' % (name, base), file = f)
+    next_ea = base + num * 2
+    echo_ea = next_ea + num
+    for i in range(num):
+      r = []
+      ea = get_word(base + i * 2)
+      if ea == 0:
+        t = 'None'
+      else:
+        items.add(ea)
+        t = 'Sfx_0x%x' % ea
+      if name == 'SfxPort1':
+        print('%s,%d' % (t, get_byte(next_ea + i)), file = f)
+      else:
+        print('%s,%d,%d' % (t, get_byte(next_ea + i), get_byte(echo_ea + i)), file = f)
+    print(file = f)
+  add_sfx_top(0x17c0, 32, 'SfxPort1')
+  add_sfx_top(0x1820, 63, 'SfxPort2')
+  add_sfx_top(0x191c, 63, 'SfxPort3')
+  items.add(0x1a5b)
+  items.add(0x1d1c)
+  items.add(0x1ee2)
+  items.add(0x1f13)
+  items.add(0x1f1c)
+  items.add(0x252d)
+  items.add(0x2533)
+  items.add(0x26a2)
+  items.add(0x277e)
+  items.add(0x279d)
+  items.add(0x27c9)
+  items.add(0x27f6)
+  items.add(0x2807)
+  items.add(0x2818)
+  items.add(0x2829)
+  items.add(0x2831)
+  items.add(0x284a)
+  items = sorted(list(items))
+  for i in range(len(items)):
+    print('[Sfx_0x%x]' % items[i], file = f)
+    next_addr = items[i + 1] if i + 1 < len(items) else 0
+    rs = decode_sfx(items[i], next_addr)
+    for r in rs:
+      if len(r) == 5:
+        aa = '.  ' if r[1] == None else r[1]
+        bb = '--' if r[2] == None else '%2d' % r[2]
+        cc = '---' if r[3] == None else '%3d' % r[3]
+        dd = '---' if r[4] == None else '%3d' % r[4]
+        r0 = '' if r[0] == None else ' ' + r[0]
+        print('%s %s %s %s%s' % (aa, bb, cc, dd, r0), file = f)
+      else:
+        print(r[0], file = f)
+    print(file = f)
+
+def extract_sound_data(rom):
+  load_song(rom, 'intro')
+  print_song('intro', open('sound_intro.txt', 'w'))
+
+  dump_brr_audio()
+  dump_music_info()
+  print_all_sfx(open('sfx.txt', 'w'))
+
+  load_song(rom, 'indoor')
+  print_song('indoor', open('sound_indoor.txt', 'w'))
+
+  load_song(rom, 'ending')
+  print_song('ending', open('sound_ending.txt', 'w'))
+
+if __name__ == "__main__":
+  ROM = util.LoadedRom(sys.argv[1])
+  song = sys.argv[2]
+
+  load_song(ROM, song)
+  print_song(song, sys.stdout)
+
--- /dev/null
+++ b/assets/extract_music.py
@@ -1,0 +1,470 @@
+import hashlib
+import array
+import heapq, sys
+import yaml
+import time
+import util
+
+
+def load_sound_bank(rom, ea, mem_in = None):
+  memory = list(mem_in) if mem_in else [None]*65536
+  j =0 
+  while True:
+    numbytes = rom.get_word(ea)
+    target = rom.get_word(ea+2)
+    if numbytes==0:
+#      print('Entry point = 0x%x' % target)
+      return memory, target
+#    print('# Copy %d bytes to 0x%x' % (numbytes, target))
+    ea += 4
+    for i in range(numbytes):
+      memory[target+i] = rom.get_byte(ea)
+      ea += 1
+      if (ea & 0xffff) < 0x8000:
+        ea += 0x8000
+    j += 1
+    if j > 256:
+      break
+
+def get_byte(ea):
+  return memory[ea]
+
+def get_word(ea):
+  return get_byte(ea) | get_byte(ea + 1) * 256
+
+
+# lightworld
+# Copy 11694 bytes to 0xd000
+# Copy 1672 bytes to 0x2b00
+
+
+# indoor
+# Copy 11455 bytes to 0xd000
+# Copy 1292 bytes to 0x2b00
+
+def to_str(s):
+  if isinstance(s, str):
+    return s
+  if isinstance(s, int):
+    return str(s)
+  return s.name
+
+
+class Song:
+  name = 'Song'
+  def __str__(self):
+    s = '# Song index %d\n' % self.index
+    s += '[Song_0x%x]\n' % (self.ea)
+    s += "".join(x.name + '\n' for x in self.phrases)
+    return s
+
+class SongList:
+  name = 'SongList'
+  def __str__(self):
+    s = '[SongList_0x%x]\n' % (self.ea)
+    s += "".join(('None' if x == None else x.name) + '\n' for x in self.songs)
+    return s
+
+class Phrase:
+  name = 'Phrase'
+  def __str__(self):
+    s = '[Phrase_0x%x]\n' % (self.ea)
+    s += "".join(('None' if x == None else x.name) + '\n' for x in self.patterns)
+    return s
+
+class Pattern:
+  name = 'Pattern'
+  def __str__(self):
+    r = '[Pattern_0x%x]\n' % (self.ea)
+    last_len = None
+    for a in self.lines:
+      s = ''
+      if len(a) == 4:
+        s += a[0] + " " + " ".join(map(to_str, a[1]))
+      else:
+        s += '%s' % (a[0])
+
+        if a[-2] != None:
+          s += ' %2d' % a[-2]
+          last_len = a[-2]
+        else:
+          s += ' --'# % last_len
+
+        if a[-1] != None:
+          s += ' %2x' % a[-1]
+        else:
+          s += ' --'
+
+      r += s + '\n'
+    return r
+  
+class PhraseLoop:
+  name = 'PhraseLoop'
+  def __init__(self, loops, jmp):
+    self.loops = loops
+    self.jmp = jmp
+    self.name = 'PhraseLoop %d %d' % (self.loops, self.jmp)
+  def __str__(self):
+    return self.name
+
+types_for_ea = {}
+pqueue_by_ea = []
+
+def reset_queues():
+  global types_for_ea, pqueue_by_ea
+  types_for_ea = {}
+  pqueue_by_ea = []
+
+def get_type_for_ea(ea, tp):
+  if ea == 0:
+    return None
+  assert(ea >= 256), ea
+  a = types_for_ea.get(ea)
+  if a != None:
+    assert type(a)==tp, (type(a), tp, '0x%x' % ea)
+    return a
+  a = tp()
+  a.ea = ea
+  a.name = '%s_0x%x' % (a.name, ea)
+  types_for_ea[ea] = a
+  if get_byte(ea) != None:
+    heapq.heappush(pqueue_by_ea, (ea, a))
+    a.is_imported = False
+  else:
+    a.is_imported = True
+  return a
+
+kEffectByteLength = [1, 1, 2, 3, 0, 1, 2, 1, 2, 1, 1, 3, 0, 1, 2, 3, 1, 3, 3, 0, 1, 3, 0, 3, 3, 3, 1]
+kEffectNames = ['Instrument', 'Pan', 'PanFade', 'Vibrato', 'VibratoOff',
+                'SongVolume', 'SongVolumeFade', 'Tempo', 'TempoFade',
+                'Transpose', 'ChannelTranpose', 'Tremolo', 'TremoloOff',
+                'Volume', 'VolumeFade', 'Call', 'VibratoFade',
+                'PitchEnvelopeTo', 'PitchEnvelopeFrom', 'PitchEnvelopeOff',
+                'FineTune', 'EchoEnable', 'EchoOff', 'EchoSetup', 'EchoVolumeFade',
+                'PitchSlide', 'PercussionDefine']
+assert(len(kEffectNames) == 27)
+
+def note_to_str(note):
+  kKeys  = ['C-', 'C#', 'D-', 'D#', 'E-', 'F-', 'F#', 'G-', 'G#', 'A-', 'A#', 'B-']
+  if note >= 72:
+    if note == 72:
+      return '-+-' # don't write kof
+    elif note == 73:
+      return '---' # want kof
+    else:
+      assert 0
+  octave = note / 12
+  key = note % 12
+  return '%s%d' % (kKeys[key], octave + 1)
+
+def get_pattern(ea):
+  if ea == 0:
+    return None
+  pattern = get_type_for_ea(ea, Pattern)
+  return pattern
+
+def get_song(ea, index):
+  song = get_type_for_ea(ea, Song)
+  if song:
+    song.index = index
+  return song
+
+def get_phrase(ea):
+  phrase = get_type_for_ea(ea, Phrase)
+  return phrase
+
+def decode_pattern(pattern, next_ea):
+  ea = pattern.ea
+  pattern.lines = []
+  start_ea = ea
+  while True:
+#    print('0x%x 0x%x' % (ea, start_ea))
+#    assert ea != 0x28f0
+    if ea != start_ea and ea == next_ea:
+      pattern.lines.append(('Fallthrough', (), None, None))
+      return
+    note_length, volstuff = None, None
+    cmd = get_byte(ea); ea += 1
+    if cmd == 0:
+      break
+    if not (cmd & 0x80):
+      note_length = cmd
+      cmd = get_byte(ea); ea += 1
+      if not (cmd & 0x80):
+        volstuff = cmd
+        cmd = get_byte(ea); ea += 1
+    if cmd == 0xef:
+      addr = get_word(ea)
+      loops = get_byte(ea + 2)
+      ea += 3
+      pattern.lines.append((kEffectNames[cmd-0xe0], (get_pattern(addr), loops), note_length, volstuff))
+    elif cmd >= 0xe0:
+      assert note_length == None and volstuff == None, (note_length, volstuff)
+      x = kEffectByteLength[cmd - 0xe0]
+      args = [get_byte(ea+i) for i in range(x)]
+      ea += x
+      pattern.lines.append((kEffectNames[cmd-0xe0], args, note_length, volstuff))
+    else:
+      assert(cmd & 0x80)
+      pattern.lines.append((note_to_str(cmd & 0x7f), note_length, volstuff))
+
+  return pattern
+
+def decode_phrase(phrase):
+  phrase.patterns = [get_pattern(get_word(phrase.ea + i * 2)) for i in range(8)]
+
+def decode_song(song):
+  ea = song.ea
+  song.phrases = []
+  ea_org = ea
+  eas_in_phrase = []
+  while True:
+    eas_in_phrase.append(ea)
+    phrase = get_word(ea)
+    if phrase == 0:
+      break
+    if phrase < 0x100:
+      assert phrase != 0x80 and phrase != 0x81
+      tgt = get_word(ea + 2)
+      assert tgt in eas_in_phrase
+      song.phrases.append(PhraseLoop(phrase, (tgt - ea) // 2))
+      ea += 4                                     
+    else:
+      song.phrases.append(get_phrase(phrase))
+      ea += 2
+  return song
+
+def decode_any(what, next_ea):
+  if isinstance(what, Song):
+    decode_song(what)
+  elif isinstance(what, SongList):
+    pass # no need
+  elif isinstance(what, Phrase):
+    decode_phrase(what)
+  elif isinstance(what, Pattern):
+    decode_pattern(what, next_ea)
+  else:
+    assert 0
+
+def get_song_list(ea, num):
+  song_list = get_type_for_ea(ea, SongList)
+  song_list.songs  = [get_song(get_word(ea + i * 2), i) for i in range(num)]    
+
+def load_song(ROM, song):
+  global memory, SONGS_IN_BANK
+  reset_queues()
+  if song == 'intro':
+    memory, entry_point = load_sound_bank(ROM, 0x998000) # intro
+    SONGS_IN_BANK = (get_word(0xd000) - 0xd000) // 2
+  elif song == 'lightworld':
+    memory, entry_point = load_sound_bank(ROM, 0x9a9ef5) # lw
+    SONGS_IN_BANK = (get_word(0xd000) - 0xd000) // 2
+  elif song == 'indoor':
+    memory, entry_point = load_sound_bank(ROM, 0x9b8000) # indoor
+    SONGS_IN_BANK = (0xd046 - 0xd000) // 2
+  elif song == 'ending':
+    memory, entry_point = load_sound_bank(ROM, 0x9ad380) # ending
+    SONGS_IN_BANK = (0xd046 - 0xd000) // 2
+
+
+def print_song(song, f):
+  get_song_list(0xd000, SONGS_IN_BANK)
+  if song in ('intro', 'lightworld'):
+    get_phrase(0xD878)
+    get_phrase(0xD8A8)
+    get_phrase(0xD8B8)
+    get_phrase(0xDf11)
+    get_phrase(0xe37c)
+  if song == 'indoor':
+    get_phrase(0xDc5e)
+    get_phrase(0xDc6e)
+    get_pattern(0xe905)
+    get_phrase(0xe94a)
+  if song == 'ending':
+    get_phrase(0x2a10)    
+  while len(pqueue_by_ea):
+    _, item = heapq.heappop(pqueue_by_ea)
+    decode_any(item, pqueue_by_ea[0][0] if len(pqueue_by_ea) else None)
+  for a, b in sorted(types_for_ea.items()):
+    if not b.is_imported:
+      print(b, file = f)
+
+
+def dump_brr_audio():
+  def decode_brr(snd):
+    start, loop_start = get_word(0x3c00 + snd * 4), get_word(0x3c00 + snd * 4 + 2)
+    r = util.decode_brr(lambda x: get_byte(start+x))
+    return r, [get_byte(start+x) for x in range(len(r)//16 * 9)], get_byte(start)&0x2 != 0
+  for audio_idx in range(25):
+    sound_data, brr_data, brr_repeat = decode_brr(audio_idx)
+    open('sound/sound%d.pcm.brr' % audio_idx, 'wb').write(bytes(brr_data))
+    open('sound/sound%d.pcm' % audio_idx, 'wb').write(sound_data)
+
+def dump_music_info():
+  music_info = {}
+  kDupSamples = {10 : 9, 20 : 19}
+  music_info['samples'] = []
+  for audio_idx in range(25):
+    start, rep = get_word(0x3c00 + audio_idx * 4), get_word(0x3c00 + audio_idx * 4 + 2)
+    sample_info = {
+      'file' : 'sound/sound%d.pcm' % kDupSamples.get(audio_idx, audio_idx)
+    }
+    if get_byte(start) & 2:
+      sample_info['repeat'] = (rep - start) // 9 * 16
+    music_info['samples'].append(sample_info)
+
+  def add_sustain_decay_etc(ea, info):
+    adsr1, adsr2, gain = get_byte(ea), get_byte(ea + 1), get_byte(ea + 2)
+    info['decay'] = (adsr1 >> 4) & 7
+    info['attack'] = adsr1 & 0xf
+    info['sustain_level'] = adsr2 >> 5
+    info['sustain_rate'] = adsr2 & 0x1f
+    info['vxgain'] = gain  
+
+  music_info['instruments'] = []
+  for i in range(25):
+    ea = 0x3d00 + i * 6
+    adsr1, adsr2 = get_byte(ea + 1), get_byte(ea + 2)
+    info = {
+      'sample' : get_byte(ea),
+    }
+    add_sustain_decay_etc(ea + 1, info)
+    info['pitch_base'] = get_byte(ea + 4) << 8 | get_byte(ea + 5)
+    music_info['instruments'].append(info)
+
+  music_info['note_gate_off'] = [get_byte(i) for i in range(0x3D96, 0x3D96 + 8)]
+  music_info['note_volume'] = [get_byte(i) for i in range(0x3D9E, 0x3D9E + 16)]
+
+  music_info['sfx_instruments'] = []
+
+  for i in range(25):
+    ea = 0x3e00 + i * 9
+    info = {
+      'voll' : get_byte(ea),
+      'volr' : get_byte(ea + 1),
+      'pitch' : get_word(ea + 2),
+      'sample' : get_byte(ea + 4)
+    }
+    add_sustain_decay_etc(ea + 5, info)
+    info['pitch_base'] = get_byte(ea + 8)
+    music_info['sfx_instruments'].append(info)  
+
+  s = yaml.dump(music_info, default_flow_style=None, sort_keys=False)
+  open('music_info.yaml', 'w').write(s)
+
+def decode_sfx(ea, next_addr):
+  r = []
+  while True:
+    if ea == next_addr:
+      r.append(('Fallthrough', ))
+      return r
+    b = get_byte(ea); ea += 1
+    if b == 0:
+      return r
+    note_length = None
+    volume_left, volume_right = None, None
+    if not (b & 0x80):
+      note_length = b
+      b = get_byte(ea); ea += 1
+      if not (b & 0x80):
+        volume_left, volume_right = b, None
+        b = get_byte(ea); ea += 1
+        if not b & 0x80:
+          volume_right = b
+          b = get_byte(ea); ea += 1
+    if b == 0xe0:
+      assert note_length == None and volume_left == None and volume_right == None, ea
+      b = get_byte(ea); ea += 1
+      r.append(('SetInstrument %d' % b, ))
+    elif b == 0xf9:
+      #assert note_length == None and volume_left == None and volume_right == None, ea
+      b = get_byte(ea); ea += 1
+      b0, b1, b2 = get_byte(ea), get_byte(ea+1), get_byte(ea+2); ea += 3
+      r.append(('PitchSlide %d %d %d' % (b0, b1, b2), note_to_str(b & 0x7f), note_length, volume_left, volume_right))
+    elif b == 0xf1:
+      #assert note_length == None and volume_left == None and volume_right == None, ea
+      b0, b1, b2 = get_byte(ea), get_byte(ea+1), get_byte(ea+2); ea += 3
+      r.append(('PitchSlide %d %d %d' % (b0, b1, b2), None, note_length, volume_left, volume_right))
+    elif b == 0xff:
+      assert note_length == None and volume_left == None and volume_right == None, ea
+      r.append(('Restart',))
+      return r
+    else:
+      r.append((None, note_to_str(b & 0x7f), note_length, volume_left, volume_right))
+
+def print_all_sfx(f):
+  items = set()
+  def add_sfx_top(base, num, name):
+    print('[%s_0x%x]' % (name, base), file = f)
+    next_ea = base + num * 2
+    echo_ea = next_ea + num
+    for i in range(num):
+      r = []
+      ea = get_word(base + i * 2)
+      if ea == 0:
+        t = 'None'
+      else:
+        items.add(ea)
+        t = 'Sfx_0x%x' % ea
+      if name == 'SfxPort1':
+        print('%s,%d' % (t, get_byte(next_ea + i)), file = f)
+      else:
+        print('%s,%d,%d' % (t, get_byte(next_ea + i), get_byte(echo_ea + i)), file = f)
+    print(file = f)
+  add_sfx_top(0x17c0, 32, 'SfxPort1')
+  add_sfx_top(0x1820, 63, 'SfxPort2')
+  add_sfx_top(0x191c, 63, 'SfxPort3')
+  items.add(0x1a5b)
+  items.add(0x1d1c)
+  items.add(0x1ee2)
+  items.add(0x1f13)
+  items.add(0x1f1c)
+  items.add(0x252d)
+  items.add(0x2533)
+  items.add(0x26a2)
+  items.add(0x277e)
+  items.add(0x279d)
+  items.add(0x27c9)
+  items.add(0x27f6)
+  items.add(0x2807)
+  items.add(0x2818)
+  items.add(0x2829)
+  items.add(0x2831)
+  items.add(0x284a)
+  items = sorted(list(items))
+  for i in range(len(items)):
+    print('[Sfx_0x%x]' % items[i], file = f)
+    next_addr = items[i + 1] if i + 1 < len(items) else 0
+    rs = decode_sfx(items[i], next_addr)
+    for r in rs:
+      if len(r) == 5:
+        aa = '.  ' if r[1] == None else r[1]
+        bb = '--' if r[2] == None else '%2d' % r[2]
+        cc = '---' if r[3] == None else '%3d' % r[3]
+        dd = '---' if r[4] == None else '%3d' % r[4]
+        r0 = '' if r[0] == None else ' ' + r[0]
+        print('%s %s %s %s%s' % (aa, bb, cc, dd, r0), file = f)
+      else:
+        print(r[0], file = f)
+    print(file = f)
+
+def extract_sound_data(rom):
+  for song in ['intro', 'indoor', 'ending']:
+    load_song(rom, song)
+    open('sound/%s.spc' % song, 'wb').write(bytes((0 if a == None else a) for a in memory))
+    print_song(song, open('sound_%s.txt' % song, 'w'))
+    if song == 'intro':
+      dump_brr_audio()
+      dump_music_info()
+      print_all_sfx(open('sfx.txt', 'w'))
+
+if __name__ == "__main__":
+  if len(sys.argv) < 3:
+    print('extract_music.py [rom-filename] [intro|lightworld|indoor|ending]')
+    sys.exit(0)
+  ROM = util.LoadedRom(None if sys.argv[1] == '' else sys.argv[1])
+  song = sys.argv[2]
+
+  load_song(ROM, song)
+  print_song(song, sys.stdout)
+
--- /dev/null
+++ b/assets/extract_resources.py
@@ -1,0 +1,541 @@
+from ast import literal_eval as make_tuple
+import sys
+import text_compression
+import util
+from util import get_bytes, get_words, get_byte, get_word, get_int8, get_int16, cache
+import tables
+import yaml
+import extract_music
+import os
+import sprite_sheets
+
+def print_map32_to_map16(f):
+  for i in range(2218):
+    def getit(ea):
+      ov = [get_byte(ea + j) for j in range(6)]
+      res=[0]*4
+      res[0] = ov[0] | (ov[4] >> 4) << 8
+      res[1] = ov[1] | (ov[4] & 0xf) << 8
+      res[2] = ov[2] | (ov[5] >> 4) << 8
+      res[3] = ov[3] | (ov[5] & 0xf) << 8
+      return res
+    t0 = getit(0x838000 + i * 6)
+    t1 = getit(0x83b400 + i * 6)
+    t2 = getit(0x848000 + i * 6)
+    t3 = getit(0x84b400 + i * 6)
+    for j in range(4):
+      print('%5d: %4d, %4d, %4d, %4d' % (i * 4 + j, t0[j], t1[j], t2[j], t3[j]), file = f)
+
+@cache
+def get_exit_datas():
+  r = {}
+  for i in range(79):
+    room = get_word(0x82dd8a + i * 2)
+    screen_index = get_byte(0x82DE28 + i)
+    load_offs = get_word(0x82DE77 + i * 2)
+    scroll_y = get_word(0x82DF15 + i * 2)
+    scroll_x = get_word(0x82DFB3 + i * 2)
+    pos_y = get_word(0x82E051 + i * 2)
+    pos_x = get_word(0x82E0EF + i * 2)
+    camera_y = get_word(0x82E18D + i * 2)
+    camera_x = get_word(0x82E22B + i * 2)
+    unk1 = get_int8(0x82E2C9 + i)
+    unk3 = get_int8(0x82E318 + i)
+    ndoor = get_word(0x82E367 + i * 2)
+    fdoor = get_word(0x82E405 + i * 2)
+    base_x = (screen_index & 7) << 9
+    base_y = (screen_index & 56) << 6
+    y = {
+      'index' : i,
+      'room' : room,
+      'xy' : [pos_x - base_x, pos_y - base_y],
+      'scroll_xy' : [scroll_x - base_x, scroll_y - base_y],
+      'camera_xy' : [camera_x - base_x, camera_y - base_y],
+    }
+    y['load_xy'] = [((load_offs >> 1) - (y['scroll_xy'][0] >> 4)) & 0x3f, (load_offs >> 7) - (y['scroll_xy'][1] >> 4) & 0x3f]
+    y['unk'] = [unk1, unk3]
+    def get_special_exit_info(room_index):
+      return {
+        'dir' : get_byte(0x82E801  + room_index - 0x180) >> 1,
+        'spr_gfx' : get_byte(0x82E811  + room_index - 0x180),
+        'aux_gfx' : get_byte(0x82E821  + room_index - 0x180),
+        'pal_bg' : get_byte(0x82E831  + room_index - 0x180),
+        'pal_spr' : get_byte(0x82E841  + room_index - 0x180),
+        'top' : get_word(0x82e6e1 + (room_index - 0x180) * 2),
+        'bottom' : get_word(0x82e701 + (room_index - 0x180) * 2),
+        'left' : get_word(0x82e721 + (room_index - 0x180) * 2),
+        'right' : get_word(0x82e741 + (room_index - 0x180) * 2),
+        'left_edge_of_map' : get_word(0x82E7E1 + (room_index - 0x180) * 2),
+        'unk4' : get_int16(0x82e761 + (room_index - 0x180) * 2),
+        'unk6' : get_int16(0x82e781 + (room_index - 0x180) * 2),
+        'unk5' : get_int16(0x82e7a1 + (room_index - 0x180) * 2),
+        'unk7' : get_int16(0x82e7c1 + (room_index - 0x180) * 2),
+      }
+
+    if room >= 0x180 and room < 0x190:
+      y['special_exit'] = get_special_exit_info(room)
+
+    if ndoor != 0:
+      assert fdoor == 0
+      y['door'] = ['bombable' if ndoor & 0x8000 else 'wooden', (ndoor & 0x7e) >> 1, (ndoor & 0x3f80) >> 7]
+    if fdoor != 0:
+      y['door'] = ['palace' if fdoor & 0x8000 else 'sanctuary', (fdoor & 0x7e) >> 1, (fdoor & 0x3f80) >> 7]
+    r.setdefault(screen_index, []).append(y)
+  return r
+
+def get_loadoffs(c, d):
+  x, y = c[0] >> 4, c[1] >> 4
+  x += d[0]
+  y += d[1]
+  return (y&0x3f) << 7 | (x&0x3f) << 1
+
+@cache
+def get_ow_travel_infos():
+  r = {}
+  for i in range(17):
+    screen_index = get_word(0x82EAE5 + i * 2)
+    load_offs = get_word(0x82EB07 + i * 2)
+    scroll_y = get_word(0x82EB29 + i * 2)
+    scroll_x = get_word(0x82EB4B + i * 2)
+    pos_y = get_word(0x82EB6D + i * 2)
+    pos_x = get_word(0x82EB8F + i * 2)
+    camera_y = get_word(0x82EBB1 + i * 2)
+    camera_x = get_word(0x82EBD3 + i * 2)
+    unk1 = get_int8(0x82EBF5 + i * 2)
+    unk3 = get_int8(0x82EC17 + i * 2)
+    base_x = (screen_index & 7) << 9
+    base_y = (screen_index & 56) << 6
+    y = {}
+    if i < 9:
+      y['bird_travel_id'] = i
+    else:
+      y['whirlpool_src_area'] = get_word(0x82ECF8 + (i - 9) * 2)
+    y['xy'] = [pos_x - base_x, pos_y - base_y]
+    y['scroll_xy'] = [scroll_x - base_x, scroll_y - base_y]
+    y['camera_xy'] = [camera_x - base_x, camera_y - base_y]
+    y['load_xy'] = [((load_offs >> 1) - (y['scroll_xy'][0] >> 4)) & 0x3f, (load_offs >> 7) - (y['scroll_xy'][1] >> 4) & 0x3f]
+
+    t0 = get_loadoffs(y['scroll_xy'], y['load_xy'])
+    assert t0 == load_offs, (t0 & 0x7f, load_offs & 0x7f)
+    
+    y['unk'] = [unk1, unk3]
+    r.setdefault(screen_index, []).append(y)
+  return r
+
+@cache
+def get_ow_entrance_info():
+  r = {}
+  for i in range(129):
+    area = get_word(0x9BB96F + i * 2)
+    pos = get_word(0x9BBA71 + i * 2)
+    entrance_id = get_byte(0x9BBB73 + i)
+    r.setdefault(area, []).append({'index' : i, 'x' : (pos >> 1) & 0x3f, 'y' : (pos >> 7) & 0x3f, 'entrance_id' : entrance_id})
+  return r
+
+@cache
+def get_hole_infos():
+  r = {}
+  for i in range(19):
+    pos = get_word(0x9BB800 + i * 2) + 0x400
+    area = get_word(0x9BB826 + i * 2)
+    entrance_id = get_byte(0x9BB84C + i)
+    r.setdefault(area, []).append({'x' : (pos >> 1) & 0x3f, 'y' : (pos >> 7) & 0x3f, 'entrance_id' : entrance_id})
+  return r
+
+def print_overworld_area(overworld_area):
+  is_small = get_bytes(0x82F88D, 192)
+  y = {}
+
+  def get_music(ambient):
+    def fn(x):
+      if ambient:
+        return tables.kAmbientSoundName[x >> 4]
+      else:
+        return tables.kMusicNames[x & 0xf]
+    if overworld_area < 64:
+      return {
+        'beginning' : fn(get_byte(0x82C303 + overworld_area)),
+        'zelda' : fn(get_byte(0x82C303 + overworld_area + 64)),
+        'sword' : fn(get_byte(0x82C303 + overworld_area + 128)),
+        'agahnim' : fn(get_byte(0x82C303 + overworld_area + 192)),
+      }
+    else:
+      assert overworld_area < 64 + 96
+      return {'agahnim' : fn(get_byte(0x82C403 + overworld_area - 64)) }
+
+  def get_items():
+    if overworld_area >= 128: return []
+    ea = 0x9b0000 | get_word(0x9BC2F9 + overworld_area * 2)
+    xs = []
+    while get_word(ea) != 0xffff:
+      pos = get_word(ea)
+      assert pos%2==0
+      x, y = pos//2%64, pos//2//64 
+      xs.append([x, y, tables.kSecretNames[get_byte(ea+2)]])
+      ea += 3
+    return xs
+
+  header = {
+    'name' : tables.kAreaNames[overworld_area],
+    'size' : 'small' if is_small[overworld_area] else 'big',
+    'gfx' : get_byte(0x80FC9C + overworld_area) if overworld_area < 128 else -1,
+    'palette' : get_byte(0x80FD1C + overworld_area) if overworld_area < 136 else -1,
+    'sign_text' : get_word(0x87F51D + overworld_area * 2) if overworld_area < 128 else -1,
+    'music' : get_music(False),
+    'ambient' : get_music(True),
+  }
+      
+  y['Header'] = header
+  y['Travel'] = get_ow_travel_infos().get(overworld_area, [])
+  y['Entrances'] = get_ow_entrance_info().get(overworld_area, [])
+  hole_infos = get_hole_infos()
+  if overworld_area in hole_infos:
+    y['Holes'] = hole_infos[overworld_area]
+  y['Exits'] = get_exit_datas().get(overworld_area, [])
+  y['Items'] = get_items()
+  
+  def decode_sprites(base_addr):
+    r = []
+    ea = 0x890000 + get_word(base_addr + overworld_area * 2)
+    while get_byte(ea) != 0xff:
+      y, x, w = get_byte(ea), get_byte(ea+1), get_byte(ea+2)
+      r.append([x, y, tables.kSpriteNames[w]])
+      ea += 3
+    return r
+
+  def get_info(stage):
+    if overworld_area >= 128: return {}
+    if overworld_area >= 64: stage = 3
+    return {
+      'gfx' : get_byte(0x80FA41 + (overworld_area & 63) + stage * 64),
+      'palette' : get_byte(0x80FB41 + (overworld_area & 63) + stage * 64),
+    }
+  if overworld_area < 64:
+    y['Sprites.Beginning'] = {
+      'info' : get_info(0),
+      'sprites' : decode_sprites(0x89C881)
+    }
+    y['Sprites.FirstPart'] = {
+      'info' : get_info(1),
+      'sprites' : decode_sprites(0x89C901)
+    }
+    y['Sprites.SecondPart'] = {
+      'info' : get_info(2),
+      'sprites' : decode_sprites(0x89CA21)
+    }
+  elif overworld_area < 144:
+    y['Sprites'] = {
+      'info' : get_info(2),
+      'sprites' : decode_sprites(0x89CA21)
+    }
+    
+  s = yaml.dump(y, default_flow_style=None, sort_keys=False)
+  open('overworld/overworld-%d.yaml' % overworld_area, 'w').write(s)
+
+def print_all_overworld_areas():
+  area_heads = get_bytes(0x82A5EC, 64)
+  
+  for i in range(160):
+    if i >= 128 or area_heads[i&63] == (i&63):
+      print_overworld_area(i)
+
+def print_dialogue():
+  text_compression.print_strings(util.ROM, file = open(text_compression.dialogue_filename(util.ROM.language), 'w', encoding='utf8'))
+
+def decode_room_objects(p):
+  objs = []
+  j = 0
+  while True:
+    p0, p1, p2 = get_byte(p), get_byte(p+1), get_byte(p+2)
+    A = p0 | p1 << 8
+    if A == 0xffff:
+      return p + 2, objs, None
+    if A == 0xfff0:
+      p += 2
+      break
+    if (A & 0xfc) != 0xfc:
+      index = p2
+      Dst = (p1 >> 2) << 7
+      Dst |= (p0 & 0xfc) >> 1
+      X = (Dst >> 1) & 0x3f
+      Y = (Dst >> 7) & 0x3f
+      W = p0 & 3
+      H = p1 & 3
+      if index < 0xf8:
+        objs.append({'x' : X, 'y' : Y, 's' : '%d*%d' % (W, H), 'n': tables.kType0Names[index]})
+      else:
+        index2 = (index & 7) << 4 | H << 2 | W
+        objs.append({'x' : X, 'y' : Y, 'n': tables.kType1Names[index2]})
+    else:
+      # subtype 2: 111111xx xxxxyyyy yyiiiiii
+      X = ((p0 << 4 | p1 >> 4) & 0x3f)
+      Y = (p1 << 2 | p2 >> 6) & 0x3f
+      index = p2 & 0x3f
+      objs.append({'x' : X, 'y' : Y, 'n' : tables.kType2Names[index]})
+    p += 3
+    j += 1
+
+  doors = []
+  while True:
+    A = get_byte(p) | get_byte(p+1) << 8
+    if A == 0xffff:
+      return p + 2, objs, doors
+    doors.append({'type':get_byte(p + 1), 'pos' : get_byte(p) >> 4, 'dir' : A & 3})
+    p += 2
+
+@cache
+def get_chest_info():
+  ea = 0x81e96e
+  all = {}
+  for i in range(504//3):
+    room = get_word(ea + i * 3)
+    data = get_byte(ea + i * 3 + 2)
+    all.setdefault(room & 0x7fff, []).append((data, (room & 0x8000) != 0))
+  return all
+
+def _get_entrance_info_one(i, set):
+  def get_exit_door(i):
+    x = get_word((0x82D724, 0x82DC32)[set] + i * 2)
+    if x == 0:
+      return ['none']
+    if x == 0xffff:
+      return ['none_0xffff']
+    return ['bombable' if x & 0x8000 else 'wooden', (x & 0x7e) >> 1, (x & 0x3f80) >> 7]
+  kQuadrantNames = { 0 : 'upper_left', 2 : 'lower_left', 16 : 'upper_right', 18 : 'lower_right' }
+  room = get_word((0x82C813, 0x82DB6E )[set] + i * 2)
+  def get_se(se_base_addr, xy, quds):
+    base_x = (room & 0xf) * 2
+    base_y = (room >> 4) * 2  
+    ym = (xy[1] & 0x100) >> 8
+    xm = (xy[0] & 0x100) >> 8
+    #if room == 259: ym = 1 # possibly related to none_0xffff
+    hu = get_byte(se_base_addr + i * 8 + 0) - base_y - ym
+    fu = get_byte(se_base_addr + i * 8 + 1) - base_y
+    hd = get_byte(se_base_addr + i * 8 + 2) - base_y - ym
+    fd = get_byte(se_base_addr + i * 8 + 3) - base_y - 1
+    #assert fu == 0 and fd == 0 and hd == 0 and fd == 0, (room, fu, fd, hd, fd)
+    qqq = xm if room >= 242 and quds[0] == 'single_x' else 0
+    hl = get_byte(se_base_addr + i * 8 + 4) - base_x - xm
+    fl = get_byte(se_base_addr + i * 8 + 5) - base_x - qqq
+    hr = get_byte(se_base_addr + i * 8 + 6) - base_x - xm
+    fr = get_byte(se_base_addr + i * 8 + 7) - base_x - 1 - qqq
+    return [hu, fu, hd, fd, hl, fl, hr, fr]#
+
+  player_x = get_word((0x82D063, 0x82DBDE)[set] + i * 2) - ((room & 0x00f) << 9)
+  player_y = get_word((0x82CF59, 0x82DBD0)[set] + i * 2) - ((room & 0x1f0) << 5)
+
+  y = {
+    ('entrance_index' if set == 0 else 'starting_point_index'): i,
+    'name' : tables.kEntranceNames[i] if set == 0 else 'Starting Location %d' % i,
+    'scroll_xy' : [
+      get_word((0x82CD45, 0x82DBB4)[set] + i * 2) - ((room & 0x00f) << 9),
+      get_word((0x82CE4F, 0x82DBC2)[set] + i * 2) - ((room & 0x1f0) << 5),
+    ],
+    'player_xy' : [ player_x, player_y ],
+    'camera_xy' : [
+      get_word((0x82D277, 0x82DBFA)[set] + i * 2),
+      get_word((0x82D16D, 0x82DBEC)[set] + i * 2),
+    ],
+    'blockset' : get_byte((0x82D381, 0x82DC08)[set] + i),
+    'music' : tables.kMusicNames[get_byte((0x82D82E, 0x82DC4E)[set] + i)],
+    'palace' : tables.kPalaceNames[(get_int8((0x82D48B, 0x82DC16)[set] + i) + 2) >> 1],
+    'doorway_orientation' : get_int8(0x82D510 + i) if set == 0 else 0,
+    'plane' : get_byte((0x82D595, 0x82DC1D)[set] + i) & 0xf,
+    'ladder_level' : get_byte((0x82D595, 0x82DC1D)[set] + i) >> 4,
+    'quadrants' : [
+      'double_x' if (get_byte((0x82D61a, 0x82DC24)[set] + i) & 0x20) != 0 else 'single_x',
+      'double_y' if (get_byte((0x82D61a, 0x82DC24)[set] + i) & 0x2) else 'single_y',
+      kQuadrantNames[get_byte((0x82D69F, 0x82DC2B)[set] + i)]
+      ],
+    'floor' : get_int8((0x82D406, 0x82DC0F)[set] + i),
+  }
+
+  se = get_se((0x82C91D, 0x82DB7C)[set], y['player_xy'], y['quadrants'])
+  if se != [0, 0, 0, 0, 0, 0, 0, 0]:
+    y['repair_scroll_bounds'] = se
+  y['house_exit_door'] = get_exit_door(i)
+
+#  quadrant_byte = (2 if player_y & 0x100 else 0) + (16 if player_x & 0x100 else 0)
+#  if get_byte((0x82D69F, 0x82DC2B)[set] + i) != quadrant_byte:
+#    print('Room %d has incorrect quadrant byte' % room, y['quadrants'])
+  if set:
+    y['associated_entrance_index'] = get_word(0x82DC40 + i * 2)
+  return room, y 
+
+@cache
+def get_entrance_info(set):
+  r = {}
+  for i in range(133 if set == 0 else 7):
+    room, y = _get_entrance_info_one(i, set)
+    r.setdefault(room, []).append(y)
+  return r
+
+@cache 
+def pits_hurt_player():
+  return set(get_word(0x80990C + i * 2) for i in range(57))
+
+def print_room(room_index):
+  p = 0x1f8000 + room_index * 3
+  room_addr = get_byte(p) | get_byte(p+1) << 8 | get_byte(p+2) << 16
+  p = 0x40000 | get_word(0x4f502 + room_index * 2)
+  if p == 0x4FFEF:
+    p = 0x82EDC5 # just some place with zeros
+  floor, layout = get_byte(room_addr), get_byte(room_addr + 1)
+
+  flags = get_byte(p + 0)
+  p7, p8 = get_byte(p + 7), get_byte(p + 8)
+
+  ea = 0x890000 + get_word(0x89D62E + room_index * 2)
+  sort_sprites_setting = get_byte(ea)
+
+  header = {
+    'floor1': floor & 0xf,
+    'floor2' : floor >> 4,
+    'layout': layout >> 2,
+    'start_quadrant' : layout & 3,
+    'bg2' : tables.kBg2[flags >> 5],
+    'collision' : tables.kCollisionNames[flags >> 2 & 7],
+    'lights_out' : flags & 1,
+    'palette' : get_byte(p + 1),
+    'blockset' : get_byte(p + 2),
+    'enemyblk' : get_byte(p + 3),
+    'effect' : tables.kEffectNames[get_byte(p + 4)],
+    'tag0' : tables.kTagNames[get_byte(p + 5)],
+    'tag1' : tables.kTagNames[get_byte(p + 6)],
+    'hole0_dest' : [get_byte(p+9), p7 & 3],
+    'stair0_dest' : [get_byte(p+10), p7 >> 2 & 3],
+    'stair1_dest' : [get_byte(p+11), p7 >> 4 & 3],
+    'stair2_dest' : [get_byte(p+12), p7 >> 6 & 3],
+    'stair3_dest' : [get_byte(p+13),p8 & 3],
+    'tele_msg' : get_word(0x87F61D+room_index*2),
+    'sort_sprites' : sort_sprites_setting,
+    'pits_hurt_player' : room_index in pits_hurt_player()
+  }
+
+  def get_sprites():
+    ea = 0x890000 + get_word(0x89D62E + room_index * 2)
+    ea += 1
+    r = []
+    while get_byte(ea) != 0xff:
+      y, x, type = get_byte(ea), get_byte(ea+1), get_byte(ea+2)
+      if type == 0xe4:
+        if y == 0xfe or y == 0xfd:
+          r[-1].append('drop_key' if y == 0xfe else 'drop_big_key')
+          ea += 3
+          continue
+      elif x >= 0xe0:
+        floor = y >> 7
+        r.append([x & 0x1f, y & 0x1f, 'lower' if floor else 'upper', tables.kSpriteNames[type + 0x100]])
+        ea += 3
+        continue
+      subtype = (x >> 5) | ((y >> 5) & 3) << 3
+      floor = y >> 7
+      name = tables.kSpriteNames[type]
+      if subtype != 0:
+        i = name.index('-')
+        name = name[:i] + ('.%d' % subtype) + name[i:]
+      r.append([x & 0x1f, y & 0x1f, 'lower' if floor else 'upper', name])
+      ea += 3
+    return r
+
+  def get_secrets():
+    ea = 0x810000 | get_word(0x81db69 + room_index * 2)
+    xs = []
+    while get_word(ea) != 0xffff:
+      pos = get_word(ea)
+      assert pos%2==0
+      x, y = pos//2%64, pos//2//64 
+      xs.append([x, y, tables.kSecretNames[get_byte(ea+2)]])
+      ea += 3
+    return xs
+
+  def get_chests():
+    r = []
+    for data, big in get_chest_info().get(room_index, []):
+      if big:
+        r.append('%d!' % data)
+      else:
+        r.append(data)
+    return r
+      
+  sprites = get_sprites()
+  secrets = get_secrets()
+
+  data = {'Header' : header, 'Sprites' : sprites, 'Secrets' : secrets, 'Chests' : get_chests()}
+  data['Entrances'] = get_entrance_info(0).get(room_index, [])
+  if room_index in get_entrance_info(1):
+    data['StartingPoints'] = get_entrance_info(1)[room_index]
+
+  p = room_addr + 2
+  p, objs, doors = decode_room_objects(p)
+  data['Layer1'] = objs
+  if doors: data['Layer1.doors'] = doors
+
+  p, objs, doors = decode_room_objects(p)
+  data['Layer2'] = objs
+  if doors: data['Layer2.doors'] = doors
+
+  p, objs, doors = decode_room_objects(p)
+  data['Layer3'] = objs
+  if doors: data['Layer3.doors'] = doors
+  
+  return yaml.dump(data, default_flow_style=None, sort_keys=False)
+
+def print_all_dungeon_rooms():
+  for i in range(320):
+    s = print_room(i)
+    open( 'dungeon/dungeon-%d.yaml' % i, 'w').write(s)
+
+def print_default_rooms():
+  def print_default_room(idx):
+    p = 0x84EF2F + idx * 3
+    room_addr = get_byte(p) | get_byte(p+1) << 8 | get_byte(p+2) << 16
+    p, objs, doors = decode_room_objects(room_addr)
+    assert doors == None
+    return objs
+  default_rooms = {}
+  for i in range(8):
+    default_rooms['Default%d' % i] = print_default_room(i)
+  s = yaml.dump(default_rooms, default_flow_style=None, sort_keys=False)
+  open('dungeon/default_rooms.yaml', 'w').write(s)
+
+def print_overlay_rooms():
+  def print_overlay_room(idx):
+    p = 0x84ECC0 + idx * 3
+    room_addr = get_byte(p) | get_byte(p+1) << 8 | get_byte(p+2) << 16
+    p, objs, doors = decode_room_objects(room_addr)
+    assert doors == None
+    return objs
+  default_rooms = {}
+  for i in range(19):
+    default_rooms['Overlay%d' % i] = print_overlay_room(i)
+  s = yaml.dump(default_rooms, default_flow_style=None, sort_keys=False)
+  open('dungeon/overlay_rooms.yaml', 'w').write(s)
+
+def make_directories():
+  os.makedirs('img', exist_ok=True)
+  os.makedirs('overworld', exist_ok=True)
+  os.makedirs('dungeon', exist_ok=True)
+  os.makedirs('sound', exist_ok=True)
+
+def print_all_text_stuff():
+  print_all_overworld_areas()
+  print_all_dungeon_rooms()
+  print_overlay_rooms()
+  print_default_rooms()
+  print_dialogue()
+  print_map32_to_map16(open('map32_to_map16.txt', 'w'))
+
+def main():
+  make_directories()
+  print_all_text_stuff()
+  extract_music.extract_sound_data(util.ROM)
+  sprite_sheets.decode_link_sprites()
+  sprite_sheets.decode_sprite_sheets()
+  sprite_sheets.decode_hud_icons()
+  sprite_sheets.decode_font()
+ 
+if __name__ == "__main__":
+  util.load_rom(sys.argv[1] if len(sys.argv) >= 2 else None)
+  main()
+
binary files /dev/null b/assets/palette_usage.bin differ
--- /dev/null
+++ b/assets/restool.py
@@ -1,0 +1,52 @@
+import argparse
+import util
+import sys
+import os
+
+os.chdir(os.path.dirname(__file__))
+
+
+parser = argparse.ArgumentParser(description='Resource tool used to build zelda3_assets.dat', allow_abbrev=False)
+parser.add_argument('-r', '--rom', nargs='?', metavar='ROM')
+parser.add_argument('--extract-from-rom', '-e', action='store_true', help='Extract/overwrite things from the ROM')
+
+optional = parser.add_argument_group('Language settings')
+optional.add_argument('--extract-dialogue', action='store_true', help = 'Extract dialogue from a translated ROM')
+optional.add_argument('--languages', action='store', metavar='L1,L2', help = 'Comma separated list of additional languages to build (de,fr,fr-c,en,es,pl,pt,redux,nl,sv).')
+
+optional = parser.add_argument_group('Debug things')
+optional.add_argument('--no-build', action='store_true', help="Don't actually build zelda3_assets.dat")
+optional.add_argument('--print-strings', action='store_true', help="Print all dialogue strings")
+optional.add_argument('--print-assets-header', action='store_true')
+
+optional = parser.add_argument_group('Image handling')
+optional.add_argument('--sprites-from-png', action='store_true', help="When compiling, load sprites from png instead of from ROM")
+
+args = parser.parse_args()
+
+if args.extract_dialogue:
+  ROM = util.load_rom(args.rom, True)
+  import extract_resources, sprite_sheets
+  sprite_sheets.decode_font()
+  extract_resources.print_dialogue()
+  sys.exit(0)
+
+ROM = util.load_rom(args.rom)
+
+want_compile = True
+
+if args.extract_from_rom:
+  import extract_resources
+  extract_resources.main()
+
+if args.print_strings:
+  import text_compression
+  text_compression.print_strings(ROM)
+  want_compile = False
+
+if want_compile and not args.no_build:
+  import compile_resources
+  compile_resources.main(args)
+
+
+
--- /dev/null
+++ b/assets/sprite_sheet_info.py
@@ -1,0 +1,1547 @@
+class Entry:
+  def __init__(self, name, dungeon_or_ow, tileset_and_pal, ss_idx, matrix, pal_base):
+    self.name = name.replace(' - ', ': ')
+    self.dungeon_or_ow = dungeon_or_ow
+    self.tileset, self.palset_idx = tileset_and_pal
+    self.ss_idx = ss_idx
+    self.matrix = matrix
+    self.pal_base = pal_base
+
+entries = []
+def add(name, lw = None, dw = None, sheet = None, ow = None, dung = None, ss_1 = None, ss_2 = None, ss_3 = None, ss_4 = None, palette = None):
+  def doit(tileset_and_pal, dungeon_or_ow, suffix = ''):
+    all_chars = sorted(set("".join([ss.lower() for ss in (ss_1, ss_2, ss_3, ss_4) if ss != None])))
+    for ch in all_chars:
+      if ch == '\n' or ch == '.' or ch == 'o': continue
+      for ss_idx, ss in enumerate((ss_1, ss_2, ss_3, ss_4)):
+        if ss == None: continue
+        ss = ss.lower().replace('o', 'x')
+        matrix = ss.splitlines()[1:]
+        assert len(matrix) == 4 and all(len(m) == 16 for m in matrix), name
+        matrix2 = [[('x' if x == ch else '.') for x in m] for m in matrix]
+        if any('x' in m for m in matrix2):
+          entries.append(Entry(name + suffix, dungeon_or_ow, tileset_and_pal, ss_idx, matrix2, palette if ch == 'x' else int(ch)))
+
+  if lw and dw:
+    doit(lw, 0, ' - LW')
+    doit(dw, 1, ' - DW')
+  elif lw:
+    doit(lw, 0)
+  elif dw:
+    doit(dw, 1)
+  elif ow:
+    doit(ow, 0)
+  elif dung:
+    doit(dung, 2)
+  elif sheet:
+    doit(sheet, 3)
+
+
+add("00 - Raven", lw=(4, 3), dw=(23, 13), ss_4 = """
+....XXXXXX......
+....XXXXXX......
+................
+................""")
+
+add("01 - Vulture", ow=(8, 4), ss_3 = """
+XXXXXXXX........
+XXXXXXXX........
+................
+................""")
+
+add("04 - PullSwitch", dung=(6, 29), ss_4 = """
+..............XX
+..............XX
+..............XX
+..............XX""")
+
+add("07 - PullSwitch2", dung=(4, 0), ss_3 = """
+................
+................
+..XXXX..........
+..XXXX..........""")
+
+add("08 - Octorok", lw=(11, 3), dw=(22, 10), ss_3 = """
+XXXXXX..........
+XXXXXX..........
+XXXX.....XXX....
+XXXX....XXXXX...""")
+
+add("09 - Moldorm", dung=(12, 6), ss_3 = """
+5555555555666666
+5555555555666666
+5555555566666666
+5555555566666666""")
+
+add("0b - Chicken", lw=(6, 1), dw=(21, 16), ss_4 = """
+................
+................
+..........XXXX..
+..........XXXX..""")
+
+add("0d - Buzzblob", ow=(7, 6), ss_4 = """
+..........XXXXXX
+..........XXXXXX
+XXXXXX..........
+XXXX............""")
+
+add("0e - SnapDragon", ow=(19, 14), ss_1 = """
+................
+................
+........XXXX....
+........XXXXXXXX""", ss_3 = """
+............XXXX
+............XXXX
+..........XXXXXX
+..........XXXXXX""")
+
+add("0f - Octoballon", ow=(4, 3), ss_3 = """
+......XX....XX..
+......XX....XX..
+............XX..
+.............X..""")
+
+add("11 - Hinox", dw=(19, 14), ss_1 = """
+33333333....3333
+33333333....3333
+333333......3333
+333333..........""")
+
+add("12 - Moblin", ow=(19, 14), ss_3 = """
+XXXXXXXXXXXX....
+XXXXXXXXXXXX....
+XXXXXXXXXX......
+XXXXXXXXXX......""")
+
+add("13 - MiniHelmasaur", dung=(12, 26), ss_2 = """
+..............XX
+............X.XX
+....XXXXXXXXXXXX
+....XXXXXXXXXXXX""")
+
+add("15 - Antifairy", dung=(8, 10), ss_4 = """
+................
+................
+.1.1............
+................""")
+
+# Aginah is (16, 7)
+add("16 - Elder", dung=(16, 28), ss_3 = """
+................
+................
+XXXXXX..........
+XXXXXX..........""")
+
+add("17 - Hoarder", ow=(4, 3), ss_4 = """
+................
+................
+......XXXX......
+......XXXX......""")
+
+
+add("18 - MiniMoldorm", dung=(19, 13), ss_2 = """
+.............X..
+.............X..
+XXXX............
+XXXX............""")
+
+add("19 - Poe", lw=(3, 2), dw=(21, 16), ss_4 = """
+................
+................
+......XX........
+......XX........""")
+
+add("1a - Smithy", dung=(5, 30), ss_2 = """
+XXXXXX..........
+XXXXXX..........
+XXXXXX..........
+XXXXXX..........""")
+
+add("1a - Smithy", ow=(29, 0), ss_4 = """
+........XX......
+........XX......
+................
+................""")
+
+add("1c - Statue", dung=(17, 10), ss_4 = """
+XXX.............
+XX..............
+................
+................""")
+
+add("1e - CrystalSwitch", dung=(8, 15), ss_4 = """
+................
+................
+....11..........
+....11..........""")
+
+add("1f - SickKid", dung=(13, 21), ss_1 = """
+..........6666XX
+..........6666XX
+.......X......XX
+.......X......XX""")
+
+
+add("20 - Sluggula", dung=(29, 17), ss_3 = """
+XXXXXX..........
+XXXXXX..........
+xx........xxxxxx
+xx........xxxxxx""")
+
+
+add("21 - PushSwitch", dung=(17, 10), ss_4 = """
+..........xxxx..
+..........xxxx..
+..........xx....
+..........xx....""")
+
+add("22 - Ropa", ow=(19, 14), ss_1 = """
+........xxxx....
+........xxxx....
+......xx........
+......xx........""")
+
+# also used for blue bari
+add("23 - RedBari", dung=(8, 15), ss_1 = """
+................
+................
+xxxx..xx........
+xxxx..xx........""")
+
+add("25 - TalkingTree (S27)", dw=(19, 16), ss_4 = """
+................
+................
+........xx......
+........xx......""")
+
+add("25 - TalkingTree (S21)", dw=(21, 16), ss_1 = """
+................
+................
+........xx......
+........xx......""")
+
+add("26 - HardhatBeetle", dung=(19, 13), ss_2 = """
+xxxxxxxxxxxxx...
+xxxxxxxxxxxx....
+................
+................""")
+add("27 - Deadrock", ow=(16, 9), ss_4 = """
+..xxxxxx........
+..xxxxxx........
+..xxxx..........
+..xxxx..........""")
+add("28 - DarkWorldHintNpc", dung=(5, 7), ss_2 = """
+..........55....
+..........55....
+..............55
+..............55""")
+add("28 - DarkWorldHintNpc", dung=(5, 7), ss_1 = """
+................
+................
+....55..........
+....55..........""")
+add("28 - DarkWorldHintNpc", dung=(5, 7), ss_1 = """
+....44..........
+....44..........
+................
+................""")
+add("28 - DarkWorldHintNpc", dung=(7, 7), ss_1 = """
+..............55
+..............55
+..............55
+..............55""")
+add("28 - DarkWorldHintNpc", dung=(5, 28), ss_2 = """
+................
+................
+..........5555..
+..........5555..""")
+
+
+add("29 - Human/Woman", dung=(15, 35), ss_1 = """
+............xxxx
+............xxxx
+................
+................""", ss_4 = """
+..........xxxxxx
+..........xxxxxx
+................
+................""")
+
+add("29 - Human/Thief", dung=(40, 7), ss_1 = """
+xxxxxxxx..xx..xx
+xxxxxxxx..xx..xx
+xxxxxx......xx..
+xxxxxx......xx..""", palette = 7)
+
+
+add("29 - Human/Elder", dung=(15, 35), ss_3 = """
+....xxxxxx......
+....xxxxxx......
+..xx............
+..xx............""")
+
+add("2a - SweepingLady", ow=(6, 1), ss_3 = """
+..........xxxxxx
+..........xxxxxx
+................
+................""")
+
+add("2b - Hobo", ow=(12, 8), ss_3 = """
+........xxxx....
+........xxxx....
+......xxxxxxx...
+......xxxxxxx...""")
+
+add("2c - LumberJacks", ow=(26, 6), ss_1 = """
+..............xx
+..............xx
+................
+................""", ss_3 = """
+................
+................
+....xxxxxx......
+....xxxxxx....44""")
+
+add("2e - FluteKid - LW", lw=(15, 1), ss_3= """
+................
+................
+........xxxx...x
+........xxxx..xx""")
+
+
+add("2e - FluteKid - DW", dw=(17,11), ss_4 = """
+........xxxx00..
+........xxxx00..
+......xxxx..00..
+......xxxx..00..""", palette = 3)
+
+
+add("2f - MazeGameLady", ow=(6, 1), ss_4 = """
+xxxx............
+xxxx............
+xxxxxxxxxx......
+xxxxxxxxxx......""")
+
+add("30 - MazeGameGuy", ow=(6, 1), ss_1="""
+xxxx............
+xxxx............
+xx..............
+xx..............""")
+
+add("31 - FortuneTeller", dung=(5, 30), ss_1 = """
+..........xxxx..
+..........xxxx..
+..........x.x...
+................""", ss_2 = """
+................
+................
+......xxxx......
+......xxxx......""")
+
+add("32 - QuarrelBros", dung=(15,2), ss_1 = """
+....XX..XXXX....
+....XX..XXXX....
+................
+................""")
+
+add("34 - YoungSnitchLady", ow=(6,1), ss_1 = """
+................
+................
+....xxxxxx......
+....xxxxxx......""", ss_4 = """
+..xx............
+..xx............
+....xxxxxx......
+....xxxxxx......""")
+
+add("35 - InnKeeper", dung=(15,5), ss_4 = """
+....xxxxxxxxxxxx
+....xxxxxxxxxxxx
+..............xx
+..............xx""")
+
+add("36 - Witch", ow=(13, 6), ss_3 = """
+xxxxxx11........
+xxxxxx11........
+..............xx
+..............xx""")
+
+add("39 - Locksmith", ow=(10, 0), ss_4 = """
+................
+................
+..........xxxx..
+..........xxxx..""")
+
+add("3a - MagicBat", dung=(9, 32), ss_4 = """
+................
+................
+..........xxxx..
+..........xxxx.x""")
+
+add("3b - TreeTop", ow=(26, 6), ss_1 = """
+xxxxxxxxxx......
+xxxxxxxxxx......
+xxxxxxxxxxxx....
+xxxxxxxxxxxx....""", palette = 0)
+
+add("3c - TroughBoy", ow=(6, 1), ss_3 = """
+4444............
+4444............
+55........55....
+55........55....""")
+
+add("3d - OldSnitchLady", ow=(6, 1), ss_4 = """
+xxxx............
+xxxx............
+xxxxxxxxxx......
+xxxxxxxxxx......""")
+
+# rock crab is included in two sheets
+add("3e - RockCrab", ow=(10, 0), ss_4 = """
+................
+................
+......xxxx......
+......xxxx......""", palette = 0)
+
+add("3e - RockCrab (S16)", ow=(33, 0), ss_4 = """
+................
+................
+......xxxx......
+......xxxx......""", palette = 0)
+
+
+add("3f - PalaceGuard", ow=(2, 1), ss_1 = """
+xx..............
+xx..............
+......xxxxx.....
+......xxxxx.....""", palette = 4)
+
+add("3f - PalaceGuard", ow=(2, 1), ss_2 = """
+xxxxxxxx......xx
+xxxxxxxx......xx
+....xx..........
+....xx..........""")
+
+
+add("40 - ElectricBarrier", ow=(2, 1), ss_4 = """
+..........xxxx..
+..........xxxx..
+......xxxx......
+......xxxx......""")
+
+
+add("41 - Soldier", dung=(3, 0), ss_2 = """
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx""")
+
+add("41 - Soldier (DW)", dung=(36, 37), ss_2 = """
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx""", ss_3 = """
+................
+................
+......xxxxxxxxx.
+......xxxxxxxxx.
+""")
+
+add("44 - Warrior", dung=(33, 38), ss_1 = """
+xxxxxx..........
+xxxxxx..........
+................
+................""")
+
+add("47 - GrassArcher", ow=(4, 3), ss_1 = """
+..xxxxxxxxxxxxxx
+..xxxxxxxxxxxxxx
+11xxxx..........
+11xxxx..........""")
+
+add("4a - RedBombKnight", ow=(1, 3), ss_1 = """
+xxxxxxxxxxxxxxx.
+xxxxxxxxxxxxxxx.
+..xx........xxxx
+..xx........xxx.""")
+
+add("4b - GreenKnifeGuard", ow=(2, 1), ss_3 = """
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xx....xxxxxxxxxx
+xx....xxxxxxxxxx""")
+
+add("4c - Geldman", ow=(8, 4), ss_3 = """
+................
+................
+xxxxxxxx........
+xxxxxxxxx.......""")
+
+add("4d - Toppo", ow=(4, 3), ss_4 = """
+xxxx............
+xxxx............
+................
+................""")
+
+add("4e - Popo", dung=(8, 11), ss_2 = """
+xxxx............
+xxxx............
+................
+................""")
+
+add("51 - ArmosStatue", ow=(5, 7), ss_4 = """
+xx..............
+xx..............
+xx..............
+xx..............""", palette = 5)
+
+add("52 - ZoraKing", ow=(14, 8), ss_3 = """
+........2222....
+........2222....
+........2.......
+................""", ss_4 = """
+xxxx2222........
+xxxx2222........
+xxxx2222..xx....
+xxxx2222..xx....""")
+
+add("53 - ArmosKnight", dung=(9, 11), ss_4 = """
+xxxxxxxxxx......
+xxxxxxxxxx......
+xxxxxx..........
+xxxxxx..........""")
+
+add("54 - Lanmolas", dung=(11, 4), ss_4 = """
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx""")
+
+add("55 - FireBallZora", lw=(4, 3), dw=(22, 10), ss_3 = """
+........2222....
+........2222....
+....xxxx2.......
+....xxxx........""")
+
+add("56 - WalkingZora", ow=(14, 8), ss_4 = """
+........xxxxxxxx
+........xxxxxxxx
+........xx..xxxx
+........xx..xxxx""")
+
+add("57 - HyliaObstacle", ow=(8, 4), ss_3 = """
+..............xx
+..............xx
+..............xx
+..............xx""")
+
+add("58 - Crab", ow=(4, 3), ss_3 = """
+..............xx
+..............xx
+..............xx
+..............xx""")
+
+add("59 - LostWoodsBird", ow=(12, 1), ss_4 = """
+................
+................
+...xxxx.........
+...xxxx.........""")
+
+add("5a - LostWoodsSquirrel", ow=(12, 1), ss_4 = """
+.....xx.........
+.....xx.........
+.xx.............
+.xx.............""")
+
+add("5b - Spark", dung=(17, 10), ss_1 = """
+................
+................
+........xx......
+........xx......""", palette = 2)
+
+add("5d - Roller", dung=(30, 24), ss_3 = """
+........xxx.....
+........xxx.....
+................
+................""")
+
+add("5f - Roller", dung=(30, 24), ss_3 = """
+..............xx
+..............xx
+..............xx
+................""")
+  
+add("61 - Beamos", dung=(10, 9), ss_2 = """
+........xx555...
+........xx551...
+........xx......
+........xx......""")
+
+add("62 - MasterSword", ow=(12, 1), ss_3 = """
+xxxxxxxx........
+xxxxxxxx........
+xxxxxx..........
+xxxxxx..........""", ss_4 = """
+...xx...........
+...xx...........
+x......xx.......
+x......xx.......""")
+
+add("63 - DebirandoPit", dung=(10, 9), ss_1 = """
+..xxxx..........
+..xxxx..........
+..xx....xxxx....
+..xx....xxxx....""")
+
+add("64 - Debirando", dung=(10, 9), ss_1 = """
+xx..............
+xx..............
+xx..............
+xx..............""", palette = 3)
+
+add("65 - ArcherGame", dung=(5, 30), ss_1 = """
+..xxxxxxxx......
+..xxxxxxxx......
+..xxxxxxxx.x....
+xxxxxxxxxxxx....""", palette = 4)
+
+add("66 - Cannon", dung=(10, 9), ss_1 = """
+..........xxxxxx
+..........xxxxxx
+....44........xx
+....44........xx""")
+
+add("6a - MorningStar", dung=(4, 1), ss_1 = """
+xxxxxxxxxxxxxxx.
+xxxxxxxxxxxxxxx.
+..xx......xxxxxx
+..xx......xxxxxx""", ss_2 = """
+......xxxxxxx.xO
+......xxxxxxx.xO
+xxxxxxxxxxx.....
+xxxxxxxxxxx.....""")
+
+add("6b - CannonTrooper", dung=(4, 1), ss_1 = """
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxx.""")
+
+add("6d - Rat", dung=(1, 1), ss_3 = """
+......xxxxxxxxxx
+......xxxxxxxxxx
+..xx............
+..xx............""")
+
+add("6d - Rat (DW)", dung=(33, 35), ss_3 = """
+......xxxxxxxxxx
+......xxxxxxxxxx
+xxxx............
+xxxx............""")
+
+
+
+add("6e - Rope", dung=(1, 1), ss_3 = """
+................
+................
+....xxxxxxxx....
+....xxxxxxxx....""")
+
+add("6e - Rope (DW)", dung=(33, 35), ss_3 = """
+................
+................
+....xxxxxxxx....
+....xxxxxxxx....""")
+
+add("6f - Keese", dung=(1, 1), ss_3 = """
+xxxxxx..........
+xxxxxx..........
+................
+................""")
+
+add("6f - Keese (DW)", dung=(33, 35), ss_3 = """
+xxxxxx..........
+xxxxxx..........
+................
+................""")
+
+add("70 - KingHelmasaurFireball", dung=(21, 16), ss_3 = """
+................
+................
+............xx..
+............xx..""", ss_4 = """
+..........xxxx..
+..........xxxx.x
+................
+................""")
+
+add("71 - Leever", dung=(10, 9), ss_1 = """
+......xxxx......
+......xxxx......
+......xxx.......
+......xxx.......""")
+
+add("72 - FairyPond", dung=(7, 7), ss_4 = """
+........xxxxxxxx
+........xxxxxxxx
+................
+................""")
+
+add("72 - FairyPond", dung=(7, 34), ss_4 = """
+................
+................
+.........xxxxxxx
+.........xxxxxxx""")
+
+add("73 - UncleAndPriest", dung=(6, 29), ss_1 = """
+OOOOOOxxxxxxxxxx
+OOOOOOxxxxxxxxxx
+xxxxxxxxxxxx0000
+xxxxxxxxxxxx0000""", palette = 4)
+
+add("73 - UncleAndPriest", dung=(13, 21), ss_1 = """
+xxxxxxxxxx......
+xxxxxxxxxx......
+xxxxxxx.xxxxxx..
+xxxxxxx.xxxxxx..""", palette = 4)
+
+
+
+add("74 - RunningMan", ow=(6, 1), ss_1 = """
+................
+................
+..........xxxxxx
+..........xxxxxx""", ss_4 = """
+..........xxxxxx
+..........xxxxxx
+..............xx
+..............xx""")
+
+add("75 - BottleVendor", ow=(6, 1), ss_3 = """
+........xx......
+........xx......
+..xx........xx..
+..xx........xx..""")
+
+add("78 - MrsSahasrahla", dung=(5, 2), ss_1 = """
+................
+................
+........xx......
+........xx......""", ss_3 = """
+..............xx
+..............xx
+................
+................""")
+
+add("7a - Agahnim", dung=(24, 27), ss_1 = """
+............xxxx
+............xxxx
+............xxxx
+............xxxx""", ss_2 = """
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx""", ss_3 = """
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx""", ss_4 = """
+xxxxxx..xxxx...x
+xxxxxx..xxxx..xx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx""", palette = 6)
+
+add("7b - AgahnimBalls", dung=(24, 27), ss_4 = """
+......xx....xxx.
+......xx....xx..
+................
+................""", palette = 2)
+
+add("7c - StalfosHead", dung=(8, 11), ss_1 = """
+xxxxxx..........
+xxxxxx..........
+................
+................""")
+
+add("7d - BigSpikeBlock", dung=(12, 16), ss_4 = """
+....xx..........
+....xx..........
+................
+................""")
+
+add("7e - FireBlade", dung=(17, 10), ss_1 = """
+................
+................
+........xx......
+........xx......""")
+
+add("81 - WaterBug", dung=(17, 10), ss_3 = """
+xxxxxx..........
+xxxxxx..........
+................
+................""")
+
+add("83 - GreenEyegore", dung=(10, 9), ss_3 = """
+..........xxxxxx
+..........xxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxx..""")
+
+add("83 - GreenEyegore", dung=(8, 39), ss_2 = """
+....xxxx......xx
+....xxxx......xx
+..xxxxxx..xxxxxx
+..xxxxxx..xxxxxx""")
+
+add("85 - YellowStalfos", dung=(25, 15), ss_1 = """
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+....xx....xxxxxx
+....xx....xxxxxx""")
+
+add("86 - Kodongo", dung=(25, 6), ss_3 = """
+............xx..
+............xx..
+xxxxxxxxxxxxxx..
+xxxxxxxxxxxxxx..""")
+
+add("88 - Mothula", dung=(26, 14), ss_3 = """
+xxxxxxxxxx.xxxxx
+xxxxxxxxxx.xxxxx
+xxxxxxxxxx..xxxx
+xxxxxxxxxx..xxxx""")
+
+add("89 - MothulaRing", dung=(26, 14), ss_3 = """
+..........x.....
+..........x.....
+..........xx....
+..........xx....""")
+
+add("8a - SpikeBlock", dung=(8, 15), ss_4 = """
+................
+................
+......xx........
+......xx........""")
+
+add("8b - Gibdo", dung=(19, 13), ss_3 = """
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxx..........
+xxxxxx..........""")
+
+add("8c - Arrghus", dung=(20, 8), ss_3 = """
+xxxxxxxxxx......
+xxxxxxxxxx......
+xxxxxxxxxx......
+xxxxxxxxxx......""")
+
+add("8e - TerrorPin", dung=(25, 15), ss_3 = """
+..........xx..xx
+..........xx..xx
+..............xx
+..............xx""")
+
+add("8f - Blob", dung=(17, 8), ss_2 = """
+xxxxxx..........
+xxxxxx..........
+x...............
+x...............""")
+
+add("90 - WallMaster", dung=(19, 13), ss_3 = """
+................
+................
+......xxxxxxxxxx
+......xxxxxxxxxx""")
+
+add("91 - StalfosKnight", dung=(28, 19), ss_2 = """
+......xxxxxxxx..
+......xxxxxxxx..
+.xxxxxxxxxx.....
+.xxxxxxxxxx.....""")
+
+add("92 - HelmasaurKing", dung=(21, 16), ss_3 = """
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxx66
+xxxxxxxxxxxxxx66""", ss_4 = """
+6666666666xxxxxx
+6666666666xxxxxx
+6666xxOOOOOOOOOO
+6666xxOOOOOOOOOO""", palette = 5)
+
+add("93 - Bumper", dung=(12, 26), ss_4 = """
+................
+................
+............xx..
+............xx..""")
+
+add("94 - Pirogusu", dung=(17, 10), ss_3 = """
+.......x....xxxx
+.......x....xxxx
+..........xxxxxx
+..........xxxxxx""")
+
+add("95 - LaserEye", dung=(29, 17), ss_4 = """
+......xxxx......
+..2...xxxx......
+................
+...2............""")
+
+add("99 - Pengator", dung=(28, 19), ss_3 = """
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxx..........
+xxxxxx..........""")
+
+add("9a - Kyameron", dung=(17, 10), ss_3 = """
+......x.xxxx....
+......x.xxxx....
+xxxxxxxxxx......
+xxxxxxxxxx......""")
+
+add("9b - Wizzrobe", dung=(29, 17), ss_3 = """
+......xxxxxxxxxx
+......xxxxxxxxxx
+....xx..........
+..xxxx..........""")
+
+add("9b - Wizzrobe (DW)", dung=(36, 37), ss_3 = """
+......xxxxxxxxxx
+......xxxxxxxxxx
+....xx..........
+..xxxx..........""")
+
+
+
+add("9c - Babasu", dung=(17, 10), ss_2 = """
+..............xx
+..............xx
+...........xxxxx
+...........xxxxx""", palette=1)
+
+add("9e - HauntedGroveOstrich", ow=(15, 1), ss_3 = """
+xxxxxx..........
+xxxxxx..........
+xxxxxx..........
+xxxxxx..........""")
+
+add("9f - HauntedGroveRabbit", ow=(15, 1), ss_3 = """
+........xxxxxx..
+........xxxxxx..
+......xx........
+......xx........""")
+
+add("A0 - HauntedGroveBird", ow=(15, 1), ss_3 = """
+......xx......xx
+......xx......xx
+............xxx.
+............xx..""")
+
+add("A1 - Freezor", dung=(28, 19), ss_3 = """
+................
+................
+......xxxxxxxxxx
+......xxxxxxxxxx""")
+
+add("A2 - Kholdstare", dung=(22, 20), ss_3 = """
+xxxxxxxx....xx..
+xxxxxxxx....xx..
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx""")
+
+add("A4 - FallingIce", dung=(22, 20), ss_3 = """
+........xxxx..xx
+........xxxx..xx
+................
+................""")
+
+add("A5 - Zazak", dung=(27, 23), ss_3 = """
+xxxxxxxxxx......
+xxxxxxxxxx......
+xxxxxxxxxx......
+xxxxxxxxxx......""")
+
+add("A8 - GreenZirro", ow=(19, 14), ss_4 = """
+xxxxxxxx........
+xxxxxxxx........
+xxxxxxxx........
+xxxxxxxx.......7""")
+
+add("AA - Pikit", ow=(19, 14), ss_4 = """
+........xxxxxxxx
+........xxxxxxxx
+..........xxxxx.
+..........xxxxx.""")
+
+add("AD - OldMan", dung=(1, 7), ss_3 = """
+................
+................
+............xxxx
+............xxxx""")
+
+
+add("B4 - PurpleChest", ow=(21, 16), ss_1 = """
+................
+................
+..............xx
+..............xx""", ss_4 = """
+................
+................
+..............xx
+..............xx""")
+
+add("B5 - BombShop", dung=(5, 31), ss_2 = """
+........xx..xxxx
+........xx..xx44
+................
+................""", palette = 1)
+
+add("B6 - Kiki", ow=(23, 13), ss_4 = """
+..........xxx.xx
+..........xxxxxx
+............xxxx
+............xxxx""")
+
+add("B9 - BullyAndPinkBall", dw=(20, 12), ss_4 = """
+....xx..........
+....xx..........
+xxxx............
+xxxx............""", palette = 6)
+
+add("B9 - BullyAndPinkBall", dw=(20, 12), ss_4 = """
+xxxx............
+xxxx............
+................
+................""")
+
+add("BB - Shopkeeper", dung=(5, 7), ss_1 = """
+xxxx............
+xxxx............
+xxxx............
+xxxx............""", palette = 5)
+
+add("BB - Shopkeeper", dung=(5, 7), ss_4 = """
+11..22......4422
+11..22......4422
+........22......
+........22......""")
+
+add("BB - Shopkeeper", dung=(15, 31), ss_2 = """
+......xx........
+......xx........
+................
+................""", palette = 6)
+
+add("BB - Shopkeeper", dung=(40, 5), ss_1 = """
+xxxxxxxx..xx..xx
+xxxxxxxx..xx..xx
+xxxxxx......xx..
+xxxxxx......xx..""", palette = 6)
+
+add("BB - Shopkeeper", dung=(15, 5), ss_1 = """
+xxxx............
+xxxx............
+xx..............
+xx..............""", palette = 6)
+
+add("BB - Shopkeeper", dung=(42, 32), ss_1 = """
+xxxxxxxx..xx..xx
+xxxxxxxx..xx..xx
+xxxxxx..........
+xxxxxx..........""", palette = 6)
+
+add("BC - Drunkard", dung=(15, 5), ss_1 = """
+......xx........
+......xx........
+..xx............
+..xx............""", ss_3 = """
+................
+................
+..............xx
+................""", palette = 4)
+
+add("BD - Viterous", dung=(22, 18), ss_4 = """
+xxxxxxxxxxxx....
+xxxxxxxxxxxx....
+xxxxxxxxxxxx....
+xxxxxxxxxxxx....""")
+
+add("BF - ViterousLightning", dung=(22, 18), ss_4 = """
+............xxxx
+............xxxx
+............xxxx
+............xxxx""")
+
+add("C0 - Catfish", ow=(22, 10), ss_3 = """
+......xxxxxxxxx.
+......xxxxxxxxx.
+........x...xxx.
+.............xx.""")
+
+add("C1 - CutsceneAgahnim", dung=(18, 12), ss_1 = """
+xxxxxx..........
+xxxxxx..........
+xxxxxxxx........
+xxxxxxx.........""", ss_3 = """
+xxxx............
+xxxx............
+xxxx............
+xxxx............""", ss_4 = """
+..............2.
+...............x
+............xxxx
+............xxxx""", palette = 5)
+
+add("C3 - Gibo", dung=(27, 23), ss_3 = """
+..........xxxxxx
+..........xxxxxx
+..........xxxxxx
+..........xxxxxx""")
+
+add("C7 - Pokey", dung=(30, 24), ss_3 = """
+xxxx............
+xxxx............
+xxxx............
+xxxx............""")
+
+add("C8 - BigFairy", dung=(7, 7), ss_3 = """
+..........xxxxxx
+..........xxxxxx
+..........xxxxxx
+..........xxxxxx""")
+
+add("C9 - Tektite", dw=(5, 7), ss_4 = """
+........xxxx....
+........xxxx....
+..........xx....
+..........xx....""", palette = 4)
+
+add("CA - ChainChomp", dung=(30, 24), ss_3 = """
+......xx...xxx..
+......xx....xx..
+......xxxxxx....
+......xxxxxx....""")
+
+add("CB - Trinexx", dung=(23, 25), ss_1 = """
+xxxx55xx55xxxxXX
+xxxx55xx55xxxxXX
+xxxx55xxxxxxxxXX
+xxxx55xxxxxxxxXX""", ss_4 = """
+xxxxxxXXXXXXXXXX
+xxxxxxXXXXXXXXXX
+xxxxxxxxxxXXXXxx
+xxxxxxxxxxXXXXxx""")
+
+add("CE - Blind", dung=(32, 23), ss_3 = """
+xxxxxxxxxxxxxx66
+xxxxxxxxxxxxxx66
+666666xxxxxx6666
+666666xxxxxx6666""", palette = 5)
+
+add("CF - Swamola", ow=(22, 15), ss_4 = """
+xxxx............
+xxxx............
+xxxxxxxxxxxx....
+xxxxxxxxxxxx....""")
+
+add("D0 - Lynel", ow=(20, 12), ss_4 = """
+......xxxxxxxxxx
+......xxxxxxxxxx
+....xxxxxxxxxxxx
+....xxxxxxxxxxxx""")
+
+add("D5 - DigGameGuy", ow=(27, 18), ss_2 = """
+xxxxxxx.........
+xxxxxxx.........
+................
+................""", palette = 5)
+
+add("D6 - Ganon", dung=(34, 33), ss_2 = """
+....xx..........
+....xx..........
+xxxxxx..........
+xxxxxx..........""", palette = 4)
+
+add("D6 - Ganon", dung=(34, 33), ss_1 = """
+xx5555xxxxxxxx55
+xx5555xxxxxxxx55
+xx5555xxxxxxxxxx
+xx5555xxxxxxxxxx""", ss_2 = """
+xxxx..xxxxxxxx55
+xxxx..xxxxxxxx55
+......xxxxxxxx55
+......xxxxxxxx55""", ss_3 = """
+xxxx55xxxxxxxxxx
+xxxx55xxxxxxxxxx
+xxxx55xxxxxxxxxx
+xxxx55xxxxxxxxxx""", ss_4 = """
+xxxxxx5555xxxx55
+xxxxxx5555xxxx55
+xxxxxx5555xxxx55
+xxxxxx5555xxxx55""", palette = 6)
+
+add("E7 - Mushroom", ow=(7, 5), ss_4 = """
+................
+................
+..............xx
+..............xx""", palette = 3)
+
+add("E8 - FakeSword", ow=(7, 5), ss_4 = """
+................
+................
+................
+....xx..........""")
+
+add("E9 - PotionShop", dung=(5, 5), ss_4 = """
+................
+................
+......xx........
+......xx........""", palette = 2)
+
+add("ED - SomariaPlatform", dung=(30, 24), ss_3 = """
+................
+................
+............XX..
+............XX..""")
+
+add("EE - MovableMantle", dung=(3, 0), ss_1 = """
+............xxxx
+............xxxx
+............xxxx
+............xxxx""")
+
+add("F2 - MedallionTablet", ow=(8, 4), ss_3 = """
+..........xxxx..
+..........xxxx..
+..........xxxx..
+..........xxxx..""")
+
+add("F4 - FallingRocks", ow=(5, 7), ss_4 = """
+............xxxx
+............xxxx
+............xxxx
+............xxxx""")
+
+add("XX - Unknown Sheet 00", sheet=(0, 1), ss_1 = """
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx""", palette = 4)
+
+add("XX - Unknown Sheet 01", sheet=(1, 1), ss_1 = """
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx""", palette = 4)
+
+add("XX - Unknown Sheet 02", sheet=(2, 1), ss_1 = """
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx""", palette = 4)
+
+add("XX - Unknown Sheet 03", sheet=(3, 1), ss_1 = """
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx""", palette = 4)
+
+add("XX - Unknown Sheet 04", sheet=(4, 1), ss_1 = """
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx""", palette = 4)
+
+add("XX - Unknown Sheet 05", sheet=(5, 1), ss_1 = """
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx""", palette = 4)
+
+add("XX - Unknown Sheet 06", sheet=(6, 1), ss_1 = """
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx""", palette = 4)
+
+add("XX - Unknown Sheet 07", sheet=(7, 1), ss_1 = """
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx""", palette = 4)
+
+add("XX - Unknown Sheet 08", sheet=(8, 1), ss_1 = """
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx""", palette = 4)
+
+add("XX - Unknown Sheet 09", sheet=(9, 1), ss_1 = """
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx""", palette = 4)
+
+add("XX - Unknown Sheet 10", sheet=(10, 1), ss_1 = """
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx""", palette = 4)
+
+add("XX - Unknown Sheet 11", sheet=(11, 1), ss_1 = """
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx""", palette = 4)
+
+add("XX - Unknown Sheet 14", ow=(37, 1), ss_1 = """
+........xx..xx..
+........xx..xx..
+........xxxx..xx
+........xxxx..xx""", palette = 4)
+
+
+add("XX - Unknown Sheet 15", ow=(26, 1), ss_1 = """
+..........xxxx..
+..........xxxx..
+............xxxx
+............xxxx""", palette = 4)
+
+
+add("XX - Unknown Sheet 21", ow=(21, 1), ss_1 = """
+............xx..
+............xx..
+................
+................""", palette = 4)
+
+add("XX - Unknown Sheet 27", ow=(25, 1), ss_4 = """
+................
+................
+...............x
+................""", palette = 4)
+
+add("XX - Unknown Sheet 37", ow=(93, 1), ss_3 = """
+................
+................
+..xx..xxxx......
+......xxxx......""", palette = 4)
+
+
+add("XX - Unknown Sheet 39", ow=(94, 1), ss_3 = """
+....xx..........
+....xx.....x....
+....xx..........
+....xx........xx""", palette = 4)
+
+add("XX - Unknown Sheet 41", dung=(36, 1), ss_3 = """
+xxxxxx..........
+xxxxxx..........
+xxxx...........x
+xx.............x""", palette = 4)
+
+
+add("XX - Unknown Sheet 42", ow=(107, 1), ss_3 = """
+.......xxx......
+.......xxx......
+................
+................""", palette = 4)
+
+add("XX - Unknown Sheet 43", dung=(16, 1), ss_4 = """
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx""", palette = 4)
+
+add("XX - Unknown Sheet 44", ow=(72, 1), ss_2 = """
+.............x..
+.............x..
+xx..............
+xx..............""", palette = 4)
+
+add("XX - Unknown Sheet 45", ow=(45, 1), ss_1 = """
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx""", palette = 4)
+
+add("XX - Unknown Sheet 46", ow=(73, 1), ss_3 = """
+xxxxxxxxxx......
+xxxxxxxxxx......
+................
+..............xx""", palette = 4)
+
+add("XX - Intro Sheet 50", sheet=(50, 1), ss_1 = """
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx""", palette = 4)
+
+add("XX - Ending Sheet 52", sheet=(52, 1), ss_2 = """
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx""", palette = 4)
+
+add("XX - Ending Sheet 53", sheet=(53, 1), ss_1 = """
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx""", palette = 4)
+
+add("XX - Unknown Sheet 54", ow=(40, 1), ss_4 = """
+xxx....x........
+xxx....x........
+................
+................""", palette = 4)
+
+add("XX - Unknown Sheet 55", ow=(12, 1), ss_3 = """
+............xxxx
+............xxxx
+.............xxx
+.............xxx""", palette = 4)
+
+add("XX - Unknown Sheet 72", ow=(2, 1), ss_1 = """
+................
+................
+...........xxxxx
+...........xxxxx""", palette = 4)
+
+add("XX - Unknown Sheet 75", ow=(27, 1), ss_1 = """
+................
+................
+.............x..
+............xx..""", palette = 4)
+
+
+add("XX - Unknown Sheet 76", ow=(13, 1), ss_3 = """
+..............xx
+..............xx
+..........xx....
+..........xx....""", palette = 4)
+
+add("XX - Unknown Sheet 82", dung=(19, 1), ss_4 = """
+xxxx......xxxx..
+xx.x......xxxx..
+x.x.....xxxx....
+xxx.....xxxx....""", palette = 4)
+
+add("XX - Unknown Sheet 83", dung=(38, 1), ss_4 = """
+...xxxxxxx....xx
+..xxxxxxxx....xx
+xxxxxxxxxx..xxxx
+xxxxxxxxxx..xxxx""", palette = 4)
+
+add("XX - Unknown Sheet 84", sheet=(84, 1), ss_3 = """
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx""", palette = 4)
+
+add("XX - Unknown Sheet 85", dung=(63, 1), ss_1 = """
+......xxxxxx....
+......xxxxxx....
+........xxxx....
+.......xxxxx....""", palette = 4)
+
+add("XX - Map Sheet 86", sheet=(86, 1), ss_2 = """
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx""", palette = 4)
+
+add("XX - Map Sheet 87", sheet=(87, 1), ss_3 = """
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx""", palette = 4)
+
+add("XX - Unknown Sheet 88", sheet=(88, 1), ss_3 = """
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx""", palette = 4)
+
+add("XX - Tagalong S89", sheet=(89, 1), ss_4 = """
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx""", palette = 4)
+
+add("XX - Unknown Sheet 90", dung=(5, 1), ss_4 = """
+..xx..xxxxxx....
+..xx..xxxxxx....
+xxxxxx....xxxxxx
+xxxxxx....xxxxxx""", palette = 4)
+
+add("XX - Unknown Sheet 91", sheet=(91, 1), ss_3 = """
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx""", palette = 4)
+
+add("XX - Unknown Sheet 92", sheet=(92, 1), ss_3 = """
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx""", palette = 4)
+
+add("XX - Unknown Sheet 93", ow=(43, 1), ss_3 = """
+xxxxxxxxxxxx....
+xxxxxxxxxxxx....
+xxxxxxxxxxxx....
+xxxxxxxxxxxx....""", palette = 4)
+
+add("XX - Unknown Sheet 94", sheet=(94, 1), ss_3 = """
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx""", palette = 4)
+
+add("XX - Unknown Sheet 95", sheet=(95, 1), ss_3 = """
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx""", palette = 4)
+
+add("XX - Unknown Sheet 96", sheet=(96, 1), ss_3 = """
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx""", palette = 4)
+
+add("XX - Map Sheet 97", sheet=(97, 1), ss_1 = """
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx""", palette = 4)
+
+add("XX - Map Sheet 98", sheet=(98, 1), ss_2 = """
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx""", palette = 4)
+
+add("XX - Map Sheet 99", sheet=(99, 1), ss_3 = """
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx""", palette = 4)
+
+add("XX - Tagalong S100", sheet=(100, 1), ss_1 = """
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx""", palette = 4)
+
+add("XX - Tagalong S101", sheet=(101, 1), ss_1 = """
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx""", palette = 4)
+
+
+add("XX - Tagalong S102", sheet=(102, 1), ss_1 = """
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx""", palette = 4)
--- /dev/null
+++ b/assets/sprite_sheets.py
@@ -1,0 +1,640 @@
+from PIL import Image
+import sprite_sheet_info
+import util
+from util import get_bytes, get_words, get_byte, cache
+import array
+import tables
+import sys
+
+override_armor_palette = None
+#override_armor_palette = [0x7fff, 0x237e, 0x11b7, 0x369e, 0x14a5,  0x1ff, 0x1078, 0x599d, 0x3647, 0x3b68, 0xa4a, 0x12ef, 0x2a5c, 0x1571, 0x7a18,
+#                          0x7fff, 0x237e, 0x11b7, 0x369e, 0x14a5,  0x1ff, 0x1078, 0x599d, 0x6980, 0x7691, 0x26b8, 0x437f, 0x2a5c, 0x1199, 0x7a18,
+#                          0x7fff, 0x237e, 0x11b7, 0x369e, 0x14a5,  0x1ff, 0x1078, 0x599d, 0x1057, 0x457e, 0x6df3, 0xfeb9, 0x2a5c, 0x2227, 0x7a18,
+#                          0x7fff, 0x237e, 0x11b7, 0x369e, 0x14a5,  0x1ff, 0x1078, 0x3d97, 0x3647, 0x3b68, 0xa4a, 0x12ef, 0x567e, 0x1571, 0x7a18,
+#                          0,      0x0EFA, 0x7DD1, 0,      0x7F1A,  0x7F1A,0,      0x716E, 0x7DD1, 0x40A7, 0x7DD1, 0x40A7, 0x48E9, 0x50CF, 0x7FFF]
+
+
+def save_as_png(dimensions, data, fname, palette = None):
+  img = Image.new('L' if palette == None else 'P', dimensions)
+  img.putdata(data)
+  if palette != None:
+    img.putpalette(palette)
+  img.save(fname)
+
+def save_as_24bpp_png(dimensions, data, fname):
+  img = Image.new("RGB", dimensions)
+  img.putdata(data)
+  img.save(fname)
+
+@cache
+def decode_2bit_tileset(tileset, height = 32, base = 0):
+  data = util.decomp(tables.kCompSpritePtrs[tileset], get_byte, False)
+  assert len(data) == 0x400 * height // 32
+  dst = bytearray(128*height)
+  def decode_2bit(offs, toffs, base):
+    for y in range(8):
+      d0, d1 = data[offs + y * 2], data[offs + y * 2 + 1]
+      for x in range(8):
+        t = ((d0 >> x) & 1) * 1 + ((d1 >> x) & 1) * 2
+        dst[toffs + y * 128 + (7 - x)] = t + base
+  for i in range(16*height//8):
+    x = i % 16
+    y = i // 16
+    decode_2bit(i * 16, x * 8 + y * 8 * 128, base[i] if isinstance(base, tuple) else base)
+  return dst
+
+def is_high_3bit_tileset(tileset):
+  # is 0x5c, 0x5e, 0x5f included or not?
+  return tileset in (0x52, 0x53, 0x5a, 0x5b, 0x5c, 0x5e, 0x5f)
+
+def get_unpacked_snes_tileset(tileset):
+  if tileset < 12:
+    return get_bytes(tables.kCompSpritePtrs[tileset], 0x600)
+  else:
+    return util.decomp(tables.kCompSpritePtrs[tileset], get_byte, False)
+
+@cache
+def decode_3bit_tileset(tileset):
+  data = get_unpacked_snes_tileset(tileset)
+  assert len(data) == 0x600
+  base = 8 if is_high_3bit_tileset(tileset) else 0
+  height = 32
+  dst = bytearray(128*height)
+  def decode_3bit(offs, toffs):
+    for y in range(8):
+      d0, d1, d2 = data[offs + y * 2], data[offs + y * 2 + 1], data[offs + y + 16]
+      for x in range(8):
+        t = ((d0 >> x) & 1) * 1 + ((d1 >> x) & 1) * 2 + ((d2 >> x) & 1) * 4
+        dst[toffs + y * 128 + (7 - x)] = base + t
+  for i in range(16*height//8):
+    x, y = i % 16, i // 16
+    decode_3bit(i * 24, x * 8 + y * 8 * 128)
+  return dst
+
+def decode_4bit_tileset_link():
+  height = 448
+  data = get_bytes(0x108000, 0x800 * height // 32) # only link sprites for now
+  dst = bytearray(128*height)
+  def decode_4bit(offs, toffs):
+    for y in range(8):
+      d0, d1, d2, d3 = data[offs + y * 2 + 0], data[offs + y * 2 + 1], data[offs + y * 2 + 16], data[offs + y * 2 + 17]
+      for x in range(8):
+        t = ((d0 >> x) & 1) * 1 + ((d1 >> x) & 1) * 2 + ((d2 >> x) & 1) * 4 + ((d3 >> x) & 1) * 8
+        dst[toffs + y * 128 + (7 - x)] = t
+  for i in range(16*height//8):
+    x, y = i % 16, i // 16
+    decode_4bit(i * 32, x * 8 + y * 8 * 128)
+  return dst
+
+def convert_snes_palette(v):
+  rr=bytearray()
+  for x in v:
+    r, g, b = x & 0x1f, x >> 5 & 0x1f, x >> 10 & 0x1f
+    rr.extend((r << 3 | r >> 2, g << 3 | g >> 2, b << 3 | b >> 2))
+  return rr
+
+def convert_int24_palette_to_bytes(v):
+  rr=bytearray()
+  for x in v:
+    rr.extend((x & 0xff, x >> 8 & 0xff, x >> 16 & 0xff))
+  return rr
+
+def convert_snes_palette_to_int(v):
+  rr=[]
+  for x in v:
+    r, g, b = x & 0x1f, x >> 5 & 0x1f, x >> 10 & 0x1f
+    rr.append((r << 3 | r >> 2) | (g << 3 | g >> 2) << 8 | (b << 3 | b >> 2) << 16)
+  return rr
+
+def decode_link_sprites():
+  kLinkPalette = [0, 0x7fff, 0x237e, 0x11b7, 0x369e, 0x14a5,  0x1ff, 0x1078, 0x599d, 0x3647, 0x3b68,  0xa4a, 0x12ef, 0x2a5c, 0x1571, 0x7a18]
+  save_as_png((128, 448), decode_4bit_tileset_link(), 'linksprite.png', convert_snes_palette(kLinkPalette))
+
+def get_hud_snes_palette():
+  hud_palette  = get_words(0x9BD660, 64)
+  palette = [(31 << 10 | 31) for i in range(256)]
+  for i in range(16):
+    for j in range(1, 4):
+      palette[i * 16 + j] = hud_palette[i * 4 + j]
+  return palette
+
+def decode_hud_icons():
+  class PaletteUsage:
+    def __init__(self):
+      self.data = open('palette_usage.bin', 'rb').read()
+    def get(self, icon):
+      usage = self.data[icon]
+      for j in range(8):
+        if usage & (1 << j):
+          return j 
+      return 0
+  pu = PaletteUsage()
+  dst = bytearray()
+  for slot, image_set in enumerate([106, 107, 105]):
+    tbase = tuple([pu.get(slot * 128 + i) * 16 for i in range(128)])
+    dst += decode_2bit_tileset(image_set, height = 64, base = tbase)
+
+  save_as_png((128, 64 * 3), dst, 'hud_icons.png', convert_snes_palette(get_hud_snes_palette()[:128]))
+
+def get_pt_remapper():
+  b = util.ROM.get_bytes(0x8EFC09, 121 * 3)
+  d = {}
+  for i in range(121):
+    ch = (i & 0xf) | (i << 1) & 0xe0
+    d[ch] = b[i*3+0]
+    d[ch|0x10] = b[i*3+1]
+  return d
+
+kFontTypes = {
+  'us'   : (0x8e8000, 256, 'font.png', (0x8ECADF, 99)),
+  'de'   : (0xCC6E8, 256, 'font_de.png', (0x8CDECF, 112)),
+  'fr'   : (0xCC6E8, 256, 'font_fr.png', (0x8CDEAF, 112)),
+  'fr-c' : (0xCD078, 256, 'font_fr_c.png', (0x8CE83F, 112)),
+  'en'   : (0x8E8000, 256, 'font_en.png', (0x8ECAFF, 102)),
+  'es'   : (0x8e8000, 256, 'font_es.png', (0x8ECADF, 99)),
+  'pl'   : (0x8e8000, 256, 'font_pl.png', (0x8ECADF, 99)),
+  'pt'   : (0x8e8000, 256, 'font_pt.png', (0x8ECADF, 121)),
+  'redux': (0x8e8000, 256, 'font_redux.png', (0x8ECADF, 99)),
+  'nl': (0x8e8000, 256, 'font_nl.png', (0x8ECADF, 99)),
+  'sv': (0x8e8000, 256, 'font_sv.png', (0x8ECADF, 99)),
+}
+
+def decode_font():
+  lang = util.ROM.language
+  def decomp_one_spr_2bit(data, offs, target, toffs, pitch, palette_base):
+    for y in range(8):
+      d0, d1 = data[offs + y * 2], data[offs + y * 2 + 1]
+      for x in range(8):
+        t = ((d0 >> x) & 1) * 1 + ((d1 >> x) & 1) * 2
+        target[toffs + y * pitch + (7 - x)] = t + palette_base
+  ft = kFontTypes[lang]
+  if lang == 'pt':
+    W = util.ROM.get_bytes(0x8EFC09, 121 * 3)
+    W = [W[i*3+2] for i in range(121)]
+    remapper = get_pt_remapper()
+  else:
+    W = get_bytes(*ft[3])
+    remapper = {}
+  w = 128 + 15
+  hi = ft[1] // 32
+  h = hi * 17
+  data = get_bytes(ft[0], ft[1] * 16)
+  dst = bytearray(w * h)
+  
+  for i in range(ft[1]):
+    x, y = i % 16, i // 16
+    pal_base = 6 * 16
+    base_offs = x * 9 + (y * 8 + (y >> 1)) * w
+    decomp_one_spr_2bit(data, remapper.get(i, i) * 16, dst, base_offs + w, w, pal_base)
+    if (y & 1) == 0:
+      j = (y >> 1) * 16 + x
+      if j < len(W):
+        dst[base_offs + W[j] - 1] = 255
+  pal = convert_snes_palette(get_hud_snes_palette()[:128])
+  pal.extend([0] * 384)
+  pal[0], pal[1], pal[2] = 192, 192, 192
+  pal[255*3+0], pal[255*3+1], pal[255*3+2] = 128, 128, 128
+  save_as_png((w, h), dst, ft[2], pal)
+  if lang != 'pt':
+    assert (data, W) == encode_font_from_png(lang)
+
+def encode_font_from_png(lang):
+  font_data = Image.open(kFontTypes[lang][2]).tobytes()
+  def encode_one_spr_2bit(data, offs, target, toffs, pitch):
+    for y in range(8):
+      d0, d1 = 0, 0
+      for x in range(8):
+        pixel = data[offs + y * pitch + 7 - x]
+        d0 |= (pixel & 1) << x
+        d1 |= ((pixel >> 1) & 1) << x
+      target[toffs + y * 2 + 0], target[toffs + y * 2 + 1] = d0, d1
+  w = 128 + 15
+  dst = bytearray(256 * 16)
+  def get_width(base_offs):
+    for i in range(8):
+      if font_data[base_offs + i] == 255:
+        break
+    return i + 1
+  W = bytearray()
+  for i in range(256):
+    x, y = i % 16, i // 16
+    base_offs = x * 9 + (y * 8 + (y >> 1)) * w
+    if (y & 1) == 0:
+      W.append(get_width(base_offs))
+    encode_one_spr_2bit(font_data, base_offs + w, dst, i * 16, w)
+  chars_per_lang = kFontTypes[lang][3][1]
+  return dst, W[:chars_per_lang]
+
+# Returns the dungeon palette for the specified palette index
+# 0 = lightworld, 1 = darkworld, 2 = dungeon
+@cache
+def get_palette_subidx(palset_idx, dungeon_or_ow, which_palette):
+  spmain = 1 if (dungeon_or_ow == 1) else 0
+  if dungeon_or_ow == 2:
+    main, sp0l, sp5l, sp6l = tables.kDungPalinfos[palset_idx]
+    sp0r = (main // 2) + 11
+    sp6r = 10
+  else:
+    sp5l, sp6l = tables.kOwSprPalInfo[palset_idx * 2 : palset_idx * 2 + 2]
+    sp0l = 3 if dungeon_or_ow == 1 else 1
+    sp0r = 9 if dungeon_or_ow == 1 else 7
+    sp6r = 8 if dungeon_or_ow == 1 else 6
+  pal_defs = (sp0l, sp0r, 
+    spmain, None, spmain, None, spmain, None, None, None,
+    sp5l, None,
+    sp6l, sp6r,
+    None, None)
+  return pal_defs[which_palette]
+
+@cache
+def get_palette_subset(pal_idx, j):
+  if j == None: j = 0
+  pal = [0] * 7
+  if pal_idx == 0: # 0
+    kPalette_SpriteAux3 = get_words(0x9BD39E, 84)
+    return kPalette_SpriteAux3[j * 7 : j * 7 + 7]
+  if pal_idx == 1: # 0R
+    if j < 11:
+      kPalette_MiscSprite = get_words(0x9BD446, 77)
+      return kPalette_MiscSprite[j * 7 : j * 7 + 7]
+    else:
+      kPalette_DungBgMain = get_words(0x9BD734, 1800)
+      return kPalette_DungBgMain[(j - 11) * 90 : (j - 11) * 90 + 7]
+  if pal_idx in (2, 3, 4, 5, 6, 7, 8, 9):
+    o = j * 60 + ((pal_idx - 2) >> 1) * 15 + (pal_idx & 1) * 8
+    kPalette_MainSpr = get_words(0x9BD218, 120)
+    return kPalette_MainSpr[o : o + 7]
+  if pal_idx in (10, 12):
+    kPalette_SpriteAux1 = get_words(0x9BD4E0, 168)
+    return kPalette_SpriteAux1[j * 7 : j * 7 + 7]
+  assert pal_idx != 11
+  if pal_idx == 13:
+    kPalette_MiscSprite = get_words(0x9BD446, 77)
+    return kPalette_MiscSprite[j * 7 : j * 7 + 7]
+  elif pal_idx == 14:
+    kPalette_ArmorAndGloves = get_words(0x9BD308, 75)
+    return kPalette_ArmorAndGloves[1:8]
+  elif pal_idx == 15:
+    kPalette_ArmorAndGloves = get_words(0x9BD308, 75)
+    return kPalette_ArmorAndGloves[9:16]
+
+@cache
+def get_full_palette(pal_idx, pal_subidx):
+  rv = []
+  if pal_idx & 1:
+    rv.extend([0x00fe00] * 9)
+  else:
+    rv.extend([0x00fe00] * 1)
+  rv.extend(convert_snes_palette_to_int(get_palette_subset(pal_idx, pal_subidx)))
+  rv += [0xe000e0] * (256 - len(rv))
+  # change the transparent to teal #008080
+  for i in range(0, 128, 8):
+    rv[i] = 0x808000
+  rv[251] = 0xe0c0c0 # blueish text
+  rv[252] = 0xc0c0c0 # palette text
+  rv[253] = 0xf0f0f0 # unallocated
+  rv[254] = 0x404040 # lines
+  rv[255] = 0xe0e0e0 # bg
+  return rv
+
+@cache
+def get_font_3x5():
+  return Image.open('../other/3x5_font.png').tobytes()
+
+def draw_letter3x5(dst, dst_pitch, dx, dy, ch, color):
+  font = get_font_3x5()
+  dst_offs = dy * dst_pitch + dx
+  src_offs = (ord(ch) & 31) * 4 + (ord(ch) // 32) * 6 * 128
+  for y in range(6):
+    for x in range(3):
+      if font[src_offs + y * 128 + x] == 0:
+        dst[dst_offs + y * dst_pitch + x] = color
+
+def draw_string3x5(dst, dst_pitch, dx, dy, s, color):
+  for ch in s:
+    draw_letter3x5(dst, dst_pitch, dx, dy, ch, color)
+    dx += 4
+
+def convert_to_24bpp(data, palette):
+  out = [0] * len(data)
+  for i in range(len(data)):
+    out[i] = palette[data[i]]
+  return out
+
+def concat_byte_arrays(ar):
+  r = bytearray()
+  for a in ar:
+    r += a
+  return r
+
+def fixup_sprite_set_entry(e, e_prev):
+  sprite_index = int(e.name[:2], 16) if e.name[0] != 'X' else 10000
+
+  if e.dungeon_or_ow != 3:
+    e.tileset = tables.kSpriteTilesets[e.tileset + (64 if e.dungeon_or_ow == 2 else 0)][e.ss_idx]
+  e.high_palette = is_high_3bit_tileset(e.tileset)
+  e.skip_header = False
+  if e.pal_base == None:
+    if sprite_index < len(tables.kSpriteInit_Flags3):
+      e.pal_base = (tables.kSpriteInit_Flags3[sprite_index] >> 1) & 7
+    else:
+      e.pal_base = 4 # just default to some palette
+
+  e.pal_idx = e.pal_base * 2 + e.high_palette
+  e.pal_subidx = get_palette_subidx(e.palset_idx, e.dungeon_or_ow, e.pal_idx)
+
+  if e_prev != None and e_prev.name == e.name and e_prev.pal_idx == e.pal_idx and e_prev.pal_subidx == e.pal_subidx:
+    e.skip_header = True
+
+  # the (pal_idx, pal_subidx) tuple identifies the palette
+  e.encoded_id = e.pal_base | e.tileset << 3 | e.skip_header << 10 | (e.pal_subidx or 0) << 11 
+  e.encoded_id = e.encoded_id << 8 | ((e.encoded_id + 41) % 255)
+
+
+BIGW = 148
+def save_sprite_set_entry(finaldst, e, master_tilesheets = None):
+  empty_253 = [253] * 8
+  def fill_with_empty(dst, dst_offs):
+    for y in range(8):
+      o = dst_offs + y * BIGW
+      dst[o : o + 8] = empty_253
+
+  def copy_8x8(dst, dst_offs, src, src_offs, base):
+    for y in range(8):
+      for x in range(8):
+        dst[dst_offs + y * BIGW + x] = src[src_offs + y * 128 + x] + base
+
+  def hline(dst, x1, x2, y, color):
+    for x in range(x1, x2 + 1):
+      dst[y * BIGW + x] = color
+
+  def vline(dst, x, y1, y2, color):
+    for y in range(y1, y2 + 1):
+      dst[y * BIGW + x] = color
+  
+  def fillrect(dst, x1, x2, y1, y2, color):
+    for y in range(y1, y2 + 1):
+      hline(dst, x1, x2, y, color)
+
+  def encode_id(dst, x, y, v):
+    while v:
+      if v & 1:
+        dst[y * BIGW + x] = 253
+      x -= 1
+      v >>= 1
+
+  palette = get_full_palette(e.pal_idx, e.pal_subidx)
+
+  if not e.skip_header:
+    pal_subidx = e.pal_subidx
+    if e.high_palette:
+      pal_name = '%sR' % e.pal_base
+    else:
+      pal_name = '%s' % e.pal_base
+      if e.pal_base in (1, 2, 3):
+        assert e.pal_subidx in (0, 1)
+        pal_subidx = 'LW' if pal_subidx == 0 else 'DW'
+    if pal_subidx != None:
+      pal_name = '%s-%s' % (pal_name, pal_subidx)
+
+    header = bytearray([255] * BIGW * 9)
+    draw_string3x5(header, BIGW, 1, 3, e.name[:22], 254)
+
+    for i in range(7):
+      xx = BIGW - 37 + i * 5 - 9
+      fillrect(header, xx, xx + 4, 3, 7, i + (9 if e.high_palette else 1))
+
+    draw_string3x5(header, BIGW, BIGW - 9, 3, '%2s' % e.tileset, 252)
+    draw_string3x5(header, BIGW, BIGW - 45 - 1 - len(pal_name) * 4, 3, pal_name, 252)
+    finaldst.extend(convert_to_24bpp(header, palette))
+
+  bigdst = bytearray([255] * BIGW * 36)
+  hline(bigdst, 1, 137, 0, 254)
+  hline(bigdst, 1, 137, 34, 254)
+  vline(bigdst, 1, 0, 34, 254)
+  vline(bigdst, 137, 0, 34, 254)
+
+  encode_id(bigdst, 137, 35, e.encoded_id << 9 | 0x55)
+
+  src = decode_3bit_tileset(e.tileset) # returns 128x64
+
+  for i in range(16*4):
+    x, y = i % 16, i // 16
+    dst_offs = (y * 8 + 1 + (y >> 1)) * BIGW + x * 8 + 2 + (x >> 1)
+    if x & 8: dst_offs
+    m = e.matrix[y][x]
+    if m == '.':
+      fill_with_empty(bigdst, dst_offs)
+    else:
+      copy_8x8(bigdst, dst_offs, src, x * 8 + y * 8 * 128, 0)
+      if master_tilesheets:
+        master_tilesheets.insert(e.tileset, src, x, y, palette, 0)
+
+  # display vram addresses
+  draw_string3x5(bigdst, BIGW, BIGW - 9, 4, '%Xx' % (e.ss_idx * 0x4), 251)
+  draw_string3x5(bigdst, BIGW, BIGW - 9, 4 + 17, '%Xx' % (e.ss_idx * 0x4 + 2), 251)
+
+  # collapse unused matrix sections
+  if all(m=='.' for m in e.matrix[0]) and all(m=='.' for m in e.matrix[1]):
+    del bigdst[1*BIGW:17*BIGW]
+  elif all(m=='.' for m in e.matrix[2]) and all(m=='.' for m in e.matrix[3]):
+    del bigdst[18*BIGW:34*BIGW]
+
+  if e.skip_header:
+    draw_string3x5(bigdst, BIGW, BIGW - 9, len(bigdst)//BIGW - 6, '%.2d' % e.tileset, 252)
+  
+  finaldst.extend(convert_to_24bpp(bigdst, palette))
+
+def fixup_entries():
+  e_prev = None
+  for e in sprite_sheet_info.entries:
+    fixup_sprite_set_entry(e, e_prev)
+    e_prev = e
+
+class MasterTilesheets:
+  def __init__(self):
+    self.sheets = {}
+
+  def insert(self, tileset, src, xp, yp, palette, pal_base):
+    sheet = self.sheets.get(tileset)
+    if sheet == None:
+      sheet = (array.array('I', [0x00f000] * 128 * 32), None)
+      self.sheets[tileset] = sheet
+    sheet24 = sheet[0]
+    for y in range(yp * 8, yp * 8 + 8):
+      for x in range(xp * 8, xp * 8 + 8):
+        o = y * 128 + x
+        sheet24[o] = palette[pal_base + src[o]]
+
+  def add_verify_8x8(self, tileset, pal_lut, img_data, pitch, dst_pos, src_pos):
+    # add to the master sheet
+    sheet = self.sheets.get(tileset)
+    if sheet == None:
+      sheet = (array.array('I', [0x00f000] * 128 * 32), bytearray([248] * 128 * 32))
+      self.sheets[tileset] = sheet
+    sheet24, sheet8 = sheet[0], sheet[1]
+    for y in range(8):
+      for x in range(8):
+        pixel = img_data[src_pos + y * pitch + x]
+        o = dst_pos + y * 128 + x 
+        sheet24[o] = pixel
+        pixel8 = pal_lut.get(pixel)
+        if pixel8 == None:
+          raise Exception('Pixel #%.6x not found' % pixel)
+        if sheet8[o] != 248 and pixel8 != sheet8[o]:
+          raise Exception('Pixel has more than one value')
+        sheet8[o] = pixel8
+
+  def save_to_all_sheets(self, save_also_8bit = False):
+    rv = array.array('I')
+    if save_also_8bit:
+      rv8 = bytearray()
+
+    def extend_with_string_line(text):
+      header = array.array('I', [0xf0f0f0] * 128 * 8)
+      draw_string3x5(header, 128, 1, 2, text, 0x404040)
+      rv.extend(header)
+      if save_also_8bit:
+        header8 = bytearray([255] * 128 * 8)
+        draw_string3x5(header8, 128, 1, 2, text, 254)
+        rv8.extend(header8)
+    extend_with_string_line('AUTO GENERATED DO NOT EDIT')
+    kk = 0
+    for k in sorted(self.sheets.keys()):
+      extend_with_string_line('Sheet %d' % k)
+      rv.extend(self.sheets[k][0])
+      if save_also_8bit:
+        rv8.extend(self.sheets[k][1])
+      if k != kk:
+        print('Missing %d' % kk)
+      kk = k + 1
+    if save_also_8bit:
+      palette8 = get_full_palette(4, 0)
+      for i, v in enumerate(convert_snes_palette_to_int(get_palette_subset(5, 0))):
+        palette8[i + 9] = v
+      palette8[248] = 0x00f000
+      save_as_png((128, len(rv)//128), rv8, 'sprites/all_sheets_8bit.png', palette = convert_int24_palette_to_bytes(palette8))
+      self.verify_identical_to_snes()
+    save_as_24bpp_png((128, len(rv)//128), rv, 'sprites/all_sheets.png')
+
+  def verify_identical_to_snes(self):
+    for tileset in range(103):
+      a = self.encode_sheet_in_snes_format(tileset)
+      b = get_unpacked_snes_tileset(tileset)
+      if a != b:
+        print('Sheet %d mismatch' % tileset)
+        break
+
+  # convert a tileset to the 8bit snes format, 24 bytes per tile
+  def encode_sheet_in_snes_format(self, tileset):
+    sheet8 = self.sheets[tileset][1]
+    result = bytearray(24 * 16 * 4)
+    def encode_into(dst_pos, src_pos):
+      for y in range(8):
+        for x in range(8):
+          b = sheet8[src_pos + 128 * y + 7 - x]
+          result[dst_pos+2*y] |= (b & 1) << x
+          result[dst_pos+2*y+1] |= ((b & 2) >> 1) << x
+          result[dst_pos+y+16] |= ((b & 4) >> 2) << x
+    for y in range(4):
+      for x in range(16):
+        encode_into((y * 16 + x) * 24, y * 8 * 128 + x * 8)
+    return result
+
+def decode_sprite_sheets():
+  master_tilesheets = MasterTilesheets()
+
+  fixup_entries()
+  for char in "0123456789ABCDEFX":
+    dst = []
+    for e in sprite_sheet_info.entries:
+      if e.name[0].upper() == char:
+        save_sprite_set_entry(dst, e, master_tilesheets)
+    if len(dst):
+      save_as_24bpp_png((BIGW, len(dst) // BIGW), dst, 'sprites/sprites_%s.png' % char)
+  master_tilesheets.save_to_all_sheets()
+
+def load_sprite_sheets():
+  master_tilesheets = MasterTilesheets()
+  for char in "0123456789ABCDEFX":
+    img = Image.open('sprites/sprites_%s.png' % char)
+    img_size = img.size
+    img_data = array.array('I', (a[0] | a[1] << 8 | a[2] << 16 for a in img.getdata()))
+    pitch = img.size[0]
+
+    def find_next_tag(start_pos):
+      for i in range(start_pos, len(img_data) - pitch * 2, pitch if start_pos != 0 else 1):
+        if img_data[i+0] == 0x404040 and img_data[i+pitch] == 0x404040 and \
+          img_data[i+pitch * 2 + 0] == 0xf0f0f0 and img_data[i+pitch * 2 - 1] == 0xe0e0e0 and \
+          img_data[i+pitch * 2 - 2] == 0xf0f0f0 and img_data[i+pitch * 2 - 3] == 0xe0e0e0 and \
+          img_data[i+pitch * 2 - 4] == 0xf0f0f0 and img_data[i+pitch * 2 - 5] == 0xe0e0e0 and \
+          img_data[i+pitch * 2 - 6] == 0xf0f0f0 and img_data[i+pitch * 2 - 7] == 0xe0e0e0:
+          return i + pitch * 2
+      else:
+        return None
+
+    def decode_tag(pos):
+      r = 0
+      for i in range(64):
+        v = img_data[pos - 63 + i]
+        assert v in (0xe0e0e0, 0xf0f0f0)
+        r = r * 2 + (v == 0xf0f0f0)
+      if (r & 0x1ff) != 0x55:
+        raise Exception('Invalid tag')
+      r >>= 9
+      if (((r >> 8) + 41) % 255) != (r & 0xff):
+        raise Exception('Invalid checksum')
+      r >>= 8
+      return r & 7, (r >> 3) & 127, (r >> 10) & 1, (r >> 11) & 31
+
+    def determine_image_rects(tag_pos):
+      h = 1
+      while (img_data[tag_pos - pitch * (h + 1)] == 0x404040):
+        h += 1
+      if h == 19:
+        if img_data[tag_pos - pitch * 2 - 1] == 0xe0e0e0:
+          image_rects = ((0, tag_pos - 135 - pitch * 18), )
+        elif img_data[tag_pos - pitch * 18 - 1] == 0xe0e0e0:
+          image_rects = ((1, tag_pos - 135 - pitch * 17), )
+        else:
+          raise Exception('cant uncompact')
+      elif h == 35:
+        image_rects = ((0, tag_pos - 135 - pitch * 34), (1, tag_pos - 135 - pitch * 17))
+      else:
+        raise Exception('height not found')
+      return image_rects, h
+
+    def get_pal_lut(tag_pos, is_high):
+      # read palette colors from the image pixels
+      pal_lut = {img_data[tag_pos + 5 * i] : i + (9 if is_high else 1) for i in range(7)}
+      pal_lut[0x808000] = 0 # transparent color
+      return pal_lut
+
+    def is_empty(pos):
+      return all(img_data[pos+y*pitch+x] == 0xf0f0f0 for x in range(8) for y in range(8))
+
+    pal_lut = None
+    tag_pos = 0
+    while True:
+      tag_pos = find_next_tag(tag_pos)
+      if tag_pos == None:
+        break
+      pal_base, tileset, headerless, pal_subidx = decode_tag(tag_pos)
+      image_rects, box_height = determine_image_rects(tag_pos)
+      if not headerless:
+        pal_lut = get_pal_lut(tag_pos - pitch * (box_height + 3) - 34, is_high_3bit_tileset(tileset))
+      for idx, sheet_pos in image_rects:
+        for y in range(2):
+          for x in range(16):
+            src_pos = sheet_pos + (y * 8 + (y >> 1)) * pitch + (x * 8 + (x >> 1))
+            dst_pos = (y + idx * 2) * 8 * 128 + x * 8
+            if not is_empty(src_pos):
+              master_tilesheets.add_verify_8x8(tileset, pal_lut, img_data, pitch, dst_pos, src_pos)
+  return master_tilesheets
+
+#if __name__ == "__main__":
+#  ROM = util.load_rom(sys.argv[1] if len(sys.argv) >= 2 else None, True)
+#  decode_font()
+  
+
+
--- /dev/null
+++ b/assets/sprites/.gitignore
@@ -1,0 +1,1 @@
+/*.png
--- /dev/null
+++ b/assets/tables.py
@@ -1,0 +1,1132 @@
+def invert_dict(xs):
+  return {s:i for i,s in xs.items()}
+
+type0_names="""Ceiling [L-R]
+[N]Wall Horz: [L-R]
+[S]Wall Horz: [L-R]
+[N]Wall Horz: (LOW) [L-R]
+[S]Wall Horz: (LOW) [L-R]
+[N]Wall Column [L-R]
+[S]Wall Column [L-R]
+[N]Wall Pit [L-R]
+[S]Wall Pit [L-R]
+/ Wall Wood Bot (HIGH) [NW]
+\ Wall Wood Bot (HIGH) [SW]
+\ Wall Wood Bot (HIGH) [NE]
+/ Wall Wood Bot (HIGH) [SE]
+/ Wall Tile Bot (HIGH) [NW]
+\ Wall Tile Bot (HIGH) [SW]
+\ Wall Tile Bot (HIGH) [NE]
+/ Wall Tile Bot (HIGH) [SE]
+/ Wall Tile2 Bot (HIGH) [NW]
+\ Wall Tile2 Bot (HIGH) [SW]
+\ Wall Tile2 Bot (HIGH) [NE]
+/ Wall Tile2 Bot (HIGH) [SE]
+/ Wall Tile Top (LOW)[NW]
+\ Wall Tile Top (LOW)[SW]
+\ Wall Tile Top (LOW)[NE]
+/ Wall Tile Top (LOW)[SE]
+/ Wall Tile Bot (LOW)[NW]
+\ Wall Tile Bot (LOW)[SW]
+\ Wall Tile Bot (LOW)[NE]
+/ Wall Tile Bot (LOW)[SE]
+/ Wall Tile2 Bot (LOW)[NW]
+\ Wall Tile2 Bot (LOW)[SW]
+\ Wall Tile2 Bot (LOW)[NE]
+/ Wall Tile2 Bot (LOW)[SE]
+Mini Stairs [L-R]
+Horz: Rail Thin [L-R]
+Pit [N]Edge [L-R]
+Pit [N]Edge [L-R]
+Pit [N]Edge [L-R]
+Pit [N]Edge [L-R]
+Pit [N]Edge [L-R]
+Pit [S]Edge [L-R]
+Pit [S]Edge [L-R]
+Pit [N]Edge [L-R]
+Pit [SE]Corner [L-R]
+Pit [SW]Corner [L-R]
+Pit [NE]Corner [L-R]
+Pit [NW]Corner [L-R]
+Rail Wall [L-R]
+Rail Wall [L-R]
+Unused -empty
+Unused -empty
+Red Carpet Floor [L-R]
+Red Carpet Floor Trim [L-R]
+Unused -empty
+[N]Curtain [L-R]
+[W]Curtain [L-R]-unused-
+Statue [L-R]
+Column [L-R]
+[N]Wall Decor: [L-R]
+[S]Wall Decor: [L-R]
+Double Chair [L-R]
+Stand Torch [L-R]
+[N]Wall Column [L-R]
+Water Edge [L-R]
+Water Edge [L-R]
+Water Edge [L-R]
+Water Edge [L-R]
+Water Edge [L-R]
+Water Edge [L-R]
+Water Edge [L-R]
+Water Edge [L-R]
+Unused Waterfall [L-R]
+Unused Waterfall [L-R]
+N/A
+N/A
+[S]Wall Column [L-R]
+Bar [L-R]
+Shelf [L-R]
+Shelf [L-R]
+Shelf [L-R]
+Cane Ride [L-R]
+[N]Canon Hole [L-R]
+[S]Canon Hole [L-R]
+Cane Ride [L-R]
+Unused [L-R]
+[N]Wall Torches [L-R]
+[S]Wall Torches [L-R]
+Unused
+Unused
+Unused
+Unused
+[N]Canon Hole [L-R]
+[S]Canon Hole [L-R]
+Large Horz: Rail [L-R]
+Block [L-R]
+Long Horz: Rail [L-R]
+Ceiling [U-D]
+[W]Wall Vert: [U-D]
+[E]Wall Vert: [U-D]
+[W]Wall Vert: (LOW) [U-D]
+[E]Wall Vert: (LOW) [U-D]
+[W]Wall Column [U-D]
+[E]Wall Column [U-D]
+[W]Wall Pit [U-D]
+[E]Wall Pit [U-D]
+Vert: Rail Thin [U-D]
+[W]Pit Edge [U-D]
+[E]Pit Edge [U-D]
+[W]Rail Wall [U-D]
+[E]Rail Wall [U-D]
+Unused
+Unused
+Red Floor/Wire Floor [U-D]
+Red Carpet Floor Trim [U-D]
+Unused
+[W]Curtain [U-D]
+[E]Curtain [U-D]
+Column [U-D]
+[W]Wall Decor: [U-D]
+[E]Wall Decor: [U-D]
+[W]Wall Top Column [U-D]
+Water Edge [U-D]
+Water Edge [U-D]
+[E]Wall Top Column [U-D]
+Cane Ride [U-D]
+Pipe Ride [U-D]
+Unused
+[W]Wall Torches [U-D]
+[E]Wall Torches [U-D]
+[W]Wall Decor: [U-D]
+[E]Wall Decor: [U-D]
+[W]Wall Decor:?? [U-D]
+[E]Wall Decor:?? [U-D]
+[W]Wall Canon Hole [U-D]
+[E]Wall Canon Hole [U-D]
+Floor Torch [U-D]
+Large Vert: Rail [U-D]
+Block Vert: [U-D]
+Long Vert: Rail [U-D]
+[W]Vert: Jump Edge [U-D]
+[E]Vert: Jump Edge [U-D]
+[W]Edge [U-D]
+[E]Edge [U-D]
+N/A
+[W]Wall Vert: [U-D]
+[E]Wall Horz: [U-D]
+Blue Peg Block [U-D]
+Orange Peg Block [U-D]
+Invisible Floor [U-D]
+Fake Pot [U-D]
+Hammer Peg Block [U-D]
+Unused
+Unused
+Unused
+Unused
+Unused
+Unused
+Unused
+Unused
+Unused
+/ Ceiling [NW]
+\ Ceiling [SW]
+\ Ceiling [NE]
+/ Ceiling [SE]
+Hole [4-way]
+/ Ceiling [Trans][NW]
+\ Ceiling [Trans][SW]
+\ Ceiling [Trans][NE]
+/ Ceiling [Trans][SE]
+/ Ceiling [BG2 X-RAY][SE]
+\ Ceiling [BG2 X-RAY][NE]
+\ Ceiling [BG2 X-RAY][SW]
+/ Ceiling [BG2 X-RAY][NW]
+N/A
+N/A
+N/A
+[S]Horz: Jump Edge [L-R]
+[S]Horz: Jump Edge [L-R]
+Floor? [L-R]
+N/A
+N/A
+N/A
+[N]Wall Decor: 1/2 [L-R]
+[S]Wall Decor: 1/2 [L-R]
+Blue Switch Block [L-R]
+Red Switch Block [L-R]
+Invisible Floor [L-R]
+N/A
+fake pots [L-R]
+Hammer Pegs [L-R]
+Unused
+Unused
+Ceiling Large [4-way]
+Chest Pedastal [4-way]
+Falling Edge Mask [4-way]
+Falling Edge Mask [4-way]
+Doorless Room Transition
+Floor3 [4-way]
+BG2 X-RAY Overlay [4-way]
+Floor4 [4-way]
+Water Floor [4-way]
+Water Floor2 [4-way]
+Floor5 [4-way]
+Unused
+Unused
+Moving Wall Right [4-way]
+Moving Wall Left [4-way]
+Unused
+Unused
+Water Floor3 [4-way]
+Floor6 [4-way]
+Unused
+Unused
+Unused
+N/A
+overlay tile? [4-way]
+Lava Background? [4-way]
+Swimming Overlay [4-way]
+Lava Background 2 [4-way]
+Floor2 [4-way]
+Chest Platform? [4-way]
+Table / Rock [4-way]
+Spike Block [4-way]
+Spike Floor [4-way]
+Floor7 [4-way]
+Floor9 [4-way]
+Rupee Floor [4-way]
+Moving Floor Up [4-way]
+Moving Floor Down [4-way]
+Moving Floor Left [4-way]
+Moving Floor Right [4-way]
+Moving Floor/Water [4-way]
+Weird Floor? [4-way]
+Unused
+Unused
+Unused
+Unused
+Unused
+Unused
+Unused
+Unused
+Unused
+Unused
+Unused
+Unused
+Unused
+Unused
+Unused
+Water Face
+Waterfall Face
+Waterfall Face Longer
+Cane Ride Spawn [?]Block
+Cane Ride Node [4-way]
+Cane Ride Node [S-E]
+Cane Ride Node [N-E]
+Cane Ride Node [S-E]-2
+Cane Ride Node [N-E]-2
+Cane Ride Node [W-S-E]
+Cane Ride Node [W-N-E]
+Cane Ride Node [N-E-S]
+Cane Ride Node [N-W-S]
+Prison Cell
+Cane Ride Spawn [?]Block
+?
+?
+?
+Rupee Floor
+Telepathic Tile
+Down Warp Door
+Kholdstare Shell - BG2
+Single Hammer Peg
+Cell
+Cell Lock
+Chest
+Open Chest
+Stair
+Stair [S](Layer)
+Stair Wet [S](Layer)
+Staircase going Up(Up)
+Staircase Going Down (Up)
+Staircase Going Up (Down)
+Staircase Going Down (Down)
+Pit Wall Corner
+Pit Wall Corner
+Pit Wall Corner
+Pit Wall Corner
+Staircase Going Up (Lower)
+Staircase Going Up (Lower)
+Staircase Going Down (Lower)
+Staircase Going Down (Lower)
+Dark Room BG2 Mask
+Staircase Going Down (Lower)
+Large Pick Up Block
+Agahnim Altar
+Agahnim Room
+Pot
+??
+Big Chest
+Big Chest Open
+Stairs Submerged [S](layer)
+???
+???
+???
+???
+???
+???
+Pipe Ride Mouth [S]
+Pipe Ride Mouth [N]
+Pipe Ride Mouth [E]
+Pipe Ride Mouth [W]
+Pipe Ride Corner [S-E]
+Pipe Ride Corner [N-E]
+Pipe Ride Corner [S-W]
+Pipe Ride Corner [N-W]
+Pipe Ride Tunnel [N]
+Pipe Ride Tunnel [S]
+Pipe Ride Tunnel [W]
+Pipe Ride Tunnel [E]
+Pipe Ride Over Mask [U-D]
+Bomb Floor
+Fake Bomb Floor
+Fake Bomb Floor
+Warp Tile
+???
+???
+???
+???
+Inactive Warp
+Floor Switch
+Skull Pot
+Single Blue Peg
+Single Red Peg
+
+???
+Bar Corner [NW]
+Bar Corner [SW]
+Bar Corner [NE]
+Bar Corner [SE]
+Plate on Table
+Water Troof
+Bookshelf
+Forge
+???
+Bottles on Bar
+???
+Left Warp Door
+Right Warp Door
+Fake Floor Switch
+Fireball Shooter
+Medusa Head
+Hole
+Top Crack Wall
+Bottom Crack Wall
+Left Crack Wall
+Right Crack Wall
+Throne/Decor: Object
+???
+???
+???
+???
+Window Light
+Floor Light Blind BG2
+Boss Goo/Shell BG2
+Bg2 Full Mask
+Boss Entrance
+Minigame Chest
+???
+???
+???
+???
+???
+Vitreous Boss?
+???
+???
+???
+???
+""".splitlines()
+
+type2_names="""Wall Outer Corner (HIGH) [NW]
+Wall Outer Corner (HIGH) [SW]
+Wall Outer Corner (HIGH) [NE]
+Wall Outer Corner (HIGH) [SE]
+Wall Inner Corner (HIGH) [NW]
+Wall Inner Corner (HIGH) [SW]
+Wall Inner Corner (HIGH) [NE]
+Wall Inner Corner (HIGH) [SE]
+Wall Outer Corner (LOW) [NW]
+Wall Outer Corner (LOW) [SW]
+Wall Outer Corner (LOW) [NE]
+Wall Outer Corner (LOW) [SE]
+Wall Inner Corner (LOW) [NW]
+Wall Inner Corner (LOW) [SW]
+Wall Inner Corner (LOW) [NE]
+Wall Inner Corner (LOW) [SE]
+Wall S-Bend (LOW) [N1]
+Wall S-Bend (LOW) [S1]
+Wall S-Bend (LOW) [N2]
+Wall S-Bend (LOW) [S2]
+Wall S-Bend (LOW) [W1]
+Wall S-Bend (LOW) [W2]
+Wall S-Bend (LOW) [E1]
+Wall S-Bend (LOW) [E2]
+Wall Pit Corner (Lower) [NW]
+Wall Pit Corner (Lower) [SW]
+Wall Pit Corner (Lower) [NE]
+Wall Pit Corner (Lower) [SE]
+Fairy Pot
+Statue
+Star Tile Off
+Star Tile On
+Torch Lit
+Barrel
+Weird Bed
+Table
+Decoration
+???
+???
+Chair
+Bed
+Decoration
+Wall Painting
+???
+???
+Floor Stairs Up (room)
+Floor Stairs Down (room)
+Floor Stairs Down2 (room)
+Stairs [N](unused)
+Stairs [N](layer)
+Stairs [N](layer)
+Stairs Submerged [N](layer)
+Block
+Water Ladder
+Water Ladder
+Water Gate Large
+Door Staircase Up R
+Door Staircase Down L
+Door Staircase Up R (Lower)
+Door Staircase Down L (Lower)
+Sanctuary Wall
+???
+Church Pew
+???
+Ceiling [L-R]""".splitlines()
+
+kType0Names = ['%.2X-%s' % (i, type0_names[i]) for i in range(0xf8)]
+kType1Names = ['%.3X-%s' % (0xf80 + i, type0_names[i+0xf8]) for i in range(0x80)]
+kType2Names = ['%X-%s' % (i + 0x100, x) for i,x in enumerate(type2_names)]
+
+def invert_list(x):
+	return {s:i for i,s in enumerate(x)}
+
+kType0Names_rev = invert_list(kType0Names)
+kType1Names_rev = invert_list(kType1Names)
+kType2Names_rev = invert_list(kType2Names)
+
+kTagNames = [        "None","NW Kill enemy to open","NE Kill enemy to open","SW Kill enemy to open","SE Kill enemy to open","W Kill enemy to open","E Kill enemy to open","N Kill enemy to open","S Kill enemy to open","Clear quadrant to open","Clear room to open",
+        "NW Move block to open","NE Move block to open","SW Move block to open","SE Move block to open","W Move block to open","E Move block to open","N Move block to open",
+        "S Move block to open","Move block to open","Pull lever to open","Clear level to open door","Switch opens door(Hold)","Switch opens door(Toggle)",
+        "Turn off water","Turn on water","Water gate","Water twin","Secret wall (Right)","Secret wall (Left)","Crash","Crash",
+        "Use switch to bomb wall","Holes(0)","Open chest for holes(0)","Holes(1)","Holes(2)","Kill enemy to clear level","SE Kill enemy to move block","Trigger activated chest",
+        "Use lever to bomb wall","NW Kill enemy for chest","NE Kill enemy for chest","SW Kill enemies for chest","SE Kill enemy for chest","W Kill enemy for chest","E Kill enemy for chest","N Kill enemy for chest",
+        "S Kill enemy for chest","Clear quadrant for chest","Clear room for chest","Light torches to open","Holes(3)","Holes(4)","Holes(5)","Holes(6)",
+        "Agahnim's room","Holes(7)","Holes(8)","Open chest for holes(8)","Move block to get chest","Kill to open Ganon's door","Light torches to get chest","Kill boss again",
+]
+
+kTagNames_rev = invert_list(kTagNames)
+
+kEffectNames = ["None","01","Moving floor","Moving water","04","Red flashes","Light torch to see floor","Ganon room"]
+kEffectNames_rev = invert_list(kEffectNames)
+
+kCollisionNames = ["One", "Both", "Both w/scroll", "Moving floor", "Moving water"]
+kCollisionNames_rev = invert_list(kCollisionNames)
+
+kBg2 = ["None", "Parallaxing", "Dark", "On top", "Translucent", "Parallaxing2", "Normal", "Addition", "Dark room"]
+kBg2_rev = invert_list(kBg2)
+
+kMusicNames = {
+    255: "Same",
+    0: "None",
+    1:"Title",
+    2:"World_map",
+    3:"Beginning",
+    4:"Rabbit",
+    5:"Forest",
+    6:"Intro",
+    7:"Town",
+    8:"Warp",
+    9:"Dark_world",
+    10:"Master_swd",
+    11:"File_select",
+    12:"Soldier",
+    13:"Mountain",
+    14:"Shop",
+    15:"Fanfare",
+    16:"Castle",
+    17:"Palace",
+    18:"Cave",
+    19:"Clear",
+    20:"Church",
+    21:"Boss",
+    22:"Dungeon",
+    23:"Psychic",
+    24:"Secret_way",
+    25:"Rescue",
+    26:"Crystal",
+    27:"Fountain",
+    28:"Pyramid",
+    29:"Kill_Agah",
+    30:"Ganon_room",
+    31:"Last_boss",
+    32:"Triforce",
+    33:"Ending",
+    34:"Staff",
+    240:"Stop",
+    241:"Fade_out",
+    242:"Lower_vol",
+    243:"Normal_vol"
+}
+
+kMusicNamesRev = invert_dict(kMusicNames)
+
+kAmbientSoundName = {
+    0: "None",
+    1: "Heavy rain",
+    3: "Light rain",
+    5: "Stop",
+    7: "Earthquake",
+    9: "Wind",
+    11: "Flute",
+    13: "Chime 1",
+    15: "Chime 2"
+}
+
+kAmbientSoundNameRev = invert_dict(kAmbientSoundName)
+
+kPalaceNames = (
+    "None",
+    "Church",
+    
+    "Castle",
+    "East",
+    "Desert",
+    "Agahnim",
+    
+    "Water",
+    "Dark",
+    "Mud",
+    "Wood",
+    
+    "Ice",
+    "Tower",
+    "Town",
+    "Mountain",
+    "Agahnim2"
+)
+
+kAreaNames = """LW 000 : Lost Woods NW
+LW 001 : Lost Woods NE
+LW 002 : Lumberjack Estate
+LW 003 : Tower of Hera NW
+LW 004 : Tower of Hera NE
+LW 005 : Death Mountain Bridge NW
+LW 006 : Death Mountain Bridge NE
+LW 007 : Turtle Rock
+LW 008 : Lost Woods SW
+LW 009 : Lost Woods SE
+LW 010 : Death Mountain Gateway
+LW 011 : Tower of Hera SW
+LW 012 : Tower of Hera SE
+LW 013 : Mountain Bridge NW
+LW 014 : Mountain Bridge NE
+LW 015 : Zora Falls Outskirts
+LW 016 : Lost Woods Outskirts
+LW 017 : Kakariko Psychics Unlimited
+LW 018 : Nothern Pond
+LW 019 : Sanctuary Grounds
+LW 020 : Graveyard
+LW 021 : South Bend
+LW 022 : Coven of Commerce
+LW 023 : Zora Ridge
+LW 024 : Kakariko NW
+LW 025 : Kakariko NE
+LW 026 : West Woods
+LW 027 : Hyrule Castle NW
+LW 028 : Hyrule Castle NE
+LW 029 : Castle East Bridge
+LW 030 : Eastern Ruins NW
+LW 031 : Eastern Ruins NE
+LW 032 : Kakariko SW
+LW 033 : Kakariko SE
+LW 034 : Smithy Estate
+LW 035 : Hyrule Castle SW
+LW 036 : Hyrule Castle SE
+LW 037 : Moundlands
+LW 038 : Eastern Ruins SW
+LW 039 : Eastern Ruins SE
+LW 040 : Kakariko Maze
+LW 041 : Kakariko South Annex
+LW 042 : Haunted Grove
+LW 043 : Uncle's Estate West
+LW 044 : Uncle's Estate East
+LW 045 : Eastern Ruins Bridge
+LW 046 : Eastern Ruins Ridge
+LW 047 : Eastern Cul-de-sac
+LW 048 : Desert of Mystery NW
+LW 049 : Desert of Mystery NE
+LW 050 : Haunted Terrace
+LW 051 : Hyrule Wetlands NW
+LW 052 : Hyrule Wetlands NE
+LW 053 : Lake Hylia NW
+LW 054 : Lake Hylia NE
+LW 055 : Frosty Caves
+LW 056 : Desert of Mystery SW
+LW 057 : Desert of Mystery SE
+LW 058 : Via of Mystery
+LW 059 : Watergate Grounds
+LW 060 : Hyrule Wetlands Terrace
+LW 061 : Lake Hylia SW
+LW 062 : Lake Hylia SE
+LW 063 : Octorock Nesting Grounds
+DW 064 : Skull Woods NW
+DW 065 : Skull Woods NE
+DW 066 : Eastern Skull Clearing
+DW 067 : Ganon's Tower NW
+DW 068 : Ganon's Tower NE
+DW 069 : Death Mountain Bridge NW
+DW 070 : Death Mountain Bridge NE
+DW 071 : Turtle Rock
+DW 072 : Skull Woods SW
+DW 073 : Skull Woods SE
+DW 074 : Bungie Cave Fun Zone
+DW 075 : Ganon's Tower SW
+DW 076 : Ganon's Tower SE
+DW 077 : Death Mountain Bridge SW
+DW 078 : Death Mountain Bridge SE
+DW 079 : Falls of Ill Omen
+DW 080 : Skull Woods Outskirts
+DW 081 : Village of Outcasts Psychics Unlimited
+DW 082 : Northern Pond (Evil Edition)
+DW 083 : Unctuary Grounds
+DW 084 : Garden of Very Bad Things
+DW 085 : South Bend
+DW 086 : Riverside Commerce
+DW 087 : Ridge of Ill Omen
+DW 088 : Village of Outcasts NW
+DW 089 : Village of Outcasts NE
+DW 090 : West Woods
+DW 091 : Pyramid of Power NW
+DW 092 : Pyramid of Power NE
+DW 093 : Pyramid East Non-bridge
+DW 094 : Maze of Darkness NW
+DW 095 : Maze of Darkness NE
+DW 096 : Village of Outcasts SW
+DW 097 : Village of Outcasts SW
+DW 098 : Gossip Shop
+DW 099 : Pyramid of Power SW
+DW 100 : Pyramid of Power SE
+DW 101 : Moundlands
+DW 102 : Maze of Darkness SW
+DW 103 : Maze of Darkness SE  
+DW 104 : Digging Game Field
+DW 105 : Archery Shop Grounds
+DW 106 : Depressing Grove
+DW 107 : Bomb Shop Grounds West
+DW 108 : Bomp Shop Grounds
+DW 109 : Hammer Time Bridge
+DW 110 : Terrace of Darkness
+DW 111 : Cul-de-sac of Darkness
+DW 112 : Swamp of Evil NW
+DW 113 : Swamp of Evil NE
+DW 114 : Depressing Terrace
+DW 115 : Wilted Wetlands NW
+DW 116 : Wilted Wetlands NE
+DW 117 : Lake Dielia NW
+DW 118 : Lake Dielia NE
+DW 119 : Info Hub
+DW 120 : Swamp of Evil SW
+DW 121 : Swamp of Evil SE
+DW 122 : Via To Nowhere
+DW 123 : Swamp Palace Grounds
+DW 124 : Wilted Terrace
+DW 125 : Lake Dielia SW
+DW 126 : Lake Dielia SE
+DW 127 : A Terrible Vacation Spot
+SP 128 : Master Grove / Under Hyrule Bridge
+SP 129 : Zora Falls NW <AVAILABLE>
+SP 130 : Zora Falls NE <NO SPRITES>
+NA 131 : Unused N/A
+NA 132 : Unused N/A
+NA 133 : Unused N/A
+NA 134 : Unused N/A
+NA 135 : Unused N/A
+SP 136 : Triforce Room / Curtain Overlay
+SP 137 : Zora Falls SW <NO SPRITES>
+SP 138 : Zora Falls SE <NO SPRITES>
+NA 139 : Unused N/A
+NA 140 : Unused N/A
+NA 141 : Unused N/A
+NA 142 : Unused N/A
+NA 143 : Unused N/A
+NA 144 : Unused N/A
+NA 145 : Unused N/A
+NA 146 : Unused N/A
+SP 147 : Triforce Rm / Overlay (2?) N/A
+SP 148 : Master Gr. / Under Bdg (2?) N/A
+SP 149 : Birds' Eye Woods Underlay
+SP 150 : Death Mountain Panorama
+SP 151 : Lost Woods Mist Overlay
+NA 152 : Unused N/A
+NA 153 : Unused N/A
+NA 154 : Unused N/A
+NA 155 : Unused N/A
+SP 156 : Lava Flow Underlay
+SP 157 : Lost Woods Mist Overlay (2?) N/A
+SP 158 : Lost Woods Tree Cover Overlay
+SP 159 : Rain Overlay
+NA 160 : non-existant N/A""".splitlines()
+
+kEntranceNames = """[Room #260] -- Link's House Intro
+[Room #260] -- Link's House Post-intro
+[Room #018] -- Sanctuary
+[Room #096] -- Hyrule Castle West
+[Room #097] -- Hyrule Castle Central
+[Room #098] -- Hyrule Castle East
+[Room #240] -- Death Mountain Express (Lower)
+[Room #241] -- Death Mountain Express (Upper)
+[Room #201] -- Eastern Palace
+[Room #132] -- Desert Palace Central
+[Room #133] -- Desert Palace East
+[Room #131] -- Desert Palace West
+[Room #099] -- Desert Palace Boss Lair
+[Room #242] -- Kakariko Elder's House West
+[Room #243] -- Kakariko Elder's House East
+[Room #244] -- Kakariko Angry Bros West
+[Room #245] -- Kakariko Angry Bros East
+[Room #227] -- Mad Batter Lair
+[Room #226] -- Under Lumberjacks' Weird Tree
+[Room #248] -- Death Mountain Maze 0000
+[Room #232] -- Death Mountain Maze 0001
+[Room #035] -- Turtle Rock Mountainface 1
+[Room #251] -- Death Mountain Cape Heart Piece Cave (Lower)
+[Room #235] -- Death Mountain Cape Heart Piece Cave (Upper)
+[Room #213] -- Turtle Rock Mountainface 2
+[Room #036] -- Turtle Rock Mountainface 3
+[Room #253] -- Death Mountain Maze 0002
+[Room #237] -- Death Mountain Maze 0003
+[Room #254] -- Death Mountain Maze 0004
+[Room #238] -- Death Mountain Maze 0005
+[Room #255] -- Death Mountain Maze 0006
+[Room #239] -- Death Mountain Maze 0007
+[Room #223] -- Death Mountain Maze 0008
+[Room #249] -- Spectacle Rock Maze 1
+[Room #250] -- Spectacle Rock Maze 2
+[Room #234] -- Spectacle Rock Maze 3
+[Room #224] -- Hyrule Castle Tower
+[Room #040] -- Swamp Palace
+[Room #074] -- Palace of Darkness
+[Room #152] -- Misery Mire
+[Room #086] -- Skull Woods 1
+[Room #087] -- Skull Woods 2
+[Room #088] -- Skull Woods Big Chest
+[Room #089] -- Skull Woods Boss Lair
+[Room #225] -- Lost Woods Thieves' Lair
+[Room #014] -- Ice Palace
+[Room #230] -- Death Mountain Escape West
+[Room #231] -- Death Mountain Escape East
+[Room #228] -- Death Mountain Elder's Cave (Lower)
+[Room #229] -- Death Mountain Elder's Cave (Upper)
+[Room #085] -- Hyrule Castle Secret Cellar
+[Room #119] -- Tower of Hera
+[Room #219] -- Thieves's Town
+[Room #214] -- Turtle Rock Main
+[Room #016] -- Ganon's Pyramid Sanctum (Lower)
+[Room #012] -- Ganon's Tower
+[Room #008] -- Fairy Cave 1
+[Room #047] -- Kakariko Western Well
+[Room #060] -- Death Mountain Maze 0009
+[Room #044] -- Death Mountain Maze 0010
+[Room #256] -- Treasure Shell Game 1
+[Room #286] -- Storyteller Cave 1
+[Room #257] -- Snitch House 1
+[Room #257] -- Snitch House 2
+[Room #258] -- SickBoy House
+[Room #279] -- Byrna Gauntlet
+[Room #259] -- Kakariko Pub South
+[Room #259] -- Kakariko Pub North
+[Room #259] -- Kakariko Inn
+[Room #261] -- Sahasrahlah's Disco Infernum
+[Room #287] -- Kakariko's Lame Shop
+[Room #262] -- Village of Outcasts Chest Game
+[Room #262] -- Village of Outcasts Orphanage
+[Room #263] -- Kakariko Library
+[Room #263] -- Kakariko Storage Shed
+[Room #264] -- Kakariko Sweeper Lady's House
+[Room #265] -- Potion Shop
+[Room #266] -- Aginah's Desert Cottage
+[Room #267] -- Watergate
+[Room #268] -- Death Mountain Maze 0011
+[Room #268] -- Fairy Cave 2
+[Room #283] -- Refill Cave 0001
+[Room #283] -- Refill Cave 0002
+[Room #284] -- The Bomb "Shop"
+[Room #284] -- Village of Outcasts Retirement Center
+[Room #286] -- Fairy Cave 3
+[Room #288] -- Good Bee Cave
+[Room #272] -- General Store 1
+[Room #274] -- General Store 2
+[Room #273] -- Archery Game
+[Room #274] -- Storyteller Cave 2
+[Room #275] -- Hall of the Invisibility Cape
+[Room #276] -- Pond of Wishing
+[Room #277] -- Pond of Happiness
+[Room #277] -- Fairy Cave 4
+[Room #269] -- Swamp of Evil Heart Piece Hall
+[Room #271] -- General Store 3
+[Room #281] -- Blind's Old Hideout
+[Room #276] -- Storyteller Cave 3
+[Room #278] -- Warped Pond of Wishing
+[Room #289] -- Chez Smithies
+[Room #290] -- Fortune Teller 1
+[Room #290] -- Fortune Teller 2
+[Room #280] -- Chest Shell Game 2
+[Room #282] -- Storyteller Cave 4
+[Room #270] -- Storyteller Cave 5
+[Room #270] -- Storyteller Cave 6
+[Room #287] -- Village House 1
+[Room #291] -- Thief Hideout 1
+[Room #292] -- Thief Hideout 2
+[Room #292] -- Heart Piece Cave 1
+[Room #293] -- Thief Hideout 3
+[Room #293] -- Refill Cave 3
+[Room #294] -- Fairy Cave 5
+[Room #294] -- Heart Piece Cave 2
+[Room #128] -- Hyrule Castle Prison
+[Room #081] -- Hyrule Castle Throne Room
+[Room #048] -- Hyrule Tower Agahnim's Sanctum
+[Room #088] -- Skull Woods 3 (Drop In)
+[Room #103] -- Skull Woods 4 (Drop In)
+[Room #104] -- Skull Woods 5 (Drop In)
+[Room #086] -- Skull Woods 6 (Drop In)
+[Room #225] -- Lost Woods Thieves' Hideout (Drop In)
+[Room #000] -- Ganon's Pyramid Sanctum (Upper)
+[Room #024] -- Fairy Cave 6 (Drop In)
+[Room #085] -- Hyrule Castle Secret Cellar (Drop In)
+[Room #227] -- Mad Batter Lair (Drop In)
+[Room #226] -- Under Lumberjacks' Weird Tree (Drop In)
+[Room #047] -- Kakariko Western Well (Drop In)
+[Room #017] -- Hyrule Sewers Goodies Room (Drop In)
+[Room #003] -- Chris Houlihan Room (Drop In)
+[Room #295] -- Heart Piece Cave 3 (Drop In)
+[Room #288] -- Ice Rod Cave""".splitlines()
+
+kEntranceNames = [a[a.find(' -- ') + 4:] for a in kEntranceNames]
+
+kEntranceNames_rev = {s:i for i,s in enumerate(kEntranceNames)}
+
+kSpriteNames=['00:Raven', '01:Vulture', '02', '03:BigCanon', '04:PullSwitch', '05:DnSwitch', '06:TrapSwitch', '07:FloorMove', '08:Octorok', '09:Mouldrum', '0A:4WayOctorok', '0B:Chicken', '0C:HoveringRock', '0D:Cucumber', '0E:SnapDragon', '0F:OctoBlimp', '10', '11:Hinox', '12:PigSpearMan', '13:MiniHelmasaur', '14:GargoyleGrate', '15:Bubble', '16:Mutant', '17:BushCrab', '18:Moldorm', '19:Poe/Ghini', '1A:BlackSmith(Frog', '1B:AnArrow', '1C:Statue', '1D:UselessSprite', '1E:PegSwitch', '1F:SickBoy', '20:BombSlug', '21:PushSwitch', '22:HoppingBulbPlan', '23:RedMiri', '24:BlueMiri', '25:LiveTree', '26:BlueOrb', '27:Squirrel', '28:PersonRm270', '29:Thief', '2A:DustGirl', '2B:TentMan', '2C:Lumberjacks', '2D', '2E:FluteBoy', '2F:Person', '30:Person', '31:FortuneTeller', '32:AngryBrother', '33:PullForRupees', '34:ScaredGirl2', '35:HedgeMan', '36:Witch', '37:Waterfall', '38:ArrowTarget', '39:GuyByTheSign', '3A:Person11_227', '3B:DashItem', '3C:FarmBoy', '3D:ScaredGirl1', '3E:RockCrab', '3F:PalaceGuard', '40:ElectricBarrier', '41:BlueSoldier', '42:GreenSoldier', '43:RedSpearSoldier', '44:Warrior', '45:HogSpearMan', '46:BlueArcher', '47:GreenGrassArche', '48:RedSpearKnight', '49:RedGrassSpearSo', '4A:RedBombKnight', '4B:Knight', '4C:Geldman', '4D:Bunny', '4E:Tentacle2', '4F:Tentacle', '50:GlassSquirrel', '51:Armos', '52:ZoraKing', '53:ArmosKnight', '54:Lanmolas', '55:FireBallZora', '56:WalkingZora', '57:HyliaObstacle', '58:Crab', '59:Animal', '5A:Animal', '5B:WallBubble(L-R)', '5C:WallBubble(R-L)', '5D:Roller_1', '5E:Roller_2', '5F:Roller_3', '60:Roller_4', '61:Beamos', '62:MasterSwd', '63:SandCrab1', '64:SandCrab2', '65:ArcherGame', '66:Cannon(Right)', '67:Cannon(Left)', '68:Cannon(Down)', '69:Cannon(Up)', '6A:MorningStar', '6B:CannonSoldier', '6C:Teleport', '6D:Rat', '6E:Rope', '6F:Keese', '70', '71:Leever', '72:Pond', '73:Priest/Uncle', '74:Runner', '75:BottleMan', '76:Zelda', '77:WierdBuble', '78:OldWoman', '79:Bee', '7A:Agahnim', '7B:OneShotMagicBal', '7C:StalfosHead', '7D:BigSpikeBlock', '7E:FireBlade', '7F:FireBlade2', '80:Lanmola', '81:WaterBug', '82:4Bubbles', '83:GreenRocklops', '84:RedRocklops', '85:BigSpikeBlock', '86:Triceritops', '87:FireKeese', '88:Mothula', '89', '8A:SpikeBlock', '8B:Gibdo', '8C:Arrghus', '8D:ArrghusFuzz', '8E:Shell', '8F:Blob', '90:WallMaster', '91:StalfosKnight', '92:Helmasaur', '93:RedOrb', '94', '95:EyeLaser(Right)', '96:EyeLaser(Left)', '97:EyeLaser(Down)', '98:EyeLaser(Up)', '99:Penguin', '9A:Splash', '9B:Wizzrobe', '9C', '9D:VRat', '9E:Ostrich', '9F:Rabbit', 'A0:Uglybird', 'A1:IceMan', 'A2:KholdStare', 'A3', 'A4', 'A5:GreenLizard', 'A6:RedLizard', 'A7:Stalfos', 'A8:GreenAirBomber', 'A9:BlueAirBomber', 'AA:LikeLike', 'AB', 'AC:Apples', 'AD:OldMan', 'AE:DownPipe', 'AF:UpPipe', 'B0:RightPipe', 'B1:LeftPipe', 'B2:Good-Bee', 'B3:Inscription', 'B4:BlueChest', 'B5:BombShop', 'B6:Kiki', 'B7:BlindMan', 'B8', 'B9:Bully&Whimp(DW)', 'BA:Whirlpool', 'BB:ShopMan', 'BC:OldMan2', 'BD:Viterous', 'BE:', 'BF:Lighting', 'C0:Item', 'C1:AgahTalk', 'C2:RockChip', 'C3:Half-Bubble', 'C4:Bully', 'C5:Shooter', 'C6:4WayShooter', 'C7:FuzzyStack', 'C8:BigFairy', 'C9:Tektite', 'CA:Chomp', 'CB:TriNexx1', 'CC:TriNexx2', 'CD:TriNexx3', 'CE:Blind', 'CF:SwampSnake', 'D0:Lynel', 'D1:Transform/Smoke', 'D2:Fish', 'D3:AliveRock', 'D4:GroundBomb', 'D5:DiggingGameGuy', 'D6:Ganon', 'D7', 'D8:Heart', 'D9:Rupee-G', 'DA:Rupee-B', 'DB:InTreeRocks', 'DC:Bomb', 'DD:4_bombs', 'DE:8_bombs', 'DF:Magic', 'E0:BigMagic', 'E1:Arrow', 'E2:10-Arrows', 'E3:Fairy', 'E4:Key', 'E5:Big_Key', 'E6', 'E7:Mushroom', 'E8:FakeSword', 'E9:ShopMan2', 'EA:WitchAssistant', 'EB:HeartPie', 'EC:PickedObj', 'ED', 'EE:Mantle', 'EF', 'F0', 'F1', 'F2:MedallianTablet', 'F3:PersonsDoor', 'F4:FallingRocks', 'F5', 'F6', 'F7', 'F8', 'F9', 'FA', 'FB', 'FC', 'FD', 'FE', 'FF', '100:CannonRoom', '101:01', '102:CannonRoom', '103:CannonBalls', '104:RopeDrp(Snake)', '105:StalfosDrop', '106:BombDrop', '107:MovingFloor', '108:Transformer', '109:WallMaster', '10A:FloorDrop(Sqr)', '10B:FloorDrop(Vert)', '10C:0C', '10D:0D', '10E:0E', '10F:0F', '110:RightEvil', '111:LeftEvil', '112:DownEvil
\ No newline at end of file
+kSpriteNames = [a.replace(':', '-') for a in kSpriteNames]
+
+kSpriteName2Idx = {a:i for i,a in enumerate(kSpriteNames)}
+kSpriteNamesRev = {v : i for i, v in enumerate(kSpriteNames)}
+
+
+
+kSpriteDropToNameIdx = [
+  0xd9, 0x3e, 0x79, 0xd9, 0xdc, 0xd8, 0xda, 0xe4, 0xe1, 0xdc, 0xd8, 0xdf, 0xe0, 0xb, 0x42, 0xd3, 
+  0x41, 0xd4, 0xd9, 0xe3, 0xd8,    0, ]
+
+def get_secret_names():
+  r = {}
+  for i in range(1, 23):
+    r[i] = '%.2X-%s' % (i, kSpriteNames[kSpriteDropToNameIdx[i - 1]][3:])
+  kSpecialSecret = {0 : "Nothing", 4 : "Random", 0x80 : "Hole", 0x82 : "Warp", 0x84 : "Staircase", 0x86 : 'Bombable', 0x88 : 'Switch' }
+  for k,v in kSpecialSecret.items():
+    r[k] = '%.2X-%s' % (k, v)
+  return r
+
+kSecretNames = get_secret_names()
+kSecretNamesRev = invert_dict(kSecretNames)
+
+kCompSpritePtrs = [
+  0x10f000,0x10f600,0x10fc00,0x118200,0x118800,0x118e00,0x119400,0x119a00,
+  0x11a000,0x11a600,0x11ac00,0x11b200,0x14fffc,0x1585d4,0x158ab6,0x158fbe,
+  0x1593f8,0x1599a6,0x159f32,0x15a3d7,0x15a8f1,0x15aec6,0x15b418,0x15b947,
+  0x15bed0,0x15c449,0x15c975,0x15ce7c,0x15d394,0x15d8ac,0x15ddc0,0x15e34c,
+  0x15e8e8,0x15ee31,0x15f3a6,0x15f92d,0x15feba,0x1682ff,0x1688e0,0x168e41,
+  0x1692df,0x169883,0x169cd0,0x16a26e,0x16a275,0x16a787,0x16aa06,0x16ae9d,
+  0x16b3ff,0x16b87e,0x16be6b,0x16c13d,0x16c619,0x16cbbb,0x16d0f1,0x16d641,
+  0x16d95a,0x16dd99,0x16e278,0x16e760,0x16ed25,0x16f20f,0x16f6b7,0x16fa5f,
+  0x16fd29,0x1781cd,0x17868d,0x178b62,0x178fd5,0x179527,0x17994b,0x179ea7,
+  0x17a30e,0x17a805,0x17acf8,0x17b2a2,0x17b7f9,0x17bc93,0x17c237,0x17c78e,
+  0x17cd55,0x17d2bc,0x17d82f,0x17dcec,0x17e1cc,0x17e36b,0x17e842,0x17eb38,
+  0x17ed58,0x17f06c,0x17f4fd,0x17fa39,0x17ff86,0x18845c,0x1889a1,0x188d64,
+  0x18919d,0x189610,0x189857,0x189b24,0x189dd2,0x18a03f,0x18a4ed,0x18a7ba,
+  0x18aedf,0x18af0d,0x18b520,0x18b953,
+]
+
+kCompBgPtrs = [
+  0x11b800,0x11bce2,0x11c15f,0x11c675,0x11cb84,0x11cf4c,0x11d2ce,0x11d726,
+  0x11d9cf,0x11dec4,0x11e393,0x11e893,0x11ed7d,0x11f283,0x11f746,0x11fc21,
+  0x11fff2,0x128498,0x128a0e,0x128f30,0x129326,0x129804,0x129d5b,0x12a272,
+  0x12a6fe,0x12aa77,0x12ad83,0x12b167,0x12b51d,0x12b840,0x12bd54,0x12c1c9,
+  0x12c73d,0x12cc86,0x12d198,0x12d6b1,0x12db6a,0x12e0ea,0x12e6bd,0x12eb51,
+  0x12f135,0x12f6c5,0x12fc71,0x138129,0x138693,0x138bad,0x139117,0x139609,
+  0x139b21,0x13a074,0x13a619,0x13ab2b,0x13b00c,0x13b4f5,0x13b9eb,0x13bebf,
+  0x13c3ce,0x13c817,0x13cb68,0x13cfb5,0x13d460,0x13d8c2,0x13dd7a,0x13e266,
+  0x13e7af,0x13ece5,0x13f245,0x13f6f0,0x13fc30,0x1480e9,0x14863b,0x148a7c,
+  0x148f2a,0x149346,0x1497ed,0x149cc2,0x14a173,0x14a61d,0x14ab5d,0x14b083,
+  0x14b4bd,0x14b94e,0x14be0e,0x14c291,0x14c7ba,0x14cce4,0x14d1db,0x14d6bd,
+  0x14db77,0x14ded1,0x14e2ac,0x14e754,0x14ebae,0x14ef4e,0x14f309,0x14f6f4,
+  0x14fa55,0x14ff8c,0x14ff93,0x14ff9a,0x14ffa1,0x14ffa8,0x14ffaf,0x14ffb6,
+  0x14ffbd,0x14ffc4,0x14ffcb,0x14ffd2,0x14ffd9,0x14ffe0,0x14ffe7,0x14ffee,
+  0x14fff5,0x18b520,0x18b953,
+]
+
+kSpriteTilesets = [
+  ( 0, 73,   0,  0),
+  (70, 73,  12, 29),
+  (72, 73,  19, 29),
+  (70, 73,  19, 14),
+  (72, 73,  12, 17),
+  (72, 73,  12, 16),
+  (79, 73,  74, 80),
+  (14, 73,  74, 17),
+  (70, 73,  18,  0),
+  ( 0, 73,   0, 80),
+  ( 0, 73,   0, 17),
+  (72, 73,  12,  0),
+  ( 0,  0,  55, 54),
+  (72, 73,  76, 17),
+  (93, 44,  12, 68),
+  ( 0,  0,  78,  0),
+  (15,  0,  18, 16),
+  ( 0,  0,   0, 76),
+  ( 0, 13,  23,  0),
+  (22, 13,  23, 27),
+  (22, 13,  23, 20),
+  (21, 13,  23, 21),
+  (22, 13,  24, 25),
+  (22, 13,  23, 25),
+  (22, 13,   0,  0),
+  (22, 13,  24, 27),
+  (15, 73,  74, 17),
+  (75, 42,  92, 21),
+  (22, 73,  23, 29),
+  ( 0,  0,   0, 21),
+  (22, 13,  23, 16),
+  (22, 73,  18,  0),
+  (22, 73,  12, 17),
+  ( 0,  0,  18, 16),
+  (22, 13,   0, 17),
+  (22, 73,  12,  0),
+  (22, 13,  76, 17),
+  (14, 13,  74, 17),
+  (22, 26,  23, 27),
+  (79, 52,  74, 80),
+  (53, 77, 101, 54),
+  (74, 52,  78,  0),
+  (14, 52,  74, 17),
+  (81, 52,  93, 89),
+  (75, 73,  76, 17),
+  (45,  0,   0,  0),
+  (93,  0,  18, 89),
+  ( 0,  0,   0,  0),
+  ( 0,  0,   0,  0),
+  ( 0,  0,   0,  0),
+  ( 0,  0,   0,  0),
+  ( 0,  0,   0,  0),
+  ( 0,  0,   0,  0),
+  ( 0,  0,   0,  0),
+  ( 0,  0,   0,  0),
+  ( 0,  0,   0,  0),
+  ( 0,  0,   0,  0),
+  ( 0,  0,   0,  0),
+  ( 0,  0,   0,  0),
+  ( 0,  0,   0,  0),
+  ( 0,  0,   0,  0),
+  ( 0,  0,   0,  0),
+  ( 0,  0,   0,  0),
+  ( 0,  0,   0,  0),
+  (71, 73,  43, 45),
+  (70, 73,  28, 82),
+  ( 0, 73,  28, 82),
+  (93, 73,   0, 82),
+  (70, 73,  19, 82),
+  (75, 77,  74, 90),
+  (71, 73,  28, 82),
+  (75, 77,  57, 54),
+  (31, 44,  46, 82),
+  (31, 44,  46, 29),
+  (47, 44,  46, 82),
+  (47, 44,  46, 49),
+  (31, 30,  48, 82),
+  (81, 73,  19,  0),
+  (79, 73,  19, 80),
+  (79, 77,  74, 80),
+  (75, 73,  76, 43),
+  (31, 32,  34, 83),
+  (85, 61,  66, 67),
+  (31, 30,  35, 82),
+  (31, 30,  57, 58),
+  (31, 30,  58, 62),
+  (31, 30,  60, 61),
+  (64, 30,  39, 63),
+  (85, 26,  66, 67),
+  (31, 30,  42, 82),
+  (31, 30,  56, 82),
+  (31, 32,  40, 82),
+  (31, 32,  38, 82),
+  (31, 44,  37, 82),
+  (31, 32,  39, 82),
+  (31, 30,  41, 82),
+  (31, 44,  59, 82),
+  (70, 73,  36, 82),
+  (33, 65,  69, 51),
+  (31, 44,  40, 49),
+  (31, 13,  41, 82),
+  (31, 30,  39, 82),
+  (31, 32,  39, 83),
+  (72, 73,  19, 82),
+  (14, 30,  74, 80),
+  (31, 32,  38, 83),
+  (21,  0,   0,  0),
+  (31,  0,  42, 82),
+  ( 0,  0,   0,  0),
+  ( 0,  0,   0,  0),
+  ( 0,  0,   0,  0),
+  ( 0,  0,   0,  0),
+  ( 0,  0,   0,  0),
+  ( 0,  0,   0,  0),
+  ( 0,  0,   0,  0),
+  ( 0,  0,   0,  0),
+  ( 0,  0,   0,  0),
+  ( 0,  0,   0,  0),
+  ( 0,  0,   0,  0),
+  ( 0,  0,   0,  0),
+  ( 0,  0,   0,  0),
+  ( 0,  0,   0,  0),
+  ( 0,  0,   0,  0),
+  ( 0,  0,   0,  0),
+  ( 0,  0,   0,  0),
+  (50,  0,   0,  8),
+  (93, 73,   0, 82),
+  (85, 73,  66, 67),
+  (97, 98,  99, 80),
+  (97, 98,  99, 80),
+  (97, 98,  99, 80),
+  (97, 98,  99, 80),
+  (97, 98,  99, 80),
+  (97, 98,  99, 80),
+  (97, 86,  87, 80),
+  (97, 98,  99, 80),
+  (97, 98,  99, 80),
+  (97, 86,  87, 80),
+  (97, 86,  99, 80),
+  (97, 86,  87, 80),
+  (97, 86,  51, 80),
+  (97, 86,  87, 80),
+  (97, 98,  99, 80),
+  (97, 98,  99, 80),
+]
+
+kDungPalinfos = [
+  ( 0,  0,  3,  1),
+  ( 2,  0,  3,  1),
+  ( 4,  0, 10,  1),
+  ( 6,  0,  1,  7),
+  (10,  2,  2,  7),
+  ( 4,  4,  3, 10),
+  (12,  5,  8, 20),
+  (14,  0,  3, 10),
+  ( 2,  0, 15, 20),
+  (10,  2,  0,  7),
+  ( 2,  0, 15, 12),
+  ( 6,  0,  6,  7),
+  ( 0,  0, 14, 18),
+  (18,  5,  5, 11),
+  (18,  0,  2, 12),
+  (16,  5, 10,  7),
+  (16,  0, 16, 12),
+  (22,  7,  2,  7),
+  (22,  0,  7, 15),
+  ( 8,  0,  4, 12),
+  ( 8,  0,  4,  9),
+  ( 4,  0,  3,  1),
+  (20,  0,  4,  4),
+  (20,  0, 20, 12),
+  (24,  5,  7, 11),
+  (24,  6, 16, 12),
+  (26,  5,  8, 20),
+  (26,  2,  0,  7),
+  ( 6,  0,  3, 10),
+  (28,  0,  3,  1),
+  (30,  0, 11, 17),
+  ( 4,  0, 11, 17),
+  (14,  0,  0,  2),
+  (32,  8, 19, 13),
+  (10,  0,  3, 10),
+  (20,  0,  4,  4),
+  (26,  2,  2,  7),
+  (26, 10,  0,  0),
+  ( 0,  0,  3,  2),
+  (14,  0,  3,  7),
+  (26,  5,  5, 11),
+]
+
+kOwSprPalInfo = [
+  -1, -1, 3, 10, 3, 6, 3, 1, 0, 2, 3, 14, 3, 2, 19, 1, 11, 12, 17, 1, 7, 5, 17, 0,
+  9, 11, 15, 5, 3, 5, 3, 7, 15, 2, 10, 2, 5, 1, 12, 14,
+]
+
+kSpriteInit_Flags3 = [
+  0x19,  0xb, 0x1b, 0x4b, 0x41, 0x41, 0x41, 0x4d, 0x1d,    1, 0x1d, 0x19, 0x8d, 0x1b,    9, 0x9d,
+  0x3d,    1,    9, 0x11, 0x40,    1, 0x4d, 0x19,    7, 0x1d, 0x59, 0x80, 0x4d, 0x40,    1, 0x49,
+  0x1b, 0x41,    3, 0x13, 0x15, 0x41, 0x18, 0x1b, 0x41, 0x47,  0xf, 0x49, 0x4b, 0x4d, 0x41, 0x47,
+  0x49, 0x4d, 0x49, 0x40, 0x4d, 0x47, 0x49, 0x41, 0x74, 0x47, 0x5b, 0x58, 0x51, 0x49, 0x1d, 0x5d,
+     3, 0x19, 0x1b, 0x17, 0x19, 0x17, 0x19, 0x1b, 0x17, 0x17, 0x17, 0x1b,  0xd,    9, 0x19, 0x19,
+  0x49, 0x5d, 0x5b, 0x49,  0xd,    3, 0x13, 0x41, 0x1b, 0x5b, 0x5d, 0x43, 0x43, 0x4d, 0x4d, 0x4d,
+  0x4d, 0x4d, 0x49,    1,    0, 0x41, 0x4d, 0x4d, 0x4d, 0x4d, 0x1d,    9, 0xc4,  0xd,  0xd,    9,
+     3,    3, 0x4b, 0x47, 0x47, 0x49, 0x49, 0x41, 0x47, 0x36, 0x8b, 0x49, 0x1d, 0x49, 0x43, 0x43,
+  0x43,  0xb, 0x41,  0xd,    7,  0xb, 0x1d, 0x43,  0xd, 0x43,  0xd, 0x1d, 0x4d, 0x4d, 0x1b, 0x1b,
+   0xa,  0xb,    0,    5,  0xd,    1,    1,    1,    1,  0xb,    5,    1,    1,    1,    7, 0x17,
+  0x19,  0xd,  0xd, 0x80, 0x4d, 0x19, 0x17, 0x19,  0xb,    9,  0xd, 0x4a, 0x12, 0x49, 0xc3, 0xc3,
+  0xc3, 0xc3, 0x76, 0x40, 0x59, 0x41, 0x58, 0x4f, 0x73, 0x5b, 0x44, 0x41, 0x51,  0xa,  0xb,  0xb,
+  0x4b,    0, 0x40, 0x5b,  0xd,    0,    0,  0xd, 0x4b,  0xb, 0x59, 0x41,  0xb,  0xd,    1,  0xd,
+   0xd,    0, 0x50, 0x4c, 0x44, 0x51,    1,    1, 0xf2, 0xf8, 0xf4, 0xf2, 0xd4, 0xd4, 0xd4, 0xf8,
+  0xf8, 0xf4, 0xf4, 0xd8, 0xf8, 0xd8, 0xdf, 0xc8, 0x69, 0xc1, 0xd2, 0xd2, 0xdc, 0xc7, 0xc1, 0xc7,
+  0xc7, 0xc7, 0xc1,
+]
--- /dev/null
+++ b/assets/text_compression.py
@@ -1,0 +1,551 @@
+import util, sys
+
+kTextAlphabet_US = [
+  "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", # 0 - 15
+  "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "a", "b", "c", "d", "e", "f", # 16 - 31
+  "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", # 32 - 47
+  "w", "x", "y", "z", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "!", "?", # 48 - 63
+  "-", ".", ",", 
+  # 64 - 79
+  "[...]", ">", "(", ")",
+  "[Ankh]", "[Waves]", "[Snake]", "[LinkL]", "[LinkR]",
+  "\"", "[Up]", "[Down]", "[Left]",
+  # 80 - 95
+  "[Right]", "'", "[1HeartL]", "[1HeartR]", "[2HeartL]", "[3HeartL]", "[3HeartR]",
+  "[4HeartL]", "[4HeartR]", " ", "<", "[A]", "[B]", "[X]", "[Y]",
+]
+
+kTextAlphabet_DE = [
+  "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", # 0 - 15
+  "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "a", "b", "c", "d", "e", "f", # 16 - 31
+  "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", # 32 - 47
+  "w", "x", "y", "z", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "!", "?", # 48 - 63
+  # 64 - 79
+  "-", ".", ",",  "[...]", ">", "(", ")",
+  "[Ankh]", "[Waves]", "[Snake]", "[LinkL]", "[LinkR]",
+  "\"", "[UpL]", "[UpR]", "[LeftL]",
+  # 80 - 95
+  "[LeftR]", "'", "[1HeartL]", "[1HeartR]", "[2HeartL]", "[3HeartL]", "[3HeartR]",
+  "[4HeartL]", "[4HeartR]", " ", "ö", "[A]", "[B]", "[X]", "[Y]", "ü",
+  # 96-111
+  "ß", ":", "[DownL]", "[DownR]", "[RightL]", "[RightR]",
+  "è", "é", "ê", "à", "ù", "ç", "Ä", "Ö", "Ü", "ä"
+  # 112-
+]
+
+kTextAlphabet_FR = [
+  "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", # 0 - 15
+  "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "a", "b", "c", "d", "e", "f", # 16 - 31
+  "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", # 32 - 47
+  "w", "x", "y", "z", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "!", "?", # 48 - 63
+  # 64 - 79
+  "-", ".", ",",  "[...]", ">", "(", ")",
+  "[Ankh]", "[Waves]", "[Snake]", "[LinkL]", "[LinkR]",
+  "\"", "[UpL]", "[UpR]", "[LeftL]",
+  # 80 - 95
+  "[LeftR]", "'", "[1HeartL]", "[1HeartR]", "[2HeartL]", "[3HeartL]", "[3HeartR]",
+  "[4HeartL]", "[4HeartR]", " ", "ö", "[A]", "[B]", "[X]", "[Y]", "ü",
+  # 96-111
+  "ô", ":", "[DownL]", "[DownR]", "[RightL]", "[RightR]",
+  "è", "é", "ê", "à", "ù", "ç", "â", "û", "î", "ä"
+  # 112-
+]
+
+kText_CommandLengths_US = [1, 1, 1, 1, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 1, 1, 1, 1, 1, ]
+kText_CommandNames_US = [
+  "NextPic", "Choose", "Item", "Name", "Window", "Number",
+  "Position","ScrollSpd", "Selchg", "Unused_Crash", "Choose3",
+  "Choose2", "Scroll", "1", "2", "3", "Color",
+  "Wait", "Sound", "Speed", "Unused_Mark", "Unused_Mark2", "Unused_Clear",
+  "Waitkey"
+]
+
+kTextDictionary_US = [
+'    ', '   ', '  ', "'s ", 'and ', 
+'are ', 'all ', 'ain', 'and', 'at ', 
+'ast', 'an', 'at', 'ble', 'ba', 
+'be', 'bo', 'can ', 'che', 'com', 
+'ck', 'des', 'di', 'do', 'en ', 
+'er ', 'ear', 'ent', 'ed ', 'en', 
+'er', 'ev', 'for', 'fro', 'give ', 
+'get', 'go', 'have', 'has', 'her', 
+'hi', 'ha', 'ight ', 'ing ', 'in', 
+'is', 'it', 'just', 'know', 'ly ', 
+'la', 'lo', 'man', 'ma', 'me', 
+'mu', "n't ", 'non', 'not', 'open', 
+'ound', 'out ', 'of', 'on', 'or', 
+'per', 'ple', 'pow', 'pro', 're ', 
+'re', 'some', 'se', 'sh', 'so', 
+'st', 'ter ', 'thin', 'ter', 'tha', 
+'the', 'thi', 'to', 'tr', 'up', 
+'ver', 'with', 'wa', 'we', 'wh', 
+'wi', 'you', 'Her', 'Tha', 'The', 
+'Thi', 'You', 
+]
+
+
+kText_CommandLengths_EU = [1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2]
+kText_CommandNames_EU = [
+  "Selchg", "Choose3", "Choose2", "Scroll", "1", "2", "3",
+  "Color", "Wait", "Sound", "Speed", "Mark", "Mark2",
+  "Clear", "Waitkey", "EndMessage", "NextPic", "Choose",
+  "Item", "Name", "Window", "Number", "Position", "ScrollSpd",
+]
+
+kTextDictionary_DE = [
+'    ', '   ', '                                          ', '-Knopf', ' ich ', 
+' Sch', ' Ver', ' zu ', ' es ', 'aber', 
+'alle', 'auch', 'ang', 'aus', 'auf', 
+'an', 'bist', 'bin', 'bei', 'der ', 
+'die ', 'das ', 'den ', 'dem ', 'daß', 
+'der', 'die', 'das', 'den', 'da', 
+'etwas', 'ein ', 'ein', 'en ', 'er ', 
+'es ', 'en', 'er', 'es', 'ei', 
+'für', 'fe', 'habe', 'hier', 'hast', 
+'her', 'ich ', 'icht', 'ich', 'ist', 
+'ie ', 'im', 'ie', 'kannst ', 'kannst', 
+'kommen', 'kann ', 'll', 'mich', 'mein', 
+'mit', 'mal', 'mir', 'nicht ', 'nicht', 
+'nen', 'nn', 'och ', 'och', 'or', 
+'schon', 'sich', 'sein', 'sch', 'sie', 
+'st', 'tte', 'te ', 'te', 'und ', 
+'und', 'ung', 'um', 'von', 'ver', 
+'vor', 'wird', 'zu ', 'Amulett', 'Aber', 
+'Deine', 'Dich ', 'Dir ', 'Dir', 'Der', 
+'Die', 'Das', 'Du ', 'Du', 'Da', 
+'Ein', 'Hyrule', 'Hier', 'Ich ', 'Master-Schwert', 
+'Mach', 'Rubine', 'Sch', 'Sie', 'Ver', 
+'Weisen', 'Zelda', 
+]
+
+kTextDictionary_FR = [
+'                                          ', ' de ', ' la ', ' le ', ' ! ', 
+' d', ' p', ' t', ' !', ", c'est moi, Sahasrahla", 
+', ', 'ais ', 'as ', 'an', 'ai', 
+'a ', 'che', 'ce', 'ch', 'dans ', 
+'des ', 'de ', 'de', 'est ', 'ent', 
+'en ', 'er ', 'es ', 'en', 'es', 
+'et', 'eu', 'e,', 'e ', 'ique', 
+'ien', 'is ', 'ie', 'in', 'ir', 
+'is', 'i ', 'les ', 'la ', 'le ', 
+'le', 'll', 'maintenant', 'magique', 'ment', 
+'mon', 'mai', 'me', 'ne ', 'onne', 
+'oir', 'our', 'ouv', 'oi', 'on', 
+'ou', 'or', 'pouvoir', 'pour', 'peux', 
+'pas', 'que ', 'qu', 'rubis', 're ', 
+'ra', 're', 'r ', 'sorcier', 's l', 
+'s d', 'se', 'so', 's ', 'tro', 
+'te ', 'tu ', 'te', 't ', 'un', 
+'ur', 'u ', 'ver', 'Ah ! Ah ! Ah !', "C'est", 
+'Ganon', 'Maintenant', 'Merci', 'Monde', 'Perle de Lune', 
+'Tu as trouvé ', 'Ténèbres', 'Tu peux', 'Tu ',
+]
+
+
+# Uses the original format
+def org_encoder(cmd, param):
+    if cmd not in kText_CommandNames_US:
+      raise Exception(f'Invalid cmd {cmd}')
+    cmd_index = kText_CommandNames_US.index(cmd)
+    if kText_CommandLengths_US[cmd_index] != (1 if param == None else 2):
+      raise Exception(f'Invalid cmd params {cmd} {param}')
+    if param == None:
+      return [cmd_index + 0x67]
+    return [cmd_index + 0x67, int(param)]
+
+kCmdInfo = {
+  "Scroll" : (0x80, ),
+  "Waitkey" : (0x81, ),
+  "1" : (0x82, ),
+  "2" : (0x83, ),
+  "3" : (0x84, ),
+  "Name" : (0x85, ),
+  "Wait" : (0x87, {i:i+0x00 for i in range(16)}),
+  "Color" : (0x87, {i:i+0x10 for i in range(16)}),
+  "Number" : (0x87, {i:i+0x20 for i in range(16)}),
+  "Speed" : (0x87, {i:i+0x30 for i in range(16)}),
+  "Sound" : (0x87, {45 : 0x40, 64 : None}), # pt uses 64 for some reason
+  "Choose" : (0x87, 0x80),
+  "Choose2" : (0x87, 0x81),
+  "Choose3" : (0x87, 0x82),
+  "Selchg" : (0x87, 0x83),
+  "Item" : (0x87, 0x84),
+  "NextPic" : (0x87, 0x85),
+  "Window" : (0x87, {0 : None, 2 : 0x86}),
+  "Position" : (0x87, {0: 0x87, 1: 0x88}),
+  "ScrollSpd" : (0, {0 : None}),
+}
+
+# Uses another format where there's more bytes left for characters
+def new_encoder(cmd, param):
+  if cmd not in kCmdInfo:
+    raise Exception(f'Invalid cmd {cmd}')
+  info = kCmdInfo[cmd]
+  if len(info) <= 1 or isinstance(info[1], int):
+    if param != None:
+      raise Exception(f'Invalid cmd params {cmd} {param}')
+    return info
+  else:
+    if param == None or param not in info[1]:
+      raise Exception(f'Invalid cmd params {cmd} {param}')
+    r = info[1][param]
+    return (info[0], r) if r != None else ()
+
+kEncoders = {'org' : org_encoder, 'new' : new_encoder}
+
+
+class LangUS:
+  alphabet = kTextAlphabet_US
+  dictionary = kTextDictionary_US
+  command_lengths = kText_CommandLengths_US
+  command_names = kText_CommandNames_US
+  rom_addrs = [0x9c8000, 0x8edf40]
+  COMMAND_START = 0x67
+  SWITCH_BANK = 0x80
+  FINISH = 0xff
+  DICT_BASE_ENC, DICT_BASE_DEC = 0x88, 0x88
+  ESCAPE_CHARACTER = None
+  encoder = 'org'
+
+class LangEN(LangUS):
+  alphabet = kTextAlphabet_DE
+  dictionary = kTextDictionary_US
+  rom_addrs = [0x9c8000, 0x8edf60]
+
+class LangES(LangUS):
+  alphabet = [
+    "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", # 0 - 15
+    "Q", "R", "S", "T", "U", "V", "W", "é", "Y", "Z", "a", "b", "c", "d", "e", "f", # 16 - 31
+    "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", # 32 - 47
+    "ó", "x", "y", "z", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "!", "?", # 48 - 63
+    "[Waves]", ".", ",", 
+    # 64 - 79
+    "[...]", ">", "(", ")",
+    "ñ", "ú", "á", "[LinkL]", "[LinkR]", "\"", "[Up]", "[Down]", "[Left]",
+    # 80 - 95
+    "[Right]", "í", "[1HeartL]", "[1HeartR]", "[2HeartL]", "[3HeartL]", "[3HeartR]",
+    "[Ankh]", "[4HeartR]", " ", "[Snake]", "[A]", "[B]", "[X]", "[Y]", "[I]",
+    "¡", "¿", "Ñ"
+  ]
+  # "[Ankh]", "[Waves]", "[Snake]"
+
+  dictionary = [
+    '    ', '   ', '  ', ' en', ' la ', ' el ', ' de ', 'ien', 'tra', ' de', 
+    'te ', 'ar', 'a ', 'ada', 'es', 'as', 'o ', ' con', 'ero', 'ado', 
+    'e ', 'que', 'en', 'al', 'os ', 'ora', 'nte', ' al', 'lo ', 'or', 
+    'os', 'er', 'aci', 'res', ' que ', ' es', 'el', 'los ', 'tar', ' se', 
+    ', ', 'ro', ' de l', ' est', 're', 'on', 'an', 'pued', ' del', 'ás ', 
+    'la', 'ti', 'la ', 'Es', 'to', 'ta', 'para', 'uer', 'ier', ' un ', 
+    ' por', 'oder', 'da', 'in', 'cu', ' ha', 'per', 'ano', ' ve', 'cer', 
+    'lo', ' no ', 'ic', 'ra', 'ab', 'ir', ' una', 'undo', 'es ', 'as ', 
+    'con', 'a, ', 'te', ' m', 'gu', ' tu', 'ando', ' p', 'de', 'le', 
+    'ol', 'o, ', 'ten', 'lle', ' a ', 'aba', 'com', 
+  ]
+  rom_addrs = [0x9c8000, 0x8edf40]
+
+
+class LangNL(LangUS):
+  alphabet = [
+    "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", # 0 - 15
+    "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "a", "b", "c", "d", "e", "f", # 16 - 31
+    "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", # 32 - 47
+    "w", "x", "y", "z", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "!", "?", # 48 - 63
+    "-", ".", ",", "[...]", ">", "(", ")", "[Ankh]",
+    "[Waves]", "[Snake]", "[LinkL]", "[LinkR]", "\"", "[Up]", "[Down]", "[Left]",
+    # 80 - 95
+    "[Right]", "'", "[1HeartL]", "[1HeartR]", "[2HeartL]", "[3HeartL]", "[3HeartR]",
+    "[4HeartL]", "[4HeartR]", " ", "<", "[A]", "[B]", "[X]", "[Y]",
+  ]
+
+  dictionary = [
+    '    ', '   ', '  ', "'s ", 'and ', 'are ', 'all ', 'ain', 'and', 'at ', 
+    'ast', 'an', 'at', 'ble', 'ba', 'be', 'bo', 'can ', 'che', 'com', 
+    'ck', 'des', 'di', 'do', 'en ', 'er ', 'ear', 'ent', 'ed ', 'en', 
+    'er', 'ev', 'for', 'fro', 'give ', 'get', 'go', 'have', 'has', 'her', 
+    'hi', 'ha', 'ight ', 'ing ', 'in', 'is', 'it', 'just', 'know', 'ly ', 
+    'la', 'lo', 'man', 'ma', 'me', 'mu', "n't ", 'non', 'not', 'open', 
+    'ound', 'out ', 'of', 'on', 'or', 'per', 'ple', 'pow', 'pro', 're ', 
+    're', 'some', 'se', 'sh', 'so', 'st', 'ter ', 'thin', 'ter', 'tha', 
+    'the', 'thi', 'to', 'tr', 'up', 'ver', 'with', 'wa', 'we', 'wh', 
+    'wi', 'you', 'Her', 'Tha', 'The', 'Thi', 'You', 
+  ]
+  rom_addrs = [0x9c8000, 0x8edf40]
+
+
+
+class LangSV(LangUS):
+  alphabet = [
+    "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "Ö", "P", # 0 - 15
+    "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "a", "b", "c", "d", "e", "f", # 16 - 31
+    "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", # 32 - 47
+    "w", "x", "y", "z", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "!", "?", # 48 - 63
+    "å", ".", ",", "ä", ">", "(", ")","ö",
+    "Å", "Ä", "[LinkL]", "[LinkR]", "\"", "[Up]", "[Down]", "[Left]",
+    # 80 - 95
+    "[Right]", "'", "[1HeartL]", "[1HeartR]", "[2HeartL]", "[3HeartL]", "[3HeartR]",
+    "[4HeartL]", "[4HeartR]", " ", "<", "[Ankh]", "[Waves]", "[Snake]", "-", "[I]",
+    "[i]", "…", " ",
+  ]
+
+  dictionary = [
+    '    ', '   ', '  ', 'Du ', 'till', 'vill', 'bara', 'det', 'den', 'och', 
+    'en ', 'r ', 'n ', 'ett', 'en', ' d', 'a ', 'Hjäl', 'har', 'ter', 
+    't ', 'var', ' s', 'de', 'kan', 'med', 'som', 'för', 'att', 'ar', 
+    ' h', 'er', 'jag', 'dig', 'öppna', 'mig', 'är', 'inte', 'hit', 'på ', 
+    'an', 'e ', 'rupie', '0kej', ' m', 'et', ', ', 'gång', 'måst', 'ten', 
+    ' f', 'u ', 'men', 'te', 'tt', 'ka', 'vara', 'ken', '0m ', 'från', 
+    'myck', 'någo', 'in', ' k', ' i', 'vil', 'bar', 'ond', 'För', 'Jag', 
+    'ra', 'tack', 'll', 'g ', 'ta', 'om', 'anna', 'alla', 'en,', 'ber', 
+    'hem', 'han', 'st', 'ig', ' t', 'tro', 'kraf', 'ör', ' v', 'ag', 
+    '… ', 'får', 'sin', 'mme', 'mma', 'en ', 'tat',
+  ]
+  rom_addrs = [0x9c8000, 0x8edf40]
+
+
+class LangPL(LangUS):
+  alphabet = [
+    "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", # 0 - 15
+    "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "a", "b", "c", "d", "e", "f", # 16 - 31
+    "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", # 32 - 47
+    "w", "x", "y", "z", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "!", "?", # 48 - 63
+    "-", ".", ",", "ć", "[Right]", "(", ")", "[Ankh]", 
+    "[Waves]", "[Snake]", "[LinkL]", "[LinkR]","\"", "[Up]", "[Down]", "ę",
+
+    "ł", "ń", "[1HeartL]", "[1HeartR]", "[2HeartL]", "[3HeartL]", "[3HeartR]",
+    "ą", "[4HeartR]", " ", "[Left]", "ó", "ś", "ż", "ź", "Ł",
+    "Ś", "Ż", "Ź",
+  ] # 
+  dictionary = ['Trój', '...', 'ść', 'Nie', ' nie', ' się', 'może', ' że', 'and', 'at ', 
+    ' ty', 'an', 'at', 'kus', 'ba', 'be', 'bo', 'chce', 'che', 'ki ', 
+    'za', 'des', 'di', 'do', 'en ', 'er ', 'sz ', 'ent', 'ed ', 'en', 
+    'er', ' w', 'moc', 'zię', 'przez', 'ale', 'go', 'dzie', 'has', 'rze', 
+    'hi', 'ha', 'który', 'aby ', 'in', 'is', 'it', 'twoj', 'Może', 'łeś', 
+    'la', 'lo', 'czn', 'ma', 'me', 'mu', 'szcz', 'ska', 'śli', 'przy', 
+    'znaj', 'iecz', 'of', 'on', 'or', '   ', 'ple', 'pow', 'pro', 're ', 
+    're', 'mnie', 'se', ' z', 'so', 'st', 'któr', ' jak', 'ksz', 'sze', 
+    'coś', ' je', 'to', 'tr', 'up', 'kie', 'praw', 'wa', 'we', 'mi', 
+    'wi', 'szy', 'chc', 'pra', 'cie', ' i ', 'esz',
+  ]
+
+  rom_addrs = [0x9c8000, 0x8edf40]
+
+class LangPT(LangUS):
+  alphabet = [
+    "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", # 0 - 15
+    "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "a", "b", "c", "d", "e", "f", # 16 - 31
+    "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", # 32 - 47
+    "w", "x", "y", "z", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "!", "?", # 48 - 63
+    "-", ".", ",", "[...]", ">", "(", ")", "[Ankh]",
+    "[Waves]", "[Snake]", "[LinkL]", "[LinkR]", "\"", "[Up]", "[Down]", "[Left]",
+    # 80 - 95
+    "[Right]", "'", "[1HeartL]", "[1HeartR]", "[2HeartL]", "[3HeartL]", "[3HeartR]",
+    "[4HeartL]", "[4HeartR]", " ", "<", "[A]", "[B]", "[X]", "[Y]", "[I]",
+
+    "¡", "[!]", "Á", "À", "Â", "Ã", "É", "Ê", "Í", "Ó", "Ô", "Õ", "Ú", "á", "à", "â", 
+    "ã", "é", "ê", "í", "ó", "ô", "õ", "ú", "ç", 
+  ]
+  dictionary = [
+    '     ', '    ', '   ', '                                          ', 'o ', 'a ', 'e ', '..', 'de', 'ar', 
+    's ', 'ra', ' d', 'es', 'ocê ', 'do', ' a', ' p', 'er', ' e', 
+    'que', 'r ', 'os', 'te', ', ', 'as', 'or', 'm ', 'en', ' o', 
+    'nt', 're', ' s', 'co', 'da', 'se', 'st', ' c', ' m', 'em', 
+    'ma', 'ta', ' n', 'ad', 'on', 'al', 'ro', 'an', 'u ', 'nd', 
+    ' um', 'pa', 'ca', 'el', ' f', 'to', 'in', ' t', 'ou', 'ei', 
+    'ss', 'ir', 'no', 'ri', 'tr', 'me', 'la', 'ia', 'le', 've', 
+    'is', 'sa', 'eu', 'pe', 'a.', 'na', 'so', 'mo', 'ga', 'o.', 
+    'á ', 'lo', 'ha', 'pr', 'ua', ' l', '! ', 'ui', 'am', 'ti', 
+    'io', 'gu', 'i ', 'di', 'nh', ' i', 'id', 
+  ]
+  ESCAPE_CHARACTER = 0x62
+  rom_addrs = [0x9c8000, 0x8edf40]
+  encoder = 'new'
+
+  def __init__(self):
+    assert len(self.alphabet) == 121
+
+class LangEU:
+  command_lengths = kText_CommandLengths_EU
+  command_names = kText_CommandNames_EU
+  COMMAND_START = 0x70
+  SWITCH_BANK = 0x88
+  FINISH = 0x8f
+  DICT_BASE_ENC, DICT_BASE_DEC = 0x88, 0x90
+  ESCAPE_CHARACTER = None
+  encoder = 'new'
+
+class LangDE(LangEU):
+  alphabet = kTextAlphabet_DE
+  dictionary = kTextDictionary_DE
+  rom_addrs = [0x9c8000, 0x8CEB00]
+
+class LangFR(LangEU):
+  alphabet = kTextAlphabet_FR
+  dictionary = kTextDictionary_FR
+  rom_addrs = [0x9c8000, 0x8CE800]
+
+class LangFR_C(LangEU):
+  alphabet = kTextAlphabet_FR
+  dictionary = kTextDictionary_FR
+  rom_addrs = [0x9c8000, 0x8CF150]
+
+kLanguages = {
+  'us' : LangUS(),
+  'de' : LangDE(),
+  'fr' : LangFR(),
+  'fr-c' : LangFR_C(),
+  'en' : LangEN(),
+  'es' : LangES(),
+  'pl' : LangPL(),
+  'pt' : LangPT(),
+  'redux' : LangUS(),
+  'nl' : LangNL(),
+  'sv' : LangSV(),
+}
+
+def dialogue_filename(s):
+  if s == 'us': return 'dialogue.txt'
+  return f"dialogue_{s.replace('-', '_')}.txt"
+
+def uses_new_format(lang): 
+  return kLanguages[lang].encoder == 'new'
+
+dict_expansion = []
+
+def decode_strings_generic(get_byte, lang):
+  info = kLanguages[lang]
+  p, rom_idx = info.rom_addrs[0], 1
+  result = []
+  while True:
+    s, srcdata = '', []
+    while True:
+      c = get_byte(p)
+      srcdata.append(c)
+      l = info.command_lengths[c - info.COMMAND_START] if c >= info.COMMAND_START and c < info.SWITCH_BANK else 1
+
+      p += l
+      if c == 0x7f: # EndMessage
+        break
+      if c < info.COMMAND_START:
+        if c == info.ESCAPE_CHARACTER:
+          c = get_byte(p); p += 1
+          srcdata.append(c)
+        s += info.alphabet[c]
+      elif c < info.SWITCH_BANK:
+        if l == 2:
+          srcdata.append(get_byte(p - 1))
+          s += '[%s %.2d]' % (info.command_names[c - info.COMMAND_START], get_byte(p - 1))
+        else:
+          s += '[%s]' % info.command_names[c - info.COMMAND_START]
+      elif c == info.FINISH:
+        return result # done
+      elif c == info.SWITCH_BANK:
+        p = info.rom_addrs[rom_idx]; rom_idx += 1
+        s, srcdata = '', []
+      elif c < info.SWITCH_BANK + 8:
+        if lang != 'pt':
+          assert 0
+      else:
+        s += info.dictionary[c - info.DICT_BASE_DEC]
+        dict_expansion.append(len(info.dictionary[c - info.DICT_BASE_DEC]))
+    result.append((s, srcdata)) 
+    if len(result) >= 397 and lang == 'pt':
+      return result
+#    print(len(result), s)   
+#    if len(result) == 89:
+#      print(s)
+#      sys.exit(0)
+
+
+  
+def print_strings(rom, file = None):
+  texts = decode_strings_generic(rom.get_byte, rom.language)
+  if len(texts) == 396:
+    extra_str = "[Speed 00]0- [Number 00]. 1- [Number 01][2]2- [Number 02]. 3- [Number 03]"
+    texts = texts[:4] + [(extra_str, None)] + texts[4:]
+
+  for i, s in enumerate(texts):
+    print('%s: %s' % (i + 1, s[0]), file = file)
+
+
+def encode_greedy_from_dict(s, i, rev, a2i, info):
+  a = s[i:]
+  if r := rev.get(a[0]):
+    for k, v in r.items():
+      if a.startswith(k):
+        return [v + info.DICT_BASE_ENC], len(k)
+
+  if a[0] == '[':
+    cmd, param = a[1:a.index(']')], None
+    cmdlen = len(cmd)
+    if r := a2i.get(a[:cmdlen+2]):
+      return [r], cmdlen+2
+    if ' ' in cmd:
+      cmd, param = cmd.split(' ', 1)
+      param = int(param)
+    return kEncoders[info.encoder](cmd, param), cmdlen + 2
+  else:
+    return [a2i[a[0]]], 1
+
+  print('substr %s not found' % a)
+  assert 0
+
+def compress_strings(xs, lang = 'us'):
+  info = kLanguages[lang]
+  rev = {}
+  for a,b in enumerate(info.dictionary):
+    rev.setdefault(b[0], {})[b] = a
+  #rev = {b:a for a,b in enumerate(info.dictionary)}
+  a2i = {e:i for i,e in enumerate(info.alphabet)}
+  def compress_string(s):
+    i = 0
+    r = bytearray()
+    while i < len(s):
+      what, num = encode_greedy_from_dict(s, i, rev, a2i, info)
+      r.extend(what)
+      i += num
+    return r
+  return [compress_string(x) for x in xs]
+  
+def verify(get_byte):
+  for i, (decoded, original) in enumerate(decode_strings_generic(get_byte, 'us')):
+    c = compress_strings([decoded])[0]
+    if c != original:
+      print('String %s not match: %s, %s' % (decoded, c, original))
+      break
+    else:
+      pass
+
+def encode_dictionary(lang = 'us'):
+  info = kLanguages[lang]
+  rev = {b:a for a,b in enumerate(info.alphabet)}
+  return [bytearray(rev[c] for c in line) for line in info.dictionary]
+
+if __name__ == "__main__":
+  ROM = util.load_rom(sys.argv[1] if len(sys.argv) >= 2 else None, True)
+
+  decoded = decode_strings_generic(ROM.get_byte, 'de')
+  print('Total bytes: %d' % sum(len(a[1]) for a in decoded))
+
+  print('Dict tokens: %d' % len(dict_expansion))
+  print('Dict save: %d' % (sum(dict_expansion) - len(dict_expansion)))
+
+  print('US size ', len(kTextDictionary_US))
+  print('DE size ', len(kTextDictionary_DE))
+
+  texts = [a[0] for a in decoded]
+
+
+  # Pal seems to have one string too little
+  if len(texts) == 396:
+    extra_str = "[Speed 00]0- [Number 00]. 1- [Number 01][2]2- [Number 02]. 3- [Number 03]"
+    texts = texts[:4] + [extra_str] + texts[4:]
+
+  #for i, s in enumerate(texts):
+  #  print('%s: %s' % (i + 1, s), file = None)
+
+
+  #encode_dictionary()
+  compr = compress_strings(texts, 'de')
+  print(f'Compressed size (excl eof): {sum(len(a) for a in compr)}')
+
+
--- /dev/null
+++ b/assets/util.py
@@ -1,0 +1,333 @@
+import array
+import sys
+import hashlib
+import os
+from functools import lru_cache
+
+def cache(user_function):
+  'Simple lightweight unbounded cache.  Sometimes called "memoize".'
+  return lru_cache(maxsize=None)(user_function)
+
+# Both are common SNES rom extensions. For Zelda3 (NA), they are equivalent files.
+COMMON_ROM_NAMES = ['zelda3.sfc', 'zelda3.smc']
+DEFAULT_ROM_DIRECTORY = os.path.join(os.path.dirname(__file__), '..')
+
+ZELDA3_SHA1_US = '6D4F10A8B10E10DBE624CB23CF03B88BB8252973'
+ZELDA3_SHA1 = {
+   ZELDA3_SHA1_US : ('us', 'Legend of Zelda, The - A Link to the Past (USA)'),
+  '2E62494967FB0AFDF5DA1635607F9641DF7C6559' : ('de', 'Legend of Zelda, The - A Link to the Past (Germany)'),
+  '229364A1B92A05167CD38609B1AA98F7041987CC' : ('fr', 'Legend of Zelda, The - A Link to the Past (France)'),
+  'C1C6C7F76FFF936C534FF11F87A54162FC0AA100' : ('fr-c', 'Legend of Zelda, The - A Link to the Past (Canada)'),
+  '7C073A222569B9B8E8CA5FCB5DFEC3B5E31DA895' : ('en',  'Legend of Zelda, The - A Link to the Past (Europe)'),
+  '461FCBD700D1332009C0E85A7A136E2A8E4B111E' : ('es',  'Spanish - https://www.romhacking.net/translations/2195/'),
+  '3C4D605EEFDA1D76F101965138F238476655B11D' : ('pl',  'Polish - https://www.romhacking.net/translations/5760/'),
+  'D0D09ED41F9C373FE6AFDCCAFBF0DA8C88D3D90D' : ('pt',  'Portuguese - https://www.romhacking.net/translations/6530/'),
+  'B2A07A59E64C498BC1B2F28728F9BF4014C8D582' : ('redux', 'English Redux - https://www.romhacking.net/translations/6657/'),
+  '9325C22EB0A2A1F0017157C8B620BC3A605CEDE1' : ('redux', 'English Redux - https://www.romhacking.net/hacks/2594/'),
+  'FA8ADFDBA2697C9A54D583A1284A22AC764C7637' : ('nl', 'Dutch - https://www.romhacking.net/translations/1124/'),
+  '43CD3438469B2C3FE879EA2F410B3EF3CB3F1CA4' : ('sv', 'Swedish - https://www.romhacking.net/translations/982/'),
+}
+
+def load_rom(filename, support_multilanguage = False):
+  global ROM
+  ROM = LoadedRom(filename, support_multilanguage)
+  return ROM
+
+def get_byte(addr):
+  return ROM.get_byte(addr)
+
+@cache
+def get_bytes(addr, n):
+  return ROM.get_bytes(addr, n)
+
+@cache
+def get_words(addr, n):
+  return ROM.get_words(addr, n)
+
+def get_int8(ea):
+  b = get_byte(ea)
+  if b & 0x80: b -= 256
+  return b
+
+def get_int16(ea):
+  b = get_word(ea)
+  if b & 0x8000: b -= 65536
+  return b
+
+def get_word(addr):
+  return ROM.get_word(addr)
+
+
+class LoadedRom:
+  def __init__(self, path = None, support_multilanguage = False):
+    rom_path = self.__get_rom_path(path)
+    self.ROM = open(rom_path, 'rb').read()
+
+    # Remove the SMC header?
+    if (len(self.ROM) & 0xfffff) == 0x200:
+      self.ROM = self.ROM[0x200:]
+
+    hash = hashlib.sha1(self.ROM).hexdigest().upper()
+    entry = ZELDA3_SHA1.get(hash)
+    self.language = entry[0] if entry != None else None
+
+    # Workaround for swedish rom with broken size
+    if self.language == 'sv' and len(self.ROM) == 0x10083b:
+      self.ROM = self.ROM[0x200:]
+
+    if support_multilanguage:
+      if self.language == None:
+        msg = f"\n\nROM with hash {hash} not supported.\n\nYou need one of the following ROMs to extract the resources:\n"
+        for k, v in ZELDA3_SHA1.items():
+          msg += '%5s: %s: %s\n' % (v[0], k, v[1])
+        raise Exception(msg)
+      print('Identified ROM as: %s - "%s"' % entry)
+    else:
+      if self.language != 'us':
+        raise Exception(f"\n\nROM with hash {hash} not supported.\n\nExpected {ZELDA3_SHA1_US}.\nPlease verify your ROM is \"Legend of Zelda, The - A Link to the Past (USA)\"");
+
+  def get_byte(self, ea):
+    assert (ea & 0x8000)
+    ea = ((ea >> 16) & 0x7f) * 0x8000 + (ea & 0x7fff)
+    return self.ROM[ea]
+
+  def get_word(self, ea):
+    return self.get_byte(ea) + self.get_byte(ea + 1) * 256
+
+  def get_24(self, ea):
+    return self.get_byte(ea) + self.get_byte(ea + 1) * 256 + self.get_byte(ea + 2) * 65536
+
+  def get_bytes(self, addr, n):
+    r = bytearray()
+    for i in range(n):
+      r.append(self.get_byte(addr))
+      addr += 1
+      if (addr & 0x8000) == 0:
+        addr += 0x8000
+    return r
+
+  def get_words(self, addr, n):
+    r = []
+    for i in range(n):
+      r.append(self.get_word(addr))
+      addr += 2
+      if (addr & 0x8000) == 0:
+        addr += 0x8000
+    return r
+
+  def __get_rom_path(self, path = None):
+    # Check default locations when no path is given by user.
+    if path is None:
+      for rom_name in COMMON_ROM_NAMES:
+        rom_path = os.path.join(DEFAULT_ROM_DIRECTORY, rom_name)
+        if os.path.isfile(rom_path):
+          return rom_path
+      raise Exception(f"Could not find any ROMs ({', '.join(COMMON_ROM_NAMES)}) at the default location {DEFAULT_ROM_DIRECTORY}.") 
+
+    rom_path = os.path.join(DEFAULT_ROM_DIRECTORY, path)
+    if os.path.isfile(rom_path):
+      return rom_path
+    raise Exception(f"No ROM found at provided path {rom_path}.")
+
+
+
+def split_list(l, n):
+  return [l[i:i+n] for i in range(0, len(l), n)]
+
+def to_hex(v):
+  return '%#x' % v if v < -9 or v >9 else '%d'%v
+
+
+def print_int_array(name, r, tname, decimal, split_length = 16, file = sys.stdout):
+  rlen = len(r)
+  rr = split_list(r, split_length )
+  if decimal != None:
+    if decimal:
+      rr = [['%d' % s for s in t] for t in rr]
+    else:
+      rr = [[to_hex(s) for s in t] for t in rr]
+
+  def pad_all_columns(rrs):
+    colsiz = [max((0 if j >= len(r) else len(r[j])) for r in rrs) for j in range(len(rrs[0]))]
+    def pad(c, i):
+      return (' ' * (i - len(c))) + c
+    return [[pad(c, colsiz[i]) for (i, c) in enumerate(r)] for r in rrs]
+
+  if len(rr) == 1:
+    print('static const %s %s[%d] = {%s};' % (tname, name, rlen, ", ".join(rr[0])), file = file)
+  else:
+    print('static const %s %s[%d] = {' % (tname, name, rlen), file = file)
+    for t in pad_all_columns(rr):
+      print("  " + "".join([(a + ', ') for a in t]), file = file)
+    print('};', file = file)
+
+
+
+class Reader:
+  def __init__(self, ea, rb):
+    self.ea, self.rb = ea, rb
+  def next(self):
+    r = self.rb(self.ea)
+    self.ea += 1
+    if (self.ea & 0xffff) == 0:
+      self.ea += 0x8000
+    return r
+
+def decomp(ea, rb, offset_is_be = True, return_length = False):
+  result = bytearray()
+  reader = Reader(ea, rb)
+  while True:
+    b = reader.next()
+    if b == 0xff:
+      if return_length:
+        return result, (reader.ea - ea) & 0x7fff
+      else:
+        return result
+    if (b & 0xe0) != 0xe0:
+      lx = b & 0x1f
+      cmd = b & 0xe0
+    else:
+      cmd = (b << 3) & 0xe0
+      lx = ((b & 3) << 8) | reader.next()
+    lx += 1
+    if cmd == 0x00: # 000 - literal
+#      print('literal %d' % lx)
+      while lx:
+        result.append(reader.next())
+        lx -= 1
+    elif cmd & 0x80: # 1xx - copy
+#      print('copy %d' % lx)
+      offs = reader.next() << 8
+      offs |= reader.next()
+      if not offset_is_be: offs = ((offs >> 8) | (offs << 8)) & 0xffff
+      while lx:
+        result.append(result[offs])
+        offs += 1
+        lx -= 1
+    elif (cmd & 0x40) == 0: # 00x - memset
+#      print('memset %d' % lx)
+      b = reader.next()
+      while lx:
+        result.append(b)
+        lx -= 1
+    elif (cmd & 0x20) == 0: # 010 - memset16
+#      print('memsetw %d' % lx)
+      b1, b2 = reader.next(), reader.next()
+      while lx:
+        result.append(b1)
+        if lx==1: break
+        result.append(b2)
+        lx -= 2
+    else: # 011 - incr
+#      print('incr %d' % lx)
+      b = reader.next()
+      while lx:
+        result.append(b)
+        b = (b + 1) & 0xff
+        lx -= 1
+
+
+def decode_brr(get_byte, olds = (0, 0)):
+  ea=0
+  r = []
+  old , older = olds
+  while True:
+    cmd = get_byte(ea)
+    
+    shift = cmd >> 4
+    filter = (cmd >> 2) & 3
+    #print("shift=%d, filter=%d" % (shift, filter))
+    for i in range(16):
+      t = (get_byte(ea+1+i//2) >> (0 if i & 1 else 4)) & 0xf
+      s = (t & 7) - (t & 8)
+      if shift <= 12:
+        s = ((s << shift) >> 1)
+      else:
+        s = (s >> 3) << 12 # -2048 or 0
+
+      if filter == 1:
+        s += old*1+((-old*1) >> 4)
+      elif filter == 2:
+        s += old*2 + ((-old*3) >> 5)  - older + ((older*1) >> 4)
+      elif filter == 3:
+        s += old*2 + ((-old*13) >> 6) - older + ((older*3) >> 4)
+      # saturate to 16 bits
+      if s < -0x8000: s = -0x8000
+      elif s >= 0x7fff: s = 0x7fff
+      # wrap to 15 bits
+      s = (s & 0x3fff) - (s & 0x4000)
+
+      older, old = old, s
+      #print('%d: 0x%x -> %d (shift %d, filter %d)' % (i, t, s*2, shift, filter))
+      r.append(s*2)
+    ea += 9
+    if cmd & 1:
+      break
+  return array.array('h', r)
+
+kBrrFilters = [
+  lambda old, older: 0,
+  lambda old, older: old*1+((-old*1) >> 4),
+  lambda old, older: old*2 + ((-old*3) >> 5)  - older + ((older*1) >> 4),
+  lambda old, older: old*2 + ((-old*13) >> 6) - older + ((older*3) >> 4)
+]
+
+def brr_get_one(old, rs, r):
+  s = (rs << r) >> 1 if r <= 12 else (rs >> 3) << 12
+  s += old
+  s = -0x8000 if s < -0x8000 else 0x7fff if s > 0x7fff else s
+  return (s & 0x3fff) - (s & 0x4000) # wrap to 15 bits
+
+def encode_brr_generic(data, brr_repeat, olds = (0, 0), lossless=True):  
+  assert len(data) % 16 == 0
+  loop_enabled, loop_offset = 1 if brr_repeat != 0 else 0, 0
+  result = []
+  blk_data = [0] * 16
+  best_data = [0] * 9
+  p = 0
+  best_old, best_older = olds
+  while p < len(data):
+#    print(p)
+    best_err = 1 << 60
+    startold, startolder = best_old, best_older
+
+    if all(data[p + i] == 0 for i in range(16)):
+      result.extend((loop_enabled * 2, 0, 0, 0, 0, 0, 0, 0, 0))
+      p += 16
+      continue
+    for filter in range(4):
+      if filter != 0 and (p == 0 or p == loop_offset):
+        continue
+      for r in range(12, 0, -1):
+        blk_err = 0
+        old, older = startold, startolder
+        for i in range(16):
+          s = kBrrFilters[filter](old, older)
+          xs = data[p + i] >> 1 
+          best_e = 1<<60
+          for j in (0, 1, -1, 2, -2, 3, -3, 4, -4, 5, -5, 6, -6, 7, -7, -8):
+            s0 = brr_get_one(s, j, r)
+            e = (xs - s0) * (xs - s0)
+            if e < best_e:
+              best_e, best_j, best_s0 = e, j, s0
+              if e == 0:
+                #print(j)
+                break
+          if best_e != 0 and lossless:
+            break
+          blk_err += best_e
+          blk_data[i] = best_j & 0xf
+          older, old = old, best_s0
+        else:
+          if blk_err < best_err:
+            best_err = blk_err
+            best_old, best_older = old, older
+            best_data[0] = r << 4 | filter << 2 | loop_enabled << 1
+            for i in range(8):
+              best_data[i + 1] = blk_data[i * 2] << 4 | blk_data[i * 2 + 1]
+    result.extend(best_data)
+    if lossless: assert best_err==0
+    p += 16
+#  result[-9] |= 1
+  return result
+
--- a/attract.c
+++ /dev/null
@@ -1,1063 +1,0 @@
-#include "zelda_rtl.h"
-#include "variables.h"
-#include "snes/snes_regs.h"
-#include "load_gfx.h"
-#include "dungeon.h"
-#include "sprite.h"
-#include "ending.h"
-#include "messaging.h"
-#include "attract.h"
-#include "sprite_main.h"
-
-const uint16 kMapMode_Zooms1[240] = {
-  375, 374, 373, 373, 372, 371, 371, 370, 369, 369, 368, 367, 367, 366, 365, 365,
-  364, 363, 363, 361, 361, 360, 359, 359, 358, 357, 357, 356, 355, 355, 354, 354,
-  353, 352, 352, 351, 351, 350, 349, 349, 348, 348, 347, 346, 346, 345, 345, 344,
-  343, 343, 342, 342, 341, 341, 340, 339, 339, 338, 338, 337, 337, 336, 335, 335,
-  334, 334, 333, 333, 332, 332, 331, 331, 330, 330, 328, 327, 327, 326, 326, 325,
-  325, 324, 324, 323, 323, 322, 322, 321, 321, 320, 320, 319, 319, 318, 318, 317,
-  317, 316, 316, 315, 315, 314, 314, 313, 313, 312, 312, 311, 311, 310, 310, 309,
-  309, 309, 308, 308, 307, 307, 306, 306, 305, 305, 304, 304, 303, 303, 303, 302,
-  302, 301, 301, 300, 300, 299, 299, 299, 298, 298, 297, 297, 295, 295, 294, 294,
-  294, 293, 293, 292, 292, 292, 291, 291, 290, 290, 289, 289, 289, 288, 288, 287,
-  287, 287, 286, 286, 285, 285, 285, 284, 284, 283, 283, 283, 282, 282, 281, 281,
-  281, 280, 280, 279, 279, 279, 278, 278, 278, 277, 277, 276, 276, 276, 275, 275,
-  275, 274, 274, 273, 273, 273, 272, 272, 272, 271, 271, 271, 270, 270, 269, 269,
-  269, 268, 268, 268, 267, 267, 267, 266, 266, 266, 265, 265, 265, 264, 264, 264,
-  263, 263, 262, 262, 262, 261, 261, 261, 260, 260, 260, 259, 259, 259, 258, 258,
-};
-const uint16 kMapMode_Zooms2[240] = {
-  136, 136, 135, 135, 135, 135, 135, 134, 134, 134, 133, 133, 133, 133, 132, 132,
-  132, 132, 132, 131, 131, 131, 130, 130, 130, 130, 130, 129, 129, 129, 129, 129,
-  128, 128, 128, 127, 127, 127, 127, 127, 126, 126, 126, 126, 126, 125, 125, 125,
-  124, 124, 124, 124, 124, 124, 123, 123, 123, 123, 123, 122, 122, 122, 121, 121,
-  121, 121, 121, 121, 120, 120, 120, 120, 120, 120, 119, 119, 119, 118, 118, 118,
-  118, 118, 118, 117, 117, 117, 117, 117, 117, 116, 116, 116, 116, 115, 115, 115,
-  115, 115, 115, 114, 114, 114, 114, 114, 114, 113, 113, 113, 113, 112, 112, 112,
-  112, 112, 112, 112, 111, 111, 111, 111, 111, 111, 110, 110, 110, 110, 110, 109,
-  109, 109, 109, 109, 109, 108, 108, 108, 108, 108, 108, 108, 107, 107, 107, 107,
-  107, 106, 106, 106, 106, 106, 106, 106, 105, 105, 105, 105, 105, 105, 105, 104,
-  104, 104, 104, 104, 103, 103, 103, 103, 103, 103, 103, 103, 102, 102, 102, 102,
-  102, 102, 102, 101, 101, 101, 101, 101, 101, 100, 100, 100, 100, 100, 100, 100,
-  100,  99,  99,  99,  99,  99,  99,  99,  99,  98,  98,  98,  98,  98,  97,  97,
-  97,  97,  97,  97,  97,  97,  97,  96,  96,  96,  96,  96,  96,  96,  96,  96,
-  95, 95, 95, 95, 95, 95, 95, 94, 94, 94, 94, 94, 94, 94, 94, 94,
-};
-static const uint8 kAttract_Legendgraphics_0[157+1] = {
-  0x61, 0x65, 0x40, 0x28,    0, 0x35, 0x61, 0x85, 0x40, 0x28, 0x10, 0x35, 0x61, 0xa5,    0, 0x29,
-     1, 0x35,    2, 0x35,    1, 0x35,    2, 0x35,    1, 0x35,    2, 0x35,    1, 0x35,    2, 0x35,
-     1, 0x35,    3, 0x31,    3, 0x71,    2, 0x35,    1, 0x35,    2, 0x35,    1, 0x35,    2, 0x35,
-     1, 0x35,    2, 0x35,    1, 0x35,    2, 0x35,    1, 0x35, 0x61, 0xc5,    0, 0x29, 0x11, 0x35,
-  0x12, 0x35, 0x11, 0x35, 0x12, 0x35, 0x11, 0x35, 0x12, 0x35, 0x11, 0x35, 0x12, 0x35, 0x11, 0x35,
-  0x13, 0x35, 0x13, 0x75, 0x12, 0x35, 0x11, 0x35, 0x12, 0x35, 0x11, 0x35, 0x12, 0x35, 0x11, 0x35,
-  0x12, 0x35, 0x11, 0x35, 0x12, 0x35, 0x11, 0x35, 0x61, 0xe5,    0, 0x29, 0x20, 0x35, 0x21, 0x35,
-  0x20, 0x35, 0x21, 0x35, 0x20, 0x35, 0x21, 0x35, 0x20, 0x35, 0x21, 0x35, 0x20, 0x35, 0x21, 0x35,
-  0x20, 0x35, 0x21, 0x35, 0x20, 0x35, 0x21, 0x35, 0x20, 0x35, 0x21, 0x35, 0x20, 0x35, 0x21, 0x35,
-  0x20, 0x35, 0x21, 0x35, 0x20, 0x35, 0x62,    5, 0x40, 0x28,    0, 0xb5, 0xff, 0x61,
-};
-static const uint8 kAttract_Legendgraphics_1[237+1] = {
-  0x61, 0x65, 0x40, 0x28,    0, 0x35, 0x61, 0x85,    0, 0x13, 0x10, 0x35, 0x4e, 0x75, 0x6e, 0x35,
-  0x10, 0x35, 0x4e, 0x35, 0x10, 0x35, 0x4c, 0x35, 0x10, 0x35, 0x4e, 0x75, 0x49, 0x35, 0x61, 0x8f,
-  0x40,    8, 0x10, 0x35, 0x61, 0x94,    0,  0xb, 0x4e, 0x75, 0x6e, 0x35, 0x10, 0x35, 0x4e, 0x35,
-  0x10, 0x35, 0x4c, 0x35, 0x61, 0xa5,    0, 0x29, 0x5f, 0x75, 0x5e, 0x75, 0x7e, 0x35, 0x7f, 0x35,
-  0x5e, 0x35, 0x5f, 0x35, 0x4d, 0x35, 0x5f, 0x75, 0x5e, 0x75, 0x4a, 0x35, 0x4b, 0x35, 0x10, 0x35,
-  0x49, 0x75, 0x10, 0x35, 0x5f, 0x75, 0x5e, 0x75, 0x7e, 0x35, 0x7f, 0x35, 0x5e, 0x35, 0x5f, 0x35,
-  0x4d, 0x35, 0x61, 0xc5,    0, 0x29, 0x50, 0x35, 0x51, 0x35, 0x52, 0x35, 0x53, 0x35, 0x54, 0x35,
-  0x55, 0x35, 0x56, 0x35, 0x57, 0x35, 0x58, 0x35, 0x59, 0x35, 0x5a, 0x35, 0x5b, 0x35, 0x5c, 0x35,
-  0x5d, 0x35, 0x50, 0x35, 0x51, 0x35, 0x52, 0x35, 0x53, 0x35, 0x54, 0x35, 0x55, 0x35, 0x56, 0x35,
-  0x61, 0xe5,    0, 0x29, 0x60, 0x35, 0x61, 0x35, 0x62, 0x35, 0x63, 0x35, 0x64, 0x35, 0x65, 0x35,
-  0x66, 0x35, 0x67, 0x35, 0x68, 0x35, 0x69, 0x35, 0x6a, 0x35, 0x6b, 0x35, 0x6c, 0x35, 0x6d, 0x35,
-  0x60, 0x35, 0x61, 0x35, 0x62, 0x35, 0x63, 0x35, 0x64, 0x35, 0x65, 0x35, 0x66, 0x35, 0x62,    5,
-     0, 0x29, 0x70, 0x35, 0x71, 0x35, 0x72, 0x35, 0x73, 0x35, 0x74, 0x35, 0x75, 0x35, 0x76, 0x35,
-  0x77, 0x35, 0x78, 0x35, 0x79, 0x35, 0x7a, 0x35, 0x7b, 0x35, 0x7c, 0x35, 0x7d, 0x35, 0x70, 0x35,
-  0x71, 0x35, 0x72, 0x35, 0x73, 0x35, 0x74, 0x35, 0x75, 0x35, 0x76, 0x35, 0xff, 0x61,
-};
-static const uint8 kAttract_Legendgraphics_2[199+1] = {
-  0x61, 0x65, 0x40, 0x28,    0, 0x35, 0x61, 0x85, 0x40, 0x28, 0x10, 0x35, 0x61, 0xa5,    0, 0x1d,
-  0x22, 0x35, 0x23, 0x35, 0x10, 0x35, 0x22, 0x35, 0x23, 0x35, 0x10, 0x35, 0x22, 0x35, 0x23, 0x35,
-  0x10, 0x35, 0x22, 0x35, 0x23, 0x35, 0x10, 0x35, 0x10, 0x75, 0x23, 0x75, 0x22, 0x75, 0x61, 0xb4,
-  0x40,    6, 0x10, 0x35, 0x61, 0xb8,    0,    3, 0x23, 0x75, 0x22, 0x75, 0x61, 0xc5,    0, 0x29,
-     4, 0x35,    5, 0x35,    6, 0x35,    4, 0x35,    5, 0x35,    6, 0x35,    4, 0x35,    5, 0x35,
-     6, 0x35,    4, 0x35,    5, 0x35,    6, 0x35,    6, 0x75,    5, 0x75,    4, 0x75, 0x10, 0x75,
-  0x23, 0x75, 0x22, 0x75,    6, 0x75,    5, 0x75,    4, 0x75, 0x61, 0xe5,    0, 0x29, 0x14, 0x35,
-  0x15, 0x35, 0x16, 0x35, 0x14, 0x35, 0x15, 0x35, 0x16, 0x35, 0x14, 0x35, 0x15, 0x35, 0x16, 0x35,
-  0x14, 0x35, 0x15, 0x35, 0x16, 0x35, 0x16, 0x75, 0x15, 0x75, 0x14, 0x75,    6, 0x75,    5, 0x75,
-     4, 0x75, 0x16, 0x75, 0x15, 0x75, 0x14, 0x75, 0x62,    5,    0, 0x29, 0x24, 0x35, 0x25, 0x35,
-  0x26, 0x35, 0x24, 0x35, 0x25, 0x35, 0x26, 0x35, 0x24, 0x35, 0x25, 0x35, 0x26, 0x35, 0x24, 0x35,
-  0x25, 0x35, 0x26, 0x35, 0x26, 0x75, 0x25, 0x75, 0x24, 0x75, 0x26, 0x75, 0x25, 0x75, 0x24, 0x75,
-  0x26, 0x75, 0x25, 0x75, 0x24, 0x75, 0xff, 0x61,
-};
-static const uint8 kAttract_Legendgraphics_3[265+1] = {
-  0x61, 0x65,    0, 0x29,    0, 0x35,    0, 0x35, 0x1b, 0x35, 0x30, 0x35, 0x31, 0x35, 0x32, 0x35,
-     0, 0x35,    0, 0x35,    0, 0x35, 0x33, 0x35, 0x41, 0x35, 0x41, 0x75, 0x33, 0x75,    0, 0x75,
-     0, 0x75,    0, 0x75, 0x32, 0x75, 0x31, 0x75, 0x30, 0x75, 0x1b, 0x75,    0, 0x75, 0x61, 0x85,
-  0x40, 0x1e, 0x10, 0x35, 0x61, 0x86,    0,    9, 0x34, 0x35,  0xb, 0x35, 0x40, 0x35, 0x41, 0x35,
-  0x42, 0x35, 0x61, 0x95,    0,    9, 0x42, 0x75, 0x41, 0x75, 0x40, 0x75,  0xb, 0x75, 0x34, 0x75,
-  0x61, 0xa5,    0, 0x29, 0x43, 0x35, 0x44, 0x35,    7, 0x35,    8, 0x35,    9, 0x35,  0xa, 0x35,
-  0x10, 0x35,  0xc, 0x35,  0xd, 0x35,  0xe, 0x35,  0xf, 0x35,  0xf, 0x75,  0xe, 0x75,  0xd, 0x75,
-   0xc, 0x75, 0x10, 0x75,  0xa, 0x75,    9, 0x75,    8, 0x75,    7, 0x75, 0x44, 0x75, 0x61, 0xc5,
-     0, 0x29, 0x35, 0x35, 0x36, 0x35, 0x17, 0x35, 0x18, 0x35, 0x19, 0x35, 0x1a, 0x35, 0x10, 0x35,
-  0x1c, 0x35, 0x1d, 0x35, 0x1e, 0x35, 0x1f, 0x35, 0x1f, 0x75, 0x1e, 0x75, 0x1d, 0x75, 0x1c, 0x75,
-  0x10, 0x75, 0x1a, 0x75, 0x19, 0x75, 0x18, 0x75, 0x17, 0x75, 0x36, 0x75, 0x61, 0xe5,    0, 0x29,
-  0x45, 0x35, 0x46, 0x35, 0x27, 0x35, 0x28, 0x35, 0x29, 0x35, 0x2a, 0x35, 0x2b, 0x35, 0x2c, 0x35,
-  0x2d, 0x35, 0x2e, 0x35, 0x2f, 0x35, 0x2f, 0x75, 0x2e, 0x75, 0x2d, 0x75, 0x2c, 0x75, 0x2b, 0x75,
-  0x2a, 0x75, 0x29, 0x75, 0x28, 0x75, 0x27, 0x75, 0x46, 0x75, 0x62,    5,    0, 0x29, 0x47, 0x35,
-  0x48, 0x35, 0x37, 0x35, 0x38, 0x35, 0x39, 0x35, 0x3a, 0x35, 0x3b, 0x35, 0x3c, 0x35, 0x3d, 0x35,
-  0x3e, 0x35, 0x3f, 0x35, 0x3f, 0x75, 0x3e, 0x75, 0x3d, 0x75, 0x3c, 0x75, 0x3b, 0x75, 0x3a, 0x75,
-  0x39, 0x75, 0x38, 0x75, 0x37, 0x75, 0x48, 0x75, 0xff, 0x0
-};
-void Attract_DrawSpriteSet2(const AttractOamInfo *p, int n) {
-  OamEnt *oam = &oam_buf[attract_oam_idx + 64];
-  attract_oam_idx += n;
-  for (; n--; oam++)
-    SetOamPlain(oam, attract_x_base + p[n].x, attract_y_base + p[n].y, p[n].c, p[n].f, p[n].e);
-}
-
-void Attract_ZeldaPrison_Case0() {
-  static const AttractOamInfo kZeldaPrison_Oams0[] = {
-    { 5, 25, 0x6c, 0x38, 2},
-    {11, 25, 0x6c, 0x38, 2},
-    { 0,  0, 0x84, 0x3b, 2},
-    {16,  0, 0x84, 0x7b, 2},
-    { 0, 16, 0xa4, 0x3b, 2},
-    {16, 16, 0xa4, 0x7b, 2},
-  };
-  if (!attract_var4)
-    attract_var5++;
-  if (frame_counter & 1)
-    attract_vram_dst--;
-  attract_x_base = 0x58;
-  attract_y_base = attract_var9;
-  Attract_DrawSpriteSet2(kZeldaPrison_Oams0, 6);
-  attract_var7 = 0xf8d9;
-}
-
-void Attract_ZeldaPrison_Case1() {
-  int k;
-  static const AttractOamInfo kZeldaPrison_Oams1[] = {
-    { 5, 25, 0x6c, 0x38, 2},
-    {11, 25, 0x6c, 0x38, 2},
-    { 0,  0, 0x84, 0x3b, 2},
-    {16,  0, 0x84, 0x7b, 2},
-    { 0, 16, 0xa4, 0x3b, 2},
-    {16, 16, 0xa4, 0x7b, 2},
-
-    { 5, 25, 0x6c, 0x38, 2},
-    {11, 25, 0x6c, 0x38, 2},
-    { 0,  0, 0xc4, 0x3b, 2},
-    {16,  0, 0xc2, 0x3b, 2},
-    { 0, 16, 0xe4, 0x3b, 2},
-    {16, 16, 0xe6, 0x3b, 2},
-
-    { 5, 25, 0x6c, 0x38, 2},
-    {11, 25, 0x6c, 0x38, 2},
-    { 0,  0, 0x88, 0x3b, 2},
-    {16,  0, 0x8a, 0x3b, 2},
-    { 0, 16, 0xa8, 0x3b, 2},
-    {16, 16, 0xaa, 0x3b, 2},
-
-    { 5, 25, 0x6c, 0x38, 2},
-    {11, 25, 0x6c, 0x38, 2},
-    { 0,  0, 0x82, 0x3b, 2},
-    {16,  0, 0x82, 0x7b, 2},
-    { 0, 16, 0xa2, 0x3b, 2},
-    {16, 16, 0xa2, 0x7b, 2},
-
-    { 5, 25, 0x6c, 0x38, 2},
-    {11, 25, 0x6c, 0x38, 2},
-    { 0,  0, 0x80, 0x3b, 2},
-    {16,  0, 0x80, 0x7b, 2},
-    { 0, 16, 0xa0, 0x3b, 2},
-    {16, 16, 0xa0, 0x7b, 2},
-  };
-  if (attract_var10 < 0x80 && (Attract_ShowTimedTextMessage(), oam_priority_value != 0)) {
-    k = 4;
-  } else if (attract_var9 != 0x6e) {
-    attract_var9--;
-    k = 0;
-  } else {
-    if (attract_var10 < 31 && !(attract_var10 & 1))
-      INIDISP_copy--;
-    if (!--attract_var10) {
-      attract_sequence++;
-      attract_state -= 2;
-      return;
-    }
-
-    k = attract_var10 >= 0xc0 ? 0 :
-      attract_var10 >= 0xb8 ? 1 :
-      attract_var10 >= 0xb0 ? 2 :
-      attract_var10 >= 0xa0 ? 3 : 4;
-  }
-  if (frame_counter & 1)
-    attract_vram_dst--;
-  attract_x_base = 0x58;
-  attract_y_base = attract_var9;
-  Attract_DrawSpriteSet2(&kZeldaPrison_Oams1[k * 6], 6);
-}
-
-void Attract_ZeldaPrison_DrawA() {
-  OamEnt *oam = &oam_buf[64 + attract_oam_idx];
-  uint8 ext = attract_x_base_hi ? 3 : 2;
-  int j = (attract_var1 >> 3) & 1;
-  SetOamPlain(oam + 0, attract_x_base, attract_y_base + j, 6, 0x3d, ext);
-  SetOamPlain(oam + 1, attract_x_base, attract_y_base + 10, j ? 10 : 8, 0x3d, ext);
-  attract_oam_idx += 2;
-}
-
-void Attract_MaidenWarp_Case0() {
-  if (attract_var11)
-    attract_var5++;
-}
-
-void Attract_MaidenWarp_Case1() {
-  static const AttractOamInfo kZeldaPrison_MaidenWarpCase1_Oam[] = {
-    { 0,  0, 0xce, 0x35, 0},
-    {28,  0, 0xce, 0x35, 0},
-    {-2,  3, 0x26, 0x75, 0},
-    {30,  3, 0x26, 0x35, 0},
-    {-2, 11, 0x36, 0x75, 0},
-    {30, 11, 0x36, 0x35, 0},
-    { 0, 16, 0x26, 0x75, 0},
-    {28, 16, 0x26, 0x35, 0},
-    { 0, 24, 0x36, 0x75, 0},
-    {28, 24, 0x36, 0x35, 0},
-    { 2, 16, 0x20, 0x35, 2},
-    {18, 16, 0x20, 0x75, 2},
-    { 2, 32, 0x20, 0xb5, 2},
-    {18, 32, 0x20, 0xf5, 2},
-    { 0,  0, 0xce, 0x37, 0},
-    {28,  0, 0xce, 0x37, 0},
-    {-2,  3, 0x26, 0x77, 0},
-    {30,  3, 0x26, 0x37, 0},
-    {-2, 11, 0x36, 0x77, 0},
-    {30, 11, 0x36, 0x37, 0},
-    { 0, 16, 0x26, 0x77, 0},
-    {28, 16, 0x26, 0x37, 0},
-    { 0, 24, 0x36, 0x77, 0},
-    {28, 24, 0x36, 0x37, 0},
-    { 2, 16, 0x22, 0x37, 2},
-    {18, 16, 0x22, 0x77, 2},
-    { 2, 32, 0x22, 0xb7, 2},
-    {18, 32, 0x22, 0xf7, 2},
-  };
-  int k = frame_counter >> 2 & 1;
-  static const uint8 kAttract_MaidenWarp_Case1_Num[8] = { 2, 2, 2, 6, 6, 10, 10, 14 };
-  attract_x_base = 110;
-  attract_y_base = 72;
-  Attract_DrawSpriteSet2(kZeldaPrison_MaidenWarpCase1_Oam + k * 14, kAttract_MaidenWarp_Case1_Num[attract_var21 >> 1 & 7]);
-
-  if (!attract_var21 && attract_var20 == 0x70)
-    sound_effect_2 = 0x27;
-
-  if (attract_var21 == 15) {
-    attract_var5++;
-  } else {
-    if (attract_var21 == 6) {
-      intro_times_pal_flash = 0x90;
-      sound_effect_2 = 0x2b;
-    }
-    if (attract_var20)
-      attract_var20--;
-    else
-      attract_var21++;
-  }
-}
-
-void Attract_MaidenWarp_Case2() {
-  static const uint8 kMaidenWarp_Case2_Num[8] = { 4, 4, 8, 8, 12, 12, 14, 14 };
-  static const AttractOamInfo kAttract_MaidenWarpCase2_Oam[] = {
-    { 0,  0, 0xce, 0x35, 0},
-    {28,  0, 0xce, 0x35, 0},
-    {-2,  3, 0x26, 0x75, 0},
-    {30,  3, 0x26, 0x35, 0},
-    {-2, 11, 0x36, 0x75, 0},
-    {30, 11, 0x36, 0x35, 0},
-    { 0, 16, 0x26, 0x75, 0},
-    {28, 16, 0x26, 0x35, 0},
-    { 0, 24, 0x36, 0x75, 0},
-    {28, 24, 0x36, 0x35, 0},
-    { 2, 16, 0x20, 0x35, 2},
-    {18, 16, 0x20, 0x75, 2},
-    { 2, 32, 0x20, 0xb5, 2},
-    {18, 32, 0x20, 0xf5, 2},
-    { 0,  0, 0xce, 0x37, 0},
-    {28,  0, 0xce, 0x37, 0},
-    {-2,  3, 0x26, 0x77, 0},
-    {30,  3, 0x26, 0x37, 0},
-    {-2, 11, 0x36, 0x77, 0},
-    {30, 11, 0x36, 0x37, 0},
-    { 0, 16, 0x26, 0x77, 0},
-    {28, 16, 0x26, 0x37, 0},
-    { 0, 24, 0x36, 0x77, 0},
-    {28, 24, 0x36, 0x37, 0},
-    { 2, 16, 0x22, 0x37, 2},
-    {18, 16, 0x22, 0x77, 2},
-    { 2, 32, 0x22, 0xb7, 2},
-    {18, 32, 0x22, 0xf7, 2},
-  };
-  attract_x_base = 110;
-  attract_y_base = 72;
-  int k = frame_counter >> 2 & 1;
-  int n = kMaidenWarp_Case2_Num[attract_var21 >> 1 & 7];
-  Attract_DrawSpriteSet2(kAttract_MaidenWarpCase2_Oam + k * 14 + (14 - n), n);
-  if (attract_var21 == 0) {
-    if (!--attract_var19)
-      attract_var5++;
-  } else {
-    attract_var21--;
-  }
-}
-
-void Attract_MaidenWarp_Case3() {
-  static const AttractOamInfo kAttract_MaidenWarpCase3_Oam[] = {
-    { 0,  0, 0xc6, 0x3d, 2},
-    { 0,  0, 0x24, 0x35, 2},
-    {16,  0, 0x24, 0x75, 2},
-  };
-  static const uint8 kMaidenWarp_Case3_Xbase[2] = { 0x78, 0x70 };
-
-  if (attract_var21 == 6) {
-    attract_var15++;
-    sound_effect_1 = 51;
-  } else if (attract_var21 == 0x40) {
-    attract_var21 = 224;
-    attract_var5++;
-  } else if (attract_var21 < 0xf) {
-    int k = attract_var21 >> 3 & 1;
-    attract_x_base = kMaidenWarp_Case3_Xbase[k];
-    attract_y_base = 0x60;
-    Attract_DrawSpriteSet2(kAttract_MaidenWarpCase3_Oam + k, k ? 2 : 1);
-  }
-  attract_var21++;
-}
-
-void Attract_MaidenWarp_Case4() {
-  Attract_ShowTimedTextMessage();
-  if (!oam_priority_value) {
-    if (attract_var21 < 31 && !(attract_var21 & 1)) {
-      INIDISP_copy--;
-    }
-    if (!--attract_var21)
-      attract_var22++;
-  }
-}
-
-void Dungeon_LoadAndDrawEntranceRoom(uint8 a) {  // 82c533
-  attract_room_index = a;
-  Dungeon_LoadEntrance();
-  dung_num_lit_torches = 0;
-  hdr_dungeon_dark_with_lantern = 0;
-  Dungeon_LoadAndDrawRoom();
-  Dungeon_ResetTorchBackgroundAndPlayer();
-}
-
-void Dungeon_SaveAndLoadLoadAllPalettes(uint8 a, uint8 k) {  // 82c546
-  sprite_graphics_index = k;
-  main_tile_theme_index = a;
-  aux_tile_theme_index = a;
-  InitializeTilesets();
-  overworld_palette_aux_or_main = 0x200;
-  flag_update_cgram_in_nmi++;
-  Palette_BgAndFixedColor_Black();
-  Palette_Load_Sp0L();
-  Palette_Load_SpriteMain();
-  Palette_Load_Sp5L();
-  Palette_Load_Sp6L();
-  Palette_Load_SpriteEnvironment_Dungeon();
-  Palette_Load_HUD();
-  Palette_Load_DungeonSet();
-}
-
-void Module14_Attract() {  // 8cedad
-  uint8 st = attract_state;
-  if (INIDISP_copy && INIDISP_copy != 128 && st && st != 2 && st != 6 && filtered_joypad_H & 0x90)
-    attract_state = st = 9;
-
-  switch (st) {
-  case 0: Attract_Fade(); break;
-  case 1: Attract_InitGraphics(); break;
-  case 2: Attract_FadeOutSequence(); break;
-  case 3: Attract_LoadNewScene(); break;
-  case 4: Attract_FadeInSequence(); break;
-  case 5: Attract_EnactStory(); break;
-  case 6: Attract_FadeOutSequence(); break;
-  case 7: Attract_LoadNewScene(); break;
-  case 8: Attract_EnactStory(); break;
-  case 9: Attract_SkipToFileSelect(); break;
-  }
-}
-
-void Attract_Fade() {  // 8cede6
-  Intro_HandleAllTriforceAnimations();
-  intro_did_run_step = 0;
-  is_nmi_thread_active = 0;
-  Intro_PeriodicSwordAndIntroFlash();
-  if (INIDISP_copy) {
-    INIDISP_copy--;
-    return;
-  }
-  EnableForceBlank();
-  irq_flag = 255;
-  is_nmi_thread_active = 0;
-  nmi_flag_update_polyhedral = 0;
-  attract_state++;
-}
-
-void Attract_InitGraphics() {  // 8cee0c
-  memset(&attract_var12, 0, 0x51);
-  EraseTileMaps_normal();
-  Attract_LoadBG3GFX();
-  overworld_palette_mode = 4;
-  hud_palette = 1;
-  overworld_palette_aux_or_main = 0;
-  Palette_Load_HUD();
-  overworld_palette_aux_or_main = 0x200;
-  Palette_Load_OWBGMain();
-  Palette_Load_HUD();
-  Palette_Load_LinkArmorAndGloves();
-  main_palette_buffer[0x1d] = 0x3800;
-  flag_update_cgram_in_nmi++;
-  BYTE(BG3VOFS_copy2) = 20;
-  Attract_BuildBackgrounds();
-  messaging_module = 0;
-  dialogue_message_index = 0x112;
-  BG2VOFS_copy2 = 0;
-  attract_legend_ctr = 0x1010;
-  attract_state += 3;
-  HdmaSetup(0xCFA87, 0xCFA94, 1, (uint8)WH0, (uint8)WH2, 0);
-  HDMAEN_copy = 0xc0;
-
-  W12SEL_copy = 0;
-  W34SEL_copy = 0;
-  WOBJSEL_copy = 0xb0;
-  TMW_copy = 3;
-  TSW_copy = 0;
-  COLDATA_copy0 = 0x25;
-  COLDATA_copy1 = 0x45;
-  COLDATA_copy2 = 0x85;
-  CGWSEL_copy = 0x10;
-  CGADSUB_copy = 0xa3;
-
-  music_control = 6;
-  attract_legend_flag++;
-}
-
-void Attract_FadeInStep() {  // 8ceea6
-  if (INIDISP_copy != 15) {
-    if (sign8(--link_speed_setting)) {
-      INIDISP_copy++;
-      link_speed_setting = 1;
-    }
-  } else {
-    attract_var18++;
-  }
-}
-
-void Attract_FadeInSequence() {  // 8ceeba
-  if (INIDISP_copy != 15) {
-    if (sign8(--link_speed_setting)) {
-      INIDISP_copy++;
-      link_speed_setting = 1;
-    }
-  } else {
-    attract_state++;
-  }
-}
-
-void Attract_FadeOutSequence() {  // 8ceecb
-  if (INIDISP_copy != 0) {
-    if (sign8(--link_speed_setting)) {
-      INIDISP_copy--;
-      link_speed_setting = 1;
-    }
-  } else {
-    EnableForceBlank();
-    EraseTileMaps_normal();
-    attract_state++;
-  }
-}
-
-void Attract_LoadNewScene() {  // 8ceee5
-  switch (attract_sequence) {
-  case 0: AttractScene_PolkaDots(); break;
-  case 1: AttractScene_WorldMap(); break;
-  case 2: AttractScene_ThroneRoom(); break;
-  case 3: Attract_PrepZeldaPrison(); break;
-  case 4: Attract_PrepMaidenWarp(); break;
-  case 5: AttractScene_EndOfStory(); break;
-  }
-}
-
-void AttractScene_PolkaDots() {  // 8ceef8
-  attract_next_legend_gfx = 0;
-  attract_state++;
-  INIDISP_copy = 0;
-}
-
-void AttractScene_WorldMap() {  // 8ceeff
-  zelda_ppu_write(BG1SC, 0x13);
-  zelda_ppu_write(BG2SC, 0x3);
-  CGWSEL_copy = 0x80;
-  CGADSUB_copy = 0x21;
-  BGMODE_copy = 7;
-  WorldMap_LoadLightWorldMap();
-  M7Y_copy = 0xed;
-  M7X_copy = 0x100;
-  BG1HOFS_copy = 0x80;
-  BG1VOFS_copy = 0xc0;
-  timer_for_mode7_zoom = 255;
-  Attract_ControlMapZoom();
-  attract_var10 = 1;
-  attract_state++;
-  INIDISP_copy = 0;
-}
-
-void AttractScene_ThroneRoom() {  // 8cef4e
-  HDMAEN_copy = 0;
-  CGWSEL_copy = 2;
-  CGADSUB_copy = 0x20;
-  misc_sprites_graphics_index = 10;
-  LoadCommonSprites();
-  uint16 bak0 = attract_var12;
-  uint16 bak1 = WORD(attract_state);
-  Dungeon_LoadAndDrawEntranceRoom(0x74);
-  WORD(attract_state) = bak1;
-  attract_var12 = bak0;
-  palette_main_indoors = 0;
-  palette_sp0l = 0;
-  palette_sp5l = 14;
-  palette_sp6l = 3;
-  Dungeon_SaveAndLoadLoadAllPalettes(0, 0x7e);
-
-  main_palette_buffer[0x1d] = 0x3800;
-  messaging_module = 0;
-  dialogue_message_index = 0x113;
-  attract_var10 = 2;
-  attract_var13 = 0xe0;
-  oam_priority_value = 0x210;
-
-  Attract_PrepFinish();
-}
-
-void Attract_PrepFinish() {  // 8cefc0
-  attract_state++;
-  INIDISP_copy = 0;
-  BYTE(BG3VOFS_copy2) = 0;
-  BG2HOFS_copy &= 0x1ff;
-  BG2VOFS_copy &= 0x1ff;
-  BG2HOFS_copy2 &= 0x1ff;
-  BG2VOFS_copy2 &= 0x1ff;
-}
-
-void Attract_PrepZeldaPrison() {  // 8cefe3
-  CGWSEL_copy = 0;
-  CGADSUB_copy = 0;
-
-  uint16 bak0 = attract_var12;
-  uint16 bak1 = WORD(attract_state);
-  Dungeon_LoadAndDrawEntranceRoom(0x73);
-  WORD(attract_state) = bak1;
-  attract_var12 = bak0;
-
-  palette_main_indoors = 2;
-  palette_sp0l = 0;
-  palette_sp5l = 14;
-  palette_sp6l = 3;
-  Dungeon_SaveAndLoadLoadAllPalettes(1, 0x7f);
-  main_palette_buffer[0x1d] = 0x3800;
-
-  messaging_module = 0;
-  dialogue_message_index = 0x114;
-
-  attract_var9 = 148;
-  attract_vram_dst = 0x68;
-  attract_var1 = 0;
-  attract_var3 = 0;
-  attract_x_base_hi = 0;
-  attract_var17 = 0;
-  attract_var18 = 0;
-  attract_var10 = 255;
-  oam_priority_value = 0x240;
-  Attract_PrepFinish();
-}
-
-void Attract_PrepMaidenWarp() {  // 8cf058
-  uint16 bak0 = attract_var12;
-  uint16 bak1 = WORD(attract_state);
-  Dungeon_LoadAndDrawEntranceRoom(0x75);
-  WORD(attract_state) = bak1;
-  attract_var12 = bak0;
-
-  palette_main_indoors = 0;
-  palette_sp0l = 0;
-  palette_sp5l = 14;
-  palette_sp6l = 3;
-
-  overworld_palette_aux_or_main = 0;
-  Palette_Load_Sp0L();
-  Palette_Load_SpriteMain();
-  Palette_Load_Sp5L();
-  Palette_Load_Sp6L();
-  Palette_Load_SpriteEnvironment_Dungeon();
-  Palette_Load_HUD();
-  Palette_Load_DungeonSet();
-  Dungeon_SaveAndLoadLoadAllPalettes(2, 0x7f);
-  aux_palette_buffer[0x1d] = main_palette_buffer[0x1d] = 0x3800;
-
-  messaging_module = 0;
-  dialogue_message_index = 0x115;
-  attract_var10 = 255;
-  BYTE(attract_vram_dst) = 112;
-  attract_var19 = 112;
-  attract_var20 = 112;
-  attract_var1 = 8;
-  attract_var17 = 0;
-  attract_var21 = 0;
-  attract_var15 = 0;
-  attract_var18 = 0;
-  attract_var5 = 0;
-  attract_var11 = 0;
-
-  oam_priority_value = 0xc0;
-  Attract_PrepFinish();
-}
-
-void AttractScene_EndOfStory() {  // 8cf0dc
-  Attract_SetUpConclusionHDMA();
-  Death_Func31();
-}
-
-void Death_Func31() {  // 8cf0e2
-  nmi_disable_core_updates++;
-  Intro_InitializeMemory_darken();
-  Overworld_LoadAllPalettes();
-  BYTE(BG3VOFS_copy2) = 0;
-  M7Y_copy = 0;
-  M7X_copy = 0;
-  BG1HOFS_copy = 0;
-  BG1VOFS_copy = 0;
-  BG2HOFS_copy = 0;
-  BG2VOFS_copy = 0;
-  music_control = 0xF1;
-  attract_sequence = 0;
-  main_module_index = 0;
-  submodule_index = 10;
-  subsubmodule_index = 10;
-}
-
-void Attract_EnactStory() {  // 8cf115
-  switch (attract_sequence) {
-  case 0: AttractDramatize_PolkaDots(); break;
-  case 1: AttractDramatize_WorldMap(); break;
-  case 2: Attract_ThroneRoom(); break;
-  case 3: AttractDramatize_Prison(); break;
-  case 4: AttractDramatize_AgahnimAltar(); break;
-  }
-}
-
-void AttractDramatize_PolkaDots() {  // 8cf126
-  if (!(frame_counter & 3)) {
-    BYTE(BG1VOFS_copy)++;
-    BYTE(BG1HOFS_copy)++;
-    BYTE(BG2VOFS_copy)++;
-    BYTE(BG2HOFS_copy)--;
-  }
-
-  if (attract_legend_flag) {
-    Attract_BuildNextImageTileMap();
-    attract_legend_flag = 0;
-    attract_next_legend_gfx += 2;
-  }
-  joypad1L_last = 0;
-  filtered_joypad_L = 0;
-  filtered_joypad_H = 0;
-  RenderText();
-  if (!--attract_legend_ctr) {
-    attract_sequence++;
-    attract_state -= 3;
-  } else {
-    if (attract_legend_ctr < 0x18 && attract_legend_ctr & 1)
-      INIDISP_copy--;
-  }
-}
-
-void AttractDramatize_WorldMap() {  // 8cf176
-  if (timer_for_mode7_zoom != 0) {
-    if (timer_for_mode7_zoom < 15)
-      INIDISP_copy--;
-    if (!--attract_var10) {
-      attract_var10 = 1;
-      timer_for_mode7_zoom -= 1;
-      Attract_ControlMapZoom();
-    }
-  } else {
-    EnableForceBlank();
-    BGMODE_copy = 9;
-    EraseTileMaps_normal();
-    attract_sequence++;
-    attract_state -= 2;
-  }
-}
-
-void Attract_ThroneRoom() {  // 8cf1c8
-  static const AttractOamInfo kThroneRoom_Oams[] = {
-    {16, 16, 0x2a, 0x7b, 2},
-    { 0, 16, 0x2a, 0x3b, 2},
-    {16,  0, 0x0a, 0x7b, 2},
-    { 0,  0, 0x0a, 0x3b, 2},
-    { 0,  0, 0x0c, 0x31, 2},
-    {16,  0, 0x0e, 0x31, 2},
-    {32,  0, 0x0c, 0x71, 2},
-    { 0, 16, 0x2c, 0x31, 2},
-    {16, 16, 0x2e, 0x31, 2},
-    {32, 16, 0x2c, 0x71, 2},
-  };
-  static const uint8 kThroneRoom_OamOffs[3] = { 0, 4, 10 };
-  static const int8 kAttract_ThroneRoom_Xbase[2] = { 80, 104 };
-  static const int8 kAttract_ThroneRoom_Ybase[2] = { 88, 32 };
-  attract_oam_idx = 0;
-  if (!attract_var15) {
-    if (INIDISP_copy != 15)
-      INIDISP_copy++;
-    else
-      attract_var15++;
-  }
-  if (!BG2VOFS_copy) {
-    Attract_ShowTimedTextMessage();
-    if (!oam_priority_value) {
-      if (attract_var13 < 31 && !(attract_var13 & 1))
-        INIDISP_copy--;
-      if (!--attract_var13) {
-        attract_sequence++;
-        attract_state++;
-        return;
-      }
-    }
-  } else {
-    BG2VOFS_copy--;
-    BG1VOFS_copy--;
-  }
-  for (int i = 1; i >= 0; i--) {
-    const AttractOamInfo *oamp = &kThroneRoom_Oams[kThroneRoom_OamOffs[i]];
-    int n = kThroneRoom_OamOffs[i + 1] - kThroneRoom_OamOffs[i];
-    uint16 y = kAttract_ThroneRoom_Ybase[i] - BG2VOFS_copy;
-    if (!sign16(y + 32)) {
-      attract_x_base = kAttract_ThroneRoom_Xbase[i];
-      attract_y_base = y;
-      Attract_DrawSpriteSet2(oamp, n);
-    }
-  }
-
-  attract_var7 = 0xf8a7;
-}
-
-void AttractDramatize_Prison() {  // 8cf27a
-  static const uint8 kAttract_ZeldaPrison_Tab0[16] = { 0, 1, 2, 3, 4, 5, 5, 5, 4, 4, 3, 3, 2, 2, 1, 1 };
-  static const int8 kZeldaPrison_Soldier_X[2] = { 32, -12 };
-  static const int8 kZeldaPrison_Soldier_Y[2] = { 24, 24 };
-  static const uint8 kZeldaPrison_Soldier_Dir[2] = { 1, 1 };
-  static const uint8 kZeldaPrison_Soldier_Flags[2] = { 9, 7 };
-
-  attract_oam_idx = 0;
-  if (!attract_var18)
-    Attract_FadeInStep();
-  attract_x_base = 56;
-  Attract_DrawZelda();
-  if (attract_var10 >= 192) {
-    attract_y_base = 112;
-    if (sign8(--attract_var17))
-      attract_var17 = 0xf;
-    int t = attract_vram_dst + kAttract_ZeldaPrison_Tab0[attract_var17];
-    attract_x_base_hi = t >> 8;
-    attract_x_base = t;
-    Attract_ZeldaPrison_DrawA();
-
-    for (int k = 1; k >= 0; k--) {
-      SpritePrep_ResetProperties(k * 2);
-      uint16 x = kZeldaPrison_Soldier_X[k] + attract_vram_dst + 0x100;
-      attract_var4 = x;
-      Sprite_SimulateSoldier(k * 2,
-                             x, attract_y_base + kZeldaPrison_Soldier_Y[k],
-                             kZeldaPrison_Soldier_Dir[k], kZeldaPrison_Soldier_Flags[k], attract_var3);
-    }
-
-    if (!(++attract_var1 & 7)) {
-      if (attract_var3 == 2) {
-        attract_var3 = 0xff;
-        if (!HIBYTE(attract_vram_dst) && attract_var1 & 8)
-          sound_effect_2 = 4;
-      }
-      attract_var3++;
-    }
-  }
-
-  switch (attract_var5) {
-  case 0: Attract_ZeldaPrison_Case0(); break;
-  case 1: Attract_ZeldaPrison_Case1(); break;
-  }
-}
-
-void AttractDramatize_AgahnimAltar() {  // 8cf423
-  if (attract_var22) {
-    attract_sequence++;
-    attract_state -= 2;
-    return;
-  }
-  attract_oam_idx = 0;
-  HandleScreenFlash();
-  if (!attract_var18)
-    Attract_FadeInStep();
-  if (attract_var17 != 255)
-    attract_var17++;
-  if (intro_times_pal_flash & 4)
-    sound_effect_2 = 0x2b;
-  switch (attract_var5) {
-  case 0: Attract_MaidenWarp_Case0(); break;
-  case 1: Attract_MaidenWarp_Case1(); break;
-  case 2: Attract_MaidenWarp_Case2(); break;
-  case 3: Attract_MaidenWarp_Case3(); break;
-  case 4: Attract_MaidenWarp_Case4(); break;
-  }
-
-  static const uint8 kMaidenWarp_Soldier_X[6] = { 48, 192, 48, 192, 80, 160 };
-  static const uint8 kMaidenWarp_Soldier_Y[6] = { 112, 112, 152, 152, 192, 192 };
-  static const uint8 kMaidenWarp_Soldier_Dir[6] = { 0, 1, 0, 1, 3, 3 };
-  static const uint8 kMaidenWarp_Soldier_Flags[6] = { 9, 9, 9, 9, 7, 9 };
-  for (int k = 5; k >= 0; k--) {
-
-    SpritePrep_ResetProperties(k);
-    Sprite_SimulateSoldier(k, kMaidenWarp_Soldier_X[k], kMaidenWarp_Soldier_Y[k],
-                           kMaidenWarp_Soldier_Dir[k], kMaidenWarp_Soldier_Flags[k], 0);
-  }
-
-  if (attract_var17 >= 0xa0) {
-    if (BYTE(attract_vram_dst) != 0x60) {
-      if (!--attract_var1) {
-        BYTE(attract_vram_dst)--;
-        attract_var1 = 8;
-      }
-    } else {
-      attract_var11++;
-    }
-  }
-
-  if (attract_var15 == 0) {
-    static const AttractOamInfo kZeldaPrison_MaidenWarp0[] = {
-      { 0,  0, 0x03, 0x3d, 2},
-      { 8,  0, 0x04, 0x3d, 2},
-      { 0,  0, 0x00, 0x3d, 2},
-      { 8,  0, 0x01, 0x3d, 2},
-    };
-
-    attract_x_base = 116;
-    attract_y_base = attract_vram_dst;
-    Attract_DrawSpriteSet2(kZeldaPrison_MaidenWarp0 + (BYTE(attract_vram_dst) == 0x70 ? 0 : 2), 2);
-    static const uint8 kAttract_MaidenWarp_Xbase[8] = { 4, 4, 3, 3, 2, 2, 1, 0 };
-    static const AttractOamInfo kZeldaPrison_MaidenWarp1[] = {
-      { 0,  0, 0x6c, 0x38, 2},
-      { 0,  0, 0x6c, 0x38, 2},
-      { 0,  0, 0x6c, 0x38, 2},
-      { 0,  0, 0x6c, 0x38, 2},
-      { 0,  0, 0x6c, 0x38, 2},
-      { 2,  0, 0x6c, 0x38, 2},
-      { 0,  0, 0x6c, 0x38, 2},
-      { 2,  0, 0x6c, 0x38, 2},
-      { 0,  0, 0x6c, 0x38, 2},
-      { 4,  0, 0x6c, 0x38, 2},
-      { 0,  0, 0x6c, 0x38, 2},
-      { 4,  0, 0x6c, 0x38, 2},
-      { 0,  0, 0x6c, 0x38, 2},
-      { 6,  0, 0x6c, 0x38, 2},
-      { 0,  0, 0x6c, 0x38, 2},
-      { 8,  0, 0x6c, 0x38, 2},
-    };
-    int k = 7;
-    if (BYTE(attract_vram_dst) < 0x68)
-      k = (BYTE(attract_vram_dst) - 0x68) & 7;
-    attract_x_base = 0x74 + kAttract_MaidenWarp_Xbase[k];
-    attract_y_base = 0x76;
-    Attract_DrawSpriteSet2(kZeldaPrison_MaidenWarp1 + k * 2, 2);
-
-  }
-  static const AttractOamInfo kZeldaPrison_MaidenWarp2[] = {
-    { 5, 25, 0x6c, 0x38, 2},
-    {11, 25, 0x6c, 0x38, 2},
-    { 0,  0, 0x82, 0x3b, 2},
-    {16,  0, 0x82, 0x7b, 2},
-    { 0, 16, 0xa2, 0x3b, 2},
-    {16, 16, 0xa2, 0x7b, 2},
-    { 5, 25, 0x6c, 0x38, 2},
-    {11, 25, 0x6c, 0x38, 2},
-    { 0,  0, 0x80, 0x3b, 2},
-    {16,  0, 0x82, 0x7b, 2},
-    { 0, 16, 0xa0, 0x3b, 2},
-    {16, 16, 0xa2, 0x7b, 2},
-    { 5, 25, 0x6c, 0x38, 2},
-    {11, 25, 0x6c, 0x38, 2},
-    { 0,  0, 0x82, 0x3b, 2},
-    {16,  0, 0x82, 0x7b, 2},
-    { 0, 16, 0xa2, 0x3b, 2},
-    {16, 16, 0xa2, 0x7b, 2},
-    { 5, 25, 0x6c, 0x38, 2},
-    {11, 25, 0x6c, 0x38, 2},
-    { 0,  0, 0x82, 0x3b, 2},
-    {16,  0, 0x80, 0x7b, 2},
-    { 0, 16, 0xa2, 0x3b, 2},
-    {16, 16, 0xa0, 0x7b, 2},
-    { 5, 25, 0x6c, 0x38, 2},
-    {11, 25, 0x6c, 0x38, 2},
-    { 0,  0, 0x82, 0x3b, 2},
-    {16,  0, 0x82, 0x7b, 2},
-    { 0, 16, 0xa2, 0x3b, 2},
-    {16, 16, 0xa2, 0x7b, 2},
-    { 5, 25, 0x6c, 0x38, 2},
-    {11, 25, 0x6c, 0x38, 2},
-    { 0,  0, 0x80, 0x3b, 2},
-    {16,  0, 0x82, 0x7b, 2},
-    { 0, 16, 0xa0, 0x3b, 2},
-    {16, 16, 0xa2, 0x7b, 2},
-    { 5, 25, 0x6c, 0x38, 2},
-    {11, 25, 0x6c, 0x38, 2},
-    { 0,  0, 0x82, 0x3b, 2},
-    {16,  0, 0x82, 0x7b, 2},
-    { 0, 16, 0xa2, 0x3b, 2},
-    {16, 16, 0xa2, 0x7b, 2},
-    { 5, 25, 0x6c, 0x38, 2},
-    {11, 25, 0x6c, 0x38, 2},
-    { 0,  0, 0x80, 0x3b, 2},
-    {16,  0, 0x80, 0x7b, 2},
-    { 0, 16, 0xa0, 0x3b, 2},
-    {16, 16, 0xa0, 0x7b, 2},
-  };
-  int k = attract_var17 >> 5 & 7;
-  attract_x_base = 112;
-  attract_y_base = 70;
-  Attract_DrawSpriteSet2(kZeldaPrison_MaidenWarp2 + k * 6, 6);
-
-}
-
-void Attract_SkipToFileSelect() {  // 8cf700
-  if (--INIDISP_copy)
-    return;
-  EnableForceBlank();
-  zelda_ppu_write(BG1SC, 0x13);
-  zelda_ppu_write(BG2SC, 0x3);
-  Attract_SetUpConclusionHDMA();
-  M7Y_copy = 0;
-  M7X_copy = 0;
-  BG1HOFS_copy = 0;
-  BG1VOFS_copy = 0;
-  BG3VOFS_copy2 = 0;
-  FadeMusicAndResetSRAMMirror();
-}
-
-void Attract_BuildNextImageTileMap() {  // 8cf73e
-  static const uint8 *const kAttract_LegendGraphics_pointers[4] = {
-    kAttract_Legendgraphics_0,
-    kAttract_Legendgraphics_1,
-    kAttract_Legendgraphics_2,
-    kAttract_Legendgraphics_3,
-  };
-  static const uint16 kAttract_LegendGraphics_sizes[4] = { 157+1, 237+1, 199+1, 265+1 };
-  int i = attract_next_legend_gfx >> 1;
-  memcpy(&g_ram[0x1002], kAttract_LegendGraphics_pointers[i], kAttract_LegendGraphics_sizes[i]);
-  nmi_load_bg_from_vram = 1;
-}
-
-void Attract_ShowTimedTextMessage() {  // 8cf766
-  attract_var12 = BG2VOFS_copy2;
-  BYTE(joypad1L_last) = 0;
-  BYTE(filtered_joypad_L) = 0;
-  BYTE(filtered_joypad_H) = 0;
-  RenderText();
-  if (oam_priority_value)
-    oam_priority_value--;
-}
-
-void Attract_ControlMapZoom() {  // 8cf783
-  for (int i = 240 - 1; i >= 0; i--)
-    hdma_table_dynamic[i] = kMapMode_Zooms1[i] * timer_for_mode7_zoom >> 8;
-}
-
-void Attract_BuildBackgrounds() {  // 8cf7e6
-  static const uint16 kAttract_CopyToVram_Tab0[16] = { 0x1a0, 0x9a6, 0x89a5, 0x1a0, 0x9a5, 0x1a0, 0x1a0, 0x89a6, 0x49a5, 0x1a0, 0x1a0, 0x49a5, 0x1a0, 0x89a5, 0xc9a5, 0x1a0 };
-  static const uint16 kAttract_CopyToVram_Tab1[4] = { 0x9a1, 0x9a2, 0x9a3, 0x9a4 };
-
-  BGMODE_copy = 9;
-  TM_copy = 0x17;
-  TS_copy = 0;
-
-  zelda_ppu_write(BG1SC, 0x10);
-  zelda_ppu_write(BG2SC, 0x0);
-
-  {
-    int k = 0;
-    const uint16 *p = kAttract_CopyToVram_Tab0;
-    uint16 *dst = (uint16 *)&g_ram[0x1006];
-    do {
-      int j = k & 3;
-      do {
-        dst[k++] = p[j++];
-      } while (j & 3);
-    } while (k & 0x1f || (p += 4, k != 0x80));
-    Attract_TriggerBGDMA(0x1000);
-  }
-
-  {
-    int k = 0;
-    uint16 *dst = (uint16 *)&g_ram[0x1006];
-    do {
-      int j = k & 1;
-      const uint16 *p = kAttract_CopyToVram_Tab1 + ((k & 0x20) >> 4);
-      do {
-        dst[k++] = p[j++];
-      } while (j & 1);
-    } while (k != 0x80);
-    Attract_TriggerBGDMA(0);
-  }
-  attract_vram_dst = 0;
-}
-
-void Attract_TriggerBGDMA(uint16 dstv) {  // 8cf879
-  uint16 *dst = &g_zenv.vram[dstv];
-  for (int i = 0; i < 8; i++) {
-    memcpy(dst, &g_ram[0x1006], 0x100);
-    dst += 0x80;
-  }
-}
-
-void Attract_DrawPreloadedSprite(const uint8 *xp, const uint8 *yp, const uint8 *cp, const uint8 *fp, const uint8 *ep, int n) {  // 8cf9b5
-  OamEnt *oam = &oam_buf[attract_oam_idx + 64];
-  attract_oam_idx += n + 1;
-  do {
-    SetOamPlain(oam, attract_x_base + xp[n], attract_y_base + yp[n], cp[n], fp[n], ep[n]);
-  } while (oam++, --n >= 0);
-}
-
-void Attract_DrawZelda() {  // 8cf9e8
-  OamEnt *oam = &oam_buf[64 + attract_oam_idx];
-  SetOamPlain(oam + 0, 0x60, attract_x_base, 0x28, 0x29, 2);
-  SetOamPlain(oam + 1, 0x60, attract_x_base + 10, 0x2a, 0x29, 2);
-  attract_oam_idx += 2;
-}
-
-void Sprite_SimulateSoldier(int k, uint16 x, uint16 y, uint8 dir, uint8 flags, uint8 gfx) {  // 9deb84
-  static const uint8 kSimulateSoldier_Gfx[4] = { 11, 4, 0, 7 };
-  Sprite_SetX(k, x);
-  Sprite_SetY(k, y);
-  sprite_z[k] = 0;
-  Sprite_Get16BitCoords(k);
-  sprite_D[k] = sprite_head_dir[k] = dir;
-  sprite_graphics[k] = kSimulateSoldier_Gfx[dir] + gfx;
-  sprite_flags3[k] = 16;
-  sprite_obj_prio[k] = 0;
-  sprite_oam_flags[k] = flags | 0x30;
-  sprite_type[k] = (flags == 9) ? 0x41 : 0x43;
-  sprite_flags2[k] = 7;
-  int oam_idx = k * 8;
-  oam_cur_ptr = 0x800 + oam_idx * 4;
-  oam_ext_cur_ptr = 0xa20 + oam_idx;
-  Guard_HandleAllAnimation(k);
-}
-
--- a/attract.h
+++ /dev/null
@@ -1,50 +1,0 @@
-#pragma once
-typedef struct AttractOamInfo {
-  int8 x, y;
-  uint8 c, f, e;
-} AttractOamInfo;
-
-
-extern const uint16 kMapMode_Zooms1[240];
-extern const uint16 kMapMode_Zooms2[240];
-void Attract_DrawSpriteSet2(const AttractOamInfo *p, int n);
-void Attract_ZeldaPrison_Case0();
-void Attract_ZeldaPrison_Case1();
-void Attract_ZeldaPrison_DrawA();
-void Attract_MaidenWarp_Case0();
-void Attract_MaidenWarp_Case1();
-void Attract_MaidenWarp_Case2();
-void Attract_MaidenWarp_Case3();
-void Attract_MaidenWarp_Case4();
-void Dungeon_LoadAndDrawEntranceRoom(uint8 a);
-void Dungeon_SaveAndLoadLoadAllPalettes(uint8 a, uint8 k);
-void Module14_Attract();
-void Attract_Fade();
-void Attract_InitGraphics();
-void Attract_FadeInStep();
-void Attract_FadeInSequence();
-void Attract_FadeOutSequence();
-void Attract_LoadNewScene();
-void AttractScene_PolkaDots();
-void AttractScene_WorldMap();
-void AttractScene_ThroneRoom();
-void Attract_PrepFinish();
-void Attract_PrepZeldaPrison();
-void Attract_PrepMaidenWarp();
-void AttractScene_EndOfStory();
-void Death_Func31();
-void Attract_EnactStory();
-void AttractDramatize_PolkaDots();
-void AttractDramatize_WorldMap();
-void Attract_ThroneRoom();
-void AttractDramatize_Prison();
-void AttractDramatize_AgahnimAltar();
-void Attract_SkipToFileSelect();
-void Attract_BuildNextImageTileMap();
-void Attract_ShowTimedTextMessage();
-void Attract_ControlMapZoom();
-void Attract_BuildBackgrounds();
-void Attract_TriggerBGDMA(uint16 dstv);
-void Attract_DrawPreloadedSprite(const uint8 *xp, const uint8 *yp, const uint8 *cp, const uint8 *fp, const uint8 *ep, int n);
-void Attract_DrawZelda();
-void Sprite_SimulateSoldier(int k, uint16 x, uint16 y, uint8 dir, uint8 flags, uint8 gfx);
--- a/audio.c
+++ /dev/null
@@ -1,542 +1,0 @@
-#include "audio.h"
-#include "zelda_rtl.h"
-#include "variables.h"
-#include "features.h"
-#include "snes/snes_regs.h"
-#include "spc_player.h"
-#include "third_party/opus-1.3.1-stripped/opus.h"
-#include "config.h"
-#include "assets.h"
-
-// This needs to hold a lot more things than with just PCM
-typedef struct MsuPlayerResumeInfo {
-  uint32 tag;
-  uint32 offset;
-  uint32 samples_until_repeat;
-  uint16 range_cur, range_repeat;
-  uint64 initial_packet_bytes;  // To verify we seeked right
-  uint8 orig_track;        // Using the old zelda track numbers
-  uint8 actual_track;      // The MSU track index we're playing (Different if using msu deluxe)
-} MsuPlayerResumeInfo;
-
-enum {
-  kMsuState_Idle = 0,
-  kMsuState_FinishedPlaying = 1,
-  kMsuState_Resuming = 2,
-  kMsuState_Playing = 3,
-};
-
-typedef struct MsuPlayer {
-  FILE *f;
-  uint32 buffer_size, buffer_pos;
-  uint32 preskip, samples_until_repeat;
-  uint32 total_samples_in_file, repeat_position;
-  uint32 cur_file_offs;
-  MsuPlayerResumeInfo resume_info;
-  uint8 enabled;
-  uint8 state;
-  float volume, volume_step, volume_target;
-  uint16 range_cur, range_repeat;
-  OpusDecoder *opus;
-  int16 buffer[960 * 2];
-} MsuPlayer;
-
-static MsuPlayer g_msu_player;
-
-static void MsuPlayer_Open(MsuPlayer *mp, int orig_track, bool resume_from_snapshot);
-
-static const uint8 kMsuTracksWithRepeat[48] = {
-  1,0,1,1,1,1,1,1,0,1,0,1,1,1,1,0,
-  1,1,1,0,1,1,1,1,1,1,1,1,1,0,1,1,
-  1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,
-};
-
-static const uint8 kIsMusicOwOrDungeon[] = {
-  0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, // 1 = ow songs : 2 = lw, 5 = forest, 7 = town, 9 = dark world, 13 = mountain
-  2, 2, 2, 0, 0, 0, 2, 2, 0, 0, 0, 2, 0, 0, 0, 0, // 2 = indoor songs : 16, 17, 18, 22, 23, 27
-};
-
-
-static const uint8 kMsuDeluxe_OW_Songs[] = {
-  37, 37, 42, 38, 38, 38, 38, 39, 37, 37, 42, 38, 38, 38, 38, 41, // lw
-  42, 42, 42, 42, 42, 42, 40, 40, 43, 43, 42, 47, 47, 42, 45, 45,
-  43, 43, 43, 47, 47, 42, 45, 45, 112, 112, 48, 42, 42, 42, 42, 45,
-  44, 44, 48, 48, 48, 46, 46, 46, 44, 44, 44, 48, 48, 46, 46, 46,
-  49, 49, 51, 50, 50, 50, 50, 50, 49, 49, 51, 50, 50, 50, 50, 51, // dw
-  51, 51, 51, 51, 51, 51, 51, 51, 52, 52, 51, 56, 56, 51, 54, 54,
-  52, 52, 52, 56, 56, 51, 54, 54, 58, 52, 57, 51, 51, 51, 51, 54,
-  53, 53, 57, 57, 57, 55, 55, 110, 53, 53, 57, 57, 57, 55, 55, 110,
-  37, 41, 41, 42, 42, 42, 42, 42, 42, 41, 41, 42, 42, 42, 42, 42, // special
-  42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42,
-};
-
-static const uint8 kMsuDeluxe_Entrance_Songs[] = {
-   59,  59,  60,  61,  61,  61,  62,  62,  63,  64,  64,  64, 105,  65,  65,  66,
-   66,  62,  67,  62,  62,  68,  62,  62,  68,  68,  62,  62,  62,  62,  62,  62,
-   62,  62,  62,  62,  69,  70,  71,  72,  73,  73,  73, 106, 102,  74,  62,  62,
-   75,  75,  76,  77,  78,  68,  79,  80,  81,  62,  62,  62,  82,  75, 242,  59,
-   59,  76, 242, 242, 242,  96,  83,  99,  59, 242, 242, 242,  84,  95, 104,  62,
-   85,  62,  62,  86, 242,  67, 103,  83,  83,  87,  76,  88,  81,  98,  81,  88,
-   83,  89,  75,  97,  90,  91,  91, 100,  92,  93,  92, 242,  93, 107,  62,  75,
-   62,  67,  62, 242, 242, 242,  73,  73,  73,  73, 102, 114,  81,  76,  62,  67,
-   62,  61,  94,  62, 103,
-};
-
-
-// Remap an track number into a potentially different track number (used for msu deluxe)
-static uint8 RemapMsuDeluxeTrack(MsuPlayer *mp, uint8 track) {
-  if (!(mp->enabled & kMsuEnabled_MsuDeluxe) || track >= sizeof(kIsMusicOwOrDungeon))
-    return track;
-  switch (kIsMusicOwOrDungeon[track]) {
-  case 1:
-    return BYTE(overworld_area_index) < sizeof(kMsuDeluxe_OW_Songs) ? kMsuDeluxe_OW_Songs[BYTE(overworld_area_index)] : track;
-  case 2:
-    if (which_entrance >= sizeof(kMsuDeluxe_Entrance_Songs) || kMsuDeluxe_Entrance_Songs[which_entrance] == 242)
-      return track;
-    return kMsuDeluxe_Entrance_Songs[which_entrance];
-  default:
-    return track;
-  }
-}
-
-bool ZeldaIsPlayingMusicTrack(uint8 track) {
-  MsuPlayer *mp = &g_msu_player;
-  if (mp->state != kMsuState_Idle && mp->enabled & kMsuEnabled_MsuDeluxe)
-    return RemapMsuDeluxeTrack(mp, track) == mp->resume_info.actual_track;
-  else
-    return track == music_unk1;
-}
-
-bool ZeldaIsPlayingMusicTrackWithBug(uint8 track) {
-  MsuPlayer *mp = &g_msu_player;
-  if (mp->state != kMsuState_Idle && mp->enabled & kMsuEnabled_MsuDeluxe)
-    return RemapMsuDeluxeTrack(mp, track) == mp->resume_info.actual_track;
-  else
-    return track == (enhanced_features0 & kFeatures0_MiscBugFixes ? music_unk1 : last_music_control);
-}
-
-uint8 ZeldaGetEntranceMusicTrack(int i) {
-  MsuPlayer *mp = &g_msu_player;
-  uint8 rv = kEntranceData_musicTrack[i];
-
-  // For some entrances the original performs a fade out, while msu deluxe has new tracks.
-  if (mp->state != kMsuState_Idle && mp->enabled & kMsuEnabled_MsuDeluxe) {
-    if (rv == 242 && kMsuDeluxe_Entrance_Songs[which_entrance] != 242)
-      rv = 16;
-  }
-
-  return rv;
-}
-
-static const uint8 kVolumeTransitionTarget[4] = { 0, 64, 255, 255};
-static const uint8 kVolumeTransitionStep[4] = { 7, 3, 3, 24};
-// These are precomputed in the config parse
-static float kVolumeTransitionStepFloat[4];
-static float kVolumeTransitionTargetFloat[4];
-
-void ZeldaPlayMsuAudioTrack(uint8 music_ctrl) {
-  MsuPlayer *mp = &g_msu_player;
-  if (!mp->enabled) {
-    mp->resume_info.tag = 0;
-    zelda_apu_write(APUI00, music_ctrl);
-    return;
-  }
-  ZeldaApuLock();
-  if ((music_ctrl & 0xf0) != 0xf0)
-    MsuPlayer_Open(mp, music_ctrl, false);
-  else if (music_ctrl >= 0xf1 && music_ctrl <= 0xf3) {
-    mp->volume_target = kVolumeTransitionTargetFloat[music_ctrl - 0xf1];
-    mp->volume_step = kVolumeTransitionStepFloat[music_ctrl - 0xf1];
-  }
-
-  if (mp->state == 0) {
-    zelda_apu_write(APUI00, music_ctrl);
-  } else {
-    zelda_apu_write(APUI00, 0xf0);  // pause spc player
-  }
-  ZeldaApuUnlock();
-}
-
-static void MsuPlayer_CloseFile(MsuPlayer *mp) {
-  if (mp->f)
-    fclose(mp->f);
-  opus_decoder_destroy(mp->opus);
-  mp->opus = NULL;
-  mp->f = NULL;
-  if (mp->state != kMsuState_FinishedPlaying)
-    mp->state = kMsuState_Idle;
-  memset(&mp->resume_info, 0, sizeof(mp->resume_info));
-}
-
-static void MsuPlayer_Open(MsuPlayer *mp, int orig_track, bool resume_from_snapshot) {
-  MsuPlayerResumeInfo resume;
-  int actual_track = RemapMsuDeluxeTrack(mp, orig_track);
-
-  if (!resume_from_snapshot) {
-    resume.tag = 0;
-    // Attempt to resume MSU playback when exiting back to the overworld.
-    if (main_module_index == 9 &&
-        actual_track == ((MsuPlayerResumeInfo *)msu_resume_info_alt)->actual_track && g_config.resume_msu) {
-      memcpy(&resume, msu_resume_info_alt, sizeof(mp->resume_info));
-    }
-    if (mp->state >= kMsuState_Resuming)
-      memcpy(msu_resume_info_alt, &mp->resume_info, sizeof(mp->resume_info));
-  } else {
-    memcpy(&resume, msu_resume_info, sizeof(mp->resume_info));
-  }
-
-  mp->volume_target = kVolumeTransitionTargetFloat[3];
-  mp->volume_step = kVolumeTransitionStepFloat[3];
-
-  mp->state = kMsuState_Idle;
-  MsuPlayer_CloseFile(mp);
-  if (actual_track == 0)
-    return;
-  char fname[256], buf[8];
-  snprintf(fname, sizeof(fname), "%s%d.%s", g_config.msu_path ? g_config.msu_path : "", actual_track, mp->enabled & kMsuEnabled_Opuz ? "opuz" : "pcm");
-  printf("Loading MSU %s\n", fname);
-  mp->f = fopen(fname, "rb");
-  if (mp->f == NULL)
-    goto READ_ERROR;
-  setvbuf(mp->f, NULL, _IOFBF, 16384);
-  if (fread(buf, 1, 8, mp->f) != 8) READ_ERROR: {
-    fprintf(stderr, "Unable to read MSU file %s\n", fname);
-    MsuPlayer_CloseFile(mp);
-    return;
-  }
-  uint32 file_tag = *(uint32 *)(buf + 0);
-  mp->repeat_position = *(uint32 *)(buf + 4);
-  mp->state = (resume.actual_track == actual_track && resume.tag == file_tag) ? kMsuState_Resuming : kMsuState_Playing;
-  if (mp->state == kMsuState_Resuming) {
-    memcpy(&mp->resume_info, &resume, sizeof(mp->resume_info));
-  } else {
-    mp->resume_info.orig_track = orig_track;
-    mp->resume_info.actual_track = actual_track;
-    mp->resume_info.tag = file_tag;
-    mp->resume_info.range_cur = 8;
-  }
-  mp->cur_file_offs = mp->resume_info.offset;
-  mp->samples_until_repeat = mp->resume_info.samples_until_repeat;
-  mp->range_cur = mp->resume_info.range_cur;
-  mp->range_repeat = mp->resume_info.range_repeat;
-  mp->buffer_size = mp->buffer_pos = 0;
-  mp->preskip = 0;
-  if (file_tag == (('Z' << 24) | ('U' << 16) | ('P' << 8) | 'O')) {
-    mp->opus = opus_decoder_create(48000, 2, NULL);
-    if (!mp->opus)
-      goto READ_ERROR;
-    if (mp->state == kMsuState_Resuming)
-      fseek(mp->f, mp->cur_file_offs, SEEK_SET);
-  } else if (file_tag == (('1' << 24) | ('U' << 16) | ('S' << 8) | 'M')) {
-    fseek(mp->f, 0, SEEK_END);
-    mp->total_samples_in_file = (ftell(mp->f) - 8) / 4;
-    mp->samples_until_repeat = mp->total_samples_in_file - mp->cur_file_offs;
-    fseek(mp->f, mp->cur_file_offs * 4 + 8, SEEK_SET);
-  } else {
-    goto READ_ERROR;
-  }
-}
-
-static void MixToBufferWithVolume(int16 *dst, const int16 *src, size_t n, float volume) {
-  if (volume == 1.0f) {
-    for (size_t i = 0; i < n; i++) {
-      dst[i * 2 + 0] += src[i * 2 + 0];
-      dst[i * 2 + 1] += src[i * 2 + 1];
-    }
-  } else {
-    uint32 vol = (int32)(65536 * volume);
-    for (size_t i = 0; i < n; i++) {
-      dst[i * 2 + 0] += src[i * 2 + 0] * vol >> 16;
-      dst[i * 2 + 1] += src[i * 2 + 1] * vol >> 16;
-    }
-  }
-}
-
-static void MixToBufferWithVolumeRamp(int16 *dst, const int16 *src, size_t n, float volume, float volume_step, float ideal_target) {
-  int64 vol = volume * 281474976710656.0f;
-  int64 step = volume_step * 281474976710656.0f;
-  for (size_t i = 0; i < n; i++) {
-    uint32 v = (vol >> 32);
-    dst[i * 2 + 0] += src[i * 2 + 0] * v >> 16;
-    dst[i * 2 + 1] += src[i * 2 + 1] * v >> 16;
-    vol += step;
-  }
-}
-
-static void MixToBuffer(MsuPlayer *mp, int16 *dst, const int16 *src, uint32 n) {
-  if (mp->volume != mp->volume_target) {
-    float step = mp->volume < mp->volume_target ? mp->volume_step : -mp->volume_step;
-    float new_vol = mp->volume + step * n;
-    uint32 curn = n;
-    if (step >= 0 ? new_vol >= mp->volume_target : new_vol < mp->volume_target) {
-      uint32 maxn = (uint32)((mp->volume_target - mp->volume) / step);
-      curn = UintMin(maxn, curn);
-      new_vol = mp->volume_target;
-    }
-    float vol = mp->volume;
-    mp->volume = new_vol;
-    MixToBufferWithVolumeRamp(dst, src, curn, vol, step, new_vol);
-    dst += curn * 2, src += curn * 2, n -= curn;
-  }
-  MixToBufferWithVolume(dst, src, n, mp->volume);
-}
-
-void MsuPlayer_Mix(MsuPlayer *mp, int16 *audio_buffer, int audio_samples) {
-  int r;
-
-  do {
-    if (mp->buffer_size - mp->buffer_pos == 0) {
-      if (mp->opus != NULL) {
-        if (mp->samples_until_repeat == 0) {
-          if (mp->range_cur == 0) FINISHED_PLAYING: {
-            mp->state = kMsuState_FinishedPlaying;
-            MsuPlayer_CloseFile(mp);
-            return;
-          }
-          opus_decoder_ctl(mp->opus, OPUS_RESET_STATE);
-          fseek(mp->f, mp->range_cur, SEEK_SET);
-          uint8 *file_data = (uint8 *)mp->buffer;
-          if (fread(file_data, 1, 10, mp->f) != 10) READ_ERROR: {
-            fprintf(stderr, "MSU read/decode error!\n");
-            zelda_apu_write(APUI00, mp->resume_info.orig_track);
-            MsuPlayer_CloseFile(mp);
-            return;
-          }
-          uint32 file_offs = *(uint32 *)&file_data[0];
-          assert((file_offs & 0xF0000000) == 0);
-          uint32 samples_until_repeat = *(uint32 *)&file_data[4];
-          uint16 preskip = *(uint32 *)&file_data[8];
-          mp->samples_until_repeat = samples_until_repeat;
-          mp->preskip = preskip & 0x3fff;
-          if (preskip & 0x4000)
-            mp->range_repeat = mp->range_cur;
-          mp->range_cur = (preskip & 0x8000) ? mp->range_repeat : mp->range_cur + 10;
-          mp->cur_file_offs = file_offs;
-          mp->resume_info.range_repeat = mp->range_repeat;
-          mp->resume_info.range_cur = mp->range_cur;
-          fseek(mp->f, file_offs, SEEK_SET);
-        }
-        assert(mp->samples_until_repeat != 0);
-        for (;;) {
-          uint8 *file_data = (uint8 *)mp->buffer;
-          *(uint64 *)file_data = 0;
-          if (fread(file_data, 1, 2, mp->f) != 2)
-            goto READ_ERROR;
-          int size = *(uint16 *)file_data & 0x7fff;
-          if (size > 1275)
-            goto READ_ERROR;
-          int n = (*(uint16 *)file_data >> 15);
-          if (fread(&file_data[2], 1, size, mp->f) != size)
-            goto READ_ERROR;
-          // Verify if the snapshot matches the file on disk.
-          uint64 initial_file_data = *(uint64 *)file_data;
-          if (mp->state == kMsuState_Resuming) {
-            mp->state = kMsuState_Playing;
-            if (mp->resume_info.initial_packet_bytes != initial_file_data)
-              goto READ_ERROR;
-          }
-          mp->resume_info.initial_packet_bytes = initial_file_data;
-          mp->resume_info.samples_until_repeat = mp->samples_until_repeat + mp->preskip;
-          mp->resume_info.offset = mp->cur_file_offs;
-          mp->cur_file_offs += 2 + size;
-          file_data[1] = 0xfc;
-          r = opus_decode(mp->opus, &file_data[2 - n], size + n, mp->buffer, 960, 0);
-          if (r <= 0)
-            goto READ_ERROR;
-          if (r > mp->preskip)
-            break;
-          mp->preskip -= r;
-        }
-      } else {
-        if (mp->samples_until_repeat == 0) {
-          if (mp->resume_info.actual_track < sizeof(kMsuTracksWithRepeat) && !kMsuTracksWithRepeat[mp->resume_info.actual_track])
-            goto FINISHED_PLAYING;
-          mp->samples_until_repeat = mp->total_samples_in_file - mp->repeat_position;
-          if (mp->samples_until_repeat == 0)
-            goto READ_ERROR; // impossible to make progress
-          mp->cur_file_offs = mp->repeat_position;
-          fseek(mp->f, mp->cur_file_offs * 4 + 8, SEEK_SET);
-        }
-        r = UintMin(960, mp->samples_until_repeat);
-        if (fread(mp->buffer, 4, r, mp->f) != r)
-          goto READ_ERROR;
-        mp->resume_info.offset = mp->cur_file_offs;
-        mp->cur_file_offs += r;
-      }
-      uint32 n = UintMin(r - mp->preskip, mp->samples_until_repeat);
-      mp->samples_until_repeat -= n;
-      mp->buffer_pos = mp->preskip;
-      mp->buffer_size = mp->buffer_pos + n;
-      mp->preskip = 0;
-    }
-#if 0
-    if (mp->samples_to_play > 44100 * 5) {
-      mp->buffer_pos = mp->buffer_size;
-    }
-#endif
-    int nr = IntMin(audio_samples, mp->buffer_size - mp->buffer_pos);
-    int16 *buf = mp->buffer + mp->buffer_pos * 2;
-    mp->buffer_pos += nr;
-
-#if 0
-    static int t;
-    for (int i = 0; i < nr; i++) {
-      buf[i * 2 + 0] = buf[i * 2 + 1] = 5000 * sinf(2 * 3.1415 * t++ / 440);
-    }
-#endif
-    MixToBuffer(mp, audio_buffer, buf, nr);
-
-#if 0
-    static FILE *f;
-    if (!f)f = fopen("out.pcm", "wb");
-    fwrite(audio_buffer, 4, nr, f);
-    fflush(f);
-#endif
-    audio_samples -= nr, audio_buffer += nr * 2;
-  } while (audio_samples != 0);
-}
-
-// Maintain a queue cause the snes and audio callback are not in sync.
-struct ApuWriteEnt {
-  uint8 ports[4];
-};
-static struct ApuWriteEnt g_apu_write_ents[16], g_apu_write;
-static uint8 g_apu_write_ent_pos, g_apu_write_count, g_apu_total_write;
-void zelda_apu_write(uint32_t adr, uint8_t val) {
-  g_apu_write.ports[adr & 0x3] = val;
-}
-
-void ZeldaPushApuState() {
-  ZeldaApuLock();
-  g_apu_write_ents[g_apu_write_ent_pos++ & 0xf] = g_apu_write;
-  if (g_apu_write_count < 16)
-    g_apu_write_count++;
-  g_apu_total_write++;
-  ZeldaApuUnlock();
-}
-
-static void ZeldaPopApuState() {
-  if (g_apu_write_count != 0)
-    memcpy(g_zenv.player->input_ports, &g_apu_write_ents[(g_apu_write_ent_pos - g_apu_write_count--) & 0xf], 4);
-}
-
-void ZeldaDiscardUnusedAudioFrames() {
-  if (g_apu_write_count != 0 && memcmp(g_zenv.player->input_ports, &g_apu_write_ents[(g_apu_write_ent_pos - g_apu_write_count) & 0xf], 4) == 0) {
-    if (g_apu_total_write >= 16) {
-      g_apu_total_write = 14;
-      g_apu_write_count--;
-    }
-  } else {
-    g_apu_total_write = 0;
-  }
-}
-
-static void ZeldaResetApuQueue() {
-  g_apu_write_ent_pos = g_apu_total_write = g_apu_write_count = 0;
-}
-
-uint8_t zelda_read_apui00() {
-  // This needs to be here because the ancilla code reads
-  // from the apu and we don't want to make the core code
-  // dependent on the apu timings, so relocated this value
-  // to 0x648.
-  return g_ram[kRam_APUI00];
-}
-
-uint8_t zelda_apu_read(uint32_t adr) {
-  return g_zenv.player->port_to_snes[adr & 0x3];
-}
-
-void ZeldaRenderAudio(int16 *audio_buffer, int samples, int channels) {
-  ZeldaApuLock();
-  ZeldaPopApuState();
-  SpcPlayer_GenerateSamples(g_zenv.player);
-  dsp_getSamples(g_zenv.player->dsp, audio_buffer, samples, channels);
-  if (g_msu_player.f && channels == 2)
-    MsuPlayer_Mix(&g_msu_player, audio_buffer, samples);
-  ZeldaApuUnlock();
-}
-
-bool ZeldaIsMusicPlaying() {
-  if (g_msu_player.state != kMsuState_Idle) {
-    return g_msu_player.state != kMsuState_FinishedPlaying;
-  } else {
-    return g_zenv.player->port_to_snes[0] != 0;
-  }
-}
-
-void ZeldaRestoreMusicAfterLoad_Locked(bool is_reset) {
-  // Restore spc variables from the ram dump.
-  SpcPlayer_CopyVariablesFromRam(g_zenv.player);
-  // This is not stored in the snapshot
-  g_zenv.player->timer_cycles = 0;
-
-  // Restore input ports state
-  SpcPlayer *spc_player = g_zenv.player;
-  memcpy(spc_player->input_ports, &spc_player->ram[0x410], 4);
-  memcpy(g_apu_write.ports, spc_player->input_ports, 4);
-
-  if (is_reset) {
-    SpcPlayer_Initialize(g_zenv.player);
-  }
-
-  MsuPlayer *mp = &g_msu_player;
-  if (mp->enabled) {
-    mp->volume = 0.0;
-    MsuPlayer_Open(mp, (music_unk1 == 0xf1) ? ((MsuPlayerResumeInfo*)msu_resume_info)->orig_track : 
-                   music_unk1, true);
-
-    // If resuming in the middle of a transition, then override
-    // the volume with that of the transition.
-    if (last_music_control >= 0xf1 && last_music_control <= 0xf3) {
-      uint8 target = kVolumeTransitionTarget[last_music_control - 0xf1];
-      if (target != msu_volume) {
-        float f = kVolumeTransitionTargetFloat[3] * (1.0f / 255);
-        mp->volume = msu_volume * f;
-        mp->volume_target = target * f;
-        mp->volume_step = kVolumeTransitionStepFloat[last_music_control - 0xf1];
-      }
-    }
-
-    if (g_msu_player.state)
-      zelda_apu_write(APUI00, 0xf0);  // pause spc player
-  }
-  ZeldaResetApuQueue();
-}
-
-void ZeldaSaveMusicStateToRam_Locked() {
-  SpcPlayer_CopyVariablesToRam(g_zenv.player);
-  // SpcPlayer.input_ports is not saved to the SpcPlayer ram by SpcPlayer_CopyVariablesToRam,
-  // in any case, we want to save the most recently written data, and that might still
-  // be in the queue. 0x410 is a free memory location in the SPC ram, so store it there.
-  SpcPlayer *spc_player = g_zenv.player;
-  memcpy(&spc_player->ram[0x410], g_apu_write.ports, 4);
-
-  msu_volume = g_msu_player.volume * 255;
-  memcpy(msu_resume_info, &g_msu_player.resume_info, sizeof(g_msu_player.resume_info));
-}
-
-void ZeldaEnableMsu(uint8 enable) {
-  g_msu_player.volume = 1.0f;
-  g_msu_player.enabled = enable;
-  if (enable & kMsuEnabled_Opuz) {
-    if (g_config.audio_freq != 48000)
-      fprintf(stderr, "Warning: MSU Opuz requires: AudioFreq = 48000\n");
-  } else if (enable) {
-    if (g_config.audio_freq != 44100)
-      fprintf(stderr, "Warning: MSU requires: AudioFreq = 44100\n");
-  }
-
-  float volscale = g_config.msuvolume * (1.0f / 255 / 100);
-  float stepscale = g_config.msuvolume * (60.0f / 256 / 100) / g_config.audio_freq;
-  for (size_t i = 0; i != countof(kVolumeTransitionStepFloat); i++) {
-    kVolumeTransitionStepFloat[i] = kVolumeTransitionStep[i] * stepscale;
-    kVolumeTransitionTargetFloat[i] = kVolumeTransitionTarget[i] * volscale;
-  }
-}
-
-void LoadSongBank(const uint8 *p) {  // 808888
-  ZeldaApuLock();
-  SpcPlayer_Upload(g_zenv.player, p);
-  ZeldaApuUnlock();
-}
--- a/audio.h
+++ /dev/null
@@ -1,20 +1,0 @@
-#ifndef ZELDA3_AUDIO_H_
-#define ZELDA3_AUDIO_H_
-
-#include "types.h"
-
-// Things for msu
-bool ZeldaIsPlayingMusicTrack(uint8 track);
-bool ZeldaIsPlayingMusicTrackWithBug(uint8 track);
-void ZeldaPlayMsuAudioTrack(uint8 track);
-bool ZeldaIsMusicPlaying();
-
-void ZeldaEnableMsu(uint8 enable);
-
-void ZeldaRenderAudio(int16 *audio_buffer, int samples, int channels);
-void ZeldaDiscardUnusedAudioFrames();
-void ZeldaRestoreMusicAfterLoad_Locked(bool is_reset);
-void ZeldaSaveMusicStateToRam_Locked();
-void ZeldaPushApuState();
-
-#endif  // ZELDA3_AUDIO_H_
--- a/config.c
+++ /dev/null
@@ -1,529 +1,0 @@
-#include "config.h"
-#include "types.h"
-#include <stdio.h>
-#include <string.h>
-#include <SDL.h>
-#include "features.h"
-#include "util.h"
-
-enum {
-  kKeyMod_ScanCode = 0x200,
-  kKeyMod_Alt = 0x400,
-  kKeyMod_Shift = 0x800,
-  kKeyMod_Ctrl = 0x1000,
-};
-
-Config g_config;
-
-#define REMAP_SDL_KEYCODE(key) ((key) & SDLK_SCANCODE_MASK ? kKeyMod_ScanCode : 0) | (key) & (kKeyMod_ScanCode - 1)
-#define _(x) REMAP_SDL_KEYCODE(x)
-#define S(x) REMAP_SDL_KEYCODE(x) | kKeyMod_Shift
-#define A(x) REMAP_SDL_KEYCODE(x) | kKeyMod_Alt
-#define C(x) REMAP_SDL_KEYCODE(x) | kKeyMod_Ctrl
-#define N 0
-static const uint16 kDefaultKbdControls[kKeys_Total] = {
-  0,
-  // Controls
-  _(SDLK_UP), _(SDLK_DOWN), _(SDLK_LEFT), _(SDLK_RIGHT), _(SDLK_RSHIFT), _(SDLK_RETURN), _(SDLK_x), _(SDLK_z), _(SDLK_s), _(SDLK_a), _(SDLK_c), _(SDLK_v),
-  // LoadState
-  _(SDLK_F1), _(SDLK_F2), _(SDLK_F3), _(SDLK_F4), _(SDLK_F5), _(SDLK_F6), _(SDLK_F7), _(SDLK_F8), _(SDLK_F9), _(SDLK_F10), N, N, N, N, N, N, N, N, N, N,
-  // SaveState
-  S(SDLK_F1), S(SDLK_F2), S(SDLK_F3), S(SDLK_F4), S(SDLK_F5), S(SDLK_F6), S(SDLK_F7), S(SDLK_F8), S(SDLK_F9), S(SDLK_F10), N, N, N, N, N, N, N, N, N, N,
-  // Replay State
-  C(SDLK_F1), C(SDLK_F2), C(SDLK_F3), C(SDLK_F4), C(SDLK_F5), C(SDLK_F6), C(SDLK_F7), C(SDLK_F8), C(SDLK_F9), C(SDLK_F10), N, N, N, N, N, N, N, N, N, N,
-  // Load Ref State
-  N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N,
-  // Replay Ref State
-  N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N,
-  // CheatLife, CheatKeys, CheatEquipment, CheatWalkThroughWalls
-  _(SDLK_w), _(SDLK_o), S(SDLK_w), C(SDLK_e),
-  // ClearKeyLog, StopReplay, Fullscreen, Reset, Pause, PauseDimmed, Turbo, ReplayTurbo, WindowBigger, WindowSmaller, DisplayPerf, ToggleRenderer
-  _(SDLK_k), _(SDLK_l), A(SDLK_RETURN), C(SDLK_r), S(SDLK_p), _(SDLK_p), _(SDLK_TAB), _(SDLK_t), N, N, _(SDLK_f), _(SDLK_r),
-};
-#undef _
-#undef A
-#undef C
-#undef S
-#undef N
-
-typedef struct KeyNameId {
-  const char *name;
-  uint16 id, size;
-} KeyNameId;
-
-#define M(n) {#n, kKeys_##n, kKeys_##n##_Last - kKeys_##n + 1}
-#define S(n) {#n, kKeys_##n, 1}
-static const KeyNameId kKeyNameId[] = {
-  {"Null", kKeys_Null, 65535},
-  M(Controls), M(Load), M(Save), M(Replay), M(LoadRef), M(ReplayRef),
-  S(CheatLife), S(CheatKeys), S(CheatEquipment), S(CheatWalkThroughWalls),
-  S(ClearKeyLog), S(StopReplay), S(Fullscreen), S(Reset),
-  S(Pause), S(PauseDimmed), S(Turbo), S(ReplayTurbo), S(WindowBigger), S(WindowSmaller), S(VolumeUp), S(VolumeDown), S(DisplayPerf), S(ToggleRenderer),
-};
-#undef S
-#undef M
-typedef struct KeyMapHashEnt {
-  uint16 key, cmd, next;
-} KeyMapHashEnt;
-
-static uint16 keymap_hash_first[255];
-static KeyMapHashEnt *keymap_hash;
-static int keymap_hash_size;
-static bool has_keynameid[countof(kKeyNameId)];
-
-static bool KeyMapHash_Add(uint16 key, uint16 cmd) {
-  if ((keymap_hash_size & 0xff) == 0) {
-    if (keymap_hash_size > 10000)
-      Die("Too many keys");
-    keymap_hash = realloc(keymap_hash, sizeof(KeyMapHashEnt) * (keymap_hash_size + 256));
-  }
-  int i = keymap_hash_size++;
-  KeyMapHashEnt *ent = &keymap_hash[i];
-  ent->key = key;
-  ent->cmd = cmd;
-  ent->next = 0;
-  int j = (uint32)key % 255;
-
-  uint16 *cur = &keymap_hash_first[j];
-  while (*cur) {
-    KeyMapHashEnt *ent = &keymap_hash[*cur - 1];
-    if (ent->key == key)
-      return false;
-    cur = &ent->next;
-  }
-  *cur = i + 1;
-  return true;
-}
-
-static int KeyMapHash_Find(uint16 key) {
-  int i = keymap_hash_first[key % 255];
-  while (i) {
-    KeyMapHashEnt *ent = &keymap_hash[i - 1];
-    if (ent->key == key)
-      return ent->cmd;
-    i = ent->next;
-  }
-  return 0;
-}
-
-int FindCmdForSdlKey(SDL_Keycode code, SDL_Keymod mod) {
-  if (code & ~(SDLK_SCANCODE_MASK | 0x1ff))
-    return 0;
-  int key = 0;
-  if (code != SDLK_LALT && code != SDLK_RALT)
-    key |=  mod & KMOD_ALT ? kKeyMod_Alt : 0;
-  if (code != SDLK_LCTRL && code != SDLK_RCTRL)
-    key |= mod & KMOD_CTRL ? kKeyMod_Ctrl : 0;
-  if (code != SDLK_LSHIFT && code != SDLK_RSHIFT)
-    key |= mod & KMOD_SHIFT ? kKeyMod_Shift : 0;
-  key |= REMAP_SDL_KEYCODE(code);
-  return KeyMapHash_Find(key);
-}
-
-static void ParseKeyArray(char *value, int cmd, int size) {
-  char *s;
-  int i = 0;
-  for (; i < size && (s = NextDelim(&value, ',')) != NULL; i++, cmd += (cmd != 0)) {
-    if (*s == 0)
-      continue;
-    int key_with_mod = 0;
-    for (;;) {
-      if (StringStartsWithNoCase(s, "Shift+")) {
-        key_with_mod |= kKeyMod_Shift, s += 6;
-      } else if (StringStartsWithNoCase(s, "Ctrl+")) {
-        key_with_mod |= kKeyMod_Ctrl, s += 5;
-      } else if (StringStartsWithNoCase(s, "Alt+")) {
-        key_with_mod |= kKeyMod_Alt, s += 4;
-      } else {
-        break;
-      }
-    }
-    SDL_Keycode key = SDL_GetKeyFromName(s);
-    if (key == SDLK_UNKNOWN) {
-      fprintf(stderr, "Unknown key: '%s'\n", s);
-      continue;
-    }
-    if (!KeyMapHash_Add(key_with_mod | REMAP_SDL_KEYCODE(key), cmd))
-      fprintf(stderr, "Duplicate key: '%s'\n", s);
-  }
-}
-
-typedef struct GamepadMapEnt {
-  uint32 modifiers;
-  uint16 cmd, next;
-} GamepadMapEnt;
-
-static uint16 joymap_first[kGamepadBtn_Count];
-static GamepadMapEnt *joymap_ents;
-static int joymap_size;
-static bool has_joypad_controls;
-
-static int CountBits32(uint32 n) {
-  int count = 0;
-  for (; n != 0; count++)
-    n &= (n - 1);
-  return count;
-}
-
-static void GamepadMap_Add(int button, uint32 modifiers, uint16 cmd) {
-  if ((joymap_size & 0xff) == 0) {
-    if (joymap_size > 1000)
-      Die("Too many joypad keys");
-    joymap_ents = realloc(joymap_ents, sizeof(GamepadMapEnt) * (joymap_size + 64));
-    if (!joymap_ents) Die("realloc failure");
-  }
-  uint16 *p = &joymap_first[button];
-  // Insert it as early as possible but before after any entry with more modifiers.
-  int cb = CountBits32(modifiers);
-  while (*p && cb < CountBits32(joymap_ents[*p - 1].modifiers))
-    p = &joymap_ents[*p - 1].next;
-  int i = joymap_size++;
-  GamepadMapEnt *ent = &joymap_ents[i];
-  ent->modifiers = modifiers;
-  ent->cmd = cmd;
-  ent->next = *p;
-  *p = i + 1;
-}
-
-int FindCmdForGamepadButton(int button, uint32 modifiers) {
-  GamepadMapEnt *ent;
-  for(int e = joymap_first[button]; e != 0; e = ent->next) {
-    ent = &joymap_ents[e - 1];
-    if ((modifiers & ent->modifiers) == ent->modifiers)
-      return ent->cmd;
-  }
-  return 0;
-}
-
-static int ParseGamepadButtonName(const char **value) {
-  const char *s = *value;
-  // Longest substring first
-  static const char *const kGamepadKeyNames[] = {
-    "Back", "Guide", "Start", "L3", "R3",
-    "L1", "R1", "DpadUp", "DpadDown", "DpadLeft", "DpadRight", "L2", "R2",
-    "Lb", "Rb", "A", "B", "X", "Y"
-  };
-  static const uint8 kGamepadKeyIds[] = {
-    kGamepadBtn_Back, kGamepadBtn_Guide, kGamepadBtn_Start, kGamepadBtn_L3, kGamepadBtn_R3,
-    kGamepadBtn_L1, kGamepadBtn_R1, kGamepadBtn_DpadUp, kGamepadBtn_DpadDown, kGamepadBtn_DpadLeft, kGamepadBtn_DpadRight, kGamepadBtn_L2, kGamepadBtn_R2,
-    kGamepadBtn_L1, kGamepadBtn_R1, kGamepadBtn_A, kGamepadBtn_B, kGamepadBtn_X, kGamepadBtn_Y,
-  };
-  for (size_t i = 0; i != countof(kGamepadKeyNames); i++) {
-    const char *r = StringStartsWithNoCase(s, kGamepadKeyNames[i]);
-    if (r) {
-      *value = r;
-      return kGamepadKeyIds[i];
-    }
-  }
-  return kGamepadBtn_Invalid;
-}
-
-static const uint8 kDefaultGamepadCmds[] = {
-  kGamepadBtn_DpadUp, kGamepadBtn_DpadDown, kGamepadBtn_DpadLeft, kGamepadBtn_DpadRight, kGamepadBtn_Back, kGamepadBtn_Start,
-  kGamepadBtn_B, kGamepadBtn_A, kGamepadBtn_Y, kGamepadBtn_X, kGamepadBtn_L1, kGamepadBtn_R1,
-};
-
-static void ParseGamepadArray(char *value, int cmd, int size) {
-  char *s;
-  int i = 0;
-  for (; i < size && (s = NextDelim(&value, ',')) != NULL; i++, cmd += (cmd != 0)) {
-    if (*s == 0)
-      continue;
-    uint32 modifiers = 0;
-    const char *ss = s;
-    for (;;) {
-      int button = ParseGamepadButtonName(&ss);
-      if (button == kGamepadBtn_Invalid) BAD: {
-        fprintf(stderr, "Unknown gamepad button: '%s'\n", s);
-        break;
-      }
-      while (*ss == ' ' || *ss == '\t') ss++;
-      if (*ss == '+') {
-        ss++;
-        modifiers |= 1 << button;
-      } else if (*ss == 0) {
-        GamepadMap_Add(button, modifiers, cmd);
-        break;
-      } else
-        goto BAD;
-    }
-  }
-}
-
-static void RegisterDefaultKeys() {
-  for (int i = 1; i < countof(kKeyNameId); i++) {
-    if (!has_keynameid[i]) {
-      int size = kKeyNameId[i].size, k = kKeyNameId[i].id;
-      for (int j = 0; j < size; j++, k++)
-        KeyMapHash_Add(kDefaultKbdControls[k], k);
-    }
-  }
-  if (!has_joypad_controls) {
-    for (int i = 0; i < countof(kDefaultGamepadCmds); i++)
-      GamepadMap_Add(kDefaultGamepadCmds[i], 0, kKeys_Controls + i);
-  }
-}
-
-static int GetIniSection(const char *s) {
-  if (StringEqualsNoCase(s, "[KeyMap]"))
-    return 0;
-  if (StringEqualsNoCase(s, "[Graphics]"))
-    return 1;
-  if (StringEqualsNoCase(s, "[Sound]"))
-    return 2;
-  if (StringEqualsNoCase(s, "[General]"))
-    return 3;
-  if (StringEqualsNoCase(s, "[Features]"))
-    return 4;
-  if (StringEqualsNoCase(s, "[GamepadMap]"))
-    return 5;
-  return -1;
-}
-
-bool ParseBool(const char *value, bool *result) {
-  bool rv = false;
-  switch (*value++ | 32) {
-  case '0': if (*value == 0) break; return false;
-  case 'f': if (StringEqualsNoCase(value, "alse")) break; return false;
-  case 'n': if (StringEqualsNoCase(value, "o")) break; return false;
-  case 'o':
-    rv = (*value | 32) == 'n';
-    if (StringEqualsNoCase(value, rv ? "n" : "ff")) break;
-    return false;
-  case '1': rv = true; if (*value == 0) break; return false;
-  case 'y': rv = true; if (StringEqualsNoCase(value, "es")) break; return false;
-  case 't': rv = true; if (StringEqualsNoCase(value, "rue")) break; return false;
-  default: return false;
-  }
-  if (result) {
-    *result = rv;
-    return true;
-  }
-  return rv;
-}
-
-static bool ParseBoolBit(const char *value, uint32 *data, uint32 mask) {
-  bool tmp;
-  if (!ParseBool(value, &tmp))
-    return false;
-  *data = *data & ~mask | (tmp ? mask : 0);
-  return true;
-}
-
-static bool HandleIniConfig(int section, const char *key, char *value) {
-  if (section == 0) {
-    for (int i = 0; i < countof(kKeyNameId); i++) {
-      if (StringEqualsNoCase(key, kKeyNameId[i].name)) {
-        has_keynameid[i] = true;
-        ParseKeyArray(value, kKeyNameId[i].id, kKeyNameId[i].size);
-        return true;
-      }
-    }
-  } else if (section == 5) {
-    for (int i = 0; i < countof(kKeyNameId); i++) {
-      if (StringEqualsNoCase(key, kKeyNameId[i].name)) {
-        if (i == 1)
-          has_joypad_controls = true;
-        ParseGamepadArray(value, kKeyNameId[i].id, kKeyNameId[i].size);
-        return true;
-      }
-    }
-  } else if (section == 1) {
-    if (StringEqualsNoCase(key, "WindowSize")) {
-      char *s;
-      if (StringEqualsNoCase(value, "Auto")){
-        g_config.window_width  = 0;
-        g_config.window_height = 0;
-        return true;
-      }
-      while ((s = NextDelim(&value, 'x')) != NULL) {
-        if(g_config.window_width == 0) {
-          g_config.window_width = atoi(s);
-        } else {
-          g_config.window_height = atoi(s);
-          return true;
-        }
-      }
-    } else if (StringEqualsNoCase(key, "EnhancedMode7")) {
-      return ParseBool(value, &g_config.enhanced_mode7);
-    } else if (StringEqualsNoCase(key, "NewRenderer")) {
-      return ParseBool(value, &g_config.new_renderer);
-    } else if (StringEqualsNoCase(key, "IgnoreAspectRatio")) {
-      return ParseBool(value, &g_config.ignore_aspect_ratio);
-    } else if (StringEqualsNoCase(key, "Fullscreen")) {
-      g_config.fullscreen = (uint8)strtol(value, (char**)NULL, 10);
-      return true;
-    } else if (StringEqualsNoCase(key, "WindowScale")) {
-      g_config.window_scale = (uint8)strtol(value, (char**)NULL, 10);
-      return true;
-    } else if (StringEqualsNoCase(key, "OutputMethod")) {
-      g_config.output_method = StringEqualsNoCase(value, "SDL-Software") ? kOutputMethod_SDLSoftware :
-                               StringEqualsNoCase(value, "OpenGL") ? kOutputMethod_OpenGL : 
-                               StringEqualsNoCase(value, "OpenGL ES") ? kOutputMethod_OpenGL_ES :
-                                                                        kOutputMethod_SDL;
-      return true;
-    } else if (StringEqualsNoCase(key, "LinearFiltering")) {
-      return ParseBool(value, &g_config.linear_filtering);
-    } else if (StringEqualsNoCase(key, "NoSpriteLimits")) {
-      return ParseBool(value, &g_config.no_sprite_limits);
-    } else if (StringEqualsNoCase(key, "LinkGraphics")) {
-      g_config.link_graphics = value;
-      return true;
-    } else if (StringEqualsNoCase(key, "Shader")) {
-      g_config.shader = *value ? value : NULL;
-      return true;
-    } else if (StringEqualsNoCase(key, "DimFlashes")) {
-      return ParseBoolBit(value, &g_config.features0, kFeatures0_DimFlashes);
-    }
-  } else if (section == 2) {
-    if (StringEqualsNoCase(key, "EnableAudio")) {
-      return ParseBool(value, &g_config.enable_audio);
-    } else if (StringEqualsNoCase(key, "AudioFreq")) {
-      g_config.audio_freq = (uint16)strtol(value, (char**)NULL, 10);
-      return true;
-    } else if (StringEqualsNoCase(key, "AudioChannels")) {
-      g_config.audio_channels = (uint8)strtol(value, (char**)NULL, 10);
-      return true;
-    } else if (StringEqualsNoCase(key, "AudioSamples")) {
-      g_config.audio_samples = (uint16)strtol(value, (char**)NULL, 10);
-      return true;
-    } else if (StringEqualsNoCase(key, "EnableMSU")) {
-        if (StringEqualsNoCase(value, "opuz"))
-        g_config.enable_msu = kMsuEnabled_Opuz;
-      else if (StringEqualsNoCase(value, "deluxe"))
-        g_config.enable_msu = kMsuEnabled_MsuDeluxe;
-      else if (StringEqualsNoCase(value, "deluxe-opuz"))
-        g_config.enable_msu = kMsuEnabled_MsuDeluxe | kMsuEnabled_Opuz;
-      else 
-        return ParseBool(value, (bool*)&g_config.enable_msu);
-      return true;
-    } else if (StringEqualsNoCase(key, "MSUPath")) {
-      g_config.msu_path = value;
-      return true;
-    } else if (StringEqualsNoCase(key, "MSUVolume")) {
-      g_config.msuvolume = atoi(value);
-      return true;
-    } else if (StringEqualsNoCase(key, "ResumeMSU")) {
-      return ParseBool(value, &g_config.resume_msu);
-    }
-  } else if (section == 3) {
-    if (StringEqualsNoCase(key, "Autosave")) {
-      g_config.autosave = (bool)strtol(value, (char**)NULL, 10);
-      return true;
-    } else if (StringEqualsNoCase(key, "ExtendedAspectRatio")) {
-      const char* s;
-      int h = 224;
-      bool nospr = false, novis = false;
-      // todo: make it not depend on the order
-      while ((s = NextDelim(&value, ',')) != NULL) {
-        if (strcmp(s, "extend_y") == 0)
-          h = 240, g_config.extend_y = true;
-        else if (strcmp(s, "16:9") == 0)
-          g_config.extended_aspect_ratio = (h * 16 / 9 - 256) / 2;
-        else if (strcmp(s, "16:10") == 0)
-          g_config.extended_aspect_ratio = (h * 16 / 10 - 256) / 2;
-        else if (strcmp(s, "18:9") == 0)
-          g_config.extended_aspect_ratio = (h * 18 / 9 - 256) / 2;
-        else if (strcmp(s, "4:3") == 0)
-          g_config.extended_aspect_ratio = 0;
-        else if (strcmp(s, "unchanged_sprites") == 0)
-          nospr = true;
-        else if (strcmp(s, "no_visual_fixes") == 0)
-          novis = true;
-        else
-          return false;
-      }
-      if (g_config.extended_aspect_ratio && !nospr)
-        g_config.features0 |= kFeatures0_ExtendScreen64;
-      if (g_config.extended_aspect_ratio && !novis)
-        g_config.features0 |= kFeatures0_WidescreenVisualFixes;
-      return true;
-    } else if (StringEqualsNoCase(key, "DisplayPerfInTitle")) {
-      return ParseBool(value, &g_config.display_perf_title);
-    } else if (StringEqualsNoCase(key, "DisableFrameDelay")) {
-      return ParseBool(value, &g_config.disable_frame_delay);
-    } else if (StringEqualsNoCase(key, "Language")) {
-      g_config.language = value;
-      return true;
-    }
-  } else if (section == 4) {
-    if (StringEqualsNoCase(key, "ItemSwitchLR")) {
-      return ParseBoolBit(value, &g_config.features0, kFeatures0_SwitchLR);
-    } else if (StringEqualsNoCase(key, "ItemSwitchLRLimit")) {
-      return ParseBoolBit(value, &g_config.features0, kFeatures0_SwitchLRLimit);
-    } else if (StringEqualsNoCase(key, "TurnWhileDashing")) {
-      return ParseBoolBit(value, &g_config.features0, kFeatures0_TurnWhileDashing);
-    } else if (StringEqualsNoCase(key, "MirrorToDarkworld")) {
-      return ParseBoolBit(value, &g_config.features0, kFeatures0_MirrorToDarkworld);
-    } else if (StringEqualsNoCase(key, "CollectItemsWithSword")) {
-      return ParseBoolBit(value, &g_config.features0, kFeatures0_CollectItemsWithSword);
-    } else if (StringEqualsNoCase(key, "BreakPotsWithSword")) {
-      return ParseBoolBit(value, &g_config.features0, kFeatures0_BreakPotsWithSword);
-    } else if (StringEqualsNoCase(key, "DisableLowHealthBeep")) {
-      return ParseBoolBit(value, &g_config.features0, kFeatures0_DisableLowHealthBeep);
-    } else if (StringEqualsNoCase(key, "SkipIntroOnKeypress")) {
-      return ParseBoolBit(value, &g_config.features0, kFeatures0_SkipIntroOnKeypress);
-    } else if (StringEqualsNoCase(key, "ShowMaxItemsInYellow")) {
-      return ParseBoolBit(value, &g_config.features0, kFeatures0_ShowMaxItemsInYellow);
-    } else if (StringEqualsNoCase(key, "MoreActiveBombs")) {
-      return ParseBoolBit(value, &g_config.features0, kFeatures0_MoreActiveBombs);
-    } else if (StringEqualsNoCase(key, "CarryMoreRupees")) {
-      return ParseBoolBit(value, &g_config.features0, kFeatures0_CarryMoreRupees);
-    } else if (StringEqualsNoCase(key, "MiscBugFixes")) {
-      return ParseBoolBit(value, &g_config.features0, kFeatures0_MiscBugFixes);
-    } else if (StringEqualsNoCase(key, "GameChangingBugFixes")) {
-      return ParseBoolBit(value, &g_config.features0, kFeatures0_GameChangingBugFixes);
-    } else if (StringEqualsNoCase(key, "CancelBirdTravel")) {
-      return ParseBoolBit(value, &g_config.features0, kFeatures0_CancelBirdTravel);
-    }
-  }
-  return false;
-}
-
-static bool ParseOneConfigFile(const char *filename, int depth) {
-  char *filedata = (char*)ReadWholeFile(filename, NULL), *p;
-  if (!filedata)
-    return false;
-  
-  int section = -2;
-  g_config.memory_buffer = filedata;
-
-  for (int lineno = 1; (p = NextLineStripComments(&filedata)) != NULL; lineno++) {
-    if (*p == 0)
-      continue; // empty line
-    if (*p == '[') {
-      section = GetIniSection(p);
-      if (section < 0)
-        fprintf(stderr, "%s:%d: Invalid .ini section %s\n", filename, lineno, p);
-    } else if (*p == '!' && SkipPrefix(p + 1, "include ")) {
-      char *tt = p + 8;
-      char *new_filename = ReplaceFilenameWithNewPath(filename, NextPossiblyQuotedString(&tt));
-      if (depth > 10 || !ParseOneConfigFile(new_filename, depth + 1))
-        fprintf(stderr, "Warning: Unable to read %s\n", new_filename);
-      free(new_filename);
-    } else if (section == -2) {
-      fprintf(stderr, "%s:%d: Expecting [section]\n", filename, lineno);
-    } else {
-      char *v = SplitKeyValue(p);
-      if (v == NULL) {
-        fprintf(stderr, "%s:%d: Expecting 'key=value'\n", filename, lineno);
-        continue;
-      }
-      if (section >= 0 && !HandleIniConfig(section, p, v))
-        fprintf(stderr, "%s:%d: Can't parse '%s'\n", filename, lineno, p);
-    }
-  }
-  return true;
-}
-
-void ParseConfigFile(const char *filename) {
-  g_config.msuvolume = 100;  // default msu volume, 100%
-
-  if (filename != NULL || !ParseOneConfigFile("zelda3.user.ini", 0)) {
-    if (filename == NULL)
-      filename = "zelda3.ini";
-    if (!ParseOneConfigFile(filename, 0))
-      fprintf(stderr, "Warning: Unable to read config file %s\n", filename);
-  }
-  RegisterDefaultKeys();
-}
--- a/config.h
+++ /dev/null
@@ -1,110 +1,0 @@
-#pragma once
-#include "types.h"
-#include <SDL_keycode.h>
-
-enum {
-  kKeys_Null,
-  kKeys_Controls,
-  kKeys_Controls_Last = kKeys_Controls + 11,
-  kKeys_Load,
-  kKeys_Load_Last = kKeys_Load + 19,
-  kKeys_Save,
-  kKeys_Save_Last = kKeys_Save + 19,
-  kKeys_Replay,
-  kKeys_Replay_Last = kKeys_Replay + 19,
-  kKeys_LoadRef,
-  kKeys_LoadRef_Last = kKeys_LoadRef + 19,
-  kKeys_ReplayRef,
-  kKeys_ReplayRef_Last = kKeys_ReplayRef + 19,
-  kKeys_CheatLife,
-  kKeys_CheatKeys,
-  kKeys_CheatEquipment,
-  kKeys_CheatWalkThroughWalls,
-  kKeys_ClearKeyLog,
-  kKeys_StopReplay,
-  kKeys_Fullscreen,
-  kKeys_Reset,
-  kKeys_Pause,
-  kKeys_PauseDimmed,
-  kKeys_Turbo,
-  kKeys_ReplayTurbo,
-  kKeys_WindowBigger,
-  kKeys_WindowSmaller,
-  kKeys_DisplayPerf,
-  kKeys_ToggleRenderer,
-  kKeys_VolumeUp,
-  kKeys_VolumeDown,
-  kKeys_Total,
-};
-
-enum {
-  kOutputMethod_SDL,
-  kOutputMethod_SDLSoftware,
-  kOutputMethod_OpenGL,
-  kOutputMethod_OpenGL_ES,
-};
-
-typedef struct Config {
-  int window_width;
-  int window_height;
-  bool enhanced_mode7;
-  bool new_renderer;
-  bool ignore_aspect_ratio;
-  uint8 fullscreen;
-  uint8 window_scale;
-  bool enable_audio;
-  bool linear_filtering;
-  uint8 output_method;
-  uint16 audio_freq;
-  uint8 audio_channels;
-  uint16 audio_samples;
-  bool autosave;
-  uint8 extended_aspect_ratio;
-  bool extend_y;
-  bool no_sprite_limits;
-  bool display_perf_title;
-  uint8 enable_msu;
-  bool resume_msu;
-  bool disable_frame_delay;
-  uint8 msuvolume;
-  uint32 features0;
-
-  const char *link_graphics;
-  char *memory_buffer;
-  const char *shader;
-  const char *msu_path;
-  const char *language;
-} Config;
-
-enum {
-  kMsuEnabled_Msu = 1,
-  kMsuEnabled_MsuDeluxe = 2,
-  kMsuEnabled_Opuz = 4,
-};
-enum {
-  kGamepadBtn_Invalid = -1,
-  kGamepadBtn_A,
-  kGamepadBtn_B,
-  kGamepadBtn_X,
-  kGamepadBtn_Y,
-  kGamepadBtn_Back,
-  kGamepadBtn_Guide,
-  kGamepadBtn_Start,
-  kGamepadBtn_L3,
-  kGamepadBtn_R3,
-  kGamepadBtn_L1,
-  kGamepadBtn_R1,
-  kGamepadBtn_DpadUp,
-  kGamepadBtn_DpadDown,
-  kGamepadBtn_DpadLeft,
-  kGamepadBtn_DpadRight,
-  kGamepadBtn_L2,
-  kGamepadBtn_R2,
-  kGamepadBtn_Count,
-};
-
-extern Config g_config;
-
-void ParseConfigFile(const char *filename);
-int FindCmdForSdlKey(SDL_Keycode code, SDL_Keymod mod);
-int FindCmdForGamepadButton(int button, uint32 modifiers);
--- a/dungeon.c
+++ /dev/null
@@ -1,8796 +1,0 @@
-#include "zelda_rtl.h"
-#include "snes/snes_regs.h"
-#include "variables.h"
-#include "dungeon.h"
-#include "nmi.h"
-#include "hud.h"
-#include "load_gfx.h"
-#include "overworld.h"
-#include "sprite.h"
-#include "ancilla.h"
-#include "ending.h"
-#include "player.h"
-#include "misc.h"
-#include "player_oam.h"
-#include "tagalong.h"
-#include "messaging.h"
-#include "assets.h"
-
-// todo: move to config
-static const uint16 kBossRooms[] = {
-  200, 51, 7,
-  32,
-  6, 90, 41, 144, 222, 164, 172,
-  13
-};
-static const uint8 kDungeonExit_From[12] = {200, 51, 7, 32, 6, 90, 41, 144, 222, 164, 172, 13};
-static const uint8 kDungeonExit_To[12] = {201, 99, 119, 32, 40, 74, 89, 152, 14, 214, 219, 13};
-static const uint16 kObjectSubtype1Params[] = {
-  0x3d8, 0x2e8, 0x2f8, 0x328, 0x338, 0x400, 0x410, 0x388, 0x390, 0x420, 0x42a, 0x434, 0x43e, 0x448, 0x452, 0x45c,
-  0x466, 0x470, 0x47a, 0x484, 0x48e, 0x498, 0x4a2, 0x4ac, 0x4b6, 0x4c0, 0x4ca, 0x4d4, 0x4de, 0x4e8, 0x4f2, 0x4fc,
-  0x506, 0x598, 0x600, 0x63c, 0x63c, 0x63c, 0x63c, 0x63c, 0x642, 0x64c, 0x652, 0x658, 0x65e, 0x664, 0x66a, 0x688,
-  0x694, 0x6a8, 0x6a8, 0x6a8, 0x6c8, 0x0, 0x78a, 0x7aa, 0xe26, 0x84a, 0x86a, 0x882, 0x8ca, 0x85a, 0x8fa, 0x91a,
-  0x920, 0x92a, 0x930, 0x936, 0x93c, 0x942, 0x948, 0x94e, 0x96c, 0x97e, 0x98e, 0x902, 0x99e, 0x9d8, 0x9d8, 0x9d8,
-  0x9fa, 0x156c, 0x1590, 0x1d86, 0x0, 0xa14, 0xa24, 0xa54, 0xa54, 0xa84, 0xa84, 0x14dc, 0x1500, 0x61e, 0xe52, 0x600,
-  0x3d8, 0x2c8, 0x2d8, 0x308, 0x318, 0x3e0, 0x3f0, 0x378, 0x380, 0x5fa, 0x648, 0x64a, 0x670, 0x67c, 0x6a8, 0x6a8,
-  0x6a8, 0x6c8, 0x0, 0x7aa, 0x7ca, 0x84a, 0x89a, 0x8b2, 0x90a, 0x926, 0x928, 0x912, 0x9f8, 0x1d7e, 0x0, 0xa34,
-  0xa44, 0xa54, 0xa6c, 0xa84, 0xa9c, 0x1524, 0x1548, 0x85a, 0x606, 0xe52, 0x5fa, 0x6a0, 0x6a2, 0xb12, 0xb14, 0x9b0,
-  0xb46, 0xb56, 0x1f52, 0x1f5a, 0x288, 0xe82, 0x1df2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
-  0x3d8, 0x3d8, 0x3d8, 0x3d8, 0x5aa, 0x5b2, 0x5b2, 0x5b2, 0x5b2, 0xe0, 0xe0, 0xe0, 0xe0, 0x110, 0x0, 0x0,
-  0x6a4, 0x6a6, 0xae6, 0xb06, 0xb0c, 0xb16, 0xb26, 0xb36, 0x1f52, 0x1f5a, 0x288, 0xeba, 0xe82, 0x1df2, 0x0, 0x0,
-  0x3d8, 0x510, 0x5aa, 0x5aa, 0x0, 0x168, 0xe0, 0x158, 0x100, 0x110, 0x178, 0x72a, 0x72a, 0x72a, 0x75a, 0x670,
-  0x670, 0x130, 0x148, 0x72a, 0x72a, 0x72a, 0x75a, 0xe0, 0x110, 0xf0, 0x110, 0x0, 0xab4, 0x8da, 0xade, 0x188,
-  0x1a0, 0x1b0, 0x1c0, 0x1d0, 0x1e0, 0x1f0, 0x200, 0x120, 0x2a8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
-  0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
-};
-static const uint16 kObjectSubtype2Params[] = {
-  0xb66, 0xb86, 0xba6, 0xbc6, 0xc66, 0xc86, 0xca6, 0xcc6, 0xbe6, 0xc06, 0xc26, 0xc46, 0xce6, 0xd06, 0xd26, 0xd46,
-  0xd66, 0xd7e, 0xd96, 0xdae, 0xdc6, 0xdde, 0xdf6, 0xe0e, 0x398, 0x3a0, 0x3a8, 0x3b0, 0xe32, 0xe26, 0xea2, 0xe9a,
-  0xeca, 0xed2, 0xede, 0xede, 0xf1e, 0xf3e, 0xf5e, 0xf6a, 0xef6, 0xf72, 0xf92, 0xfa2, 0xfa2, 0x1088, 0x10a8, 0x10a8,
-  0x10c8, 0x10c8, 0x10c8, 0x10c8, 0xe52, 0x1108, 0x1108, 0x12a8, 0x1148, 0x1160, 0x1178, 0x1190, 0x1458, 0x1488, 0x2062, 0x2086,
-};
-static const uint16 kObjectSubtype3Params[] = {
-  0x1614, 0x162c, 0x1654, 0xa0e, 0xa0c, 0x9fc, 0x9fe, 0xa00, 0xa02, 0xa04, 0xa06, 0xa08, 0xa0a, 0x0, 0xa10, 0xa12,
-  0x1dda, 0x1de2, 0x1dd6, 0x1dea, 0x15fc, 0x1dfa, 0x1df2, 0x1488, 0x1494, 0x149c, 0x14a4, 0x10e8, 0x10e8, 0x10e8, 0x11a8, 0x11c8,
-  0x11e8, 0x1208, 0x3b8, 0x3c0, 0x3c8, 0x3d0, 0x1228, 0x1248, 0x1268, 0x1288, 0x0, 0xe5a, 0xe62, 0x0, 0x0, 0xe82,
-  0xe8a, 0x14ac, 0x14c4, 0x10e8, 0x1614, 0x1614, 0x1614, 0x1614, 0x1614, 0x1614, 0x1cbe, 0x1cee, 0x1d1e, 0x1d4e, 0x1d8e, 0x1d96,
-  0x1d9e, 0x1da6, 0x1dae, 0x1db6, 0x1dbe, 0x1dc6, 0x1dce, 0x220, 0x260, 0x280, 0x1f3a, 0x1f62, 0x1f92, 0x1ff2, 0x2016, 0x1f42,
-  0xeaa, 0x1f4a, 0x1f52, 0x1f5a, 0x202e, 0x2062, 0x9b8, 0x9c0, 0x9c8, 0x9d0, 0xfa2, 0xfb2, 0xfc4, 0xff4, 0x1018, 0x1020,
-  0x15b4, 0x15d8, 0x20f6, 0xeba, 0x22e6, 0x22ee, 0x5da, 0x281e, 0x2ae0, 0x2d2a, 0x2f2a, 0x22f6, 0x2316, 0x232e, 0x2346, 0x235e,
-  0x2376, 0x23b6, 0x1e9a, 0x0, 0x2436, 0x149c, 0x24b6, 0x24e6, 0x2516, 0x1028, 0x1040, 0x1060, 0x1070, 0x1078, 0x1080, 0x0,
-};
-static const uint16 kDoorTypeSrcData[] = {
-  0x2716, 0x272e, 0x272e, 0x2746, 0x2746, 0x2746, 0x2746, 0x2746, 0x2746, 0x275e, 0x275e, 0x275e, 0x275e, 0x2776, 0x278e, 0x27a6,
-  0x27be, 0x27be, 0x27d6, 0x27d6, 0x27ee, 0x2806, 0x2806, 0x281e, 0x2836, 0x2836, 0x2836, 0x2836, 0x284e, 0x2866, 0x2866, 0x2866,
-  0x2866, 0x287e, 0x2896, 0x28ae, 0x28c6, 0x28de, 0x28f6, 0x28f6, 0x28f6, 0x290e, 0x2926, 0x2958, 0x2978, 0x2990, 0x2990, 0x2990,
-  0x2990, 0x29a8, 0x29c0, 0x29d8,
-};
-static const uint16 kDoorTypeSrcData2[] = {
-  0x29f0, 0x2a08, 0x2a08, 0x2a20, 0x2a20, 0x2a20, 0x2a20, 0x2a20, 0x2a20, 0x2a38, 0x2a38, 0x2a38, 0x2a38, 0x2a50, 0x2a68, 0x2a80,
-  0x2a98, 0x2a98, 0x2a98, 0x2a98, 0x2a98, 0x2ab0, 0x2ac8, 0x2ae0, 0x2af8, 0x2af8, 0x2af8, 0x2af8, 0x2b10, 0x2b28, 0x2b28, 0x2b28,
-  0x2b28, 0x2b40, 0x2b58, 0x2b70, 0x2b88, 0x2ba0, 0x2bb8, 0x2bb8, 0x2bb8, 0x2bd0, 0x2be8, 0x2c1a, 0x2c3a, 0x2c52, 0x2c6a, 0x2c6a,
-};
-static const uint16 kDoorTypeSrcData3[] = {
-  0x2c6a, 0x2c82, 0x2c82, 0x2c9a, 0x2c9a, 0x2c9a, 0x2c9a, 0x2c9a, 0x2c9a, 0x2cb2, 0x2cb2, 0x2cb2, 0x2cb2, 0x2cca, 0x2ce2, 0x2cfa,
-  0x2cfa, 0x2cfa, 0x2cfa, 0x2cfa, 0x2cfa, 0x2d12, 0x2d12, 0x2d2a, 0x2d42, 0x2d42, 0x2d42, 0x2d42, 0x2d5a, 0x2d72, 0x2d72, 0x2d72,
-  0x2d72, 0x2d8a, 0x2da2, 0x2dba, 0x2dd2, 0x2dea, 0x2e02, 0x2e02, 0x2e02, 0x2e1a, 0x2e32, 0x2e32, 0x2e52, 0x2e6a, 0x2e6a, 0x2e6a,
-};
-static const uint16 kDoorTypeSrcData4[] = {
-  0x2e6a, 0x2e82, 0x2e82, 0x2e9a, 0x2e9a, 0x2e9a, 0x2e9a, 0x2e9a, 0x2e9a, 0x2eb2, 0x2eb2, 0x2eb2, 0x2eb2, 0x2eca, 0x2ee2, 0x2efa,
-  0x2efa, 0x2efa, 0x2efa, 0x2efa, 0x2efa, 0x2f12, 0x2f12, 0x2f2a, 0x2f42, 0x2f42, 0x2f42, 0x2f42, 0x2f5a, 0x2f72, 0x2f72, 0x2f72,
-  0x2f72, 0x2f8a, 0x2fa2, 0x2fba, 0x2fd2, 0x2fea, 0x3002, 0x3002, 0x3002, 0x301a, 0x3032, 0x3032, 0x3052, 0x306a, 0x306a,
-};
-static const uint16 kDoorPositionToTilemapOffs_Up[] = { 0x21c, 0x23c, 0x25c, 0x39c, 0x3bc, 0x3dc, 0x121c, 0x123c, 0x125c, 0x139c, 0x13bc, 0x13dc };
-static const uint16 kDoorPositionToTilemapOffs_Down[] = { 0xd1c, 0xd3c, 0xd5c, 0xb9c, 0xbbc, 0xbdc, 0x1d1c, 0x1d3c, 0x1d5c, 0x1b9c, 0x1bbc, 0x1bdc };
-static const uint16 kDoorPositionToTilemapOffs_Left[] = { 0x784, 0xf84, 0x1784, 0x78a, 0xf8a, 0x178a, 0x7c4, 0xfc4, 0x17c4, 0x7ca, 0xfca, 0x17ca };
-static const uint16 kDoorPositionToTilemapOffs_Right[] = { 0x7b4, 0xfb4, 0x17b4, 0x7ae, 0xfae, 0x17ae, 0x7f4, 0xff4, 0x17f4, 0x7ee, 0xfee, 0x17ee };
-static const int8 kSpiralTab1[] = { 0, 1, 1, -1, 1, 1, 1, 1 };
-static const int8 kTeleportPitLevel1[] = { 0, 1, 1 };
-static const int8 kTeleportPitLevel2[] = { 0, 0, 1 };
-static const uint8 kDoorTypeRemap[] = {
-  0, 2, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 80, 0, 80, 80,
-  96, 98, 100, 102, 82, 90, 80, 82, 84, 86, 0, 80, 80, 0, 0, 0,
-  64, 88, 88, 0, 88, 88, 0, 0,
-};
-static const int8 kStaircaseTab2[] = {
-  12, 32, 48, 56, 72, -44, -40, -64, -64, -88, 12, 24, 40, 48, 64, -28,
-  -40, -56, -64, -80,
-};
-static const int8 kStaircaseTab3[] = { 4, -4, 4, -4 };
-static const int8 kStaircaseTab4[] = { 52, 52, 59, 58 };
-static const int8 kStaircaseTab5[] = { 32, -64, 32, -32 };
-static const uint8 kMovingWall_Sizes0[4] = { 5, 7, 11, 15 };
-static const uint8 kMovingWall_Sizes1[4] = { 8, 16, 24, 32 };
-static const uint8 kWatergateLayout[17] = {
-  0x1b, 0xa1, 0xc9,
-  0x51, 0xa1, 0xc9,
-  0x92, 0xa1, 0xc9,
-  0xa1, 0x33, 0xc9,
-  0xa1, 0x72, 0xc9,
-  0xff, 0xff,
-};
-static const uint16 kChestOpenMasks[] = { 0x100, 0x200, 0x400, 0x800, 0x1000, 0x2000 };
-const uint8 kLayoutQuadrantFlags[] = { 0xF, 0xF, 0xF, 0xF, 0xB, 0xB, 7, 7, 0xF, 0xB, 0xF, 7, 0xB, 0xF, 7, 0xF, 0xE, 0xD, 0xE, 0xD, 0xF, 0xF, 0xE, 0xD, 0xE, 0xD, 0xF, 0xF, 0xA, 9, 6, 5 };
-static const uint8 kQuadrantVisitingFlags[] = { 8, 4, 2, 1, 0xC, 0xC, 3, 3, 0xA, 5, 0xA, 5, 0xF, 0xF, 0xF, 0xF };
-#define XY(x, y) ((y)*64+(x))
-static const uint8 kDungeon_MinigameChestPrizes1[8] = {
-  0x40, 0x41, 0x34, 0x42, 0x43, 0x44, 0x27, 0x17
-};
-static const uint8 kDungeon_RupeeChestMinigamePrizes[32] = {
-  0x47, 0x34, 0x46, 0x34, 0x46, 0x46, 0x34, 0x47, 0x46, 0x47, 0x34, 0x46, 0x47, 0x34, 0x46, 0x47,
-  0x34, 0x47, 0x41, 0x47, 0x41, 0x41, 0x47, 0x34, 0x41, 0x34, 0x47, 0x41, 0x34, 0x47, 0x41, 0x34,
-};
-static const int8 kDungeon_QueryIfTileLiftable_x[4] = { 7, 7, -3, 16 };
-static const int8 kDungeon_QueryIfTileLiftable_y[4] = { 3, 24, 14, 14 };
-static const uint16 kDungeon_QueryIfTileLiftable_rv[16] = { 0x5252, 0x5050, 0x5454, 0x0, 0x2323 };
-static const uint16 kDoor_BlastWallUp_Dsts[] = { 0xd8a, 0xdaa, 0xdca, 0x2b6, 0xab6, 0x12b6 };
-#define adjacent_doors_flags (*(uint16*)(g_ram+0x1100))
-#define adjacent_doors ((uint16*)(g_ram+0x1110))
-static const DungPalInfo kDungPalinfos[41] = {
-  { 0,  0,  3,  1},
-  { 2,  0,  3,  1},
-  { 4,  0, 10,  1},
-  { 6,  0,  1,  7},
-  {10,  2,  2,  7},
-  { 4,  4,  3, 10},
-  {12,  5,  8, 20},
-  {14,  0,  3, 10},
-  { 2,  0, 15, 20},
-  {10,  2,  0,  7},
-  { 2,  0, 15, 12},
-  { 6,  0,  6,  7},
-  { 0,  0, 14, 18},
-  {18,  5,  5, 11},
-  {18,  0,  2, 12},
-  {16,  5, 10,  7},
-  {16,  0, 16, 12},
-  {22,  7,  2,  7},
-  {22,  0,  7, 15},
-  { 8,  0,  4, 12},
-  { 8,  0,  4,  9},
-  { 4,  0,  3,  1},
-  {20,  0,  4,  4},
-  {20,  0, 20, 12},
-  {24,  5,  7, 11},
-  {24,  6, 16, 12},
-  {26,  5,  8, 20},
-  {26,  2,  0,  7},
-  { 6,  0,  3, 10},
-  {28,  0,  3,  1},
-  {30,  0, 11, 17},
-  { 4,  0, 11, 17},
-  {14,  0,  0,  2},
-  {32,  8, 19, 13},
-  {10,  0,  3, 10},
-  {20,  0,  4,  4},
-  {26,  2,  2,  7},
-  {26, 10,  0,  0},
-  { 0,  0,  3,  2},
-  {14,  0,  3,  7},
-  {26,  5,  5, 11},
-};
-// these are not used by the code, but needed for the comparison with the real rom to work.
-static const uint8 kDungeon_DrawObjectOffsets_BG1[33] = {
-     0, 0x20, 0x7e,    2, 0x20, 0x7e,    4, 0x20, 0x7e,    6, 0x20, 0x7e, 0x80, 0x20, 0x7e, 0x82,
-  0x20, 0x7e, 0x84, 0x20, 0x7e, 0x86, 0x20, 0x7e,    0, 0x21, 0x7e, 0x80, 0x21, 0x7e,    0, 0x22,
-  0x7e,
-};
-static const uint8 kDungeon_DrawObjectOffsets_BG2[33] = {
-     0, 0x40, 0x7e,    2, 0x40, 0x7e,    4, 0x40, 0x7e,    6, 0x40, 0x7e, 0x80, 0x40, 0x7e, 0x82,
-  0x40, 0x7e, 0x84, 0x40, 0x7e, 0x86, 0x40, 0x7e,    0, 0x41, 0x7e, 0x80, 0x41, 0x7e,    0, 0x42,
-  0x7e,
-};
-static const uint16 kUploadBgSrcs[] = { 0x0, 0x1000, 0x0, 0x40, 0x40, 0x1040, 0x1000, 0x1040, 0x1000, 0x0, 0x40, 0x0, 0x1040, 0x40, 0x1040, 0x1000 };
-static const uint8 kUploadBgDsts[] = { 1, 5, 9, 13, 2, 6, 10, 14, 3, 7, 11, 15, 4, 8, 12, 16 };
-static const uint16 kTileAttrsByDoor[] = {
-  0x8080, 0x8484, 0x0, 0x101, 0x8484, 0x8e8e, 0x0, 0x0, 0x8888, 0x8e8e, 0x8080, 0x8080, 0x8282, 0x8080, 0x8080, 0x8080,
-  0x8080, 0x8080, 0x8080, 0x8080, 0x8282, 0x8e8e, 0x8080, 0x8282, 0x8080, 0x8080, 0x8080, 0x8282, 0x8282, 0x8080, 0x8080, 0x8080,
-  0x8484, 0x8484, 0x8686, 0x8888, 0x8686, 0x8686, 0x8080, 0x8080,
-};
-static PlayerHandlerFunc *const kDungeon_Effect_Handler[28] = {
-  &LayerEffect_Nothing,
-  &LayerEffect_Nothing,
-  &LayerEffect_Scroll,
-  &LayerEffect_WaterRapids,
-  &LayerEffect_Trinexx,
-  &LayerEffect_Agahnim2,
-  &LayerEffect_InvisibleFloor,
-  &LayerEffect_Ganon,
-};
-static const int16 kPushBlockMoveDistances[] = { -0x100, 0x100, -0x4, 0x4 };
-static HandlerFuncK *const kDungTagroutines[] = {
-  &Dung_TagRoutine_0x00,
-  &RoomTag_NorthWestTrigger,
-  &Dung_TagRoutine_0x2A,
-  &Dung_TagRoutine_0x2B,
-  &Dung_TagRoutine_0x2C,
-  &Dung_TagRoutine_0x2D,
-  &Dung_TagRoutine_0x2E,
-  &Dung_TagRoutine_0x2F,
-  &Dung_TagRoutine_0x30,
-  &RoomTag_QuadrantTrigger,
-  &RoomTag_RoomTrigger,
-  &RoomTag_NorthWestTrigger,
-  &Dung_TagRoutine_0x2A,
-  &Dung_TagRoutine_0x2B,
-  &Dung_TagRoutine_0x2C,
-  &Dung_TagRoutine_0x2D,
-  &Dung_TagRoutine_0x2E,
-  &Dung_TagRoutine_0x2F,
-  &Dung_TagRoutine_0x30,
-  &RoomTag_QuadrantTrigger,
-  &RoomTag_RoomTrigger_BlockDoor,
-  &RoomTag_PrizeTriggerDoorDoor,
-  &RoomTag_SwitchTrigger_HoldDoor,
-  &RoomTag_SwitchTrigger_ToggleDoor,
-  &RoomTag_WaterOff,
-  &RoomTag_WaterOn,
-  &RoomTag_WaterGate,
-  &Dung_TagRoutine_0x1B,
-  &RoomTag_MovingWall_East,
-  &RoomTag_MovingWall_West,
-  &RoomTag_MovingWallTorchesCheck,
-  &RoomTag_MovingWallTorchesCheck,
-  &RoomTag_Switch_ExplodingWall,
-  &RoomTag_Holes0,
-  &RoomTag_ChestHoles0,
-  &Dung_TagRoutine_0x23,
-  &RoomTag_Holes2,
-  &RoomTag_GetHeartForPrize,
-  &RoomTag_KillRoomBlock,
-  &RoomTag_TriggerChest,
-  &RoomTag_PullSwitchExplodingWall,
-  &RoomTag_NorthWestTrigger,
-  &Dung_TagRoutine_0x2A,
-  &Dung_TagRoutine_0x2B,
-  &Dung_TagRoutine_0x2C,
-  &Dung_TagRoutine_0x2D,
-  &Dung_TagRoutine_0x2E,
-  &Dung_TagRoutine_0x2F,
-  &Dung_TagRoutine_0x30,
-  &RoomTag_QuadrantTrigger,
-  &RoomTag_RoomTrigger,
-  &RoomTag_TorchPuzzleDoor,
-  &Dung_TagRoutine_0x34,
-  &Dung_TagRoutine_0x35,
-  &Dung_TagRoutine_0x36,
-  &Dung_TagRoutine_0x37,
-  &RoomTag_Agahnim,
-  &Dung_TagRoutine_0x39,
-  &Dung_TagRoutine_0x3A,
-  &Dung_TagRoutine_0x3B,
-  &RoomTag_PushBlockForChest,
-  &RoomTag_GanonDoor,
-  &RoomTag_TorchPuzzleChest,
-  &RoomTag_RekillableBoss,
-};
-static const uint16 kDoorAnimUpSrc[] = { 0x306a, 0x306a, 0x3082, 0x309a, 0x30b2 };
-static const uint16 kDoorAnimDownSrc[] = { 0x30b2, 0x30ca, 0x30e2, 0x30fa, 0x3112 };
-static const uint16 kDoorAnimLeftSrc[] = { 0x3112, 0x312a, 0x3142, 0x315a, 0x3172 };
-static const uint16 kDoorAnimRightSrc[] = { 0x3172, 0x318a, 0x31a2, 0x31ba, 0x31D2 };
-static PlayerHandlerFunc *const kDungeon_IntraRoomTrans[8] = {
-  &DungeonTransition_Subtile_PrepTransition,
-  &DungeonTransition_Subtile_ApplyFilter,
-  &DungeonTransition_Subtile_ResetShutters,
-  &DungeonTransition_ScrollRoom,
-  &DungeonTransition_FindSubtileLanding,
-  &Dungeon_IntraRoomTrans_State5,
-  &DungeonTransition_Subtile_ApplyFilter,
-  &DungeonTransition_Subtile_TriggerShutters,
-};
-static PlayerHandlerFunc *const kDungeon_InterRoomTrans[16] = {
-  &Module07_02_00_InitializeTransition,
-  &Module07_02_01_LoadNextRoom,
-  &Module07_02_FadedFilter,
-  &Dungeon_InterRoomTrans_State3,
-  &Dungeon_InterRoomTrans_State4,
-  &Dungeon_InterRoomTrans_notDarkRoom,
-  &Dungeon_InterRoomTrans_State4,
-  &Dungeon_InterRoomTrans_State7,
-  &DungeonTransition_ScrollRoom,
-  &Dungeon_InterRoomTrans_State9,
-  &Dungeon_InterRoomTrans_State10,
-  &Dungeon_InterRoomTrans_State9,
-  &Dungeon_InterRoomTrans_State12,
-  &Dungeon_InterRoomTrans_State13,
-  &Module07_02_FadedFilter,
-  &Dungeon_InterRoomTrans_State15,
-};
-static PlayerHandlerFunc *const kDungeon_Submodule_7_DownFloorTrans[18] = {
-  &Module07_07_00_HandleMusicAndResetRoom,
-  &ApplyPaletteFilter_bounce,
-  &Dungeon_InitializeRoomFromSpecial,
-  &DungeonTransition_TriggerBGC34UpdateAndAdvance,
-  &DungeonTransition_TriggerBGC56UpdateAndAdvance,
-  &DungeonTransition_LoadSpriteGFX,
-  &Module07_07_06_SyncBG1and2,
-  &Dungeon_InterRoomTrans_State4,
-  &Dungeon_InterRoomTrans_notDarkRoom,
-  &Dungeon_InterRoomTrans_State4,
-  &Dungeon_InterRoomTrans_notDarkRoom,
-  &Dungeon_InterRoomTrans_State4,
-  &Dungeon_InterRoomTrans_notDarkRoom,
-  &Dungeon_InterRoomTrans_State4,
-  &Dungeon_Staircase14,
-  &Module07_07_0F_FallingFadeIn,
-  &Module07_07_10_LandLinkFromFalling,
-  &Module07_07_11_CacheRoomAndSetMusic,
-};
-static PlayerHandlerFunc *const kWatergateFuncs[6] = {
-  &FloodDam_PrepTiles_init,
-  &Watergate_Main_State1,
-  &Watergate_Main_State1,
-  &Watergate_Main_State1,
-  &FloodDam_Expand,
-  &FloodDam_Fill,
-};
-static const int8 kSpiralStaircaseX[] = { -28, -28, 24, 24 };
-static const int8 kSpiralStaircaseY[] = { 16, -10, -10, -32 };
-static PlayerHandlerFunc *const kDungeon_SpiralStaircase[20] = {
-  &Module07_0E_00_InitPriorityAndScreens,
-  &Module07_0E_01_HandleMusicAndResetProps,
-  &Module07_0E_02_ApplyFilterIf,
-  &Dungeon_InitializeRoomFromSpecial,
-  &DungeonTransition_TriggerBGC34UpdateAndAdvance,
-  &DungeonTransition_TriggerBGC56UpdateAndAdvance,
-  &DungeonTransition_LoadSpriteGFX,
-  &Dungeon_SyncBackgroundsFromSpiralStairs,
-  &Dungeon_InterRoomTrans_State4,
-  &Dungeon_InterRoomTrans_notDarkRoom,
-  &Dungeon_InterRoomTrans_State4,
-  &Dungeon_SpiralStaircase11,
-  &Dungeon_SpiralStaircase12,
-  &Dungeon_SpiralStaircase11,
-  &Dungeon_SpiralStaircase12,
-  &Dungeon_DoubleApplyAndIncrementGrayscale,
-  &Dungeon_AdvanceThenSetBossMusicUnorthodox,
-  &Dungeon_SpiralStaircase17,
-  &Dungeon_SpiralStaircase18,
-  &Module07_0E_13_SetRoomAndLayerAndCache,
-};
-static PlayerHandlerFunc *const kDungeon_Submodule_F[2] = {
-  &Module07_0F_00_InitSpotlight,
-  &Module07_0F_01_OperateSpotlight,
-};
-static PlayerHandlerFunc *const kDungeon_StraightStaircase[2] = {
-  &Module07_10_00_InitStairs,
-  &Module07_10_01_ClimbStairs,
-};
-static PlayerHandlerFunc *const kDungeon_StraightStaircaseDown[2] = {
-  &Module07_08_00_InitStairs,
-  &Module07_08_01_ClimbStairs,
-};
-static PlayerHandlerFunc *const kDungeon_StraightStairs[19] = {
-  &Module07_11_00_PrepAndReset,
-  &Module07_11_01_FadeOut,
-  &Module07_11_02_LoadAndPrepRoom,
-  &Module07_11_03_FilterAndLoadBGChars,
-  &Module07_11_04_FilterDoBGAndResetSprites,
-  &Dungeon_SpiralStaircase11,
-  &Dungeon_SpiralStaircase12,
-  &Dungeon_SpiralStaircase11,
-  &Dungeon_SpiralStaircase12,
-  &Module07_11_09_LoadSpriteGraphics,
-  &Module07_11_0A_ScrollCamera,
-  &Module07_11_0B_PrepDestination,
-  &Dungeon_InterRoomTrans_State4,
-  &Dungeon_InterRoomTrans_notDarkRoom,
-  &Dungeon_InterRoomTrans_State4,
-  &Dungeon_DoubleApplyAndIncrementGrayscale,
-  &Module07_11_19_SetSongAndFilter,
-  &Module07_11_11_KeepSliding,
-  &ResetThenCacheRoomEntryProperties,
-};
-static PlayerHandlerFunc *const kDungeon_Teleport[15] = {
-  &ResetTransitionPropsAndAdvance_ResetInterface,
-  &Module07_15_01_ApplyMosaicAndFilter,
-  &Dungeon_InitializeRoomFromSpecial,
-  &DungeonTransition_LoadSpriteGFX,
-  &Module07_15_04_SyncRoomPropsAndBuildOverlay,
-  &Dungeon_InterRoomTrans_State4,
-  &Dungeon_InterRoomTrans_notDarkRoom,
-  &Dungeon_InterRoomTrans_State4,
-  &Dungeon_InterRoomTrans_notDarkRoom,
-  &Dungeon_InterRoomTrans_State4,
-  &Dungeon_InterRoomTrans_notDarkRoom,
-  &Dungeon_InterRoomTrans_State4,
-  &Dungeon_Staircase14,
-  &Module07_15_0E_FadeInFromWarp,
-  &Module07_15_0F_FinalizeAndCacheEntry,
-};
-static PlayerHandlerFunc *const kDungeonSubmodules[31] = {
-  &Module07_00_PlayerControl,
-  &Module07_01_SubtileTransition,
-  &Module07_02_SupertileTransition,
-  &Module07_03_OverlayChange,
-  &Module07_04_UnlockDoor,
-  &Module07_05_ControlShutters,
-  &Module07_06_FatInterRoomStairs,
-  &Module07_07_FallingTransition,
-  &Module07_08_NorthIntraRoomStairs,
-  &Module07_09_OpenCrackedDoor,
-  &Module07_0A_ChangeBrightness,
-  &Module07_0B_DrainSwampPool,
-  &Module07_0C_FloodSwampWater,
-  &Module07_0D_FloodDam,
-  &Module07_0E_SpiralStairs,
-  &Module07_0F_LandingWipe,
-  &Module07_10_SouthIntraRoomStairs,
-  &Module07_11_StraightInterroomStairs,
-  &Module07_11_StraightInterroomStairs,
-  &Module07_11_StraightInterroomStairs,
-  &Module07_14_RecoverFromFall,
-  &Module07_15_WarpPad,
-  &Module07_16_UpdatePegs,
-  &Module07_17_PressurePlate,
-  &Module07_18_RescuedMaiden,
-  &Module07_19_MirrorFade,
-  &Module07_1A_RoomDraw_OpenTriforceDoor_bounce,
-};
-const uint8 kDungAnimatedTiles[24] = {
-  0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5f, 0x5d, 0x5f, 0x5f, 0x5e, 0x5f, 0x5e, 0x5e, 0x5d,
-  0x5d, 0x5e, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d,
-};
-uint16 *DstoPtr(uint16 d) {
-  return (uint16 *)&(g_ram[dung_line_ptrs_row0 + d * 2]);
-}
-
-void Object_Fill_Nx1(int n, const uint16 *src, uint16 *dst) {
-  int t = src[0];
-  do *dst++ = t; while (--n);
-}
-
-void Object_Draw_5x4(const uint16 *src, uint16 *dst) {
-  int n = 5;
-  do {
-    dst[XY(0, 0)] = src[0];
-    dst[XY(1, 0)] = src[1];
-    dst[XY(2, 0)] = src[2];
-    dst[XY(3, 0)] = src[3];
-    dst += XY(0, 1), src += 4;
-  } while (--n);
-}
-
-void Object_Draw_4x2_BothBgs(const uint16 *src, uint16 dsto) {
-  dung_bg1[dsto + XY(0, 0)] = dung_bg2[dsto + XY(0, 0)] = src[0];
-  dung_bg1[dsto + XY(1, 0)] = dung_bg2[dsto + XY(1, 0)] = src[1];
-  dung_bg1[dsto + XY(2, 0)] = dung_bg2[dsto + XY(2, 0)] = src[2];
-  dung_bg1[dsto + XY(3, 0)] = dung_bg2[dsto + XY(3, 0)] = src[3];
-  dung_bg1[dsto + XY(0, 1)] = dung_bg2[dsto + XY(0, 1)] = src[4];
-  dung_bg1[dsto + XY(1, 1)] = dung_bg2[dsto + XY(1, 1)] = src[5];
-  dung_bg1[dsto + XY(2, 1)] = dung_bg2[dsto + XY(2, 1)] = src[6];
-  dung_bg1[dsto + XY(3, 1)] = dung_bg2[dsto + XY(3, 1)] = src[7];
-}
-
-void Object_ChestPlatform_Helper(const uint16 *src, int dsto) {
-  dung_bg2[dsto] = src[0];
-  int n = src[3];
-  for (int i = dung_draw_width_indicator; i--; dsto++)
-    dung_bg2[1 + dsto] = n;
-
-  dung_bg2[1 + dsto] = src[6];
-  dung_bg2[2 + dsto] = dung_bg2[3 + dsto] = dung_bg2[4 + dsto] = dung_bg2[5 + dsto] = src[9];
-
-  dung_bg2[6 + dsto] = src[12];
-  n = src[15];
-  for (int i = dung_draw_width_indicator; i--; dsto++)
-    dung_bg2[7 + dsto] = n;
-
-  dung_bg2[7 + dsto] = src[18];
-}
-
-void Object_Hole(const uint16 *src, uint16 *dst) {
-  Object_SizeAtoAplus15(4);
-  int w = dung_draw_width_indicator;
-  for (int i = 0; i < w; i++)
-    Object_Fill_Nx1(w, src, dst + XY(0, i));
-  // fill top/bottom
-  src = SrcPtr(0x63c);
-  dst[XY(0, 0)] = src[0];
-  Object_Fill_Nx1(w - 2, src + 1, dst + XY(1, 0));
-  dst[XY(w - 1, 0)] = src[2];
-
-  dst[XY(0, w - 1)] = src[3];
-  Object_Fill_Nx1(w - 2, src + 4, dst + XY(1, w - 1));
-  dst[XY(w - 1, w - 1)] = src[5];
-
-  // fill left/right edge
-  src = SrcPtr(0x648);
-  for (int i = 1; i < w - 1; i++) {
-    dst[XY(0, i)] = src[0];
-    dst[XY(w - 1, i)] = src[1];
-  }
-}
-
-// dsto is half the value of Y
-void LoadType1ObjectSubtype1(uint8 idx, uint16 *dst, uint16 dsto) {
-  uint16 param1 = kObjectSubtype1Params[idx];
-  const uint16 *src = SrcPtr(param1);
-  int n;
-
-  switch (idx) {
-  case 0x0:  // RoomDraw_Rightwards2x2_1to15or32 - Ceiling
-  case 0xb8: case 0xb9: // B8 -  Blue Switch Block [L-R]
-    RoomDraw_GetObjectSize_1to15or32();
-    do {
-      RoomDraw_Rightwards2x2(src, dst), dst += XY(2, 0);
-    } while (--dung_draw_width_indicator);
-    break;
-  case 0x1: case 0x2:  // RoomDraw_Rightwards2x4_1to15or26 - [N]Wall Horz: [L-R]
-  case 0xb6: case 0xb7:  // B6 -  [N]Wall Decor: 1/2 [L-R]
-    RoomDraw_GetObjectSize_1to15or26();
-    do {
-      RoomDraw_Object_Nx4(2, src, dst), dst += XY(2, 0);
-    } while (--dung_draw_width_indicator);
-    break;
-
-  case 0x3: case 0x4:  // RoomDraw_Rightwards2x4spaced4_1to16 - 03 -  [N]Wall Horz: (LOW) [L-R]
-    RoomDraw_GetObjectSize_1to16();
-    do {
-      dung_bg1[dsto + XY(0, 0)] = dung_bg2[dsto + XY(0, 0)] = src[0];
-      dung_bg1[dsto + XY(0, 1)] = dung_bg2[dsto + XY(0, 1)] = src[1];
-      dung_bg1[dsto + XY(0, 2)] = dung_bg2[dsto + XY(0, 2)] = src[2];
-      dung_bg1[dsto + XY(0, 3)] = dung_bg2[dsto + XY(0, 3)] = src[3];
-      dung_bg1[dsto + XY(1, 0)] = dung_bg2[dsto + XY(1, 0)] = src[4];
-      dung_bg1[dsto + XY(1, 1)] = dung_bg2[dsto + XY(1, 1)] = src[5];
-      dung_bg1[dsto + XY(1, 2)] = dung_bg2[dsto + XY(1, 2)] = src[6];
-      dung_bg1[dsto + XY(1, 3)] = dung_bg2[dsto + XY(1, 3)] = src[7];
-      dsto += XY(2, 0);
-    } while (--dung_draw_width_indicator);
-    break;
-
-  case 0x5: case 0x6: // RoomDraw_Rightwards2x4spaced4_1to16_BothBG - 05 -  [N]Wall Column [L-R]
-    RoomDraw_GetObjectSize_1to16();
-    do {
-      RoomDraw_Object_Nx4(2, src, dst), dst += XY(6, 0);
-    } while (--dung_draw_width_indicator);
-    break;
-
-  case 0x7: case 0x8: case 0x53: // RoomDraw_Rightwards2x2_1to16 - 07 -  [N]Wall Pit [L-R]
-    RoomDraw_GetObjectSize_1to16();
-    do {
-      RoomDraw_Rightwards2x2(src, dst), dst += XY(2, 0);
-    } while (--dung_draw_width_indicator);
-    break;
-
-  case 0x9: case 0x0c: case 0x0d: case 0x10: case 0x11: case 0x14:  // 09 -  / Wall Wood Bot (HIGH) [NW]
-    Object_SizeAtoAplus15(6);
-    do {
-      RoomDraw_DrawObject2x2and1(src, dst), dst += XY(1, -1);
-    } while (--dung_draw_width_indicator);
-    break;
-
-  case 0x0a: case 0x0b: case 0x0e: case 0x0f: case 0x12: case 0x13:  // 12 -  \ Wall Tile2 Bot (HIGH) [SW]
-    Object_SizeAtoAplus15(6);
-    do {
-      RoomDraw_DrawObject2x2and1(src, dst), dst += XY(1, 1);
-    } while (--dung_draw_width_indicator);
-    break;
-
-  case 0x15: case 0x18: case 0x19: case 0x1C: case 0x1D: case 0x20:  // 15 -  / Wall Tile Top (LOW)[NW]
-    Object_SizeAtoAplus15(6);
-    do {
-      dung_bg1[dsto + XY(0, 0)] = dung_bg2[dsto + XY(0, 0)] = src[0];
-      dung_bg1[dsto + XY(0, 1)] = dung_bg2[dsto + XY(0, 1)] = src[1];
-      dung_bg1[dsto + XY(0, 2)] = dung_bg2[dsto + XY(0, 2)] = src[2];
-      dung_bg1[dsto + XY(0, 3)] = dung_bg2[dsto + XY(0, 3)] = src[3];
-      dung_bg1[dsto + XY(0, 4)] = dung_bg2[dsto + XY(0, 4)] = src[4];
-      dsto -= 63;
-    } while (--dung_draw_width_indicator);
-    break;
-
-  case 0x16: case 0x17: case 0x1A: case 0x1B: case 0x1E: case 0x1F:  // 16 -  \ Wall Tile Top (LOW)[SW]
-    Object_SizeAtoAplus15(6);
-    do {
-      dung_bg1[dsto + XY(0, 0)] = dung_bg2[dsto + XY(0, 0)] = src[0];
-      dung_bg1[dsto + XY(0, 1)] = dung_bg2[dsto + XY(0, 1)] = src[1];
-      dung_bg1[dsto + XY(0, 2)] = dung_bg2[dsto + XY(0, 2)] = src[2];
-      dung_bg1[dsto + XY(0, 3)] = dung_bg2[dsto + XY(0, 3)] = src[3];
-      dung_bg1[dsto + XY(0, 4)] = dung_bg2[dsto + XY(0, 4)] = src[4];
-      dsto += 65;
-    } while (--dung_draw_width_indicator);
-    break;
-
-  case 0x21:  // 21 -  Mini Stairs [L-R]
-    dung_draw_width_indicator = (dung_draw_width_indicator << 2 | dung_draw_height_indicator) * 2 + 1;
-    RoomDraw_1x3_rightwards(2, src, dst), dst += XY(2, 0);
-    do {
-      RoomDraw_1x3_rightwards(1, src + 3, dst), dst += XY(1, 0);
-    } while (--dung_draw_width_indicator);
-    RoomDraw_1x3_rightwards(1, src + 6, dst);
-    break;
-
-  case 0x22: { // 22 -  Horz: Rail Thin [L-R]
-    Object_SizeAtoAplus15(2);
-    if ((dst[0] & 0x3ff) != 0xe2)
-      dst[0] = src[0];
-    n = src[1];
-    do *++dst = n; while (--dung_draw_width_indicator);
-    dst[1] = src[2];
-    break;
-  }
-  case 0x23: case 0x24: case 0x25: case 0x26: case 0x27: case 0x28:
-  case 0x29: case 0x2a: case 0x2b: case 0x2c: case 0x2d: case 0x2e:  // 23 -  Pit [N]Edge [L-R]
-  case 0x3f: case 0x40: case 0x41: case 0x42: case 0x43: case 0x44:  // 3F -  Water Edge [L-R]
-  case 0x45: case 0x46: case 0xb3: case 0xb4:
-    RoomDraw_GetObjectSize_1to16();
-    n = dst[0] & 0x3ff;
-    if (n != 0x1db && n != 0x1a6 && n != 0x1dd && n != 0x1fc)
-      dst[0] = src[0];
-    n = src[1];
-    do *++dst = n; while (--dung_draw_width_indicator);
-    dst[1] = src[2];
-    break;
-
-  case 0x2f: // 2F -  Rail Wall [L-R]
-    Object_SizeAtoAplus15(10);
-    n = *src++;
-    if ((dst[0] & 0x3ff) != 0xe2) {
-      dst[XY(0, 0)] = src[0];
-      dst[XY(1, 0)] = src[1];
-      dst[XY(1, 1)] = dst[XY(0, 1)] = n;
-      dst += 2;
-    }
-    src += 2;
-    do {
-      dst[XY(0, 0)] = src[0];
-      dst[XY(0, 1)] = n;
-    } while (dst++, --dung_draw_width_indicator);
-    src++;
-    dst[XY(0, 0)] = src[0];
-    dst[XY(1, 0)] = src[1];
-    dst[XY(1, 1)] = dst[XY(0, 1)] = n;
-    break;
-
-  case 0x30:  // 30 -  Rail Wall [L-R]
-    Object_SizeAtoAplus15(10);
-    n = *src++;
-    if ((dst[XY(0, 1)] & 0x3ff) != 0xe2) {
-      dst[XY(0, 0)] = dst[XY(1, 0)] = n;
-      dst[XY(0, 1)] = src[0];
-      dst[XY(1, 1)] = src[1];
-      dst += 2;
-    }
-    src += 2;
-    do {
-      dst[XY(0, 0)] = n;
-      dst[XY(0, 1)] = src[0];
-    } while (dst++, --dung_draw_width_indicator);
-    src++;
-    dst[XY(0, 0)] = dst[XY(1, 0)] = n;
-    dst[XY(0, 1)] = src[0];
-    dst[XY(1, 1)] = src[1];
-    break;
-  case 0x31: case 0x32:  // 31 -  Unused -empty
-  case 0x35: case 0x54: case 0x57:case 0x58:case 0x59:case 0x5A:
-    break;
-  case 0x33:  // 33 -  Red Carpet Floor [L-R]
-  case 0xb2: case 0xba:  // B2 -  Floor? [L-R]
-    RoomDraw_GetObjectSize_1to16();
-    do {
-      RoomDraw_4x4(src, dst), dst += XY(4, 0);
-    } while (--dung_draw_width_indicator);
-    break;
-  case 0x34:  // 34 -  Red Carpet Floor Trim [L-R]
-    Object_SizeAtoAplus15(4);
-    n = src[0];
-    do *dst++ = n; while (--dung_draw_width_indicator);
-    break;
-  case 0x36: case 0x37: // 36 -  [N]Curtain [L-R]
-    RoomDraw_GetObjectSize_1to16();
-    do {
-      RoomDraw_4x4(src, dst), dst += XY(6, 0);
-    } while (--dung_draw_width_indicator);
-    break;
-  case 0x38:  // 38 -  Statue [L-R]
-    src = (uint16 *)((uint8 *)src - param1 + 0xe26);
-    RoomDraw_GetObjectSize_1to16();
-    do {
-      RoomDraw_1x3_rightwards(2, src, dst), dst += XY(4, 0);
-    } while (--dung_draw_width_indicator);
-    break;
-  case 0x39: case 0x3d: // 39 -  Column [L-R]
-    RoomDraw_GetObjectSize_1to16();
-    do {
-      RoomDraw_Object_Nx4(2, src, dst), dst += XY(6, 0);
-    } while (--dung_draw_width_indicator);
-    break;
-  case 0x3a: case 0x3b: // 3A -  [N]Wall Decor: [L-R]
-    RoomDraw_GetObjectSize_1to16();
-    do {
-      RoomDraw_1x3_rightwards(4, src, dst), dst += XY(8, 0);
-    } while (--dung_draw_width_indicator);
-    break;
-  case 0x3c:  // 3C -  Double Chair [L-R]
-    RoomDraw_GetObjectSize_1to16();
-    do {
-      const uint16 *src = SrcPtr(0x8ca);
-      RoomDraw_Rightwards2x2(src + 0, dst);
-      RoomDraw_Rightwards2x2(src + 4, dst + XY(0, 6));
-      dst += 4;
-    } while (--dung_draw_width_indicator);
-    break;
-  case 0x3e: case 0x4b: // 3E -  [N]Wall Column [L-R]
-    RoomDraw_GetObjectSize_1to16();
-    do {
-      RoomDraw_Rightwards2x2(src, dst), dst += XY(14, 0);
-    } while (--dung_draw_width_indicator);
-    break;
-  case 0x47:  // 47 -  Unused Waterfall [L-R]
-    RoomDraw_GetObjectSize_1to16();
-    dung_draw_width_indicator <<= 1;
-    dst = RoomDraw_DrawObject2x2and1(src, dst) + 1;
-    do {
-      RoomDraw_DrawObject2x2and1(src + 5, dst);
-    } while (dst++, --dung_draw_width_indicator);
-    RoomDraw_DrawObject2x2and1(src + 10, dst);
-    break;
-  case 0x48:
-    RoomDraw_GetObjectSize_1to16();
-    dung_draw_width_indicator <<= 1;
-    RoomDraw_1x3_rightwards(1, src, dst), dst += XY(1, 0);
-    do {
-      dst[XY(0, 0)] = src[3];
-      dst[XY(0, 1)] = src[4];
-      dst[XY(0, 2)] = src[5];
-    } while (dst++, --dung_draw_width_indicator);
-    RoomDraw_1x3_rightwards(1, src + 6, dst);
-    break;
-  case 0x49: case 0x4A:  // RoomDraw_RightwardsFloorTile4x2_1to16      ; 49 -  N/A
-    RoomDraw_GetObjectSize_1to16();
-    RoomDraw_Downwards4x2VariableSpacing(4, src, dst);
-    break;
-  case 0x4c:  // 4C -  Bar [L-R]
-    RoomDraw_GetObjectSize_1to16();
-    dung_draw_width_indicator <<= 1;
-    dst = RoomDraw_RightwardBarSegment(src, dst) + 1;
-    do {
-      dst = RoomDraw_RightwardBarSegment(src + 3, dst) + 1;
-    } while (--dung_draw_width_indicator);
-    dst = RoomDraw_RightwardBarSegment(src + 6, dst) + 1;
-    break;
-
-  case 0x4d: case 0x4e: case 0x4f:  // 4C -  Bar [L-R]
-    RoomDraw_GetObjectSize_1to16();
-    RoomDraw_Object_Nx4(1, src, dst), dst += XY(1, 0);
-    do {
-      RoomDraw_Object_Nx4(2, src + 4, dst), dst += XY(2, 0);
-    } while (--dung_draw_width_indicator);
-    RoomDraw_RightwardShelfEnd(src + 12, dst);
-    break;
-
-  case 0x50:   // 50 -  Cane Ride [L-R]
-    Object_SizeAtoAplus15(2);
-    n = src[0];
-    do *dst++ = n; while (--dung_draw_width_indicator);
-    break;
-
-  case 0x51: case 0x52: // 51 -  [N]Canon Hole [L-R]
-  case 0x5B: case 0x5C:
-    RoomDraw_GetObjectSize_1to16();
-    RoomDraw_1x3_rightwards(2, src, dst), dst += XY(2, 0);
-    while (--dung_draw_width_indicator)
-      RoomDraw_1x3_rightwards(2, src + 6, dst), dst += XY(2, 0);
-    RoomDraw_1x3_rightwards(2, src + 12, dst);
-    break;
-
-  case 0x55: case 0x56:  // 55 -  [N]Wall Torches [L-R]
-    RoomDraw_GetObjectSize_1to16();
-    RoomDraw_Downwards4x2VariableSpacing(12, src, dst);
-    break;
-
-  case 0x5D:  // 5D -  Large Horz: Rail [L-R]
-    RoomDraw_GetObjectSize_1to16();
-    dung_draw_width_indicator++;
-    RoomDraw_1x3_rightwards(2, src, dst), dst += XY(2, 0);
-    do {
-      RoomDraw_RightwardBarSegment(src + 6, dst), dst += XY(1, 0);
-    } while (--dung_draw_width_indicator);
-    RoomDraw_1x3_rightwards(2, src + 9, dst);
-    break;
-
-  case 0x5E:  // 5E -  Block [L-R]
-  case 0xbb:  // BB -  N/A
-    RoomDraw_GetObjectSize_1to16();
-    do {
-      RoomDraw_Rightwards2x2(src, dst), dst += XY(4, 0);
-    } while (--dung_draw_width_indicator);
-    break;
-
-  case 0x5f: { // 5F -  Long Horz: Rail [L-R]
-    Object_SizeAtoAplus15(21);
-    if ((dst[0] & 0x3ff) != 0xe2)
-      dst[0] = src[0];
-    n = src[1];
-    do *++dst = n; while (--dung_draw_width_indicator);
-    dst[1] = src[2];
-    break;
-  }
-
-  case 0x60:  // 60 -  Ceiling [U-D]
-  case 0x92: case 0x93: // 92 -  Blue Peg Block [U-D]
-    RoomDraw_GetObjectSize_1to15or32();
-    do {
-      RoomDraw_Rightwards2x2(src, dst), dst += XY(0, 2);
-    } while (--dung_draw_width_indicator);
-    break;
-
-  case 0x61: case 0x62: case 0x90: case 0x91:  // 61 -  [W]Wall Vert: [U-D]
-    RoomDraw_GetObjectSize_1to15or26();
-    RoomDraw_Downwards4x2VariableSpacing(2 * 64, src, dst);
-    break;
-
-  case 0x63:
-  case 0x64:  // RoomDraw_Downwards4x2_1to16_BothBG - 63 -  [W]Wall Vert: (LOW) [U-D]
-    RoomDraw_GetObjectSize_1to16();
-    do {
-      dung_bg1[dsto + XY(0, 0)] = dung_bg2[dsto + XY(0, 0)] = src[0];
-      dung_bg1[dsto + XY(1, 0)] = dung_bg2[dsto + XY(1, 0)] = src[1];
-      dung_bg1[dsto + XY(2, 0)] = dung_bg2[dsto + XY(2, 0)] = src[2];
-      dung_bg1[dsto + XY(3, 0)] = dung_bg2[dsto + XY(3, 0)] = src[3];
-      dung_bg1[dsto + XY(0, 1)] = dung_bg2[dsto + XY(0, 1)] = src[4];
-      dung_bg1[dsto + XY(1, 1)] = dung_bg2[dsto + XY(1, 1)] = src[5];
-      dung_bg1[dsto + XY(2, 1)] = dung_bg2[dsto + XY(2, 1)] = src[6];
-      dung_bg1[dsto + XY(3, 1)] = dung_bg2[dsto + XY(3, 1)] = src[7];
-      dsto += XY(0, 2);
-    } while (--dung_draw_width_indicator);
-    break;
-
-  case 0x65: case 0x66:  // 65 -  [W]Wall Column [U-D]
-    RoomDraw_GetObjectSize_1to16();
-    RoomDraw_Downwards4x2VariableSpacing(6 * 64, src, dst);
-    break;
-
-  case 0x67: case 0x68: // 67 -  [W]Wall Pit [U-D]
-  case 0x7d:            // 7D -  Pipe Ride [U-D]
-    RoomDraw_GetObjectSize_1to16();
-    do {
-      RoomDraw_Rightwards2x2(src, dst), dst += XY(0, 2);
-    } while (--dung_draw_width_indicator);
-    break;
-  case 0x69:  // 69 -  Vert: Rail Thin [U-D]
-    Object_SizeAtoAplus15(2);
-    if ((dst[0] & 0x3ff) != 0xe3)
-      dst[0] = src[0];
-    n = src[1];
-    do { dst += 64; *dst = n; } while (--dung_draw_width_indicator);
-    dst[64] = src[2];
-    break;
-  case 0x6a: case 0x6b: // 6A -  [W]Pit Edge [U-D]
-  case 0x79: case 0x7a: // 79 -  Water Edge [U-D]
-  case 0x8d: case 0x8e: // 8D -  [W]Edge [U-D]
-    RoomDraw_GetObjectSize_1to16();
-    do {
-      dst[0] = src[0], dst += XY(0, 1);
-    } while (--dung_draw_width_indicator);
-    break;
-  case 0x6c: // 6C -  [W]Rail Wall [U-D]
-    Object_SizeAtoAplus15(10);
-    n = *src++;
-    if ((dst[0] & 0x3ff) != 0xe3) {
-      dst[XY(0, 0)] = src[0];
-      dst[XY(0, 1)] = src[1];
-      dst[XY(1, 0)] = dst[XY(1, 1)] = n;
-      dst += XY(0, 2);
-    }
-    src += 2;
-    do {
-      dst[XY(0, 0)] = src[0];
-      dst[XY(1, 0)] = n;
-      dst += XY(0, 1);
-    } while (--dung_draw_width_indicator);
-    src += 1;
-    dst[XY(0, 0)] = src[0];
-    dst[XY(0, 1)] = src[1];
-    dst[XY(1, 0)] = dst[XY(1, 1)] = n;
-    break;
-  case 0x6d:   // 6D -  [E]Rail Wall [U-D]
-    Object_SizeAtoAplus15(10);
-    n = *src++;
-    if ((dst[XY(1, 0)] & 0x3ff) != 0xe3) {
-      dst[XY(0, 0)] = dst[XY(0, 1)] = n;
-      dst[XY(1, 0)] = src[0];
-      dst[XY(1, 1)] = src[1];
-      dst += XY(0, 2);
-    }
-    src += 2;
-    do {
-      dst[XY(0, 0)] = n;
-      dst[XY(1, 0)] = src[0];
-      dst += XY(0, 1);
-    } while (--dung_draw_width_indicator);
-    src += 1;
-    dst[XY(0, 0)] = dst[XY(0, 1)] = n;
-    dst[XY(1, 0)] = src[0];
-    dst[XY(1, 1)] = src[1];
-    break;
-  case 0x6e: case 0x6f: // unused
-  case 0x72: case 0x7e:
-    break;
-  case 0x70: case 0x94:  // 70 -  Red Floor/Wire Floor [U-D]
-    RoomDraw_GetObjectSize_1to16();
-    do {
-      RoomDraw_4x4(src, dst), dst += XY(0, 4);
-    } while (--dung_draw_width_indicator);
-    break;
-  case 0x71:  // 71 -  Red Carpet Floor Trim [U-D]
-    Object_SizeAtoAplus15(4);
-    do {
-      *dst = src[0], dst += XY(0, 1);
-    } while (--dung_draw_width_indicator);
-    break;
-  case 0x73: case 0x74:  // 73 -  [W]Curtain [U-D]
-    RoomDraw_GetObjectSize_1to16();
-    do {
-      RoomDraw_4x4(src, dst), dst += XY(0, 6);
-    } while (--dung_draw_width_indicator);
-    break;
-  case 0x75: case 0x87:  // 75 -  Column [U-D]
-    RoomDraw_GetObjectSize_1to16();
-    do {
-      RoomDraw_Object_Nx4(2, src, dst), dst += XY(0, 6);
-    } while (--dung_draw_width_indicator);
-    break;
-  case 0x76: case 0x77:  // 76 -  [W]Wall Decor: [U-D]
-    RoomDraw_GetObjectSize_1to16();
-    do {
-      RoomDraw_Object_Nx4(3, src, dst), dst += XY(0, 8);
-    } while (--dung_draw_width_indicator);
-    break;
-  case 0x78: case 0x7b:  // 78 -  [W]Wall Top Column [U-D]
-    RoomDraw_GetObjectSize_1to16();
-    do {
-      RoomDraw_Rightwards2x2(src, dst), dst += XY(0, 14);
-    } while (--dung_draw_width_indicator);
-    break;
-  case 0x7c:  // 7C -  Cane Ride [U-D]
-    RoomDraw_GetObjectSize_1to16();
-    dung_draw_width_indicator += 1;
-    do {
-      dst[0] = src[0], dst += XY(0, 1);
-    } while (--dung_draw_width_indicator);
-    break;
-  case 0x7f: case 0x80:  // 7F -  [W]Wall Torches [U-D]
-    RoomDraw_GetObjectSize_1to16();
-    do {
-      RoomDraw_Object_Nx4(2, src, dst), dst += XY(0, 12);
-    } while (--dung_draw_width_indicator);
-    break;
-  case 0x81: case 0x82: case 0x83: case 0x84: // 81 -  [W]Wall Decor: [U-D]
-    RoomDraw_GetObjectSize_1to16();
-    do {
-      RoomDraw_Object_Nx4(3, src, dst), dst += XY(0, 6);
-    } while (--dung_draw_width_indicator);
-    break;
-  case 0x85: case 0x86:  // 85 -  [W]Wall Canon Hole [U-D]
-    RoomDraw_GetObjectSize_1to16();
-    Object_Draw_3x2(src, dst), dst += XY(0, 2);
-    while (--dung_draw_width_indicator)
-      Object_Draw_3x2(src + 6, dst), dst += XY(0, 2);
-    Object_Draw_3x2(src + 12, dst);
-    break;
-  case 0x88: // 88 -  Large Vert: Rail [U-D]
-    RoomDraw_GetObjectSize_1to16();
-    RoomDraw_Rightwards2x2(src, dst), dst += XY(0, 2), src += 4;
-    do {
-      dst[XY(0, 0)] = src[0];
-      dst[XY(1, 0)] = src[1];
-      dst += XY(0, 1);
-    } while (--dung_draw_width_indicator);
-    RoomDraw_1x3_rightwards(2, src + 2, dst);
-    break;
-  case 0x89: // 89 -  Block Vert: [U-D]
-    RoomDraw_GetObjectSize_1to16();
-    do {
-      RoomDraw_Rightwards2x2(src, dst), dst += XY(0, 4);
-    } while (--dung_draw_width_indicator);
-    break;
-  case 0x8a: // 8A -  Long Vert: Rail [U-D]
-    Object_SizeAtoAplus15(21);
-    if ((dst[0] & 0x3ff) != 0xe3)
-      dst[0] = src[0];
-    n = src[1];
-    do { dst += XY(0, 1); *dst = n; } while (--dung_draw_width_indicator);
-    dst[XY(0, 1)] = src[2];
-    break;
-  case 0x8b: case 0x8c: // 8B -  [W]Vert: Jump Edge [U-D]
-    Object_SizeAtoAplus15(8);
-    do {
-      dst[0] = src[0], dst += XY(0, 1);
-    } while (--dung_draw_width_indicator);
-    break;
-  case 0x8f: // 8F -  N/A
-    Object_SizeAtoAplus15(2);
-    dung_draw_width_indicator <<= 1;
-    dst[XY(0, 0)] = src[0], dst[XY(1, 0)] = src[1];
-    do {
-      dst[XY(0, 1)] = src[2], dst[XY(1, 1)] = src[3], dst += XY(0, 1);
-    } while (--dung_draw_width_indicator);
-    break;
-  case 0x95:  // 95 -  Fake Pot [U-D]
-    RoomDraw_GetObjectSize_1to16();
-    do {
-      RoomDraw_SinglePot(src, dst, dsto);
-      dst += XY(0, 2), dsto += XY(0, 2);
-    } while (--dung_draw_width_indicator);
-    break;
-  case 0x96:  // 96 -  Hammer Peg Block [U-D]
-    RoomDraw_GetObjectSize_1to16();
-    do {
-      RoomDraw_HammerPegSingle(src, dst, dsto);
-      dst += XY(0, 2), dsto += XY(0, 2);
-    } while (--dung_draw_width_indicator);
-    break;
-  case 0x97: case 0x98: case 0x99: case 0x9a: case 0x9b: case 0x9c: case 0x9d: case 0x9e: case 0x9f:
-  case 0xad: case 0xae: case 0xaf:
-  case 0xbe: case 0xbf:
-    break;
-  case 0xa0:  // A0 -  / Ceiling [NW]
-  case 0xa5: case 0xa9:  // A5 -  / Ceiling [Trans][NW]
-    Object_SizeAtoAplus15(4);
-    do {
-      Object_Fill_Nx1(dung_draw_width_indicator, src, dst), dst += XY(0, 1);
-    } while (--dung_draw_width_indicator);
-    break;
-  case 0xa1:  // A1 -  \ Ceiling [SW]
-  case 0xa6: case 0xaa:  // A6 -  \ Ceiling [Trans][SW]
-    Object_SizeAtoAplus15(4);
-    n = 1;
-    do {
-      Object_Fill_Nx1(n++, src, dst), dst += XY(0, 1);
-    } while (--dung_draw_width_indicator);
-    break;
-  case 0xa2:  // A2 -  \ Ceiling [NE]
-  case 0xa7: case 0xab:  // A7 -  \ Ceiling [Trans][NE]
-    Object_SizeAtoAplus15(4);
-    do {
-      Object_Fill_Nx1(dung_draw_width_indicator, src, dst), dst += XY(1, 1);
-    } while (--dung_draw_width_indicator);
-    break;
-  case 0xa3:             // A3 -  / Ceiling [SE]
-  case 0xa8: case 0xac:  // A8 -  / Ceiling [Trans][SE]
-    Object_SizeAtoAplus15(4);
-    do {
-      Object_Fill_Nx1(dung_draw_width_indicator, src, dst), dst += XY(1, -1);
-    } while (--dung_draw_width_indicator);
-    break;
-  case 0xa4: // A4 -  Hole [4-way]
-    Object_Hole(src, dst);
-    break;
-  case 0xb0: case 0xb1: // B0 -  [S]Horz: Jump Edge [L-R]
-    Object_SizeAtoAplus15(8);
-    Object_Fill_Nx1(dung_draw_width_indicator, src, dst);
-    break;
-  case 0xb5:  // B5 -  N/A
-    RoomDraw_GetObjectSize_1to16();
-    do {
-      src = SrcPtr(0xb16);
-      RoomDraw_Object_Nx4(2, src, dst), dst += XY(2, 0);
-    } while (--dung_draw_width_indicator);
-    break;
-  case 0xbc: // BC -  fake pots [L-R]
-    RoomDraw_GetObjectSize_1to16();
-    do {
-      RoomDraw_SinglePot(src, dst, dsto);
-      dst += XY(2, 0), dsto += XY(2, 0);
-    } while (--dung_draw_width_indicator);
-    break;
-  case 0xbd: // BD -  Hammer Pegs [L-R]
-    RoomDraw_GetObjectSize_1to16();
-    do {
-      RoomDraw_HammerPegSingle(src, dst, dsto);
-      dst += XY(2, 0), dsto += XY(2, 0);
-    } while (--dung_draw_width_indicator);
-    break;
-  case 0xc0: case 0xc2: // C0 -  Ceiling Large [4-way]
-    n = src[0];
-    for (int y = dung_draw_height_indicator; y-- >= 0; ) {
-      uint16 *dst_org = dst;
-      for (int x = dung_draw_width_indicator; x-- >= 0; dst += XY(4, 0)) {
-        dst[XY(0, 0)] = dst[XY(1, 0)] = dst[XY(2, 0)] = dst[XY(3, 0)] = n;
-        dst[XY(0, 1)] = dst[XY(1, 1)] = dst[XY(2, 1)] = dst[XY(3, 1)] = n;
-        dst[XY(0, 2)] = dst[XY(1, 2)] = dst[XY(2, 2)] = dst[XY(3, 2)] = n;
-        dst[XY(0, 3)] = dst[XY(1, 3)] = dst[XY(2, 3)] = dst[XY(3, 3)] = n;
-      }
-      dst = dst_org + XY(0, 4);
-    }
-    break;
-  case 0xc1: { // C1 -  Chest Pedastal [4-way]
-    dung_draw_width_indicator += 4;
-    dung_draw_height_indicator += 1;
-    // draw upper part
-    uint16 *dsto = dst;
-    RoomDraw_1x3_rightwards(3, src, dst), src += 9, dst += XY(3, 0);
-    for (int i = dung_draw_width_indicator; i--; )
-      RoomDraw_1x3_rightwards(2, src, dst), dst += XY(2, 0);
-    RoomDraw_1x3_rightwards(3, src + 6, dst), src += 6 + 9;
-    // draw center part
-    dst = dsto + XY(0, 3);
-    for (int i = dung_draw_height_indicator; i--; ) {
-      uint16 *dt = dst;
-      Object_Draw_3x2(src, dt), dt += XY(3, 0);
-      for (int j = dung_draw_width_indicator; j--; )
-        RoomDraw_Rightwards2x2(src + 6, dt), dt += XY(2, 0);
-      Object_Draw_3x2(src + 10, dt);
-      dst += XY(0, 2);
-    }
-    dsto = dst;
-    src += 6 + 4 + 6;
-    RoomDraw_1x3_rightwards(3, src, dst), src += 9, dst += XY(3, 0);
-    for (int i = dung_draw_width_indicator; i--; )
-      RoomDraw_1x3_rightwards(2, src, dst), dst += XY(2, 0);
-    RoomDraw_1x3_rightwards(3, src + 6, dst), src += 6 + 9;
-
-    src = SrcPtr(0x590);
-    RoomDraw_Rightwards2x2(src, dsto + XY(dung_draw_width_indicator + 2, -(dung_draw_height_indicator + 1)));
-    break;
-  }
-  case 0xc3:  // C3 -  Falling Edge Mask [4-way]
-  case 0xd7:  // D7 -  overlay tile? [4-way]
-    dung_draw_width_indicator++;
-    dung_draw_height_indicator++;
-    n = *src;
-    do {
-      uint16 *d = dst;
-      for (int i = dung_draw_width_indicator; i--; d += XY(3, 0)) {
-        d[XY(0, 0)] = d[XY(1, 0)] = d[XY(2, 0)] = n;
-        d[XY(0, 1)] = d[XY(1, 1)] = d[XY(2, 1)] = n;
-        d[XY(0, 2)] = d[XY(1, 2)] = d[XY(2, 2)] = n;
-      }
-      dst += XY(0, 3);
-    } while (--dung_draw_height_indicator);
-    break;
-
-  case 0xc4: // C4 -  Doorless Room Transition
-    src = SrcPtr(dung_floor_2_filler_tiles);
-    goto fill_floor;
-
-  case 0xdb: // C4 -  DB -  Floor2 [4-way]
-    src = SrcPtr(dung_floor_1_filler_tiles);
-    goto fill_floor;
-
-  case 0xc5: case 0xc6: case 0xc7: case 0xc8: case 0xc9: case 0xca:
-  case 0xd1: case 0xd2: case 0xd9:
-  case 0xdf: case 0xe0: case 0xe1: case 0xe2: case 0xe3: case 0xe4:
-  case 0xe5: case 0xe6: case 0xe7: case 0xe8:
-fill_floor:
-    dung_draw_width_indicator++;
-    dung_draw_height_indicator++;
-    do {
-      RoomDraw_A_Many32x32Blocks(dung_draw_width_indicator, src, dst);
-      dst += XY(0, 4);
-    } while (--dung_draw_height_indicator);
-    break;
-
-  case 0xcd: { // CD -  Moving Wall Right [4-way]
-    if (!RoomDraw_CheckIfWallIsMoved())
-      return;
-    dung_hdr_collision_2_mirror++;
-    int size0 = kMovingWall_Sizes0[dung_draw_width_indicator];
-    int size1 = kMovingWall_Sizes1[dung_draw_height_indicator];
-    MovingWall_FillReplacementBuffer(dsto - size1 - 1);
-    moving_wall_var2 = dung_draw_height_indicator * 2;
-    src = SrcPtr(0x3d8);
-    uint16 *dst1 = dst - size1;
-    do {
-      uint16 *dst2 = dst1;
-      dst2[XY(0, 0)] = src[0];
-      int n1 = size0 * 2 + 4;
-      do {
-        dst2[XY(0, 1)] = src[1];
-        dst2 += XY(0, 1);
-      } while (--n1);
-      dst2[XY(0, 1)] = src[2];
-      dst1++;
-    } while (--size1);
-    src = SrcPtr(0x72a);
-    RoomDraw_1x3_rightwards(3, src, dst);
-    dst += XY(0, 3);
-    do {
-      Object_Draw_3x2(src + 9, dst);
-    } while (dst += XY(0, 2), --size0);
-    RoomDraw_1x3_rightwards(3, src + 9 + 6, dst);
-    break;
-  }
-
-  case 0xce: { // CE -  Moving Wall Left [4-way]
-    if (!RoomDraw_CheckIfWallIsMoved())
-      return;
-    dung_hdr_collision_2_mirror++;
-    src = SrcPtr(0x75a);
-    int size1 = kMovingWall_Sizes1[dung_draw_height_indicator];
-    int size0 = kMovingWall_Sizes0[dung_draw_width_indicator];
-    moving_wall_var2 = dung_draw_height_indicator * 2;
-    MovingWall_FillReplacementBuffer(dsto + 3 + size1);
-    uint16 *dst1 = dst;
-    RoomDraw_1x3_rightwards(3, src, dst1);
-    dst1 += XY(0, 3);
-    int n = size0;
-    do {
-      Object_Draw_3x2(src + 9, dst1);
-      dst1 += XY(0, 2);
-    } while (--n);
-    RoomDraw_1x3_rightwards(3, src + 15, dst1);
-    src = SrcPtr(0x3d8);
-    dst1 = dst + XY(3, 0);
-    do {
-      uint16 *dst2 = dst1;
-      dst2[XY(0, 0)] = src[0];
-      int n1 = size0 * 2 + 4;
-      do {
-        dst2[XY(0, 1)] = src[1];
-        dst2 += XY(0, 1);
-      } while (--n1);
-      dst2[XY(0, 1)] = src[2];
-      dst1++;
-    } while (--size1);
-    break;
-  }
-
-  case 0xd8: {
-    // loads of lava/water hdma stuff
-    dung_draw_width_indicator += 2;
-    water_hdma_var3 = (dung_draw_width_indicator << 4);
-    dung_draw_height_indicator += 2;
-    water_hdma_var2 = (dung_draw_height_indicator << 4);
-    water_hdma_var4 = water_hdma_var2 - 24;
-    water_hdma_var0 = (dsto & 0x3f) << 3;
-    water_hdma_var0 += (dung_draw_width_indicator << 4) + dung_loade_bgoffs_h_copy;
-    water_hdma_var1 = (dsto & 0xfc0) >> 3;
-    water_hdma_var1 += (dung_draw_height_indicator << 4) + dung_loade_bgoffs_v_copy;
-    if (dung_savegame_state_bits & 0x800) {
-      dung_hdr_tag[1] = 0;
-      dung_hdr_bg2_properties = 0;
-      dung_num_interpseudo_upnorth_stairs = dung_num_inroom_upnorth_stairs_water;
-      dung_some_stairs_unk4 = dung_num_activated_water_ladders;
-      dung_num_activated_water_ladders = 0;
-      dung_num_inroom_upnorth_stairs_water = 0;
-      dung_num_stairs_wet = dung_num_inroom_upsouth_stairs_water;
-      dung_num_inroom_upsouth_stairs_water = 0;
-      dsto += (dung_draw_width_indicator - 1) << 1;
-      dsto += (dung_draw_height_indicator - 1) << 7;
-      DrawWaterThing(&dung_bg2[dsto], SrcPtr(0x1438));
-    } else {
-      src = SrcPtr(0x110);
-      do {
-        RoomDraw_A_Many32x32Blocks(dung_draw_width_indicator, src, dst);
-        dst += XY(0, 4);
-      } while (--dung_draw_height_indicator);
-    }
-    break;
-  }
-
-  case 0xda: {  // water hdma stuff
-    dung_draw_width_indicator += 2;
-    water_hdma_var3 = (dung_draw_width_indicator << 4) - 24;
-
-    dung_draw_height_indicator += 2;
-    water_hdma_var4 = (dung_draw_height_indicator << 4) - 8;
-
-    water_hdma_var2 = water_hdma_var4 - 24;
-    water_hdma_var5 = 0;
-    water_hdma_var0 = (dsto & 0x3f) << 3;
-    water_hdma_var0 += (dung_draw_width_indicator << 4) + dung_loade_bgoffs_h_copy;
-    water_hdma_var1 = (dsto & 0xfc0) >> 3;
-    water_hdma_var1 += (dung_draw_height_indicator << 4) + dung_loade_bgoffs_v_copy - 8;
-    if (dung_savegame_state_bits & 0x800) {
-      dung_hdr_tag[1] = 0;
-    } else {
-      dung_hdr_bg2_properties = 0;
-      dung_num_interpseudo_upnorth_stairs = dung_num_inroom_upnorth_stairs_water;
-      dung_some_stairs_unk4 = dung_num_activated_water_ladders;
-      dung_num_activated_water_ladders = 0;
-      dung_num_inroom_upnorth_stairs_water = 0;
-      dung_num_stairs_wet = dung_num_inroom_upsouth_stairs_water;
-      dung_num_inroom_upsouth_stairs_water = 0;
-    }
-    int n = dung_draw_height_indicator * 2 - 1;
-    src = SrcPtr(0x110);
-    do {
-      uint16 *dst2 = dst;
-      int j = dung_draw_width_indicator;
-      do {
-        dst[XY(0, 0)] = src[0];
-        dst[XY(1, 0)] = src[1];
-        dst[XY(2, 0)] = src[2];
-        dst[XY(3, 0)] = src[3];
-        dst[XY(0, 1)] = src[4];
-        dst[XY(1, 1)] = src[5];
-        dst[XY(2, 1)] = src[6];
-        dst[XY(3, 1)] = src[7];
-        dst += 4;
-      } while (--j);
-      dst = dst2 + XY(0, 2);
-    } while (--n);
-    break;
-  }
-
-  case 0xdc: { // DC -  Chest Platform? [4-way]
-    dsto |= (dung_line_ptrs_row0 != 0x4000 ? 0 : 0x1000);
-    dung_draw_width_indicator++;
-    dung_draw_height_indicator = dung_draw_height_indicator * 2 + 5;
-    src = SrcPtr(0xAB4);
-    do {
-      Object_ChestPlatform_Helper(src, dsto), dsto += XY(0, 1);
-    } while (--dung_draw_height_indicator);
-    Object_ChestPlatform_Helper(src + 1, dsto), dsto += XY(0, 1);
-    Object_ChestPlatform_Helper(src + 2, dsto), dsto += XY(0, 1);
-    break;
-  }
-  case 0xdd: // DD -  Table / Rock [4-way]
-    dung_draw_width_indicator++;
-    dung_draw_height_indicator = dung_draw_height_indicator * 2 + 1;
-    Object_Table_Helper(src, dst), dst += XY(0, 1);
-    do {
-      Object_Table_Helper(src + 4, dst), dst += XY(0, 1);
-    } while (--dung_draw_height_indicator);
-    Object_Table_Helper(src + 8, dst), dst += XY(0, 1);
-    Object_Table_Helper(src + 12, dst), dst += XY(0, 1);
-    break;
-
-  case 0xde: // DE -  Spike Block [4-way]
-    dung_draw_width_indicator++;
-    dung_draw_height_indicator++;
-    do {
-      int n = dung_draw_width_indicator;
-      uint16 *dst1 = dst;
-      do {
-        RoomDraw_Rightwards2x2(src, dst1), dst1 += XY(2, 0);
-      } while (--n);
-      dst += XY(0, 2);
-    } while (--dung_draw_height_indicator);
-    break;
-
-  case 0xcb: case 0xcc: case 0xcf: case 0xd0:
-  case 0xd3: case 0xd4: case 0xd5: case 0xd6:
-  case 0xe9: case 0xea: case 0xeb: case 0xec: case 0xed: case 0xee: case 0xef:
-  case 0xf0: case 0xf1: case 0xf2: case 0xf3: case 0xf4: case 0xf5: case 0xf6: case 0xf7:
-    assert(0);
-    break;
-  default:
-    assert(0);
-  }
-}
-
-void Object_DrawNx3_BothBgs(int n, const uint16 *src, int dsto) {
-  do {
-    dung_bg1[dsto + XY(0, 0)] = dung_bg2[dsto + XY(0, 0)] = src[0];
-    dung_bg1[dsto + XY(0, 1)] = dung_bg2[dsto + XY(0, 1)] = src[1];
-    dung_bg1[dsto + XY(0, 2)] = dung_bg2[dsto + XY(0, 2)] = src[2];
-    src += 3, dsto += 1;
-  } while (--n);
-}
-
-void LoadType1ObjectSubtype2(uint8 idx, uint16 *dst, uint16 dsto) {
-  uint16 params = kObjectSubtype2Params[idx];
-  const uint16 *src = SrcPtr(params);
-  int i;
-  switch (idx) {
-  case 0x00: case 0x01: case 0x02: case 0x03:
-  case 0x04: case 0x05: case 0x06: case 0x07:  // 00 -  Wall Outer Corner (HIGH) [NW]
-  case 0x1c: case 0x24: case 0x25: case 0x29:
-    RoomDraw_Object_Nx4(4, src, dst);
-    break;
-  case 0x08: case 0x09: case 0x0a: case 0x0b:
-  case 0x0c: case 0x0d: case 0x0e: case 0x0f:  // 08 -  Wall Outer Corner (LOW) [NW]
-    Object_DrawNx4_BothBgs(4, src, dsto);
-    break;
-  case 0x10: case 0x11: case 0x12: case 0x13:  // 10 -  Wall S-Bend (LOW) [N1]
-    Object_DrawNx4_BothBgs(3, src, dsto);
-    break;
-  case 0x14: case 0x15: case 0x16: case 0x17:  // 14 -  Wall S-Bend (LOW) [W1]
-    Object_DrawNx3_BothBgs(4, src, dsto);
-    break;
-  case 0x18: case 0x19: case 0x1a: case 0x1b:  // 18 -  Wall Pit Corner (Lower) [NW]
-  case 0x27: case 0x2b: case 0x34:
-    RoomDraw_Rightwards2x2(src, dst);
-    break;
-  case 0x1d: case 0x21: case 0x26:             // 1D -  Statue
-    RoomDraw_1x3_rightwards(2, src, dst);
-    break;
-  case 0x1e:                                   // 1E -  Star Tile Off
-    RoomDraw_Rightwards2x2(src, dst);
-    break;
-  case 0x1f:                                   // 1F -  Star Tile On
-    i = dung_num_star_shaped_switches >> 1;
-    dung_num_star_shaped_switches += 2;
-    star_shaped_switches_tile[i] = (dsto | (dung_line_ptrs_row0 != 0x4000 ? 0 : 0x1000));
-    RoomDraw_Rightwards2x2(src, dst);
-    break;
-  case 0x20:                                   // 20 -  Torch Lit
-    dung_num_lit_torches++;
-    RoomDraw_Rightwards2x2(src, dst);
-    break;
-  case 0x22: case 0x28:                        // 22 -  Weird Bed
-    Object_Draw_5x4(src, dst);
-    break;
-  case 0x23:                                   // 23 -  Table
-    RoomDraw_1x3_rightwards(4, src, dst);
-    break;
-  case 0x2a:                                   // 2A -  Wall Painting
-    dung_draw_width_indicator = 1;
-    RoomDraw_Downwards4x2VariableSpacing(1, src, dst);
-    break;
-  case 0x2c:                                   // 2C -  ???
-    RoomDraw_1x3_rightwards(6, src, dst);
-    break;
-  case 0x2d:    // 2D -  Floor Stairs Up (room)
-    i = dung_num_inter_room_upnorth_stairs >> 1;
-    dung_inter_starcases[i] = (dsto | (dung_line_ptrs_row0 != 0x4000 ? 0 : 0x1000));
-    dung_num_inter_room_upnorth_stairs =
-      dung_num_wall_upnorth_spiral_stairs =
-      dung_num_wall_upnorth_spiral_stairs_2 =
-      dung_num_inter_room_upnorth_straight_stairs =
-      dung_num_inter_room_upsouth_straight_stairs =
-      dung_num_inter_room_southdown_stairs =
-      dung_num_wall_downnorth_spiral_stairs =
-      dung_num_wall_downnorth_spiral_stairs_2 =
-      dung_num_inter_room_downnorth_straight_stairs =
-      dung_num_inter_room_downsouth_straight_stairs = dung_num_inter_room_upnorth_stairs + 2;
-    RoomDraw_4x4(SrcPtr(0x1088), dst);
-    break;
-  case 0x2e:    // 2E -  Floor Stairs Down (room)
-  case 0x2f:    // 2F -  Floor Stairs Down2 (room)
-    i = dung_num_inter_room_southdown_stairs >> 1;
-    dung_inter_starcases[i] = (dsto | (dung_line_ptrs_row0 != 0x4000 ? 0 : 0x1000));
-    dung_num_inter_room_southdown_stairs =
-      dung_num_wall_downnorth_spiral_stairs =
-      dung_num_wall_downnorth_spiral_stairs_2 =
-      dung_num_inter_room_downnorth_straight_stairs =
-      dung_num_inter_room_downsouth_straight_stairs = dung_num_inter_room_southdown_stairs + 2;
-    RoomDraw_4x4(SrcPtr(0x10A8), dst);
-    break;
-  case 0x30:     // 30 -  Stairs [N](unused)
-    assert(0);
-    break;
-  case 0x31:     // 31 -  Stairs [N](layer)
-    i = dung_num_inroom_southdown_stairs >> 1;
-    dung_stairs_table_1[i] = dsto;
-    dung_num_inroom_southdown_stairs =
-      dung_num_water_ladders =
-      dung_some_stairs_unk4 = dung_num_inroom_southdown_stairs + 2;
-    Object_DrawNx4_BothBgs(4, src, dsto);
-    break;
-  case 0x32:     // 32 -  Stairs [N](layer)
-non_submerged:
-    i = dung_num_interpseudo_upnorth_stairs >> 1;
-    dung_stairs_table_1[i] = dsto;
-    dung_num_interpseudo_upnorth_stairs =
-      dung_num_water_ladders =
-      dung_some_stairs_unk4 = dung_num_interpseudo_upnorth_stairs + 2;
-    RoomDraw_4x4(src, dst);
-    break;
-  case 0x33:       // 33 -  Stairs Submerged [N](layer)
-    if (dung_hdr_tag[1] == 27 && !(save_dung_info[dungeon_room_index] & 0x100)) {
-      dung_hdr_bg2_properties = 0;
-      src = SrcPtr(0x10C8);
-      goto non_submerged;
-    } else {
-      i = dung_num_inroom_upnorth_stairs_water >> 1;
-      dung_stairs_table_1[i] = dsto;
-      dung_num_inroom_upnorth_stairs_water =
-        dung_num_activated_water_ladders = dung_num_inroom_upnorth_stairs_water + 2;
-      RoomDraw_4x4(SrcPtr(0x10C8), dst);
-    }
-    break;
-  case 0x35:  // 35 -  Water Ladder
-    if (dung_hdr_tag[1] == 27 && !(save_dung_info[dungeon_room_index] & 0x100))
-      goto inactive_water_ladder;
-    dung_stairs_table_1[dung_num_activated_water_ladders >> 1] = dsto;
-    dung_num_activated_water_ladders += 2;
-    dung_draw_width_indicator = 1;
-    RoomDraw_Downwards4x2VariableSpacing(1, SrcPtr(0x1108), dst);
-    break;
-  case 0x36:  // 36 -  Water Ladder Inactive
-inactive_water_ladder:
-    dung_stairs_table_1[dung_num_water_ladders >> 1] = dsto;
-    dung_some_stairs_unk4 = (dung_num_water_ladders += 2);
-    Object_Draw_4x2_BothBgs(SrcPtr(0x1108), dsto);
-    break;
-  case 0x37:  // 37 -  Water Gate Large
-    if (!(dung_savegame_state_bits & 0x800)) {
-      RoomDraw_Object_Nx4(10, src, dst);
-      watergate_var1 = 0xf;
-      watergate_pos = dsto * 2;
-    } else {
-      RoomDraw_Object_Nx4(10, SrcPtr(0x13e8), dst);
-      uint16 bak0 = dung_load_ptr;
-      uint16 bak1 = dung_load_ptr_offs;
-      uint8 bak2 = dung_load_ptr_bank;
-      RoomTag_OperateWaterFlooring();
-      dung_load_ptr_bank = bak2;
-      dung_load_ptr_offs = bak1;
-      dung_load_ptr = bak0;
-    }
-    break;
-  case 0x38:  // 38 -  Door Staircase Up R
-    i = dung_num_wall_upnorth_spiral_stairs >> 1;
-    dung_inter_starcases[i] = (dsto - 0x40) | (dung_line_ptrs_row0 != 0x4000 ? 0 : 0x1000);
-    dung_num_wall_upnorth_spiral_stairs =
-      dung_num_wall_upnorth_spiral_stairs_2 =
-      dung_num_inter_room_upnorth_straight_stairs =
-      dung_num_inter_room_upsouth_straight_stairs =
-      dung_num_inter_room_southdown_stairs =
-      dung_num_wall_downnorth_spiral_stairs =
-      dung_num_wall_downnorth_spiral_stairs_2 =
-      dung_num_inter_room_downnorth_straight_stairs =
-      dung_num_inter_room_downsouth_straight_stairs = dung_num_wall_upnorth_spiral_stairs + 2;
-    RoomDraw_1x3_rightwards(4, SrcPtr(0x1148), dst);
-    dung_bg2[dsto - 1] |= 0x2000;
-    dung_bg2[dsto + 4] |= 0x2000;
-    break;
-  case 0x39:  // 39 -  Door Staircase Down L
-    i = dung_num_wall_downnorth_spiral_stairs >> 1;
-    dung_inter_starcases[i] = (dsto - 0x40) | (dung_line_ptrs_row0 != 0x4000 ? 0 : 0x1000);
-    dung_num_wall_downnorth_spiral_stairs =
-      dung_num_wall_downnorth_spiral_stairs_2 =
-      dung_num_inter_room_downnorth_straight_stairs =
-      dung_num_inter_room_downsouth_straight_stairs = dung_num_wall_downnorth_spiral_stairs + 2;
-    RoomDraw_1x3_rightwards(4, SrcPtr(0x1160), dst);
-    dung_bg2[dsto - 1] |= 0x2000;
-    dung_bg2[dsto + 4] |= 0x2000;
-    break;
-  case 0x3a:  // 3A -  Door Staircase Up R (Lower)
-    i = dung_num_wall_upnorth_spiral_stairs_2 >> 1;
-    dung_inter_starcases[i] = (dsto - 0x40) | (dung_line_ptrs_row0 != 0x4000 ? 0 : 0x1000);
-    dung_num_wall_upnorth_spiral_stairs_2 =
-      dung_num_inter_room_upnorth_straight_stairs =
-      dung_num_inter_room_upsouth_straight_stairs =
-      dung_num_inter_room_southdown_stairs =
-      dung_num_wall_downnorth_spiral_stairs =
-      dung_num_wall_downnorth_spiral_stairs_2 =
-      dung_num_inter_room_downnorth_straight_stairs =
-      dung_num_inter_room_downsouth_straight_stairs = dung_num_wall_upnorth_spiral_stairs_2 + 2;
-    RoomDraw_1x3_rightwards(4, SrcPtr(0x1178), dst);
-    dung_bg1[dsto - 1] |= 0x2000;
-    dung_bg1[dsto + 4] |= 0x2000;
-    break;
-  case 0x3b:  // 3B -  Door Staircase Down L (Lower)
-    i = dung_num_wall_downnorth_spiral_stairs_2 >> 1;
-    dung_inter_starcases[i] = (dsto - 0x40) | (dung_line_ptrs_row0 != 0x4000 ? 0 : 0x1000);
-    dung_num_wall_downnorth_spiral_stairs_2 =
-      dung_num_inter_room_downnorth_straight_stairs =
-      dung_num_inter_room_downsouth_straight_stairs =
-      dung_num_wall_downnorth_spiral_stairs_2 + 2;
-    RoomDraw_1x3_rightwards(4, SrcPtr(0x1190), dst);
-    dung_bg1[dsto - 1] |= 0x2000;
-    dung_bg1[dsto + 4] |= 0x2000;
-    break;
-  case 0x3c:  // 3C -  Sanctuary Wall
-    for (int i = 0; i < 6; i++) {
-      dung_bg2[dsto + 0] = dung_bg2[dsto + 4] = dung_bg2[dsto + 8] =
-        dung_bg2[dsto + 14] = dung_bg2[dsto + 18] = dung_bg2[dsto + 22] = src[0];
-      dung_bg2[dsto + 1] = dung_bg2[dsto + 5] = dung_bg2[dsto + 9] =
-        dung_bg2[dsto + 15] = dung_bg2[dsto + 19] = dung_bg2[dsto + 23] = src[0] | 0x4000;
-      dung_bg2[dsto + 2] = dung_bg2[dsto + 6] = dung_bg2[dsto + 16] = dung_bg2[dsto + 20] = src[6];
-      dung_bg2[dsto + 3] = dung_bg2[dsto + 7] = dung_bg2[dsto + 17] = dung_bg2[dsto + 21] = src[6] | 0x4000;
-      dsto += XY(0, 1);
-      src++;
-    }
-    RoomDraw_1x3_rightwards(4, src + 6, dst + 10);
-    break;
-  case 0x3e:  // 3E -  Church Pew
-    RoomDraw_1x3_rightwards(6, src, dst);
-    break;
-  case 0x3f: { // 3F - used in hole at the smithy dwarves
-    dsto |= (dung_line_ptrs_row0 != 0x4000 ? 0 : 0x1000);
-    dst = &dung_bg2[dsto];
-    for (int i = 0; i < 8; i++) {
-      dst[XY(0, 0)] = src[0];
-      dst[XY(0, 1)] = src[1];
-      dst[XY(0, 2)] = src[2];
-      dst[XY(0, 3)] = src[3];
-      dst[XY(0, 4)] = src[4];
-      dst[XY(0, 5)] = src[5];
-      dst[XY(0, 6)] = src[6];
-      dst += XY(1, 0);
-      src += 7;
-    }
-    break;
-  }
-
-  default:
-    assert(0);
-  }
-}
-
-void Object_BombableFloorHelper(uint16 a, const uint16 *src, const uint16 *src_below, uint16 *dst, uint16 dsto) {
-  int i = dung_misc_objs_index >> 1;
-  dung_replacement_tile_state[i] = a;
-  dung_misc_objs_index += 2;
-  dung_object_pos_in_objdata[i] = dung_load_ptr_offs;
-  dung_object_tilemap_pos[i] = dsto * 2 | (dung_line_ptrs_row0 != 0x4000 ? 0 : 0x2000);
-  replacement_tilemap_UL[i] = src_below[0];
-  replacement_tilemap_LL[i] = src_below[1];
-  replacement_tilemap_UR[i] = src_below[2];
-  replacement_tilemap_LR[i] = src_below[3];
-  RoomDraw_Rightwards2x2(src, dst);
-}
-
-void LoadType1ObjectSubtype3(uint8 idx, uint16 *dst, uint16 dsto) {
-  uint16 params = kObjectSubtype3Params[idx];
-  const uint16 *src = SrcPtr(params);
-  int i;
-
-  switch (idx) {
-  case 0x00:  // 00 -  Water Face Closed
-    if (dung_hdr_tag[1] == 27) {
-      if (save_dung_info[dungeon_room_index] & 0x100)
-        goto water_face_open;
-    } else if (dung_hdr_tag[1] == 25) {
-      if (dung_savegame_state_bits & 0x800)
-        goto water_face_open;
-    }
-    word_7E047C = dsto * 2;
-    RoomDraw_WaterHoldingObject(3, src, dst);
-    break;
-  case 0x01:  // 01 -  Waterfall Face
-water_face_open:
-    RoomDraw_WaterHoldingObject(5, SrcPtr(0x162c), dst);
-    break;
-  case 0x02:  // 02 -  Waterfall Face Longer
-    RoomDraw_WaterHoldingObject(7, src, dst);
-    break;
-  case 0x03: case 0x0e:  // 03 -  Cane Ride Spawn [?]Block
-    dung_unk6++;
-    dst[0] = src[0];
-    break;
-  case 0x04: case 0x05: case 0x06: case 0x07:  // 04 -  Cane Ride Node [4-way]
-  case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0f:
-    dst[0] = src[0];
-    break;
-  case 0x0d: case 0x17: { // 0D -  Prison Cell
-    src = SrcPtr(0x1488);
-    dsto |= (dung_line_ptrs_row0 != 0x4000 ? 0 : 0x1000);
-    uint16 *d = &dung_bg2[dsto], *dd = d;
-    for (int i = 0; i < 5; i++, d++) {
-      d[XY(2, 0)] = d[XY(9, 0)] = src[1];
-      d[XY(2, 1)] = src[2];
-      d[XY(9, 1)] = src[2] | 0x4000;
-      d[XY(2, 2)] = src[4];
-      d[XY(9, 2)] = src[4] | 0x4000;
-      d[XY(2, 3)] = src[5];
-      d[XY(9, 3)] = src[5] | 0x4000;
-    }
-    dd[XY(0, 0)] = src[0];
-    dd[XY(15, 0)] = src[0] | 0x4000;
-    dd[XY(1, 0)] = dd[XY(7, 0)] = dd[XY(8, 0)] = dd[XY(14, 0)] = src[1];
-    dd[XY(1, 2)] = src[3];
-    dd[XY(14, 2)] = src[3] | 0x4000;
-    break;
-  }
-  case 0x10: case 0x11: case 0x13: case 0x1a: case 0x22: case 0x23:
-  case 0x24: case 0x25:
-  case 0x3e: case 0x3f: case 0x40: case 0x41: case 0x42:
-  case 0x43: case 0x44: case 0x45: case 0x46: case 0x49: case 0x4a: case 0x4f:
-  case 0x50: case 0x51: case 0x52: case 0x53: case 0x56: case 0x57: case 0x58: case 0x59:
-  case 0x5e: case 0x5f: case 0x63: case 0x64: case 0x65:
-  case 0x75: case 0x7c: case 0x7d: case 0x7e:
-    RoomDraw_Rightwards2x2(src, dst);
-    break;
-
-  case 0x12:  // 12 -  Rupee Floor
-    if (dung_savegame_state_bits & 0x1000)
-      return;
-    src = SrcPtr(0x1dd6);
-    dst = &dung_bg2[dsto | (dung_line_ptrs_row0 != 0x4000 ? 0 : 0x1000)];
-    for (int i = 0; i < 3; i++) {
-      dst[XY(0, 0)] = dst[XY(0, 3)] = dst[XY(0, 6)] = src[0];
-      dst[XY(0, 1)] = dst[XY(0, 4)] = dst[XY(0, 7)] = src[1];
-      dst += 2;
-    }
-    break;
-  case 0x14: case 0x4E: // 14 -  Down Warp Door
-  case 0x67: case 0x68: case 0x6c: case 0x6d: case 0x79:
-    RoomDraw_1x3_rightwards(4, src, dst);
-    break;
-  case 0x15:  // 15 -  Kholdstare Shell - BG2
-    if (dung_savegame_state_bits & 0x8000)
-      return;
-    src = SrcPtr(0x1dfa);
-    RoomDraw_SomeBigDecors(10, src, dsto);
-    break;
-  case 0x16:   // 16 -  Single Hammer Peg
-    RoomDraw_HammerPegSingle(src, dst, dsto);
-    break;
-  case 0x18:  // 18 -  Cell Lock
-    i = dung_num_bigkey_locks_x2 >> 1;
-    dung_num_bigkey_locks_x2 += 2;
-    if (!(dung_savegame_state_bits & kChestOpenMasks[i])) {
-      dung_chest_locations[i] = dsto * 2;
-      RoomDraw_Rightwards2x2(SrcPtr(0x1494), dst);
-    } else {
-      dung_chest_locations[i] = 0;
-    }
-    break;
-  case 0x19: {  // 19 -  Chest
-    if (main_module_index == 26)
-      return;
-    i = dung_num_chests_x2 >> 1;
-    dung_num_bigkey_locks_x2 = (dung_num_chests_x2 += 2);
-
-    int h = -1;
-    if (dung_hdr_tag[0] == 0x27 || dung_hdr_tag[0] == 0x3c ||
-        dung_hdr_tag[0] == 0x3e || dung_hdr_tag[0] >= 0x29 && dung_hdr_tag[0] < 0x33)
-      h = 0;
-    else if (dung_hdr_tag[1] == 0x27 || dung_hdr_tag[1] == 0x3c ||
-             dung_hdr_tag[1] == 0x3e || dung_hdr_tag[1] >= 0x29 && dung_hdr_tag[1] < 0x33)
-      h = 1;
-
-    dung_chest_locations[i] = 2 * (dsto | (dung_line_ptrs_row0 != 0x4000 ? 0 : 0x1000));
-    if (!(dung_savegame_state_bits & kChestOpenMasks[i])) {
-      if (h >= 0) {
-        if (!(dung_savegame_state_bits & kChestOpenMasks[h]))
-          return;
-        dung_hdr_tag[h] = 0;
-      }
-      RoomDraw_Rightwards2x2(SrcPtr(0x149c), dst);
-    } else {
-      dung_chest_locations[i] = 0;
-      if (h >= 0)
-        dung_hdr_tag[h] = 0;
-      RoomDraw_Rightwards2x2(SrcPtr(0x14a4), dst);
-    }
-    break;
-  }
-  case 0x1b:  // 1B -  Stair
-    dung_stairs_table_1[dung_num_stairs_1 >> 1] = dsto;
-    dung_num_stairs_1 += 2;
-stair1b:
-    for (int i = 0; i < 4; i++) {
-      dung_bg1[dsto + XY(0, 0)] = dung_bg2[dsto + XY(0, 0)] = src[0];
-      dung_bg1[dsto + XY(0, 1)] = dung_bg2[dsto + XY(0, 1)] = src[1];
-      dung_bg1[dsto + XY(0, 2)] = dung_bg2[dsto + XY(0, 2)] = src[2];
-      dung_bg1[dsto + XY(0, 3)] = dung_bg2[dsto + XY(0, 3)] = src[3];
-      src += 4, dsto += 1;
-    }
-    break;
-  case 0x1c:  // 1C -  Stair [S](Layer)
-    dung_stairs_table_2[dung_num_stairs_2 >> 1] = dsto;
-    dung_num_stairs_2 += 2;
-    goto stair1b;
-  case 0x1d:  //  1D -  Stair Wet [S](Layer)
-stairs_wet:
-    dung_stairs_table_2[dung_num_stairs_wet >> 1] = dsto;
-    dung_num_stairs_wet += 2;
-    RoomDraw_4x4(src, dst);
-    break;
-  case 0x1e:  // 1E -  Staircase going Up(Up)
-    dung_inter_starcases[dung_num_inter_room_upnorth_straight_stairs >> 1] = dsto;
-    dung_num_inter_room_upnorth_straight_stairs =
-      dung_num_inter_room_upsouth_straight_stairs =
-      dung_num_inter_room_southdown_stairs =
-      dung_num_wall_downnorth_spiral_stairs =
-      dung_num_wall_downnorth_spiral_stairs_2 =
-      dung_num_inter_room_downnorth_straight_stairs =
-      dung_num_inter_room_downsouth_straight_stairs = dung_num_inter_room_upnorth_straight_stairs + 2;
-    RoomDraw_Object_Nx4(4, src, dst);
-    break;
-  case 0x1f: // 1F -  Staircase Going Down (Up)
-    dung_inter_starcases[dung_num_inter_room_downnorth_straight_stairs >> 1] = dsto;
-    dung_num_inter_room_downnorth_straight_stairs =
-      dung_num_inter_room_downsouth_straight_stairs = dung_num_inter_room_downnorth_straight_stairs + 2;
-    RoomDraw_Object_Nx4(4, src, dst);
-    break;
-  case 0x20:  // 20 -  Staircase Going Up (Down)
-    dung_inter_starcases[dung_num_inter_room_upsouth_straight_stairs >> 1] = dsto;
-    dung_num_inter_room_upsouth_straight_stairs =
-      dung_num_inter_room_southdown_stairs =
-      dung_num_wall_downnorth_spiral_stairs =
-      dung_num_wall_downnorth_spiral_stairs_2 =
-      dung_num_inter_room_downnorth_straight_stairs =
-      dung_num_inter_room_downsouth_straight_stairs = dung_num_inter_room_upsouth_straight_stairs + 2;
-    RoomDraw_Object_Nx4(4, src, dst);
-    break;
-  case 0x21:  // 21 -  Staircase Going Down (Down)
-    dung_inter_starcases[dung_num_inter_room_downsouth_straight_stairs >> 1] = dsto;
-    dung_num_inter_room_downsouth_straight_stairs = dung_num_inter_room_downsouth_straight_stairs + 2;
-    RoomDraw_Object_Nx4(4, src, dst);
-    break;
-  case 0x26:  // 26 -  Staircase Going Up (Lower)
-    i = dung_num_inter_room_upnorth_straight_stairs >> 1;
-    dung_inter_starcases[i] = dsto | (dung_line_ptrs_row0 != 0x4000 ? 0 : 0x1000);
-    dung_num_inter_room_upnorth_straight_stairs =
-      dung_num_inter_room_upsouth_straight_stairs =
-      dung_num_inter_room_southdown_stairs =
-      dung_num_wall_downnorth_spiral_stairs =
-      dung_num_wall_downnorth_spiral_stairs_2 =
-      dung_num_inter_room_downnorth_straight_stairs =
-      dung_num_inter_room_downsouth_straight_stairs = dung_num_inter_room_upnorth_straight_stairs + 2;
-door26:
-    for (int i = 0; i < 4; i++) {
-      dung_bg1[dsto] = dung_bg2[dsto] = src[0];
-      dung_bg1[dsto + XY(0, 1)] = src[1];
-      dung_bg1[dsto + XY(0, 2)] = src[2];
-      dung_bg1[dsto + XY(0, 3)] = src[3];
-      src += 4, dsto++;
-    }
-    dsto += XY(-4, -4);
-copy_door_bg2:
-    dung_bg2[dsto + XY(0, 0)] |= 0x2000;
-    dung_bg2[dsto + XY(0, 1)] |= 0x2000;
-    dung_bg2[dsto + XY(0, 2)] |= 0x2000;
-    dung_bg2[dsto + XY(0, 3)] |= 0x2000;
-    break;
-  case 0x27:  // 27 -  Staircase Going Up (Lower)
-    i = dung_num_inter_room_downnorth_straight_stairs >> 1;
-    dung_inter_starcases[i] = dsto | (dung_line_ptrs_row0 != 0x4000 ? 0 : 0x1000);
-    dung_num_inter_room_downnorth_straight_stairs =
-      dung_num_inter_room_downsouth_straight_stairs =
-      dung_num_inter_room_downnorth_straight_stairs + 2;
-    goto door26;
-  case 0x28:  // 28 -  Staircase Going Down (Lower)
-    i = dung_num_inter_room_upsouth_straight_stairs >> 1;
-    dung_inter_starcases[i] = dsto | (dung_line_ptrs_row0 != 0x4000 ? 0 : 0x1000);
-    dung_num_inter_room_upsouth_straight_stairs =
-      dung_num_inter_room_southdown_stairs =
-      dung_num_wall_downnorth_spiral_stairs =
-      dung_num_wall_downnorth_spiral_stairs_2 =
-      dung_num_inter_room_downnorth_straight_stairs =
-      dung_num_inter_room_downsouth_straight_stairs =
-      dung_num_inter_room_upsouth_straight_stairs + 2;
-door28:
-    for (int i = 0; i < 4; i++) {
-      dung_bg1[dsto + XY(0, 0)] = src[0];
-      dung_bg1[dsto + XY(0, 1)] = src[1];
-      dung_bg1[dsto + XY(0, 2)] = src[2];
-      dung_bg1[dsto + XY(0, 3)] = dung_bg2[dsto + XY(0, 3)] = src[3];
-      src += 4, dsto++;
-    }
-    dsto += XY(-4, 4);
-    goto copy_door_bg2;
-  case 0x29:  // 29 -  Staircase Going Down (Lower)
-    i = dung_num_inter_room_downsouth_straight_stairs >> 1;
-    dung_inter_starcases[i] = dsto | (dung_line_ptrs_row0 != 0x4000 ? 0 : 0x1000);
-    dung_num_inter_room_downsouth_straight_stairs =
-      dung_num_inter_room_downsouth_straight_stairs + 2;
-    goto door28;
-  case 0x2a:  // 2A -  Dark Room BG2 Mask
-    RoomDraw_SingleLampCone(0x514, 0x16dc);
-    RoomDraw_SingleLampCone(0x554, 0x17f6);
-    RoomDraw_SingleLampCone(0x1514, 0x1914);
-    RoomDraw_SingleLampCone(0x1554, 0x1a2a);
-    break;
-  case 0x2b:  // 2B -  Staircase Going Down (Lower) not really
-    DrawBigGraySegment(0x1010, src, dst, dsto);
-    break;
-  case 0x2c: // 2C -  Large Pick Up Block
-    DrawBigGraySegment(0x2020, SrcPtr(0xe62), dst, dsto);
-    DrawBigGraySegment(0x2121, SrcPtr(0xe6a), dst + XY(2, 0), dsto + XY(2, 0));
-    DrawBigGraySegment(0x2222, SrcPtr(0xe72), dst + XY(0, 2), dsto + XY(0, 2));
-    DrawBigGraySegment(0x2323, SrcPtr(0xe7a), dst + XY(2, 2), dsto + XY(2, 2));
-    break;
-  case 0x2d: { // 2D -  Agahnim Altar
-    src = SrcPtr(0x1b4a);
-    uint16 *d = &dung_bg2[dsto];
-    for (int j = 0; j < 14; j++) {
-      i = src[0], d[0] = i, d[13] = i | 0x4000;
-      i = src[14], d[1] = d[2] = i, d[11] = d[12] = i ^ 0x4000;
-      i = src[28], d[3] = i, d[10] = i ^ 0x4000;
-      i = src[42], d[4] = i, d[9] = i ^ 0x4000;
-      i = src[56], d[5] = i, d[8] = i ^ 0x4000;
-      i = src[70], d[6] = i, d[7] = i ^ 0x4000;
-      src++, d += 64;
-    }
-    break;
-  }
-  case 0x2e:  // 2E -  Agahnim Room
-    RoomDraw_AgahnimsWindows(dsto);
-    break;
-  case 0x2f:  // 2F -  Pot
-    RoomDraw_SinglePot(src, dst, dsto);
-    break;
-  case 0x30: // 30 -  ??
-    DrawBigGraySegment(0x1212, src, dst, dsto);
-    break;
-  case 0x31: // 31 -  Big Chest
-    i = dung_num_chests_x2;
-    dung_chest_locations[i >> 1] = dsto * 2 | 0x8000 | (dung_line_ptrs_row0 != 0x4000 ? 0 : 0x2000);
-    if (dung_savegame_state_bits & kChestOpenMasks[i >> 1]) {
-      dung_chest_locations[i >> 1] = 0;
-      dung_num_chests_x2 = dung_num_bigkey_locks_x2 = i + 2;
-      RoomDraw_1x3_rightwards(4, SrcPtr(0x14c4), dst);
-    } else {
-      dung_num_chests_x2 = dung_num_bigkey_locks_x2 = i + 2;
-      RoomDraw_1x3_rightwards(4, SrcPtr(0x14ac), dst);
-    }
-    break;
-  case 0x32:  // 32 -  Big Chest Open
-    RoomDraw_1x3_rightwards(4, src, dst);
-    break;
-  case 0x33:  // 33 -  Stairs Submerged [S](layer)
-    if (dung_hdr_tag[1] == 27) {
-      if (!(save_dung_info[dungeon_room_index] & 0x100)) {
-        dung_hdr_bg2_properties = 0;
-        goto stairs_wet;
-      }
-      CGWSEL_copy = 2;
-      CGADSUB_copy = 0x62;
-    }
-    dung_stairs_table_2[dung_num_inroom_upsouth_stairs_water >> 1] = dsto;
-    dung_num_inroom_upsouth_stairs_water += 2;
-    RoomDraw_4x4(src, dst);
-    break;
-  case 0x34: case 0x35: case 0x36: case 0x37: case 0x38: case 0x39:
-    assert(0);
-    break;
-  case 0x3a: case 0x3b: // 3A -  Pipe Ride Mouth [S]
-    RoomDraw_1x3_rightwards(4, src, dst);
-    RoomDraw_1x3_rightwards(4, src + 12, dst + XY(0, 3));
-    break;
-  case 0x3c: case 0x3d: case 0x5c:  // 3C -  Pipe Ride Mouth [E]
-    RoomDraw_Object_Nx4(6, src, dst);
-    break;
-  case 0x47:  // 47 -  Bomb Floor
-    RoomDraw_BombableFloor(src, dst, dsto);
-    break;
-  case 0x48: case 0x66: case 0x6b: case 0x7a:  // 48 -  Fake Bomb Floor
-    RoomDraw_4x4(src, dst);
-    break;
-  case 0x4b: case 0x76: case 0x77:
-    RoomDraw_1x3_rightwards(8, src, dst);
-    break;
-  case 0x4c:
-    RoomDraw_SomeBigDecors(6, SrcPtr(0x1f92), dsto);
-    break;
-  case 0x4d: case 0x5d:  // 5D -  Forge
-    RoomDraw_1x3_rightwards(6, src, dst);
-    break;
-  case 0x54:
-    RoomDraw_FortuneTellerRoom(dsto);
-    break;
-  case 0x55:
-  case 0x5b:  // 5B -  Water Troof
-    dst[XY(0, 0)] = src[0];
-    dst[XY(1, 0)] = src[1];
-    dst[XY(2, 0)] = src[2];
-    for (int i = 0; i < 3; i++) {
-      dst[XY(0, 1)] = src[3];
-      dst[XY(1, 1)] = src[4];
-      dst[XY(2, 1)] = src[5];
-      dst += XY(0, 1);
-    }
-    dst[XY(0, 1)] = src[6];
-    dst[XY(1, 1)] = src[7];
-    dst[XY(2, 1)] = src[8];
-    break;
-
-  case 0x5a:  // 5A -  Plate on Table
-    RoomDraw_WaterHoldingObject(2, src, dst);
-    break;
-
-  case 0x60: case 0x61: // 60 -  Left/Right Warp Door
-    RoomDraw_1x3_rightwards(3, src, dst);
-    RoomDraw_1x3_rightwards(3, src + 9, dst + XY(0, 3));
-    break;
-
-  case 0x62: {  // 62 ??
-    src = SrcPtr(0x20f6);
-    uint16 *d = &dung_bg1[dsto];
-    for (int i = 0; i < 22; i++) {
-      d[XY(0, 0)] = src[0];
-      d[XY(0, 1)] = src[1];
-      d[XY(0, 2)] = src[2];
-      d[XY(0, 3)] = src[3];
-      d[XY(0, 4)] = src[4];
-      d[XY(0, 5)] = src[5];
-      d[XY(0, 6)] = src[6];
-      d[XY(0, 7)] = src[7];
-      d[XY(0, 8)] = src[8];
-      d[XY(0, 9)] = src[9];
-      d[XY(0, 10)] = src[10];
-      d += XY(1, 0), src += 11;
-    }
-    d -= XY(1, 0) * 22;
-    src = SrcPtr(0x22da);
-    for (int i = 0; i < 3; i++) {
-      d[XY(9, 11)] = src[0];
-      d[XY(9, 12)] = src[3];
-      d += XY(1, 0), src += 1;
-    }
-    break;
-  }
-  case 0x69: case 0x6a: case 0x6e: case 0x6f:  // 69 -  Left Crack Wall
-    RoomDraw_Object_Nx4(3, src, dst);
-    break;
-
-  case 0x70:  // 70 -  Window Light
-    RoomDraw_4x4(src, dst + XY(0, 0));
-    RoomDraw_4x4(SrcPtr(0x2376), dst + XY(0, 2));
-    RoomDraw_4x4(SrcPtr(0x2396), dst + XY(0, 6));
-    break;
-
-  case 0x71:  // 71 -  Floor Light Blind BG2
-    if (!(save_dung_info[101] & 0x100))
-      return;
-    Object_Draw8x8(src, dst);
-    break;
-  case 0x72:  // 72 -  TrinexxShell  Boss Goo/Shell BG2
-    if (dung_savegame_state_bits & 0x8000)
-      return;
-    RoomDraw_SomeBigDecors(10, src, dsto);
-    break;
-  case 0x73:  // 73 -  Entire floor is pit, Bg2 Full Mask
-    RoomDraw_FloorChunks(SrcPtr(0xe0));
-    break;
-  case 0x74:  // 74 -  Boss Entrance
-    Object_Draw8x8(src, dst);
-    break;
-
-  case 0x78:  // Triforce
-    RoomDraw_4x4(src, dst);
-    RoomDraw_4x4(src + 16, dst + XY(-2, 4));
-    RoomDraw_4x4(src + 16, dst + XY(2, 4));
-    break;
-  case 0x7b: // 7B -  Vitreous Boss?
-    RoomDraw_A_Many32x32Blocks(5, src, dst);
-    RoomDraw_A_Many32x32Blocks(5, src, dst + XY(0, 4));
-    break;
-  default:
-    assert(0);
-  }
-}
-
-void RoomBounds_AddA(RoomBounds *r) {
-  r->a0 += 0x100;
-  r->a1 += 0x100;
-}
-
-void RoomBounds_AddB(RoomBounds *r) {
-  r->b0 += 0x200;
-  r->b1 += 0x200;
-}
-
-void RoomBounds_SubB(RoomBounds *r) {
-  r->b0 -= 0x200;
-  r->b1 -= 0x200;
-}
-
-void RoomBounds_SubA(RoomBounds *r) {
-  r->a0 -= 0x100;
-  r->a1 -= 0x100;
-}
-
-void Dungeon_StartInterRoomTrans_Left() {
-  assert(submodule_index == 0);
-  link_quadrant_x ^= 1;
-  Dungeon_AdjustQuadrant();
-  RoomBounds_SubA(&room_bounds_x);
-  Dung_SaveDataForCurrentRoom();
-  DungeonTransition_AdjustCamera_X(link_quadrant_x ^ 1);
-  HandleEdgeTransition_AdjustCameraBoundaries(3);
-  submodule_index = 1;
-  if (link_quadrant_x) {
-    RoomBounds_SubB(&room_bounds_x);
-    BYTE(dungeon_room_index_prev) = dungeon_room_index;
-    if ((link_tile_below & 0xcf) == 0x89) {
-      dungeon_room_index = dung_hdr_travel_destinations[3];
-      Dungeon_AdjustForTeleportDoors(dungeon_room_index + 1, 0xff);
-    } else {
-      if ((uint8)dungeon_room_index != (uint8)dungeon_room_index2) {
-        BYTE(dungeon_room_index_prev) = dungeon_room_index2;
-        Dungeon_AdjustAfterSpiralStairs();
-      }
-      dungeon_room_index--;
-    }
-    submodule_index = 2;
-    if (room_transitioning_flags & 1) {
-      link_is_on_lower_level ^= 1;
-      link_is_on_lower_level_mirror = link_is_on_lower_level;
-    }
-    if (room_transitioning_flags & 2) {
-      cur_palace_index_x2 ^= 2;
-    }
-  }
-  room_transitioning_flags = 0;
-  quadrant_fullsize_y = (dung_blastwall_flag_y || (kLayoutQuadrantFlags[composite_of_layout_and_quadrant] & (link_quadrant_y ? 8 : 4)) == 0) ? 2 : 0;
-}
-
-void Dung_StartInterRoomTrans_Left_Plus() {
-  link_x_coord -= 8;
-  Dungeon_StartInterRoomTrans_Left();
-}
-
-void Dungeon_StartInterRoomTrans_Up() {
-  assert(submodule_index == 0);
-  link_quadrant_y ^= 2;
-  Dungeon_AdjustQuadrant();
-  RoomBounds_SubA(&room_bounds_y);
-  Dung_SaveDataForCurrentRoom();
-  DungeonTransition_AdjustCamera_Y(link_quadrant_y ^ 2);
-  HandleEdgeTransition_AdjustCameraBoundaries(1);
-  submodule_index = 1;
-  if (link_quadrant_y) {
-    RoomBounds_SubB(&room_bounds_y);
-    BYTE(dungeon_room_index_prev) = dungeon_room_index;
-    if (link_tile_below == 0x8e) {
-      Dung_HandleExitToOverworld();
-      return;
-    }
-
-    if (dungeon_room_index == 0) {
-      SaveDungeonKeys();
-      main_module_index = 25;
-      submodule_index = 0;
-      subsubmodule_index = 0;
-      return;
-    }
-
-    if (BYTE(dungeon_room_index2) == BYTE(dungeon_room_index)) {
-      BYTE(dungeon_room_index_prev) = BYTE(dungeon_room_index2);
-      Dungeon_AdjustAfterSpiralStairs();
-    }
-    BYTE(dungeon_room_index) -= 0x10;
-    submodule_index = 2;
-    if (room_transitioning_flags & 1) {
-      link_is_on_lower_level ^= 1;
-      link_is_on_lower_level_mirror = link_is_on_lower_level;
-    }
-    if (room_transitioning_flags & 2) {
-      cur_palace_index_x2 ^= 2;
-    }
-  }
-  room_transitioning_flags = 0;
-  quadrant_fullsize_x = (dung_blastwall_flag_x || (kLayoutQuadrantFlags[composite_of_layout_and_quadrant] & (link_quadrant_x ? 2 : 1)) == 0) ? 2 : 0;
-}
-
-void Dungeon_StartInterRoomTrans_Down() {
-  assert(submodule_index == 0);
-  link_quadrant_y ^= 2;
-  Dungeon_AdjustQuadrant();
-  RoomBounds_AddA(&room_bounds_y);
-  Dung_SaveDataForCurrentRoom();
-  DungeonTransition_AdjustCamera_Y(link_quadrant_y);
-  HandleEdgeTransition_AdjustCameraBoundaries(0);
-  submodule_index = 1;
-  if (!link_quadrant_y) {
-    RoomBounds_AddB(&room_bounds_y);
-    BYTE(dungeon_room_index_prev) = dungeon_room_index;
-    if (link_tile_below == 0x8e) {
-      Dung_HandleExitToOverworld();
-      return;
-    }
-
-    if ((uint8)dungeon_room_index != (uint8)dungeon_room_index2) {
-      BYTE(dungeon_room_index_prev) = dungeon_room_index2;
-      Dungeon_AdjustAfterSpiralStairs();
-    }
-    BYTE(dungeon_room_index) += 16;
-    submodule_index = 2;
-    if (room_transitioning_flags & 1) {
-      link_is_on_lower_level ^= 1;
-      link_is_on_lower_level_mirror = link_is_on_lower_level;
-    }
-    if (room_transitioning_flags & 2) {
-      cur_palace_index_x2 ^= 2;
-    }
-  }
-  room_transitioning_flags = 0;
-  quadrant_fullsize_x = (dung_blastwall_flag_x || (kLayoutQuadrantFlags[composite_of_layout_and_quadrant] & (link_quadrant_x ? 2 : 1)) == 0) ? 2 : 0;
-}
-
-void Dungeon_Store2x2(uint16 pos, uint16 t0, uint16 t1, uint16 t2, uint16 t3, uint8 attr) {
-  uint16 *dst = &vram_upload_data[vram_upload_offset >> 1];
-  dst[2] = t0;
-  dst[5] = t1;
-  dst[8] = t2;
-  dst[11] = t3;
-  overworld_tileattr[pos] = t0;
-  overworld_tileattr[pos + 64] = t1;
-  overworld_tileattr[pos + 1] = t2;
-  overworld_tileattr[pos + 65] = t3;
-
-  dung_bg2_attr_table[pos] = attr;
-  dung_bg2_attr_table[pos + 64] = attr;
-  dung_bg2_attr_table[pos + 1] = attr;
-  dung_bg2_attr_table[pos + 65] = attr;
-
-  dst[0] = Dungeon_MapVramAddr(pos + 0);
-  dst[3] = Dungeon_MapVramAddr(pos + 64);
-  dst[6] = Dungeon_MapVramAddr(pos + 1);
-  dst[9] = Dungeon_MapVramAddr(pos + 65);
-
-  dst[1] = 0x100;
-  dst[4] = 0x100;
-  dst[7] = 0x100;
-  dst[10] = 0x100;
-
-  dst[12] = 0xffff;
-
-  vram_upload_offset += 24;
-  nmi_load_bg_from_vram = 1;
-}
-
-uint16 Dungeon_MapVramAddr(uint16 pos) {
-  pos *= 2;
-  return swap16(((pos & 0x40) << 4) | ((pos & 0x303f) >> 1) | ((pos & 0xf80) >> 2));
-}
-
-uint16 Dungeon_MapVramAddrNoSwap(uint16 pos) {
-  pos *= 2;
-  return ((pos & 0x40) << 4) | ((pos & 0x303f) >> 1) | ((pos & 0xf80) >> 2);
-}
-
-void Door_Up_EntranceDoor(uint16 dsto) {
-  // NOTE: This don't pass the right value to RoomDraw_FlagDoorsAndGetFinalType
-  assert(0);
-}
-
-void Door_Down_EntranceDoor(uint16 dsto) {
-  // NOTE: This don't pass the right value to RoomDraw_FlagDoorsAndGetFinalType
-  assert(0);
-}
-
-void Door_Left_EntranceDoor(uint16 dsto) {
-  // NOTE: This don't pass the right value to RoomDraw_FlagDoorsAndGetFinalType
-  assert(0);
-}
-
-void Door_Right_EntranceDoor(uint16 dsto) {
-  // NOTE: This don't pass the right value to RoomDraw_FlagDoorsAndGetFinalType
-  assert(0);
-}
-
-void Door_Draw_Helper4(uint8 door_type, uint16 dsto) {
-  int t = RoomDraw_FlagDoorsAndGetFinalType(1, door_type, dsto), new_type;
-  if (t & 0x100)
-    return;
-
-  if ((new_type = kDoorType_Regular, t == kDoorType_1E || t == kDoorType_36) ||
-      (new_type = kDoorType_ShuttersTwoWay, t == kDoorType_38)) {
-    int i = (dung_cur_door_idx >> 1) - 1;
-    door_type_and_slot[i] = (i << 8) | new_type;
-    t = new_type;
-  }
-
-  const uint16 *src = SrcPtr(kDoorTypeSrcData2[t >> 1]);
-  uint16 *dst = DstoPtr(dsto);
-  for (int i = 0; i < 4; i++) {
-    dst[XY(0, 1)] = src[0];
-    dst[XY(0, 2)] = src[1];
-    dst[XY(0, 3)] = src[2];
-    dst++, src += 3;
-  }
-}
-
-const uint16 *GetRoomDoorInfo(int room) {
-  return (uint16 *)(kDungeonRoom + kDungeonRoomDoorOffs[room]);
-}
-
-const uint8 *GetRoomHeaderPtr(int room) {
-  return kDungeonRoomHeaders + kDungeonRoomHeadersOffs[room];
-}
-
-const uint8 *GetDefaultRoomLayout(int i) {
-  return kDungeonRoomDefault + kDungeonRoomDefaultOffs[i];
-}
-
-const uint8 *GetDungeonRoomLayout(int i) {
-  return kDungeonRoom + kDungeonRoomOffs[i];
-}
-
-static inline void WriteAttr1(int j, uint16 attr) {
-  dung_bg1_attr_table[j + 0] = attr;
-  dung_bg1_attr_table[j + 1] = attr >> 8;
-}
-
-static inline void WriteAttr2(int j, uint16 attr) {
-  dung_bg2_attr_table[j + 0] = attr;
-  dung_bg2_attr_table[j + 1] = attr >> 8;
-}
-
-void Dung_TagRoutine_0x22_0x3B(int k, uint8 j) {
-  if (dung_savegame_state_bits & 0x100) {
-    dung_hdr_tag[k] = 0;
-    dung_overlay_to_load = j;
-    dung_load_ptr_offs = 0;
-    subsubmodule_index = 0;
-    sound_effect_2 = 0x1b;
-    submodule_index = 3;
-  }
-}
-
-void Sprite_HandlePushedBlocks_One(int i) {
-  Oam_AllocateFromRegionB(4);
-
-  int y = (uint8)pushedblocks_y_lo[i] | (uint8)pushedblocks_y_hi[i] << 8;
-  int x = (uint8)pushedblocks_x_lo[i] | (uint8)pushedblocks_x_hi[i] << 8;
-
-  y -= BG2VOFS_copy2 + 1;
-  x -= BG2HOFS_copy2;
-
-  if (pushedblocks_some_index < 3) {
-    uint8 *oam = &g_ram[oam_cur_ptr];
-    oam[0] = x;
-    oam[1] = y;
-    oam[2] = 12;
-    oam[3] = 0x20;
-    g_ram[oam_ext_cur_ptr] = 2;
-  }
-}
-
-void Object_Draw_DoorLeft_3x4(uint16 src, int door) {
-  const uint16 *s = SrcPtr(src);
-  uint16 *dst = &dung_bg2[dung_door_tilemap_address[door] >> 1];
-  for (int i = 0; i < 3; i++) {
-    dst[XY(0, 0)] = s[0];
-    dst[XY(0, 1)] = s[1];
-    dst[XY(0, 2)] = s[2];
-    dst[XY(0, 3)] = s[3];
-    dst += 1, s += 4;
-  }
-}
-
-void Object_Draw_DoorRight_3x4(uint16 src, int door) {
-  const uint16 *s = SrcPtr(src);
-  uint16 *dst = &dung_bg2[dung_door_tilemap_address[door] >> 1];
-  for (int i = 0; i < 3; i++) {
-    dst[XY(1, 0)] = s[0];
-    dst[XY(1, 1)] = s[1];
-    dst[XY(1, 2)] = s[2];
-    dst[XY(1, 3)] = s[3];
-    dst += 1, s += 4;
-  }
-}
-
-void Dungeon_OpeningLockedDoor_Combined(bool skip_anim) {
-  uint8 ctr = 2;
-  int m, k, dma_ptr;
-
-  if (skip_anim) {
-    door_animation_step_indicator = 16;
-    goto step12;
-  }
-
-  door_animation_step_indicator++;
-  if (door_animation_step_indicator != 4) {
-    if (door_animation_step_indicator != 12)
-      goto middle;
-step12:
-    m = kUpperBitmasks[dung_bg2_attr_table[dung_cur_door_pos] & 7];
-    dung_door_opened_incl_adjacent |= m;
-    dung_door_opened |= m;
-    ctr = 4;
-  }
-  door_open_closed_counter = ctr;
-
-  k = dung_bg2_attr_table[dung_cur_door_pos] & 0xf;
-  dma_ptr = DrawDoorOpening_Step1(k, 0);
-  Dungeon_PrepOverlayDma_nextPrep(dma_ptr, dung_door_tilemap_address[k]);
-  sound_effect_2 = 21;
-  nmi_copy_packets_flag = 1;
-
-middle:
-  if (door_animation_step_indicator == 16) {
-    Dungeon_LoadToggleDoorAttr_OtherEntry(dung_bg2_attr_table[dung_cur_door_pos] & 0xf);
-    if (dung_bg2_attr_table[dung_cur_door_pos] >= 0xf0) {
-      k = dung_bg2_attr_table[dung_cur_door_pos] & 0xf;
-      uint8 door_type = door_type_and_slot[k];
-      if (door_type >= kDoorType_StairMaskLocked0 && door_type <= kDoorType_StairMaskLocked3)
-        DrawCompletelyOpenDoor();
-    }
-    submodule_index = 0;
-  }
-}
-
-const DungPalInfo *GetDungPalInfo(int idx) {
-  return &kDungPalinfos[idx];
-}
-
-uint16 Dungeon_GetTeleMsg(int room) {
-  return kDungeonRoomTeleMsg[room];
-}
-
-bool Dungeon_IsPitThatHurtsPlayer() {
-  for (int i = kDungeonPitsHurtPlayer_SIZE / 2 - 1; i >= 0; i--) {
-    if (kDungeonPitsHurtPlayer[i] == dungeon_room_index)
-      return true;
-  }
-  return false;
-
-}
-
-void Dungeon_PrepareNextRoomQuadrantUpload() {  // 80913f
-  int ofs = (overworld_screen_transition & 0xf) + dung_cur_quadrant_upload;
-  uint16 *src = &dung_bg2[kUploadBgSrcs[ofs] / 2];
-  int p = 0;
-  do {
-    UploadVram_32x32 *d = (UploadVram_32x32 *)&g_ram[0x1000 + p * 2];
-    do {
-      d->row[0].col[0] = src[XY(0, 0)];
-      d->row[0].col[1] = src[XY(1, 0)];
-      d->row[1].col[0] = src[XY(0, 1)];
-      d->row[1].col[1] = src[XY(1, 1)];
-      d->row[2].col[0] = src[XY(0, 2)];
-      d->row[2].col[1] = src[XY(1, 2)];
-      d->row[3].col[0] = src[XY(0, 3)];
-      d->row[3].col[1] = src[XY(1, 3)];
-      d = (UploadVram_32x32 *)((uint16 *)d + 2);
-      src += 2, p += 2;
-    } while (p & 0x1f);
-    src += 224;
-    p += 128 - 32;
-  } while (p != 0x400);
-  dung_cur_quadrant_upload += 4;
-  BYTE(nmi_load_target_addr) = kUploadBgDsts[ofs];
-  nmi_subroutine_index = 1;
-  nmi_disable_core_updates = 1;
-}
-
-void WaterFlood_BuildOneQuadrantForVRAM() {  // 8091c4
-
-  // It never seems to be 25 here, so skip updating water stuff
-  assert(dung_hdr_tag[0] != 25);
-  TileMapPrep_NotWaterOnTag();
-}
-
-void TileMapPrep_NotWaterOnTag() {  // 8091d3
-  int ofs = (overworld_screen_transition & 0xf) + dung_cur_quadrant_upload;
-  uint16 *src = &dung_bg1[kUploadBgSrcs[ofs] / 2];
-  int p = 0;
-  do {
-    UploadVram_32x32 *d = (UploadVram_32x32 *)&g_ram[0x1000 + p * 2];
-    do {
-      d->row[0].col[0] = src[XY(0, 0)];
-      d->row[0].col[1] = src[XY(1, 0)];
-      d->row[1].col[0] = src[XY(0, 1)];
-      d->row[1].col[1] = src[XY(1, 1)];
-      d->row[2].col[0] = src[XY(0, 2)];
-      d->row[2].col[1] = src[XY(1, 2)];
-      d->row[3].col[0] = src[XY(0, 3)];
-      d->row[3].col[1] = src[XY(1, 3)];
-      d = (UploadVram_32x32 *)((uint16 *)d + 2);
-      src += 2, p += 2;
-    } while (p & 0x1f);
-    src += 224;
-    p += 128 - 32;
-  } while (p != 0x400);
-  BYTE(nmi_load_target_addr) = kUploadBgDsts[ofs] + 0x10;
-  nmi_subroutine_index = 1;
-  nmi_disable_core_updates = 1;
-}
-
-void OrientLampLightCone() {  // 80f567
-  static const uint16 kOrientLampBgTab0[] = { 0, 256, 0, 256 };
-  static const uint16 kOrientLampBgTab1[] = { 0, 0, 256, 256 };
-  static const int16 kOrientLampBgTab2[] = { 52, -2, 56, 6 };
-  static const int16 kOrientLampBgTab3[] = { 64, 64, 82, -176 };
-  static const int16 kOrientLampBgTab4[] = { 128, 384, 160, 160 };
-
-  if (!hdr_dungeon_dark_with_lantern || submodule_index == 20)
-    return;
-
-  uint8 a = link_direction_facing >> 1, idx = a;
-  if (is_standing_in_doorway) {
-    idx = (is_standing_in_doorway & 0xfe);
-    if (idx) {
-      if (a < 2)
-        idx += ((uint8)(link_x_coord + 8) >= 0x80);
-      else
-        idx = a;
-    } else {
-      if (a >= 2)
-        idx += ((uint8)link_y_coord >= 0x80);
-      else
-        idx = a;
-    }
-  }
-
-  if (idx < 2) {
-    BG1HOFS_copy2 = BG2HOFS_copy2 - (link_x_coord - 0x77) + kOrientLampBgTab0[idx];
-    uint16 t = BG2VOFS_copy2 - (link_y_coord - 0x58) + kOrientLampBgTab1[idx] + kOrientLampBgTab2[idx] + kOrientLampBgTab3[idx];
-    if ((int16)t < 0) t = 0;
-    if (t > kOrientLampBgTab4[idx]) t = kOrientLampBgTab4[idx];
-    BG1VOFS_copy2 = t - kOrientLampBgTab3[idx];
-  } else {
-    BG1VOFS_copy2 = BG2VOFS_copy2 - (link_y_coord - 0x72) + kOrientLampBgTab1[idx];
-    uint16 t = BG2HOFS_copy2 - (link_x_coord - 0x58) + kOrientLampBgTab0[idx] + kOrientLampBgTab2[idx] + kOrientLampBgTab3[idx];
-    if ((int16)t < 0) t = 0;
-    if (t > kOrientLampBgTab4[idx]) t = kOrientLampBgTab4[idx];
-    BG1HOFS_copy2 = t - kOrientLampBgTab3[idx];
-  }
-}
-
-void PrepareDungeonExitFromBossFight() {  // 80f945
-  SavePalaceDeaths();
-  SaveDungeonKeys();
-  dung_savegame_state_bits |= 0x8000;
-  Dungeon_FlagRoomData_Quadrants();
-
-  int j = FindInByteArray(kDungeonExit_From, BYTE(dungeon_room_index), countof(kDungeonExit_From));
-  assert(j >= 0);
-  BYTE(dungeon_room_index) = kDungeonExit_To[j];
-  if (BYTE(dungeon_room_index) == 0x20) {
-    sram_progress_indicator = 3;
-    save_ow_event_info[2] |= 0x20;
-    savegame_is_darkworld ^= 0x40;
-    Sprite_LoadGraphicsProperties_light_world_only();
-    Ancilla_TerminateSelectInteractives(0);
-    link_disable_sprite_damage = 0;
-    button_b_frames = 0;
-    button_mask_b_y = 0;
-    link_force_hold_sword_up = 0;
-    flag_is_link_immobilized = 1;
-    saved_module_for_menu = 8;
-    main_module_index = 21;
-    submodule_index = 0;
-    subsubmodule_index = 0;
-  } else if (BYTE(dungeon_room_index) == 0xd) {
-    main_module_index = 24;
-    submodule_index = 0;
-    overworld_map_state = 0;
-    CGADSUB_copy = 0x20;
-  } else {
-    if (j >= 3) {
-      music_control = 0xf1;
-      music_unk1 = 0xf1;
-      main_module_index = 22;
-    } else {
-      main_module_index = 19;
-    }
-    saved_module_for_menu = 8;
-    submodule_index = 0;
-    subsubmodule_index = 0;
-  }
-}
-
-void SavePalaceDeaths() {  // 80f9dd
-  int j = BYTE(cur_palace_index_x2);
-  deaths_per_palace[j >> 1] = death_save_counter;
-  if (j != 8)
-    death_save_counter = 0;
-}
-
-void Dungeon_LoadRoom() {  // 81873a
-  Dungeon_LoadHeader();
-  dung_unk6 = 0;
-
-  dung_hdr_collision_2_mirror = dung_hdr_collision_2;
-  dung_hdr_collision_2_mirror_PADDING = dung_hdr_tag[0];
-  dung_some_subpixel[0] = 0x30;
-  dung_some_subpixel[1] = 0xff;
-  dung_floor_move_flags = 0;
-  word_7E0420 = 0;
-  dung_floor_x_vel = dung_floor_y_vel = 0;
-  dung_floor_x_offs = dung_floor_y_offs = 0;
-  invisible_door_dir_and_index_x2 = 0xffff;
-  dung_blastwall_flag_x = dung_blastwall_flag_y = 0;
-  dung_unk_blast_walls_2 = dung_unk_blast_walls_3 = 0;
-  water_hdma_var5 = 0;
-  dung_num_toggle_floor = 0;
-  dung_num_toggle_palace = 0;
-  dung_unk2 = 0;
-  dung_cur_quadrant_upload = 0;
-  dung_num_inter_room_upnorth_stairs = 0;
-  dung_num_inter_room_southdown_stairs = 0;
-  dung_num_inroom_upnorth_stairs = 0;
-  dung_num_inroom_southdown_stairs = 0;
-  dung_num_interpseudo_upnorth_stairs = 0;
-  dung_num_inroom_upnorth_stairs_water = 0;
-  dung_num_activated_water_ladders = 0;
-  dung_num_water_ladders = 0;
-  dung_some_stairs_unk4 = 0;
-  dung_num_stairs_1 = 0;
-  dung_num_stairs_2 = 0;
-  dung_num_stairs_wet = 0;
-  dung_num_inroom_upsouth_stairs_water = 0;
-  dung_num_wall_upnorth_spiral_stairs = 0;
-  dung_num_wall_downnorth_spiral_stairs = 0;
-  dung_num_wall_upnorth_spiral_stairs_2 = 0;
-  dung_num_wall_downnorth_spiral_stairs_2 = 0;
-  dung_num_inter_room_upnorth_straight_stairs = 0;
-  dung_num_inter_room_upsouth_straight_stairs = 0;
-  dung_num_inter_room_downnorth_straight_stairs = 0;
-  dung_num_inter_room_downsouth_straight_stairs = 0;
-  dung_exit_door_addresses[0] = 0;
-  dung_exit_door_addresses[1] = 0;
-  dung_exit_door_addresses[2] = 0;
-  dung_exit_door_addresses[3] = 0;
-  dung_exit_door_count = 0;
-  dung_door_switch_triggered = 0;
-  dung_num_star_shaped_switches = 0;
-  dung_misc_objs_index = 0;
-  dung_index_of_torches = 0;
-  dung_num_chests_x2 = 0;
-  dung_num_bigkey_locks_x2 = 0;
-  dung_unk5 = 0;
-  dung_cur_door_idx = 0;
-
-  for (int i = 0; i < 16; i++) {
-    dung_door_tilemap_address[i] = 0;
-    door_type_and_slot[i] = 0;
-    dung_door_direction[i] = 0;
-    dung_torch_timers[i] = 0;
-    dung_replacement_tile_state[i] = 0;
-    dung_object_pos_in_objdata[i] = 0;
-    dung_object_tilemap_pos[i] = 0;
-  }
-
-  const uint8 *cur_p0 = GetDungeonRoomLayout(dungeon_room_index);
-  dung_load_ptr_offs = 0;
-  RoomDraw_DrawFloors(cur_p0);
-
-  uint16 old_offs = dung_load_ptr_offs;
-  dung_layout_and_starting_quadrant = cur_p0[dung_load_ptr_offs];
-
-  const uint8 *cur_p1 = GetDefaultRoomLayout(dung_layout_and_starting_quadrant >> 2);
-
-  dung_load_ptr_offs = 0;
-  RoomDraw_DrawAllObjects(cur_p1);
-
-  dung_load_ptr_offs = old_offs + 1;
-
-  RoomDraw_DrawAllObjects(cur_p0);  // Draw Layer 1 objects to BG2
-  dung_load_ptr_offs += 2;
-
-  memcpy(&dung_line_ptrs_row0, kDungeon_DrawObjectOffsets_BG2, 33);
-  RoomDraw_DrawAllObjects(cur_p0);  // Draw Layer 2 objects to BG2
-  dung_load_ptr_offs += 2;
-
-  memcpy(&dung_line_ptrs_row0, kDungeon_DrawObjectOffsets_BG1, 33);
-  RoomDraw_DrawAllObjects(cur_p0);  // Draw Layer 3 objects to BG2
-
-  for (dung_load_ptr_offs = 0; dung_load_ptr_offs != 0x18C; dung_load_ptr_offs += 4) {
-    MovableBlockData m = movable_block_datas[dung_load_ptr_offs >> 2];
-    if (m.room == dungeon_room_index)
-      DrawObjects_PushableBlock(m.tilemap, dung_load_ptr_offs);
-  }
-
-  uint16 t;
-
-  dung_index_of_torches = dung_index_of_torches_start = dung_misc_objs_index;
-  int i = 0;
-  do {
-    if (dung_torch_data[i >> 1] == dungeon_room_index) {
-      i += 2;
-
-      do {
-        t = dung_torch_data[i >> 1];
-        i += 2;
-        DrawObjects_LightableTorch(t, i - 2);
-      } while (dung_torch_data[i >> 1] != 0xffff);
-      break;
-    }
-    i += 2;
-    do {
-      t = dung_torch_data[i >> 1];
-      i += 2;
-    } while (t != 0xffff);
-  } while (i != 0x120);
-
-  dung_load_ptr_offs = 0x120;
-}
-
-void RoomDraw_DrawAllObjects(const uint8 *level_data) {  // 8188e4
-  for (;;) {
-    dung_draw_width_indicator = dung_draw_height_indicator = 0;
-    uint16 d = WORD(level_data[dung_load_ptr_offs]);
-    if (d == 0xffff)
-      return;
-    if (d == 0xfff0)
-      break;
-    RoomData_DrawObject(d, level_data);
-  }
-  for (;;) {
-    dung_load_ptr_offs += 2;
-    uint16 d = WORD(level_data[dung_load_ptr_offs]);
-    if (d == 0xffff)
-      return;
-    RoomData_DrawObject_Door(d);
-  }
-}
-
-void RoomData_DrawObject_Door(uint16 a) {  // 818916
-  uint8 door_type = a >> 8;
-  uint8 position = a >> 4 & 0xf;
-
-  switch (a & 3) {
-  case 0: RoomDraw_Door_North(door_type, position); break;
-  case 1: RoomDraw_Door_South(door_type, position); break;
-  case 2: RoomDraw_Door_West(door_type, position); break;
-  case 3: RoomDraw_Door_East(door_type, position); break;
-  }
-}
-
-void RoomData_DrawObject(uint16 r0, const uint8 *level_data) {  // 81893c
-  uint16 offs = dung_load_ptr_offs;
-  uint8 idx = level_data[offs + 2];
-  dung_load_ptr_offs = offs + 3;
-
-  if ((r0 & 0xfc) != 0xfc) {
-    dung_draw_width_indicator = (r0 & 3);
-    dung_draw_height_indicator = (r0 >> 8) & 3;
-    uint8 x = (uint8)r0 >> 2;
-    uint8 y = (r0 >> 10);
-    uint16 dst = y * 64 + x;
-    if (idx < 0xf8) {
-      LoadType1ObjectSubtype1(idx, DstoPtr(dst), dst);
-    } else {
-      idx = (idx & 7) << 4 | ((r0 >> 8) & 3) << 2 | (r0 & 3);
-      LoadType1ObjectSubtype3(idx, DstoPtr(dst), dst);
-    }
-  } else {
-    uint8 x = (r0 & 3) << 4 | (r0 >> 12) & 0xf;
-    uint8 y = ((r0 >> 8) & 0xf) << 2 | (idx >> 6);
-    uint16 dst = y * 64 + x;
-    LoadType1ObjectSubtype2(idx & 0x3f, DstoPtr(dst), dst);
-  }
-}
-
-void RoomDraw_DrawFloors(const uint8 *level_data) {  // 8189dc
-  memcpy(&dung_line_ptrs_row0, kDungeon_DrawObjectOffsets_BG2, 33);
-  uint8 ft = level_data[dung_load_ptr_offs++];
-  dung_floor_1_filler_tiles = ft & 0xf0;
-  RoomDraw_FloorChunks(SrcPtr(dung_floor_1_filler_tiles));
-  memcpy(&dung_line_ptrs_row0, kDungeon_DrawObjectOffsets_BG1, 33);
-  dung_floor_2_filler_tiles = (ft & 0xf) << 4;
-  RoomDraw_FloorChunks(SrcPtr(dung_floor_2_filler_tiles));
-}
-
-void RoomDraw_FloorChunks(const uint16 *src) {  // 818a1f
-  static const uint16 kDungeon_QuadrantOffsets[] = { 0x0, 0x40, 0x1000, 0x1040 };
-  for (int i = 0; i < 4; i++) {
-    uint16 *dst = DstoPtr(kDungeon_QuadrantOffsets[i] / 2);
-    for (int j = 0; j < 8; j++) {
-      RoomDraw_A_Many32x32Blocks(8, src, dst);
-      dst += XY(0, 4);
-    }
-  }
-}
-
-void RoomDraw_A_Many32x32Blocks(int n, const uint16 *src, uint16 *dst) {  // 818a44
-  do {
-    // draw 4x2 twice
-    for (int i = 0; i < 2; i++) {
-      dst[XY(0, 0)] = src[0];
-      dst[XY(1, 0)] = src[1];
-      dst[XY(2, 0)] = src[2];
-      dst[XY(3, 0)] = src[3];
-      dst[XY(0, 1)] = src[4];
-      dst[XY(1, 1)] = src[5];
-      dst[XY(2, 1)] = src[6];
-      dst[XY(3, 1)] = src[7];
-      dst += XY(0, 2);
-    }
-    dst += XY(4, -4);
-  } while (--n);
-}
-
-void RoomDraw_1x3_rightwards(int n, const uint16 *src, uint16 *dst) {  // 818d80
-  do {
-    dst[XY(0, 0)] = src[0];
-    dst[XY(0, 1)] = src[1];
-    dst[XY(0, 2)] = src[2];
-    dst++, src += 3;
-  } while (--n);
-}
-
-bool RoomDraw_CheckIfWallIsMoved() {  // 819298
-  dung_some_subpixel[0] = dung_some_subpixel[1] = 0;
-  dung_floor_move_flags = 0;
-  int i;
-  if ((i = 0, dung_hdr_tag[0] >= 0x1c && dung_hdr_tag[0] < 0x20) ||
-      (i = 1, dung_hdr_tag[1] >= 0x1c && dung_hdr_tag[1] < 0x20)) {
-    if (dung_savegame_state_bits & (0x1000 >> i)) {
-      dung_hdr_collision = 0;
-      dung_hdr_tag[i] = 0;
-      dung_hdr_bg2_properties = 0;
-      return false;
-    }
-  }
-  return true;
-}
-
-void MovingWall_FillReplacementBuffer(int dsto) {  // 8192d1
-  for (int i = 0; i < 64; i++)
-    moving_wall_arr1[i] = 0x1ec;
-  moving_wall_var1 = (dsto & 0x1f) | (dsto & 0x20 ? 0x400 : 0) | 0x1000;
-}
-
-void Object_Table_Helper(const uint16 *src, uint16 *dst) {  // 8193f7
-  int n = dung_draw_width_indicator;
-  dst[0] = src[0];
-  do {
-    dst[1] = src[1];
-    dst[2] = src[2];
-    dst += 2;
-  } while (--n);
-  dst[1] = src[3];
-}
-
-void DrawWaterThing(uint16 *dst, const uint16 *src) {  // 8195a0
-  for (int i = 3; i >= 0; i--) {
-    dst[0] = src[0];
-    dst[1] = src[1];
-    dst[2] = src[2];
-    dst[3] = src[3];
-    dst += XY(0, 1), src += 4;
-  }
-}
-
-void RoomDraw_4x4(const uint16 *src, uint16 *dst) {  // 8197ed
-  RoomDraw_Object_Nx4(4, src, dst);
-}
-
-void RoomDraw_Object_Nx4(int n, const uint16 *src, uint16 *dst) {  // 8197f0
-  do {
-    dst[XY(0, 0)] = src[0];
-    dst[XY(0, 1)] = src[1];
-    dst[XY(0, 2)] = src[2];
-    dst[XY(0, 3)] = src[3];
-    src += 4;
-    dst += XY(1, 0);
-  } while (--n);
-}
-
-void Object_DrawNx4_BothBgs(int n, const uint16 *src, int dsto) {  // 819819
-  do {
-    dung_bg1[dsto + XY(0, 0)] = dung_bg2[dsto + XY(0, 0)] = src[0];
-    dung_bg1[dsto + XY(0, 1)] = dung_bg2[dsto + XY(0, 1)] = src[1];
-    dung_bg1[dsto + XY(0, 2)] = dung_bg2[dsto + XY(0, 2)] = src[2];
-    dung_bg1[dsto + XY(0, 3)] = dung_bg2[dsto + XY(0, 3)] = src[3];
-    src += 4, dsto += 1;
-  } while (--n);
-}
-
-void RoomDraw_Rightwards2x2(const uint16 *src, uint16 *dst) {  // 819895
-  dst[XY(0, 0)] = src[0];
-  dst[XY(0, 1)] = src[1];
-  dst[XY(1, 0)] = src[2];
-  dst[XY(1, 1)] = src[3];
-}
-
-void Object_Draw_3x2(const uint16 *src, uint16 *dst) {  // 819d04
-  dst[XY(0, 0)] = src[0];
-  dst[XY(1, 0)] = src[1];
-  dst[XY(2, 0)] = src[2];
-  dst[XY(0, 1)] = src[3];
-  dst[XY(1, 1)] = src[4];
-  dst[XY(2, 1)] = src[5];
-}
-
-void RoomDraw_WaterHoldingObject(int n, const uint16 *src, uint16 *dst) {  // 819d6f
-  do {
-    dst[0] = src[0];
-    dst[1] = src[1];
-    dst[2] = src[2];
-    dst[3] = src[3];
-    src += 4;
-    dst += XY(0, 1);
-  } while (--n);
-}
-
-void RoomDraw_SomeBigDecors(int n, const uint16 *src, uint16 dsto) {  // 819da2
-  uint16 *dst = &dung_bg2[dsto | (dung_line_ptrs_row0 != 0x4000 ? 0 : 0x1000)];
-  for (int i = 0; i < 8; i++) {
-    for (int j = 0; j < n; j++)
-      dst[j] = src[j];
-    dst += 64, src += n;
-  }
-}
-
-void RoomDraw_SingleLampCone(uint16 a, uint16 y) {  // 819e06
-  const uint16 *src = SrcPtr(y);
-  uint16 *dst = &dung_bg1[a / 2];
-  for (int i = 0; i < 12; i++) {
-    for (int j = 0; j < 12; j++)
-      *dst++ = *src++;
-    dst += 64 - 12;
-  }
-}
-
-void RoomDraw_AgahnimsWindows(uint16 dsto) {  // 819ea3
-  const uint16 *src;
-
-  uint16 *d = &dung_bg2[dsto];
-  src = SrcPtr(0x1BF2);
-  for (int i = 0; i < 6; i++) {
-    d[XY(7, 4)] = d[XY(13, 4)] = d[XY(19, 4)] = src[0];
-    d[XY(7, 5)] = d[XY(13, 5)] = d[XY(19, 5)] = src[1];
-    d[XY(7, 6)] = d[XY(13, 6)] = d[XY(19, 6)] = src[2];
-    d[XY(7, 7)] = d[XY(13, 7)] = d[XY(19, 7)] = src[3];
-    src += 4, d += XY(1, 0);
-  }
-  d -= 6;
-
-  src = SrcPtr(0x1c22);
-  for (int i = 0; i < 5; i++) {
-    int j = src[0];
-    d[XY(2, 10)] = d[XY(3, 9)] = d[XY(4, 8)] = d[XY(5, 7)] = d[XY(6, 6)] = d[XY(7, 5)] = d[XY(8, 4)] = j;
-    d[XY(23, 4)] = d[XY(24, 5)] = d[XY(25, 6)] = d[XY(26, 7)] = d[XY(27, 8)] = d[XY(28, 9)] = d[XY(29, 10)] = j | 0x4000;
-    src++, d += XY(0, 1);
-  }
-  d -= XY(0, 1) * 5;
-
-  src = SrcPtr(0x1c2c);
-  for (int i = 0; i < 6; i++) {
-    int j = src[0];
-    d[XY(2, 11)] = d[XY(2, 17)] = d[XY(2, 23)] = j;
-    d[XY(29, 11)] = d[XY(29, 17)] = d[XY(29, 23)] = j | 0x4000;
-    j = src[1];
-    d[XY(3, 11)] = d[XY(3, 17)] = d[XY(3, 23)] = j;
-    d[XY(28, 11)] = d[XY(28, 17)] = d[XY(28, 23)] = j | 0x4000;
-    j = src[2];
-    d[XY(4, 11)] = d[XY(4, 17)] = d[XY(4, 23)] = j;
-    d[XY(27, 11)] = d[XY(27, 17)] = d[XY(27, 23)] = j | 0x4000;
-    j = src[3];
-    d[XY(5, 11)] = d[XY(5, 17)] = d[XY(5, 23)] = j;
-    d[XY(26, 11)] = d[XY(26, 17)] = d[XY(26, 23)] = j | 0x4000;
-    src += 4, d += XY(0, 1);
-  }
-  d -= XY(0, 1) * 6;
-
-  src = SrcPtr(0x1c5c);
-  for (int i = 0; i < 6; i++) {
-    d[XY(12, 9)] = d[XY(18, 9)] = src[0];
-    d[XY(12, 10)] = d[XY(18, 10)] = src[6];
-    src += 1, d += XY(1, 0);
-  }
-  d -= XY(1, 0) * 6;
-
-  src = SrcPtr(0x1c74);
-  for (int i = 0; i < 6; i++) {
-    d[XY(7, 14)] = d[XY(7, 20)] = src[0];
-    d[XY(8, 14)] = d[XY(8, 20)] = src[1];
-    src += 2, d += XY(0, 1);
-  }
-  d -= XY(0, 1) * 6;
-
-  src = SrcPtr(0x1c8c);
-  for (int i = 0; i < 5; i++) {
-    d[XY(7, 9)] = src[0];
-    d[XY(7, 10)] = src[1];
-    d[XY(7, 11)] = src[2];
-    d[XY(7, 12)] = src[3];
-    d[XY(7, 13)] = src[4];
-    src += 5, d += XY(1, 0);
-  }
-  d -= XY(1, 0) * 5;
-
-  for (int i = 0; i < 4; i++) {
-    d[XY(14, 28)] |= 0x2000;
-    d[XY(14, 29)] |= 0x2000;
-    d += XY(1, 0);
-  }
-}
-
-void RoomDraw_FortuneTellerRoom(uint16 dsto) {  // 81a095
-  const uint16 *src = SrcPtr(0x202e), *src_org = src;
-  uint16 *d = &dung_bg2[dsto];
-  int j;
-
-  for (int i = 0; i < 6; i++) {
-    d[XY(1, 0)] =
-      d[XY(2, 0)] =
-      d[XY(1, 1)] =
-      d[XY(2, 1)] = src[0];
-    d[XY(1, 2)] = (j = src[1]);
-    d[XY(2, 2)] = j | 0x4000;
-    d += XY(2, 0);
-  }
-  d -= XY(2, 0) * 6;
-
-  for (int i = 0; i < 3; i++) {
-    d[XY(0, 3)] = d[XY(2, 3)] = d[XY(10, 3)] = d[XY(12, 3)] = (j = src[2]);
-    d[XY(1, 3)] = d[XY(3, 3)] = d[XY(11, 3)] = d[XY(13, 3)] = j | 0x4000;
-    d[XY(4, 3)] = d[XY(6, 3)] = d[XY(8, 3)] = (j = src[5]);
-    d[XY(5, 3)] = d[XY(7, 3)] = d[XY(9, 3)] = j | 0x4000;
-    src++, d += XY(0, 1);
-  }
-  d -= XY(0, 1) * 3;
-
-  d[XY(0, 0)] = d[XY(0, 1)] = (j = src[5]);
-  d[XY(13, 0)] = d[XY(13, 1)] = j | 0x4000;
-  d[XY(0, 2)] = (j = src[6]);
-  d[XY(13, 2)] = j | 0x4000;
-
-  src = src_org;
-  for (int i = 0; i < 4; i++) {
-    d[XY(3, 10)] = (j = src[10]);
-    d[XY(10, 10)] = j ^ 0x4000;
-    d[XY(4, 10)] = (j = src[14]);
-    d[XY(9, 10)] = j ^ 0x4000;
-    d[XY(5, 10)] = (j = src[18]);
-    d[XY(8, 10)] = j ^ 0x4000;
-    d[XY(6, 10)] = (j = src[22]);
-    d[XY(7, 10)] = j ^ 0x4000;
-    src++, d += XY(0, 1);
-  }
-}
-
-void Object_Draw8x8(const uint16 *src, uint16 *dst) {  // 81a7dc
-  RoomDraw_4x4(src, dst + XY(0, 0));
-  RoomDraw_4x4(src + 16, dst + XY(4, 0));
-  RoomDraw_4x4(src + 32, dst + XY(0, 4));
-  RoomDraw_4x4(src + 48, dst + XY(4, 4));
-}
-
-void RoomDraw_Door_North(int type, int pos_enum) {  // 81a81c
-  uint16 dsto = kDoorPositionToTilemapOffs_Up[pos_enum] / 2;
-  if (type == kDoorType_LgExplosion)
-    RoomDraw_Door_ExplodingWall(pos_enum);
-  else if (type == kDoorType_PlayerBgChange)
-    RoomDraw_MarkLayerToggleDoor(dsto - 0xfe / 2);
-  else if (type == kDoorType_Slashable)
-    RoomDraw_NorthCurtainDoor(dsto);
-  else if (type == kDoorType_EntranceDoor)
-    Door_Up_EntranceDoor(dsto);
-  else if (type == kDoorType_ThroneRoom)
-    RoomDraw_MarkDungeonToggleDoor(dsto - 0xfe / 2);
-  else if (type == kDoorType_Regular2) {
-    RoomDraw_MakeDoorPartsHighPriority_Y(dsto & (0xF07F / 2));
-    RoomDraw_NormalRangedDoors_North(type, dsto, pos_enum);
-  } else if (type == kDoorType_ExitToOw) {
-    dung_exit_door_addresses[dung_exit_door_count >> 1] = dsto * 2;
-    dung_exit_door_count += 2;
-  } else if (type == kDoorType_WaterfallTunnel) {
-    RoomDraw_NormalRangedDoors_North(type, dsto, pos_enum);
-    Door_PrioritizeCurDoor();
-  } else if (type >= kDoorType_StairMaskLocked0 && type <= kDoorType_StairMaskLocked3) {
-    Door_Up_StairMaskLocked(type, dsto);
-  } else if (type >= kDoorType_RegularDoor33)
-    RoomDraw_HighRangeDoor_North(type, dsto, pos_enum);
-  else
-    RoomDraw_NormalRangedDoors_North(type, dsto, pos_enum);
-
-}
-
-void Door_Up_StairMaskLocked(uint8 door_type, uint16 dsto) {  // 81a892
-  int i = dung_cur_door_idx >> 1;
-  dung_door_direction[i] = 0;
-  dung_door_tilemap_address[i] = dsto * 2;
-  door_type_and_slot[i] = i << 8 | door_type;
-  if (dung_door_opened_incl_adjacent & kUpperBitmasks[i & 7]) {
-    dung_cur_door_idx += 2;
-    return;
-  }
-
-  if (door_type < kDoorType_StairMaskLocked2) {
-    RoomDraw_OneSidedShutters_North(door_type, dsto);
-    return;
-  }
-
-  uint8 t = RoomDraw_FlagDoorsAndGetFinalType(0, door_type, dsto);
-  const uint16 *src = SrcPtr(kDoorTypeSrcData[t >> 1]);
-  for (int i = 0; i < 4; i++) {
-    dung_bg1[dsto + XY(0, 0)] = src[0];
-    dung_bg1[dsto + XY(0, 1)] = src[1];
-    dung_bg1[dsto + XY(0, 2)] = src[2];
-    dsto++, src += 3;
-  }
-  Door_PrioritizeCurDoor();
-}
-
-void Door_PrioritizeCurDoor() {  // 81a8fa
-  dung_door_tilemap_address[(dung_cur_door_idx >> 1) - 1] |= 0x2000;
-}
-
-void RoomDraw_NormalRangedDoors_North(uint8 door_type, uint16 dsto, int pos_enum) {  // 81a90f
-  if (pos_enum >= 6) {
-    uint16 bak = dung_cur_door_idx;
-    dung_cur_door_idx |= 0x10;
-    RoomDraw_CheckIfLowerLayerDoors_Y(door_type, kDoorPositionToTilemapOffs_Down[pos_enum - 6] / 2);
-    dung_cur_door_idx = bak;
-  }
-  RoomDraw_OneSidedShutters_North(door_type, dsto);
-}
-
-void RoomDraw_OneSidedShutters_North(uint8 door_type, uint16 dsto) {  // 81a932
-  int t = RoomDraw_FlagDoorsAndGetFinalType(0, door_type, dsto);
-  if (t & 0x100)
-    return;
-  // Remap type
-  if (t == 54 || t == 56) {
-    int new_type = (t == 54) ? kDoorType_ShuttersTwoWay : kDoorType_Regular;
-    int i = (dung_cur_door_idx >> 1) - 1;
-    door_type_and_slot[i] = (i << 8) | new_type;
-    t = new_type;
-  }
-  const uint16 *src = SrcPtr(kDoorTypeSrcData[t >> 1]);
-  uint16 *dst = DstoPtr(dsto);
-  for (int i = 0; i < 4; i++) {
-    dst[XY(0, 0)] = src[0];
-    dst[XY(0, 1)] = src[1];
-    dst[XY(0, 2)] = src[2];
-    dst++, src += 3;
-  }
-}
-
-void RoomDraw_Door_South(int type, int pos_enum) {  // 81a984
-  uint16 dsto = kDoorPositionToTilemapOffs_Down[pos_enum] / 2;
-  if (type == kDoorType_PlayerBgChange)
-    RoomDraw_MarkLayerToggleDoor(dsto + XY(1, 4));
-  else if (type == kDoorType_EntranceDoor)
-    Door_Down_EntranceDoor(dsto);
-  else if (type == kDoorType_ThroneRoom)
-    RoomDraw_MarkDungeonToggleDoor(dsto + XY(1, 4));
-  else if (type == kDoorType_ExitToOw) {
-    dung_exit_door_addresses[dung_exit_door_count >> 1] = dsto * 2;
-    dung_exit_door_count += 2;
-  } else if (type >= kDoorType_RegularDoor33) {
-    RoomDraw_OneSidedLowerShutters_South(type, dsto);
-  } else if (type == kDoorType_EntranceLarge) {
-    RoomDraw_FlagDoorsAndGetFinalType(1, type, dsto);
-    RoomDraw_SomeBigDecors(10, SrcPtr(0x2656), dsto + XY(-3, -4));
-  } else if (type == kDoorType_EntranceLarge2) {
-    dsto |= 0x1000;
-    RoomDraw_FlagDoorsAndGetFinalType(1, type, dsto);
-    dsto += XY(-3, -4);
-    RoomDraw_SomeBigDecors(10, SrcPtr(0x2656), dsto);
-    dsto += -0x1000 + XY(0, 7);
-    for (int i = 0; i < 10; i++) {
-      dung_bg2[dsto] = dung_bg1[dsto] | 0x2000;
-      dsto += 1;
-    }
-  } else if (type == kDoorType_EntranceCave || type == kDoorType_EntranceCave2) {
-    if (type == kDoorType_EntranceCave2)
-      RoomDraw_MakeDoorPartsHighPriority_Y(dsto + XY(0, 4));
-    RoomDraw_FlagDoorsAndGetFinalType(1, type, dsto);
-    RoomDraw_4x4(SrcPtr(0x26f6), DstoPtr(dsto));
-  } else if (type == kDoorType_4) {
-    uint16 dsto_org = dsto;
-    dsto |= 0x1000;
-    RoomDraw_MakeDoorPartsHighPriority_Y(dsto + XY(0, 4));
-    RoomDraw_FlagDoorsAndGetFinalType(1, type, dsto);
-    RoomDraw_4x4(SrcPtr(0x26f6), DstoPtr(dsto));
-    for (int i = 0; i < 4; i++) {
-      dung_bg2[dsto_org + XY(0, 3)] = dung_bg1[dsto_org + XY(0, 3)] | 0x2000;
-      dsto_org += 1;
-    }
-  } else {
-    RoomDraw_CheckIfLowerLayerDoors_Y(type, dsto);
-  }
-}
-
-void RoomDraw_CheckIfLowerLayerDoors_Y(uint8 door_type, uint16 dsto) {  // 81aa66
-  if (door_type == kDoorType_Regular2) {
-    RoomDraw_MakeDoorPartsHighPriority_Y(dsto + XY(0, 4));
-    Door_Draw_Helper4(door_type, dsto);
-  } else if (door_type == kDoorType_WaterfallTunnel) {
-    Door_Draw_Helper4(door_type, dsto);
-    Door_PrioritizeCurDoor();
-  } else {
-    Door_Draw_Helper4(door_type, dsto);
-  }
-}
-
-void RoomDraw_Door_West(int type, int pos_enum) {  // 81aad7
-  uint16 dsto = kDoorPositionToTilemapOffs_Left[pos_enum] / 2;
-  if (type == kDoorType_PlayerBgChange)
-    RoomDraw_MarkLayerToggleDoor(dsto + XY(-2, 1));
-  else if (type == kDoorType_EntranceDoor)
-    Door_Left_EntranceDoor(dsto);
-  else if (type == kDoorType_ThroneRoom)
-    RoomDraw_MarkDungeonToggleDoor(dsto + XY(-2, 1));
-  else if (type == kDoorType_Regular2) {
-    RoomDraw_MakeDoorPartsHighPriority_X(dsto & ~0x1f);
-    RoomDraw_NormalRangedDoors_West(type, dsto, pos_enum);
-  } else if (type == kDoorType_WaterfallTunnel) {
-    RoomDraw_NormalRangedDoors_West(type, dsto, pos_enum);
-    Door_PrioritizeCurDoor();
-  } else if (type < kDoorType_RegularDoor33) {
-    RoomDraw_NormalRangedDoors_West(type, dsto, pos_enum);
-  } else {
-    RoomDraw_HighRangeDoor_West(type, dsto, pos_enum);
-  }
-}
-
-void RoomDraw_NormalRangedDoors_West(uint8 door_type, uint16 dsto, int pos_enum) {  // 81ab1f
-  if (pos_enum >= 6) {
-    uint16 bak = dung_cur_door_idx;
-    dung_cur_door_idx |= 0x10;
-    RoomDraw_NormalRangedDoors_East(door_type, kDoorPositionToTilemapOffs_Right[pos_enum - 6] / 2);
-    dung_cur_door_idx = bak;
-  }
-
-  int t = RoomDraw_FlagDoorsAndGetFinalType(2, door_type, dsto), new_type;
-  if (t & 0x100)
-    return;
-
-  if ((new_type = kDoorType_ShuttersTwoWay, t == kDoorType_36) ||
-      (new_type = kDoorType_Regular, t == kDoorType_38)) {
-    int i = (dung_cur_door_idx >> 1) - 1;
-    door_type_and_slot[i] = (i << 8) | new_type;
-    t = new_type;
-  }
-
-  const uint16 *src = SrcPtr(kDoorTypeSrcData3[t >> 1]);
-  uint16 *dst = DstoPtr(dsto);
-  for (int i = 0; i < 3; i++) {
-    dst[XY(0, 0)] = src[0];
-    dst[XY(0, 1)] = src[1];
-    dst[XY(0, 2)] = src[2];
-    dst[XY(0, 3)] = src[3];
-    dst++, src += 4;
-  }
-
-}
-
-void RoomDraw_Door_East(int type, int pos_enum) {  // 81ab99
-  uint16 dsto = kDoorPositionToTilemapOffs_Right[pos_enum] / 2;
-  if (type == kDoorType_PlayerBgChange)
-    RoomDraw_MarkLayerToggleDoor(dsto + XY(4, 1));
-  else if (type == kDoorType_EntranceDoor)
-    Door_Right_EntranceDoor(dsto);
-  else if (type == kDoorType_ThroneRoom)
-    RoomDraw_MarkDungeonToggleDoor(dsto + XY(4, 1));
-  else if (type < kDoorType_RegularDoor33) {
-    RoomDraw_NormalRangedDoors_East(type, dsto);
-  } else {
-    RoomDraw_OneSidedLowerShutters_East(type, dsto);
-  }
-}
-
-void RoomDraw_NormalRangedDoors_East(uint8 door_type, uint16 dsto) {  // 81abc8
-  if (door_type == kDoorType_Regular2)
-    RoomDraw_MakeDoorPartsHighPriority_X(dsto + XY(4, 0));
-  if (door_type == kDoorType_WaterfallTunnel) {
-    RoomDraw_OneSidedShutters_East(door_type, dsto);
-    Door_PrioritizeCurDoor();
-  } else {
-    RoomDraw_OneSidedShutters_East(door_type, dsto);
-  }
-}
-
-void RoomDraw_OneSidedShutters_East(uint8 door_type, uint16 dsto) {  // 81abe2
-  int t = RoomDraw_FlagDoorsAndGetFinalType(3, door_type, dsto), new_type;
-  if (t & 0x100)
-    return;
-  if ((new_type = kDoorType_Regular, t == kDoorType_36) ||
-      (new_type = kDoorType_ShuttersTwoWay, t == kDoorType_38)) {
-    int i = (dung_cur_door_idx >> 1) - 1;
-    door_type_and_slot[i] = (i << 8) | new_type;
-    t = new_type;
-  }
-  const uint16 *src = SrcPtr(kDoorTypeSrcData4[t >> 1]);
-  uint16 *dst = DstoPtr(dsto) + 1;
-  for (int i = 0; i < 3; i++) {
-    dst[XY(0, 0)] = src[0];
-    dst[XY(0, 1)] = src[1];
-    dst[XY(0, 2)] = src[2];
-    dst[XY(0, 3)] = src[3];
-    dst++, src += 4;
-  }
-}
-
-void RoomDraw_NorthCurtainDoor(uint16 dsto) {  // 81ac3b
-  int rv = RoomDraw_FlagDoorsAndGetFinalType(0, kDoorType_Slashable, dsto);
-  if (rv & 0x100) {
-    RoomDraw_4x4(SrcPtr(0x78a), DstoPtr(dsto));
-  } else {
-    RoomDraw_4x4(SrcPtr(kDoorTypeSrcData[rv >> 1]), DstoPtr(dsto));
-  }
-}
-
-void RoomDraw_Door_ExplodingWall(int pos_enum) {  // 81ac70
-  uint16 dsto = kDoor_BlastWallUp_Dsts[pos_enum] / 2;
-  int i = dung_cur_door_idx >> 1;
-  dung_door_tilemap_address[i] = 2 * (dsto + 10);
-  door_type_and_slot[i] = i << 8 | kDoorType_LgExplosion;
-  if (!(dung_door_opened_incl_adjacent & kUpperBitmasks[i & 7])) {
-    dung_door_direction[i] = 0;
-    dung_cur_door_idx += 2;
-    return;
-  }
-  int slot = dung_hdr_tag[0] != 0x20 && dung_hdr_tag[0] != 0x25 && dung_hdr_tag[0] != 0x28;
-  dung_hdr_tag[slot] = 0;
-  quadrant_fullsize_y = 2;
-  dung_blastwall_flag_y = 1;
-  RoomDraw_ExplodingWallSegment(SrcPtr(kDoorTypeSrcData2[42]), dsto);
-  dung_cur_door_idx += 2;
-  dung_unk2 |= 0x200;
-  RoomDraw_ExplodingWallSegment(SrcPtr(kDoorTypeSrcData[42]), dsto + XY(0, 6));
-}
-
-void RoomDraw_ExplodingWallSegment(const uint16 *src, uint16 dsto) {  // 81ace4
-  RoomDraw_ExplodingWallColumn(src, DstoPtr(dsto));
-  src += 12, dsto += 2;
-  int n = src[0];
-  uint16 *d = &dung_bg2[dsto];
-  dung_draw_width_indicator = 18;
-  do {
-    d[XY(0, 0)] = d[XY(0, 1)] = d[XY(0, 2)] = n;
-    d[XY(0, 3)] = d[XY(0, 4)] = d[XY(0, 5)] = n;
-    d++;
-  } while (--dung_draw_width_indicator);
-  RoomDraw_ExplodingWallColumn(src + 1, DstoPtr(dsto + 18));
-}
-
-void RoomDraw_ExplodingWallColumn(const uint16 *src, uint16 *dst) {  // 81ad25
-  for (int i = 0; i < 6; i++) {
-    dst[0] = src[0];
-    dst[1] = src[6];
-    dst += XY(0, 1), src += 1;
-  }
-}
-
-void RoomDraw_HighRangeDoor_North(uint8 door_type, uint16 dsto, int pos_enum) {  // 81ad41
-  if (pos_enum >= 6 && door_type != kDoorType_WarpRoomDoor) {
-    uint16 bak = dung_cur_door_idx;
-    dung_cur_door_idx |= 0x10;
-    RoomDraw_OneSidedLowerShutters_South(door_type, kDoorPositionToTilemapOffs_Down[pos_enum - 6] / 2);
-    dung_cur_door_idx = bak;
-  }
-  uint8 t = RoomDraw_FlagDoorsAndGetFinalType(0, door_type, dsto);
-  if (t == kDoorType_ShutterTrapUR || t == kDoorType_ShutterTrapDL) {
-    int new_type = (t == kDoorType_ShutterTrapUR) ? kDoorType_RegularDoor33 : kDoorType_Shutter;
-    int i = (dung_cur_door_idx >> 1) - 1;
-    door_type_and_slot[i] = (i << 8) | new_type;
-    t = new_type;
-  }
-  uint16 dsto_org = dsto;
-  const uint16 *src = SrcPtr(kDoorTypeSrcData[t >> 1]);
-  for (int i = 0; i < 4; i++) {
-    dung_bg2[dsto + XY(0, 0)] = src[0];
-    dung_bg1[dsto + XY(0, 1)] = src[1];
-    dung_bg1[dsto + XY(0, 2)] = src[2];
-    dsto++, src += 3;
-  }
-  if (door_type != kDoorType_WarpRoomDoor)
-    RoomDraw_MakeDoorHighPriority_North(dsto_org);
-  Door_PrioritizeCurDoor();
-}
-
-void RoomDraw_OneSidedLowerShutters_South(uint8 door_type, uint16 dsto) {  // 81add4
-  uint8 t = RoomDraw_FlagDoorsAndGetFinalType(1, door_type, dsto);
-  if (t == kDoorType_ShutterTrapUR || t == kDoorType_ShutterTrapDL) {
-    int new_type = (t == kDoorType_ShutterTrapUR) ? kDoorType_Shutter : kDoorType_RegularDoor33;
-    int i = (dung_cur_door_idx >> 1) - 1;
-    door_type_and_slot[i] = (i << 8) | new_type;
-    t = new_type;
-  }
-  uint16 dsto_org = dsto;
-  const uint16 *src = SrcPtr(kDoorTypeSrcData2[t >> 1]);
-  for (int i = 0; i < 4; i++) {
-    dung_bg1[dsto + XY(0, 1)] = src[0];
-    dung_bg1[dsto + XY(0, 2)] = src[1];
-    dung_bg2[dsto + XY(0, 3)] = src[2];
-    dsto++, src += 3;
-  }
-  RoomDraw_MakeDoorHighPriority_South(dsto_org + XY(0, 4));
-  Door_PrioritizeCurDoor();
-}
-
-void RoomDraw_HighRangeDoor_West(uint8 door_type, uint16 dsto, int pos_enum) {  // 81ae40
-  if (pos_enum >= 6) {
-    uint16 bak = dung_cur_door_idx;
-    dung_cur_door_idx |= 0x10;
-    RoomDraw_OneSidedLowerShutters_East(door_type, kDoorPositionToTilemapOffs_Right[pos_enum - 6] / 2);
-    dung_cur_door_idx = bak;
-  }
-
-  uint8 t = RoomDraw_FlagDoorsAndGetFinalType(2, door_type, dsto), new_type;
-  if ((new_type = kDoorType_Shutter, t == kDoorType_ShutterTrapUR) ||
-      (new_type = kDoorType_RegularDoor33, t == kDoorType_ShutterTrapDL)) {
-    int i = (dung_cur_door_idx >> 1) - 1;
-    door_type_and_slot[i] = (i << 8) | new_type;
-    t = new_type;
-  }
-
-  const uint16 *src = SrcPtr(kDoorTypeSrcData3[t >> 1]);
-  uint16 dsto_org = dsto;
-  dung_bg2[dsto + XY(0, 0)] = src[0];
-  dung_bg2[dsto + XY(0, 1)] = src[1];
-  dung_bg2[dsto + XY(0, 2)] = src[2];
-  dung_bg2[dsto + XY(0, 3)] = src[3];
-  dsto++, src += 4;
-  for (int i = 0; i < 2; i++) {
-    dung_bg1[dsto + XY(0, 0)] = src[0];
-    dung_bg1[dsto + XY(0, 1)] = src[1];
-    dung_bg1[dsto + XY(0, 2)] = src[2];
-    dung_bg1[dsto + XY(0, 3)] = src[3];
-    dsto++, src += 4;
-  }
-  RoomDraw_MakeDoorHighPriority_West(dsto_org);
-  Door_PrioritizeCurDoor();
-}
-
-void RoomDraw_OneSidedLowerShutters_East(uint8 door_type, uint16 dsto) {  // 81aef0
-  uint8 t = RoomDraw_FlagDoorsAndGetFinalType(3, door_type, dsto), new_type;
-  if ((new_type = kDoorType_RegularDoor33, t == kDoorType_ShutterTrapUR) ||
-      (new_type = kDoorType_Shutter, t == kDoorType_ShutterTrapDL)) {
-    int i = (dung_cur_door_idx >> 1) - 1;
-    door_type_and_slot[i] = (i << 8) | new_type;
-    t = new_type;
-  }
-
-  uint16 dst_org = dsto;
-  const uint16 *src = SrcPtr(kDoorTypeSrcData4[t >> 1]);
-  for (int i = 0; i < 2; i++) {
-    dung_bg1[dsto + XY(1, 0)] = src[0];
-    dung_bg1[dsto + XY(1, 1)] = src[1];
-    dung_bg1[dsto + XY(1, 2)] = src[2];
-    dung_bg1[dsto + XY(1, 3)] = src[3];
-    dsto++, src += 4;
-  }
-  dung_bg2[dsto + XY(1, 0)] = src[0];
-  dung_bg2[dsto + XY(1, 1)] = src[1];
-  dung_bg2[dsto + XY(1, 2)] = src[2];
-  dung_bg2[dsto + XY(1, 3)] = src[3];
-  RoomDraw_MakeDoorHighPriority_East(dst_org + XY(4, 0));
-  Door_PrioritizeCurDoor();
-}
-
-void RoomDraw_MakeDoorHighPriority_North(uint16 dsto) {  // 81af8b
-  uint16 dsto_org = dsto;
-  dsto &= 0xF07F >> 1;
-  do {
-    dung_bg2[dsto + 0] |= 0x2000;
-    dung_bg2[dsto + 1] |= 0x2000;
-    dung_bg2[dsto + 2] |= 0x2000;
-    dung_bg2[dsto + 3] |= 0x2000;
-    dsto += XY(0, 1);
-  } while (dsto != dsto_org);
-}
-
-void RoomDraw_MakeDoorHighPriority_South(uint16 dsto) {  // 81afd4
-  do {
-    dung_bg2[dsto + 0] |= 0x2000;
-    dung_bg2[dsto + 1] |= 0x2000;
-    dung_bg2[dsto + 2] |= 0x2000;
-    dung_bg2[dsto + 3] |= 0x2000;
-    dsto += XY(0, 1);
-  } while (dsto & 0x7c0);
-}
-
-void RoomDraw_MakeDoorHighPriority_West(uint16 dsto) {  // 81b017
-  uint16 dsto_org = dsto;
-  dsto &= 0xffe0;
-  do {
-    dung_bg2[dsto + XY(0, 0)] |= 0x2000;
-    dung_bg2[dsto + XY(0, 1)] |= 0x2000;
-    dung_bg2[dsto + XY(0, 2)] |= 0x2000;
-    dung_bg2[dsto + XY(0, 3)] |= 0x2000;
-    dsto += XY(1, 0);
-  } while (dsto != dsto_org);
-}
-
-void RoomDraw_MakeDoorHighPriority_East(uint16 dsto) {  // 81b05c
-  uint16 *d = &dung_bg2[dsto];
-  do {
-    d[XY(0, 0)] |= 0x2000;
-    d[XY(0, 1)] |= 0x2000;
-    d[XY(0, 2)] |= 0x2000;
-    d[XY(0, 3)] |= 0x2000;
-    d += XY(1, 0), dsto += 1;
-  } while (dsto & 0x1f);
-}
-
-void RoomDraw_MarkDungeonToggleDoor(uint16 dsto) {  // 81b092
-  dung_toggle_palace_pos[dung_num_toggle_palace >> 1] = dsto;
-  dung_num_toggle_palace += 2;
-}
-
-void RoomDraw_MarkLayerToggleDoor(uint16 dsto) {  // 81b09f
-  dung_toggle_floor_pos[dung_num_toggle_floor >> 1] = dsto;
-  dung_num_toggle_floor += 2;
-}
-
-void RoomDraw_GetObjectSize_1to16() {  // 81b0ac
-  dung_draw_width_indicator = (dung_draw_width_indicator << 2 | dung_draw_height_indicator) + 1;
-  dung_draw_height_indicator = 0;
-}
-
-void Object_SizeAtoAplus15(uint8 a) {  // 81b0af
-  dung_draw_width_indicator = (dung_draw_width_indicator << 2 | dung_draw_height_indicator) + a;
-  dung_draw_height_indicator = 0;
-}
-
-void RoomDraw_GetObjectSize_1to15or26() {  // 81b0be
-  uint16 x = dung_draw_width_indicator << 2 | dung_draw_height_indicator;
-  dung_draw_width_indicator = x ? x : 26;
-}
-
-void RoomDraw_GetObjectSize_1to15or32() {  // 81b0cc
-  uint16 x = dung_draw_width_indicator << 2 | dung_draw_height_indicator;
-  dung_draw_width_indicator = x ? x : 32;
-}
-
-// returns 0x100 on inverse carry
-int RoomDraw_FlagDoorsAndGetFinalType(uint8 direction, uint8 door_type, uint16 dsto) {  // 81b0da
-  int slot = dung_cur_door_idx >> 1;
-  dung_door_direction[slot] = direction;
-  dung_door_tilemap_address[slot] = dsto * 2;
-  door_type_and_slot[slot] = slot << 8 | door_type;
-
-  uint8 door_type_remapped = door_type;
-
-  if ((slot & 7) < 4 && (dung_door_opened_incl_adjacent & kUpperBitmasks[slot & 7])) {
-    if ((door_type == kDoorType_ShuttersTwoWay || door_type == kDoorType_Shutter) && dung_flag_trapdoors_down)
-      goto dont_mark_opened;
-    door_type_remapped = kDoorTypeRemap[door_type >> 1];
-
-    if (door_type != kDoorType_ShuttersTwoWay && door_type != kDoorType_Shutter &&
-        door_type >= kDoorType_InvisibleDoor && door_type != kDoorType_RegularDoor33 && door_type != kDoorType_WarpRoomDoor)
-      dung_door_opened |= kUpperBitmasks[slot];
-  }
-dont_mark_opened:
-  dung_cur_door_idx = slot * 2 + 2;
-
-  if (door_type_remapped == kDoorType_Slashable || door_type_remapped == kDoorType_WaterfallTunnel)
-    return 0x100 | door_type_remapped;
-
-  if (door_type != kDoorType_InvisibleDoor)
-    return door_type_remapped;
-
-  invisible_door_dir_and_index_x2 = (slot << 8 | direction) * 2;
-  //  if (direction * 2 == link_direction_facing || ((direction * 2) ^ 2) == link_direction_facing)
-  //    return door_type_remapped;
-  dung_door_opened_incl_adjacent |= kUpperBitmasks[slot];
-  return kDoorType_Regular;
-}
-
-void RoomDraw_MakeDoorPartsHighPriority_Y(uint16 dsto) {  // 81b1a4
-  uint16 *d = &dung_bg2[dsto];
-  for (int i = 0; i < 7; i++) {
-    d[XY(0, 0)] |= 0x2000;
-    d[XY(1, 0)] |= 0x2000;
-    d[XY(2, 0)] |= 0x2000;
-    d[XY(3, 0)] |= 0x2000;
-    d += XY(0, 1);
-  }
-}
-
-void RoomDraw_MakeDoorPartsHighPriority_X(uint16 dsto) {  // 81b1e7
-  uint16 *d = &dung_bg2[dsto];
-  for (int i = 0; i < 5; i++) {
-    d[XY(0, 0)] |= 0x2000;
-    d[XY(0, 1)] |= 0x2000;
-    d[XY(0, 2)] |= 0x2000;
-    d[XY(0, 3)] |= 0x2000;
-    d += XY(1, 0);
-  }
-}
-
-void RoomDraw_Downwards4x2VariableSpacing(int increment, const uint16 *src, uint16 *dst) {  // 81b220
-  do {
-    dst[XY(0, 0)] = src[0];
-    dst[XY(1, 0)] = src[1];
-    dst[XY(2, 0)] = src[2];
-    dst[XY(3, 0)] = src[3];
-    dst[XY(0, 1)] = src[4];
-    dst[XY(1, 1)] = src[5];
-    dst[XY(2, 1)] = src[6];
-    dst[XY(3, 1)] = src[7];
-    dst += increment;
-  } while (--dung_draw_width_indicator);
-}
-
-uint16 *RoomDraw_DrawObject2x2and1(const uint16 *src, uint16 *dst) {  // 81b279
-  dst[XY(0, 0)] = src[0];
-  dst[XY(0, 1)] = src[1];
-  dst[XY(0, 2)] = src[2];
-  dst[XY(0, 3)] = src[3];
-  dst[XY(0, 4)] = src[4];
-  return dst;
-}
-
-uint16 *RoomDraw_RightwardShelfEnd(const uint16 *src, uint16 *dst) {  // 81b2e1
-  dst[XY(0, 0)] = src[0];
-  dst[XY(0, 1)] = src[1];
-  dst[XY(0, 2)] = src[2];
-  dst[XY(0, 3)] = src[3];
-  return dst;
-}
-
-uint16 *RoomDraw_RightwardBarSegment(const uint16 *src, uint16 *dst) {  // 81b2f6
-  dst[XY(0, 0)] = src[0];
-  dst[XY(0, 1)] = src[1];
-  dst[XY(0, 2)] = src[2];
-  return dst;
-}
-
-void DrawBigGraySegment(uint16 a, const uint16 *src, uint16 *dst, uint16 dsto) {  // 81b33a
-  int i = dung_misc_objs_index >> 1;
-  dung_replacement_tile_state[i] = a;
-  dung_misc_objs_index += 2;
-  dung_object_pos_in_objdata[i] = dung_load_ptr_offs;
-  dung_object_tilemap_pos[i] = dsto * 2 | (dung_line_ptrs_row0 != 0x4000 ? 0 : 0x2000);
-  replacement_tilemap_UL[i] = dst[XY(0, 0)];
-  replacement_tilemap_LL[i] = dst[XY(0, 1)];
-  replacement_tilemap_UR[i] = dst[XY(1, 0)];
-  replacement_tilemap_LR[i] = dst[XY(1, 1)];
-  RoomDraw_Rightwards2x2(src, dst);
-}
-
-void RoomDraw_SinglePot(const uint16 *src, uint16 *dst, uint16 dsto) {  // 81b395
-  int i = dung_misc_objs_index >> 1;
-  dung_misc_objs_index += 2;
-  dung_replacement_tile_state[i] = 0x1111;
-  dung_object_pos_in_objdata[i] = dung_load_ptr_offs;
-  dung_object_tilemap_pos[i] = (dsto * 2) | (dung_line_ptrs_row0 != 0x4000 ? 0 : 0x2000);
-  replacement_tilemap_UL[i] = 0x0d0e;
-  replacement_tilemap_LL[i] = 0x0d1e;
-  replacement_tilemap_UR[i] = 0x4d0e;
-  replacement_tilemap_LR[i] = 0x4d1e;
-  if (savegame_is_darkworld)
-    src = SrcPtr(0xe92);
-  RoomDraw_Rightwards2x2(src, dst);
-}
-
-void RoomDraw_BombableFloor(const uint16 *src, uint16 *dst, uint16 dsto) {  // 81b3e1
-  if (dungeon_room_index == 101 && (dung_savegame_state_bits & 0x1000)) {
-    dung_draw_width_indicator = 0;
-    dung_draw_height_indicator = 0;
-    Object_Hole(SrcPtr(0x5aa), dst);
-    return;
-  }
-
-  src = SrcPtr(0x220);
-  const uint16 *src_below = SrcPtr(0x5ba);
-
-  Object_BombableFloorHelper(0x3030, src, src_below, dst, dsto);
-  Object_BombableFloorHelper(0x3131, src + 4, src_below + 4, dst + XY(2, 0), dsto + XY(2, 0));
-  Object_BombableFloorHelper(0x3232, src + 8, src_below + 8, dst + XY(0, 2), dsto + XY(0, 2));
-  Object_BombableFloorHelper(0x3333, src + 12, src_below + 12, dst + XY(2, 2), dsto + XY(2, 2));
-}
-
-void RoomDraw_HammerPegSingle(const uint16 *src, uint16 *dst, uint16 dsto) {  // 81b493
-  int i = dung_misc_objs_index >> 1;
-  dung_misc_objs_index += 2;
-  dung_replacement_tile_state[i] = 0x4040;
-  dung_object_pos_in_objdata[i] = dung_load_ptr_offs;
-  dung_object_tilemap_pos[i] = (dsto * 2) | (dung_line_ptrs_row0 != 0x4000 ? 0 : 0x2000);
-  replacement_tilemap_UL[i] = 0x19d8;
-  replacement_tilemap_LL[i] = 0x19d9;
-  replacement_tilemap_UR[i] = 0x59d8;
-  replacement_tilemap_LR[i] = 0x59d9;
-  RoomDraw_Rightwards2x2(src, dst);
-}
-
-void DrawObjects_PushableBlock(uint16 dsto_x2, uint16 slot) {  // 81b4d6
-  int x = dung_misc_objs_index >> 1;
-  dung_misc_objs_index += 2;
-  dung_replacement_tile_state[x] = 0;
-  dung_object_pos_in_objdata[x] = slot;
-  dung_object_tilemap_pos[x] = dsto_x2;
-  uint16 *dst = DstoPtr((dsto_x2 >> 1) & 0x1fff);
-  replacement_tilemap_UL[x] = dst[XY(0, 0)];
-  replacement_tilemap_LL[x] = dst[XY(0, 1)];
-  replacement_tilemap_UR[x] = dst[XY(1, 0)];
-  replacement_tilemap_LR[x] = dst[XY(1, 1)];
-  RoomDraw_Rightwards2x2(SrcPtr(0xe52), dst);
-}
-
-void DrawObjects_LightableTorch(uint16 dsto_x2, uint16 slot) {  // 81b509
-  int x = dung_index_of_torches >> 1;
-  dung_index_of_torches += 2;
-  dung_object_tilemap_pos[x] = dsto_x2;
-  dung_object_pos_in_objdata[x] = slot;
-  uint16 src_img = 0xec2;
-  uint16 *dst = DstoPtr((dsto_x2 >> 1) & 0x1fff);
-  if (dsto_x2 & 0x8000) {
-    src_img = 0xeca;
-    if (dung_num_lit_torches < 3)
-      dung_num_lit_torches++;
-  }
-  RoomDraw_Rightwards2x2(SrcPtr(src_img), dst);
-}
-
-void Dungeon_LoadHeader() {  // 81b564
-  dung_flag_statechange_waterpuzzle = 0;
-  dung_flag_somaria_block_switch = 0;
-  dung_flag_movable_block_was_pushed = 0;
-
-  static const int16 kAdjustment[] = { 256, -256 };
-
-  if (submodule_index == 0) {
-    dung_loade_bgoffs_h_copy = BG2HOFS_copy2 & ~0x1FF;
-    dung_loade_bgoffs_v_copy = BG2VOFS_copy2 & ~0x1FF;
-  } else if (submodule_index == 21 || submodule_index < 18 && submodule_index >= 6) {
-    dung_loade_bgoffs_h_copy = (BG2HOFS_copy2 + 0x20) & ~0x1FF;
-    dung_loade_bgoffs_v_copy = (BG2VOFS_copy2 + 0x20) & ~0x1FF;
-  } else {
-    if (((link_direction & 0xf) >> 1) < 2) {
-      dung_loade_bgoffs_h_copy = (BG2HOFS_copy2 + kAdjustment[(link_direction & 0xf) >> 1]) & ~0x1FF;
-      dung_loade_bgoffs_v_copy = (BG2VOFS_copy2 + 0x20) & ~0x1FF;
-    } else {
-      dung_loade_bgoffs_h_copy = (BG2HOFS_copy2 + 0x20) & ~0x1FF;
-      dung_loade_bgoffs_v_copy = (BG2VOFS_copy2 + kAdjustment[(link_direction & 0xf) >> 3]) & ~0x1FF;
-    }
-  }
-
-  const uint8 *hdr_ptr = GetRoomHeaderPtr(dungeon_room_index);
-
-  dung_bg2_properties_backup = dung_hdr_bg2_properties;
-  dung_hdr_bg2_properties = hdr_ptr[0] >> 5;
-  dung_hdr_collision = (hdr_ptr[0] >> 2) & 7;
-  dung_want_lights_out_copy = dung_want_lights_out;
-  dung_want_lights_out = hdr_ptr[0] & 1;
-  const DungPalInfo *dpi = &kDungPalinfos[hdr_ptr[1]];
-  palette_main_indoors = dpi->pal0;
-  palette_sp0l = dpi->pal1;
-  palette_sp5l = dpi->pal2;
-  palette_sp6l = dpi->pal3;
-  aux_tile_theme_index = hdr_ptr[2];
-  sprite_graphics_index = hdr_ptr[3] + 0x40;
-  dung_hdr_collision_2 = hdr_ptr[4];
-  dung_hdr_tag[0] = hdr_ptr[5];
-  dung_hdr_tag[1] = hdr_ptr[6];
-  dung_hdr_hole_teleporter_plane = hdr_ptr[7] & 3;
-  dung_hdr_staircase_plane[0] = (hdr_ptr[7] >> 2) & 3;
-  dung_hdr_staircase_plane[1] = (hdr_ptr[7] >> 4) & 3;
-  dung_hdr_staircase_plane[2] = (hdr_ptr[7] >> 6) & 3;
-  dung_hdr_staircase_plane[3] = hdr_ptr[8] & 3;
-  dung_hdr_travel_destinations[0] = hdr_ptr[9];
-  dung_hdr_travel_destinations[1] = hdr_ptr[10];
-  dung_hdr_travel_destinations[2] = hdr_ptr[11];
-  dung_hdr_travel_destinations[3] = hdr_ptr[12];
-  dung_hdr_travel_destinations[4] = hdr_ptr[13];
-  dung_flag_trapdoors_down = 1;
-  dung_overlay_to_load = 0;
-  dung_index_x3 = dungeon_room_index * 3;
-
-  uint16 x = save_dung_info[dungeon_room_index];
-  dung_door_opened = x & 0xf000;
-  dung_door_opened_incl_adjacent = dung_door_opened | 0xf00;
-  dung_savegame_state_bits = (x & 0xff0) << 4;
-  dung_quadrants_visited = x & 0xf;
-
-  const uint16 *dp = GetRoomDoorInfo(dungeon_room_index);
-  int i = 0;
-  for (; dp[i] != 0xffff; i++)
-    dung_door_tilemap_address[i] = dp[i];
-  dung_door_tilemap_address[i] = 0;
-
-  if (((dungeon_room_index - 1) & 0xf) != 0xf)
-    Dungeon_CheckAdjacentRoomsForOpenDoors(18, dungeon_room_index - 1);
-  if (((dungeon_room_index + 1) & 0xf) != 0)
-    Dungeon_CheckAdjacentRoomsForOpenDoors(12, dungeon_room_index + 1);
-  if (dungeon_room_index - 16 >= 0)
-    Dungeon_CheckAdjacentRoomsForOpenDoors(6, dungeon_room_index - 16);
-  if (dungeon_room_index + 16 < 0x140)
-    Dungeon_CheckAdjacentRoomsForOpenDoors(0, dungeon_room_index + 16);
-}
-
-void Dungeon_CheckAdjacentRoomsForOpenDoors(int idx, int room) {  // 81b759
-  static const uint16 kLookup[] = {
-    0x00, 0x10, 0x20, 0x30, 0x40, 0x50,
-    0x61, 0x71, 0x81, 0x91, 0xa1, 0xb1,
-    0x02, 0x12, 0x22, 0x32, 0x42, 0x52,
-    0x63, 0x73, 0x83, 0x93, 0xa3, 0xb3,
-  };
-  static const uint16 kLookup2[] = {
-    0x61, 0x71, 0x81, 0x91, 0xa1, 0xb1,
-    0x0, 0x10, 0x20, 0x30, 0x40, 0x50,
-    0x63, 0x73, 0x83, 0x93, 0xa3, 0xb3,
-    0x02, 0x12, 0x22, 0x32, 0x42, 0x52,
-  };
-  Dungeon_LoadAdjacentRoomDoors(room);
-  int i, j;
-  uint16 a;
-  for (i = 0; i != 8 && (a = adjacent_doors[i]) != 0xffff; i++) {
-    a &= 0xff;
-    j = idx;
-    if (a == kLookup[j] || a == kLookup[++j] || a == kLookup[++j] || a == kLookup[++j] || a == kLookup[++j] || a == kLookup[++j]) {
-      uint8 rev = kLookup2[j];
-      for (j = 0; j != 8; j++) {
-        if ((uint8)dung_door_tilemap_address[j] == rev) {
-          uint8 k = dung_door_tilemap_address[j] >> 8;
-          if (k == 0x30)
-            break;
-          if (k == 0x44 || k == 0x18) {
-            // trapdoor
-            if (room != dungeon_room_index_prev)
-              break;
-            dung_flag_trapdoors_down = 0;
-          } else {
-            // not trapdoor
-            if (!(adjacent_doors_flags & kUpperBitmasks[i]))
-              break;
-          }
-          dung_door_opened_incl_adjacent |= kUpperBitmasks[j];
-          break;
-        }
-      }
-    }
-  }
-}
-
-void Dungeon_LoadAdjacentRoomDoors(int room) {  // 81b7ef
-  const uint16 *dp = GetRoomDoorInfo(room);
-  adjacent_doors_flags = (save_dung_info[room] & 0xf000) | 0xf00;
-  for (int i = 0; ; i++) {
-    uint16 a = dp[i];
-    adjacent_doors[i] = a;
-    if (a == 0xffff)
-      break;
-    if ((a & 0xff00) == 0x4000 || (a & 0xff00) < 0x200)
-      adjacent_doors_flags |= kUpperBitmasks[i];
-  }
-}
-
-void Dungeon_LoadAttribute_Selectable() {  // 81b8b4
-  switch (overworld_map_state) {
-  case 0:  // Dungeon_LoadBasicAttribute
-    overworld_map_state = 1;
-    dung_draw_width_indicator = dung_draw_height_indicator = 0;
-  case 1:
-    Dungeon_LoadBasicAttribute_full(0x40);
-    break;
-  case 2:
-    Dungeon_LoadObjectAttribute();
-    break;
-  case 3:
-    Dungeon_LoadDoorAttribute();
-    break;
-  case 4:
-    overworld_map_state = 5;
-    if (orange_blue_barrier_state)
-      Dungeon_FlipCrystalPegAttribute();
-    break;
-  case 5:
-    break;
-  default:
-    assert(0);
-  }
-}
-
-void Dungeon_LoadAttributeTable() {  // 81b8bf
-  dung_draw_width_indicator = dung_draw_height_indicator = 0;
-  Dungeon_LoadBasicAttribute_full(0x1000);
-  Dungeon_LoadObjectAttribute();
-  Dungeon_LoadDoorAttribute();
-  if (orange_blue_barrier_state)
-    Dungeon_FlipCrystalPegAttribute();
-  overworld_map_state = 0;
-}
-
-void Dungeon_LoadBasicAttribute_full(uint16 loops) {  // 81b8f3
-  do {
-    int i = dung_draw_width_indicator / 2;
-    uint8 a0 = attributes_for_tile[dung_bg2[i] & 0x3ff];
-    if (a0 >= 0x10 && a0 < 0x1c)
-      a0 |= (dung_bg2[i] >> 14);  // vflip/hflip
-    uint8 a1 = attributes_for_tile[dung_bg2[i + 1] & 0x3ff];
-    if (a1 >= 0x10 && a1 < 0x1c)
-      a1 |= (dung_bg2[i + 1] >> 14);  // vflip/hflip
-    int j = dung_draw_height_indicator;
-    dung_bg2_attr_table[j] = a0;
-    dung_bg2_attr_table[j + 1] = a1;
-    dung_draw_height_indicator = j + 2;
-    dung_draw_width_indicator += 4;
-  } while (--loops);
-  if (dung_draw_height_indicator == 0x2000)
-    overworld_map_state++;
-}
-
-void Dungeon_LoadObjectAttribute() {  // 81b967
-  for (int i = 0; i != dung_num_star_shaped_switches; i += 2) {
-    int j = star_shaped_switches_tile[i >> 1];
-    WriteAttr2(j + XY(0, 0), 0x3b3b);
-    WriteAttr2(j + XY(0, 1), 0x3b3b);
-  }
-
-  int i = 0, t = 0x3030;
-  for (; i != dung_num_inter_room_upnorth_stairs; i += 2, t += 0x101) {
-    int j = dung_inter_starcases[i >> 1];
-    WriteAttr2(j + XY(1, 2), 0);
-    WriteAttr2(j + XY(1, 0), 0x2626);
-    WriteAttr2(j + XY(1, 1), t);
-  }
-  for (; i != dung_num_wall_upnorth_spiral_stairs; i += 2, t += 0x101) {
-    int j = dung_inter_starcases[i >> 1];
-    WriteAttr2(j + XY(1, 0), 0x5e5e);
-    WriteAttr2(j + XY(1, 2), 0x5e5e);
-    WriteAttr2(j + XY(1, 3), 0x5e5e);
-    WriteAttr2(j + XY(1, 1), t);
-  }
-  for (; i != dung_num_wall_upnorth_spiral_stairs_2; i += 2, t += 0x101) {
-    int j = dung_inter_starcases[i >> 1];
-    WriteAttr2(j + XY(1, 0), 0x5f5f);
-    WriteAttr2(j + XY(1, 2), 0x5f5f);
-    WriteAttr2(j + XY(1, 3), 0x5f5f);
-    WriteAttr2(j + XY(1, 1), t);
-  }
-  for (; i != dung_num_inter_room_upnorth_straight_stairs; i += 2, t += 0x101) {
-    int j = dung_inter_starcases[i >> 1];
-    WriteAttr2(j + XY(1, 0), 0x3838);
-    WriteAttr2(j + XY(1, 2), 0);
-    WriteAttr2(j + XY(1, 3), 0);
-    WriteAttr2(j + XY(1, 1), t);
-  }
-  for (; i != dung_num_inter_room_upsouth_straight_stairs; i += 2, t += 0x101) {
-    int j = dung_inter_starcases[i >> 1];
-    WriteAttr2(j + XY(1, 0), 0);
-    WriteAttr2(j + XY(1, 1), 0);
-    WriteAttr2(j + XY(1, 2), t);
-    WriteAttr2(j + XY(1, 3), 0x3939);
-  }
-  t = (t & 0x707) | 0x3434;
-  for (; i != dung_num_inter_room_southdown_stairs; i += 2, t += 0x101) {
-    int j = dung_inter_starcases[i >> 1];
-    WriteAttr2(j + XY(1, 2), t);
-    WriteAttr2(j + XY(1, 3), 0x2626);
-  }
-  for (; i != dung_num_wall_downnorth_spiral_stairs; i += 2, t += 0x101) {
-    int j = dung_inter_starcases[i >> 1];
-    WriteAttr2(j + XY(1, 0), 0x5e5e);
-    WriteAttr2(j + XY(1, 1), t);
-    WriteAttr2(j + XY(1, 2), 0x5e5e);
-    WriteAttr2(j + XY(1, 3), 0x5e5e);
-  }
-  for (; i != dung_num_wall_downnorth_spiral_stairs_2; i += 2, t += 0x101) {
-    int j = dung_inter_starcases[i >> 1];
-    WriteAttr2(j + XY(1, 0), 0x5f5f);
-    WriteAttr2(j + XY(1, 1), t);
-    WriteAttr2(j + XY(1, 2), 0x5f5f);
-    WriteAttr2(j + XY(1, 3), 0x5f5f);
-  }
-  for (; i != dung_num_inter_room_downnorth_straight_stairs; i += 2, t += 0x101) {
-    int j = dung_inter_starcases[i >> 1];
-    WriteAttr2(j + XY(1, 0), 0x3838);
-    WriteAttr2(j + XY(1, 1), t);
-    WriteAttr2(j + XY(1, 2), 0);
-    WriteAttr2(j + XY(1, 3), 0);
-  }
-  for (; i != dung_num_inter_room_downsouth_straight_stairs; i += 2, t += 0x101) {
-    int j = dung_inter_starcases[i >> 1];
-    WriteAttr2(j + XY(1, 0), 0);
-    WriteAttr2(j + XY(1, 1), 0);
-    WriteAttr2(j + XY(1, 2), t);
-    WriteAttr2(j + XY(1, 3), 0x3939);
-  }
-
-  i = 0;
-  int type = 0, iend = dung_num_inroom_upnorth_stairs;
-  uint16 attr = 0x1f1f;
-  if (iend == 0) {
-    type = 1, attr = 0x1e1e;
-    iend = dung_num_inroom_southdown_stairs;
-    if (iend == 0) {
-      type = 2, attr = 0x1d1d;
-      iend = dung_num_interpseudo_upnorth_stairs;
-      if (iend == 0)
-        goto skip3;
-    }
-  }
-  kind_of_in_room_staircase = type;
-  for (; i != iend; i += 2) {
-    int j = dung_stairs_table_1[i >> 1];
-    WriteAttr2(j + XY(0, 0), 0x02);
-    WriteAttr1(j + XY(0, 3), 0x02);
-    WriteAttr2(j + XY(2, 0), 0x0200);
-    WriteAttr1(j + XY(2, 3), 0x0200);
-    WriteAttr2(j + XY(0, 1), 0x01);
-    WriteAttr1(j + XY(0, 2), 0x01);
-    WriteAttr2(j + XY(2, 1), 0x0100);  // todo: use 8-bit write?
-    WriteAttr1(j + XY(2, 2), 0x0100);
-    WriteAttr2(j + XY(1, 1), attr);
-    WriteAttr1(j + XY(1, 1), attr);
-    WriteAttr2(j + XY(1, 2), attr);
-    WriteAttr1(j + XY(1, 2), attr);
-  }
-skip3:
-  if (i != dung_some_stairs_unk4) {
-    kind_of_in_room_staircase = 2;
-    for (; i != dung_some_stairs_unk4; i += 2) {
-      int j = dung_stairs_table_1[i >> 1];
-      WriteAttr2(j + XY(0, 0), 0xa03);
-      WriteAttr1(j + XY(0, 0), 0xa03);
-      WriteAttr2(j + XY(2, 0), 0x30a);
-      WriteAttr1(j + XY(2, 0), 0x30a);
-      WriteAttr2(j + XY(0, 1), 0x803);
-      WriteAttr2(j + XY(2, 1), 0x308);
-    }
-  }
-  i = 0;
-  if (i != dung_num_inroom_upnorth_stairs_water) {
-    kind_of_in_room_staircase = 2;
-    for (; i != dung_num_inroom_upnorth_stairs_water; i += 2) {
-      int j = dung_stairs_table_1[i >> 1];
-      WriteAttr2(j + XY(0, 0), 0x003);
-      WriteAttr2(j + XY(2, 0), 0x300);
-      WriteAttr1(j + XY(0, 0), 0xa03);
-      WriteAttr1(j + XY(2, 0), 0x30a);
-      WriteAttr2(j + XY(0, 1), 0x808);
-      WriteAttr2(j + XY(2, 1), 0x808);
-    }
-  }
-  if (i != dung_num_activated_water_ladders) {
-    kind_of_in_room_staircase = 2;
-    for (; i != dung_num_activated_water_ladders; i += 2) {
-      int j = dung_stairs_table_1[i >> 1];
-      WriteAttr2(j + XY(0, 0), 0x003);
-      WriteAttr2(j + XY(2, 0), 0x300);
-      WriteAttr1(j + XY(0, 0), 0xa03);
-      WriteAttr1(j + XY(2, 0), 0x30a);
-    }
-  }
-
-  for (i = 0, t = 0x7070; i != dung_misc_objs_index; i += 2, t += 0x101) {
-    uint16 k = dung_replacement_tile_state[i >> 1];
-    if ((k & 0xf0) != 0x30) {
-      int j = (dung_object_tilemap_pos[i >> 1] & 0x3fff) >> 1;
-      WriteAttr2(j + XY(0, 0), t);
-      WriteAttr2(j + XY(0, 1), t);
-    }
-  }
-
-  if (i != dung_index_of_torches) {
-    for (t = 0xc0c0; i != dung_index_of_torches; i += 2, t = (t & 0xefef) + 0x101) {
-      int j = (dung_object_tilemap_pos[i >> 1] & 0x3fff) >> 1;
-      WriteAttr2(j + XY(0, 0), t);
-      WriteAttr2(j + XY(0, 1), t);
-    }
-    dung_index_of_torches = 0;
-  }
-
-  t = 0x5858, i = 0;
-  if (dung_num_chests_x2) {
-    if (dung_hdr_tag[0] == 0x27 || dung_hdr_tag[0] == 0x3c || dung_hdr_tag[0] == 0x3e || dung_hdr_tag[0] >= 0x29 && dung_hdr_tag[0] < 0x33)
-      goto no_big_key_locks;
-    if (dung_hdr_tag[1] == 0x27 || dung_hdr_tag[1] == 0x3c || dung_hdr_tag[1] == 0x3e || dung_hdr_tag[1] >= 0x29 && dung_hdr_tag[1] < 0x33)
-      goto no_big_key_locks;
-
-    for (; i != dung_num_chests_x2; i += 2, t += 0x101) {
-      int k = dung_chest_locations[i >> 1];
-      if (k != 0) {
-        int j = (k & 0x7fff) >> 1;
-        WriteAttr2(j + XY(0, 0), t);
-        WriteAttr2(j + XY(0, 1), t);
-        if (k & 0x8000) {
-          dung_chest_locations[i >> 1] = k & 0x7fff;
-          WriteAttr2(j + XY(2, 1), t);
-          WriteAttr2(j + XY(0, 2), t);
-          WriteAttr2(j + XY(2, 2), t);
-        }
-      }
-    }
-  }
-  for (; i != dung_num_bigkey_locks_x2; i += 2, t += 0x101) {
-    int k = dung_chest_locations[i >> 1];
-    dung_chest_locations[i >> 1] = k | 0x8000;
-    int j = (k & 0x7fff) >> 1;
-    WriteAttr2(j + XY(0, 0), t);
-    WriteAttr2(j + XY(0, 1), t);
-  }
-no_big_key_locks:
-
-  i = 0;
-  type = 0, iend = dung_num_stairs_1;
-  attr = 0x3f3f;
-  if (iend == 0) {
-    type = 1, attr = 0x3e3e;
-    iend = dung_num_stairs_2;
-    if (iend == 0) {
-      type = 2, attr = 0x3d3d;
-      iend = dung_num_stairs_wet;
-      if (iend == 0)
-        goto skip7;
-    }
-  }
-  kind_of_in_room_staircase = type;
-  for (i = 0; i != iend; i += 2) {
-    int j = dung_stairs_table_2[i >> 1];
-    WriteAttr1(j + XY(0, 0), 0x02);
-    WriteAttr2(j + XY(0, 3), 0x02);
-    WriteAttr1(j + XY(0, 1), 0x01);
-    WriteAttr2(j + XY(0, 2), 0x01);
-    WriteAttr1(j + XY(2, 0), 0x0200);
-    WriteAttr2(j + XY(2, 3), 0x0200);
-    WriteAttr1(j + XY(2, 1), 0x0100);  // todo: use 8-bit write?
-    WriteAttr2(j + XY(2, 2), 0x0100);
-    WriteAttr1(j + XY(1, 1), attr);
-    WriteAttr2(j + XY(1, 1), attr);
-    WriteAttr1(j + XY(1, 2), attr);
-    WriteAttr2(j + XY(1, 2), attr);
-  }
-skip7:
-
-  if (dung_num_inroom_upsouth_stairs_water) {
-    kind_of_in_room_staircase = 2;
-    for (i = 0; i != dung_num_inroom_upsouth_stairs_water; i += 2) {
-      int j = dung_stairs_table_2[i >> 1];
-      WriteAttr1(j + XY(0, 3), 0xa03);
-      WriteAttr1(j + XY(2, 3), 0x30a);
-      WriteAttr2(j + XY(0, 3), 0x003);
-      WriteAttr2(j + XY(2, 3), 0x300);
-      WriteAttr2(j + XY(0, 2), 0x808);
-      WriteAttr2(j + XY(2, 2), 0x808);
-    }
-  }
-  overworld_map_state += 1;
-}
-
-void Dungeon_LoadDoorAttribute() {  // 81be17
-  for (int i = 0; i != 16; i++) {
-    if (dung_door_tilemap_address[i])
-      Dungeon_LoadSingleDoorAttribute(i);
-  }
-  Dungeon_LoadSingleDoorTileAttribute();
-  ChangeDoorToSwitch();
-  overworld_map_state += 1;
-}
-
-void Dungeon_LoadSingleDoorAttribute(int k) {  // 81be35
-  assert(k >= 0 && k < 16);
-  uint8 t = door_type_and_slot[k] & 0xfe, dir;
-  uint16 attr;
-  int i, j;
-
-  if (t == kDoorType_Regular || t == kDoorType_EntranceDoor || t == kDoorType_ExitToOw || t == kDoorType_EntranceLarge || t == kDoorType_EntranceCave)
-    goto alpha;
-
-  if (t == kDoorType_EntranceLarge2 || t == kDoorType_EntranceCave2 || t == kDoorType_4 || t == kDoorType_Regular2 || t == kDoorType_WaterfallTunnel)
-    goto beta;
-
-  if (t == kDoorType_LgExplosion)
-    return;
-
-  if (t >= kDoorType_RegularDoor33) {
-    if (t == kDoorType_RegularDoor33 || t == kDoorType_WarpRoomDoor)
-      goto beta;
-    if (dung_door_opened_incl_adjacent & kUpperBitmasks[k])
-      goto beta;
-
-    j = dung_door_tilemap_address[k] >> 1;
-    attr = (0xf0 + k) * 0x101;
-    WriteAttr2(j + XY(1, 1), attr);
-    WriteAttr2(j + XY(1, 2), attr);
-    return;
-
-  }
-
-  i = (t == kDoorType_ShuttersTwoWay || t == kDoorType_Shutter) ? k : k & 7;
-  if (!(dung_door_opened_incl_adjacent & kUpperBitmasks[i])) {
-    j = dung_door_tilemap_address[k] >> 1;
-    attr = (0xf0 + k) * 0x101;
-    WriteAttr2(j + XY(1, 1), attr);
-    WriteAttr2(j + XY(1, 2), attr);
-    return;
-  }
-
-alpha:
-  if (t >= kDoorType_StairMaskLocked0 && t <= kDoorType_StairMaskLocked3)
-    return;
-  attr = kTileAttrsByDoor[t >> 1];
-  dir = dung_door_direction[k] & 3;
-  if (dir == 0) {
-    uint16 a = dung_door_tilemap_address[k];
-    if (a == dung_exit_door_addresses[0] || a == dung_exit_door_addresses[1] || a == dung_exit_door_addresses[2] || a == dung_exit_door_addresses[3])
-      attr = 0x8e8e;
-    j = (a >> 1) & ~0x7c0;
-    WriteAttr2(j + XY(1, 0), attr);
-    WriteAttr2(j + XY(1, 1), attr);
-    WriteAttr2(j + XY(1, 2), attr);
-    WriteAttr2(j + XY(1, 3), attr);
-    WriteAttr2(j + XY(1, 4), attr);
-    WriteAttr2(j + XY(1, 5), attr);
-    WriteAttr2(j + XY(1, 6), attr);
-    WriteAttr2(j + XY(1, 7), 0);
-  } else if (dir == 1) {
-    uint16 a = dung_door_tilemap_address[k];
-    if (t == kDoorType_EntranceLarge || t == kDoorType_EntranceCave ||
-        a == dung_exit_door_addresses[0] || a == dung_exit_door_addresses[1] || a == dung_exit_door_addresses[2] || a == dung_exit_door_addresses[3])
-      attr = 0x8e8e;
-    j = a >> 1;
-    WriteAttr2(j + XY(1, 1), attr);
-    WriteAttr2(j + XY(1, 2), attr);
-    WriteAttr2(j + XY(1, 3), attr);
-    WriteAttr2(j + XY(1, 4), attr);
-    WriteAttr2(j + XY(1, 5), attr);
-  } else if (dir == 2) {
-    j = (dung_door_tilemap_address[k] >> 1) & ~0x1f;
-    WriteAttr2(j + XY(0, 1), attr + 0x101);
-    WriteAttr2(j + XY(2, 1), attr + 0x101);
-    WriteAttr2(j + XY(0, 2), attr + 0x101);
-    WriteAttr2(j + XY(2, 2), attr + 0x101);
-    WriteAttr2(j + XY(4, 1), (attr + 0x101) & 0xff);
-    WriteAttr2(j + XY(4, 2), (attr + 0x101) & 0xff);
-  } else {
-    j = (dung_door_tilemap_address[k] >> 1);
-    WriteAttr2(j + XY(2, 1), attr + 0x101);
-    WriteAttr2(j + XY(4, 1), attr + 0x101);
-    WriteAttr2(j + XY(2, 2), attr + 0x101);
-    WriteAttr2(j + XY(4, 2), attr + 0x101);
-    WriteAttr2(j + XY(0, 1), (attr + 0x101) & 0xff00);
-    WriteAttr2(j + XY(0, 2), (attr + 0x101) & 0xff00);
-  }
-  return;
-
-beta:
-  attr = kTileAttrsByDoor[t >> 1];
-  dir = dung_door_direction[k] & 3;
-  if (dir == 0) {
-    j = (dung_door_tilemap_address[k] >> 1) & ~0x7c0;
-    WriteAttr2(j + XY(1, 0), attr);
-    WriteAttr2(j + XY(1, 1), attr);
-    WriteAttr2(j + XY(1, 2), attr);
-    WriteAttr2(j + XY(1, 3), attr);
-    WriteAttr2(j + XY(1, 4), attr);
-    WriteAttr2(j + XY(1, 5), attr);
-    WriteAttr2(j + XY(1, 6), attr);
-    WriteAttr2(j + XY(1, 7), attr);
-    WriteAttr2(j + XY(1, 8), attr);
-    WriteAttr2(j + XY(1, 9), attr);
-  } else if (dir == 1) {
-    uint16 a = dung_door_tilemap_address[k] & 0x1fff;
-    if (t == kDoorType_EntranceLarge2 || t == kDoorType_EntranceCave2 || t == kDoorType_4 ||
-        a == dung_exit_door_addresses[0] || a == dung_exit_door_addresses[1] || a == dung_exit_door_addresses[2] || a == dung_exit_door_addresses[3])
-      attr = 0x8e8e;
-    j = dung_door_tilemap_address[k] >> 1;
-    WriteAttr2(j + XY(1, 1), attr);
-    WriteAttr2(j + XY(1, 2), attr);
-    WriteAttr2(j + XY(1, 3), attr);
-    WriteAttr2(j + XY(1, 4), attr);
-    WriteAttr2(j + XY(1, 5), attr);
-    WriteAttr2(j + XY(1, 6), attr);
-    WriteAttr2(j + XY(1, 7), attr);
-    WriteAttr2(j + XY(1, 8), attr);
-  } else if (dir == 2) {
-    j = (dung_door_tilemap_address[k] >> 1) & ~0x1f;
-    WriteAttr2(j + XY(0, 1), attr + 0x101);
-    WriteAttr2(j + XY(2, 1), attr + 0x101);
-    WriteAttr2(j + XY(4, 1), attr + 0x101);
-    WriteAttr2(j + XY(6, 1), attr + 0x101);
-    WriteAttr2(j + XY(0, 2), attr + 0x101);
-    WriteAttr2(j + XY(2, 2), attr + 0x101);
-    WriteAttr2(j + XY(4, 2), attr + 0x101);
-    WriteAttr2(j + XY(6, 2), attr + 0x101);
-  } else {
-    j = ((dung_door_tilemap_address[k] >> 1) + 1);
-    WriteAttr2(j + XY(0, 1), attr + 0x101);
-    WriteAttr2(j + XY(2, 1), attr + 0x101);
-    WriteAttr2(j + XY(4, 1), attr + 0x101);
-    WriteAttr2(j + XY(6, 1), attr + 0x101);
-    WriteAttr2(j + XY(0, 2), attr + 0x101);
-    WriteAttr2(j + XY(2, 2), attr + 0x101);
-    WriteAttr2(j + XY(4, 2), attr + 0x101);
-    WriteAttr2(j + XY(6, 2), attr + 0x101);
-  }
-}
-
-void Door_LoadBlastWallAttr(int k) {  // 81bfc1
-  int j = dung_door_tilemap_address[k] >> 1;
-  if (!(dung_door_direction[k] & 2)) {
-    for (int n = 12; n; n--) {
-      WriteAttr2(j + XY(0, 0), 0x102);
-      for (int i = 2; i < 20; i += 2)
-        WriteAttr2(j + XY(i, 0), 0x0);
-      WriteAttr2(j + XY(20, 0), 0x201);
-      j += XY(0, 1);
-    }
-  } else {
-    for (int n = 5; n; n--) {
-      WriteAttr2(j + XY(0, 0), 0x101);
-      WriteAttr2(j + XY(0, 21), 0x101);
-      WriteAttr2(j + XY(0, 1), 0x202);
-      WriteAttr2(j + XY(0, 20), 0x202);
-      for (int i = 2; i < 20; i++)
-        WriteAttr2(j + XY(0, i), 0x0);
-      j += XY(2, 0);
-    }
-  }
-}
-
-void ChangeDoorToSwitch() {  // 81c1ba
-  assert(dung_unk5 == 0);
-}
-
-void Dungeon_FlipCrystalPegAttribute() {  // 81c22a
-  for (int i = 0xfff; i >= 0; i--) {
-    if ((dung_bg2_attr_table[i] & ~1) == 0x66)
-      dung_bg2_attr_table[i] ^= 1;
-    if ((dung_bg1_attr_table[i] & ~1) == 0x66)
-      dung_bg1_attr_table[i] ^= 1;
-  }
-}
-
-void Dungeon_HandleRoomTags() {  // 81c2fd
-  if (!flag_skip_call_tag_routines) {
-    Dungeon_DetectStaircase();
-
-    // Dungeon_DetectStaircase might change the submodule, so avoid
-    // calling the tag routines cause they could also change the submodule,
-    // causing items to spawn in incorrect locations cause link_x/y_coord gets
-    // out of sync if you enter a staircase exactly when a room tag triggers.
-    if (enhanced_features0 & kFeatures0_MiscBugFixes && submodule_index != 0)
-      return;
-
-    g_ram[14] = 0;
-    kDungTagroutines[dung_hdr_tag[0]](0);
-    g_ram[14] = 1;
-    kDungTagroutines[dung_hdr_tag[1]](1);
-  }
-  flag_skip_call_tag_routines = 0;
-}
-
-void Dung_TagRoutine_0x00(int k) {  // 81c328
-}
-
-void Dungeon_DetectStaircase() {  // 81c329
-  int k = link_direction & 12;
-  if (!k)
-    return;
-
-  static const int8 kBuggyLookup[] = { 7, 24, 8, 8, 0, 0, -1, 17 };
-  int pos = ((link_y_coord + kBuggyLookup[k >> 1]) & 0x1f8) << 3;
-  pos |= (link_x_coord & 0x1f8) >> 3;
-  pos |= (link_is_on_lower_level ? 0x1000 : 0);
-
-  uint8 at = dung_bg2_attr_table[pos + (k == 4 ? 0x80 : 0)];
-  if (!(at == 0x26 || at == 0x38 || at == 0x39 || at == 0x5e || at == 0x5f))
-    return;
-
-  uint8 attr2 = dung_bg2_attr_table[pos + XY(0, 1)];
-  if ((attr2 & 0xf8) != 0x30)
-    return;
-
-  if (link_state_bits & 0x80) {
-    link_y_coord = link_y_coord_prev;
-    return;
-  }
-
-  which_staircase_index = attr2;
-  which_staircase_index_PADDING = pos >> 8; // residual
-  dungeon_room_index_prev = dungeon_room_index;
-  Dungeon_FlagRoomData_Quadrants();
-
-  if (at == 0x38 || at == 0x39) {
-    staircase_var1 = 0x20;
-    if (at == 0x38)
-      Dungeon_StartInterRoomTrans_Up();
-    else
-      Dungeon_StartInterRoomTrans_Down();
-  }
-
-  int j = (which_staircase_index & 3);
-  BYTE(dungeon_room_index) = dung_hdr_travel_destinations[j + 1];
-  cur_staircase_plane = dung_hdr_staircase_plane[j];
-  byte_7E0492 = (link_is_on_lower_level || link_is_on_lower_level_mirror) ? 2 : 0;
-  subsubmodule_index = 0;
-  bitmask_of_dragstate = 0;
-  link_delay_timer_spin_attack = 0;
-  button_mask_b_y = 0;
-  button_b_frames = 0;
-  link_cant_change_direction &= ~1;
-  if (at == 0x26) {
-    submodule_index = 6;
-    sound_effect_1 = (cur_staircase_plane < 0x34 ? 22 : 24); // wtf?
-  } else if (at == 0x38 || at == 0x39) {
-    submodule_index = (at == 0x38) ? 18 : 19;
-    link_timer_push_get_tired = 7;
-  } else {
-    UsedForStraightInterRoomStaircase();
-    submodule_index = 14;
-  }
-}
-
-void RoomTag_NorthWestTrigger(int k) {  // 81c432
-  if (!(link_x_coord & 0x100) && !(link_y_coord & 0x100))
-    RoomTag_QuadrantTrigger(k);
-}
-
-void Dung_TagRoutine_0x2A(int k) {  // 81c438
-  if ((link_x_coord & 0x100) && !(link_y_coord & 0x100))
-    RoomTag_QuadrantTrigger(k);
-}
-
-void Dung_TagRoutine_0x2B(int k) {  // 81c43e
-  if (!(link_x_coord & 0x100) && (link_y_coord & 0x100))
-    RoomTag_QuadrantTrigger(k);
-}
-
-void Dung_TagRoutine_0x2C(int k) {  // 81c444
-  if ((link_x_coord & 0x100) && (link_y_coord & 0x100))
-    RoomTag_QuadrantTrigger(k);
-}
-
-void Dung_TagRoutine_0x2D(int k) {  // 81c44a
-  if (!(link_x_coord & 0x100))
-    RoomTag_QuadrantTrigger(k);
-}
-
-void Dung_TagRoutine_0x2E(int k) {  // 81c450
-  if (link_x_coord & 0x100)
-    RoomTag_QuadrantTrigger(k);
-}
-
-void Dung_TagRoutine_0x2F(int k) {  // 81c456
-  if (!(link_y_coord & 0x100))
-    RoomTag_QuadrantTrigger(k);
-}
-
-void Dung_TagRoutine_0x30(int k) {  // 81c45c
-  if (link_y_coord & 0x100)
-    RoomTag_QuadrantTrigger(k);
-}
-
-void RoomTag_QuadrantTrigger(int k) {  // 81c461
-  uint8 tag = dung_hdr_tag[k];
-  if (tag >= 0xb) {
-    if (tag >= 0x29) {
-      if (Sprite_CheckIfScreenIsClear())
-        RoomTag_OperateChestReveal(k);
-    } else {
-      uint8 a = (dung_flag_movable_block_was_pushed ^ 1);
-      if (a != BYTE(dung_flag_trapdoors_down)) {
-        BYTE(dung_flag_trapdoors_down) = a;
-        sound_effect_2 = 37;
-        submodule_index = 5;
-        dung_cur_door_pos = 0;
-        door_animation_step_indicator = 0;
-      }
-    }
-  } else {
-    if (Sprite_CheckIfScreenIsClear())
-      Dung_TagRoutine_TrapdoorsUp();
-  }
-}
-
-void Dung_TagRoutine_TrapdoorsUp() {  // 81c49e
-  if (dung_flag_trapdoors_down) {
-    dung_flag_trapdoors_down = 0;
-    dung_cur_door_pos = 0;
-    door_animation_step_indicator = 0;
-    sound_effect_2 = 0x1b;
-    submodule_index = 5;
-  }
-}
-
-void RoomTag_RoomTrigger(int k) {  // 81c4bf
-  if (dung_hdr_tag[k] == 10) {
-    if (Sprite_CheckIfRoomIsClear())
-      Dung_TagRoutine_TrapdoorsUp();
-  } else {
-    if (Sprite_CheckIfRoomIsClear())
-      RoomTag_OperateChestReveal(k);
-  }
-}
-
-void RoomTag_RekillableBoss(int k) {  // 81c4db
-  if (Sprite_CheckIfRoomIsClear()) {
-    flag_block_link_menu = 0;
-    dung_hdr_tag[1] = 0;
-  }
-}
-
-void RoomTag_RoomTrigger_BlockDoor(int k) {  // 81c4e7
-  if (dung_flag_statechange_waterpuzzle && dung_flag_trapdoors_down) {
-    dung_flag_trapdoors_down = 0;
-    dung_cur_door_pos = 0;
-    door_animation_step_indicator = 0;
-    submodule_index = 5;
-  }
-}
-
-// Used for bosses
-void RoomTag_PrizeTriggerDoorDoor(int k) {  // 81c508
-  int t = savegame_is_darkworld ? link_has_crystals : link_which_pendants;
-  if (t & kDungeonCrystalPendantBit[BYTE(cur_palace_index_x2) >> 1]) {
-    dung_flag_trapdoors_down = 0;
-    dung_cur_door_pos = 0;
-    door_animation_step_indicator = 0;
-    submodule_index = 5;
-    dung_hdr_tag[k] = 0;
-  }
-}
-
-void RoomTag_SwitchTrigger_HoldDoor(int k) {  // 81c541
-  uint16 i = -2, v;
-  uint8 tmp;
-  for (;;) {
-    i += 2;
-    if (i == dung_index_of_torches_start)
-      break;
-    if (dung_replacement_tile_state[i >> 1] == 5) {
-      v = related_to_trapdoors_somehow;
-      if (v != 0xffff)
-        goto shortcut;
-      break;
-    }
-  }
-  v = !dung_flag_somaria_block_switch && !dung_flag_statechange_waterpuzzle && !RoomTag_CheckForPressedSwitch(&tmp);
-shortcut:
-  if (v != dung_flag_trapdoors_down) {
-    dung_flag_trapdoors_down = v;
-    dung_cur_door_pos = 0;
-    door_animation_step_indicator = 0;
-    if (v == 0)
-      sound_effect_2 = 0x25;
-    submodule_index = 5;
-  }
-}
-
-void RoomTag_SwitchTrigger_ToggleDoor(int k) {  // 81c599
-  uint8 attr;
-  if (!dung_door_switch_triggered) {
-    if (RoomTag_MaybeCheckShutters(&attr)) {
-      dung_cur_door_pos = 0;
-      door_animation_step_indicator = 0;
-      sound_effect_2 = 0x25;
-      PushPressurePlate(attr);
-      dung_flag_trapdoors_down ^= 1;
-      dung_door_switch_triggered = 1;
-    }
-  } else {
-    if (!RoomTag_MaybeCheckShutters(&attr))
-      dung_door_switch_triggered = 0;
-  }
-}
-
-void PushPressurePlate(uint8 attr) {  // 81c5cf
-  submodule_index = 5;
-  if (attr == 0x23 || !word_7E04B6)
-    return;
-  saved_module_for_menu = submodule_index;
-  submodule_index = 23;
-  subsubmodule_index = 32;
-  link_y_coord += 2;
-  if ((WORD(dung_bg2_attr_table[word_7E04B6]) & 0xfe00) != 0x2400)
-    word_7E04B6++;
-  Dungeon_UpdateTileMapWithCommonTile((word_7E04B6 & 0x3f) << 3, (word_7E04B6 >> 3) & 0x1f8, 0x10);
-}
-
-void RoomTag_TorchPuzzleDoor(int k) {  // 81c629
-  int j = 0;
-  for (int i = 0; i < 16; i++)
-    if (dung_object_tilemap_pos[i] & 0x8000)
-      j++;
-  int down = (j < 4);
-  if (down != dung_flag_trapdoors_down) {
-    dung_flag_trapdoors_down = down;
-    dung_cur_door_pos = 0;
-    door_animation_step_indicator = 0;
-    sound_effect_2 = 0x1b;
-    submodule_index = 5;
-  }
-}
-
-void RoomTag_Switch_ExplodingWall(int k) {  // 81c67a
-  uint8 yv;
-  if (!RoomTag_MaybeCheckShutters(&yv))
-    return;
-
-  Dung_TagRoutine_BlastWallStuff(k);
-}
-
-void RoomTag_PullSwitchExplodingWall(int k) {  // 81c685
-  if (!dung_flag_statechange_waterpuzzle)
-    return;
-  Dung_TagRoutine_BlastWallStuff(k);
-}
-
-void Dung_TagRoutine_BlastWallStuff(int k) {  // 81c68c
-  static const uint8 kBlastWall_Tab0[5] = { 4, 6, 0, 0, 2 };
-  static const uint16 kBlastWall_Tab1[5] = { 0, 0xa, 0, 0, 0x280 };
-
-  dung_hdr_tag[k] = 0;
-
-  int j = -1;
-  do {
-    j++;
-  } while ((door_type_and_slot[j] & ~1) != 0x30);
-  dung_unk_blast_walls_3 = j * 2;
-
-  int i = ((link_y_coord >> 8 & 1) + 1) * 2;
-  if (dung_door_direction[j] & 2)
-    i = (link_x_coord >> 8 & 1);
-
-  messaging_buf[0x1c / 2] = kBlastWall_Tab0[i];
-  j = dung_door_tilemap_address[j] + kBlastWall_Tab1[i];
-
-  messaging_buf[0x1a / 2] = (j & 0x7e) * 4 + dung_loade_bgoffs_h_copy;
-  messaging_buf[0x18 / 2] = ((j & 0x1f80) >> 4) + dung_loade_bgoffs_v_copy;
-  sound_effect_2 = 27;
-  BYTE(dung_unk_blast_walls_2) = 1;
-  AncillaAdd_BlastWall();
-}
-
-// Used for bosses
-void RoomTag_GetHeartForPrize(int k) {  // 81c709
-  static const uint8 kBossFinishedFallingItem[13] = { 0, 0, 1, 2, 0, 6, 6, 6, 6, 6, 3, 6, 6 };
-  if (!(dung_savegame_state_bits & 0x8000))
-    return;
-  int t = savegame_is_darkworld ? link_has_crystals : link_which_pendants;
-  if (!(t & kDungeonCrystalPendantBit[BYTE(cur_palace_index_x2) >> 1])) {
-    byte_7E04C2 = 128;
-    if (Ancilla_SpawnFallingPrize(kBossFinishedFallingItem[BYTE(cur_palace_index_x2) >> 1]) < 0)
-      return; // Zelda bugfix. Price won't spawn if we're out of ancillas
-  }
-  dung_hdr_tag[k] = 0;
-}
-
-void RoomTag_Agahnim(int k) {  // 81c74e
-  if (!(save_ow_event_info[0x5b] & 0x20) && dung_savegame_state_bits & 0x8000) {
-    Palette_RevertTranslucencySwap();
-    dung_hdr_tag[0] = 0;
-    PrepareDungeonExitFromBossFight();
-  }
-}
-
-void RoomTag_GanonDoor(int tagidx) {  // 81c767
-  for (int k = 15; k >= 0; k--) {
-    if (sprite_state[k] == 4 || !(sprite_flags4[k] & 64) && sprite_state[k])
-      return;
-  }
-  if (link_player_handler_state != kPlayerState_FallingIntoHole) {
-    flag_is_link_immobilized = 26;
-    submodule_index = 26;
-    subsubmodule_index = 0;
-    dung_hdr_tag[0] = 0;
-    link_force_hold_sword_up = 1;
-    button_mask_b_y = 0;
-    button_b_frames = 0;
-    R16 = 0x364;
-  }
-}
-
-void RoomTag_KillRoomBlock(int k) {  // 81c7a2
-  if (link_x_coord & 0x100 && link_y_coord & 0x100) {
-    if (Sprite_CheckIfScreenIsClear()) {
-      sound_effect_2 = 0x1b;
-      dung_hdr_tag[k] = 0;
-    }
-  }
-}
-
-void RoomTag_PushBlockForChest(int k) {  // 81c7c2
-  if (!nmi_load_bg_from_vram && dung_flag_movable_block_was_pushed)
-    RoomTag_OperateChestReveal(k);
-}
-
-void RoomTag_TriggerChest(int k) {  // 81c7cc
-  uint8 attr;
-  if (!countdown_for_blink && RoomTag_MaybeCheckShutters(&attr))
-    RoomTag_OperateChestReveal(k);
-}
-
-void RoomTag_OperateChestReveal(int k) {  // 81c7d8
-  dung_hdr_tag[k] = 0;
-  vram_upload_offset = 0;
-  WORD(overworld_map_state) = 0;
-  uint16 attr = 0x5858;
-  do {
-    int pos = dung_chest_locations[WORD(overworld_map_state) >> 1] >> 1 & 0x1fff;
-
-    WORD(dung_bg2_attr_table[pos + XY(0, 0)]) = attr;
-    WORD(dung_bg2_attr_table[pos + XY(0, 1)]) = attr;
-    attr += 0x101;
-
-    const uint16 *src = SrcPtr(0x149c);
-    dung_bg2[pos + XY(0, 0)] = src[0];
-    dung_bg2[pos + XY(0, 1)] = src[1];
-    dung_bg2[pos + XY(1, 0)] = src[2];
-    dung_bg2[pos + XY(1, 1)] = src[3];
-
-    uint16 yy = WORD(overworld_map_state);
-
-    uint16 *dst = &vram_upload_data[vram_upload_offset >> 1];
-    dst[0] = RoomTag_BuildChestStripes(XY(0, 0) * 2, yy);
-    dst[3] = RoomTag_BuildChestStripes(XY(0, 1) * 2, yy);
-    dst[6] = RoomTag_BuildChestStripes(XY(1, 0) * 2, yy);
-    dst[9] = RoomTag_BuildChestStripes(XY(1, 1) * 2, yy);
-
-    dst[2] = src[0];
-    dst[5] = src[1];
-    dst[8] = src[2];
-    dst[11] = src[3];
-
-    dst[1] = 0x100;
-    dst[4] = 0x100;
-    dst[7] = 0x100;
-    dst[10] = 0x100;
-
-    dst[12] = 0xffff;
-
-    vram_upload_offset += 24;
-    WORD(overworld_map_state) += 2;
-  } while (WORD(overworld_map_state) != dung_num_chests_x2);
-  WORD(overworld_map_state) = 0;
-  sound_effect_2 = 26;
-  nmi_load_bg_from_vram = 1;
-}
-
-void RoomTag_TorchPuzzleChest(int k) {  // 81c8ae
-  int j = 0;
-  for (int i = 0; i < 16; i++)
-    if (dung_object_tilemap_pos[i] & 0x8000)
-      j++;
-  if (j >= 4)
-    RoomTag_OperateChestReveal(k);
-}
-
-void RoomTag_MovingWall_East(int k) {  // 81c8d4
-  static const int16 kMovingWall_Tab1[8] = { -63, -127, -191, -255, -71, -135, -199, -263 };
-
-  if (!dung_floor_move_flags) {
-    RoomTag_MovingWallTorchesCheck(k);
-    dung_floor_x_vel = 0;
-  } else {
-    flag_unk1 = 1;
-    RoomTag_MovingWallShakeItUp(k);
-    dung_floor_x_vel = MovingWall_MoveALittle();
-  }
-  dung_floor_x_offs -= dung_floor_x_vel;
-  BG1HOFS_copy2 = BG2HOFS_copy2 + dung_floor_x_offs;
-
-  if (dung_floor_x_vel) {
-    if (dung_floor_x_offs < (uint16)kMovingWall_Tab1[moving_wall_var2 >> 1] &&
-        dung_floor_x_offs < (uint16)kMovingWall_Tab1[RoomTag_AdvanceGiganticWall(k) >> 1]) {
-      sound_effect_2 = 0x1b;
-      sound_effect_ambient = 5;
-      dung_hdr_tag[k] = 0;
-      flag_is_link_immobilized = 0;
-      flag_unk1 = 0;
-      bg1_x_offset = bg1_y_offset = 0;
-    }
-    nmi_subroutine_index = 5;
-    nmi_load_target_addr = (moving_wall_var1 - ((-dung_floor_x_offs & 0x1f8) >> 3)) & 0x141f;
-  }
-}
-
-void RoomTag_MovingWallShakeItUp(int k) {  // 81c969
-  int i = frame_counter & 1;
-  bg1_x_offset = i ? -1 : 1;
-  bg1_y_offset = -bg1_x_offset;
-  if (!dung_hdr_tag[k])
-    bg1_x_offset = bg1_y_offset = 0;
-}
-
-void RoomTag_MovingWall_West(int k) {  // 81c98b
-  static const uint16 kMovingWall_Tab0[8] = { 0x42, 0x82, 0xc2, 0x102, 0x4a, 0x8a, 0xca, 0x10a };
-
-  if (!dung_floor_move_flags) {
-    RoomTag_MovingWallTorchesCheck(k);
-    dung_floor_x_vel = 0;
-  } else {
-    flag_unk1 = 1;
-    RoomTag_MovingWallShakeItUp(k);
-    dung_floor_x_vel = MovingWall_MoveALittle();
-  }
-  dung_floor_x_offs += dung_floor_x_vel;
-  BG1HOFS_copy2 = BG2HOFS_copy2 + dung_floor_x_offs;
-  if (dung_floor_x_vel) {
-    if (dung_floor_x_offs >= kMovingWall_Tab0[moving_wall_var2 >> 1] &&
-        dung_floor_x_offs >= kMovingWall_Tab0[RoomTag_AdvanceGiganticWall(k) >> 1]) {
-      sound_effect_2 = 0x1b;
-      sound_effect_ambient = 5;
-      dung_hdr_tag[k] = 0;
-      flag_is_link_immobilized = 0;
-      flag_unk1 = 0;
-      bg1_x_offset = bg1_y_offset = 0;
-    }
-    nmi_subroutine_index = 5;
-    nmi_load_target_addr = moving_wall_var1 + ((dung_floor_x_offs & 0x1f8) >> 3);
-    if (nmi_load_target_addr & 0x1020)
-      nmi_load_target_addr = (nmi_load_target_addr & 0x1020) ^ 0x420;
-  }
-}
-
-void RoomTag_MovingWallTorchesCheck(int k) {  // 81ca17
-  if (!dung_flag_statechange_waterpuzzle) {
-    int count = 0;
-    for (int i = 0; i < 16; i++)
-      count += (dung_object_tilemap_pos[i] & 0x8000) != 0;
-    if (count < 4)
-      return;
-  }
-  dung_floor_move_flags++;
-  WORD(dung_flag_statechange_waterpuzzle) = 0;
-  dung_savegame_state_bits |= 0x1000 >> k;
-  sound_effect_ambient = 7;
-  flag_is_link_immobilized = 1;
-  flag_unk1 = 1;
-}
-
-int MovingWall_MoveALittle() {  // 81ca66
-  int t = dung_some_subpixel[1] + 0x22;
-  dung_some_subpixel[1] = t;
-  return t >> 8;
-}
-
-int RoomTag_AdvanceGiganticWall(int k) {  // 81ca75
-  int i = moving_wall_var2;
-  if (dung_hdr_tag[k] < 0x20) {
-    dung_hdr_collision = 0;
-    TM_copy = 0x16;
-    i += 8;
-  }
-  return i;
-}
-
-void RoomTag_WaterOff(int k) {  // 81ca94
-  if (dung_flag_statechange_waterpuzzle) {
-    W12SEL_copy = 3;
-    W34SEL_copy = 0;
-    WOBJSEL_copy = 0;
-    TMW_copy = 22;
-    TSW_copy = 1;
-    turn_on_off_water_ctr = 1;
-    AdjustWaterHDMAWindow();
-    submodule_index = 11;
-    palette_filter_countdown = 0;
-    darkening_or_lightening_screen = 0;
-    mosaic_target_level = 31;
-    flag_update_cgram_in_nmi++;
-    dung_hdr_tag[1] = 0;
-    dung_savegame_state_bits |= 0x800;
-    dung_flag_statechange_waterpuzzle = 0;
-    int dsto = ((water_hdma_var1 & 0x1ff) - 0x10) << 3 | ((water_hdma_var0 & 0x1ff) - 0x10) >> 3;
-    DrawWaterThing(&dung_bg2[dsto], SrcPtr(0x1438));
-    Dungeon_PrepOverlayDma_nextPrep(0, dsto * 2);
-    sound_effect_2 = 0x1b;
-    sound_effect_1 = 0x2e;
-    nmi_copy_packets_flag = 1;
-  }
-}
-
-void RoomTag_WaterOn(int k) {  // 81cb1a
-  if (dung_flag_statechange_waterpuzzle) {
-    sound_effect_2 = 0x1b;
-    sound_effect_1 = 0x2f;
-    submodule_index = 12;
-    subsubmodule_index = 0;
-    BYTE(dung_floor_y_offs) = 1;
-    dung_hdr_tag[1] = 0;
-    dung_savegame_state_bits |= 0x800;
-    dung_flag_statechange_waterpuzzle = 0;
-    dung_cur_quadrant_upload = 0;
-  }
-}
-
-void RoomTag_WaterGate(int k) {  // 81cb49
-  if (dung_savegame_state_bits & 0x800 || !dung_flag_statechange_waterpuzzle)
-    return;
-  submodule_index = 13;
-  subsubmodule_index = 0;
-  dung_hdr_tag[1] = 0;
-  dung_savegame_state_bits |= 0x800;
-  dung_flag_statechange_waterpuzzle = 0;
-  BYTE(water_hdma_var2) = 0;
-  BYTE(spotlight_var4) = 0;
-  W12SEL_copy = 3;
-  W34SEL_copy = 0;
-  WOBJSEL_copy = 0;
-  TMW_copy = 0x16;
-  TSW_copy = 1;
-  CGWSEL_copy = 2;
-  CGADSUB_copy = 0x62;
-  save_ow_event_info[0x3b] |= 32;
-  save_ow_event_info[0x7b] |= 32;
-  save_dung_info[0x28] |= 0x100;
-  RoomTag_OperateWaterFlooring();
-  water_hdma_var0 = ((watergate_pos & 0x7e) << 2) + (dung_draw_width_indicator * 16 + dung_loade_bgoffs_h_copy + 40);
-  word_7E0678 = spotlight_y_upper = (watergate_pos & 0x1f80) >> 4;
-  water_hdma_var1 = word_7E0678 + dung_loade_bgoffs_v_copy;
-  water_hdma_var3 = 0;
-  sound_effect_2 = 0x1b;
-  sound_effect_1 = 0x2f;
-}
-
-void Dung_TagRoutine_0x1B(int k) {  // 81cbff
-  // empty
-}
-
-void RoomTag_Holes0(int k) {  // 81cc00
-  Dung_TagRoutine_Func2(1);
-}
-
-void Dung_TagRoutine_0x23(int k) {  // 81cc04
-  Dung_TagRoutine_Func2(3);
-}
-
-void Dung_TagRoutine_0x34(int k) {  // 81cc08
-  Dung_TagRoutine_Func2(6);
-}
-
-void Dung_TagRoutine_0x35(int k) {  // 81cc0c
-  Dung_TagRoutine_Func2(8);
-}
-
-void Dung_TagRoutine_0x36(int k) {  // 81cc10
-  Dung_TagRoutine_Func2(10);
-}
-
-void Dung_TagRoutine_0x37(int k) {  // 81cc14
-  Dung_TagRoutine_Func2(12);
-}
-
-void Dung_TagRoutine_0x39(int k) {  // 81cc18
-  Dung_TagRoutine_Func2(14);
-}
-
-void Dung_TagRoutine_0x3A(int k) {  // 81cc1c
-  Dung_TagRoutine_Func2(16);
-}
-
-void Dung_TagRoutine_Func2(uint8 av) {  // 81cc1e
-  uint8 yv;
-  if (!dung_overlay_to_load)
-    dung_overlay_to_load = av;
-
-  if (RoomTag_CheckForPressedSwitch(&yv) && (av += yv) != dung_overlay_to_load) {
-    dung_overlay_to_load = av;
-    dung_load_ptr_offs = 0;
-    subsubmodule_index = 0;
-    sound_effect_2 = 27;
-    submodule_index = 3;
-    byte_7E04BC ^= 1;
-    Dungeon_RestoreStarTileChr();
-  }
-}
-
-void RoomTag_ChestHoles0(int k) {  // 81cc5b
-  Dung_TagRoutine_0x22_0x3B(k, 0x0);
-}
-
-void Dung_TagRoutine_0x3B(int k) {  // 81cc62
-  Dung_TagRoutine_0x22_0x3B(k, 0x12);
-}
-
-void RoomTag_Holes2(int k) {  // 81cc89
-  uint8 yv;
-
-  if (!RoomTag_CheckForPressedSwitch(&yv))
-    return;
-
-  dung_hdr_tag[k] = 0;
-  dung_overlay_to_load = 5;
-  dung_load_ptr_offs = 0;
-  subsubmodule_index = 0;
-  sound_effect_2 = 0x1b;
-  submodule_index = 3;
-}
-
-void RoomTag_OperateWaterFlooring() {  // 81cc95
-  dung_load_ptr_offs = 0;
-  const uint8 *layoutsrc = kWatergateLayout;
-  for (;;) {
-    dung_draw_width_indicator = 0;
-    dung_draw_height_indicator = 0;
-    uint16 t = WORD(*layoutsrc);
-    if (t == 0xffff)
-      break;
-    dung_draw_width_indicator = (t & 3) + 1;
-    dung_draw_height_indicator = (t >> 8 & 3) + 1;
-    dung_load_ptr_offs += 3, layoutsrc += 3;
-    const uint16 *src = SrcPtr(0x110);
-    int dsto2 = (t & 0xfc) >> 2 | (t >> 10) << 6;
-    do {
-      int dsto = dsto2;
-      int n = dung_draw_width_indicator;
-      do {
-        int nn = 2;
-        do {
-          dung_bg1[dsto + XY(0, 0)] = src[0];
-          dung_bg1[dsto + XY(1, 0)] = src[1];
-          dung_bg1[dsto + XY(2, 0)] = src[2];
-          dung_bg1[dsto + XY(3, 0)] = src[3];
-          dung_bg1[dsto + XY(0, 1)] = src[4];
-          dung_bg1[dsto + XY(1, 1)] = src[5];
-          dung_bg1[dsto + XY(2, 1)] = src[6];
-          dung_bg1[dsto + XY(3, 1)] = src[7];
-          dsto += XY(0, 2);
-        } while (--nn);
-        dsto += XY(4, -4);
-      } while (--n);
-      dsto2 += XY(0, 4);
-    } while (--dung_draw_height_indicator);
-  }
-}
-
-bool RoomTag_MaybeCheckShutters(uint8 *attr_out) {  // 81cd39
-  int p, t;
-  word_7E04B6 = 0;
-  if (flag_is_link_immobilized || link_auxiliary_state)
-    return false;
-  p = RoomTag_GetTilemapCoords();
-  t = WORD(dung_bg2_attr_table[p]);
-  if (t == 0x2323 || t == 0x2424)
-    goto done;
-  t = WORD(dung_bg2_attr_table[p += 64]);
-  if (t == 0x2323 || t == 0x2424)
-    goto done;
-  t = WORD(dung_bg2_attr_table[p -= 63]);
-  if (t == 0x2323 || t == 0x2424)
-    goto done;
-  t = WORD(dung_bg2_attr_table[p += 64]);
-  if (t == 0x2323 || t == 0x2424)
-    goto done;
-  return false;
-done:
-  if (t != WORD(dung_bg2_attr_table[p + 64]))
-    return false;
-  *attr_out = t;
-  word_7E04B6 = p;
-  return true;
-}
-
-int RoomTag_GetTilemapCoords() {  // 81cda5
-  return ((link_x_coord - 1) & 0x1f8) >> 3 | ((link_y_coord + 14) & 0x1f8) << 3 | (link_is_on_lower_level ? 0x1000 : 0);
-
-}
-
-bool RoomTag_CheckForPressedSwitch(uint8 *y_out) {  // 81cdcc
-  int p, t;
-  word_7E04B6 = 0;
-  if (flag_is_link_immobilized || link_auxiliary_state)
-    return false;
-  p = RoomTag_GetTilemapCoords();
-  t = WORD(dung_bg2_attr_table[p]);
-  if (t == 0x2323 || t == 0x3a3a || t == 0x3b3b)
-    goto done;
-  t = WORD(dung_bg2_attr_table[p += 64]);
-  if (t == 0x2323 || t == 0x3a3a || t == 0x3b3b)
-    goto done;
-  t = WORD(dung_bg2_attr_table[p -= 63]);
-  if (t == 0x2323 || t == 0x3a3a || t == 0x3b3b)
-    goto done;
-  t = WORD(dung_bg2_attr_table[p += 64]);
-  if (t == 0x2323 || t == 0x3a3a || t == 0x3b3b)
-    goto done;
-  return false;
-done:
-  if (t != WORD(dung_bg2_attr_table[p + 64]))
-    return false;
-  *y_out = (t == 0x3b3b);
-  word_7E04B6 = p;
-  return true;
-}
-
-void Dungeon_ProcessTorchesAndDoors() {  // 81ce70
-  static const int16 kDungLinkOffs1X[] = { 0, 0, -1, 17 };
-  static const int16 kDungLinkOffs1Y[] = { 7, 24, 8, 8 };
-  static const uint16 kDungLinkOffs1Pos[] = { 0x2, 0x2, 0x80, 0x80 };
-
-  if ((frame_counter & 3) == 0 && !flag_custom_spell_anim_active) {
-    for (int i = 0; i != 16; i++) {
-      if (dung_torch_timers[i] && !--dung_torch_timers[i]) {
-        byte_7E0333 = 0xc0 + i;
-        Dungeon_ExtinguishTorch();
-      }
-    }
-  }
-
-  if (!flag_is_link_immobilized) {
-    int dir = link_direction_facing >> 1;
-    int pos = ((link_y_coord + kDungLinkOffs1Y[dir]) & 0x1f8) << 3;
-    pos |= ((link_x_coord + kDungLinkOffs1X[dir]) & 0x1f8) >> 3;
-    pos |= (link_is_on_lower_level ? 0x1000 : 0);
-
-    if ((dung_bg2_attr_table[pos] & 0xf0) == 0xf0 ||
-        (dung_bg2_attr_table[pos += kDungLinkOffs1Pos[dir]] & 0xf0) == 0xf0) {
-      int k = dung_bg2_attr_table[pos] & 0xf;
-      dung_which_key_x2 = 2 * k;
-
-      if ((dung_door_direction[k] & 3) != dir)
-        goto not_openable;
-
-      uint8 door_type = door_type_and_slot[k] & 0xfe;
-      if (door_type == kDoorType_BreakableWall) {
-        if (link_is_running && link_dash_ctr < 63) {
-          dung_cur_door_pos = pos;
-
-          int db = AncillaAdd_DoorDebris();
-          if (db >= 0) {
-            door_debris_direction[db] = dung_door_direction[k] & 3;
-            door_debris_x[db] = dung_loade_bgoffs_h_copy + (dung_door_tilemap_address[k] & 0x7e) * 4;
-            door_debris_y[db] = dung_loade_bgoffs_v_copy + ((dung_door_tilemap_address[k] & 0x1f80) >> 4);
-          }
-          sound_effect_2 = 27;
-          submodule_index = 9;
-          Sprite_RepelDash();
-          return;
-        }
-      } else if (door_type == kDoorType_1E) {
-        door_animation_step_indicator = 0;
-        dung_cur_door_pos = pos;
-        if (link_bigkey & kUpperBitmasks[cur_palace_index_x2 >> 1])
-          goto has_key_for_door;
-        if (!big_key_door_message_triggered) {
-          big_key_door_message_triggered = 1;
-          dialogue_message_index = 0x7a;
-          Main_ShowTextMessage();
-        }
-      } else if (door_type >= kDoorType_SmallKeyDoor && door_type < 0x2c && door_type != 0x2a && link_num_keys != 0) {
-        link_num_keys -= 1;
-has_key_for_door:
-        door_animation_step_indicator = 0;
-        dung_cur_door_pos = pos;
-        submodule_index = 4;
-        static const uint8 kOpenDoorPanning[] = { 0x0, 0x0, 0x80, 0x40 };
-        sound_effect_2 = 20 | kOpenDoorPanning[dung_door_direction[k] & 3];
-        return;
-      }
-    } else {
-not_openable:
-      big_key_door_message_triggered = 0;
-    }
-  }
-
-  if (!(invisible_door_dir_and_index_x2 & 0x80) && !is_standing_in_doorway && (link_x_coord >> 8) == 0xc) {
-    uint8 dir = invisible_door_dir_and_index_x2;
-    int j = (invisible_door_dir_and_index_x2 >> 8) >> 1;
-    uint16 m = dung_door_opened_incl_adjacent;
-    if (dir != link_direction_facing && (dir ^ 2) == link_direction_facing)
-      m |= kUpperBitmasks[j];
-    else
-      m &= ~kUpperBitmasks[j];
-    if (m != dung_door_opened_incl_adjacent) {
-      dung_door_opened_incl_adjacent = m;
-      DrawEyeWatchDoor(j);
-      Dungeon_PrepOverlayDma_nextPrep(0, dung_door_tilemap_address[j]);
-      Dungeon_LoadToggleDoorAttr_OtherEntry(j);
-      nmi_copy_packets_flag = 1;
-      sound_effect_2 = 21;
-      return;
-    }
-  }
-
-  if (!(button_mask_b_y & 0x80) || button_b_frames != 4)
-    return;
-
-  int pos = ((link_y_coord + (int8)player_oam_y_offset) & 0x1f8) << 3;
-  pos |= ((link_x_coord + (int8)player_oam_x_offset) & 0x1f8) >> 3;
-  uint8 attr, y;
-
-#define is_6c_fx(yv,x) (y=yv, ((attr = (dung_bg2_attr_table[x] & 0xfc)) == 0x6c || (attr & 0xf0) == 0xf0))
-
-  if (!(is_6c_fx(0x41, pos) || is_6c_fx(0x40, pos += 1) || is_6c_fx(1, pos += 63) || is_6c_fx(0, pos += 1)))
-    return;
-
-  int addr;
-
-  if (attr == 0x6c) {
-    if (y & 0x40 && (dung_bg2_attr_table[pos -= 64] & 0xfc) != 0x6c)
-      pos += 64;
-    if (y & 1 && (dung_bg2_attr_table[pos -= 1] & 0xfc) != 0x6c)
-      pos += 1;
-    attr = dung_bg2_attr_table[pos];
-    WriteAttr2(pos + XY(0, 0), 0x202);
-    WriteAttr2(pos + XY(0, 1), 0x202);
-    static const uint16 kSrcTiles1[] = { 0x7ea, 0x80a, 0x80a, 0x82a };
-    addr = (pos - XY(1, 1)) * 2;
-    RoomDraw_Object_Nx4(4, SrcPtr(kSrcTiles1[attr & 3]), &dung_bg2[addr >> 1]);
-  } else {
-    dung_cur_door_pos = pos;
-    int k = attr & 0xf;
-
-    uint8 door_type = door_type_and_slot[k];
-    if (door_type != kDoorType_Slashable)
-      return;
-    sound_effect_2 = 27;
-    addr = dung_door_tilemap_address[k];
-    dung_door_opened_incl_adjacent |= kUpperBitmasks[k];
-    dung_door_opened |= kUpperBitmasks[k];
-    door_open_closed_counter = 0;
-    dung_cur_door_idx = k * 2;
-    dung_which_key_x2 = k * 2;
-    RoomDraw_Object_Nx4(4, SrcPtr(kDoorTypeSrcData[0x56 / 2]), &dung_bg2[addr >> 1]);
-    Dungeon_LoadToggleDoorAttr_OtherEntry(k);
-  }
-
-  Dungeon_PrepOverlayDma_nextPrep(0, addr);
-  sound_effect_1 = 30 | CalculateSfxPan_Arbitrary((addr & 0x7f) * 2);
-  nmi_copy_packets_flag = 1;
-}
-
-void Bomb_CheckForDestructibles(uint16 x, uint16 y, uint8 r14) {  // 81d1f4
-  if (main_module_index != 7) {
-    Overworld_BombTiles32x32(x, y);
-    return;
-  }
-  int k = ((y & 0x1f8) << 3 | (x & 0x1f8) >> 3) - 0x82;
-  uint8 a;
-  for (int i = 2; i >= 0; i--) {
-    a = dung_bg2_attr_table[k];
-    if (a == 0x62) {
-handle_62:
-      if (dungeon_room_index == 0x65)
-        dung_savegame_state_bits |= 0x1000;
-      Point16U pt;
-      printf("Wtf is R6\n");
-      ThievesAttic_DrawLightenedHole(0, 0, &pt);
-      sound_effect_2 = 0x1b;
-      return;
-    }
-    if ((a & 0xf0) == 0xf0) {
-      int j;
-handle_f0:
-      j = a & 0xf;
-      a = door_type_and_slot[j] & 0xfe;
-      if (a != kDoorType_BreakableWall && a != 0x2A && a != 0x2E)
-        return;
-      dung_cur_door_pos = k;
-      door_debris_x[r14] = ((dung_door_tilemap_address[j] & 0x7e) << 2) + dung_loade_bgoffs_h_copy;
-      door_debris_y[r14] = ((dung_door_tilemap_address[j] & 0x1f80) >> 4) + dung_loade_bgoffs_v_copy;
-      door_debris_direction[r14] = dung_door_direction[j] & 3;
-      sound_effect_2 = 0x1b;
-      submodule_index = 9;
-      return;
-    }
-
-    a = dung_bg2_attr_table[k += 2];
-    if (a == 0x62) goto handle_62;
-    if ((a & 0xf0) == 0xf0) goto handle_f0;
-
-    a = dung_bg2_attr_table[k += 2];
-    if (a == 0x62) goto handle_62;
-    if ((a & 0xf0) == 0xf0) goto handle_f0;
-
-    k += 0x7c;
-  }
-
-}
-
-int DrawDoorOpening_Step1(int door, int dma_ptr) {  // 81d2e8
-  dung_cur_door_idx = door * 2;
-  dung_which_key_x2 = door * 2;
-  switch (dung_door_direction[door] & 3) {
-  case 0: return DoorDoorStep1_North(door, dma_ptr);
-  case 1: return DoorDoorStep1_South(door, dma_ptr);
-  case 2: return DoorDoorStep1_West(door, dma_ptr);
-  case 3: return DoorDoorStep1_East(door, dma_ptr);
-  }
-  return 0;
-}
-
-void DrawShutterDoorSteps(int door) {  // 81d311
-  dung_cur_door_idx = door * 2;
-  dung_which_key_x2 = door * 2;
-  switch (dung_door_direction[door] & 3) {
-  case 0: GetDoorDrawDataIndex_North_clean_door_index(door); break;
-  case 1: GetDoorDrawDataIndex_South_clean_door_index(door); break;
-  case 2: GetDoorDrawDataIndex_West_clean_door_index(door); break;
-  case 3: GetDoorDrawDataIndex_East_clean_door_index(door); break;
-  }
-}
-
-void DrawEyeWatchDoor(int door) {  // 81d33a
-  dung_cur_door_idx = door * 2;
-  dung_which_key_x2 = door * 2;
-  switch (dung_door_direction[door] & 3) {
-  case 0: DrawDoorToTileMap_North(door, door); break;
-  case 1: DrawDoorToTileMap_South(door, door); break;
-  case 2: DrawDoorToTileMap_West(door, door); break;
-  case 3: DrawDoorToTileMap_East(door, door); break;
-  }
-}
-
-void Door_BlastWallExploding_Draw(int dsto) {  // 81d373
-  uint16 *dst = &dung_bg2[dsto];
-  const uint16 *src = SrcPtr(0x31ea);
-  ClearExplodingWallFromTileMap_ClearOnePair(dst, src);
-  dst += 2;
-  uint16 v = src[24];
-  for (int n = dung_unk_blast_walls_2 - 1; n; n--) {
-    for (int j = 0; j < 12; j++)
-      dst[XY(0, j)] = v;
-    dst++;
-  }
-  ClearExplodingWallFromTileMap_ClearOnePair(dst, src + 25);
-}
-
-void OperateShutterDoors() {  // 81d38f
-  int anim_dst = 0;
-  uint8 y = 2;
-
-  if (++door_animation_step_indicator != 4) {
-    y = dung_flag_trapdoors_down ? 0 : 4;
-    if (door_animation_step_indicator != 8)
-      goto getout;
-  }
-  door_open_closed_counter = y;
-
-  for (dung_cur_door_pos = 0; dung_cur_door_pos != 0x18; dung_cur_door_pos += 2) {
-    int j = dung_cur_door_pos >> 1;
-    uint8 door_type = door_type_and_slot[j] & 0xfe;
-    if (door_type != kDoorType_Shutter && door_type != kDoorType_ShuttersTwoWay)
-      continue;
-
-    int mask = kUpperBitmasks[j];
-    if (!dung_flag_trapdoors_down) {
-      if (dung_door_opened_incl_adjacent & mask)
-        continue;
-      if (door_animation_step_indicator == 8) {
-        sound_effect_2 = 21;
-        dung_door_opened_incl_adjacent ^= mask;
-      }
-    } else {
-      if (!(dung_door_opened_incl_adjacent & mask))
-        continue;
-      if (door_animation_step_indicator == 8) {
-        sound_effect_2 = 22;
-        dung_door_opened_incl_adjacent ^= mask;
-      }
-    }
-    DrawShutterDoorSteps(j);
-    anim_dst = Dungeon_PrepOverlayDma_nextPrep(anim_dst, dung_door_tilemap_address[j]);
-    if (door_animation_step_indicator == 8)
-      Dungeon_LoadToggleDoorAttr_OtherEntry(j);
-  }
-  dung_cur_door_pos -= 2;
-
-  if (anim_dst != 0) {
-    nmi_disable_core_updates = nmi_copy_packets_flag = 1;
-getout:
-    if (BYTE(door_animation_step_indicator) != 0x10)
-      return;
-  }
-  submodule_index = 0;
-  nmi_copy_packets_flag = 0;
-}
-
-void OpenCrackedDoor() {  // 81d469
-  Dungeon_OpeningLockedDoor_Combined(true);
-}
-
-void Dungeon_LoadToggleDoorAttr_OtherEntry(int door) {  // 81d51c
-  Dungeon_LoadSingleDoorAttribute(door);
-  Dungeon_LoadSingleDoorTileAttribute();
-}
-
-void Dungeon_LoadSingleDoorTileAttribute() {  // 81d51f
-  for (int i = 0; i != dung_num_toggle_floor; i += 2) {
-    int j = dung_toggle_floor_pos[i >> 1];
-    if ((dung_bg2_attr_table[j] & 0xf0) == 0x80) {
-      uint16 attr = *(uint16 *)&dung_bg2_attr_table[j];
-      WriteAttr2(j + XY(0, 0), attr | 0x1010);
-      WriteAttr2(j + XY(0, 1), attr | 0x1010);
-    } else {
-      uint16 attr = *(uint16 *)&dung_bg1_attr_table[j];
-      WriteAttr1(j + XY(0, 0), attr | 0x1010);
-      WriteAttr1(j + XY(0, 1), attr | 0x1010);
-    }
-  }
-  for (int i = 0; i != dung_num_toggle_palace; i += 2) {
-    int j = dung_toggle_palace_pos[i >> 1];
-    if ((dung_bg2_attr_table[j] & 0xf0) == 0x80) {
-      uint16 attr = *(uint16 *)&dung_bg2_attr_table[j];
-      WriteAttr2(j + XY(0, 0), attr | 0x2020);
-      WriteAttr2(j + XY(0, 1), attr | 0x2020);
-    } else {
-      uint16 attr = *(uint16 *)&dung_bg1_attr_table[j];
-      WriteAttr1(j + XY(0, 0), attr | 0x2020);
-      WriteAttr1(j + XY(0, 1), attr | 0x2020);
-    }
-  }
-}
-
-void DrawCompletelyOpenDoor() {  // 81d5aa
-  uint16 t;
-  int i;
-
-  for (i = 0, t = 0x3030; i != dung_num_inter_room_upnorth_stairs; i += 2, t += 0x101) {}
-
-  for (; i != dung_num_wall_upnorth_spiral_stairs; i += 2, t += 0x101) {
-    int pos = dung_inter_starcases[i >> 1];
-    WriteAttr2(pos + XY(1, 0), 0x5e5e);
-    WriteAttr2(pos + XY(1, 1), t);
-    WriteAttr2(pos + XY(1, 2), 0);
-    WriteAttr2(pos + XY(1, 3), 0);
-  }
-
-  for (; i != dung_num_wall_upnorth_spiral_stairs_2; i += 2, t += 0x101) {
-    int pos = dung_inter_starcases[i >> 1];
-    WriteAttr2(pos + XY(1, 0), 0x5f5f);
-    WriteAttr2(pos + XY(1, 1), t);
-    WriteAttr2(pos + XY(1, 2), 0);
-    WriteAttr2(pos + XY(1, 3), 0);
-  }
-
-  for (; i != dung_num_inter_room_upnorth_straight_stairs; i += 2, t += 0x101) {}
-  for (; i != dung_num_inter_room_upsouth_straight_stairs; i += 2, t += 0x101) {}
-
-  t = (t & 0x707) | 0x3434;
-
-  for (; i != dung_num_inter_room_southdown_stairs; i += 2, t += 0x101) {}
-
-  for (; i != dung_num_wall_downnorth_spiral_stairs; i += 2, t += 0x101) {
-    int pos = dung_inter_starcases[i >> 1];
-    WriteAttr2(pos + XY(1, 0), 0x5e5e);
-    WriteAttr2(pos + XY(1, 1), t);
-    WriteAttr2(pos + XY(1, 2), 0);
-    WriteAttr2(pos + XY(1, 3), 0);
-  }
-
-  for (; i != dung_num_wall_downnorth_spiral_stairs_2; i += 2, t += 0x101) {
-    int pos = dung_inter_starcases[i >> 1];
-    WriteAttr2(pos + XY(1, 0), 0x5f5f);
-    WriteAttr2(pos + XY(1, 1), t);
-    WriteAttr2(pos + XY(1, 2), 0);
-    WriteAttr2(pos + XY(1, 3), 0);
-  }
-}
-
-void Dungeon_ClearAwayExplodingWall() {  // 81d6c1
-  flag_is_link_immobilized = 6;
-  flag_unk1 = 6;
-  if (BYTE(messaging_buf[0]) != 6)
-    return;
-
-  word_7E045E = 0;
-  g_ram[12] = 0;
-  door_animation_step_indicator = 0;
-  dung_cur_door_idx = dung_unk_blast_walls_3;
-  int dsto = (dung_door_tilemap_address[dung_unk_blast_walls_3 >> 1] -= 2) >> 1;
-
-  Door_BlastWallExploding_Draw(dsto);
-  ClearAndStripeExplodingWall(dsto);
-
-  WORD(nmi_disable_core_updates) = 0xffff;
-  dung_unk_blast_walls_2 += 2;
-
-  if (dung_unk_blast_walls_2 == 21) {
-    int m = kUpperBitmasks[dung_unk_blast_walls_3 >> 1];
-    dung_door_opened_incl_adjacent |= m;
-    dung_door_opened |= m;
-
-    if (dung_door_direction[dung_unk_blast_walls_3 >> 1] & 2) {
-      dung_blastwall_flag_x = 1;
-      quadrant_fullsize_x = 2;
-    } else {
-      dung_blastwall_flag_y = 1;
-      quadrant_fullsize_y = 2;
-    }
-    WORD(quadrant_fullsize_x_cached) = WORD(quadrant_fullsize_x);
-    Door_LoadBlastWallAttr(dung_unk_blast_walls_3 >> 1);
-    dung_unk_blast_walls_2 = 0;
-    dung_unk_blast_walls_3 = 0;
-    Dungeon_FlagRoomData_Quadrants();
-    flag_is_link_immobilized = 0;
-    flag_unk1 = 0;
-  }
-  nmi_copy_packets_flag = 3;
-}
-
-uint16 Dungeon_CheckForAndIDLiftableTile() {  // 81d748
-  uint16 x = (link_x_coord + kDungeon_QueryIfTileLiftable_x[link_direction_facing >> 1]) & 0x1f8;
-  uint16 y = (link_y_coord + kDungeon_QueryIfTileLiftable_y[link_direction_facing >> 1]) & 0x1f8;
-  uint16 xy = (y << 3) | (x >> 3) | (link_is_on_lower_level ? 0x1000 : 0x0);
-
-  uint8 attr = dung_bg2_attr_table[xy];
-  if ((attr & 0xf0) != 0x70)
-    return 0xffff;  // clc
-
-  uint16 rt = dung_replacement_tile_state[attr & 0xf];
-  if (rt == 0)
-    return 0xffff;
-  if ((rt & 0xf0f0) == 0x2020)
-    return 0x55;
-  return kDungeon_QueryIfTileLiftable_rv[rt & 0xf];
-}
-
-void Dungeon_PushBlock_Handler() {  // 81d81b
-  while (dung_misc_objs_index != dung_index_of_torches_start) {
-    int k = dung_misc_objs_index >> 1;
-    int st = dung_replacement_tile_state[k];
-    if (st == 1) {
-      RoomDraw_16x16Single(k * 2);
-      dung_object_tilemap_pos[k] += kPushBlockMoveDistances[push_block_direction >> 1];
-      dung_replacement_tile_state[k] = 2;
-    } else if (st == 2) {
-      PushBlock_Slide(k * 2);
-
-      if (dung_replacement_tile_state[dung_misc_objs_index >> 1] == 3) {
-        PushBlock_CheckForPit(dung_misc_objs_index);
-        dung_replacement_tile_state[dung_misc_objs_index >> 1]++;
-      }
-    } else if (st == 4) {
-      PushBlock_HandleFalling(k * 2);
-    }
-
-    dung_misc_objs_index += 2;
-  }
-}
-
-void RoomDraw_16x16Single(uint8 index) {  // 81d828
-  index >>= 1;
-  uint16 pos = (dung_object_tilemap_pos[index] & 0x3fff) >> 1;
-  Dungeon_Store2x2(pos,
-                   replacement_tilemap_UL[index],
-                   replacement_tilemap_LL[index],
-                   replacement_tilemap_UR[index],
-                   replacement_tilemap_LR[index],
-                   attributes_for_tile[replacement_tilemap_LR[index] & 0x3ff]);
-}
-
-void PushBlock_CheckForPit(uint8 y) {  // 81d8d4
-  y >>= 1;
-  if (!(dung_object_tilemap_pos[y] & 0x4000))
-    dung_flag_movable_block_was_pushed ^= 1;
-
-  int p = (dung_object_tilemap_pos[y] & 0x3fff) >> 1;
-  uint8 attr = dung_bg2_attr_table[p];
-  if (attr == 0x20) {  // fall into pit
-    sound_effect_1 = 0x20;
-    int k = dung_object_pos_in_objdata[y] >> 2;
-    movable_block_datas[k].room = dung_hdr_travel_destinations[0];
-    movable_block_datas[k].tilemap = dung_object_tilemap_pos[y];
-    return;
-  }
-
-  int i = (index_of_changable_dungeon_objs[1] - 1) == y;
-  index_of_changable_dungeon_objs[i] = 0;
-
-  if (attr == 0x23) {
-    related_to_trapdoors_somehow = dung_flag_trapdoors_down ^ 1;
-    dung_replacement_tile_state[y] = 4;
-  } else {
-    dung_replacement_tile_state[y] = 0xffff;
-  }
-  Dungeon_Store2x2(p, 0x922, 0x932, 0x923, 0x933, 0x27);
-}
-
-uint8 Dungeon_LiftAndReplaceLiftable(Point16U *pt) {  // 81d9ec
-  uint16 x = link_x_coord + kDungeon_QueryIfTileLiftable_x[link_direction_facing >> 1];
-  uint16 y = link_y_coord + kDungeon_QueryIfTileLiftable_y[link_direction_facing >> 1];
-  pt->x = x;
-  pt->y = y;
-
-  R16 = y;
-  R18 = x;
-
-  x &= 0x1f8;
-  y &= 0x1f8;
-  uint16 xy = (y << 3) | (x >> 3) | (link_is_on_lower_level ? 0x1000 : 0x0);
-
-  uint8 attr = dung_bg2_attr_table[xy];
-
-  assert((attr & 0x70) == 0x70);
-
-  attr &= 0xf;
-  uint16 rt = dung_replacement_tile_state[attr];
-
-  if ((rt & 0xf0f0) == 0x1010) {
-    dung_misc_objs_index = attr * 2;
-    RevealPotItem(xy, dung_object_tilemap_pos[attr]);
-    RoomDraw_16x16Single(dung_misc_objs_index);
-    ManipBlock_Something(pt);
-    return kDungeon_QueryIfTileLiftable_rv[rt & 0xf];
-  } else if ((rt & 0xf0f0) == 0x2020) {
-    return ThievesAttic_DrawLightenedHole(xy, (attr - (rt & 0xf)) * 2, pt);
-  } else {
-    return 0;
-  }
-  return 0;
-}
-
-uint8 ThievesAttic_DrawLightenedHole(uint16 pos6, uint16 a, Point16U *pt) {  // 81da71
-  dung_misc_objs_index = a;
-  RevealPotItem(pos6, dung_object_tilemap_pos[a >> 1]);
-  RoomDraw_16x16Single(a);
-  RoomDraw_16x16Single(a + 2);
-  RoomDraw_16x16Single(a + 4);
-  RoomDraw_16x16Single(a + 6);
-  ManipBlock_Something(pt);
-  return 0x55;
-}
-
-uint8 HandleItemTileAction_Dungeon(uint16 x, uint16 y) {  // 81dabb
-  if (!(link_item_in_hand & 2)) {
-    if (!(enhanced_features0 & kFeatures0_BreakPotsWithSword) ||
-        button_b_frames == 0 || link_sword_type == 1)
-      return 0;
-  }
-  uint16 pos = (y & 0x1f8) * 8 + x + (link_is_on_lower_level ? 0x1000 : 0);
-  uint16 tile = dung_bg2_attr_table[pos];
-  if ((tile & 0xf0) == 0x70) {
-    uint16 tile2 = dung_replacement_tile_state[tile & 0xf];
-    if ((tile2 & 0xf0f0) == 0x4040) {  // Hammer peg
-      if (!(link_item_in_hand & 2))
-        return 0;  // only hammers on pegs
-      dung_misc_objs_index = (tile & 0xf) * 2;
-      RoomDraw_16x16Single(dung_misc_objs_index);
-      sound_effect_1 = 0x11;
-    } else if ((tile2 & 0xf0f0) == 0x1010) {  // Pot
-      dung_misc_objs_index = (tile & 0xf) * 2;
-      RevealPotItem(pos, dung_object_tilemap_pos[tile & 0xf]);
-      RoomDraw_16x16Single(dung_misc_objs_index);
-      Point16U pt;
-      ManipBlock_Something(&pt);
-      BYTE(dung_secrets_unk1) |= 0x80;
-      Sprite_SpawnImmediatelySmashedTerrain(1, pt.x, pt.y);
-      AncillaAdd_BushPoof(pt.x, pt.y);  // return value wtf?
-    }
-  }
-  return 0;
-}
-
-void ManipBlock_Something(Point16U *pt) {  // 81db41
-  uint16 pos = dung_object_tilemap_pos[dung_misc_objs_index >> 1];
-  pt->x = (link_x_coord & 0xfe00) | ((pos & 0x007e) << 2);
-  pt->y = (link_y_coord & 0xfe00) | ((pos & 0x1f80) >> 4);
-}
-
-void RevealPotItem(uint16 pos6, uint16 pos4) {  // 81e6b2
-  BYTE(dung_secrets_unk1) = 0;
-
-  const uint8 *src_ptr = kDungeonSecrets + WORD(kDungeonSecrets[dungeon_room_index * 2]);
-
-  int index = 0;
-  for (;;) {
-    uint16 test_pos = *(uint16 *)src_ptr;
-    if (test_pos == 0xffff)
-      return;
-    assert(!(test_pos & 0x8000));
-    if (test_pos == pos4)
-      break;
-    src_ptr += 3;
-    index++;
-  }
-
-  uint8 data = src_ptr[2];
-  if (data == 0)
-    return;
-
-  if (data < 0x80) {
-    if (data != 8) {
-      uint16 mask = 1 << index;
-      uint16 *pr = &pots_revealed_in_room[dungeon_room_index];
-      if (*pr & mask)
-        return;
-      *pr |= mask;
-    }
-    BYTE(dung_secrets_unk1) |= data;
-  } else if (data != 0x88) {
-    int j = dung_bg2_attr_table[pos6] & 0xf;
-    int k = (j - (dung_replacement_tile_state[j] & 0xf));
-    dung_misc_objs_index = 2 * k;
-    sound_effect_2 = 0x1b;
-    const uint16 *src = SrcPtr(0x5ba);
-    for (int i = 0; i < 4; i++, k++, src += 4) {
-      replacement_tilemap_UL[k] = src[0];
-      replacement_tilemap_LL[k] = src[1];
-      replacement_tilemap_UR[k] = src[2];
-      replacement_tilemap_LR[k] = src[3];
-    }
-  } else {
-    int k = dung_misc_objs_index >> 1;
-    replacement_tilemap_UL[k] = 0xD0B;
-    replacement_tilemap_LL[k] = 0xD1B;
-    replacement_tilemap_UR[k] = 0x4D0B;
-    replacement_tilemap_LR[k] = 0x4D1B;
-  }
-}
-
-void Dungeon_UpdateTileMapWithCommonTile(int x, int y, uint8 v) {  // 81e7a9
-  if (v == 8)
-    Dungeon_PrepSpriteInducedDma(x + 16, y, v + 2);
-  Dungeon_PrepSpriteInducedDma(x, y, v);
-  nmi_load_bg_from_vram = 1;
-}
-
-void Dungeon_PrepSpriteInducedDma(int x, int y, uint8 v) {  // 81e7df
-  static const uint16 kPrepSpriteInducedDma_Srcs[10] = { 0xe0, 0xade, 0x5aa, 0x198, 0x210, 0x218, 0x1f3a, 0xeaa, 0xeb2, 0x140 };
-  int pos = ((y + 1) & 0x1f8) << 3 | (x & 0x1f8) >> 3;
-  const uint16 *src = SrcPtr(kPrepSpriteInducedDma_Srcs[v >> 1]);
-  uint16 *dst = &vram_upload_data[vram_upload_offset >> 1];
-  dst[0] = Dungeon_MapVramAddr(pos + 0);
-  dst[3] = Dungeon_MapVramAddr(pos + 64);
-  dst[6] = Dungeon_MapVramAddr(pos + 1);
-  dst[9] = Dungeon_MapVramAddr(pos + 65);
-  uint8 attr = attributes_for_tile[src[3] & 0x3ff];
-  dung_bg2_attr_table[pos + XY(0, 0)] = attr;
-  dung_bg2_attr_table[pos + XY(0, 1)] = attr;
-  dung_bg2_attr_table[pos + XY(1, 0)] = attr;
-  dung_bg2_attr_table[pos + XY(1, 1)] = attr;
-  dung_bg2[pos + XY(0, 0)] = dst[2] = src[0];
-  dung_bg2[pos + XY(0, 1)] = dst[5] = src[1];
-  dung_bg2[pos + XY(1, 0)] = dst[8] = src[2];
-  dung_bg2[pos + XY(1, 1)] = dst[11] = src[3];
-  dst[1] = 0x100;
-  dst[4] = 0x100;
-  dst[7] = 0x100;
-  dst[10] = 0x100;
-  dst[12] = 0xffff;
-  vram_upload_offset += 24;
-}
-
-void Dungeon_DeleteRupeeTile(uint16 x, uint16 y) {  // 81e8bd
-  int pos = (y & 0x1f8) * 8 | (x & 0x1f8) >> 3;
-  uint16 *dst = &vram_upload_data[vram_upload_offset >> 1];
-  dst[2] = 0x190f;
-  dst[5] = 0x190f;
-  dung_bg2[pos + XY(0, 0)] = 0x190f;
-  dung_bg2[pos + XY(0, 1)] = 0x190f;
-  uint16 attr = attributes_for_tile[0x190f & 0x3ff] * 0x101;
-  WORD(dung_bg2_attr_table[pos + XY(0, 0)]) = attr;
-  WORD(dung_bg2_attr_table[pos + XY(0, 1)]) = attr;
-  dst[0] = Dungeon_MapVramAddr(pos + XY(0, 0));
-  dst[3] = Dungeon_MapVramAddr(pos + XY(0, 1));
-  dst[1] = 0x100;
-  dst[4] = 0x100;
-  dst[6] = 0xffff;
-  vram_upload_offset += 24;
-  dung_savegame_state_bits |= 0x1000;
-  nmi_load_bg_from_vram = 1;
-}
-
-// This doesn't return exactly like the original
-// Also returns in scratch_0
-uint8 OpenChestForItem(uint8 tile, int *chest_position) {  // 81eb66
-  static const uint16 kChestOpenMasks[] = { 0x100, 0x200, 0x400, 0x800, 0x1000, 0x2000 };
-  if (tile == 0x63)
-    return OpenMiniGameChest(chest_position);
-
-  int chest_idx = tile - 0x58, chest_idx_org = chest_idx;
-
-  uint16 loc = dung_chest_locations[chest_idx], pos, chest_room;
-  uint8 data = 0xff;
-  const uint16 *ptr;
-
-  if (loc >= 0x8000) {
-    // big key lock
-    if (!(link_bigkey & kUpperBitmasks[cur_palace_index_x2 >> 1])) {
-      dialogue_message_index = 0x7a;
-      Main_ShowTextMessage();
-      return 0xff;
-    } else {
-      dung_savegame_state_bits |= kChestOpenMasks[chest_idx];
-      sound_effect_1 = 0x29;
-      sound_effect_2 = 0x15;
-      pos = (loc & 0x7fff) >> 1;
-
-      ptr = SrcPtr(dung_floor_2_filler_tiles);
-      overworld_tileattr[pos + 0] = ptr[0];
-      overworld_tileattr[pos + 64] = ptr[1];
-      overworld_tileattr[pos + 1] = ptr[2];
-      overworld_tileattr[pos + 65] = ptr[3];
-      goto afterStoreCrap;
-    }
-  } else {
-    const uint8 *chest_data;
-    int i;
-    chest_data = kDungeonRoomChests;
-    for (i = 0; i < kDungeonRoomChests_SIZE; i += 3, chest_data += 3) {
-      chest_room = *(uint16 *)chest_data;
-      if ((chest_room & 0x7fff) == dungeon_room_index && --chest_idx < 0) {
-        data = chest_data[2];
-        if (chest_room & 0x8000) {
-          if (!(link_bigkey & kUpperBitmasks[cur_palace_index_x2 >> 1])) {
-            dialogue_message_index = 0x7a;
-            Main_ShowTextMessage();
-            return 0xff;
-          }
-          dung_savegame_state_bits |= kChestOpenMasks[chest_idx_org];
-          OpenBigChest(loc, chest_position);
-          return data;
-        } else {
-          dung_savegame_state_bits |= kChestOpenMasks[chest_idx_org];
-          ptr = SrcPtr(0x14A4);
-          pos = loc >> 1;
-
-          overworld_tileattr[pos + 0] = ptr[0];
-          overworld_tileattr[pos + 64] = ptr[1];
-          overworld_tileattr[pos + 1] = ptr[2];
-          overworld_tileattr[pos + 65] = ptr[3];
-
-          uint8 attr;
-afterStoreCrap:
-          attr = (loc < 0x8000) ? 0x27 : 0x00;
-
-          dung_bg2_attr_table[pos + 0] = attr;
-          dung_bg2_attr_table[pos + 64] = attr;
-          dung_bg2_attr_table[pos + 1] = attr;
-          dung_bg2_attr_table[pos + 65] = attr;
-
-          uint16 *dst = &vram_upload_data[vram_upload_offset >> 1];
-          dst[0] = Dungeon_MapVramAddr(pos + 0);
-          dst[3] = Dungeon_MapVramAddr(pos + 64);
-          dst[6] = Dungeon_MapVramAddr(pos + 1);
-          dst[9] = Dungeon_MapVramAddr(pos + 65);
-
-          dst[2] = ptr[0];
-          dst[5] = ptr[1];
-          dst[8] = ptr[2];
-          dst[11] = ptr[3];
-
-          dst[1] = 0x100;
-          dst[4] = 0x100;
-          dst[7] = 0x100;
-          dst[10] = 0x100;
-
-          dst[12] = 0xffff;
-
-          vram_upload_offset += 24;
-          nmi_load_bg_from_vram = 1;
-          Dungeon_FlagRoomData_Quadrants();
-          if (sound_effect_2 == 0)
-            sound_effect_2 = 14;
-
-          *chest_position = loc & 0x7fff;
-          return data;
-        }
-      }
-    }
-    return 0xff;
-  }
-}
-
-void OpenBigChest(uint16 loc, int *chest_position) {  // 81ed05
-  uint16 pos = loc >> 1;
-  const uint16 *src = SrcPtr(0x14C4);
-
-  for (int i = 0; i < 4; i++) {
-    dung_bg2[pos + XY(i, 0)] = src[0];
-    dung_bg2[pos + XY(i, 1)] = src[1];
-    dung_bg2[pos + XY(i, 2)] = src[2];
-    src += 3;
-  }
-
-  Dungeon_PrepOverlayDma_nextPrep(0, loc);
-  *chest_position = (loc + 2);
-  WORD(dung_bg2_attr_table[pos + XY(0, 0)]) = 0x2727;
-  WORD(dung_bg2_attr_table[pos + XY(2, 0)]) = 0x2727;
-  WORD(dung_bg2_attr_table[pos + XY(0, 1)]) = 0x2727;
-  WORD(dung_bg2_attr_table[pos + XY(2, 1)]) = 0x2727;
-  WORD(dung_bg2_attr_table[pos + XY(0, 2)]) = 0x2727;
-  WORD(dung_bg2_attr_table[pos + XY(2, 2)]) = 0x2727;
-  Dungeon_FlagRoomData_Quadrants();
-  sound_effect_2 = 14;
-  nmi_copy_packets_flag = 1;
-  byte_7E0B9E = 1;
-}
-
-uint8 OpenMiniGameChest(int *chest_position) {  // 81edab
-  int t;
-  if (minigame_credits == 0) {
-    dialogue_message_index = 0x163;
-    Main_ShowTextMessage();
-    return 0xff;
-  }
-  if (minigame_credits == 255) {
-    dialogue_message_index = 0x162;
-    Main_ShowTextMessage();
-    return 0xff;
-  }
-  minigame_credits--;
-
-  int pos = ((link_y_coord - 4) & 0x1f8) * 8;
-  pos |= ((link_x_coord + 7) & 0x1f8) >> 3;
-
-  if (WORD(dung_bg2_attr_table[pos]) != 0x6363) {
-    pos--;
-    if (WORD(dung_bg2_attr_table[pos]) != 0x6363)
-      pos += 2;
-  }
-
-  *chest_position = pos * 2;
-
-  WORD(dung_bg2_attr_table[pos + XY(0, 0)]) = 0x202;
-  WORD(dung_bg2_attr_table[pos + XY(0, 1)]) = 0x202;
-
-  const uint16 *src = SrcPtr(0x14A4);
-
-  int pos_wrong = pos + XY(0, 2);  // zelda bug?
-  dung_bg2[pos_wrong + XY(0, 0)] = src[0];
-  dung_bg2[pos_wrong + XY(0, 1)] = src[1];
-  dung_bg2[pos_wrong + XY(1, 0)] = src[2];
-  dung_bg2[pos_wrong + XY(1, 1)] = src[3];
-
-  // The orig asm code seems to access invalid vram here because it indexes by 0x14a4
-  uint16 *dst = &vram_upload_data[vram_upload_offset >> 1];
-  dst[0] = Dungeon_MapVramAddr(pos + 0);
-  dst[3] = Dungeon_MapVramAddr(pos + 64);
-  dst[6] = Dungeon_MapVramAddr(pos + 1);
-  dst[9] = Dungeon_MapVramAddr(pos + 65);
-
-  dst[2] = src[0];
-  dst[5] = src[1];
-  dst[8] = src[2];
-  dst[11] = src[3];
-
-  dst[1] = 0x100;
-  dst[4] = 0x100;
-  dst[7] = 0x100;
-  dst[10] = 0x100;
-
-  dst[12] = 0xffff;
-
-  vram_upload_offset += 24;
-
-  uint8 rv;
-
-  uint16 r16 = some_menu_ctr;
-
-  t = GetRandomNumber();
-  if (BYTE(dungeon_room_index) == 0) {
-    t = t & 0xf;
-    rv = kDungeon_RupeeChestMinigamePrizes[t & 0xf];
-
-  } else if (BYTE(dungeon_room_index) == 0x18) {
-    t = 0x10 + (t & 0xf);
-    rv = kDungeon_RupeeChestMinigamePrizes[0x10 + (t & 0xf)];
-  } else {
-    t &= 7;
-    if (t >= 2 && t == r16) {
-      t = (t + 1) & 7;
-    }
-    if (t == 7) {
-      if (dung_savegame_state_bits & 0x4000) {
-        t = 0;
-      } else {
-        dung_savegame_state_bits |= 0x4000;
-      }
-    }
-    rv = kDungeon_MinigameChestPrizes1[t];
-  }
-  some_menu_ctr = t;
-  nmi_load_bg_from_vram = 1;
-  sound_effect_2 = 14;
-  return rv;
-}
-
-uint16 RoomTag_BuildChestStripes(uint16 pos, uint16 y) {  // 81ef0f
-  pos += dung_chest_locations[y >> 1];
-  return swap16(((pos & 0x40) << 4) | ((pos & 0x303f) >> 1) | ((pos & 0xf80) >> 2));
-}
-
-void Dungeon_SetAttrForActivatedWaterOff() {  // 81ef93
-  CGWSEL_copy = 2;
-  CGADSUB_copy = 0x32;
-  TS_copy = 0;
-  W12SEL_copy = 0;
-  dung_hdr_collision = 0;
-  WORD(TMW_copy) = 0;
-  for (int j = 0; j != dung_num_inroom_upnorth_stairs_water; j += 2) {
-    int dsto = dung_stairs_table_1[j >> 1];
-    WriteAttr2(dsto + XY(1, 1), 0x1d1d);
-    WriteAttr2(dsto + XY(1, 2), 0x1d1d);
-  }
-  for (int j = 0; j != dung_num_inroom_upsouth_stairs_water; j += 2) {
-    int dsto = dung_stairs_table_2[j >> 1];
-    WriteAttr2(dsto + XY(1, 1), 0x1d1d);
-    WriteAttr2(dsto + XY(1, 2), 0x1d1d);
-  }
-  flag_update_cgram_in_nmi++;
-  subsubmodule_index++;
-}
-
-void Dungeon_FloodSwampWater_PrepTileMap() {  // 81f046
-  WaterFlood_BuildOneQuadrantForVRAM();
-  dung_cur_quadrant_upload += 4;
-  if (++subsubmodule_index == 6) {
-    dung_cur_quadrant_upload = 0;
-    subsubmodule_index = 0;
-    submodule_index = 0;
-  }
-}
-
-void Dungeon_AdjustWaterVomit(const uint16 *src, int depth) {  // 81f0c9
-  int dsto = (word_7E047C >> 1) + XY(0, 2);
-  uint16 *dst = &dung_bg2[dsto];
-  do {
-    dst[0] = src[0];
-    dst[1] = src[1];
-    dst[2] = src[2];
-    dst[3] = src[3];
-    dst += XY(0, 1), src += 4;
-  } while (--depth);
-  uint16 *vram = vram_upload_data;
-  for (int i = 0; i < 4; i++) {
-    uint16 *dst = &dung_bg2[dsto];
-    vram[0] = Dungeon_MapVramAddr(dsto);
-    vram[1] = 0x980;
-    vram[2] = dst[XY(0, 0)];
-    vram[3] = dst[XY(0, 1)];
-    vram[4] = dst[XY(0, 2)];
-    vram[5] = dst[XY(0, 3)];
-    vram[6] = dst[XY(0, 4)];
-    vram += 7, dsto++;
-  }
-  vram[0] = 0xffff;
-  nmi_load_bg_from_vram = 1;
-}
-
-void Dungeon_SetAttrForActivatedWater() {  // 81f237
-  WORD(TMW_copy) = 0;
-  for (int j = 0; j != dung_num_interpseudo_upnorth_stairs; j += 2) {
-    int dsto = dung_stairs_table_1[j >> 1];
-    WriteAttr2(dsto + 0, 0x003);
-    WriteAttr2(dsto + 2, 0x300);
-    WriteAttr1(dsto + 0, 0xa03);
-    WriteAttr1(dsto + 2, 0x30a);
-    WriteAttr2(dsto + XY(0, 1), 0x808);
-    WriteAttr2(dsto + XY(2, 1), 0x808);
-    WriteAttr1(dsto + XY(0, 1), 0x808);
-    WriteAttr1(dsto + XY(2, 1), 0x808);
-    WriteAttr1(dsto + XY(0, 2), 0x808);
-    WriteAttr1(dsto + XY(2, 2), 0x808);
-    WriteAttr1(dsto + XY(0, 3), 0x808);
-    WriteAttr1(dsto + XY(2, 3), 0x808);
-  }
-
-  for (int j = 0; j != dung_num_stairs_wet; j += 2) {
-    int dsto = dung_stairs_table_2[j >> 1];
-    WriteAttr2(dsto + XY(0, 3), 0x003);
-    WriteAttr2(dsto + XY(2, 3), 0x300);
-    WriteAttr1(dsto + XY(0, 3), 0xa03);
-    WriteAttr1(dsto + XY(2, 3), 0x30a);
-    WriteAttr2(dsto + XY(0, 2), 0x808);
-    WriteAttr2(dsto + XY(2, 2), 0x808);
-    WriteAttr1(dsto + XY(0, 0), 0x808);
-    WriteAttr1(dsto + XY(2, 0), 0x808);
-    WriteAttr1(dsto + XY(0, 1), 0x808);
-    WriteAttr1(dsto + XY(2, 1), 0x808);
-    WriteAttr1(dsto + XY(0, 2), 0x808);
-    WriteAttr1(dsto + XY(2, 2), 0x808);
-  }
-  submodule_index = 0;
-  nmi_boolean = 0; // wtf
-  subsubmodule_index = 0;
-}
-
-void FloodDam_Expand() {  // 81f30c
-  watergate_var1++;
-  water_hdma_var3 = watergate_var1 >> 1;
-  uint8 r0 = water_hdma_var3 - 8;
-  BYTE(spotlight_y_upper) = word_7E0678;
-  BYTE(spotlight_var4) += 1;
-  BYTE(water_hdma_var2) = spotlight_var4 + r0;
-
-  if (watergate_var1 & 0xf)
-    return;
-
-  if (watergate_var1 == 64)
-    subsubmodule_index++;
-
-  static const uint16 kWatergateSrcs1[] = { 0x12f8, 0x1348, 0x1398, 0x13e8 };
-  RoomDraw_Object_Nx4(10, SrcPtr(kWatergateSrcs1[(watergate_var1 >> 4) - 1]), &dung_bg2[watergate_pos >> 1]);
-  int pos = watergate_pos;
-  int n = 3;
-  int dma_ptr = 0;
-  do {
-    dma_ptr = Dungeon_PrepOverlayDma_watergate(dma_ptr, pos, 0x881, 4);
-    pos += 6;
-  } while (--n);
-  nmi_copy_packets_flag = 1;
-}
-
-void FloodDam_PrepTiles_init() {  // 81f3a7
-  dung_cur_quadrant_upload = 0;
-  overworld_screen_transition = 0;
-  WaterFlood_BuildOneQuadrantForVRAM();
-  dung_cur_quadrant_upload += 4;
-  subsubmodule_index++;
-}
-
-void Watergate_Main_State1() {  // 81f3aa
-  overworld_screen_transition = 0;
-  WaterFlood_BuildOneQuadrantForVRAM();
-  dung_cur_quadrant_upload += 4;
-  subsubmodule_index++;
-}
-
-void FloodDam_Fill() {  // 81f3bd
-  BYTE(water_hdma_var2)++;
-  uint8 t = water_hdma_var2 + spotlight_y_upper;
-  if (t >= 225) {
-    dung_cur_quadrant_upload = 0;
-    submodule_index = 0;
-    subsubmodule_index = 0;
-    TMW_copy = 0;
-    TSW_copy = 0;
-    IrisSpotlight_ResetTable();
-  }
-}
-
-void Ganon_ExtinguishTorch_adjust_translucency() {  // 81f496
-  Palette_AssertTranslucencySwap();
-  byte_7E0333 = 0xc0;
-  Dungeon_ExtinguishTorch();
-}
-
-void Ganon_ExtinguishTorch() {  // 81f4a1
-  byte_7E0333 = 193;
-  Dungeon_ExtinguishTorch();
-}
-
-void Dungeon_ExtinguishTorch() {  // 81f4a6
-  int y = (byte_7E0333 & 0xf) * 2 + dung_index_of_torches_start;
-
-  uint16 r8 = (dung_object_tilemap_pos[y >> 1] &= 0x7fff);
-
-  dung_torch_data[(dung_object_pos_in_objdata[y >> 1] & 0xff) >> 1] = r8;
-
-  r8 &= 0x3fff;
-  RoomDraw_AdjustTorchLightingChange(r8, 0xec2, r8);
-  nmi_copy_packets_flag = 1;
-
-  if (dung_want_lights_out && dung_num_lit_torches != 0 && --dung_num_lit_torches < 3) {
-    if (dung_num_lit_torches == 0)
-      TS_copy = 1;
-    overworld_fixed_color_plusminus = kLitTorchesColorPlus[dung_num_lit_torches];
-    submodule_index = 10;
-    subsubmodule_index = 0;
-  }
-
-  dung_torch_timers[byte_7E0333 & 0xf] = 0;
-  byte_7E0333 = 0;
-}
-
-void SpiralStairs_MakeNearbyWallsHighPriority_Entering() {  // 81f528
-  int pos = dung_inter_starcases[which_staircase_index & 3] - 4;
-  word_7E048C = pos * 2;
-  uint16 *dst = &dung_bg2[pos];
-  for (int i = 0; i < 5; i++) {
-    dst[XY(0, 0)] |= 0x2000;
-    dst[XY(0, 1)] |= 0x2000;
-    dst[XY(0, 2)] |= 0x2000;
-    dst[XY(0, 3)] |= 0x2000;
-    dst += 1;
-  }
-  int dp = Dungeon_PrepOverlayDma_nextPrep(0, pos * 2);
-  Dungeon_PrepOverlayDma_nextPrep(dp, pos * 2 + 8);
-  nmi_copy_packets_flag = 1;
-}
-
-void SpiralStairs_MakeNearbyWallsLowPriority() {  // 81f585
-  int pos = word_7E048C >> 1;
-  uint16 *dst = &dung_bg2[pos];
-  for (int i = 0; i < 5; i++) {
-    dst[XY(0, 0)] &= ~0x2000;
-    dst[XY(0, 1)] &= ~0x2000;
-    dst[XY(0, 2)] &= ~0x2000;
-    dst[XY(0, 3)] &= ~0x2000;
-    dst += 1;
-  }
-  int dp = Dungeon_PrepOverlayDma_nextPrep(0, pos * 2);
-  Dungeon_PrepOverlayDma_nextPrep(dp, pos * 2 + 8);
-  nmi_copy_packets_flag = 1;
-}
-
-void ClearAndStripeExplodingWall(uint16 dsto) {  // 81f811
-  static const uint16 kBlastWall_Tab2[16] = { 4, 8, 0xc, 0x10, 0x14, 0x18, 0x1c, 0x20, 0x100, 0x200, 0x300, 0x400, 0x500, 0x600, 0x700, 0x800 };
-
-  uint16 r6 = 0x80;
-  uint16 r14 = 0;
-  uint16 r10 = dung_unk_blast_walls_2 + 3;
-  uint16 r2 = 0;
-
-  if (!sign16(r10 - 8)) {
-    r2 = r10 - 6;
-    r14 = 1;
-    r10 = 3;
-  }
-  if (!(dung_door_direction[dung_cur_door_idx >> 1] & 2))
-    r6++;
-
-  uint16 *uvdata = &uvram.data[0];
-  for (;;) {
-    const uint16 *bg2 = &dung_bg2[dsto];
-    do {
-      uint16 vram_addr = Dungeon_MapVramAddrNoSwap(dsto);
-      uvdata[0] = vram_addr;
-      uvdata[1] = r6 | 0xa00;
-      uvdata[2] = bg2[XY(0, 0)];
-      uvdata[3] = bg2[XY(0, 1)];
-      uvdata[4] = bg2[XY(0, 2)];
-      uvdata[5] = bg2[XY(0, 3)];
-      uvdata[6] = bg2[XY(0, 4)];
-      uvdata[7] = vram_addr + 0x4a0;
-      uvdata[8] = r6 | 0xe00;
-      uvdata[9] = bg2[XY(0, 5)];
-      uvdata[10] = bg2[XY(0, 6)];
-      uvdata[11] = bg2[XY(0, 7)];
-      uvdata[12] = bg2[XY(0, 8)];
-      uvdata[13] = bg2[XY(0, 9)];
-      uvdata[14] = bg2[XY(0, 10)];
-      uvdata[15] = bg2[XY(0, 11)];
-      dsto++, bg2++, uvdata += 16;
-    } while (--r10);
-    if (!r14)
-      break;
-    r14--;
-    dsto += kBlastWall_Tab2[(r2 >> 1) + ((r6 & 1) ? 0 : 8) - 1] >> 1;
-    r10 = 3;
-  }
-  uvdata[0] = 0xffff;
-}
-
-void Dungeon_DrawRoomOverlay(const uint8 *src) {  // 81f967
-  for (;;) {
-    dung_draw_width_indicator = 0;
-    dung_draw_height_indicator = 0;
-    uint16 a = WORD(*src);
-    if (a == 0xffff)
-      break;
-    uint16 *p = &dung_bg2[(src[0] >> 2) | (src[1] >> 2) << 6];
-    uint8 type = src[2];
-    if (type == 0xa4) {
-      p[XY(0, 1)] = p[XY(1, 1)] = p[XY(2, 1)] = p[XY(3, 1)] =
-          p[XY(0, 2)] = p[XY(1, 2)] = p[XY(2, 2)] = p[XY(3, 2)] = SrcPtr(0x5aa)[0];
-      p[XY(0, 0)] = p[XY(1, 0)] = p[XY(2, 0)] = p[XY(3, 0)] = SrcPtr(0x63c)[1];
-      p[XY(0, 3)] = p[XY(1, 3)] = p[XY(2, 3)] = p[XY(3, 3)] = SrcPtr(0x642)[1];
-    } else {
-      const uint16 *sp = SrcPtr(dung_floor_2_filler_tiles);
-      p[XY(0, 0)] = p[XY(2, 0)] = p[XY(0, 2)] = p[XY(2, 2)] = sp[0];
-      p[XY(1, 0)] = p[XY(3, 0)] = p[XY(1, 2)] = p[XY(3, 2)] = sp[1];
-      p[XY(0, 1)] = p[XY(2, 1)] = p[XY(0, 3)] = p[XY(2, 3)] = sp[4];
-      p[XY(1, 1)] = p[XY(3, 1)] = p[XY(1, 3)] = p[XY(3, 3)] = sp[5];
-    }
-    src += 3;
-  }
-}
-
-void GetDoorDrawDataIndex_North_clean_door_index(int door) {  // 81fa4a
-  GetDoorDrawDataIndex_North(door, door);
-}
-
-int DoorDoorStep1_North(int door, int dma_ptr) {  // 81fa54
-  int pos = dung_door_tilemap_address[door];
-  if ((pos & 0x1fff) >= kDoorPositionToTilemapOffs_Up[6]) {
-    pos -= 0x500;
-    if ((door_type_and_slot[door] & 0xfe) >= 0x42)
-      pos -= 0x300;
-    GetDoorDrawDataIndex_South(door ^ 8, door & 7);
-    dma_ptr = Dungeon_PrepOverlayDma_nextPrep(dma_ptr, pos);
-    Dungeon_LoadSingleDoorAttribute(door ^ 8);
-  }
-  GetDoorDrawDataIndex_North(door, door & 7);
-  return dma_ptr;
-}
-
-void GetDoorDrawDataIndex_North(int door, int r4_door) {  // 81faa0
-  uint8 door_type = door_type_and_slot[door] & 0xfe;
-  int x = door_open_closed_counter;
-  if (x == 0 || x == 4) {
-    DrawDoorToTileMap_North(door, r4_door);
-    return;
-  }
-  x += (door_type == kDoorType_StairMaskLocked2 || door_type == kDoorType_StairMaskLocked3 || door_type >= 0x42) ? 4 : 0;
-  x += (door_type == kDoorType_ShuttersTwoWay || door_type == kDoorType_Shutter) ? 2 : 0;
-  //  assert(x < 8);
-  Object_Draw_DoorUp_4x3(kDoorAnimUpSrc[x >> 1], door);
-}
-
-void DrawDoorToTileMap_North(int door, int r4_door) {  // 81fad7
-  Object_Draw_DoorUp_4x3(kDoorTypeSrcData[GetDoorGraphicsIndex(door, r4_door) >> 1], door);
-}
-
-void Object_Draw_DoorUp_4x3(uint16 src, int door) {  // 81fae3
-  const uint16 *s = SrcPtr(src);
-  uint16 *dst = &dung_bg2[dung_door_tilemap_address[door] >> 1];
-  for (int i = 0; i < 4; i++) {
-    dst[XY(0, 0)] = s[0];
-    dst[XY(0, 1)] = s[1];
-    dst[XY(0, 2)] = s[2];
-    dst += 1, s += 3;
-  }
-}
-
-void GetDoorDrawDataIndex_South_clean_door_index(int door) {  // 81fb0b
-  GetDoorDrawDataIndex_South(door, door);
-}
-
-int DoorDoorStep1_South(int door, int dma_ptr) {  // 81fb15
-  int pos = dung_door_tilemap_address[door];
-  if ((pos & 0x1fff) < kDoorPositionToTilemapOffs_Down[9]) {
-    pos += 0x500;
-    if ((door_type_and_slot[door] & 0xfe) >= 0x42)
-      pos += 0x300;
-    GetDoorDrawDataIndex_North(door ^ 8, door & 7);
-    dma_ptr = Dungeon_PrepOverlayDma_nextPrep(dma_ptr, pos);
-    Dungeon_LoadSingleDoorAttribute(door ^ 8);
-  }
-  GetDoorDrawDataIndex_South(door, door & 7);
-  return dma_ptr;
-}
-
-void GetDoorDrawDataIndex_South(int door, int r4_door) {  // 81fb61
-  uint8 door_type = door_type_and_slot[door] & 0xfe;
-  int x = door_open_closed_counter;
-  if (x == 0 || x == 4) {
-    DrawDoorToTileMap_South(door, r4_door);
-    return;
-  }
-  x += (door_type >= 0x42) ? 4 : 0;
-  x += (door_type == kDoorType_ShuttersTwoWay || door_type == kDoorType_Shutter) ? 2 : 0;
-  //  assert(x < 8);
-  Object_Draw_DoorDown_4x3(kDoorAnimDownSrc[x >> 1], door);
-}
-
-void DrawDoorToTileMap_South(int door, int r4_door) {  // 81fb8e
-  Object_Draw_DoorDown_4x3(kDoorTypeSrcData2[GetDoorGraphicsIndex(door, r4_door) >> 1], door);
-}
-
-void Object_Draw_DoorDown_4x3(uint16 src, int door) {  // 81fb9b
-  const uint16 *s = SrcPtr(src);
-  uint16 *dst = &dung_bg2[dung_door_tilemap_address[door] >> 1];
-  for (int i = 0; i < 4; i++) {
-    dst[XY(0, 1)] = s[0];
-    dst[XY(0, 2)] = s[1];
-    dst[XY(0, 3)] = s[2];
-    dst += 1, s += 3;
-  }
-}
-
-void GetDoorDrawDataIndex_West_clean_door_index(int door) {  // 81fbc2
-  GetDoorDrawDataIndex_West(door, door);
-}
-
-int DoorDoorStep1_West(int door, int dma_ptr) {  // 81fbcc
-  int pos = dung_door_tilemap_address[door];
-  if ((pos & 0x7ff) >= kDoorPositionToTilemapOffs_Left[6]) {
-    pos -= 16;
-    if ((door_type_and_slot[door] & 0xfe) >= 0x42)
-      pos -= 12;
-    GetDoorDrawDataIndex_East(door ^ 8, door & 7);
-    dma_ptr = Dungeon_PrepOverlayDma_nextPrep(dma_ptr, pos);
-    Dungeon_LoadSingleDoorAttribute(door ^ 8);
-  }
-  GetDoorDrawDataIndex_West(door, door & 7);
-  return dma_ptr;
-}
-
-void GetDoorDrawDataIndex_West(int door, int r4_door) {  // 81fc18
-  uint8 door_type = door_type_and_slot[door] & 0xfe;
-  int x = door_open_closed_counter;
-  if (x == 0 || x == 4) {
-    DrawDoorToTileMap_West(door, r4_door);
-    return;
-  }
-  x += (door_type >= 0x42) ? 4 : 0;
-  x += (door_type == kDoorType_ShuttersTwoWay || door_type == kDoorType_Shutter) ? 2 : 0;
-  Object_Draw_DoorLeft_3x4(kDoorAnimLeftSrc[x >> 1], door);
-}
-
-void DrawDoorToTileMap_West(int door, int r4_door) {  // 81fc45
-  Object_Draw_DoorLeft_3x4(kDoorTypeSrcData3[GetDoorGraphicsIndex(door, r4_door) >> 1], door);
-}
-
-void GetDoorDrawDataIndex_East_clean_door_index(int door) {  // 81fc80
-  GetDoorDrawDataIndex_East(door, door);
-}
-
-int DoorDoorStep1_East(int door, int dma_ptr) {  // 81fc8a
-  int pos = dung_door_tilemap_address[door];
-  if ((pos & 0x7ff) < kDoorPositionToTilemapOffs_Right[6]) {
-    pos += 16;
-    if ((door_type_and_slot[door] & 0xfe) >= 0x42)
-      pos += 12;
-    GetDoorDrawDataIndex_West(door ^ 8, door & 7);
-    dma_ptr = Dungeon_PrepOverlayDma_nextPrep(dma_ptr, pos);
-    Dungeon_LoadSingleDoorAttribute(door ^ 8);
-  }
-  GetDoorDrawDataIndex_East(door, door & 7);
-  return dma_ptr;
-}
-
-void GetDoorDrawDataIndex_East(int door, int r4_door) {  // 81fcd6
-  uint8 door_type = door_type_and_slot[door] & 0xfe;
-  int x = door_open_closed_counter;
-  if (x == 0 || x == 4) {
-    DrawDoorToTileMap_East(door, r4_door);
-    return;
-  }
-  x += (door_type >= 0x42) ? 4 : 0;
-  x += (door_type == kDoorType_ShuttersTwoWay || door_type == kDoorType_Shutter) ? 2 : 0;
-  Object_Draw_DoorRight_3x4(kDoorAnimRightSrc[x >> 1], door);
-}
-
-void DrawDoorToTileMap_East(int door, int r4_door) {  // 81fd03
-  Object_Draw_DoorRight_3x4(kDoorTypeSrcData4[GetDoorGraphicsIndex(door, r4_door) >> 1], door);
-}
-
-uint8 GetDoorGraphicsIndex(int door, int r4_door) {  // 81fd79
-  uint8 door_type = door_type_and_slot[door] & 0xfe;
-  if (dung_door_opened_incl_adjacent & kUpperBitmasks[r4_door])
-    door_type = kDoorTypeRemap[door_type >> 1];
-  return door_type;
-}
-
-void ClearExplodingWallFromTileMap_ClearOnePair(uint16 *dst, const uint16 *src) {  // 81fddb
-  for (int i = 2; i != 0; i--) {
-    for (int j = 0; j < 12; j++)
-      dst[XY(0, j)] = src[j];
-    dst++;
-    src += 12;
-  }
-}
-
-void Dungeon_DrawRoomOverlay_Apply(int p) {  // 81fe41
-  for (int j = 0; j < 4; j++, p += 64) {
-    for (int i = 0; i < 4; i++) {
-      uint16 t = dung_bg2[p + i] & 0x3fe;
-      dung_bg2_attr_table[p + i] = (t == 0xee || t == 0xfe) ? 0 : 0x20;
-    }
-  }
-}
-
-void ApplyGrayscaleFixed_Incremental() {  // 81feb0
-  uint8 a = COLDATA_copy0 & 0x1f;
-  if (a == overworld_fixed_color_plusminus)
-    return;
-  a += (a < overworld_fixed_color_plusminus) ? 1 : -1;
-  Dungeon_ApproachFixedColor_variable(a);
-}
-
-void Dungeon_ApproachFixedColor_variable(uint8 a) {  // 81fec1
-  COLDATA_copy0 = a | 0x20;
-  COLDATA_copy1 = a | 0x40;
-  COLDATA_copy2 = a | 0x80;
-}
-
-void Module_PreDungeon() {  // 82821e
-  sound_effect_ambient = 5;
-  sound_effect_1 = 0;
-  dungeon_room_index = 0;
-  dungeon_room_index_prev = 0;
-  dung_savegame_state_bits = 0;
-
-  agahnim_pal_setting[0] = agahnim_pal_setting[1] = agahnim_pal_setting[2] = 0;
-  agahnim_pal_setting[3] = agahnim_pal_setting[4] = agahnim_pal_setting[5] = 0;
-
-  Dungeon_LoadEntrance();
-  uint8 d = cur_palace_index_x2;
-  link_num_keys = (d != 0xff) ? link_keys_earned_per_dungeon[d == 2 ? 0 : (d >> 1)] : 0xff;
-  Hud_Rebuild();
-  dung_num_lit_torches = 0;
-  hdr_dungeon_dark_with_lantern = 0;
-  Dungeon_LoadAndDrawRoom();
-  Dungeon_LoadCustomTileAttr();
-
-  DecompressAnimatedDungeonTiles(kDungAnimatedTiles[main_tile_theme_index]);
-  Dungeon_LoadAttributeTable();
-  misc_sprites_graphics_index = 10;
-  InitializeTilesets();
-  palette_sp6r_indoors = 10;
-  Dungeon_LoadPalettes();
-  if (link_is_bunny_mirror | link_is_bunny)
-    LoadGearPalettes_bunny();
-
-  dung_loade_bgoffs_h_copy = (dungeon_room_index & 0xf) << 9;
-  dung_loade_bgoffs_v_copy = swap16((dungeon_room_index & 0xff0) >> 3);
-
-  if (dungeon_room_index == 0x104 && sram_progress_flags & 0x10)
-    WORD(dung_want_lights_out) = 0;
-
-  SetAndSaveVisitedQuadrantFlags();
-  CGWSEL_copy = 2;
-  CGADSUB_copy = 0xb3;
-
-  uint8 x = dung_num_lit_torches;
-  if (!dung_want_lights_out) {
-    x = 3;
-    CGADSUB_copy = dung_hdr_bg2_properties == 7 ? 0x32 :
-      dung_hdr_bg2_properties == 4 ? 0x62 : 0x20;
-  }
-  overworld_fixed_color_plusminus = kLitTorchesColorPlus[x];
-  Dungeon_ApproachFixedColor_variable(overworld_fixed_color_plusminus);
-  BYTE(palette_filter_countdown) = 0x1f;
-  mosaic_target_level = 0;
-  BYTE(darkening_or_lightening_screen) = 2;
-  overworld_palette_aux_or_main = 0;
-  link_speed_modifier = 0;
-  button_mask_b_y = 0;
-  button_b_frames = 0;
-  Dungeon_ResetTorchBackgroundAndPlayer();
-  Link_CheckBunnyStatus();
-  ResetThenCacheRoomEntryProperties();
-  if (follower_indicator == 13) {
-    follower_indicator = 0;
-    super_bomb_indicator_unk2 = 0;
-    Hud_RemoveSuperBombIndicator();
-  }
-  BGMODE_copy = 9;
-  Follower_Initialize();
-  Sprite_ResetAll();
-  Dungeon_ResetSprites();
-  byte_7E02F0 = 0;
-  flag_skip_call_tag_routines++;
-  if (!sram_progress_indicator && !(sram_progress_flags & 0x10)) {
-    COLDATA_copy0 = 0x30;
-    COLDATA_copy1 = 0x50;
-    COLDATA_copy2 = 0x80;
-    dung_want_lights_out = dung_want_lights_out_copy = 0;
-    Link_TuckIntoBed();
-  }
-  saved_module_for_menu = 7;
-  main_module_index = 7;
-  submodule_index = 15;
-  Dungeon_LoadSongBankIfNeeded();
-  Module_PreDungeon_setAmbientSfx();
-}
-
-void Module_PreDungeon_setAmbientSfx() {  // 82838c
-  if (sram_progress_indicator < 2) {
-    sound_effect_ambient = 5;
-    if (!sign8(dung_cur_floor) && dungeon_room_index != 2 && dungeon_room_index != 18)
-      sound_effect_ambient = 3;
-  }
-}
-
-void LoadOWMusicIfNeeded() {  // 82854c
-  if (!flag_which_music_type)
-    return;
-  flag_which_music_type = 0;
-  LoadOverworldSongs();
-}
-
-void Module07_Dungeon() {  // 8287a2
-  Dungeon_HandleLayerEffect();
-  kDungeonSubmodules[submodule_index]();
-
-  // When having the somaria on door button and exiting in skull woods, 
-  // don't overwrite submodule_index
-  if (enhanced_features0 & kFeatures0_MiscBugFixes && main_module_index != 7)
-    goto skip;
-
-  dung_misc_objs_index = 0;
-  Dungeon_PushBlock_Handler();
-  if (submodule_index) goto skip;
-  Graphics_LoadChrHalfSlot();
-  Dungeon_HandleCamera();
-  if (submodule_index) goto skip;
-  Dungeon_HandleRoomTags();
-  if (submodule_index) goto skip;
-  Dungeon_ProcessTorchesAndDoors();
-  if (dung_unk_blast_walls_2)
-    Dungeon_ClearAwayExplodingWall();
-  if (!is_standing_in_doorway)
-    Dungeon_TryScreenEdgeTransition();
-skip:
-  OrientLampLightCone();
-
-  int bg2x = BG2HOFS_copy2;
-  int bg2y = BG2VOFS_copy2;
-  int bg1x = BG1HOFS_copy2;
-  int bg1y = BG1VOFS_copy2;
-
-  BG2HOFS_copy2 = BG2HOFS_copy = bg2x + bg1_x_offset;
-  BG2VOFS_copy2 = BG2VOFS_copy = bg2y + bg1_y_offset;
-  BG1HOFS_copy2 = BG1HOFS_copy = bg1x + bg1_x_offset;
-  BG1VOFS_copy2 = BG1VOFS_copy = bg1y + bg1_y_offset;
-
-  if (dung_hdr_collision_2_mirror) {
-    BG1HOFS_copy2 = BG1HOFS_copy = bg1x = BG2HOFS_copy2 + dung_floor_x_offs;
-    BG1VOFS_copy2 = BG1VOFS_copy = bg1y = BG2VOFS_copy2 + dung_floor_y_offs;
-  }
-
-  Sprite_Dungeon_DrawAllPushBlocks();
-  Sprite_Main();
-
-  BG2HOFS_copy2 = bg2x;
-  BG2VOFS_copy2 = bg2y;
-  BG1HOFS_copy2 = bg1x;
-  BG1VOFS_copy2 = bg1y;
-
-  LinkOam_Main();
-  Hud_RefillLogic();
-  Hud_FloorIndicator();
-}
-
-void Dungeon_TryScreenEdgeTransition() {  // 82885e
-  int dir;
-
-  if (link_y_vel != 0) {
-    int y = (link_y_coord & 0x1ff);
-    if ((dir = 3, y < 4) || (dir = 2, y >= 476))
-      goto trigger_trans;
-  }
-
-  if (link_x_vel != 0) {
-    int y = (link_x_coord & 0x1ff);
-    if ((dir = 1, y < 8) || (dir = 0, y >= 489))
-      goto trigger_trans;
-  }
-  return;
-
-trigger_trans:
-  if (!Link_CheckForEdgeScreenTransition() && main_module_index == 7) {
-    Dungeon_HandleEdgeTransitionMovement(dir);
-    if (main_module_index == 7)
-      submodule_index = 2;
-  }
-}
-
-void Dungeon_HandleEdgeTransitionMovement(int dir) {  // 8288c5
-  static const uint8 kLimitDirectionOnOneAxis[] = { 0x3, 0x3, 0xc, 0xc };
-  link_direction &= kLimitDirectionOnOneAxis[dir];
-  switch (dir) {
-  case 0: Dungeon_StartInterRoomTrans_Right(); break;
-  case 1: Dungeon_StartInterRoomTrans_Left(); break;
-  case 2: Dungeon_StartInterRoomTrans_Down(); break;
-  case 3: Dungeon_StartInterRoomTrans_Up(); break;
-  default:
-    assert(0);
-  }
-}
-
-void Module07_00_PlayerControl() {  // 8288de
-  if (!(flag_custom_spell_anim_active | flag_is_link_immobilized | flag_block_link_menu)) {
-    if (filtered_joypad_H & 0x10) {  // start
-      overworld_map_state = 0;
-      submodule_index = 1;
-      saved_module_for_menu = main_module_index;
-      main_module_index = 14;
-      return;
-    } else if (DidPressButtonForMap()) {  // x
-      if ((uint8)cur_palace_index_x2 != 0xff && (uint8)dungeon_room_index) {
-        overworld_map_state = 0;
-        submodule_index = 3;
-        saved_module_for_menu = main_module_index;
-        main_module_index = 14;
-        return;
-      }
-    } else if (joypad1H_last & 0x20) {  // select
-      if (sram_progress_indicator) {
-        overworld_map_state = 0;
-        DisplaySelectMenu();
-        return;
-      }
-    }
-    Hud_HandleItemSwitchInputs();
-  }
-  Link_Main();
-}
-
-void Module07_01_SubtileTransition() {  // 82897c
-  link_y_coord_prev = link_y_coord;
-  link_x_coord_prev = link_x_coord;
-  Link_HandleMovingAnimation_FullLongEntry();
-  kDungeon_IntraRoomTrans[subsubmodule_index]();
-}
-
-void DungeonTransition_Subtile_ResetShutters() {  // 828995
-  BYTE(dung_flag_trapdoors_down) = 0;
-  BYTE(door_animation_step_indicator) = 7;
-  uint8 bak = submodule_index;
-  OperateShutterDoors();
-  submodule_index = bak;
-  BYTE(palette_filter_countdown) = 31;
-  mosaic_target_level = 0;
-  subsubmodule_index++;
-}
-
-void DungeonTransition_Subtile_PrepTransition() {  // 8289b6
-  darkening_or_lightening_screen = 0;
-  palette_filter_countdown = 0;
-  mosaic_target_level = 31;
-  unused_config_gfx = 0;
-  dung_flag_somaria_block_switch = 0;
-  dung_flag_statechange_waterpuzzle = 0;
-  subsubmodule_index++;
-}
-
-void DungeonTransition_Subtile_ApplyFilter() {  // 8289d8
-  if (!dung_want_lights_out) {
-    subsubmodule_index++;
-    return;
-  }
-  ApplyPaletteFilter_bounce();
-  if (BYTE(palette_filter_countdown))
-    ApplyPaletteFilter_bounce();
-}
-
-void DungeonTransition_Subtile_TriggerShutters() {  // 8289f0
-  ResetThenCacheRoomEntryProperties();
-  if (!BYTE(dung_flag_trapdoors_down)) {
-    BYTE(dung_flag_trapdoors_down)++;
-    BYTE(dung_cur_door_pos) = 0;
-    BYTE(door_animation_step_indicator) = 0;
-    submodule_index = 5;
-  }
-}
-
-void Module07_02_SupertileTransition() {  // 828a26
-  link_y_coord_prev = link_y_coord;
-  link_x_coord_prev = link_x_coord;
-  if (subsubmodule_index != 0) {
-    if (subsubmodule_index >= 7)
-      Graphics_IncrementalVRAMUpload();
-    Dungeon_LoadAttribute_Selectable();
-  }
-  Link_HandleMovingAnimation_FullLongEntry();
-  kDungeon_InterRoomTrans[subsubmodule_index]();
-}
-
-void Module07_02_00_InitializeTransition() {  // 828a4f
-  uint8 bak = hdr_dungeon_dark_with_lantern;
-  ResetTransitionPropsAndAdvanceSubmodule();
-  hdr_dungeon_dark_with_lantern = bak;
-}
-
-void Module07_02_01_LoadNextRoom() {  // 828a5b
-  Dungeon_LoadRoom();
-  ResetStarTileGraphics();
-  LoadTransAuxGFX_sprite();
-  subsubmodule_index++;
-  overworld_map_state = 0;
-  BYTE(dungeon_room_index2) = BYTE(dungeon_room_index);
-  Dungeon_ResetSprites();
-  if (!hdr_dungeon_dark_with_lantern)
-    MirrorBg1Bg2Offs();
-  hdr_dungeon_dark_with_lantern = 0;
-}
-
-void Dungeon_InterRoomTrans_State3() {  // 828a87
-  if (dung_want_lights_out | dung_want_lights_out_copy)
-    TS_copy = 0;
-  Dungeon_AdjustForRoomLayout();
-  LoadNewSpriteGFXSet();
-  MirrorBg1Bg2Offs();
-  WaterFlood_BuildOneQuadrantForVRAM();
-  subsubmodule_index++;
-}
-
-void Dungeon_InterRoomTrans_State10() {  // 828aa5
-  if (dung_want_lights_out | dung_want_lights_out_copy)
-    ApplyPaletteFilter_bounce();
-  Dungeon_InterRoomTrans_notDarkRoom();
-}
-
-void Dungeon_SpiralStaircase11() {  // 828aaf
-  ApplyPaletteFilter_bounce();
-  WaterFlood_BuildOneQuadrantForVRAM();
-  subsubmodule_index++;
-}
-
-void Dungeon_InterRoomTrans_notDarkRoom() {  // 828ab3
-  WaterFlood_BuildOneQuadrantForVRAM();
-  subsubmodule_index++;
-}
-
-void Dungeon_InterRoomTrans_State9() {  // 828aba
-  if (dung_want_lights_out | dung_want_lights_out_copy)
-    ApplyPaletteFilter_bounce();
-  Dungeon_InterRoomTrans_State4();
-}
-
-void Dungeon_SpiralStaircase12() {  // 828ac4
-  ApplyPaletteFilter_bounce();
-  Dungeon_PrepareNextRoomQuadrantUpload();
-  subsubmodule_index++;
-}
-
-void Dungeon_InterRoomTrans_State4() {  // 828ac8
-  Dungeon_PrepareNextRoomQuadrantUpload();
-  subsubmodule_index++;
-}
-
-void Dungeon_InterRoomTrans_State12() {  // 828acf
-  if (submodule_index == 2) {
-    if (overworld_map_state != 5)
-      return;
-    SubtileTransitionCalculateLanding();
-    if (dung_want_lights_out | dung_want_lights_out_copy)
-      ApplyPaletteFilter_bounce();
-  }
-  subsubmodule_index++;
-  Dungeon_ResetTorchBackgroundAndPlayer();
-}
-
-void Dungeon_Staircase14() {  // 828aed
-  subsubmodule_index++;
-  Dungeon_ResetTorchBackgroundAndPlayer();
-}
-
-void Dungeon_ResetTorchBackgroundAndPlayer() {  // 828aef
-  uint8 ts = kSpiralTab1[dung_hdr_bg2_properties], tm = 0x16;
-  if (sign8(ts))
-    tm = 0x17, ts = 0;
-  if (dung_hdr_bg2_properties == 2)
-    ts = 3;
-  TM_copy = tm;
-  TS_copy = ts;
-  Hud_RestoreTorchBackground();
-  Dungeon_ResetTorchBackgroundAndPlayerInner();
-}
-
-void Dungeon_ResetTorchBackgroundAndPlayerInner() {  // 828b0c
-  Ancilla_TerminateSelectInteractives(0);
-  if (link_is_running && !(enhanced_features0 & kFeatures0_TurnWhileDashing)) {
-    link_auxiliary_state = 0;
-    link_incapacitated_timer = 0;
-    link_actual_vel_z = 0xff;
-    g_ram[0xc7] = 0xff;
-    link_delay_timer_spin_attack = 0;
-    link_speed_setting = 0;
-    swimcoll_var5[0] &= ~0xff;
-    link_is_running = 0;
-    link_player_handler_state = 0;
-  }
-}
-
-void Dungeon_InterRoomTrans_State7() {  // 828b2e
-  BG1HOFS_copy2 = BG2HOFS_copy2;
-  BG1VOFS_copy2 = BG2VOFS_copy2;
-
-  if (dungeon_room_index != 54 && dungeon_room_index != 56) {
-    uint16 y = kSpiralTab1[dung_hdr_bg2_properties] ? 0x116 : 0x16;
-    if (y != (TM_copy | TS_copy << 8) && (TM_copy == 0x17 || (TM_copy | TS_copy) != 0x17))
-      TM_copy = y, TS_copy = y >> 8;
-  }
-  DungeonTransition_RunFiltering();
-}
-
-void DungeonTransition_RunFiltering() {  // 828b67
-  if (dung_want_lights_out | dung_want_lights_out_copy) {
-    overworld_fixed_color_plusminus = kLitTorchesColorPlus[dung_want_lights_out ? dung_num_lit_torches : 3];
-    Dungeon_ApproachFixedColor_variable(overworld_fixed_color_plusminus);
-    mosaic_target_level = 0;
-  }
-  Dungeon_HandleTranslucencyAndPalette();
-}
-
-void Module07_02_FadedFilter() {  // 828b92
-  if (dung_want_lights_out | dung_want_lights_out_copy) {
-    ApplyPaletteFilter_bounce();
-    if (BYTE(palette_filter_countdown))
-      ApplyPaletteFilter_bounce();
-  } else {
-    subsubmodule_index++;
-  }
-}
-
-void Dungeon_InterRoomTrans_State15() {  // 828bae
-  ResetThenCacheRoomEntryProperties();
-  if (!BYTE(dung_flag_trapdoors_down) && (BYTE(dungeon_room_index) != 172 || dung_savegame_state_bits & 0x3000)) {
-    BYTE(dung_flag_trapdoors_down) = 1;
-    BYTE(dung_cur_door_pos) = 0;
-    BYTE(door_animation_step_indicator) = 0;
-    submodule_index = 5;
-  }
-  Dungeon_PlayMusicIfDefeated();
-}
-
-void Dungeon_PlayMusicIfDefeated() {  // 828bd7
-  uint8 x = 0x14;
-  if (dungeon_room_index != 18) {
-    x = 0x10;
-    if (dungeon_room_index != 2) {
-      if (FindInWordArray(kBossRooms, dungeon_room_index, countof(kBossRooms)) < 0)
-        return;
-      if (Sprite_CheckIfScreenIsClear())
-        return;
-      x = 0x15;
-    }
-  }
-  music_control = x;
-}
-
-void Module07_03_OverlayChange() {  // 828c05
-  const uint8 *overlay_p = kDungeonRoomOverlay + kDungeonRoomOverlayOffs[dung_overlay_to_load];
-  Dungeon_DrawRoomOverlay(overlay_p);
-  int dst_pos = 0;
-  for (;;) {
-    uint16 a = WORD(*overlay_p);
-    if (a == 0xffff)
-      break;
-    int p = (overlay_p[0] >> 2) | (overlay_p[1] >> 2) << 6;
-    dst_pos = Dungeon_PrepOverlayDma_nextPrep(dst_pos, p * 2);
-    Dungeon_DrawRoomOverlay_Apply(p);
-    overlay_p += 3;
-  }
-  nmi_copy_packets_flag = 1;
-  submodule_index = 0;
-}
-
-void Module07_04_UnlockDoor() {  // 828c0a
-  Dungeon_OpeningLockedDoor_Combined(false);
-}
-
-void Module07_05_ControlShutters() {  // 828c0f
-  OperateShutterDoors();
-}
-
-void Module07_06_FatInterRoomStairs() {  // 828c14
-  if (subsubmodule_index >= 3)
-    Dungeon_LoadAttribute_Selectable();
-
-  if (subsubmodule_index >= 13) {
-    Graphics_IncrementalVRAMUpload();
-    if (!staircase_var1)
-      goto table;
-    if (staircase_var1-- == 0x10)
-      link_speed_modifier = 2;
-    link_direction = which_staircase_index & 4 ? 4 : 8;
-    Link_HandleVelocity();
-    Dungeon_HandleCamera();
-  }
-  Link_HandleMovingAnimation_FullLongEntry();
-table:
-  switch (subsubmodule_index) {
-  case 0: ResetTransitionPropsAndAdvance_ResetInterface(); break;
-  case 1:
-    ApplyPaletteFilter_bounce();
-    if (BYTE(palette_filter_countdown))
-      ApplyPaletteFilter_bounce();
-    break;
-  case 2: Dungeon_InitializeRoomFromSpecial(); break;
-  case 3: DungeonTransition_TriggerBGC34UpdateAndAdvance(); break;
-  case 4: DungeonTransition_TriggerBGC56UpdateAndAdvance(); break;
-  case 5: DungeonTransition_LoadSpriteGFX(); break;
-  case 6: DungeonTransition_AdjustForFatStairScroll(); break;
-  case 7: Dungeon_InterRoomTrans_State4(); break;
-  case 8: Dungeon_InterRoomTrans_notDarkRoom(); break;
-  case 9: Dungeon_InterRoomTrans_State4(); break;
-  case 10: Dungeon_SpiralStaircase11(); break;
-  case 11: Dungeon_SpiralStaircase12(); break;
-  case 12: Dungeon_SpiralStaircase11(); break;
-  case 13: Dungeon_SpiralStaircase12(); break;
-  case 14: Dungeon_DoubleApplyAndIncrementGrayscale(); break;
-  case 15: Dungeon_Staircase14(); break;
-  case 16:
-    if (!(BYTE(darkening_or_lightening_screen) | BYTE(palette_filter_countdown)) && overworld_map_state == 5)
-      ResetThenCacheRoomEntryProperties();
-    break;
-  }
-}
-
-void Module07_0E_01_HandleMusicAndResetProps() {  // 828c78
-  if ((dungeon_room_index == 7 || dungeon_room_index == 23 && !ZeldaIsPlayingMusicTrack(17)) && !(link_which_pendants & 1))
-    music_control = 0xf1;
-  staircase_var1 = (which_staircase_index & 4) ? 106 : 88;
-  overworld_map_state = 0;
-  ResetTransitionPropsAndAdvanceSubmodule();
-}
-
-void ResetTransitionPropsAndAdvance_ResetInterface() {  // 828ca9
-  overworld_map_state = 0;
-  ResetTransitionPropsAndAdvanceSubmodule();
-}
-
-void ResetTransitionPropsAndAdvanceSubmodule() {  // 828cac
-  WORD(mosaic_level) = 0;
-  darkening_or_lightening_screen = 0;
-  palette_filter_countdown = 0;
-  mosaic_target_level = 31;
-  unused_config_gfx = 0;
-  dung_num_lit_torches = 0;
-  if (hdr_dungeon_dark_with_lantern) {
-    CGWSEL_copy = 0x02;
-    CGADSUB_copy = 0xB3;
-  }
-  hdr_dungeon_dark_with_lantern = 0;
-  Dungeon_ResetTorchBackgroundAndPlayerInner();
-  Overworld_CopyPalettesToCache();
-  subsubmodule_index += 1;
-}
-
-void Dungeon_InitializeRoomFromSpecial() {  // 828ce2
-  Dungeon_AdjustAfterSpiralStairs();
-  Dungeon_LoadRoom();
-  ResetStarTileGraphics();
-  LoadTransAuxGFX();
-  Dungeon_LoadCustomTileAttr();
-  BYTE(dungeon_room_index2) = BYTE(dungeon_room_index);
-  Follower_Initialize();
-  subsubmodule_index += 1;
-}
-
-void DungeonTransition_LoadSpriteGFX() {  // 828d10
-  LoadNewSpriteGFXSet();
-  Dungeon_ResetSprites();
-  DungeonTransition_RunFiltering();
-}
-
-void DungeonTransition_AdjustForFatStairScroll() {  // 828d1b
-  MirrorBg1Bg2Offs();
-  Dungeon_AdjustForRoomLayout();
-  uint8 ts = kSpiralTab1[dung_hdr_bg2_properties];
-  uint8 tm = 0x16;
-  if (sign8(ts))
-    tm = 0x17, ts = 0;
-  TM_copy = tm;
-  TS_copy = ts;
-
-  link_speed_modifier = 1;
-  if (which_staircase_index & 4) {
-    dung_cur_floor--;
-    staircase_var1 = 32;
-    sound_effect_1 = 0x19;
-  } else {
-    dung_cur_floor++;
-    staircase_var1 = 48;
-    sound_effect_1 = 0x17;
-  }
-  sound_effect_2 = 0x24;
-  Dungeon_PlayBlipAndCacheQuadrantVisits();
-  Dungeon_InterRoomTrans_notDarkRoom();
-}
-
-void ResetThenCacheRoomEntryProperties() {  // 828d71
-  overworld_map_state = 0;
-  subsubmodule_index = 0;
-  overworld_screen_transition = 0;
-  submodule_index = 0;
-  dung_flag_statechange_waterpuzzle = 0;
-  dung_flag_movable_block_was_pushed = 0;
-  CacheCameraProperties();
-}
-
-void DungeonTransition_TriggerBGC34UpdateAndAdvance() {  // 828e0f
-  PrepTransAuxGfx();
-  nmi_subroutine_index = nmi_disable_core_updates = 9;
-  subsubmodule_index += 1;
-}
-
-void DungeonTransition_TriggerBGC56UpdateAndAdvance() {  // 828e1d
-  nmi_subroutine_index = nmi_disable_core_updates = 10;
-  subsubmodule_index += 1;
-}
-
-void Module07_07_FallingTransition() {  // 828e27
-  if (subsubmodule_index >= 6) {
-    Graphics_IncrementalVRAMUpload();
-    Dungeon_LoadAttribute_Selectable();
-    ApplyGrayscaleFixed_Incremental();
-  }
-  kDungeon_Submodule_7_DownFloorTrans[subsubmodule_index]();
-}
-
-void Module07_07_00_HandleMusicAndResetRoom() {  // 828e63
-  if (dungeon_room_index == 0x10 || dungeon_room_index == 7 || dungeon_room_index == 0x17)
-    music_control = 0xf1;
-  ResetTransitionPropsAndAdvance_ResetInterface();
-}
-
-void Module07_07_06_SyncBG1and2() {  // 828e80
-  MirrorBg1Bg2Offs();
-  Dungeon_AdjustForRoomLayout();
-  uint8 ts = kSpiralTab1[dung_hdr_bg2_properties];
-  uint8 tm = 0x16;
-  if (sign8(ts))
-    tm = 0x17, ts = 0;
-  TM_copy = tm;
-  TS_copy = ts;
-  WaterFlood_BuildOneQuadrantForVRAM();
-  subsubmodule_index++;
-}
-
-void Module07_07_0F_FallingFadeIn() {  // 828ea1
-  ApplyPaletteFilter_bounce();
-  if (BYTE(darkening_or_lightening_screen))
-    return;
-  HIBYTE(tiledetect_which_y_pos[0]) = HIBYTE(link_y_coord) + (BYTE(link_y_coord) >= BYTE(tiledetect_which_y_pos[0]));
-  Dungeon_SetBossMusicUnorthodox();
-  if (BYTE(dungeon_room_index) == 0x89 || BYTE(dungeon_room_index) == 0x4f)
-    return;
-  if (BYTE(dungeon_room_index) == 0xA7) {
-    hud_floor_changed_timer = 0;
-    dung_cur_floor = 1;
-    return;
-  }
-  dung_cur_floor--;
-  Dungeon_PlayBlipAndCacheQuadrantVisits();
-}
-
-void Dungeon_PlayBlipAndCacheQuadrantVisits() {  // 828ec9
-  hud_floor_changed_timer = 1;
-  sound_effect_2 = 36;
-  SetAndSaveVisitedQuadrantFlags();
-}
-
-void Module07_07_10_LandLinkFromFalling() {  // 828ee0
-  HandleDungeonLandingFromPit();
-  if (submodule_index)
-    return;
-  submodule_index = 7;
-  subsubmodule_index = 17;
-  load_chr_halfslot_even_odd = 1;
-  Graphics_LoadChrHalfSlot();
-}
-
-void Module07_07_11_CacheRoomAndSetMusic() {  // 828efa
-  if (overworld_map_state == 5) {
-    ResetThenCacheRoomEntryProperties();
-    Dungeon_PlayMusicIfDefeated();
-    Graphics_LoadChrHalfSlot();
-  }
-}
-
-// straight staircase going down when walking south
-void Module07_08_NorthIntraRoomStairs() {  // 828f0c
-  uint8 t = staircase_var1;
-  if (t) {
-    staircase_var1--;
-    if (t == 20)
-      link_speed_modifier = 2;
-    Link_HandleVelocity();
-    ApplyLinksMovementToCamera();
-    Dungeon_HandleCamera();
-    Link_HandleMovingAnimation_FullLongEntry();
-  }
-  kDungeon_StraightStaircaseDown[subsubmodule_index]();
-}
-
-void Module07_08_00_InitStairs() {  // 828f35
-  draw_water_ripples_or_grass = 0;
-
-  uint8 v1 = 0x3c, sfx = 25;
-  if (link_direction & 8) {
-    v1 = 0x38, sfx = 23;
-    link_is_on_lower_level_mirror = 0;
-    if ((uint8)kind_of_in_room_staircase != 2)
-      link_is_on_lower_level = 0;
-  }
-  staircase_var1 = v1;
-  sound_effect_1 = sfx;
-  link_speed_modifier = 1;
-  subsubmodule_index++;
-}
-
-void Module07_08_01_ClimbStairs() {  // 828f5f
-  if (staircase_var1)
-    return;
-  if (link_direction & 4) {
-    link_is_on_lower_level_mirror = 1;
-    if ((uint8)kind_of_in_room_staircase != 2)
-      link_is_on_lower_level = 1;
-  }
-  subsubmodule_index = 0;
-  overworld_screen_transition = 0;
-  submodule_index = 0;
-  SetAndSaveVisitedQuadrantFlags();
-}
-
-// straight staircase going up when walking south
-void Module07_10_SouthIntraRoomStairs() {  // 828f88
-  uint8 t = staircase_var1;
-  if (t) {
-    staircase_var1--;
-    if (t == 20)
-      link_speed_modifier = 2;
-    Link_HandleVelocity();
-    ApplyLinksMovementToCamera();
-    Dungeon_HandleCamera();
-    Link_HandleMovingAnimation_FullLongEntry();
-  }
-  kDungeon_StraightStaircase[subsubmodule_index]();
-}
-
-void Module07_10_00_InitStairs() {  // 828fb1
-  uint8 v1 = 0x3c, sfx = 25;
-  if (link_direction & 4) {
-    v1 = 0x38, sfx = 23;
-    link_is_on_lower_level_mirror ^= 1;
-    if ((uint8)kind_of_in_room_staircase != 2)
-      link_is_on_lower_level ^= 1;
-  }
-  staircase_var1 = v1;
-  sound_effect_1 = sfx;
-  link_speed_modifier = 1;
-  subsubmodule_index++;
-}
-
-void Module07_10_01_ClimbStairs() {  // 828fe1
-  if (staircase_var1)
-    return;
-  if (link_direction & 8) {
-    link_is_on_lower_level_mirror ^= 1;
-    if ((uint8)kind_of_in_room_staircase != 2)
-      link_is_on_lower_level ^= 1;
-  }
-  subsubmodule_index = 0;
-  overworld_screen_transition = 0;
-  submodule_index = 0;
-  SetAndSaveVisitedQuadrantFlags();
-}
-
-void Module07_09_OpenCrackedDoor() {  // 82900f
-  OpenCrackedDoor();
-}
-
-// Used when lighting a lamp
-void Module07_0A_ChangeBrightness() {  // 829014
-  OrientLampLightCone();
-  ApplyGrayscaleFixed_Incremental();
-  if ((COLDATA_copy0 & 0x1f) != overworld_fixed_color_plusminus)
-    return;
-  submodule_index = 0;
-  subsubmodule_index = 0;
-}
-
-void Module07_0B_DrainSwampPool() {  // 82902d
-  static const int8 kTurnOffWater_Tab0[16] = { -1, -1, -1, 1, -1, -1, -1, 1, -1, -1, -1, 1, -1, -1, -1, 1 };
-  switch (subsubmodule_index) {
-  case 0: {
-    if (!(turn_on_off_water_ctr & 7)) {
-      int k = (turn_on_off_water_ctr >> 2) & 3;
-      if (water_hdma_var2 == water_hdma_var4) {
-        Dungeon_SetAttrForActivatedWaterOff();
-        return;
-      }
-      water_hdma_var2 += kTurnOffWater_Tab0[k];
-      water_hdma_var3 += kTurnOffWater_Tab0[k];
-    }
-    turn_on_off_water_ctr++;
-    AdjustWaterHDMAWindow();
-    break;
-  }
-  case 1: {
-    uint16 v = SrcPtr(0x1e0)[0];
-    for (int i = 0; i < 0x1000; i++)
-      dung_bg1[i] = v;
-    dung_cur_quadrant_upload = 0;
-    subsubmodule_index++;
-    break;
-  }
-  case 2: case 3: case 4: case 5:
-    Dungeon_FloodSwampWater_PrepTileMap();
-    break;
-  }
-}
-
-void Module07_0C_FloodSwampWater() {  // 82904a
-  int k;
-  static const int8 kTurnOnWater_Tab2[4] = { 1, 1, 1, -1 };
-  static const int8 kTurnOnWater_Tab1[4] = { 1, 2, 1, -1 };
-  static const int8 kTurnOnWater_Tab0[4] = { 1, -1, 1, -1 };
-
-  switch (subsubmodule_index) {
-  case 0: case 1: case 2: case 3:
-    Dungeon_FloodSwampWater_PrepTileMap();
-    break;
-  case 4: case 5: case 6: case 7: case 8:
-    if (!--turn_on_off_water_ctr) {
-      turn_on_off_water_ctr = 4;
-      int depth = ++subsubmodule_index - 4;
-      water_hdma_var3 = 8;
-      water_hdma_var5 = 0;
-      water_hdma_var2 = 0x30;
-      Dungeon_AdjustWaterVomit(SrcPtr(0x1654 + 0x10), depth);
-    }
-    break;
-  case 9:
-    W12SEL_copy = 3;
-    W34SEL_copy = 0;
-    WOBJSEL_copy = 0;
-    TMW_copy = 22;
-    TSW_copy = 1;
-    TS_copy = 1;
-    CGWSEL_copy = 2;
-    CGADSUB_copy = 98;
-    turn_on_off_water_ctr = 0;
-    subsubmodule_index++;
-    // fall through
-  case 10: {
-    k = (turn_on_off_water_ctr & 3);
-    uint16 r0 = 0x688 - BG2VOFS_copy2 - 0x24;
-    water_hdma_var3 += kTurnOnWater_Tab0[k];
-    water_hdma_var5 += kTurnOnWater_Tab1[k];
-    if (water_hdma_var5 >= r0) {
-      dung_hdr_bg2_properties = 7;
-      subsubmodule_index++;
-    }
-    turn_on_off_water_ctr++;
-    spotlight_y_lower = 0x688 - BG2VOFS_copy2 - water_hdma_var2;
-    spotlight_y_upper = spotlight_y_lower + water_hdma_var5;
-    AdjustWaterHDMAWindow_X(spotlight_y_upper);
-    break;
-  }
-  case 11: {
-    if (!(turn_on_off_water_ctr & 7)) {
-      k = (turn_on_off_water_ctr >> 2) & 3;
-      if (water_hdma_var2 == water_hdma_var4) {
-        Dungeon_SetAttrForActivatedWater();
-        return;
-      }
-      water_hdma_var2 += kTurnOnWater_Tab2[k];
-      water_hdma_var3 += kTurnOnWater_Tab2[k];
-
-      uint16 a = water_hdma_var4 - water_hdma_var2;
-      if (a == 0 || a == 8)
-        Dungeon_AdjustWaterVomit(SrcPtr(a == 0 ? 0x16b4 : 0x168c), 5);
-    }
-    turn_on_off_water_ctr++;
-    AdjustWaterHDMAWindow();
-    break;
-  }
-  }
-}
-
-void Module07_0D_FloodDam() {  // 82904f
-  FloodDam_PrepFloodHDMA();
-  kWatergateFuncs[subsubmodule_index]();
-}
-
-void Module07_0E_SpiralStairs() {  // 829054
-  if (subsubmodule_index >= 7) {
-    Graphics_IncrementalVRAMUpload();
-    Dungeon_LoadAttribute_Selectable();
-  }
-  HandleLinkOnSpiralStairs();
-  kDungeon_SpiralStaircase[subsubmodule_index]();
-}
-
-void Dungeon_DoubleApplyAndIncrementGrayscale() {  // 829094
-  ApplyPaletteFilter_bounce();
-  ApplyPaletteFilter_bounce();
-  ApplyGrayscaleFixed_Incremental();
-}
-
-void Module07_0E_02_ApplyFilterIf() {  // 8290a1
-  if (staircase_var1 < 9) {
-    ApplyPaletteFilter_bounce();
-    if (palette_filter_countdown)
-      ApplyPaletteFilter_bounce();
-  }
-  if (staircase_var1 != 0) {
-    staircase_var1--;
-    return;
-  }
-  tagalong_var5 = link_visibility_status = 12;
-}
-
-void Dungeon_SyncBackgroundsFromSpiralStairs() {  // 8290c7
-  if (follower_indicator == 6 && BYTE(dungeon_room_index) == 100)
-    follower_indicator = 0;
-  uint8 bak = link_is_on_lower_level;
-  link_y_coord += which_staircase_index & 4 ? 48 : -48;
-  link_is_on_lower_level = kTeleportPitLevel2[cur_staircase_plane];
-  SpiralStairs_MakeNearbyWallsHighPriority_Exiting();
-  link_is_on_lower_level = bak;
-  link_y_coord += which_staircase_index & 4 ? -48 : 48;
-  BG1HOFS_copy2 = BG2HOFS_copy2;
-  BG1VOFS_copy2 = BG2VOFS_copy2;
-  Dungeon_AdjustForRoomLayout();
-  uint8 ts = kSpiralTab1[dung_hdr_bg2_properties], tm = 0x16;
-  if (sign8(ts))
-    tm = 0x17, ts = 0;
-  if (dung_hdr_bg2_properties == 2)
-    ts = 3;
-  TM_copy = tm;
-  TS_copy = ts;
-  dung_cur_floor += (which_staircase_index & 4) ? -1 : 1;
-  staircase_var1 = 24;
-  Dungeon_PlayBlipAndCacheQuadrantVisits();
-  Hud_RestoreTorchBackground();
-  Dungeon_InterRoomTrans_notDarkRoom();
-}
-
-void Dungeon_AdvanceThenSetBossMusicUnorthodox() {  // 82915b
-  Dungeon_ResetTorchBackgroundAndPlayerInner();
-  staircase_var1 = 0x38;
-  subsubmodule_index++;
-  Dungeon_SetBossMusicUnorthodox();
-}
-
-void Dungeon_SetBossMusicUnorthodox() {  // 829165
-  uint8 x = 0x1c;
-  if (dungeon_room_index != 16) {
-    x = 0x15;
-    if (dungeon_room_index != 7) {
-      x = 0x11;
-      if (dungeon_room_index != 23 || ZeldaIsPlayingMusicTrack(17))
-        return;
-    }
-    if (music_unk1 != 0xf1 && (link_which_pendants & 1))
-      return;
-  }
-  music_control = x;
-}
-
-void Dungeon_SpiralStaircase17() {  // 82919b
-  SpiralStairs_FindLandingSpot();
-  if (!--staircase_var1) {
-    staircase_var1 = which_staircase_index & 4 ? 10 : 24;
-    subsubmodule_index++;
-  }
-}
-
-void Dungeon_SpiralStaircase18() {  // 8291b5
-  SpiralStairs_FindLandingSpot();
-  if (!--staircase_var1) {
-    subsubmodule_index++;
-    overworld_map_state = 0;
-  }
-}
-
-void Module07_0E_00_InitPriorityAndScreens() {  // 8291c4
-  SpiralStairs_MakeNearbyWallsHighPriority_Entering();
-  if (link_is_on_lower_level) {
-    TM_copy &= 0xf;
-    TS_copy |= 0x10;
-    link_is_on_lower_level = 3;
-  }
-  subsubmodule_index++;
-}
-
-void Module07_0E_13_SetRoomAndLayerAndCache() {  // 8291dd
-  link_is_on_lower_level_mirror = kTeleportPitLevel1[cur_staircase_plane];
-  link_is_on_lower_level = kTeleportPitLevel2[cur_staircase_plane];
-  TM_copy |= 0x10;
-  TS_copy &= 0xf;
-  if (!(which_staircase_index & 4))
-    SpiralStairs_MakeNearbyWallsLowPriority();
-  BYTE(dungeon_room_index2) = BYTE(dungeon_room_index);
-  ResetThenCacheRoomEntryProperties();
-}
-
-void RepositionLinkAfterSpiralStairs() {  // 82921a
-  link_visibility_status = 0;
-  tagalong_var5 = 0;
-
-  int i = (cur_staircase_plane == 0 && byte_7E0492 != 0) ? 1 : 0;
-  i += (which_staircase_index & 4) ? 2 : 0;
-
-  link_x_coord += kSpiralStaircaseX[i];
-  link_y_coord += kSpiralStaircaseY[i];
-
-  if (TM_copy & 0x10) {
-    if (cur_staircase_plane == 2) {
-      link_is_on_lower_level = 3;
-      TM_copy &= 0xf;
-      TS_copy |= 0x10;
-      if (byte_7E0492 != 2)
-        link_y_coord += 24;
-    }
-    Follower_Initialize();
-  } else {
-    if (cur_staircase_plane != 2) {
-      TM_copy |= 0x10;
-      TS_copy &= 0xf;
-      if (byte_7E0492 != 2)
-        link_y_coord -= 24;
-    }
-    Follower_Initialize();
-  }
-}
-
-void SpiralStairs_MakeNearbyWallsHighPriority_Exiting() {  // 8292b1
-  if (which_staircase_index & 4)
-    return;
-  int lf = (word_7E048C + 8) & 0x7f;
-  int x = 0, p;
-  while ((((p = dung_inter_starcases[x]) * 2) & 0x7f) != lf)
-    x++;
-  p -= 4;
-  word_7E048C = p * 2;
-  uint16 *dst = &dung_bg2[p];
-  for (int i = 0; i < 5; i++) {
-    dst[XY(0, 0)] |= 0x2000;
-    dst[XY(0, 1)] |= 0x2000;
-    dst[XY(0, 2)] |= 0x2000;
-    dst[XY(0, 3)] |= 0x2000;
-    dst += 1;
-  }
-}
-
-void Module07_0F_LandingWipe() {  // 82931d
-  kDungeon_Submodule_F[subsubmodule_index]();
-  Link_HandleMovingAnimation_FullLongEntry();
-  LinkOam_Main();
-}
-
-void Module07_0F_00_InitSpotlight() {  // 82932d
-  Spotlight_open();
-  subsubmodule_index++;
-}
-
-void Module07_0F_01_OperateSpotlight() {  // 829334
-  Sprite_Main();
-  IrisSpotlight_ConfigureTable();
-  if (!submodule_index) {
-    W12SEL_copy = 0;
-    W34SEL_copy = 0;
-    WOBJSEL_copy = 0;
-    TMW_copy = 0;
-    TSW_copy = 0;
-    subsubmodule_index = 0;
-    if (queued_music_control != 0xff)
-      music_control = queued_music_control;
-  }
-}
-
-// This is used for straight inter room stairs for example stairs to throne room in first dung
-void Module07_11_StraightInterroomStairs() {  // 829357
-  if (subsubmodule_index >= 3)
-    Dungeon_LoadAttribute_Selectable();
-  if (subsubmodule_index >= 13)
-    Graphics_IncrementalVRAMUpload();
-  if (staircase_var1) {
-    if (staircase_var1-- == 16)
-      link_speed_modifier = 2;
-    link_direction = (submodule_index == 18) ? 8 : 4;
-    Link_HandleVelocity();
-  }
-  Link_HandleMovingAnimation_FullLongEntry();
-  kDungeon_StraightStairs[subsubmodule_index]();
-}
-
-void Module07_11_00_PrepAndReset() {  // 8293bb
-  if (link_is_running) {
-    link_is_running = 0;
-    link_speed_setting = 2;
-  }
-  sound_effect_1 = (which_staircase_index & 4) ? 24 : 22;
-  if (dungeon_room_index == 48 || dungeon_room_index == 64)
-    music_control = 0xf1;
-  ResetTransitionPropsAndAdvance_ResetInterface();
-}
-
-void Module07_11_01_FadeOut() {  // 8293ed
-  if (staircase_var1 < 9) {
-    ApplyPaletteFilter_bounce();
-    if (BYTE(palette_filter_countdown) == 23)
-      subsubmodule_index++;
-  }
-}
-
-void Module07_11_02_LoadAndPrepRoom() {  // 829403
-  ApplyPaletteFilter_bounce();
-  Dungeon_LoadRoom();
-  Dungeon_RestoreStarTileChr();
-  LoadTransAuxGFX();
-  Dungeon_LoadCustomTileAttr();
-  Dungeon_AdjustForRoomLayout();
-  Follower_Initialize();
-  subsubmodule_index++;
-}
-
-void Module07_11_03_FilterAndLoadBGChars() {  // 829422
-  ApplyPaletteFilter_bounce();
-  DungeonTransition_TriggerBGC34UpdateAndAdvance();
-}
-
-void Module07_11_04_FilterDoBGAndResetSprites() {  // 82942a
-  ApplyPaletteFilter_bounce();
-  DungeonTransition_TriggerBGC56UpdateAndAdvance();
-  BYTE(dungeon_room_index2) = BYTE(dungeon_room_index);
-  Dungeon_ResetSprites();
-}
-
-void Module07_11_0B_PrepDestination() {  // 82943b
-  uint8 ts = kSpiralTab1[dung_hdr_bg2_properties], tm = 0x16;
-  if (sign8(ts))
-    tm = 0x17, ts = 0;
-  TM_copy = tm;
-  TS_copy = ts;
-
-  link_speed_modifier = 1;
-  dung_cur_floor += (which_staircase_index & 4) ? -1 : 1;
-  staircase_var1 = (which_staircase_index & 4) ? 0x32 : 0x3c;
-  sound_effect_1 = (which_staircase_index & 4) ? 25 : 23;
-
-  uint8 r0 = 0;
-  if (link_is_on_lower_level) {
-    link_y_coord += (submodule_index == 18) ? -32 : 32;
-    r0++;
-  }
-  link_is_on_lower_level_mirror = kTeleportPitLevel1[cur_staircase_plane];
-  link_is_on_lower_level = kTeleportPitLevel2[cur_staircase_plane];
-  if (link_is_on_lower_level) {
-    link_y_coord += (submodule_index == 18) ? -32 : 32;
-    r0++;
-  }
-
-  if (!r0) {
-    if (submodule_index == 18) {
-      link_y_coord += (which_staircase_index & 4) ? -24 : -8;
-    } else {
-      link_y_coord += 12;
-    }
-  }
-
-  Dungeon_PlayBlipAndCacheQuadrantVisits();
-  Hud_RestoreTorchBackground();
-  Dungeon_InterRoomTrans_notDarkRoom();
-}
-
-void Module07_11_09_LoadSpriteGraphics() {  // 8294e0
-  ApplyPaletteFilter_bounce();
-  subsubmodule_index--;
-  LoadNewSpriteGFXSet();
-  Dungeon_HandleTranslucencyAndPalette();
-}
-
-void Module07_11_19_SetSongAndFilter() {  // 8294ed
-  if (overworld_map_state == 5 && !BYTE(darkening_or_lightening_screen)) {
-    subsubmodule_index++;
-    if (dungeon_room_index == 48)
-      music_control = 0x1c;
-    else if (dungeon_room_index == 64)
-      music_control = 0x10;
-  }
-  ApplyGrayscaleFixed_Incremental();
-}
-
-void Module07_11_11_KeepSliding() {  // 829518
-  if (staircase_var1 == 0)
-    subsubmodule_index++;
-  else
-    ApplyGrayscaleFixed_Incremental();
-}
-
-void Module07_14_RecoverFromFall() {  // 829520
-  switch (subsubmodule_index) {
-  case 0:
-    Module07_14_00_ScrollCamera();
-    break;
-  case 1:
-    RecoverPositionAfterDrowning();
-    break;
-  }
-}
-
-void Module07_14_00_ScrollCamera() {  // 82952a
-  for (int i = 0; i < 2; i++) {
-    if (BG2HOFS_copy2 != BG2HOFS_copy2_cached)
-      BG2HOFS_copy2 += BG2HOFS_copy2 < BG2HOFS_copy2_cached ? 1 : -1;
-    if (BG2VOFS_copy2 != BG2VOFS_copy2_cached)
-      BG2VOFS_copy2 += BG2VOFS_copy2 < BG2VOFS_copy2_cached ? 1 : -1;
-  }
-  if (BG2HOFS_copy2 == BG2HOFS_copy2_cached && BG2VOFS_copy2 == BG2VOFS_copy2_cached)
-    subsubmodule_index++;
-  if (!hdr_dungeon_dark_with_lantern)
-    MirrorBg1Bg2Offs();
-}
-
-void Module07_15_WarpPad() {  // 82967a
-  if (subsubmodule_index >= 3) {
-    Graphics_IncrementalVRAMUpload();
-    Dungeon_LoadAttribute_Selectable();
-  }
-  kDungeon_Teleport[subsubmodule_index]();
-}
-
-void Module07_15_01_ApplyMosaicAndFilter() {  // 8296ac
-  ConditionalMosaicControl();
-  MOSAIC_copy = mosaic_level | 3;
-  ApplyPaletteFilter_bounce();
-}
-
-void Module07_15_04_SyncRoomPropsAndBuildOverlay() {  // 8296ba
-  ApplyGrayscaleFixed_Incremental();
-  if (dungeon_room_index == 0x17)
-    dung_cur_floor = 4;
-  MirrorBg1Bg2Offs();
-  Dungeon_AdjustForRoomLayout();
-  uint8 ts = kSpiralTab1[dung_hdr_bg2_properties], tm = 0x16;
-  if (sign8(ts))
-    tm = 0x17, ts = 0;
-  TM_copy = tm;
-  TS_copy = ts;
-  WaterFlood_BuildOneQuadrantForVRAM();
-  subsubmodule_index++;
-}
-
-void Module07_15_0E_FadeInFromWarp() {  // 8296ec
-  if (palette_filter_countdown & 1 && mosaic_level != 0)
-    mosaic_level -= 0x10;
-  BGMODE_copy = 9;
-  MOSAIC_copy = mosaic_level | 3;
-  ApplyPaletteFilter_bounce();
-}
-
-void Module07_15_0F_FinalizeAndCacheEntry() {  // 82970f
-  if (overworld_map_state == 5) {
-    SetAndSaveVisitedQuadrantFlags();
-    submodule_index = 0;
-    ResetThenCacheRoomEntryProperties();
-  }
-}
-
-void Module07_16_UpdatePegs() {  // 82972a
-  if (++subsubmodule_index & 3)
-    return;
-  switch (subsubmodule_index >> 2) {
-  case 0:
-  case 1: Module07_16_UpdatePegs_Step1(); break;
-  case 2: Module07_16_UpdatePegs_Step2(); break;
-  case 3: RecoverPegGFXFromMapping(); break;
-  case 4:
-    Dungeon_FlipCrystalPegAttribute();
-    subsubmodule_index = 0;
-    submodule_index = 0;
-    break;
-  }
-}
-
-void Module07_17_PressurePlate() {  // 8297c8
-  if (--subsubmodule_index)
-    return;
-  link_y_coord -= 2;
-  Dungeon_UpdateTileMapWithCommonTile((word_7E04B6 & 0x3f) << 3, (word_7E04B6 >> 3) & 0x1f8, 0xe);
-  submodule_index = saved_module_for_menu;
-}
-
-void Module07_18_RescuedMaiden() {  // 82980a
-  switch (subsubmodule_index) {
-  case 0:
-    PaletteFilter_RestoreBGSubstractiveStrict();
-    main_palette_buffer[0] = main_palette_buffer[32];
-    if (BYTE(darkening_or_lightening_screen) != 255)
-      return;
-    for (int i = 0; i < 0x1000; i++)
-      dung_bg2[i] = dung_bg1[i] = 0x1ec;
-    bg1_y_offset = 0;
-    bg1_x_offset = 0;
-    dung_floor_x_offs = 0;
-    dung_floor_y_offs = 0;
-    overworld_screen_transition = 0;
-    dung_cur_quadrant_upload = 0;
-    subsubmodule_index++;
-    break;
-  case 1: {
-    static const uint16 kCrystal_Tab0[7] = { 0x1618, 0x1658, 0x1658, 0x1618, 0x658, 0x1618, 0x1658 };
-    PaletteFilter_Crystal();
-    TS_copy = 1;
-    flag_is_link_immobilized = 2;
-    int j = FindInWordArray(kBossRooms, dungeon_room_index, countof(kBossRooms)) - 4;
-    uint16 *dst = &dung_bg1[kCrystal_Tab0[j] >> 1];
-    for (int n = 0, t = 0; n != 4; n++) {
-      for (int i = 0; i != 8; i++, t++) {
-        dst[i + XY(0, 0)] = 0x1f80 | t;
-        dst[i + XY(0, 4)] = 0x1f88 | t;
-      }
-      t += 8, dst += XY(0, 1);
-    }
-    subsubmodule_index++;
-    break;
-  }
-  case 2: case 4: case 6: case 8:
-    Dungeon_InterRoomTrans_notDarkRoom();
-    break;
-  case 3: case 5: case 7: case 9:
-    Dungeon_InterRoomTrans_State4();
-    break;
-  case 10:
-    is_nmi_thread_active++;
-    Polyhedral_InitializeThread();
-    CrystalCutscene_Initialize();
-    submodule_index = 0;
-    subsubmodule_index = 0;
-    break;
-  }
-}
-
-void Module07_19_MirrorFade() {  // 8298f7
-  // When using mirror
-  Overworld_ResetMosaic_alwaysIncrease();
-  if (!--INIDISP_copy) {
-    main_module_index = 5;
-    submodule_index = 0;
-    nmi_load_bg_from_vram = 0;
-    last_music_control = music_unk1;
-    if (palette_swap_flag)
-      Palette_RevertTranslucencySwap();
-  }
-}
-
-void Module07_1A_RoomDraw_OpenTriforceDoor_bounce() {  // 829916
-  static const uint16 kOpenGanonDoor_Tab[4] = { 0x2556, 0x2596, 0x25d6, 0x2616 };
-
-  flag_is_link_immobilized = 1;
-  if (R16 != 0) {
-    if (--BYTE(R16) || --HIBYTE(R16))
-      return;
-    sound_effect_ambient = 21;
-    link_force_hold_sword_up = 0;
-    link_cant_change_direction = 0;
-  }
-  flag_is_link_immobilized = 0;
-  if (++subsubmodule_index & 3)
-    return;
-
-  const uint16 *src = SrcPtr(kOpenGanonDoor_Tab[(subsubmodule_index - 4) >> 2]);
-  uint16 *dst = &dung_bg2[0];
-  for (int i = 0; i < 8; i++) {
-    dst[XY(44, 3)] = src[0];
-    dst[XY(44, 4)] = src[1];
-    dst[XY(44, 5)] = src[2];
-    dst[XY(44, 6)] = src[3];
-    dst += XY(1, 0), src += 4;
-  }
-
-  Dungeon_PrepOverlayDma_watergate(0, 0x1d8, 0x881, 8);
-  if (subsubmodule_index == 16) {
-    WriteAttr2(XY(44, 5), 0x202);
-    WriteAttr2(XY(44, 6), 0x202);
-    WriteAttr2(XY(50, 5), 0x200);
-    WriteAttr2(XY(50, 6), 0x200);
-    for (int i = 0; i != 6; i += 2) {
-      WriteAttr2(XY(45 + i, 0), 0x0);
-      WriteAttr2(XY(45 + i, 1), 0x0);
-      WriteAttr2(XY(45 + i, 2), 0x0);
-      WriteAttr2(XY(45 + i, 3), 0x0);
-      WriteAttr2(XY(45 + i, 4), 0x0);
-      WriteAttr2(XY(45 + i, 5), 0x0);
-      WriteAttr2(XY(45 + i, 6), 0x0);
-    }
-    room_bounds_y.a0 = -64;
-    submodule_index = 0;
-    subsubmodule_index = 0;
-  }
-  nmi_copy_packets_flag = 1;
-}
-
-void Module11_DungeonFallingEntrance() {  // 829af9
-  switch (subsubmodule_index) {
-  case 0:  // Module_11_00_SetSongAndInit
-    if (kEntranceData_musicTrack[which_entrance] != 3 || sram_progress_indicator >= 2)
-      music_control = 0xf1;
-    ResetTransitionPropsAndAdvance_ResetInterface();
-    break;
-  case 1:
-    if (!(frame_counter & 1))
-      ApplyPaletteFilter_bounce();
-    break;
-  case 2:
-    Module11_02_LoadEntrance();
-    break;
-  case 3:
-    DungeonTransition_LoadSpriteGFX();
-    break;
-  case 4:
-    INIDISP_copy = (INIDISP_copy + 1) & 0xf;
-    if (INIDISP_copy == 15)
-      subsubmodule_index++;
-  case 5:
-    HandleDungeonLandingFromPit();
-    if (submodule_index)
-      return;
-    main_module_index = 7;
-    flag_skip_call_tag_routines++;
-    Dungeon_PlayBlipAndCacheQuadrantVisits();
-    ResetThenCacheRoomEntryProperties();
-    music_control = queued_music_control;
-    last_music_control = music_unk1;
-    break;
-  }
-}
-
-void Module11_02_LoadEntrance() {  // 829b1c
-  EnableForceBlank();
-  CGWSEL_copy = 2;
-  Dungeon_LoadEntrance();
-
-  uint8 dung = BYTE(cur_palace_index_x2);
-  link_num_keys = (dung != 255) ? link_keys_earned_per_dungeon[((dung == 2) ? 0 : dung) >> 1] : 255;
-  Hud_Rebuild();
-  link_this_controls_sprite_oam = 4;
-  player_near_pit_state = 3;
-  link_visibility_status = 12;
-  link_speed_modifier = 16;
-
-  uint8 y = link_y_coord - BG2VOFS_copy2;
-  link_state_bits = 0;
-  link_picking_throw_state = 0;
-  some_animation_timer = 0;
-  dungeon_room_index_prev = dungeon_room_index;
-  tiledetect_which_y_pos[0] = link_y_coord;
-  link_y_coord -= y + 16;
-
-  uint8 bak = subsubmodule_index;
-  dung_num_lit_torches = 0;
-  hdr_dungeon_dark_with_lantern = 0;
-  Dungeon_LoadAndDrawRoom();
-  Dungeon_LoadCustomTileAttr();
-  DecompressAnimatedDungeonTiles(kDungAnimatedTiles[main_tile_theme_index]);
-  Dungeon_LoadAttributeTable();
-  subsubmodule_index = bak + 1;
-  misc_sprites_graphics_index = 10;
-  InitializeTilesets();
-  palette_sp6r_indoors = 10;
-  Dungeon_LoadPalettes();
-  Hud_RestoreTorchBackground();
-  button_mask_b_y = 0;
-  button_b_frames = 0;
-  Dungeon_ResetTorchBackgroundAndPlayer();
-  if (link_is_bunny_mirror)
-    LoadGearPalettes_bunny();
-  HDMAEN_copy = 0x80;
-  Hud_RefillLogic();
-  Module_PreDungeon_setAmbientSfx();
-  submodule_index = 7;
-  Dungeon_LoadSongBankIfNeeded();
-}
-
-void Dungeon_LoadSongBankIfNeeded() {  // 829bd7
-  if (queued_music_control == 0xff || queued_music_control == 0xf2)
-    return;
-
-  if (queued_music_control == 3 || queued_music_control == 7 || queued_music_control == 14) {
-    LoadOWMusicIfNeeded();
-  } else {
-    if (flag_which_music_type)
-      return;
-    flag_which_music_type = 1;
-    LoadDungeonSongs();
-  }
-}
-
-void Mirror_SaveRoomData() {  // 82a1b1
-  if (cur_palace_index_x2 == 0xff) {
-    sound_effect_1 = 60;
-    return;
-  }
-  submodule_index = 25;
-  subsubmodule_index = 0;
-  sound_effect_1 = 51;
-  Dungeon_FlagRoomData_Quadrants();
-  SaveDungeonKeys();
-}
-
-void SaveDungeonKeys() {  // 82a1c7
-  uint8 idx = cur_palace_index_x2;
-  if (idx == 0xff)
-    return;
-  if (idx == 2)
-    idx = 0;
-  link_keys_earned_per_dungeon[idx >> 1] = link_num_keys;
-}
-
-void Dungeon_AdjustAfterSpiralStairs() {  // 82a2f0
-  int xd = ((dungeon_room_index & 0xf) - (dungeon_room_index_prev & 0xf)) * 0x200;
-  link_x_coord += xd;
-  BG2HOFS_copy2 += xd;
-  room_bounds_x.a1 += xd;
-  room_bounds_x.b1 += xd;
-  room_bounds_x.a0 += xd;
-  room_bounds_x.b0 += xd;
-
-  int yd = (((dungeon_room_index & 0xf0) >> 4) - ((dungeon_room_index_prev & 0xf0) >> 4)) * 0x200;
-  link_y_coord += yd;
-  BG2VOFS_copy2 += yd;
-  room_bounds_y.a1 += yd;
-  room_bounds_y.b1 += yd;
-  room_bounds_y.a0 += yd;
-  room_bounds_y.b0 += yd;
-}
-
-void Dungeon_AdjustForTeleportDoors(uint8 room, uint8 flag) {  // 82a37c
-  dungeon_room_index2 = room;
-  dungeon_room_index_prev = room;
-
-  uint16 xx = (room & 0xf) * 2 - (link_x_coord >> 8) + flag;
-  link_x_coord += (xx << 8);
-  BG2HOFS_copy2 += (xx << 8);
-  room_bounds_x.a1 += (xx << 8);
-  room_bounds_x.b1 += (xx << 8);
-  room_bounds_x.a0 += (xx << 8);
-  room_bounds_x.b0 += (xx << 8);
-
-  xx = ((room & 0xf0) >> 3) - (link_y_coord >> 8);
-  link_y_coord += (xx << 8);
-  BG2VOFS_copy2 += (xx << 8);
-  room_bounds_y.a1 += (xx << 8);
-  room_bounds_y.b1 += (xx << 8);
-  room_bounds_y.a0 += (xx << 8);
-  room_bounds_y.b0 += (xx << 8);
-
-  for (int i = 0; i < 20; i++)
-    tagalong_y_hi[i] = link_y_coord >> 8;
-}
-
-void Dungeon_AdjustForRoomLayout() {  // 82b5dc
-  Dungeon_AdjustQuadrant();
-  quadrant_fullsize_x = (dung_blastwall_flag_x || (kLayoutQuadrantFlags[composite_of_layout_and_quadrant] & (link_quadrant_x ? 2 : 1)) == 0) ? 2 : 0;
-  quadrant_fullsize_y = (dung_blastwall_flag_y || (kLayoutQuadrantFlags[composite_of_layout_and_quadrant] & (link_quadrant_y ? 8 : 4)) == 0) ? 2 : 0;
-  if ((uint8)dung_unk2)
-    quadrant_fullsize_x = (uint8)dung_unk2;
-  if ((uint8)(dung_unk2 >> 8))
-    quadrant_fullsize_y = (uint8)(dung_unk2 >> 8);
-}
-
-void HandleEdgeTransitionMovementEast_RightBy8() {  // 82b62e
-  link_x_coord += 8;
-  Dungeon_StartInterRoomTrans_Right();
-}
-
-void Dungeon_StartInterRoomTrans_Right() {  // 82b63a
-  assert(submodule_index == 0);
-  link_quadrant_x ^= 1;
-  Dungeon_AdjustQuadrant();
-  RoomBounds_AddA(&room_bounds_x);
-  Dung_SaveDataForCurrentRoom();
-  DungeonTransition_AdjustCamera_X(link_quadrant_x);
-  HandleEdgeTransition_AdjustCameraBoundaries(2);
-  submodule_index = 1;
-  if (!link_quadrant_x) {
-    RoomBounds_AddB(&room_bounds_x);
-    BYTE(dungeon_room_index_prev) = dungeon_room_index;
-    if ((link_tile_below & 0xcf) == 0x89) {
-      dungeon_room_index = dung_hdr_travel_destinations[4];
-      Dungeon_AdjustForTeleportDoors(dungeon_room_index - 1, 1);
-    } else {
-      if ((uint8)dungeon_room_index != (uint8)dungeon_room_index2) {
-        BYTE(dungeon_room_index_prev) = dungeon_room_index2;
-        Dungeon_AdjustAfterSpiralStairs();
-      }
-      dungeon_room_index += 1;
-    }
-    submodule_index = 2;
-    if (room_transitioning_flags & 1) {
-      link_is_on_lower_level ^= 1;
-      link_is_on_lower_level_mirror = link_is_on_lower_level;
-    }
-    if (room_transitioning_flags & 2) {
-      cur_palace_index_x2 ^= 2;
-    }
-  }
-  room_transitioning_flags = 0;
-  quadrant_fullsize_y = (dung_blastwall_flag_y || (kLayoutQuadrantFlags[composite_of_layout_and_quadrant] & (link_quadrant_y ? 8 : 4)) == 0) ? 2 : 0;
-}
-
-void HandleEdgeTransitionMovementSouth_DownBy16() {  // 82b76e
-  link_y_coord += 16;
-  Dungeon_StartInterRoomTrans_Down();
-}
-
-void Dung_HandleExitToOverworld() {  // 82b7ae
-  SaveDungeonKeys();
-  SaveQuadrantsToSram();
-  saved_module_for_menu = 8;
-  main_module_index = 15;
-  submodule_index = 0;
-  subsubmodule_index = 0;
-  Dungeon_ResetTorchBackgroundAndPlayerInner();
-}
-
-void AdjustQuadrantAndCamera_right() {  // 82b8bd
-  link_quadrant_x ^= 1;
-  Dungeon_AdjustQuadrant();
-  RoomBounds_AddA(&room_bounds_x);
-  SetAndSaveVisitedQuadrantFlags();
-}
-
-void SetAndSaveVisitedQuadrantFlags() {  // 82b8cb
-  dung_quadrants_visited |= kQuadrantVisitingFlags[(quadrant_fullsize_y << 2) + (quadrant_fullsize_x << 1) + link_quadrant_y + link_quadrant_x];
-  save_dung_info[dungeon_room_index] |= dung_quadrants_visited;
-}
-
-void SaveQuadrantsToSram() {  // 82b8e5
-  save_dung_info[dungeon_room_index] |= dung_quadrants_visited;
-}
-
-void AdjustQuadrantAndCamera_left() {  // 82b8f9
-  link_quadrant_x ^= 1;
-  Dungeon_AdjustQuadrant();
-  RoomBounds_SubA(&room_bounds_x);
-  SetAndSaveVisitedQuadrantFlags();
-}
-
-void AdjustQuadrantAndCamera_down() {  // 82b909
-  link_quadrant_y ^= 2;
-  Dungeon_AdjustQuadrant();
-  RoomBounds_AddA(&room_bounds_y);
-  SetAndSaveVisitedQuadrantFlags();
-}
-
-void AdjustQuadrantAndCamera_up() {  // 82b919
-  link_quadrant_y ^= 2;
-  Dungeon_AdjustQuadrant();
-  RoomBounds_SubA(&room_bounds_y);
-  SetAndSaveVisitedQuadrantFlags();
-}
-
-void Dungeon_FlagRoomData_Quadrants() {  // 82b929
-  dung_quadrants_visited |= kQuadrantVisitingFlags[(quadrant_fullsize_y << 2) + (quadrant_fullsize_x << 1) + link_quadrant_y + link_quadrant_x];
-  Dung_SaveDataForCurrentRoom();
-}
-
-void Dung_SaveDataForCurrentRoom() {  // 82b947
-  save_dung_info[dungeon_room_index] =
-    (dung_savegame_state_bits >> 4) |
-    (dung_door_opened & 0xf000) |
-    dung_quadrants_visited;
-}
-
-void HandleEdgeTransition_AdjustCameraBoundaries(uint8 arg) {  // 82b9dc
-  static const uint16 kCameraBoundsX[] = { 127, 383, 127, 383 };
-  static const uint16 kCameraBoundsY[] = { 120, 376, 136, 392 };
-  overworld_screen_transition = arg;
-  if (link_direction & 3) {
-    uint8 t = link_direction & 1 ? 0 : 2;
-    if (link_quadrant_x) t += 1;
-    camera_x_coord_scroll_low = kCameraBoundsX[t];
-    camera_x_coord_scroll_hi = camera_x_coord_scroll_low + 2;
-  } else {
-    uint8 t = link_direction & 4 ? 0 : 2;
-    if (link_quadrant_y) t += 1;
-    camera_y_coord_scroll_low = kCameraBoundsY[t];
-    camera_y_coord_scroll_hi = camera_y_coord_scroll_low + 2;
-  }
-}
-
-void Dungeon_AdjustQuadrant() {  // 82ba27
-  composite_of_layout_and_quadrant = dung_layout_and_starting_quadrant | link_quadrant_y | link_quadrant_x;
-}
-
-void Dungeon_HandleCamera() {  // 82ba31
-  if (link_y_vel) {
-    int z = (allow_scroll_z && link_z_coord != 0xffff) ? link_z_coord : 0;
-    int y = ((link_y_coord - z) & 0x1ff) + 12;
-    int scrollamt = 1;
-    int y_vel_abs = sign8(link_y_vel) ? (scrollamt = -1, -(int8)link_y_vel) : link_y_vel;
-    do {
-      int qm = quadrant_fullsize_y >> 1;
-      if (sign8(link_y_vel)) {
-        if (y > camera_y_coord_scroll_low)
-          continue;
-      } else {
-        if (y < camera_y_coord_scroll_hi)
-          continue;
-        qm += 2;
-      }
-      if (BG2VOFS_copy2 == room_bounds_y.v[qm])
-        continue;
-      BG2VOFS_copy2 += scrollamt;
-      if (dungeon_room_index == 0xffff)
-        continue;
-
-      BG1VOFS_subpixel += 0x8000;
-      BG1VOFS_copy2 += (scrollamt >> 1) + ((BG1VOFS_subpixel & 0x8000) == 0);
-      camera_y_coord_scroll_low += scrollamt;
-      camera_y_coord_scroll_hi = camera_y_coord_scroll_low + 2;
-    } while (--y_vel_abs);
-  }
-  if (link_x_vel) {
-    int x = (link_x_coord & 0x1ff) + 8;
-    int scrollamt = 1;
-    int x_vel_abs = sign8(link_x_vel) ? (scrollamt = -1, -(int8)link_x_vel) : link_x_vel;
-    do {
-      int qm = quadrant_fullsize_x >> 1;
-      if (sign8(link_x_vel)) {
-        if (x > camera_x_coord_scroll_low)
-          continue;
-      } else {
-        if (x < camera_x_coord_scroll_hi)
-          continue;
-        qm += 2;
-      }
-      if (BG2HOFS_copy2 == room_bounds_x.v[qm])
-        continue;
-      BG2HOFS_copy2 += scrollamt;
-      if (dungeon_room_index == 0xffff)
-        continue;
-      BG1HOFS_subpixel += 0x8000;
-      BG1HOFS_copy2 += (scrollamt >> 1) + ((BG1HOFS_subpixel & 0x8000) == 0);
-      camera_x_coord_scroll_low += scrollamt;
-      camera_x_coord_scroll_hi = camera_x_coord_scroll_low + 2;
-    } while (--x_vel_abs);
-  }
-  if (dungeon_room_index != 0xffff) {
-    if (dung_hdr_bg2_properties == 0 || dung_hdr_bg2_properties == 2 || dung_hdr_bg2_properties == 3 || dung_hdr_bg2_properties == 4 || dung_hdr_bg2_properties >= 6) {
-      BG1HOFS_copy2 = BG2HOFS_copy2;
-      BG1VOFS_copy2 = BG2VOFS_copy2;
-    }
-  }
-}
-
-void MirrorBg1Bg2Offs() {  // 82bb7b
-  BG1HOFS_copy2 = BG2HOFS_copy2;
-  BG1VOFS_copy2 = BG2VOFS_copy2;
-}
-
-void DungeonTransition_AdjustCamera_X(uint8 arg) {  // 82bdc8
-  static const uint16 kUpDownScroll[4] = { 0, 256, 256, 0 };
-  left_right_scroll_target = kUpDownScroll[arg * 2];
-  left_right_scroll_target_end = kUpDownScroll[arg * 2 + 1];
-}
-
-void DungeonTransition_AdjustCamera_Y(uint8 arg) {  // 82bde2
-  static const uint16 kUpDownScroll[4] = { 0, 272, 256, 16 };
-  up_down_scroll_target = kUpDownScroll[arg];
-  up_down_scroll_target_end = kUpDownScroll[arg + 1];
-}
-
-void DungeonTransition_ScrollRoom() {  // 82be03
-  transition_counter++;
-  int i = overworld_screen_transition;
-  bg1_y_offset = bg1_x_offset = 0;
-  uint16 t;
-
-  if (i >= 2) {
-    t = BG1HOFS_copy2 = BG2HOFS_copy2 = (BG2HOFS_copy2 + kStaircaseTab3[i]) & ~1;
-    if (transition_counter >= kStaircaseTab4[i])
-      link_x_coord += kStaircaseTab3[i];
-  } else {
-    t = BG1VOFS_copy2 = BG2VOFS_copy2 = (BG2VOFS_copy2 + kStaircaseTab3[i]) & ~1;
-    if (transition_counter >= kStaircaseTab4[i])
-      link_y_coord += kStaircaseTab3[i];
-  }
-
-  if ((t & 0x1fc) == (&up_down_scroll_target)[i]) {
-    SetAndSaveVisitedQuadrantFlags();
-    subsubmodule_index++;
-    transition_counter = 0;
-    if (submodule_index == 2)
-      WaterFlood_BuildOneQuadrantForVRAM();
-  }
-
-}
-
-void Module07_11_0A_ScrollCamera() {  // 82be75
-  link_visibility_status = tagalong_var5 = 12;
-  int i = overworld_screen_transition;
-  BG1VOFS_copy2 = BG2VOFS_copy2 = (BG2VOFS_copy2 + kStaircaseTab3[i]) & ~3;
-  if ((BG1VOFS_copy2 & 0x1fc) == (&up_down_scroll_target)[i]) {
-    if (submodule_index >= 18)
-      i += 2;
-    link_y_coord += kStaircaseTab5[i];
-    link_visibility_status = tagalong_var5 = 0;
-    subsubmodule_index++;
-  }
-}
-
-void DungeonTransition_FindSubtileLanding() {  // 82c110
-  Dungeon_ResetTorchBackgroundAndPlayerInner();
-  SubtileTransitionCalculateLanding();
-  subsubmodule_index++;
-  save_dung_info[dungeon_room_index] |= dung_quadrants_visited;
-}
-
-void SubtileTransitionCalculateLanding() {  // 82c12c
-  int st = overworld_screen_transition;
-  int a = CalculateTransitionLanding();
-  if (a == 2)
-    a = 1;
-  else if (a == 4)
-    a = 2;
-  a += overworld_screen_transition * 5;
-
-  int8 v = kStaircaseTab2[a];
-  v -= (v < 0) ? -8 : 8;
-  if (st & 2)
-    BYTE(link_x_coord) = v;
-  else
-    BYTE(link_y_coord) = v;
-  link_visibility_status = 0;
-}
-
-void Dungeon_InterRoomTrans_State13() {  // 82c162
-  if (dung_want_lights_out | dung_want_lights_out_copy)
-    ApplyPaletteFilter_bounce();
-  Dungeon_IntraRoomTrans_State5();
-}
-
-void Dungeon_IntraRoomTrans_State5() {  // 82c170
-  Link_HandleMovingAnimation_FullLongEntry();
-  if (!DungeonTransition_MoveLinkOutDoor())
-    return;
-  if (byte_7E004E == 2 || byte_7E004E == 4)
-    is_standing_in_doorway = 0;
-  // todo: write to tiledetect_diag_state
-  BYTE(force_move_any_direction) = 0;
-  byte_7E004E = 0;
-  overworld_screen_transition = 0;
-  subsubmodule_index++;
-}
-
-bool DungeonTransition_MoveLinkOutDoor() {  // 82c191
-  uint8 x = kStaircaseTab2[byte_7E004E + overworld_screen_transition * 5];
-  int r0 = overworld_screen_transition & 1 ? -2 : 2;
-  if ((overworld_screen_transition & 2) == 0) {
-    link_y_coord += r0;
-    return (BYTE(link_y_coord) & 0xfe) == x;
-  } else {
-    link_x_coord += r0;
-    return (BYTE(link_x_coord) & 0xfe) == x;
-  }
-}
-
-uint8 CalculateTransitionLanding() {  // 82c1e5
-  int pos = ((link_y_coord + 12) & 0x1f8) << 3;
-  pos |= ((link_x_coord + 8) & 0x1f8) >> 3;
-  pos |= (link_is_on_lower_level ? 0x1000 : 0);
-  uint8 a = dung_bg2_attr_table[pos];
-  uint8 r = (a == 0 || a == 9) ? 0 :
-    ((a &= 0x8e) == 0x80) ? 1 :
-    (a == 0x82) ? 2 :
-    (a == 0x84 || a == 0x88) ? 3 :
-    (a == 0x86) ? 4 : 2;
-  return byte_7E004E = r;
-}
-
-// This gets called when entering a dungeon from ow.
-void Dungeon_LoadAndDrawRoom() {  // 82c57b
-  int bak = HDMAEN_copy;
-  HDMAEN_copy = 0;
-  Dungeon_LoadRoom();
-  overworld_screen_transition = 0;
-  overworld_map_state = 0;
-  for (dung_cur_quadrant_upload = 0; dung_cur_quadrant_upload != 16; ) {
-    TileMapPrep_NotWaterOnTag();
-    NMI_UploadTilemap();
-    Dungeon_PrepareNextRoomQuadrantUpload();
-    NMI_UploadTilemap();
-  }
-  HDMAEN_copy = bak;
-  nmi_subroutine_index = 0;
-  overworld_map_state = 0;
-  subsubmodule_index = 0;
-}
-
-void Dungeon_LoadEntrance() {  // 82d8b3
-  player_is_indoors = 1;
-
-  if (death_var5) {
-    death_var5 = 0;
-  } else {
-    overworld_area_index_exit = overworld_area_index;
-    TM_copy_exit = WORD(TM_copy);
-    BG2VOFS_copy2_exit = BG2VOFS_copy2;
-    BG2HOFS_copy2_exit = BG2HOFS_copy2;
-    link_y_coord_exit = link_y_coord;
-    link_x_coord_exit = link_x_coord;
-    camera_y_coord_scroll_low_exit = camera_y_coord_scroll_low;
-    camera_x_coord_scroll_low_exit = camera_x_coord_scroll_low;
-    overworld_screen_index_exit = overworld_screen_index;
-    map16_load_src_off_exit = map16_load_src_off;
-    overworld_screen_index = 0;
-    overlay_index = 0;
-    ow_scroll_vars0_exit = ow_scroll_vars0;
-    up_down_scroll_target_exit = up_down_scroll_target;
-    up_down_scroll_target_end_exit = up_down_scroll_target_end;
-    left_right_scroll_target_exit = left_right_scroll_target;
-    left_right_scroll_target_end_exit = left_right_scroll_target_end;
-    overworld_unk1_exit = overworld_unk1;
-    overworld_unk1_neg_exit = overworld_unk1_neg;
-    overworld_unk3_exit = overworld_unk3;
-    overworld_unk3_neg_exit = overworld_unk3_neg;
-    byte_7EC164 = byte_7E0AA0;
-    main_tile_theme_index_exit = main_tile_theme_index;
-    aux_tile_theme_index_exit = aux_tile_theme_index;
-    sprite_graphics_index_exit = sprite_graphics_index;
-  }
-  bg1_y_offset = bg1_x_offset = 0;
-  WORD(death_var5) = 0;
-  if (WORD(follower_indicator) == 4 || WORD(death_var4)) {
-    int i = which_starting_point;
-    WORD(which_entrance) = kStartingPoint_entrance[i];
-    dungeon_room_index = dungeon_room_index2 = kStartingPoint_rooms[i];
-    BG1VOFS_copy = BG2VOFS_copy = BG1VOFS_copy2 = BG2VOFS_copy2 = kStartingPoint_scrollY[i];
-    BG1HOFS_copy = BG2HOFS_copy = BG1HOFS_copy2 = BG2HOFS_copy2 = kStartingPoint_scrollX[i];
-    if (WORD(sram_progress_indicator)) {
-      link_y_coord = kStartingPoint_playerY[i];
-      link_x_coord = kStartingPoint_playerX[i];
-    }
-    camera_y_coord_scroll_low = kStartingPoint_cameraY[i];
-    camera_y_coord_scroll_hi = camera_y_coord_scroll_low + 2;
-    camera_x_coord_scroll_low = kStartingPoint_cameraX[i];
-    camera_x_coord_scroll_hi = camera_x_coord_scroll_low + 2;
-    tilemap_location_calc_mask = 0x1f8;
-    ow_entrance_value = kStartingPoint_doorSettings[i];
-    up_down_scroll_target = 0;
-    up_down_scroll_target_end = 0x110;
-    left_right_scroll_target = 0;
-    left_right_scroll_target_end = 0x100;
-    room_bounds_y.a0 = kStartingPoint_relativeCoords[i * 8 + 0] << 8;
-    room_bounds_y.b0 = kStartingPoint_relativeCoords[i * 8 + 1] << 8;
-    room_bounds_y.a1 = kStartingPoint_relativeCoords[i * 8 + 2] << 8 | 0x10;
-    room_bounds_y.b1 = kStartingPoint_relativeCoords[i * 8 + 3] << 8 | 0x10;
-    room_bounds_x.a0 = kStartingPoint_relativeCoords[i * 8 + 4] << 8;
-    room_bounds_x.b0 = kStartingPoint_relativeCoords[i * 8 + 5] << 8;
-    room_bounds_x.a1 = kStartingPoint_relativeCoords[i * 8 + 6] << 8;
-    room_bounds_x.b1 = kStartingPoint_relativeCoords[i * 8 + 7] << 8;
-
-    link_direction_facing = 2;
-    main_tile_theme_index = kStartingPoint_blockset[i];
-    dung_cur_floor = kStartingPoint_floor[i];
-    BYTE(cur_palace_index_x2) = kStartingPoint_palace[i];
-    is_standing_in_doorway = 0;
-    link_is_on_lower_level = kStartingPoint_startingBg[i] >> 4;
-    link_is_on_lower_level_mirror = kStartingPoint_startingBg[i] & 0xf;
-    quadrant_fullsize_x = kStartingPoint_quadrant1[i] >> 4;
-    quadrant_fullsize_y = kStartingPoint_quadrant1[i] & 0xf;
-    link_quadrant_x = kStartingPoint_quadrant2[i] >> 4;
-    link_quadrant_y = kStartingPoint_quadrant2[i] & 0xf;
-
-    queued_music_control = kStartingPoint_musicTrack[i];
-    if (i == 0 && sram_progress_indicator == 0)
-      queued_music_control = 0xff;
-    death_var4 = 0;
-  } else {
-    int i = which_entrance;
-    dungeon_room_index = dungeon_room_index2 = kEntranceData_rooms[i];
-    BG1VOFS_copy = BG2VOFS_copy = BG1VOFS_copy2 = BG2VOFS_copy2 = kEntranceData_scrollY[i];
-    BG1HOFS_copy = BG2HOFS_copy = BG1HOFS_copy2 = BG2HOFS_copy2 = kEntranceData_scrollX[i];
-    if (WORD(sram_progress_indicator)) {
-      link_y_coord = kEntranceData_playerY[i];
-      link_x_coord = kEntranceData_playerX[i];
-    }
-    camera_y_coord_scroll_low = kEntranceData_cameraY[i];
-    camera_y_coord_scroll_hi = camera_y_coord_scroll_low + 2;
-    camera_x_coord_scroll_low = kEntranceData_cameraX[i];
-    camera_x_coord_scroll_hi = camera_x_coord_scroll_low + 2;
-    tilemap_location_calc_mask = 0x1f8;
-    ow_entrance_value = kEntranceData_doorSettings[i];
-    big_rock_starting_address = 0;
-    up_down_scroll_target = 0;
-    up_down_scroll_target_end = 0x110;
-    left_right_scroll_target = 0;
-    left_right_scroll_target_end = 0x100;
-
-    room_bounds_y.a0 = kEntranceData_relativeCoords[i * 8 + 0] << 8;
-    room_bounds_y.b0 = kEntranceData_relativeCoords[i * 8 + 1] << 8;
-    room_bounds_y.a1 = kEntranceData_relativeCoords[i * 8 + 2] << 8 | 0x10;
-    room_bounds_y.b1 = kEntranceData_relativeCoords[i * 8 + 3] << 8 | 0x10;
-
-    room_bounds_x.a0 = kEntranceData_relativeCoords[i * 8 + 4] << 8;
-    room_bounds_x.b0 = kEntranceData_relativeCoords[i * 8 + 5] << 8;
-    room_bounds_x.a1 = kEntranceData_relativeCoords[i * 8 + 6] << 8;
-    room_bounds_x.b1 = kEntranceData_relativeCoords[i * 8 + 7] << 8;
-
-    link_direction_facing = (i == 0 || i == 0x43) ? 2 : 0;
-    main_tile_theme_index = kEntranceData_blockset[i];
-    queued_music_control = ZeldaGetEntranceMusicTrack(i);
-    if (queued_music_control == 3 && sram_progress_indicator >= 2)
-      queued_music_control = 18;
-
-    dung_cur_floor = kEntranceData_floor[i];
-    BYTE(cur_palace_index_x2) = kEntranceData_palace[i];
-    is_standing_in_doorway = kEntranceData_doorwayOrientation[i];
-    link_is_on_lower_level = kEntranceData_startingBg[i] >> 4;
-    link_is_on_lower_level_mirror = kEntranceData_startingBg[i] & 0xf;
-    quadrant_fullsize_x = kEntranceData_quadrant1[i] >> 4;
-    quadrant_fullsize_y = kEntranceData_quadrant1[i] & 0xf;
-    link_quadrant_x = kEntranceData_quadrant2[i] >> 4;
-    link_quadrant_y = kEntranceData_quadrant2[i] & 0xf;
-
-    if (dungeon_room_index >= 0x100)
-      dung_cur_floor = 0;
-  }
-  player_oam_x_offset = player_oam_y_offset = 0x80;
-  link_direction_mask_a = link_direction_mask_b = 0xf;
-  BYTE(link_z_coord) = link_actual_vel_z = 0xff;
-  memcpy(movable_block_datas, kMovableBlockDataInit, kMovableBlockDataInit_SIZE);
-  memcpy(&movable_block_datas[99], kTorchDataInit, 116); // junk
-  memcpy(dung_torch_data, kTorchDataInit, kTorchDataInit_SIZE);
-  memcpy(&dung_torch_data[144], kTorchDataJunk, kTorchDataJunk_SIZE);
-
-  memset(memorized_tile_addr, 0, 0x100);
-  memset(pots_revealed_in_room, 0, 0x280);
-  orange_blue_barrier_state = 0;
-  byte_7E04BC = 0;
-}
-
-void PushBlock_Slide(uint8 j) {  // 87edb5
-  if (submodule_index)
-    return;
-  int i = (index_of_changable_dungeon_objs[1] - 1) * 2 == j;
-  pushedblocks_maybe_timeout = 9;
-  pushedblocks_some_index = 0;
-  PushBlock_ApplyVelocity(i);
-  int y = (uint8)pushedblocks_y_lo[i] | (uint8)pushedblocks_y_hi[i] << 8;
-  int x = (uint8)pushedblocks_x_lo[i] | (uint8)pushedblocks_x_hi[i] << 8;
-  PushBlock_HandleCollision(i, x, y);
-}
-
-void PushBlock_HandleFalling(uint8 y) {  // 87edf9
-  y >>= 1;
-
-  if (!sign8(--pushedblocks_maybe_timeout))
-    return;
-
-  pushedblocks_maybe_timeout = 9;
-
-  if (++pushedblocks_some_index == 4) {
-    BYTE(dung_replacement_tile_state[y]) = 0;
-    pushedblocks_some_index = 0;
-    int i = (index_of_changable_dungeon_objs[1] - 1) == y;
-    index_of_changable_dungeon_objs[i] = 0;
-  }
-}
-
-void PushBlock_ApplyVelocity(uint8 i) {  // 87ee35
-  static const uint8 kPushedBlockDirMask[] = { 0x8, 0x4, 0x2, 0x1 };
-  uint8 m = kPushedBlockDirMask[(uint8)pushedblock_facing[i] >> 1];
-  uint32 o;
-  link_actual_vel_x = link_actual_vel_y = 0;
-  if (m & 3) {
-    int8 vel = (m & 2) ? -12 : 12;
-    link_actual_vel_x = vel;
-    o = (pushedblocks_subpixel[i] | pushedblocks_x_lo[i] << 8 | pushedblocks_x_hi[i] << 16) + vel * 16;
-    pushedblocks_subpixel[i] = (uint8)o;
-    pushedblocks_x_lo[i] = (uint8)(o >> 8);
-    pushedblocks_x_hi[i] = (uint8)(o >> 16);
-  } else {
-    int8 vel = (m & 8) ? -12 : 12;
-    link_actual_vel_y = vel;
-    o = (pushedblocks_subpixel[i] | pushedblocks_y_lo[i] << 8 | pushedblocks_y_hi[i] << 16);
-    o += vel * 16;
-    pushedblocks_subpixel[i] = (uint8)o;
-    pushedblocks_y_lo[i] = (uint8)(o >> 8);
-    pushedblocks_y_hi[i] = (uint8)(o >> 16);
-  }
-  if (((o >> 8) & 0xf) == (uint8)pushedblocks_target[i]) {
-    int j = index_of_changable_dungeon_objs[i] - 1;
-    dung_replacement_tile_state[j]++;
-    link_cant_change_direction &= ~0x4;
-    bitmask_of_dragstate &= ~0x4;
-  }
-  uint16 x = pushedblocks_x_lo[i] | pushedblocks_x_hi[i] << 8;
-  uint16 y = pushedblocks_y_lo[i] | pushedblocks_y_hi[i] << 8;
-  for (int j = 15; j >= 0; j--) {
-    if (sprite_state[j] >= 9) {
-      uint16 sx = sprite_x_lo[j] | sprite_x_hi[j] << 8;
-      uint16 sy = sprite_y_lo[j] | sprite_y_hi[j] << 8;
-      if ((uint16)(x - sx + 0x10) < 0x20 && (uint16)(y - sy + 0x10) < 0x20) {
-        sprite_F[j] = 8;
-        static const uint8 kPushBlockTab1[] = { 0x0, 0x0, 0xe0, 0x20 };
-        static const uint8 kPushBlockTab2[] = { 0xe0, 0x20, 0x0, 0x0 };
-        int k = (uint8)pushedblock_facing[i] >> 1;
-        sprite_x_recoil[j] = kPushBlockTab1[k];
-        sprite_y_recoil[j] = kPushBlockTab2[k];
-      }
-    }
-  }
-}
-
-void PushBlock_HandleCollision(uint8 i, uint16 x, uint16 y) {  // 87efb9
-  static const uint8 kPushBlock_A[] = { 0, 0, 8, 8 };
-  static const uint8 kPushBlock_B[] = { 15, 15, 23, 23 };
-  static const uint8 kPushBlock_D[] = { 15, 15, 15, 15 };
-  static const uint8 kPushBlock_C[] = { 0x0, 0x0, 0x0, 0x0 };
-  static const uint8 kPushBlock_E[] = { 8, 24, 0, 16 };
-  static const uint8 kPushBlock_F[] = { 15, 0, 15, 0 };
-
-  link_y_coord_safe_return_hi = link_y_coord >> 8;
-  link_x_coord_safe_return_hi = link_x_coord >> 8;
-
-  int dir = 3;
-  uint8 m = link_direction & 0xf;
-  while (!(m & 1)) {
-    m >>= 1;
-    if (--dir < 0)
-      return;
-  }
-  int l = (dir < 2) ? link_x_coord : link_y_coord;
-  int o = (dir < 2) ? x : y;
-
-  uint16 r0 = l + kPushBlock_A[dir];
-  uint16 r2 = l + kPushBlock_B[dir];
-  uint16 r4 = o + kPushBlock_C[dir];
-  uint16 r6 = o + kPushBlock_D[dir];
-
-  uint16 *coord_p = (dir < 2) ? &link_y_coord : &link_x_coord;
-  uint16 r8 = *coord_p + kPushBlock_E[dir];
-  uint16 r10 = ((dir < 2) ? y : x) + kPushBlock_F[dir];
-
-  bitmask_of_dragstate &= ~4;
-
-  if (r0 >= r4 && r0 < r6 || r2 >= r4 && r2 < r6) {
-    if (link_direction_facing == pushedblock_facing[i])
-      bitmask_of_dragstate |= index_of_changable_dungeon_objs[i] ? 4 : 1;
-    if (dir & 1 ? (r8 >= r10 && (uint16)(r8 - r10) < 8) : (uint16)(r8 - r10) >= 0xfff8) {
-      *coord_p -= r8 - r10;
-      *(dir & 2 ? &link_x_vel : &link_y_vel) -= r8 - r10;
-    }
-  }
-  HandleIndoorCameraAndDoors();
-}
-
-void Sprite_Dungeon_DrawAllPushBlocks() {  // 87f0ac
-  for (int i = 1; i >= 0; i--)
-    if (index_of_changable_dungeon_objs[i])
-      Sprite_HandlePushedBlocks_One(i);
-}
-
-void UsedForStraightInterRoomStaircase() {  // 87f25a
-  int i = 9;
-  do {
-    if (ancilla_type[i] == 13)
-      ancilla_type[i] = 0;
-  } while (--i >= 0);
-  if (link_animation_steps >= 5)
-    link_animation_steps = 0;
-  link_subpixel_x = 0;
-  link_subpixel_y = 0;
-  some_animation_timer_steps = 0;
-  link_timer_push_get_tired = 28;
-  countdown_timer_for_staircases = 32;
-  link_disable_sprite_damage = 1;
-  Ancilla_Sfx2_Near(which_staircase_index & 4 ? 0x18 : 0x16);
-
-  tiledetect_which_y_pos[1] = link_x_coord + (which_staircase_index & 4 ? -15 : 16);
-  tiledetect_which_y_pos[0] = link_y_coord;
-}
-
-void HandleLinkOnSpiralStairs() {  // 87f2c1
-  link_x_coord_prev = link_x_coord;
-  link_y_coord_prev = link_y_coord;
-  if (some_animation_timer_steps)
-    return;
-
-  link_give_damage = 0;
-  link_incapacitated_timer = 0;
-  link_auxiliary_state = 0;
-
-  if (which_staircase_index & 4) {
-    link_actual_vel_y = -2;
-    if (sign8(--link_timer_push_get_tired)) {
-      link_timer_push_get_tired = 0;
-      link_actual_vel_y = 0;
-      link_actual_vel_x = -2;
-    }
-  } else {
-    link_actual_vel_y = -2;
-    if (sign8(--link_timer_push_get_tired)) {
-      link_timer_push_get_tired = 0;
-      link_actual_vel_y = -2;
-      link_actual_vel_x = 2;
-    }
-  }
-  Link_MovePosition();
-  Link_HandleMovingAnimation_StartWithDash();
-  if (!link_timer_push_get_tired && sign8(--countdown_timer_for_staircases)) {
-    countdown_timer_for_staircases = 0;
-    link_direction_facing = (which_staircase_index & 4) ? 4 : 6;
-  }
-
-  int8 xd = link_x_coord - tiledetect_which_y_pos[1];
-  if (xd < 0)
-    xd = -xd;
-  if (xd)
-    return;
-
-  RepositionLinkAfterSpiralStairs();
-  if (follower_indicator)
-    Follower_Initialize();
-
-  tiledetect_which_y_pos[1] = link_x_coord + ((which_staircase_index & 4) ? -8 : 12);
-  some_animation_timer_steps = 1;
-  countdown_timer_for_staircases = 6;
-  Ancilla_Sfx2_Near(which_staircase_index & 4 ? 25 : 23);
-}
-
-void SpiralStairs_FindLandingSpot() {  // 87f391
-  link_give_damage = 0;
-  link_incapacitated_timer = 0;
-  link_auxiliary_state = 0;
-  link_disable_sprite_damage = 0;
-  link_x_coord_prev = link_x_coord;
-  link_y_coord_prev = link_y_coord;
-  if (sign8(--countdown_timer_for_staircases)) {
-    countdown_timer_for_staircases = 0;
-    link_direction_facing = 2;
-  }
-  link_actual_vel_x = 4, link_actual_vel_y = 0;
-  if (which_staircase_index & 4)
-    link_actual_vel_x = -4, link_actual_vel_y = 2;
-  if (some_animation_timer_steps == 2)
-    link_actual_vel_x = 0, link_actual_vel_y = 16;
-  Link_MovePosition();
-  Link_HandleMovingAnimation_StartWithDash();
-  if ((uint8)link_x_coord == (uint8)tiledetect_which_y_pos[1])
-    some_animation_timer_steps = 2;
-}
-
-void Dungeon_HandleLayerEffect() {  // 8afe80
-  kDungeon_Effect_Handler[dung_hdr_collision_2]();
-}
-
-void LayerEffect_Nothing() {  // 8afe87
-}
-
-void LayerEffect_Scroll() {  // 8afe88
-  if (dung_savegame_state_bits & 0x8000) {
-    dung_hdr_collision_2 = 0;
-    return;
-  }
-  dung_floor_x_vel = dung_floor_y_vel = 0;
-  if (dung_floor_move_flags & 1)
-    return;
-  int t = dung_some_subpixel[1] + 0x80;
-  dung_some_subpixel[1] = t;
-  t >>= 8;
-  if (dung_floor_move_flags & 2)
-    t = -t;
-
-  if (dung_floor_move_flags < 4) {
-    dung_floor_x_vel = t;
-    dung_floor_x_offs -= t;
-    BG1HOFS_copy2 = BG2HOFS_copy2 + dung_floor_x_offs;
-  } else {
-    dung_floor_y_vel = t;
-    dung_floor_y_offs -= t;
-    BG1VOFS_copy2 = BG2VOFS_copy2 + dung_floor_y_offs;
-  }
-}
-
-void LayerEffect_Trinexx() {  // 8afeee
-  dung_floor_x_offs += dung_floor_x_vel;
-  dung_floor_y_offs += dung_floor_y_vel;
-  dung_floor_x_vel = 0;
-  dung_floor_y_vel = 0;
-}
-
-void LayerEffect_Agahnim2() {  // 8aff0d
-  int j = frame_counter & 0x7f;
-  if (j == 3 || j == 36) {
-    main_palette_buffer[0x6d] = 0x1d59;
-    main_palette_buffer[0x6e] = 0x25ff;
-    main_palette_buffer[0x77] = main_palette_buffer[0x6f] = 0x1a;
-    flag_update_cgram_in_nmi++;
-  } else if (j == 5 || j == 38) {
-    main_palette_buffer[0x6d] = aux_palette_buffer[0x6d];
-    main_palette_buffer[0x6e] = aux_palette_buffer[0x6e];
-    main_palette_buffer[0x77] = main_palette_buffer[0x6f] = aux_palette_buffer[0x6f];
-    flag_update_cgram_in_nmi++;
-  }
-  TS_copy = 2;
-}
-
-void LayerEffect_InvisibleFloor() {  // 8aff5d
-  int count = 0;
-  for (int i = 0; i < 16; i++)
-    count += (dung_object_tilemap_pos[i] & 0x8000) != 0;
-
-  uint16 x = 0x2940, y = 0x4e60;
-  if (count == 0)
-    x = y = 0;
-
-  if (aux_palette_buffer[0x7b] != x) {
-    main_palette_buffer[0x7b] = aux_palette_buffer[0x7b] = x;
-    main_palette_buffer[0x7c] = aux_palette_buffer[0x7c] = y;
-    flag_update_cgram_in_nmi++;
-  }
-  TS_copy = 2;
-}
-
-void LayerEffect_Ganon() {  // 8affa4
-  int count = 0;
-  for (int i = 0; i < 16; i++)
-    count += (dung_object_tilemap_pos[i] & 0x8000) != 0;
-
-  byte_7E04C5 = count;
-  if (count == 0) {
-    TS_copy = 0;
-    CGADSUB_copy = 0xb3;
-  } else if (count == 1) {
-    TS_copy = 2;
-    CGADSUB_copy = 0x70;
-  } else {
-    TS_copy = 0;
-    CGADSUB_copy = 0x70;
-  }
-}
-
-void LayerEffect_WaterRapids() {  // 8affde
-  int t;
-  dung_some_subpixel[1] = t = dung_some_subpixel[1] + 0x80;
-  dung_floor_x_vel = -(t >> 8);
-}
-
-void Dungeon_LoadCustomTileAttr() {  // 8e942a
-  memcpy(&attributes_for_tile[0x140], &kDungAttrsForTile[kDungAttrsForTile_Offs[aux_tile_theme_index]], 0x80);
-}
-
-void Link_CheckBunnyStatus() {  // 8ffd22
-  if (link_player_handler_state == kPlayerState_RecoilWall) {
-    link_player_handler_state =
-      !link_is_bunny_mirror ? kPlayerState_Ground :
-      link_item_moon_pearl ? kPlayerState_TempBunny : kPlayerState_PermaBunny;
-  }
-}
-
-void CrystalCutscene_Initialize() {  // 9ecce3
-  static const uint16 kCrystalMaiden_Pal[8] = { 0, 0x3821, 0x4463, 0x54a5, 0x5ce7, 0x6d29, 0x79ad, 0x7e10 };
-
-  CGADSUB_copy = 0x33;
-  BYTE(palette_filter_countdown) = 0;
-  BYTE(darkening_or_lightening_screen) = 0;
-  Palette_AssertTranslucencySwap();
-  PaletteFilter_Crystal();
-  for (int i = 0; i < 8; i++)
-    main_palette_buffer[112 + i] = kCrystalMaiden_Pal[i];
-  flag_update_cgram_in_nmi++;
-  CrystalCutscene_SpawnMaiden();
-  CrystalCutscene_InitializePolyhedral();
-}
-
-void CrystalCutscene_SpawnMaiden() {  // 9ecd48
-  memset(sprite_state, 0, 16);
-  SpriteSpawnInfo info;
-  int j = Sprite_SpawnDynamically(0, 0xab, &info);
-  sprite_x_hi[j] = link_x_coord >> 8;
-  sprite_y_hi[j] = link_y_coord >> 8;
-  sprite_x_lo[j] = 0x78;
-  sprite_y_lo[j] = 0x7c;
-  sprite_D[j] = 1;
-  sprite_oam_flags[j] = 0xb;
-  sprite_subtype2[j] = 0;
-  sprite_floor[j] = 0;
-  sprite_A[j] = Ancilla_TerminateSelectInteractives(j);
-  item_receipt_method = 0;
-  if (BYTE(cur_palace_index_x2) == 24) {
-    sprite_oam_flags[j] = 9;
-    follower_indicator = 1;
-  } else {
-    follower_indicator = 6;
-  }
-  LoadFollowerGraphics();
-  follower_indicator = 0;
-  dung_floor_x_offs = BG2HOFS_copy2 - link_x_coord + 0x79;
-  dung_floor_y_offs = 0x30 - (uint8)BG1VOFS_copy2;
-  dung_hdr_collision_2_mirror = 1;
-}
-
--- a/dungeon.h
+++ /dev/null
@@ -1,448 +1,0 @@
-#pragma once
-
-typedef struct RoomBounds RoomBounds;
-
-enum {
-  kDoorType_Regular = 0,
-  kDoorType_Regular2 = 2,
-  kDoorType_4 = 4,
-  kDoorType_EntranceDoor = 6,
-  kDoorType_WaterfallTunnel = 8,
-  kDoorType_EntranceLarge = 10,
-  kDoorType_EntranceLarge2 = 12,
-  kDoorType_EntranceCave = 14,
-  kDoorType_EntranceCave2 = 16,
-  kDoorType_ExitToOw = 18,
-  kDoorType_ThroneRoom = 20,
-  kDoorType_PlayerBgChange = 22,
-  kDoorType_ShuttersTwoWay = 24,
-  kDoorType_InvisibleDoor = 26,
-  kDoorType_SmallKeyDoor = 0x1c,
-  kDoorType_1E = 0x1e,
-  kDoorType_StairMaskLocked0 = 32,
-  kDoorType_StairMaskLocked1 = 34,
-  kDoorType_StairMaskLocked2 = 36,
-  kDoorType_StairMaskLocked3 = 38,
-  kDoorType_BreakableWall = 0x28,
-  kDoorType_LgExplosion = 48,
-  kDoorType_Slashable = 50,
-  kDoorType_36 = 0x36,
-  kDoorType_38 = 0x38,
-
-  kDoorType_RegularDoor33 = 64,
-  kDoorType_Shutter = 68,
-  kDoorType_WarpRoomDoor = 70,
-  kDoorType_ShutterTrapUR = 72,
-  kDoorType_ShutterTrapDL = 74,
-};
-
-typedef struct DungPalInfo {
-  uint8 pal0;
-  uint8 pal1;
-  uint8 pal2;
-  uint8 pal3;
-} DungPalInfo;
-
-extern const uint8 kDungAnimatedTiles[24];
-uint16 *DstoPtr(uint16 d);
-void Object_Fill_Nx1(int n, const uint16 *src, uint16 *dst);
-void Object_Draw_5x4(const uint16 *src, uint16 *dst);
-void Object_Draw_4x2_BothBgs(const uint16 *src, uint16 dsto);
-void Object_ChestPlatform_Helper(const uint16 *src, int dsto);
-void Object_Hole(const uint16 *src, uint16 *dst);
-void LoadType1ObjectSubtype1(uint8 idx, uint16 *dst, uint16 dsto);
-void Object_DrawNx3_BothBgs(int n, const uint16 *src, int dsto);
-void LoadType1ObjectSubtype2(uint8 idx, uint16 *dst, uint16 dsto);
-void Object_BombableFloorHelper(uint16 a, const uint16 *src, const uint16 *src_below, uint16 *dst, uint16 dsto);
-void LoadType1ObjectSubtype3(uint8 idx, uint16 *dst, uint16 dsto);
-void RoomBounds_AddA(RoomBounds *r);
-void RoomBounds_AddB(RoomBounds *r);
-void RoomBounds_SubB(RoomBounds *r);
-void RoomBounds_SubA(RoomBounds *r);
-void Dungeon_StartInterRoomTrans_Left();
-void Dung_StartInterRoomTrans_Left_Plus();
-void Dungeon_StartInterRoomTrans_Up();
-void Dungeon_StartInterRoomTrans_Down();
-void Dungeon_Store2x2(uint16 pos, uint16 t0, uint16 t1, uint16 t2, uint16 t3, uint8 attr);
-uint16 Dungeon_MapVramAddr(uint16 pos);
-uint16 Dungeon_MapVramAddrNoSwap(uint16 pos);
-void Door_Up_EntranceDoor(uint16 dsto);
-void Door_Down_EntranceDoor(uint16 dsto);
-void Door_Left_EntranceDoor(uint16 dsto);
-void Door_Right_EntranceDoor(uint16 dsto);
-void Door_Draw_Helper4(uint8 door_type, uint16 dsto);
-const uint16 *GetRoomDoorInfo(int room);
-const uint8 *GetRoomHeaderPtr(int room);
-const uint8 *GetDefaultRoomLayout(int i);
-const uint8 *GetDungeonRoomLayout(int i);
-void Dung_TagRoutine_0x22_0x3B(int k, uint8 j);
-void Sprite_HandlePushedBlocks_One(int i);
-void Object_Draw_DoorLeft_3x4(uint16 src, int door);
-void Object_Draw_DoorRight_3x4(uint16 src, int door);
-void Dungeon_OpeningLockedDoor_Combined(bool skip_anim);
-const DungPalInfo *GetDungPalInfo(int idx);
-uint16 Dungeon_GetTeleMsg(int room);
-bool Dungeon_IsPitThatHurtsPlayer();
-void Dungeon_PrepareNextRoomQuadrantUpload();
-void WaterFlood_BuildOneQuadrantForVRAM();
-void TileMapPrep_NotWaterOnTag();
-void OrientLampLightCone();
-void PrepareDungeonExitFromBossFight();
-void SavePalaceDeaths();
-void Dungeon_LoadRoom();
-void RoomDraw_DrawAllObjects(const uint8 *level_data);
-void RoomData_DrawObject_Door(uint16 a);
-void RoomData_DrawObject(uint16 r0, const uint8 *level_data);
-void RoomDraw_DrawFloors(const uint8 *level_data);
-void RoomDraw_FloorChunks(const uint16 *src);
-void RoomDraw_A_Many32x32Blocks(int n, const uint16 *src, uint16 *dst);
-void RoomDraw_1x3_rightwards(int n, const uint16 *src, uint16 *dst);
-bool RoomDraw_CheckIfWallIsMoved();
-void MovingWall_FillReplacementBuffer(int dsto);
-void Object_Table_Helper(const uint16 *src, uint16 *dst);
-void DrawWaterThing(uint16 *dst, const uint16 *src);
-void RoomDraw_4x4(const uint16 *src, uint16 *dst);
-void RoomDraw_Object_Nx4(int n, const uint16 *src, uint16 *dst);
-void Object_DrawNx4_BothBgs(int n, const uint16 *src, int dsto);
-void RoomDraw_Rightwards2x2(const uint16 *src, uint16 *dst);
-void Object_Draw_3x2(const uint16 *src, uint16 *dst);
-void RoomDraw_WaterHoldingObject(int n, const uint16 *src, uint16 *dst);
-void RoomDraw_SomeBigDecors(int n, const uint16 *src, uint16 dsto);
-void RoomDraw_SingleLampCone(uint16 a, uint16 y);
-void RoomDraw_AgahnimsWindows(uint16 dsto);
-void RoomDraw_FortuneTellerRoom(uint16 dsto);
-void Object_Draw8x8(const uint16 *src, uint16 *dst);
-void RoomDraw_Door_North(int type, int pos_enum);
-void Door_Up_StairMaskLocked(uint8 door_type, uint16 dsto);
-void Door_PrioritizeCurDoor();
-void RoomDraw_NormalRangedDoors_North(uint8 door_type, uint16 dsto, int pos_enum);
-void RoomDraw_OneSidedShutters_North(uint8 door_type, uint16 dsto);
-void RoomDraw_Door_South(int type, int pos_enum);
-void RoomDraw_CheckIfLowerLayerDoors_Y(uint8 door_type, uint16 dsto);
-void RoomDraw_Door_West(int type, int pos_enum);
-void RoomDraw_NormalRangedDoors_West(uint8 door_type, uint16 dsto, int pos_enum);
-void RoomDraw_Door_East(int type, int pos_enum);
-void RoomDraw_NormalRangedDoors_East(uint8 door_type, uint16 dsto);
-void RoomDraw_OneSidedShutters_East(uint8 door_type, uint16 dsto);
-void RoomDraw_NorthCurtainDoor(uint16 dsto);
-void RoomDraw_Door_ExplodingWall(int pos_enum);
-void RoomDraw_ExplodingWallSegment(const uint16 *src, uint16 dsto);
-void RoomDraw_ExplodingWallColumn(const uint16 *src, uint16 *dst);
-void RoomDraw_HighRangeDoor_North(uint8 door_type, uint16 dsto, int pos_enum);
-void RoomDraw_OneSidedLowerShutters_South(uint8 door_type, uint16 dsto);
-void RoomDraw_HighRangeDoor_West(uint8 door_type, uint16 dsto, int pos_enum);
-void RoomDraw_OneSidedLowerShutters_East(uint8 door_type, uint16 dsto);
-void RoomDraw_MakeDoorHighPriority_North(uint16 dsto);
-void RoomDraw_MakeDoorHighPriority_South(uint16 dsto);
-void RoomDraw_MakeDoorHighPriority_West(uint16 dsto);
-void RoomDraw_MakeDoorHighPriority_East(uint16 dsto);
-void RoomDraw_MarkDungeonToggleDoor(uint16 dsto);
-void RoomDraw_MarkLayerToggleDoor(uint16 dsto);
-void RoomDraw_GetObjectSize_1to16();
-void Object_SizeAtoAplus15(uint8 a);
-void RoomDraw_GetObjectSize_1to15or26();
-void RoomDraw_GetObjectSize_1to15or32();
-int RoomDraw_FlagDoorsAndGetFinalType(uint8 direction, uint8 door_type, uint16 dsto);
-void RoomDraw_MakeDoorPartsHighPriority_Y(uint16 dsto);
-void RoomDraw_MakeDoorPartsHighPriority_X(uint16 dsto);
-void RoomDraw_Downwards4x2VariableSpacing(int increment, const uint16 *src, uint16 *dst);
-uint16 *RoomDraw_DrawObject2x2and1(const uint16 *src, uint16 *dst);
-uint16 *RoomDraw_RightwardShelfEnd(const uint16 *src, uint16 *dst);
-uint16 *RoomDraw_RightwardBarSegment(const uint16 *src, uint16 *dst);
-void DrawBigGraySegment(uint16 a, const uint16 *src, uint16 *dst, uint16 dsto);
-void RoomDraw_SinglePot(const uint16 *src, uint16 *dst, uint16 dsto);
-void RoomDraw_BombableFloor(const uint16 *src, uint16 *dst, uint16 dsto);
-void RoomDraw_HammerPegSingle(const uint16 *src, uint16 *dst, uint16 dsto);
-void DrawObjects_PushableBlock(uint16 dsto_x2, uint16 slot);
-void DrawObjects_LightableTorch(uint16 dsto_x2, uint16 slot);
-void Dungeon_LoadHeader();
-void Dungeon_CheckAdjacentRoomsForOpenDoors(int idx, int room);
-void Dungeon_LoadAdjacentRoomDoors(int room);
-void Dungeon_LoadAttribute_Selectable();
-void Dungeon_LoadAttributeTable();
-void Dungeon_LoadBasicAttribute_full(uint16 loops);
-void Dungeon_LoadObjectAttribute();
-void Dungeon_LoadDoorAttribute();
-void Dungeon_LoadSingleDoorAttribute(int k);
-void Door_LoadBlastWallAttr(int k);
-void ChangeDoorToSwitch();
-void Dungeon_FlipCrystalPegAttribute();
-void Dungeon_HandleRoomTags();
-void Dung_TagRoutine_0x00(int k);
-void Dungeon_DetectStaircase();
-void RoomTag_NorthWestTrigger(int k);
-void Dung_TagRoutine_0x2A(int k);
-void Dung_TagRoutine_0x2B(int k);
-void Dung_TagRoutine_0x2C(int k);
-void Dung_TagRoutine_0x2D(int k);
-void Dung_TagRoutine_0x2E(int k);
-void Dung_TagRoutine_0x2F(int k);
-void Dung_TagRoutine_0x30(int k);
-void RoomTag_QuadrantTrigger(int k);
-void Dung_TagRoutine_TrapdoorsUp();
-void RoomTag_RoomTrigger(int k);
-void RoomTag_RekillableBoss(int k);
-void RoomTag_RoomTrigger_BlockDoor(int k);
-void RoomTag_PrizeTriggerDoorDoor(int k);
-void RoomTag_SwitchTrigger_HoldDoor(int k);
-void RoomTag_SwitchTrigger_ToggleDoor(int k);
-void PushPressurePlate(uint8 attr);
-void RoomTag_TorchPuzzleDoor(int k);
-void RoomTag_Switch_ExplodingWall(int k);
-void RoomTag_PullSwitchExplodingWall(int k);
-void Dung_TagRoutine_BlastWallStuff(int k);
-void RoomTag_GetHeartForPrize(int k);
-void RoomTag_Agahnim(int k);
-void RoomTag_GanonDoor(int tagidx);
-void RoomTag_KillRoomBlock(int k);
-void RoomTag_PushBlockForChest(int k);
-void RoomTag_TriggerChest(int k);
-void RoomTag_OperateChestReveal(int k);
-void RoomTag_TorchPuzzleChest(int k);
-void RoomTag_MovingWall_East(int k);
-void RoomTag_MovingWallShakeItUp(int k);
-void RoomTag_MovingWall_West(int k);
-void RoomTag_MovingWallTorchesCheck(int k);
-int MovingWall_MoveALittle();
-int RoomTag_AdvanceGiganticWall(int k);
-void RoomTag_WaterOff(int k);
-void RoomTag_WaterOn(int k);
-void RoomTag_WaterGate(int k);
-void Dung_TagRoutine_0x1B(int k);
-void RoomTag_Holes0(int k);
-void Dung_TagRoutine_0x23(int k);
-void Dung_TagRoutine_0x34(int k);
-void Dung_TagRoutine_0x35(int k);
-void Dung_TagRoutine_0x36(int k);
-void Dung_TagRoutine_0x37(int k);
-void Dung_TagRoutine_0x39(int k);
-void Dung_TagRoutine_0x3A(int k);
-void Dung_TagRoutine_Func2(uint8 av);
-void RoomTag_ChestHoles0(int k);
-void Dung_TagRoutine_0x3B(int k);
-void RoomTag_Holes2(int k);
-void RoomTag_OperateWaterFlooring();
-bool RoomTag_MaybeCheckShutters(uint8 *attr_out);
-int RoomTag_GetTilemapCoords();
-bool RoomTag_CheckForPressedSwitch(uint8 *y_out);
-void Dungeon_ProcessTorchesAndDoors();
-void Bomb_CheckForDestructibles(uint16 x, uint16 y, uint8 r14);
-int DrawDoorOpening_Step1(int door, int dma_ptr);
-void DrawShutterDoorSteps(int door);
-void DrawEyeWatchDoor(int door);
-void Door_BlastWallExploding_Draw(int dsto);
-void OperateShutterDoors();
-void OpenCrackedDoor();
-void Dungeon_LoadToggleDoorAttr_OtherEntry(int door);
-void Dungeon_LoadSingleDoorTileAttribute();
-void DrawCompletelyOpenDoor();
-void Dungeon_ClearAwayExplodingWall();
-uint16 Dungeon_CheckForAndIDLiftableTile();
-void Dungeon_PushBlock_Handler();
-void RoomDraw_16x16Single(uint8 index);
-void PushBlock_CheckForPit(uint8 y);
-uint8 Dungeon_LiftAndReplaceLiftable(Point16U *pt);
-uint8 ThievesAttic_DrawLightenedHole(uint16 pos6, uint16 a, Point16U *pt);
-uint8 HandleItemTileAction_Dungeon(uint16 x, uint16 y);
-void ManipBlock_Something(Point16U *pt);
-void RevealPotItem(uint16 pos6, uint16 pos4);
-void Dungeon_UpdateTileMapWithCommonTile(int x, int y, uint8 v);
-void Dungeon_PrepSpriteInducedDma(int x, int y, uint8 v);
-void Dungeon_DeleteRupeeTile(uint16 x, uint16 y);
-uint8 OpenChestForItem(uint8 tile, int *chest_position);
-void OpenBigChest(uint16 loc, int *chest_position);
-uint8 OpenMiniGameChest(int *chest_position);
-uint16 RoomTag_BuildChestStripes(uint16 pos, uint16 y);
-void Dungeon_SetAttrForActivatedWaterOff();
-void Dungeon_FloodSwampWater_PrepTileMap();
-void Dungeon_AdjustWaterVomit(const uint16 *src, int depth);
-void Dungeon_SetAttrForActivatedWater();
-void FloodDam_Expand();
-void FloodDam_PrepTiles_init();
-void Watergate_Main_State1();
-void FloodDam_Fill();
-void Ganon_ExtinguishTorch_adjust_translucency();
-void Ganon_ExtinguishTorch();
-void Dungeon_ExtinguishTorch();
-void SpiralStairs_MakeNearbyWallsHighPriority_Entering();
-void SpiralStairs_MakeNearbyWallsLowPriority();
-void ClearAndStripeExplodingWall(uint16 dsto);
-void Dungeon_DrawRoomOverlay(const uint8 *src);
-void GetDoorDrawDataIndex_North_clean_door_index(int door);
-int DoorDoorStep1_North(int door, int dma_ptr);
-void GetDoorDrawDataIndex_North(int door, int r4_door);
-void DrawDoorToTileMap_North(int door, int r4_door);
-void Object_Draw_DoorUp_4x3(uint16 src, int door);
-void GetDoorDrawDataIndex_South_clean_door_index(int door);
-int DoorDoorStep1_South(int door, int dma_ptr);
-void GetDoorDrawDataIndex_South(int door, int r4_door);
-void DrawDoorToTileMap_South(int door, int r4_door);
-void Object_Draw_DoorDown_4x3(uint16 src, int door);
-void GetDoorDrawDataIndex_West_clean_door_index(int door);
-int DoorDoorStep1_West(int door, int dma_ptr);
-void GetDoorDrawDataIndex_West(int door, int r4_door);
-void DrawDoorToTileMap_West(int door, int r4_door);
-void GetDoorDrawDataIndex_East_clean_door_index(int door);
-int DoorDoorStep1_East(int door, int dma_ptr);
-void GetDoorDrawDataIndex_East(int door, int r4_door);
-void DrawDoorToTileMap_East(int door, int r4_door);
-uint8 GetDoorGraphicsIndex(int door, int r4_door);
-void ClearExplodingWallFromTileMap_ClearOnePair(uint16 *dst, const uint16 *src);
-void Dungeon_DrawRoomOverlay_Apply(int p);
-void ApplyGrayscaleFixed_Incremental();
-void Dungeon_ApproachFixedColor_variable(uint8 a);
-void Module_PreDungeon();
-void Module_PreDungeon_setAmbientSfx();
-void LoadOWMusicIfNeeded();
-void Module07_Dungeon();
-void Dungeon_TryScreenEdgeTransition();
-void Dungeon_HandleEdgeTransitionMovement(int dir);
-void Module07_00_PlayerControl();
-void Module07_01_SubtileTransition();
-void DungeonTransition_Subtile_ResetShutters();
-void DungeonTransition_Subtile_PrepTransition();
-void DungeonTransition_Subtile_ApplyFilter();
-void DungeonTransition_Subtile_TriggerShutters();
-void Module07_02_SupertileTransition();
-void Module07_02_00_InitializeTransition();
-void Module07_02_01_LoadNextRoom();
-void Dungeon_InterRoomTrans_State3();
-void Dungeon_InterRoomTrans_State10();
-void Dungeon_SpiralStaircase11();
-void Dungeon_InterRoomTrans_notDarkRoom();
-void Dungeon_InterRoomTrans_State9();
-void Dungeon_SpiralStaircase12();
-void Dungeon_InterRoomTrans_State4();
-void Dungeon_InterRoomTrans_State12();
-void Dungeon_Staircase14();
-void Dungeon_ResetTorchBackgroundAndPlayer();
-void Dungeon_ResetTorchBackgroundAndPlayerInner();
-void Dungeon_InterRoomTrans_State7();
-void DungeonTransition_RunFiltering();
-void Module07_02_FadedFilter();
-void Dungeon_InterRoomTrans_State15();
-void Dungeon_PlayMusicIfDefeated();
-void Module07_03_OverlayChange();
-void Module07_04_UnlockDoor();
-void Module07_05_ControlShutters();
-void Module07_06_FatInterRoomStairs();
-void Module07_0E_01_HandleMusicAndResetProps();
-void ResetTransitionPropsAndAdvance_ResetInterface();
-void ResetTransitionPropsAndAdvanceSubmodule();
-void Dungeon_InitializeRoomFromSpecial();
-void DungeonTransition_LoadSpriteGFX();
-void DungeonTransition_AdjustForFatStairScroll();
-void ResetThenCacheRoomEntryProperties();
-void DungeonTransition_TriggerBGC34UpdateAndAdvance();
-void DungeonTransition_TriggerBGC56UpdateAndAdvance();
-void Module07_07_FallingTransition();
-void Module07_07_00_HandleMusicAndResetRoom();
-void Module07_07_06_SyncBG1and2();
-void Module07_07_0F_FallingFadeIn();
-void Dungeon_PlayBlipAndCacheQuadrantVisits();
-void Module07_07_10_LandLinkFromFalling();
-void Module07_07_11_CacheRoomAndSetMusic();
-void Module07_08_NorthIntraRoomStairs();
-void Module07_08_00_InitStairs();
-void Module07_08_01_ClimbStairs();
-void Module07_10_SouthIntraRoomStairs();
-void Module07_10_00_InitStairs();
-void Module07_10_01_ClimbStairs();
-void Module07_09_OpenCrackedDoor();
-void Module07_0A_ChangeBrightness();
-void Module07_0B_DrainSwampPool();
-void Module07_0C_FloodSwampWater();
-void Module07_0D_FloodDam();
-void Module07_0E_SpiralStairs();
-void Dungeon_DoubleApplyAndIncrementGrayscale();
-void Module07_0E_02_ApplyFilterIf();
-void Dungeon_SyncBackgroundsFromSpiralStairs();
-void Dungeon_AdvanceThenSetBossMusicUnorthodox();
-void Dungeon_SetBossMusicUnorthodox();
-void Dungeon_SpiralStaircase17();
-void Dungeon_SpiralStaircase18();
-void Module07_0E_00_InitPriorityAndScreens();
-void Module07_0E_13_SetRoomAndLayerAndCache();
-void RepositionLinkAfterSpiralStairs();
-void SpiralStairs_MakeNearbyWallsHighPriority_Exiting();
-void Module07_0F_LandingWipe();
-void Module07_0F_00_InitSpotlight();
-void Module07_0F_01_OperateSpotlight();
-void Module07_11_StraightInterroomStairs();
-void Module07_11_00_PrepAndReset();
-void Module07_11_01_FadeOut();
-void Module07_11_02_LoadAndPrepRoom();
-void Module07_11_03_FilterAndLoadBGChars();
-void Module07_11_04_FilterDoBGAndResetSprites();
-void Module07_11_0B_PrepDestination();
-void Module07_11_09_LoadSpriteGraphics();
-void Module07_11_19_SetSongAndFilter();
-void Module07_11_11_KeepSliding();
-void Module07_14_RecoverFromFall();
-void Module07_14_00_ScrollCamera();
-void Module07_15_WarpPad();
-void Module07_15_01_ApplyMosaicAndFilter();
-void Module07_15_04_SyncRoomPropsAndBuildOverlay();
-void Module07_15_0E_FadeInFromWarp();
-void Module07_15_0F_FinalizeAndCacheEntry();
-void Module07_16_UpdatePegs();
-void Module07_17_PressurePlate();
-void Module07_18_RescuedMaiden();
-void Module07_19_MirrorFade();
-void Module07_1A_RoomDraw_OpenTriforceDoor_bounce();
-void Module11_DungeonFallingEntrance();
-void Module11_02_LoadEntrance();
-void Dungeon_LoadSongBankIfNeeded();
-void Mirror_SaveRoomData();
-void SaveDungeonKeys();
-void Dungeon_AdjustAfterSpiralStairs();
-void Dungeon_AdjustForTeleportDoors(uint8 room, uint8 flag);
-void Dungeon_AdjustForRoomLayout();
-void HandleEdgeTransitionMovementEast_RightBy8();
-void Dungeon_StartInterRoomTrans_Right();
-void HandleEdgeTransitionMovementSouth_DownBy16();
-void Dung_HandleExitToOverworld();
-void AdjustQuadrantAndCamera_right();
-void SetAndSaveVisitedQuadrantFlags();
-void SaveQuadrantsToSram();
-void AdjustQuadrantAndCamera_left();
-void AdjustQuadrantAndCamera_down();
-void AdjustQuadrantAndCamera_up();
-void Dungeon_FlagRoomData_Quadrants();
-void Dung_SaveDataForCurrentRoom();
-void HandleEdgeTransition_AdjustCameraBoundaries(uint8 arg);
-void Dungeon_AdjustQuadrant();
-void Dungeon_HandleCamera();
-void MirrorBg1Bg2Offs();
-void DungeonTransition_AdjustCamera_X(uint8 arg);
-void DungeonTransition_AdjustCamera_Y(uint8 arg);
-void DungeonTransition_ScrollRoom();
-void Module07_11_0A_ScrollCamera();
-void DungeonTransition_FindSubtileLanding();
-void SubtileTransitionCalculateLanding();
-void Dungeon_InterRoomTrans_State13();
-void Dungeon_IntraRoomTrans_State5();
-bool DungeonTransition_MoveLinkOutDoor();
-uint8 CalculateTransitionLanding();
-void Dungeon_LoadAndDrawRoom();
-void Dungeon_LoadEntrance();
-void PushBlock_Slide(uint8 j);
-void PushBlock_HandleFalling(uint8 y);
-void PushBlock_ApplyVelocity(uint8 i);
-void PushBlock_HandleCollision(uint8 i, uint16 x, uint16 y);
-void Sprite_Dungeon_DrawAllPushBlocks();
-void UsedForStraightInterRoomStaircase();
-void HandleLinkOnSpiralStairs();
-void SpiralStairs_FindLandingSpot();
-void Dungeon_HandleLayerEffect();
-void LayerEffect_Nothing();
-void LayerEffect_Scroll();
-void LayerEffect_Trinexx();
-void LayerEffect_Agahnim2();
-void LayerEffect_InvisibleFloor();
-void LayerEffect_Ganon();
-void LayerEffect_WaterRapids();
-void Dungeon_LoadCustomTileAttr();
-void Link_CheckBunnyStatus();
-void CrystalCutscene_Initialize();
-void CrystalCutscene_SpawnMaiden();
--- a/ending.c
+++ /dev/null
@@ -1,2658 +1,0 @@
-#include "zelda_rtl.h"
-#include "snes/snes_regs.h"
-#include "variables.h"
-#include "load_gfx.h"
-#include "dungeon.h"
-#include "sprite.h"
-#include "ending.h"
-#include "overworld.h"
-#include "player.h"
-#include "misc.h"
-#include "messaging.h"
-#include "player_oam.h"
-#include "sprite_main.h"
-#include "ancilla.h"
-#include "hud.h"
-#include "assets.h"
-
-static const uint16 kPolyhedralPalette[8] = { 0, 0x14d, 0x1b0, 0x1f3, 0x256, 0x279, 0x2fd, 0x35f };
-
-#define ending_which_dung (*(uint16*)(g_ram+0xcc))
-#define kPolyThreadRam (g_ram + 0x1f00)
-static const int8 kIntroSprite0_Xvel[3] = { 1, 0, -1 };
-static const int8 kIntroSprite0_Yvel[3] = { -1, 1, -1 };
-static const uint8 kIntroSprite3_X[4] = { 0xc2, 0x98, 0x6f, 0x34 };
-static const uint8 kIntroSprite3_Y[4] = { 0x7c, 0x54, 0x7c, 0x57 };
-static const uint8 kIntroSprite3_State[8] = { 0, 1, 2, 3, 2, 1, 0xff, 0xff };
-static const uint8 kTriforce_Xfinal[3] = { 0x59, 0x5f, 0x67 };
-static const uint8 kTriforce_Yfinal[3] = { 0x74, 0x68, 0x74 };
-static const uint16 kEndingSprites_X[] = {
-  0x1e0, 0x200, 0x1ed, 0x203, 0x1da, 0x216, 0x1c8, 0x228, 0x1c0, 0x1e0, 0x208, 0x228,
-  0xf8, 0xf0,
-  0x278, 0x298, 0x1e0, 0x200, 0x220, 0x288, 0x1e2,
-  0xe0, 0x150, 0xe8, 0x168, 0x128, 0x170, 0x170,
-  0x335, 0x335, 0x300,
-  0xb8, 0xce, 0xac, 0xc4,
-  0x3b0, 0x390, 0x3d0,
-  0xf8, 0xc8,
-  0x80,
-  0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xe8, 0xf8, 0xd8, 0xf8, 0xc8, 0x108,
-  0x70, 0x70, 0x70, 0x68, 0x88, 0x70,
-  0x40, 0x70, 0x4f, 0x61, 0x37, 0x79,
-  0xc8, 0x278, 0x258, 0x1d8, 0x1c8, 0x188, 0x270,
-  0x180,
-  0x2e8, 0x270, 0x270, 0x2a0, 0x2a0, 0x2a4, 0x2fc,
-  0x76, 0x73, 0x76, 0x0, 0xd0, 0x80,
-};
-static const uint16 kEndingSprites_Y[] = {
-  0x158, 0x158, 0x138, 0x138, 0x140, 0x140, 0x150, 0x150, 0x120, 0x120, 0x120, 0x120,
-  0x60, 0x37,
-  0xc2, 0xc2, 0x16b, 0x16c, 0x16b, 0xb8, 0x16b,
-  0x80, 0x60, 0x146, 0x146, 0x1c6, 0x70, 0x70,
-  0x128, 0x128, 0x16f,
-  0xf5, 0xfc, 0x10d, 0x10d,
-  0x40, 0x40, 0x40,
-  0x150, 0x158,
-  0xf4,
-  0x120, 0x120, 0x120, 0x120, 0x120, 0x108, 0x100, 0xd8, 0xd8, 0xf0, 0xf0,
-  0x3c, 0x3c, 0x3c, 0x90, 0x80, 0x3c,
-  0x16c, 0x16c, 0x174, 0x174, 0x175, 0x175,
-  0x250, 0x2b0, 0x2b0, 0x2a0, 0x2b0, 0x2b0, 0x2b8,
-  0xd8,
-  0x24b, 0x1b0, 0x1c8, 0x1c8, 0x1b0, 0x230, 0x230,
-  0x8b, 0x83, 0x85, 0x2c, 0xf8, 0x100,
-};
-static const uint8 kEndingSprites_Idx[17] = {
-  0, 12, 14, 21, 28, 31, 35, 38, 40, 41, 52, 58, 64, 71, 72, 79, 85
-};
-static PlayerHandlerFunc *const kEndSequence0_Funcs[3] = {
-&Credits_LoadScene_Overworld_PrepGFX,
-&Credits_LoadScene_Overworld_Overlay,
-&Credits_LoadScene_Overworld_LoadMap,
-};
-static PrepOamCoordsRet g_ending_coords;
-static const uint16 kEnding1_TargetScrollY[16] = { 0x6f2, 0x210, 0x72c, 0xc00, 0x10c, 0xa9b, 0x10, 0x510, 0x89, 0xa8e, 0x222c, 0x2510, 0x826, 0x5c, 0x20a, 0x30 };
-static const uint16 kEnding1_TargetScrollX[16] = { 0x77f, 0x480, 0x193, 0xaa, 0x878, 0x847, 0x4fd, 0xc57, 0x40f, 0x478, 0xa00, 0x200, 0x201, 0xaa1, 0x26f, 0 };
-static const int8 kEnding1_Yvel[16] = { -1, -1, 1, -1, 1, 1, 0, 1, 0, -1, -1, 0, 0, 0, 1, -1 };
-static const int8 kEnding1_Xvel[16] = { 0, 0, -1, 0, 0, -1, 1, 0, -1, 0, 0, 0, 1, -1, 1, 0 };
-static PlayerHandlerFunc *const kEndSequence_Funcs[39] = {
-&Credits_LoadNextScene_Overworld,
-&Credits_ScrollScene_Overworld,
-&Credits_LoadNextScene_Dungeon,
-&Credits_ScrollScene_Dungeon,
-&Credits_LoadNextScene_Overworld,
-&Credits_ScrollScene_Overworld,
-&Credits_LoadNextScene_Overworld,
-&Credits_ScrollScene_Overworld,
-&Credits_LoadNextScene_Overworld,
-&Credits_ScrollScene_Overworld,
-&Credits_LoadNextScene_Overworld,
-&Credits_ScrollScene_Overworld,
-&Credits_LoadNextScene_Overworld,
-&Credits_ScrollScene_Overworld,
-&Credits_LoadNextScene_Overworld,
-&Credits_ScrollScene_Overworld,
-&Credits_LoadNextScene_Overworld,
-&Credits_ScrollScene_Overworld,
-&Credits_LoadNextScene_Overworld,
-&Credits_ScrollScene_Overworld,
-&Credits_LoadNextScene_Dungeon,
-&Credits_ScrollScene_Dungeon,
-&Credits_LoadNextScene_Dungeon,
-&Credits_ScrollScene_Dungeon,
-&Credits_LoadNextScene_Overworld,
-&Credits_ScrollScene_Overworld,
-&Credits_LoadNextScene_Overworld,
-&Credits_ScrollScene_Overworld,
-&Credits_LoadNextScene_Overworld,
-&Credits_ScrollScene_Overworld,
-&Credits_LoadNextScene_Overworld,
-&Credits_ScrollScene_Overworld,
-&EndSequence_32,
-&Credits_BrightenTriangles,
-&Credits_FadeColorAndBeginAnimating,
-&Credits_StopCreditsScroll,
-&Credits_FadeAndDisperseTriangles,
-&Credits_FadeInTheEnd,
-&Credits_HangForever,
-};
-#define intro_sword_ypos WORD(g_ram[0xc8])
-#define intro_sword_18 g_ram[0xca]
-#define intro_sword_19 g_ram[0xcb]
-#define intro_sword_20 g_ram[0xcc]
-#define intro_sword_21 g_ram[0xcd]
-#define intro_sword_24 g_ram[0xd0]
-static const uint16 kEnding_Tab1[16] = {
-  0x1000, 2, 0x1002, 0x1012, 0x1004, 0x1006, 0x1010, 0x1014, 0x100a,
-  0x1016, 0x5d, 0x64, 0x100e, 0x1008, 0x1018, 0x180 };
-static const uint8 kEnding_SpritePack[17] = {
-  0x28, 0x46, 0x27, 0x2e, 0x2b, 0x2b, 0xe, 0x2c, 0x1a, 0x29, 0x47, 0x28, 0x27, 0x28, 0x2a, 0x28, 0x2d,
-};
-static const uint8 kEnding_SpritePal[17] = {
-  1, 0x40, 1, 4, 1, 1, 1, 0x11, 1, 1, 0x47, 0x40, 1, 1, 1, 1, 1,
-};
-void Intro_SetupScreen() {  // 828000
-  nmi_disable_core_updates = 0x80;
-  EnableForceBlank();
-  TM_copy = 16;
-  TS_copy = 0;
-  Intro_InitializeBackgroundSettings();
-  CGWSEL_copy = 0x20;
-  load_chr_halfslot_even_odd = 20;
-  Graphics_LoadChrHalfSlot();
-  load_chr_halfslot_even_odd = 0;
-  LoadOWMusicIfNeeded();
-
-  // why 17?
-  for(int i = 0; i < 17; i++)
-    main_palette_buffer[144 + i] = 0x7fff;
-
-  for (int i = 0; i < 17; i++)
-    g_zenv.vram[0x27f0 + i] = 0;
-
-  R16 = 0x1ffe;
-  R18 = 0x1bfe;
-}
-
-void Intro_LoadTextPointersAndPalettes() {  // 828116
-  Text_GenerateMessagePointers();
-  Overworld_LoadAllPalettes();
-}
-
-void Credits_LoadScene_Overworld_PrepGFX() {  // 828604
-  EnableForceBlank();
-  EraseTileMaps_normal();
-  CGWSEL_copy = 0x82;
-  int k = submodule_index >> 1;
-  dungeon_room_index = kEnding_Tab1[k];
-
-  if (k != 6 && k != 15)
-    LoadOverworldFromDungeon();
-  else
-    Overworld_EnterSpecialArea();
-  music_control = 0;
-  sound_effect_ambient = 0;
-
-  int t = BYTE(overworld_screen_index) & ~0x40;
-  DecompressAnimatedOverworldTiles((t == 3 || t == 5 || t == 7) ? 0x58 : 0x5a);
-
-  k = submodule_index >> 1;
-  sprite_graphics_index = kEnding_SpritePack[k];
-  uint8 sprpal = kEnding_SpritePal[k];
-  InitializeTilesets();
-  OverworldLoadScreensPaletteSet();
-  Overworld_LoadPalettes(GetOverworldBgPalette(BYTE(overworld_screen_index)), sprpal);
-
-  hud_palette = 1;
-  Palette_Load_HUD();
-  if (!submodule_index)
-    TransferFontToVRAM();
-  Overworld_LoadPalettesInner();
-  Overworld_SetFixedColAndScroll();
-  if (BYTE(overworld_screen_index) >= 128)
-    Palette_SetOwBgColor();
-  BGMODE_copy = 9;
-  subsubmodule_index++;
-}
-
-void Credits_LoadScene_Overworld_Overlay() {  // 828697
-  Overworld_LoadOverlays2();
-  music_control = 0;
-  sound_effect_ambient = 0;
-  submodule_index--;
-  subsubmodule_index++;
-}
-
-void Credits_LoadScene_Overworld_LoadMap() {  // 8286a5
-  Overworld_LoadAndBuildScreen();
-  Credits_PrepAndLoadSprites();
-  R16 = 0;
-  subsubmodule_index = 0;
-}
-
-void Credits_OperateScrollingAndTileMap() {  // 8286b3
-  Credits_HandleCameraScrollControl();
-  if (BYTE(overworld_screen_trans_dir_bits2))
-    OverworldHandleMapScroll();
-}
-
-void Credits_LoadCoolBackground() {  // 8286c0
-  main_tile_theme_index = 33;
-  aux_tile_theme_index = 59;
-  sprite_graphics_index = 45;
-  InitializeTilesets();
-  BYTE(overworld_screen_index) = 0x5b;
-  Overworld_LoadPalettes(GetOverworldBgPalette(BYTE(overworld_screen_index)), 0x13);
-  overworld_palette_aux2_bp5to7_hi = 3;
-  Palette_Load_OWBG2();
-  Overworld_CopyPalettesToCache();
-  Overworld_LoadOverlays2();
-  BG1VOFS_copy2 = 0;
-  BG1HOFS_copy2 = 0;
-  submodule_index--;
-}
-
-void Credits_LoadScene_Dungeon() {  // 8286fd
-  EnableForceBlank();
-  EraseTileMaps_normal();
-  WORD(which_entrance) = kEnding_Tab1[submodule_index >> 1];
-
-  Dungeon_LoadEntrance();
-  dung_num_lit_torches = 0;
-  hdr_dungeon_dark_with_lantern = 0;
-  Dungeon_LoadAndDrawRoom();
-  DecompressAnimatedDungeonTiles(kDungAnimatedTiles[main_tile_theme_index]);
-
-  int i = submodule_index >> 1;
-  sprite_graphics_index = kEnding_SpritePack[i];
-  const DungPalInfo *dpi = GetDungPalInfo(kEnding_SpritePal[i] & 0x3f);
-  palette_sp5l = dpi->pal2;
-  palette_sp6l = dpi->pal3;
-  misc_sprites_graphics_index = 10;
-  InitializeTilesets();
-  palette_sp6r_indoors = 10;
-  Dungeon_LoadPalettes();
-  BGMODE_copy = 9;
-  R16 = 0;
-  INIDISP_copy = 0;
-  submodule_index++;
-  Credits_PrepAndLoadSprites();
-}
-
-void Module18_GanonEmerges() {  // 829edc
-  uint16 hofs2 = BG2HOFS_copy2;
-  uint16 vofs2 = BG2VOFS_copy2;
-  uint16 hofs1 = BG1HOFS_copy2;
-  uint16 vofs1 = BG1VOFS_copy2;
-
-  BG2HOFS_copy2 = BG2HOFS_copy = hofs2 + bg1_x_offset;
-  BG2VOFS_copy2 = BG2VOFS_copy = vofs2 + bg1_y_offset;
-  BG1HOFS_copy2 = BG1HOFS_copy = hofs1 + bg1_x_offset;
-  BG1VOFS_copy2 = BG1VOFS_copy = vofs1 + bg1_y_offset;
-  Sprite_Main();
-  BG1VOFS_copy2 = vofs1;
-  BG1HOFS_copy2 = hofs1;
-  BG2VOFS_copy2 = vofs2;
-  BG2HOFS_copy2 = hofs2;
-
-  switch (overworld_map_state) {
-  case 0:  // GetBirdForPursuit
-    Dungeon_HandleLayerEffect();
-    CallForDuckIndoors();
-    SaveDungeonKeys();
-    overworld_map_state++;
-    flag_is_link_immobilized++;
-    break;
-  case 1:  // PrepForPyramidLocation
-    Dungeon_HandleLayerEffect();
-    if (submodule_index == 10) {
-      overworld_screen_index = 91;
-      player_is_indoors = 0;
-      main_module_index = 24;
-      submodule_index = 0;
-      overworld_map_state = 2;
-    }
-    break;
-  case 2:  // FadeOutDungeonScreen
-    Dungeon_HandleLayerEffect();
-    if (--INIDISP_copy)
-      break;
-    EnableForceBlank();
-    overworld_map_state++;
-    Hud_RebuildIndoor();
-    link_x_vel = link_y_vel = 0;
-    break;
-  case 3:  // LOadPyramidArea
-    birdtravel_var1[0] = 8;
-    birdtravel_var1[1] = 0;
-    FluteMenu_LoadSelectedScreen();
-    LoadOWMusicIfNeeded();
-    music_control = 9;
-    break;
-  case 4:  // LoadAmbientOverlay
-    Overworld_LoadOverlayAndMap();
-    subsubmodule_index = 0;
-    break;
-  case 5:  // BrightenScreenThenSpawnBat
-    if (++INIDISP_copy == 15) {
-      dung_savegame_state_bits = 0;
-      flag_unk1 = 0;
-      Sprite_SpawnBatCrashCutscene();
-      link_direction_facing = 2;
-      saved_module_for_menu = 9;
-      player_is_indoors = 0;
-      overworld_map_state++;
-      subsubmodule_index = 128;
-      BYTE(cur_palace_index_x2) = 255;
-    }
-    break;
-  case 6:  // DelayForBatSmashIntoPyramid
-    break;
-  case 7:  // DelayPlayerDropOff
-    if (!--subsubmodule_index)
-      overworld_map_state++;
-    break;
-  case 8:  // DropOffPlayerAtPyramid
-    BirdTravel_Finish_Doit();
-    break;
-  }
-
-  LinkOam_Main();
-}
-
-void Module19_TriforceRoom() {  // 829fec
-  switch (subsubmodule_index) {
-  case 0:  //
-    Link_ResetProperties_A();
-    link_last_direction_moved_towards = 0;
-    music_control = 0xf1;
-    ResetTransitionPropsAndAdvance_ResetInterface();
-    break;
-  case 1:  //
-    ConditionalMosaicControl();
-    ApplyPaletteFilter_bounce();
-    break;
-  case 2:  //
-    EnableForceBlank();
-    LoadCreditsSongs();
-    dungeon_room_index = 0x189;
-    EraseTileMaps_normal();
-    Palette_RevertTranslucencySwap();
-    Overworld_EnterSpecialArea();
-    Overworld_LoadOverlays2();
-    subsubmodule_index++;
-    main_module_index = 25;
-    submodule_index = 0;
-    break;
-  case 3:  //
-    main_tile_theme_index = 36;
-    sprite_graphics_index = 125;
-    aux_tile_theme_index = 81;
-    InitializeTilesets();
-    Overworld_LoadAreaPalettesEx(4);
-    Overworld_LoadPalettes(14, 0);
-    SpecialOverworld_CopyPalettesToCache();
-    subsubmodule_index++;
-    break;
-  case 4: { //
-    uint8 bak0 = subsubmodule_index;
-    Module08_02_LoadAndAdvance();
-    subsubmodule_index = bak0 + 1;
-    INIDISP_copy = 15;
-    palette_filter_countdown = 31;
-    mosaic_target_level = 0;
-    HIBYTE(BG1HOFS_copy2) = 1;
-    CGWSEL_copy = 2;
-    CGADSUB_copy = 50;
-    mosaic_level = 240;
-    BYTE(link_y_coord) = 236;
-    BYTE(link_x_coord) = 120;
-    link_is_on_lower_level = 2;
-    music_control = 32;
-    main_module_index = 25;
-    submodule_index = 0;
-    break;
-  }
-  case 5:  //
-    link_direction = 8;
-    link_direction_last = 8;
-    link_direction_facing = 0;
-    if (BYTE(link_y_coord) < 192) {
-      link_direction = 0;
-      link_direction_last = 0;
-      link_animation_steps = 0;
-      subsubmodule_index++;
-    }
-    break;
-  case 6:  //
-    if (!(palette_filter_countdown & 1) && mosaic_level != 0)
-      mosaic_level -= 0x10;
-    BGMODE_copy = 9;
-    MOSAIC_copy = mosaic_level | 7;
-    ApplyPaletteFilter_bounce();
-    break;
-  case 7:  //
-    TriforceRoom_PrepGFXSlotForPoly();
-    dialogue_message_index = 0x173;
-    Main_ShowTextMessage();
-    RenderText();
-    BYTE(R16) = 0x80;
-    main_module_index = 25;
-    subsubmodule_index++;
-    break;
-  case 8:  //
-  case 10:  //
-    AdvancePolyhedral();
-    if (subsubmodule_index == 11) {
-      music_control = 33;
-      main_module_index = 25;
-      link_direction = 0;
-      link_direction_last = 0;
-      submodule_index++;
-    }
-    break;
-  case 9:  //
-    AdvancePolyhedral();
-    RenderText();
-    if (!submodule_index) {
-      overworld_map_state = 0;
-      main_module_index = 25;
-      subsubmodule_index++;
-    }
-    break;
-  case 11:  //
-    AdvancePolyhedral();
-    TriforceRoom_LinkApproachTriforce();
-    if (subsubmodule_index == 12) {
-      link_direction = 0;
-      link_direction_last = 0;
-    }
-    break;
-  case 12:  //
-    AdvancePolyhedral();
-    if (!--BYTE(R16)) {
-      Palette_AnimGetMasterSword2();
-      submodule_index++;
-    }
-    break;
-  case 13:  //
-    AdvancePolyhedral();
-    PaletteFilter_BlindingWhiteTriforce();
-    if (BYTE(darkening_or_lightening_screen) == 255)
-      subsubmodule_index++;
-    break;
-  case 14:  //
-    if (!--INIDISP_copy) {
-      main_module_index = 26;
-      submodule_index = 0;
-      subsubmodule_index = 0;
-      irq_flag = 255;
-      is_nmi_thread_active = 0;
-      nmi_flag_update_polyhedral = 0;
-      savegame_is_darkworld = 0;
-    }
-    break;
-  }
-  BG1HOFS_copy = BG1HOFS_copy2;
-  BG1VOFS_copy = BG1VOFS_copy2;
-  BG2HOFS_copy = BG2HOFS_copy2;
-  BG2VOFS_copy = BG2VOFS_copy2;
-  if (subsubmodule_index < 7 || subsubmodule_index >= 11) {
-    Link_HandleVelocity();
-    Link_HandleMovingAnimation_FullLongEntry();
-  }
-  LinkOam_Main();
-}
-
-void Intro_InitializeBackgroundSettings() {  // 82c500
-  BGMODE_copy = 9;
-  MOSAIC_copy = 0;
-  zelda_ppu_write(BG1SC, 0x13);
-  zelda_ppu_write(BG2SC, 3);
-  zelda_ppu_write(BG3SC, 0x63);
-  CGADSUB_copy = 32;
-  COLDATA_copy0 = 32;
-  COLDATA_copy1 = 64;
-  COLDATA_copy2 = 128;
-}
-
-void Polyhedral_InitializeThread() {  // 89f7de
-  static const uint8 kPolyThreadInit[13] = { 9, 0, 0x1f, 0, 0, 0, 0, 0, 0, 0x30, 0x1d, 0xf8, 9 };
-  memset(kPolyThreadRam, 0, 256);
-  thread_other_stack = 0x1f31;
-  memcpy(&g_ram[0x1f32], kPolyThreadInit, 13);
-}
-
-void Module00_Intro() {  // 8cc120
-  uint8 skip_at = enhanced_features0 & kFeatures0_SkipIntroOnKeypress ? 4 : 8;
-
-  if (submodule_index >= skip_at && ((filtered_joypad_L & 0xc0 | filtered_joypad_H) & 0xd0)) {
-    FadeMusicAndResetSRAMMirror();
-    return;
-  }
-  switch (submodule_index) {
-  case 0: Intro_Init(); break;
-  case 1: Intro_Init_Continue(); break;
-  case 10:
-  case 2: Intro_InitializeTriforcePolyThread(); break;
-  case 3:
-  case 4:
-  case 9:
-  case 11: Intro_HandleAllTriforceAnimations(); break;
-  case 5: IntroZeldaFadein(); break;
-  case 6: Intro_SwordComingDown(); break;
-  case 7: Intro_FadeInBg(); break;
-  case 8: Intro_WaitPlayer(); break;
-  }
-}
-
-void Intro_Init() {  // 8cc15d
-  Intro_SetupScreen();
-  INIDISP_copy = 15;
-  subsubmodule_index = 0;
-  flag_update_cgram_in_nmi++;
-  submodule_index++;
-  sound_effect_2 = 10;
-  Intro_Init_Continue();
-}
-
-void Intro_Init_Continue() {  // 8cc170
-  Intro_DisplayLogo();
-  int t = subsubmodule_index++;
-  if (t >= 11) {
-    if (--INIDISP_copy)
-      return;
-    Intro_InitializeMemory_darken();
-    return;
-  }
-  switch (t) {
-  case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7:
-    Intro_Clear1kbBlocksOfWRAM();
-    break;
-  case 8: Intro_LoadTextPointersAndPalettes(); break;
-  case 9: LoadItemGFXIntoWRAM4BPPBuffer(); break;
-  case 10:LoadFollowerGraphics(); break;
-  }
-}
-
-void Intro_Clear1kbBlocksOfWRAM() {  // 8cc1a0
-  uint16 i = R16;
-  uint8 *dst = (uint8 *)&g_ram[0x2000];
-  do {
-    for (int j = 0; j < 15; j++)
-      WORD(dst[i + j * 0x2000]) = 0;
-  } while ((i -= 2) != R18);
-  R16 = i;
-  R18 = i - 0x400;
-}
-
-void Intro_InitializeMemory_darken() {  // 8cc1f5
-  EnableForceBlank();
-  EraseTileMaps_normal();
-  main_tile_theme_index = 35;
-  sprite_graphics_index = 125;
-  aux_tile_theme_index = 81;
-  misc_sprites_graphics_index = 8;
-  LoadDefaultGraphics();
-  InitializeTilesets();
-  DecompressAnimatedDungeonTiles(0x5d);
-  bg_tile_animation_countdown = 2;
-  BYTE(overworld_screen_index) = 0;
-  palette_main_indoors = 0;
-  overworld_palette_aux3_bp7_lo = 0;
-  R16 = 0;
-  R18 = 0;
-  darkening_or_lightening_screen = 2;
-  palette_filter_countdown = 31;
-  mosaic_target_level = 0;
-  submodule_index++;
-}
-
-void IntroZeldaFadein() {  // 8cc25c
-  Intro_HandleAllTriforceAnimations();
-  if (!(frame_counter & 1))
-    return;
-  Palette_FadeIntroOneStep();
-  if (BYTE(palette_filter_countdown) == 0) {
-    subsubmodule_index = 42;
-    submodule_index++;
-    Intro_SetupSwordAndIntroFlash();
-  } else if (BYTE(palette_filter_countdown) == 13) {
-    TM_copy = 0x15;
-    TS_copy = 0;
-  }
-}
-
-void Intro_FadeInBg() {  // 8cc284
-  Intro_PeriodicSwordAndIntroFlash();
-  Intro_HandleAllTriforceAnimations();
-  if (BYTE(palette_filter_countdown)) {
-    if (frame_counter & 1)
-      Palette_FadeIntro2();
-  } else {
-    if ((filtered_joypad_L & 0xc0 | filtered_joypad_H) & 0xd0)
-      FadeMusicAndResetSRAMMirror();
-    else {
-      if (!--subsubmodule_index)
-        submodule_index++;
-    }
-  }
-}
-
-void Intro_SwordComingDown() {  // 8cc2ae
-  Intro_HandleAllTriforceAnimations();
-  intro_did_run_step = 0;
-  is_nmi_thread_active = 0;
-  Intro_PeriodicSwordAndIntroFlash();
-  if (!--subsubmodule_index) {
-    submodule_index++;
-    CGWSEL_copy = 2;
-    CGADSUB_copy = 0x22;
-    palette_filter_countdown = 31;
-    TS_copy = 2;
-  }
-}
-
-void Intro_WaitPlayer() {  // 8cc2d4
-  Intro_HandleAllTriforceAnimations();
-  intro_did_run_step = 0;
-  is_nmi_thread_active = 0;
-  Intro_PeriodicSwordAndIntroFlash();
-  if (!--subsubmodule_index) {
-    submodule_index++;
-    main_module_index = 20;
-    submodule_index = 0;
-    BYTE(link_x_coord) = 0;
-  }
-}
-
-void FadeMusicAndResetSRAMMirror() {  // 8cc2f0
-  irq_flag = 255;
-  TM_copy = 0x15;
-  TS_copy = 0;
-  player_is_indoors = 0;
-  music_control = 0xf1;
-  SetBackdropcolorBlack();
-
-  memset(&link_y_coord, 0, 0x70);
-  memset(save_dung_info, 0, 256 * 5);
-
-  main_module_index = 1;
-  death_var4 = 1;
-  submodule_index = 0;
-}
-
-void Intro_InitializeTriforcePolyThread() {  // 8cc33c
-  misc_sprites_graphics_index = 8;
-  LoadCommonSprites();
-  Intro_InitGfx_Helper();
-  intro_sprite_isinited[0] = 1;
-  intro_sprite_isinited[1] = 1;
-  intro_sprite_isinited[2] = 1;
-  intro_sprite_subtype[0] = 0;
-  intro_sprite_subtype[1] = 0;
-  intro_sprite_subtype[2] = 0;
-  intro_sprite_isinited[4] = 1;
-  intro_sprite_subtype[4] = 2;
-  INIDISP_copy = 15;
-  submodule_index++;
-}
-
-void Intro_InitGfx_Helper() {  // 8cc36f
-  Polyhedral_InitializeThread();
-  LoadTriforceSpritePalette();
-  virq_trigger = 0x90;
-  poly_config1 = 255;
-  poly_base_x = 32;
-  poly_base_y = 32;
-  BYTE(poly_var1) = 32;
-  poly_a = 0xA0;
-  poly_b = 0x60;
-  poly_config_color_mode = 1;
-  poly_which_model = 1;
-  is_nmi_thread_active = 1;
-  intro_did_run_step = 1;
-  memset(&intro_step_index, 0, 7 * 16);
-}
-
-void LoadTriforceSpritePalette() {  // 8cc3bd
-  memcpy(main_palette_buffer + 0xd0, kPolyhedralPalette, 16);
-  flag_update_cgram_in_nmi++;
-}
-
-void Intro_HandleAllTriforceAnimations() {  // 8cc404
-  intro_frame_ctr++;
-  Intro_AnimateTriforce();
-  Scene_AnimateEverySprite();
-}
-
-void Scene_AnimateEverySprite() {  // 8cc412
-  intro_sprite_alloc = 0x800;
-  for (int k = 7; k >= 0; k--)
-    Intro_AnimOneObj(k);
-}
-
-void Intro_AnimateTriforce() {  // 8cc435
-  is_nmi_thread_active = 1;
-  if (!intro_did_run_step) {
-    Intro_RunStep();
-    intro_did_run_step = 1;
-  }
-}
-
-void Intro_RunStep() {  // 8cc448
-  switch (intro_step_index) {
-  case 0:
-    if (++intro_step_timer == 64)
-      intro_step_index++;
-    poly_b += 5, poly_a += 3;
-    break;
-  case 1:
-    if (poly_config1 < 2) {
-      poly_config1 = 0;
-      intro_step_index++;
-      intro_step_timer = 64;
-      return;
-    }
-    poly_config1 -= 2;
-    poly_b += 5;
-    poly_a += 3;
-    if (poly_config1 < 225)
-      submodule_index = 4;
-    if (poly_config1 == 113)
-      music_control = 1;
-    break;
-  case 2:
-    if (!--intro_step_timer) {
-      intro_step_index++;
-    } else {
-      poly_b += 5, poly_a += 3;
-    }
-    break;
-  case 3:
-    if (poly_b >= 250 && poly_a >= 252) {
-      intro_step_index++;
-      intro_step_timer = 32;
-    } else {
-      poly_b += 5, poly_a += 3;
-    }
-    break;
-  case 4:
-    poly_b = 0;
-    poly_a = 0;
-    if (!--intro_step_timer) {
-      intro_step_index++;
-      intro_sprite_isinited[5] = 1;
-      intro_sprite_subtype[5] = 3;
-      TM_copy = 0x10;
-      TS_copy = 5;
-      CGWSEL_copy = 2;
-      CGADSUB_copy = 0x31;
-      subsubmodule_index = 0;
-      flag_update_cgram_in_nmi++;
-      nmi_load_bg_from_vram = 3;
-      submodule_index++;
-    }
-    break;
-  }
-
-}
-
-void Intro_AnimOneObj(int k) {  // 8cc534
-  switch (intro_sprite_isinited[k]) {
-  case 0:
-    break;
-  case 1:
-    switch (intro_sprite_subtype[k]) {
-    case 0: Intro_SpriteType_A_0(k); break;
-    case 1: EXIT_0CCA90(k); break;
-    case 2: InitializeSceneSprite_Copyright(k); break;
-    case 3: InitializeSceneSprite_Sparkle(k); break;
-    case 4:
-    case 5:
-    case 6: InitializeSceneSprite_TriforceRoomTriangle(k); break;
-    case 7: InitializeSceneSprite_CreditsTriangle(k); break;
-    }
-    break;
-  case 2:
-    switch (intro_sprite_subtype[k]) {
-    case 0: Intro_SpriteType_B_0(k); break;
-    case 1: EXIT_0CCA90(k); break;
-    case 2: AnimateSceneSprite_Copyright(k); break;
-    case 3: AnimateSceneSprite_Sparkle(k); break;
-    case 4:
-    case 5:
-    case 6: Intro_SpriteType_B_456(k); break;
-    case 7: AnimateSceneSprite_CreditsTriangle(k); break;
-    }
-    break;
-  }
-}
-
-void Intro_SpriteType_A_0(int k) {  // 8cc57e
-  static const int16 kIntroSprite0_X[3] = { -38, 95, 230 };
-  static const int16 kIntroSprite0_Y[3] = { 200, -67, 200 };
-  intro_x_lo[k] = kIntroSprite0_X[k];
-  intro_x_hi[k] = kIntroSprite0_X[k] >> 8;
-  intro_y_lo[k] = kIntroSprite0_Y[k];
-  intro_y_hi[k] = kIntroSprite0_Y[k] >> 8;
-  intro_x_vel[k] = kIntroSprite0_Xvel[k];
-  intro_y_vel[k] = kIntroSprite0_Yvel[k];
-  intro_sprite_isinited[k]++;
-}
-
-void Intro_SpriteType_B_0(int k) {  // 8cc5b1
-  static const uint8 kIntroSprite0_XLimit[3] = { 75, 95, 117 };
-  static const uint8 kIntroSprite0_YLimit[3] = { 88, 48, 88 };
-
-  AnimateSceneSprite_DrawTriangle(k);
-  AnimateSceneSprite_MoveTriangle(k);
-  if (intro_step_index != 5) {
-    if (!(intro_frame_ctr & 31)) {
-      intro_x_vel[k] += kIntroSprite0_Xvel[k];
-      intro_y_vel[k] += kIntroSprite0_Yvel[k];
-    }
-    if (intro_x_lo[k] == kIntroSprite0_XLimit[k])
-      intro_x_vel[k] = 0;
-    if (intro_y_lo[k] == kIntroSprite0_YLimit[k])
-      intro_y_vel[k] = 0;
-  } else {
-    intro_x_vel[k] = 0;
-    intro_y_vel[k] = 0;
-  }
-}
-
-void AnimateSceneSprite_DrawTriangle(int k) {  // 8cc70f
-  static const IntroSpriteEnt kIntroSprite0_Left_Ents[16] = {
-    { 0,  0, 0x80, 0x1b, 2},
-    {16,  0, 0x82, 0x1b, 2},
-    {32,  0, 0x84, 0x1b, 2},
-    {48,  0, 0x86, 0x1b, 2},
-    { 0, 16, 0xa0, 0x1b, 2},
-    {16, 16, 0xa2, 0x1b, 2},
-    {32, 16, 0xa4, 0x1b, 2},
-    {48, 16, 0xa6, 0x1b, 2},
-    { 0, 32, 0x88, 0x1b, 2},
-    {16, 32, 0x8a, 0x1b, 2},
-    {32, 32, 0x8c, 0x1b, 2},
-    {48, 32, 0x8e, 0x1b, 2},
-    { 0, 48, 0xa8, 0x1b, 2},
-    {16, 48, 0xaa, 0x1b, 2},
-    {32, 48, 0xac, 0x1b, 2},
-    {48, 48, 0xae, 0x1b, 2},
-  };
-  static const IntroSpriteEnt kIntroSprite0_Right_Ents[16] = {
-    {48,  0, 0x80, 0x5b, 2},
-    {32,  0, 0x82, 0x5b, 2},
-    {16,  0, 0x84, 0x5b, 2},
-    { 0,  0, 0x86, 0x5b, 2},
-    {48, 16, 0xa0, 0x5b, 2},
-    {32, 16, 0xa2, 0x5b, 2},
-    {16, 16, 0xa4, 0x5b, 2},
-    { 0, 16, 0xa6, 0x5b, 2},
-    {48, 32, 0x88, 0x5b, 2},
-    {32, 32, 0x8a, 0x5b, 2},
-    {16, 32, 0x8c, 0x5b, 2},
-    { 0, 32, 0x8e, 0x5b, 2},
-    {48, 48, 0xa8, 0x5b, 2},
-    {32, 48, 0xaa, 0x5b, 2},
-    {16, 48, 0xac, 0x5b, 2},
-    { 0, 48, 0xae, 0x5b, 2},
-  };
-  AnimateSceneSprite_AddObjectsToOamBuffer(k, k == 2 ? kIntroSprite0_Right_Ents : kIntroSprite0_Left_Ents, 16);
-}
-
-void Intro_CopySpriteType4ToOam(int k) {  // 8cc82f
-  static const IntroSpriteEnt kIntroTriforceOam_Left[16] = {
-    { 0,  0, 0x80, 0x2b, 2},
-    {16,  0, 0x82, 0x2b, 2},
-    {32,  0, 0x84, 0x2b, 2},
-    {48,  0, 0x86, 0x2b, 2},
-    { 0, 16, 0xa0, 0x2b, 2},
-    {16, 16, 0xa2, 0x2b, 2},
-    {32, 16, 0xa4, 0x2b, 2},
-    {48, 16, 0xa6, 0x2b, 2},
-    { 0, 32, 0x88, 0x2b, 2},
-    {16, 32, 0x8a, 0x2b, 2},
-    {32, 32, 0x8c, 0x2b, 2},
-    {48, 32, 0x8e, 0x2b, 2},
-    { 0, 48, 0xa8, 0x2b, 2},
-    {16, 48, 0xaa, 0x2b, 2},
-    {32, 48, 0xac, 0x2b, 2},
-    {48, 48, 0xae, 0x2b, 2},
-  };
-  static const IntroSpriteEnt kIntroTriforceOam_Right[16] = {
-    {48,  0, 0x80, 0x6b, 2},
-    {32,  0, 0x82, 0x6b, 2},
-    {16,  0, 0x84, 0x6b, 2},
-    { 0,  0, 0x86, 0x6b, 2},
-    {48, 16, 0xa0, 0x6b, 2},
-    {32, 16, 0xa2, 0x6b, 2},
-    {16, 16, 0xa4, 0x6b, 2},
-    { 0, 16, 0xa6, 0x6b, 2},
-    {48, 32, 0x88, 0x6b, 2},
-    {32, 32, 0x8a, 0x6b, 2},
-    {16, 32, 0x8c, 0x6b, 2},
-    { 0, 32, 0x8e, 0x6b, 2},
-    {48, 48, 0xa8, 0x6b, 2},
-    {32, 48, 0xaa, 0x6b, 2},
-    {16, 48, 0xac, 0x6b, 2},
-    { 0, 48, 0xae, 0x6b, 2},
-  };
-  AnimateSceneSprite_AddObjectsToOamBuffer(k, k == 2 ? kIntroTriforceOam_Right : kIntroTriforceOam_Left, 16);
-}
-
-void EXIT_0CCA90(int k) {  // 8cc84f
-  // empty
-}
-
-void InitializeSceneSprite_Copyright(int k) {  // 8cc850
-  intro_x_lo[k] = 76;
-  intro_x_hi[k] = 0;
-  intro_y_lo[k] = 184;
-  intro_y_hi[k] = 0;
-  intro_sprite_isinited[k]++;
-}
-
-void AnimateSceneSprite_Copyright(int k) {  // 8cc864
-  static const IntroSpriteEnt kIntroSprite2_Ents[13] = {
-    { 0, 0, 0x40, 0x0a, 0},
-    { 8, 0, 0x41, 0x0a, 0},
-    {16, 0, 0x42, 0x0a, 0},
-    {24, 0, 0x68, 0x0a, 0},
-    {32, 0, 0x41, 0x0a, 0},
-    {40, 0, 0x42, 0x0a, 0},
-    {48, 0, 0x43, 0x0a, 0},
-    {56, 0, 0x44, 0x0a, 0},
-    {64, 0, 0x50, 0x0a, 0},
-    {72, 0, 0x51, 0x0a, 0},
-    {80, 0, 0x52, 0x0a, 0},
-    {88, 0, 0x53, 0x0a, 0},
-    {96, 0, 0x54, 0x0a, 0},
-  };
-  AnimateSceneSprite_AddObjectsToOamBuffer(k, kIntroSprite2_Ents, 13);
-}
-
-void InitializeSceneSprite_Sparkle(int k) {  // 8cc8e2
-  int j = intro_frame_ctr >> 5 & 3;
-  intro_x_lo[k] = kIntroSprite3_X[j];
-  intro_x_hi[k] = 0;
-  intro_y_lo[k] = kIntroSprite3_Y[j];
-  intro_y_hi[k] = 0;
-  intro_sprite_isinited[k]++;
-}
-
-void AnimateSceneSprite_Sparkle(int k) {  // 8cc90d
-  static const IntroSpriteEnt kIntroSprite3_Ents[4] = {
-    { 0,  0, 0x80, 0x34, 0},
-    { 0,  0, 0xb7, 0x34, 0},
-    {-4, -3, 0x64, 0x38, 2},
-    {-4, -3, 0x62, 0x34, 2},
-  };
-  if (intro_sprite_state[k] < 4)
-    AnimateSceneSprite_AddObjectsToOamBuffer(k, kIntroSprite3_Ents + intro_sprite_state[k], 1);
-
-  intro_sprite_state[k] = kIntroSprite3_State[intro_frame_ctr >> 2 & 7];
-  int j = intro_frame_ctr >> 5 & 3;
-  intro_x_lo[k] = kIntroSprite3_X[j];
-  intro_y_lo[k] = kIntroSprite3_Y[j];
-}
-
-void AnimateSceneSprite_AddObjectsToOamBuffer(int k, const IntroSpriteEnt *src, int num) {  // 8cc972
-  uint16 x = intro_x_hi[k] << 8 | intro_x_lo[k];
-  uint16 y = intro_y_hi[k] << 8 | intro_y_lo[k];
-  OamEnt *oam = (OamEnt *)&g_ram[intro_sprite_alloc];
-  intro_sprite_alloc += num * 4;
-  do {
-    SetOamHelper0(oam, x + src->x, y + src->y, src->charnum, src->flags, src->ext);
-  } while (oam++, src++, --num);
-}
-
-void AnimateSceneSprite_MoveTriangle(int k) {  // 8cc9f1
-  if (intro_x_vel[k] != 0) {
-    uint32 t = intro_x_subpixel[k] + (intro_x_lo[k] << 8) + (intro_x_hi[k] << 16) + ((int8)intro_x_vel[k] << 4);
-    intro_x_subpixel[k] = t, intro_x_lo[k] = t >> 8, intro_x_hi[k] = t >> 16;
-  }
-  if (intro_y_vel[k] != 0) {
-    uint32 t = intro_y_subpixel[k] + (intro_y_lo[k] << 8) + (intro_y_hi[k] << 16) + ((int8)intro_y_vel[k] << 4);
-    intro_y_subpixel[k] = t, intro_y_lo[k] = t >> 8, intro_y_hi[k] = t >> 16;
-  }
-}
-
-void TriforceRoom_PrepGFXSlotForPoly() {  // 8cca54
-  misc_sprites_graphics_index = 8;
-  LoadCommonSprites();
-  Intro_InitGfx_Helper();
-  intro_sprite_isinited[0] = 1;
-  intro_sprite_isinited[1] = 1;
-  intro_sprite_isinited[2] = 1;
-  intro_sprite_subtype[0] = 4;
-  intro_sprite_subtype[1] = 5;
-  intro_sprite_subtype[2] = 6;
-  INIDISP_copy = 15;
-  submodule_index++;
-}
-
-void Credits_InitializePolyhedral() {  // 8cca81
-  misc_sprites_graphics_index = 8;
-  LoadCommonSprites();
-  Intro_InitGfx_Helper();
-  poly_config1 = 0;
-  intro_sprite_isinited[0] = 1;
-  intro_sprite_isinited[1] = 1;
-  intro_sprite_isinited[2] = 1;
-  intro_sprite_subtype[0] = 7;
-  intro_sprite_subtype[1] = 7;
-  intro_sprite_subtype[2] = 7;
-  INIDISP_copy = 15;
-  submodule_index++;
-}
-
-void AdvancePolyhedral() {  // 8ccab1
-  TriforceRoom_HandlePoly();
-  Scene_AnimateEverySprite();
-}
-
-void TriforceRoom_HandlePoly() {  // 8ccabc
-  is_nmi_thread_active = 1;
-  intro_want_double_ret = 1;
-  if (intro_did_run_step)
-    return;
-  switch (intro_step_index) {
-  case 0:
-    poly_config1 -= 2;
-    if (poly_config1 < 2) {
-      poly_config1 = 0;
-      intro_step_index++;
-      subsubmodule_index++;
-    }
-    // fall through
-  case 1:
-    if (subsubmodule_index >= 10) {
-      intro_step_index++;
-      intro_y_vel[1] = 5;
-    }
-    poly_b += 2, poly_a += 1;
-    break;
-  case 2:
-    triforce_ctr = 0x1c0;
-    if (poly_config1 < 128) {
-      poly_config1 += 1;
-    } else {
-      if ((poly_b - 10 & 0x7f) >= 92 &&
-          (uint8)(poly_a - 11) >= 220) {
-        poly_a = 0;
-        poly_b = 0;
-        subsubmodule_index++;
-        intro_step_index++;
-        sound_effect_1 = 44;
-        main_palette_buffer[0xd7] = 0x7fff;
-        flag_update_cgram_in_nmi++;
-        intro_step_timer = 6;
-        break;
-      }
-    }
-    poly_b += 5, poly_a += 3;
-    break;
-  case 3:
-    if (!--intro_step_timer) {
-      main_palette_buffer[0xd7] = kPolyhedralPalette[7];
-      flag_update_cgram_in_nmi++;
-      intro_step_index++;
-    }
-    break;
-  case 4:
-    break;
-  }
-  intro_did_run_step = 1;
-  intro_want_double_ret = 0;
-  intro_frame_ctr++;
-}
-
-void Credits_AnimateTheTriangles() {  // 8ccba2
-  intro_frame_ctr++;
-  is_nmi_thread_active = 1;
-  if (!intro_did_run_step) {
-    poly_b += 3;
-    poly_a += 1;
-    intro_did_run_step = 1;
-  }
-  Scene_AnimateEverySprite();
-}
-
-void InitializeSceneSprite_TriforceRoomTriangle(int k) {  // 8ccbe8
-  static const int16 kIntroTriforce_X[3] = { 0x4e, 0x5f, 0x72 };
-  static const int16 kIntroTriforce_Y[3] = { 0x9c, 0x9c, 0x9c };
-  static const int8 kIntroTriforce_Xvel[3] = { -2, 0, 2 };
-  static const int8 kIntroTriforce_Yvel[3] = { 4, -4, 4 };
-
-  intro_x_lo[k] = kIntroTriforce_X[k];
-  intro_x_hi[k] = 0;
-  intro_y_lo[k] = kIntroTriforce_Y[k];
-  intro_y_hi[k] = 0;
-  intro_x_vel[k] = kIntroTriforce_Xvel[k];
-  intro_y_vel[k] = kIntroTriforce_Yvel[k];
-  intro_sprite_isinited[k]++;
-}
-
-void Intro_SpriteType_B_456(int k) {  // 8ccc13
-  static const int8 kTriforce_Xacc[3] = { -1, 0, 1 };
-  static const int8 kTriforce_Yacc[3] = { -1, -1, -1 };
-  static const uint8 kTriforce_Yfinal2[3] = { 0x72, 0x66, 0x72 };
-
-  Intro_CopySpriteType4ToOam(k);
-  if (intro_want_double_ret)
-    return;
-  AnimateSceneSprite_MoveTriangle(k);
-  switch (intro_step_index) {
-  case 0:
-    if (!(intro_frame_ctr & 7))
-      intro_x_vel[k] += kTriforce_Xacc[k];
-    if (!(intro_frame_ctr & 3))
-      intro_y_vel[k] += kTriforce_Yacc[k];
-    break;
-  case 1:
-    intro_x_vel[k] = 0;
-    intro_y_vel[k] = 0;
-    break;
-  case 2:
-    if (!(intro_frame_ctr & 3))
-      AnimateTriforceRoomTriangle_HandleContracting(k);
-    if (kTriforce_Xfinal[k] == intro_x_lo[k])
-      intro_x_vel[k] = 0;
-    if (kTriforce_Yfinal[k] == intro_y_lo[k])
-      intro_y_vel[k] = 0;
-    break;
-  case 3:
-  case 4:
-    if (triforce_ctr == 0) {
-      intro_y_lo[k] = kTriforce_Yfinal2[k];
-    } else {
-      triforce_ctr -= 1;
-    }
-    break;
-  }
-}
-
-void AnimateTriforceRoomTriangle_HandleContracting(int k) {  // 8cccb0
-  uint8 new_vel = intro_x_vel[k] + (intro_x_lo[k] <= kTriforce_Xfinal[k] ? 1 : -1);
-  intro_x_vel[k] = (new_vel == 0x11) ? 0x10 : (new_vel == 0xef) ? 0xf0 : new_vel;
-  new_vel = intro_y_vel[k] + (intro_y_lo[k] <= kTriforce_Yfinal[k] ? 1 : -1);
-  intro_y_vel[k] = (new_vel == 0x11) ? 0x10 : (new_vel == 0xef) ? 0xf0 : new_vel;
-}
-
-void InitializeSceneSprite_CreditsTriangle(int k) {  // 8ccd19
-  static const uint8 kIntroSprite7_X[3] = { 0x29, 0x5f, 0x97 };
-  static const uint8 kIntroSprite7_Y[3] = { 0x70, 0x20, 0x70 };
-  intro_x_lo[k] = kIntroSprite7_X[k];
-  intro_x_hi[k] = 0;
-  intro_y_lo[k] = kIntroSprite7_Y[k];
-  intro_y_hi[k] = 0;
-  intro_sprite_isinited[k]++;
-}
-
-void AnimateSceneSprite_CreditsTriangle(int k) {  // 8ccd3e
-  static const int8 kIntroSprite7_XAcc[3] = { -1, 0, 1 };
-  static const int8 kIntroSprite7_YAcc[3] = { 1, -1, 1 };
-
-  LoadTriforceSpritePalette();
-  Intro_CopySpriteType4ToOam(k);
-  AnimateSceneSprite_MoveTriangle(k);
-  if (submodule_index != 36) {
-    intro_sprite_state[k] = 0;
-    return;
-  }
-  if (intro_sprite_state[k] != 80) {
-    intro_sprite_state[k]++;
-    intro_x_vel[k] += kIntroSprite7_XAcc[k];
-    intro_y_vel[k] += kIntroSprite7_YAcc[k];
-  }
-}
-
-void Intro_DisplayLogo() {  // 8ced82
-  static const uint8 kIntroLogo_X[4] = { 0x60, 0x70, 0x80, 0x88 };
-  static const uint8 kIntroLogo_Tile[4] = { 0x69, 0x6b, 0x6d, 0x6e };
-  for (int i = 0; i < 4; i++)
-    SetOamPlain(&oam_buf[i], kIntroLogo_X[i], 0x68, kIntroLogo_Tile[i], 0x32, 2);
-}
-
-void Intro_SetupSwordAndIntroFlash() {  // 8cfe45
-  intro_sword_19 = 7;
-  intro_sword_20 = 0;
-  intro_sword_21 = 0;
-  intro_sword_ypos = -130;
-
-  Intro_PeriodicSwordAndIntroFlash();
-}
-
-void Intro_PeriodicSwordAndIntroFlash() {  // 8cfe56
-  if (intro_sword_18)
-    intro_sword_18--;
-  SetBackdropcolorBlack();
-  if (intro_times_pal_flash) {
-    if ((intro_times_pal_flash & 3) != 0) {
-      (&COLDATA_copy0)[intro_sword_24] |= (enhanced_features0 & kFeatures0_DimFlashes) ? 0x05 : 0x1f;
-      intro_sword_24 = (intro_sword_24 == 2) ? 0 : intro_sword_24 + 1;
-    }
-    intro_times_pal_flash--;
-  }
-  OamEnt *oam = oam_buf + 0x52;
-  for (int j = 9; j >= 0; j--) {
-    static const uint8 kIntroSword_Char[10] = { 0, 2, 0x20, 0x22, 4, 6, 8, 0xa, 0xc, 0xe };
-    static const uint8 kIntroSword_X[10] = { 0x40, 0x40, 0x30, 0x50, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40 };
-    static const uint16 kIntroSword_Y[10] = { 0x10, 0x20, 0x28, 0x28, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80 };
-    uint16 y = intro_sword_ypos + kIntroSword_Y[j];
-    SetOamPlain(&oam[j], kIntroSword_X[j], ((y & 0xff00) ? 0xf8 : y) - 8, kIntroSword_Char[j], 0x21, 2);
-  }
-
-  if (intro_sword_ypos != 30) {
-    if (intro_sword_ypos == 0xffbe) {
-      sound_effect_1 = 1;
-    } else if (intro_sword_ypos == 14) {
-      WORD(intro_sword_24) = 0;
-      intro_times_pal_flash = 0x20;
-      sound_effect_1 = 0x2c;
-    }
-    intro_sword_ypos += 16;
-  }
-
-  switch (intro_sword_20 >> 1) {
-  case 0:
-    if (!intro_times_pal_flash && intro_sword_ypos == 30)
-      intro_sword_20 += 2;
-    break;
-  case 1: {
-    static const uint8 kSwordSparkle_Tab[8] = { 4, 4, 6, 6, 6, 4, 4 };
-
-    if (!intro_sword_18) {
-      intro_sword_19 -= 1;
-      if (sign8(intro_sword_19)) {
-        intro_sword_19 = 0;
-        intro_sword_18 = 2;
-        intro_sword_20 += 2;
-        return;
-      }
-      intro_sword_18 = kSwordSparkle_Tab[intro_sword_19];
-    }
-    static const uint8 kSwordSparkle_Char[7] = { 0x28, 0x37, 0x27, 0x36, 0x27, 0x37, 0x28 };
-    SetOamPlain(&oam_buf[0x50], 0x44, 0x43, kSwordSparkle_Char[intro_sword_19], 0x25, 0);
-    break;
-  }
-  case 2: {
-    static const uint8 kIntroSwordSparkle_Char[8] = { 0x26, 0x20, 0x24, 0x34, 0x25, 0x20, 0x35, 0x20 };
-    int k = intro_sword_19;
-    if (k >= 7)
-      return;
-    uint8 y = (intro_sword_21 < 0x50 ? intro_sword_21 : 0x4f) + intro_sword_ypos + 0x31;
-    SetOamPlain(&oam_buf[0x50], 0x42, y + 0, kIntroSwordSparkle_Char[k + 0], 0x23, 0);
-    SetOamPlain(&oam_buf[0x51], 0x42, y + 8, kIntroSwordSparkle_Char[k + 1], 0x23, 0);
-    if (intro_sword_18 == 0) {
-      intro_sword_21 += 4;
-      if (intro_sword_21 == 0x4 || intro_sword_21 == 0x48 || intro_sword_21 == 0x4c || intro_sword_21 == 0x58)
-        intro_sword_19 += 2;
-    }
-    break;
-  }
-  }
-}
-
-void Module1A_Credits() {  // 8e986e
-  oam_region_base[0] = 0x30;
-  oam_region_base[1] = 0x1d0;
-  oam_region_base[2] = 0x0;
-
-  kEndSequence_Funcs[submodule_index]();
-}
-
-void Credits_LoadNextScene_Overworld() {  // 8e9889
-  kEndSequence0_Funcs[subsubmodule_index]();
-  Credits_AddEndingSequenceText();
-}
-
-void Credits_LoadNextScene_Dungeon() {  // 8e9891
-  Credits_LoadScene_Dungeon();
-  Credits_AddEndingSequenceText();
-}
-
-void Credits_PrepAndLoadSprites() {  // 8e98b9
-  for (int k = 15; k >= 0; k--) {
-    SpritePrep_ResetProperties(k);
-    sprite_state[k] = 0;
-    sprite_flags5[k] = 0;
-    sprite_defl_bits[k] = 0;
-  }
-  int k = submodule_index >> 1;
-  switch (k) {
-init_sprites_0:
-  case 0: case 4: case 5: case 8: case 13: {
-    int idx = kEndingSprites_Idx[k];
-    int num = kEndingSprites_Idx[k + 1] - idx;
-    const uint16 *px = kEndingSprites_X + idx;
-    const uint16 *py = kEndingSprites_Y + idx;
-    for (k = num - 1; k >= 0; k--) {
-      sprcoll_x_size = sprcoll_y_size = 0xffff;
-      uint16 x = (swap16(overworld_area_index << 1) & 0xf00) + px[k];
-      uint16 y = (swap16(overworld_area_index >> 2) & 0xe00) + py[k];
-      Sprite_SetX(k, x);
-      Sprite_SetY(k, y);
-    }
-    break;
-  }
-init_sprites_1:
-  case 1: {
-    int idx = kEndingSprites_Idx[k];
-    int num = kEndingSprites_Idx[k + 1] - idx;
-    const uint16 *px = kEndingSprites_X + idx;
-    const uint16 *py = kEndingSprites_Y + idx;
-    byte_7E0FB1 = dungeon_room_index2 >> 3 & 254;
-    byte_7E0FB0 = (dungeon_room_index2 & 15) << 1;
-    for (k = num - 1; k >= 0; k--) {
-      sprcoll_x_size = sprcoll_y_size = 0xffff;
-      uint16 x = byte_7E0FB0 * 256 + px[k];
-      uint16 y = byte_7E0FB1 * 256 + py[k];
-      Sprite_SetX(k, x);
-      Sprite_SetY(k, y);
-    }
-    break;
-  }
-  case 2:
-    sprite_y_vel[6] = -16;
-    goto init_sprites_0;
-  case 3:
-    sprite_A[5] = 22;
-    sprite_y_vel[0] = -16;
-    sprite_y_vel[1] = 16;
-    sprite_head_dir[1] = 1;
-    for (int j = 2; j >= 0; j--) {
-      sprite_type[2 + j] = 0x57;
-      sprite_oam_flags[2 + j] = 0x31;
-    }
-    goto init_sprites_0;
-  case 6:
-    sprite_delay_main[0] = 255;
-    sprite_delay_main[1] = 255;
-    sprite_delay_main[2] = 255;
-    goto init_sprites_0;
-  case 7:
-    sprite_delay_main[1] = 255;
-    goto init_sprites_0;
-  case 9:
-    for (int j = 4; j >= 0; j--) {
-      sprite_delay_main[j] = j * 19;
-      sprite_state[j] = 0;
-    }
-    sprite_type[5] = 0x2e;
-    for (int j = 1; j >= 0; j--) {
-      sprite_type[7 + j] = 0x9f;
-      sprite_type[9 + j] = 0xa0;
-      sprite_flags2[7 + j] = 1;
-      sprite_flags2[9 + j] = 2;
-      sprite_flags3[7 + j] = 0x10;
-      sprite_flags3[9 + j] = 0x10;
-    }
-    goto init_sprites_0;
-  case 10:
-    sprite_delay_main[1] = 0x10;
-    sprite_delay_main[2] = 0x20;
-    sprite_oam_flags[3] = 8;
-    sprite_oam_flags[4] = 8;
-    goto init_sprites_1;
-  case 11:
-    sprite_oam_flags[4] = 0x79;
-    sprite_oam_flags[5] = 0x39;
-    sprite_D[1] = 1;
-    sprite_A[1] = 4;
-    goto init_sprites_1;
-  case 12:
-    for (int j = 1; j >= 0; j--) {
-      sprite_oam_flags[j + 3] = 0x39;
-      sprite_type[j + 3] = 0xb;
-      sprite_flags3[j + 3] = 0x10;
-      sprite_flags2[j + 3] = 1;
-    }
-    sprite_type[5] = 0x2a;
-    sprite_type[6] = 0x79;
-    sprite_ai_state[6] = 1;
-    sprite_z[6] = 5;
-    goto init_sprites_0;
-  case 14:
-    sprite_y_vel[5] = -16;
-    sprite_y_vel[6] = 16;
-    sprite_head_dir[6] = 1;
-    sprite_A[0] = 8;
-    for (int j = 3; j >= 0; j--)
-      sprite_y_vel[1 + j] = 4;
-    goto init_sprites_0;
-  case 15:
-    sprite_C[4] = 2;
-    sprite_y_vel[5] = 8;
-    sprite_delay_main[1] = 0x13;
-    sprite_delay_main[4] = 0x40;
-    goto init_sprites_0;
-  }
-}
-
-void Credits_ScrollScene_Overworld() {  // 8e9958
-
-  for (int k = 15; k >= 0; k--)
-    if (sprite_delay_main[k])
-      sprite_delay_main[k]--;
-
-  int i = submodule_index >> 1;
-
-  link_x_vel = link_y_vel = 0;
-  if (R16 >= 0x40 && !(R16 & 1)) {
-    if (BG2VOFS_copy2 != kEnding1_TargetScrollY[i])
-      link_y_vel = kEnding1_Yvel[i];
-    if (BG2HOFS_copy2 != kEnding1_TargetScrollX[i])
-      link_x_vel = kEnding1_Xvel[i];
-  }
-
-  Credits_OperateScrollingAndTileMap();
-  Credits_HandleSceneFade();
-}
-
-void Credits_ScrollScene_Dungeon() {  // 8e99c5
-  for (int k = 15; k >= 0; k--)
-    if (sprite_delay_main[k])
-      sprite_delay_main[k]--;
-
-  int i = submodule_index >> 1;
-  if (R16 >= 0x40 && !(R16 & 1)) {
-    if (BG2VOFS_copy2 != kEnding1_TargetScrollY[i])
-      BG2VOFS_copy2 += kEnding1_Yvel[i];
-    if (BG2HOFS_copy2 != kEnding1_TargetScrollX[i])
-      BG2HOFS_copy2 += kEnding1_Xvel[i];
-  }
-  Credits_HandleSceneFade();
-}
-
-void Credits_HandleSceneFade() {  // 8e9a2a
-  static const uint16 kEnding1_3_Tab0[16] = { 0x300, 0x280, 0x250, 0x2e0, 0x280, 0x250, 0x2c0, 0x2c0, 0x250, 0x250, 0x280, 0x250, 0x480, 0x400, 0x250, 0x500 };
-  static const uint8 kEndSequence_Case0_Tab1[12] = { 0x1e, 0x20, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x16, 0x16, 0x16, 0x16 };
-  static const uint8 kEndSequence_Case0_Tab0[12] = { 6, 3, 2, 2, 2, 2, 2, 2, 6, 6, 6, 6 };
-  static const uint8 kEndSequence_Case0_OamFlags[12] = { 0x3b, 0x31, 0x3d, 0x3f, 0x39, 0x3b, 0x37, 0x3d, 0x39, 0x37, 0x37, 0x39 };
-  int i = submodule_index >> 1, j, k;
-
-  switch (i) {
-  case 0:
-    for (int k = 11; k != 7; k--) {
-      sprite_oam_flags[k] = kEndSequence_Case0_OamFlags[k];
-      Credits_SpriteDraw_Single(k, kEndSequence_Case0_Tab0[k], kEndSequence_Case0_Tab1[k]);
-    }
-    for (int k = 7; k != 1; k--) {
-      sprite_oam_flags[k] = kEndSequence_Case0_OamFlags[k] | (frame_counter << 2 & 0x40);
-      Credits_SpriteDraw_Single(k, kEndSequence_Case0_Tab0[k], kEndSequence_Case0_Tab1[k]);
-    }
-    for (int k = 1; k >= 0; k--) {
-      sprite_oam_flags[k] = kEndSequence_Case0_OamFlags[k];
-      Credits_SpriteDraw_Single(k, kEndSequence_Case0_Tab0[k], kEndSequence_Case0_Tab1[k]);
-    }
-    break;
-  case 1:
-    Credits_SpriteDraw_Single(0, 3, 12);
-    Credits_SpriteDraw_DrawShadow(0);
-    k = 1;
-    sprite_type[k] = 0x73;
-    sprite_oam_flags[k] = 0x27;
-    sprite_E[k] = 2;
-    Credits_SpriteDraw_PreexistingSpriteDraw(k, 16);
-    break;
-  case 2: {
-    static const uint8 kEnding_Case2_Tab0[2] = { 0x20, 0x40 };
-    static const int8 kEnding_Case2_Tab1[2] = { 16, -16 };
-    static const int8 kEnding_Case2_Tab2[5] = { 0x28, 0x2a, 0x2c, 0x2e, 0x2c };
-    static const int8 kEnding_Case2_Tab3[5] = { 3, 3, 3, 3, 3 };
-    static const uint8 kEnding_Case2_Delay[2] = { 0x30, 0x10 };
-
-    BYTE(flag_travel_bird) = kEnding_Case2_Tab0[frame_counter >> 2 & 1];
-    k = 6;
-    j = sprite_x_vel[k] >> 7 & 1;
-    sprite_oam_flags[k] = (sprite_x_vel[k] + kEnding_Case2_Tab1[j]) >> 1 & 0x40 | 0x32;
-    Credits_SpriteDraw_Single(k, 2, 0x24);
-    Credits_SpriteDraw_CirclingBirds(k);
-    k -= 1;
-    sprite_oam_flags[k] = 0x31;
-    if (!sprite_delay_main[k]) {
-      j = sprite_A[k];
-      sprite_A[k] ^= 1;
-      sprite_delay_main[k] = kEnding_Case2_Delay[j];
-      sprite_graphics[k] = sprite_graphics[k] + 1 & 3;
-    }
-    Credits_SpriteDraw_Single(k, 2, 0x26);
-    k -= 1;
-    do {
-      if (!(frame_counter & 15))
-        sprite_graphics[k] ^= 1;
-      sprite_oam_flags[k] = 0x31;
-      Credits_SpriteDraw_Single(k, kEnding_Case2_Tab3[k], kEnding_Case2_Tab2[k]);
-      EndSequence_DrawShadow2(k);
-    } while (--k >= 0);
-    break;
-  }
-  case 3: {
-    static const uint8 kEnding_Case3_Gfx[4] = { 1, 2, 3, 2 };
-    for (k = 0; k < 5; k++) {
-      if (k < 2) {
-        sprite_type[k] = 1;
-        sprite_oam_flags[k] = 0xb;
-        Credits_SpriteDraw_SetShadowProp(k, 2);
-        sprite_z[k] = 48;
-        j = (frame_counter + (k ? 0x5f : 0x7d)) >> 2 & 3;
-        sprite_graphics[k] = kEnding_Case3_Gfx[j];
-        Credits_SpriteDraw_CirclingBirds(k);
-        Credits_SpriteDraw_PreexistingSpriteDraw(k, 12);
-      } else {
-        Credits_SpriteDraw_PreexistingSpriteDraw(k, 16);
-      }
-    }
-    Credits_SpriteDraw_Single(k, 2, 0x38);
-    Ending_Func2(k, 0x30);
-    k++;
-    Credits_SpriteDraw_Single(k, 3, 0x3a);
-    break;
-  }
-  case 4: {
-    static const uint8 kEnding_Case4_Tab1[2] = { 0x30, 0x32 };
-    static const uint8 kEnding_Case4_Tab0[2] = { 2, 2 };
-    static const uint8 kEnding_Case4_Ctr[2] = { 0x20, 0 };
-    static const int8 kEnding_Case4_XYvel[10] = { 0, -12, -16, -12, 0, 12, 16, 12, 0, -12 };
-    static const uint8 kEnding_Case4_DelayVel[24] = {
-      0x3b, 0x14, 0x1e, 0x1d, 0x2c, 0x2b, 0x42, 0x20, 0x27, 0x28, 0x2e, 0x38, 0x3a, 0x4c, 0x32, 0x44,
-      0x2e, 0x2f, 0x1e, 0x28, 0x47, 0x35, 0x32, 0x30,
-    };
-    k = 2;
-    sprite_oam_flags[k] = 0x35;
-    Credits_SpriteDraw_Single(k, 1, 0x3c);
-    k--;
-    do {
-      sprite_oam_flags[k] = (sprite_x_vel[k] - 1) >> 1 & 0x40 ^ 0x71;
-      sprite_graphics[k] = frame_counter >> 3 & 1;
-      if (R16 >= kEnding_Case4_Ctr[k] && !sprite_delay_main[k]) {
-        uint8 a = kEnding_Case4_DelayVel[sprite_A[k]];
-        sprite_delay_main[k] = a & 0xf8;
-        sprite_y_vel[k] = kEnding_Case4_XYvel[(a & 7) + 2];
-        sprite_x_vel[k] = kEnding_Case4_XYvel[a & 7];
-        sprite_A[k]++;
-      }
-      Credits_SpriteDraw_Single(k, kEnding_Case4_Tab0[k], kEnding_Case4_Tab1[k]);
-      EndSequence_DrawShadow2(k);
-      Sprite_MoveXY(k);
-    } while (--k >= 0);
-    break;
-  }
-  case 5: {
-    static const uint8 kEnding_Case5_Tab0[2] = { 0, 4 };
-    static const uint16 kEnding_Case5_Tab1[2] = { 0xa, 0x224 };
-    static const uint8 kEnding_Case5_Tab2[2] = { 10, 14 };
-    if (R16 == 0x200)
-      sound_effect_1 = 1;
-    else if (R16 == 0x208)
-      sound_effect_1 = 0x2c;
-    if ((uint16)(R16 - 0x208) < 0x30)
-      Credits_SpriteDraw_AddSparkle(2, 10, R16 - 0x208); // wtf x,y
-    k = 3;
-    if (R16 >= 0x200)
-      sprite_graphics[k] = 1;
-    sprite_oam_flags[k] = 0x31;
-    Credits_SpriteDraw_Single(k, 4, 8);
-    EndSequence_DrawShadow2(k);
-    int j = sprite_graphics[k];
-    sprite_graphics[--k] = j;
-    link_dma_var3 = 0;
-    link_dma_var4 = kEnding_Case5_Tab0[j];
-    sprite_oam_flags[k] = 0x30;
-
-    link_dma_graphics_index = kEnding_Case5_Tab1[j];
-    Credits_SpriteDraw_Single(k, 5, kEnding_Case5_Tab2[j]);
-    EndSequence_DrawShadow2(k);
-    break;
-  }
-  case 6: {
-    static const uint8 kEnding_Case6_SprType[3] = { 0x52, 0x55, 0x55 };
-    static const uint8 kEnding_Case6_OamSize[3] = { 0x20, 8, 8 };
-    static const uint8 kEnding_Case6_State[3] = { 3, 1, 1 };
-    static const uint8 kEnding_Case6_Gfx[6] = { 0, 5, 5, 1, 6, 6 };
-
-    int idx = kEndingSprites_Idx[i];
-    int num = kEndingSprites_Idx[i + 1] - idx;
-
-    for (int k = num - 1; k >= 0; k--) {
-      cur_object_index = k;
-      sprite_type[k] = kEnding_Case6_SprType[k];
-      Oam_AllocateFromRegionA(kEnding_Case6_OamSize[k]);
-      sprite_ai_state[k] = kEnding_Case6_State[k];
-      j = (R16 >= 0x26f) ? k + 3 : k;
-      if (R16 == 0x26f)
-        sound_effect_2 = 0x21;
-      sprite_graphics[k] = kEnding_Case6_Gfx[j];
-      sprite_oam_flags[k] = 0x33;
-      Sprite_Get16BitCoords(k);
-      SpriteActive_Main(k);
-    }
-    break;
-  }
-  case 7:
-    k = 1;
-    Credits_SpriteDraw_SetShadowProp(k, 2);
-    sprite_type[k] = 0xe9;
-    Oam_AllocateFromRegionA(0xc);
-    sprite_oam_flags[k] = 0x37;
-    Sprite_Get16BitCoords(k);
-    if (!(frame_counter & 15))
-      sprite_graphics[k] ^= 1;
-    SpriteActive_Main(k);
-    if (R16 >= 0x180) {
-      sprite_y_vel[k] = 4;
-      if (sprite_y_lo[k] != 0x7c)
-        Sprite_MoveXY(k);
-    }
-    k--;
-    sprite_type[k] = 0x36;
-    Oam_AllocateFromRegionA(0x18);
-    sprite_oam_flags[k] = 0x39;
-    Sprite_Get16BitCoords(k);
-    if (!sprite_delay_main[k]) {
-      static const int8 kEnding_Case7_Gfx[2] = { 1, -1 };
-      sprite_delay_main[k] = 4;
-      sprite_graphics[k] = sprite_graphics[k] + kEnding_Case7_Gfx[R16 >> 9 & 1] & 7;
-    }
-    SpriteActive_Main(k);
-    break;
-  case 8:
-    k = 0;
-    sprite_type[k] = 0x2c;
-    Oam_AllocateFromRegionA(0x2c);
-    sprite_oam_flags[k] = 0x3b;
-    Sprite_Get16BitCoords(k);
-    sprite_graphics[k] = R16 < 0x1c0 ? R16 >> 5 & 1 : 2;
-    SpriteActive_Main(k);
-    break;
-  case 9:
-    for (k = 0; k < 5; k++) {
-      if (!sprite_delay_main[k]) {
-        sprite_delay_main[k] = 96;
-        sprite_state[k] = 96;
-        sprite_x_vel[k] = 0;
-        sprite_x_lo[k] = 238;
-        sprite_x_hi[k] = 4;
-        sprite_y_lo[k] = 24;
-        sprite_y_hi[k] = 11;
-      }
-      if (sprite_state[k]) {
-        sprite_y_vel[k] = -8;
-        Sprite_MoveXY(k);
-        if (!(frame_counter & 1))
-          sprite_x_vel[k] += ((frame_counter >> 5) ^ k) & 1 ? -1 : 1;
-        Credits_SpriteDraw_Single(k, 1, 0x10);
-      }
-    }
-    for (;;) {
-      if (!sprite_delay_main[k]) {
-        static const uint8 kEnding_Case8_Delay1[4] = { 16, 14, 16, 18 };
-        static const uint8 kEnding_Case8_Delay2[4] = { 20, 48, 20, 20 };
-        sprite_delay_main[k] = (k == 5) ? kEnding_Case8_Delay1[sprite_A[k]] : kEnding_Case8_Delay2[sprite_A[k]];
-        sprite_A[k] = sprite_A[k] + 1 & 3;
-        sprite_graphics[k] ^= 1;
-      }
-      if (k == 5) {
-        sprite_oam_flags[k] = 0x31;
-        Credits_SpriteDraw_PreexistingSpriteDraw(k, 0x10);
-        k++;
-      } else {
-        Credits_SpriteDraw_Single(k, 2, 0x12);
-        k++;
-        break;
-      }
-    }
-    do {
-      static const uint8 kEnding_Case8_D[4] = { 0, 1, 0, 1 };
-      static const uint8 kEnding_Case8_OamFlags[4] = { 55, 55, 59, 61 };
-      static const uint8 kEnding_Case8_Tab0[4] = { 8, 8, 12, 12 };
-      sprite_oam_flags[k] = kEnding_Case8_OamFlags[k - 7];
-      sprite_D[k] = kEnding_Case8_D[k - 7];
-      Credits_SpriteDraw_ActivateAndRunSprite(k, kEnding_Case8_Tab0[k - 7]);
-    } while (++k != 11);
-    break;
-  case 10: {
-    static const uint8 kWishPond_X[8] = { 0, 4, 8, 12, 16, 20, 24, 0 };
-    static const uint8 kWishPond_Y[8] = { 0, 8, 16, 24, 32, 40, 4, 36 };
-    k = 5;
-    Sprite_Get16BitCoords(k);
-    if (!sprite_pause[k]) {
-      uint8 xb = kWishPond_X[GetRandomNumber() & 7] + cur_sprite_x;
-      uint8 yb = kWishPond_Y[GetRandomNumber() & 7] + cur_sprite_y;
-      Credits_SpriteDraw_AddSparkle(3, xb, yb);
-    }
-    for (int k = 3; k < 5; k++) {
-      if (sprite_delay_aux1[k])
-        sprite_delay_aux1[k]--;
-      sprite_type[k] = 0xe3;
-      Credits_SpriteDraw_SetShadowProp(k, 1);
-      Credits_SpriteDraw_ActivateAndRunSprite(k, 8);
-    }
-    sprite_type[k] = 0x72;
-    sprite_oam_flags[k] = 0x3b;
-    sprite_state[k] = 9;
-    sprite_B[k] = 9;
-    Credits_SpriteDraw_PreexistingSpriteDraw(k, 0x30);
-    break;
-  }
-  case 11:
-    if (R16 >= 0x170) {
-      for (int k = 4; k != 6; k++) {
-        Credits_SpriteDraw_Single(k, 1, 0x3e);
-      }
-      k = 0;
-      sprite_oam_flags[k] = 0x39;
-      if (R16 < 0x1c0) {
-        sprite_graphics[k] = 2;
-      } else if (sprite_delay_main[k] == 0) {
-        sprite_delay_main[k] = 0x20;
-        sprite_graphics[k] = (sprite_graphics[k] ^ 1) & 1;
-      }
-      Credits_SpriteDraw_Single(k, 4, 6);
-    } else {
-      static const uint8 kEnding_Case11_Gfx[16] = { 1, 1, 2, 2, 1, 1, 1, 1, 2, 2, 2, 2, 0, 0, 0, 0 };
-      for (int k = 0; k < 2; k++) {
-        sprite_type[k] = 0x1a;
-        sprite_oam_flags[k] = 0x39;
-        Credits_SpriteDraw_SetShadowProp(k, 2);
-        uint8 bak0 = main_module_index;
-        Credits_SpriteDraw_ActivateAndRunSprite(k, 0xc);
-        main_module_index = bak0;
-        if (sprite_B[k] == 15 && sprite_A[k] == 4)
-          sprite_delay_main[k + 2] = 15;
-        int j = sprite_delay_main[k + 2];
-        if (j != 0) {
-          sprite_oam_flags[k + 2] = 2;
-          sprite_graphics[k + 2] = kEnding_Case11_Gfx[j];
-          Credits_SpriteDraw_Single(k + 2, 2, 0x36);
-        }
-      }
-    }
-    break;
-  case 12:
-    k = 6;
-    sprite_graphics[k] = frame_counter & 1;
-    if (!sprite_graphics[k]) {
-      sprite_x_vel[k] += sign8(sprite_x_lo[k] - 0x80) ? 1 : -1;
-      sprite_y_vel[k] += sign8(sprite_y_lo[k] - 0xb0) ? 1 : -1;
-      Sprite_MoveXY(k);
-    }
-
-    sprite_oam_flags[k] = sprite_x_vel[k] >> 1 & 0x40 ^ 0x7e;
-    sprite_flags2[k] = 1;
-    sprite_flags3[k] = 0x30;
-    sprite_z[k] = 16;
-    Credits_SpriteDraw_PreexistingSpriteDraw(k, 8);
-    k--;
-    sprite_oam_flags[k] = 0x37;
-    Credits_SpriteDraw_SetShadowProp(k, 2);
-    Credits_SpriteDraw_ActivateAndRunSprite(k, 12);
-    k--;
-    Credits_SpriteDraw_ActivateAndRunSprite(k, 8);
-    k--;
-    Credits_SpriteDraw_ActivateAndRunSprite(k, 8);
-    k--;
-    do {
-      static const uint8 kEnding_Case12_Tab[3] = { 3, 3, 8 };
-      static const uint8 kEnding_Case12_Z[15] = { 2, 4, 5, 6, 6, 7, 7, 7, 7, 6, 6, 5, 4, 2, 0 };
-
-      Credits_SpriteDraw_Single(k, kEnding_Case12_Tab[k], k * 2);
-      if (k == 0) {
-        Ending_Func2(k, 0x30);
-      } else if (k & ~1) {
-        sprite_graphics[k] = frame_counter >> 3 & 1;
-      } else {
-        int j = frame_counter & 0x1f;
-        if (j < 0xf) {
-          sprite_z[k] = kEnding_Case12_Z[j];
-        }
-        sprite_graphics[k] = (j < 0xf) ? 1 : 0;
-        Credits_SpriteDraw_DrawShadow(k);
-      }
-    } while (--k >= 0);
-    break;
-  case 13:
-    k = 0;
-    if (R16 == 0x200)
-      sprite_x_vel[k] = -4;
-    sprite_graphics[k] = frame_counter >> 4 & 1;
-    if (sprite_x_lo[k] == 56) {
-      sprite_x_vel[k] = 0;
-      sprite_graphics[k] += 2;
-    }
-    Credits_SpriteDraw_Single(k, 3, 0x34);
-    Sprite_MoveXY(k);
-    break;
-  case 14: {
-    static const int8 kEnding_Case14_Tab1[4] = { 0, 1, 0, 2 };
-    static const int8 kEnding_Case14_Tab0[5] = { 2, 8, 32, 32, 8 };
-    for (k = 6; k; k--) {
-      if (k >= 5) {
-        sprite_type[k] = 0;
-        Credits_SpriteDraw_SetShadowProp(k, 1);
-        sprite_graphics[k] = (frame_counter + 0x4a & 8) >> 3;
-        sprite_z[k] = 32;
-        Credits_SpriteDraw_CirclingBirds(k);
-        sprite_oam_flags[k] = (sprite_x_vel[k] >> 1 & 0x40) ^ 0xf;
-        Credits_SpriteDraw_PreexistingSpriteDraw(k, 8);
-      } else {
-        sprite_type[k] = 0xd;
-        if (k == 1)
-          sprite_head_dir[k] = 0xd;
-        Credits_SpriteDraw_SetShadowProp(k, 3);
-        sprite_oam_flags[k] = 0x2b;
-        uint8 a = sprite_delay_main[k];
-        if (!a)
-          sprite_delay_main[k] = a = 0xc0;
-        a >>= 1;
-        if (a == 0) {
-          sprite_y_vel[k] = sprite_x_vel[k] = 0;
-        } else {
-          if (a < kEnding_Case14_Tab0[k] && !(frame_counter & 3) && (a = sprite_y_vel[k]) != 0) {
-            sprite_y_vel[k] = --a;
-            a -= 4;
-            if (k < 3)
-              a = -a;
-            sprite_x_vel[k] = a;
-          }
-        }
-        Sprite_MoveXY(k);
-        sprite_graphics[k] = kEnding_Case14_Tab1[frame_counter >> 3 & 3];
-        Credits_SpriteDraw_PreexistingSpriteDraw(k, 16);
-      }
-    }
-    Credits_SpriteDraw_Single(k, 3, 0x18);
-    Ending_Func2(k, 0x20);
-    break;
-  }
-  case 15: {
-    static const uint8 kEnding_Case15_X[4] = { 0x76, 0x73, 0x71, 0x78 };
-    static const uint8 kEnding_Case15_Y[4] = { 0x8b, 0x83, 0x8d, 0x85 };
-    static const uint8 kEnding_Case15_Delay[8] = { 6, 6, 6, 6, 6, 6, 10, 8 };
-    static const uint8 kEnding_Case15_OamFlags[4] = { 0x61, 0x61, 0x3b, 0x39 };
-    j = kGeneratedEndSequence15[frame_counter] & 3;
-    Credits_SpriteDraw_AddSparkle(2, kEnding_Case15_X[j], kEnding_Case15_Y[j]);
-    k = 2;
-    sprite_type[k] = 0x62;
-    sprite_oam_flags[k] = 0x39;
-    Credits_SpriteDraw_PreexistingSpriteDraw(k, 0x18);
-    for (j = 1; j >= 0; j--) {
-      k++;
-      if (sprite_delay_aux1[k])
-        sprite_delay_aux1[k]--;
-      sprite_oam_flags[k] = (sprite_x_vel[k] >> 1 & 0x40) ^ kEnding_Case15_OamFlags[j];
-      if (!sprite_delay_main[k]) {
-        sprite_delay_main[k] = 128;
-        sprite_A[k] = 0;
-      }
-      if (!sprite_A[k]) {
-        sprite_graphics[k] = (frame_counter >> 2 & 1) + 2;
-        Credits_SpriteDraw_MoveSquirrel(k);
-      } else if (!sprite_delay_aux1[k]) {
-        if (sprite_B[k] == 8)
-          sprite_B[k] = 0;
-        sprite_delay_aux1[k] = kEnding_Case15_Delay[sprite_B[k] & 7];
-        sprite_graphics[k] = sprite_graphics[k] & 1 ^ 1;
-        sprite_B[k]++;
-      }
-      Credits_SpriteDraw_Single(k, 1, 20);
-      EndSequence_DrawShadow2(k);
-    }
-    Credits_SpriteDraw_WalkLinkAwayFromPedestal(k + 1);
-    break;
-  }
-  }
-
-  k = submodule_index >> 1;
-  if (R16 >= kEnding1_3_Tab0[k]) {
-    if (!(R16 & 1) && !--INIDISP_copy)
-      submodule_index++;
-    else
-      R16++;
-  } else {
-    if (!(R16 & 1) && INIDISP_copy != 15)
-      INIDISP_copy++;
-    R16++;
-  }
-  BG2HOFS_copy = BG2HOFS_copy2;
-  BG2VOFS_copy = BG2VOFS_copy2;
-  BG1HOFS_copy = BG1HOFS_copy2;
-  BG1VOFS_copy = BG1VOFS_copy2;
-}
-
-void Credits_SpriteDraw_DrawShadow(int k) {  // 8ea5f8
-  sprite_oam_flags[k] = 0x30;
-  Credits_SpriteDraw_SetShadowProp(k, 0);
-  Oam_AllocateFromRegionA(4);
-  SpriteDraw_Shadow(k, &g_ending_coords);
-}
-
-void EndSequence_DrawShadow2(int k) {  // 8ea5fd
-  Credits_SpriteDraw_SetShadowProp(k, 0);
-  Oam_AllocateFromRegionA(4);
-  SpriteDraw_Shadow(k, &g_ending_coords);
-}
-
-void Ending_Func2(int k, uint8 ain) {  // 8ea645
-  static const uint8 kEnding_Func2_Delay[27] = {
-  10, 10, 10, 10, 20, 8,   8,   0, 255, 12, 12, 12, 12, 12, 12, 30,
-   8,  4,  4,  4,  0, 0, 255, 255, 144,  4, 0,
-  };
-  static const int8 kEnding_Func2_Tab0[28] = {
-    0, 0, 1, 0, 1, 0, 2,  3,  0,  2, 0, 1, 0, 1, 0, 1,
-    2, 3, 4, 5, 6, 3, 0, -1, -1, -1, 2, 3,
-  };
-  sprite_oam_flags[k] = ain;
-  EndSequence_DrawShadow2(k);
-  int j = sprite_A[k];
-  if (!sprite_delay_main[k]) {
-    j++;
-    if (j == 8)
-      j = 6;
-    else if (j == 22)
-      j = 21;
-    else if (j == 28)
-      j = 27;
-    sprite_A[k] = j;
-    sprite_delay_main[k] = kEnding_Func2_Delay[j - 1];
-  }
-  uint8 a = kEnding_Func2_Tab0[j];
-  sprite_graphics[k] = (a == 255) ? frame_counter >> 3 & 1 : a;
-  if ((j < 5 || j >= 10 && j < 15) && !(frame_counter & 1))
-    sprite_y_lo[k]++;
-}
-
-void Credits_SpriteDraw_ActivateAndRunSprite(int k, uint8 a) {  // 8ea694
-  cur_object_index = k;
-  Oam_AllocateFromRegionA(a);
-  Sprite_Get16BitCoords(k);
-  uint8 bak0 = submodule_index;
-  submodule_index = 0;
-  sprite_state[k] = 9;
-  SpriteActive_Main(k);
-  submodule_index = bak0;
-}
-
-void Credits_SpriteDraw_PreexistingSpriteDraw(int k, uint8 a) {  // 8ea6b3
-  Oam_AllocateFromRegionA(a);
-  cur_object_index = k;
-  Sprite_Get16BitCoords(k);
-  SpriteActive_Main(k);
-}
-
-void Credits_SpriteDraw_Single(int k, uint8 a, uint8 j) {  // 8ea703
-  static const DrawMultipleData kEndSequence_Dmd0[12] = {
-    { 0, -8, 0x072a, 2},
-    { 0, -8, 0x072a, 2},
-    { 0,  0, 0x4fca, 2},
-    { 0, -8, 0x072a, 2},
-    { 0, -8, 0x072a, 2},
-    { 0,  0, 0x0fca, 2},
-    {-2,  0, 0x0f77, 0},
-    { 0, -8, 0x072a, 2},
-    { 0,  0, 0x4fca, 2},
-    {-3,  0, 0x0f66, 0},
-    { 0, -8, 0x072a, 2},
-    { 0,  0, 0x4fca, 2},
-  };
-  static const DrawMultipleData kEndSequence_Dmd1[6] = {
-    {14,  -7, 0x0d48, 2},
-    { 0,  -6, 0x0944, 2},
-    { 0,   0, 0x094e, 2},
-    {13, -14, 0x0d48, 2},
-    { 0,  -8, 0x0944, 2},
-    { 0,   0, 0x0946, 2},
-  };
-  static const DrawMultipleData kEndSequence_Dmd2[16] = {
-    {-2, -16, 0x3d78, 0},
-    { 0, -24, 0x3d24, 2},
-    { 0, -16, 0x3dc2, 2},
-    {61, -16, 0x3777, 0},
-    {64, -24, 0x37c4, 2},
-    {64, -16, 0x77ca, 2},
-    { 0,  -6, 0x326c, 2},
-    {64,  -6, 0x326c, 2},
-    {-2, -16, 0x3d68, 0},
-    { 0, -24, 0x3d24, 2},
-    { 0, -16, 0x3dc2, 2},
-    {61, -16, 0x3766, 0},
-    {64, -24, 0x37c4, 2},
-    {64, -16, 0x77ca, 2},
-    { 0,  -6, 0x326c, 2},
-    {64,  -6, 0x326c, 2},
-  };
-  static const DrawMultipleData kEndSequence_Dmd3[12] = {
-    { 0,  0, 0x0022, 2},
-    {48,  0, 0x0064, 2},
-    { 0, 10, 0x016c, 2},
-    {48, 10, 0x016c, 2},
-    { 0,  0, 0x0064, 2},
-    {48,  0, 0x0022, 2},
-    { 0, 10, 0x016c, 2},
-    {48, 10, 0x016c, 2},
-    { 0,  0, 0x0064, 2},
-    {48,  0, 0x0064, 2},
-    { 0, 10, 0x016c, 2},
-    {48, 10, 0x016c, 2},
-  };
-  static const DrawMultipleData kEndSequence_Dmd4[8] = {
-    {10,   8, 0x8a32, 0},
-    {10,  16, 0x8a22, 0},
-    { 0, -10, 0x0800, 2},
-    { 0,   0, 0x082c, 2},
-    {10, -14, 0x0a22, 0},
-    {10,  -6, 0x0a32, 0},
-    {0, -10, 0x082a, 2},
-    {0,   0, 0x0828, 2},
-  };
-  static const DrawMultipleData kEndSequence_Dmd5[10] = {
-    {10,  16, 0x8a05, 0},
-    {10,   8, 0x8a15, 0},
-    {-4,   2, 0x0a07, 2},
-    { 0,  -7, 0x0e00, 2},
-    { 0,   1, 0x0e02, 2},
-    {10, -20, 0x0a05, 0},
-    {10, -12, 0x0a15, 0},
-    {-7,   1, 0x4a07, 2},
-    { 0,  -7, 0x0e00, 2},
-    { 0,   1, 0x0e02, 2},
-  };
-  static const DrawMultipleData kEndSequence_Dmd6[3] = {
-    {-6, -2, 0x0706, 2},
-    { 0, -9, 0x090e, 2},
-    { 0, -1, 0x0908, 2},
-  };
-  static const DrawMultipleData kEndSequence_Dmd7[10] = {
-    {0, -10, 0x082a, 2},
-    {0,   0, 0x0828, 2},
-    {10,  16, 0x8a05, 0},
-    {10,   8, 0x8a15, 0},
-    {-4,   2, 0x0a07, 2},
-    { 0,  -7, 0x0e00, 2},
-    { 0,   1, 0x0e02, 2},
-    {10, -20, 0x0a05, 0},
-    {10, -12, 0x0a15, 0},
-    {-7,   1, 0x4a07, 2},
-  };
-  static const DrawMultipleData kEndSequence_Dmd8[1] = {
-    {0, -19, 0x39af, 0},
-  };
-  static const DrawMultipleData kEndSequence_Dmd9[4] = {
-    {-16, -24, 0x3704, 2},
-    {-16, -16, 0x3764, 2},
-    {-16, -24, 0x3762, 2},
-    {-16, -16, 0x3764, 2},
-  };
-  static const DrawMultipleData kEndSequence_Dmd10[4] = {
-    {0, 0, 0x0c0c, 2},
-    {0, 0, 0x0c0a, 2},
-    {0, 0, 0x0cc5, 2},
-    {0, 0, 0x0ce1, 2},
-  };
-  static const DrawMultipleData kEndSequence_Dmd11[6] = {
-    {1,  4, 0x002a, 0},
-    {1, 12, 0x003a, 0},
-    {4,  0, 0x0026, 2},
-    {0,  9, 0x0024, 2},
-    {8,  9, 0x4024, 2},
-    {4, 20, 0x016c, 2},
-  };
-  static const DrawMultipleData kEndSequence_Dmd12[21] = {
-    { 0, -7, 0x0d00, 2},
-    { 0, -7, 0x0d00, 2},
-    { 0,  0, 0x0d06, 2},
-    { 0, -7, 0x0d00, 2},
-    { 0, -7, 0x0d00, 2},
-    { 0,  0, 0x4d06, 2},
-    { 0, -8, 0x0d00, 2},
-    { 0, -8, 0x0d00, 2},
-    { 0,  0, 0x0d20, 2},
-    { 0, -8, 0x0d02, 2},
-    { 0, -8, 0x0d02, 2},
-    { 0,  0, 0x0d2c, 2},
-    {-3,  0, 0x0d2f, 0},
-    { 0, -7, 0x0d02, 2},
-    { 0,  0, 0x0d2c, 2},
-    {-5,  2, 0x0d2f, 0},
-    { 0, -8, 0x0d02, 2},
-    { 0,  0, 0x0d2c, 2},
-    {-5,  2, 0x0d3f, 0},
-    { 0, -8, 0x0d02, 2},
-    { 0,  0, 0x0d2c, 2},
-  };
-  static const DrawMultipleData kEndSequence_Dmd13[16] = {
-    {0, -7, 0x0e00, 2},
-    {0,  1, 0x4e02, 2},
-    {0, -8, 0x0e00, 2},
-    {0,  1, 0x0e02, 2},
-    {0, -9, 0x0e00, 2},
-    {0,  1, 0x0e02, 2},
-    {0, -7, 0x0e00, 2},
-    {0,  1, 0x0e02, 2},
-    {0, -7, 0x0e00, 2},
-    {0,  1, 0x4e02, 2},
-    {0, -8, 0x0e00, 2},
-    {0,  1, 0x4e02, 2},
-    {0, -9, 0x0e00, 2},
-    {0,  1, 0x4e02, 2},
-    {0, -7, 0x0e00, 2},
-    {0,  1, 0x4e02, 2},
-  };
-  static const DrawMultipleData kEndSequence_Dmd14[6] = {
-    {0, 0, 0, 0},
-    {0, 0, 0x34c7, 0},
-    {0, 0, 0x3480, 0},
-    {0, 0, 0x34b6, 0},
-    {0, 0, 0x34b7, 0},
-    {0, 0, 0x34a6, 0},
-  };
-  static const DrawMultipleData kEndSequence_Dmd15[6] = {
-    {-3, 17, 0x002b, 0},
-    {-3, 25, 0x003b, 0},
-    { 0,  0, 0x000e, 2},
-    {16,  0, 0x400e, 2},
-    { 0, 16, 0x002e, 2},
-    {16, 16, 0x402e, 2},
-  };
-  static const DrawMultipleData kEndSequence_Dmd16[3] = {
-    { 8,  5, 0x0a04, 2},
-    { 0, 16, 0x0806, 2},
-    {16, 16, 0x4806, 2},
-  };
-  static const DrawMultipleData kEndSequence_Dmd17[2] = {
-    {0,  0, 0x0000, 2},
-    {0, 11, 0x0002, 2},
-  };
-  static const DrawMultipleData kEndSequence_Dmd18[2] = {
-    {0,  0, 0x000e, 2},
-    {0, 64, 0x006c, 2},
-  };
-  static const DrawMultipleData kEndSequence_Dmd19[8] = {
-    {0, 0, 0x0882, 2},
-    {0, 7, 0x0a4e, 2},
-    {0, 0, 0x4880, 2},
-    {0, 7, 0x0a4e, 2},
-    {0, 0, 0x0882, 2},
-    {0, 7, 0x0a4e, 2},
-    {0, 0, 0x0880, 2},
-    {0, 7, 0x0a4e, 2},
-  };
-  static const DrawMultipleData kEndSequence_Dmd20[6] = {
-    {-4,  1, 0x0c68, 0},
-    { 0, -8, 0x0c40, 2},
-    { 0,  1, 0x0c42, 2},
-    {-4,  1, 0x0c78, 0},
-    { 0, -8, 0x0c40, 2},
-    { 0,  1, 0x0c42, 2},
-  };
-  static const DrawMultipleData kEndSequence_Dmd21[6] = {
-    {8,   5, 0x0679, 0},
-    {0, -10, 0x088e, 2},
-    {0,   0, 0x066e, 2},
-    {0, -10, 0x088e, 2},
-    {0, -10, 0x088e, 2},
-    {0,   0, 0x066e, 2},
-  };
-  static const DrawMultipleData kEndSequence_Dmd22[6] = {
-    {11,  -3, 0x0869, 0},
-    { 0, -12, 0x0804, 2},
-    { 0,   0, 0x0860, 2},
-    {10,  -3, 0x0867, 0},
-    { 0, -12, 0x0804, 2},
-    { 0,   0, 0x0860, 2},
-  };
-  static const DrawMultipleData kEndSequence_Dmd23[6] = {
-    {-2,  1, 0x0868, 0},
-    { 0, -8, 0x08c0, 2},
-    { 0,  0, 0x08c2, 2},
-    {-3,  1, 0x0878, 0},
-    { 0, -8, 0x08c0, 2},
-    { 0,  0, 0x08c2, 2},
-  };
-  static const DrawMultipleData kEndSequence_Dmd24[4] = {
-    {0, -10, 0x084c, 2},
-    {0,   0, 0x0a6c, 2},
-    {0,  -9, 0x084c, 2},
-    {0,   0, 0x0aa8, 2},
-  };
-  static const DrawMultipleData kEndSequence_Dmd25[4] = {
-    {0, -7, 0x084a, 2},
-    {0,  0, 0x0c6a, 2},
-    {0, -7, 0x084a, 2},
-    {0,  0, 0x0ca6, 2},
-  };
-  static const DrawMultipleData kEndSequence_Dmd26[12] = {
-    {-18, -24, 0x39a4, 2},
-    {-16, -16, 0x39a8, 2},
-    {-18, -24, 0x39a4, 2},
-    {-18, -24, 0x39a4, 2},
-    {-16, -16, 0x39a6, 2},
-    {-18, -24, 0x39a4, 2},
-    { -6, -17, 0x392d, 0},
-    {-16, -24, 0x39a0, 2},
-    {-16, -16, 0x39aa, 2},
-    { -5, -17, 0x392c, 0},
-    {-16, -24, 0x39a0, 2},
-    {-16, -16, 0x39aa, 2},
-  };
-  static const DrawMultipleData kEndSequence_Dmd27[6] = {
-    { 0,  -4, 0x30aa, 2},
-    { 0,  -4, 0x30aa, 2},
-    {-4,  -8, 0x3090, 0},
-    {12,  -8, 0x7090, 0},
-    {-6, -10, 0x3091, 0},
-    {14, -10, 0x7091, 0},
-  };
-  static const DrawMultipleData kEndSequence_Dmd28[8] = {
-    {0,  0, 0x0722, 2},
-    {0, -8, 0x09c2, 2},
-    {0,  0, 0x4722, 2},
-    {0, -8, 0x09c2, 2},
-    {0, -9, 0x09c4, 2},
-    {0,  0, 0x0722, 2},
-    {0, -9, 0x0924, 2},
-    {0,  0, 0x0722, 2},
-  };
-  static const DrawMultipleData kEndSequence_Dmd29[3] = {
-    {-16, -12, 0x3f08, 2},
-    {  0, -12, 0x3f20, 2},
-    { 16, -12, 0x3f20, 2},
-  };
-  static const DrawMultipleData kEndSequence_Dmd30[1] = {
-    {0, 0, 0x0086, 2},
-  };
-  static const DrawMultipleData kEndSequence_Dmd31[1] = {
-    {0, 0, 0x8060, 2},
-  };
-  static const DrawMultipleData *const kEndSequence_Dmds[] = {
-    kEndSequence_Dmd0, kEndSequence_Dmd1, kEndSequence_Dmd2, kEndSequence_Dmd3,
-    kEndSequence_Dmd4, kEndSequence_Dmd5, kEndSequence_Dmd6, kEndSequence_Dmd7,
-    kEndSequence_Dmd8, kEndSequence_Dmd9, kEndSequence_Dmd10, kEndSequence_Dmd11,
-    kEndSequence_Dmd12, kEndSequence_Dmd13, kEndSequence_Dmd14, kEndSequence_Dmd15,
-    kEndSequence_Dmd16, kEndSequence_Dmd17, kEndSequence_Dmd18, kEndSequence_Dmd19,
-    kEndSequence_Dmd20, kEndSequence_Dmd21, kEndSequence_Dmd22, kEndSequence_Dmd23,
-    kEndSequence_Dmd24, kEndSequence_Dmd25, kEndSequence_Dmd26, kEndSequence_Dmd27,
-    kEndSequence_Dmd28, kEndSequence_Dmd29, kEndSequence_Dmd30, kEndSequence_Dmd31
-  };
-
-  Oam_AllocateFromRegionA(a * 4);
-  Sprite_Get16BitCoords(k);
-  Sprite_DrawMultiple(k, kEndSequence_Dmds[j >> 1] + a * sprite_graphics[k], a, &g_ending_coords);
-}
-
-void Credits_SpriteDraw_SetShadowProp(int k, uint8 a) {  // 8eaca2
-  sprite_flags2[k] = a;
-  sprite_flags3[k] = 16;
-}
-
-void Credits_SpriteDraw_AddSparkle(int j_count, uint8 xb, uint8 yb) {  // 8eace5
-  static const uint8 kEnding_Func3_Delay[6] = { 32, 4, 4, 4, 5, 6 };
-  sprite_C[0] = j_count;
-  for (int k = 0; k < j_count; k++) {
-    int j = sprite_graphics[k];
-    if (!sprite_delay_main[k]) {
-      if (++j >= 6) {
-        sprite_x_lo[k] = xb;
-        sprite_y_lo[k] = yb;
-        j = 0;
-      }
-      sprite_graphics[k] = j;
-      sprite_delay_main[k] = kEnding_Func3_Delay[j];
-    }
-    if (j)
-      Credits_SpriteDraw_Single(k, 1, 0x1c);
-  }
-}
-
-void Credits_SpriteDraw_WalkLinkAwayFromPedestal(int k) {  // 8eadf7
-  static const uint16 kEnding_Func6_Dma[8] = { 0x16c, 0x16e, 0x170, 0x172, 0x16c, 0x174, 0x176, 0x178 };
-  if (!sprite_delay_main[k]) {
-    sprite_graphics[k] = sprite_graphics[k] + 1 & 7;
-    sprite_delay_main[k] = 4;
-  }
-  link_dma_graphics_index = kEnding_Func6_Dma[sprite_graphics[k]];
-  sprite_oam_flags[k] = 32;
-  Credits_SpriteDraw_Single(k, 2, 26);
-  EndSequence_DrawShadow2(k);
-  Sprite_MoveXY(k);
-}
-
-void Credits_SpriteDraw_MoveSquirrel(int k) {  // 8eae35
-  static const int8 kEnding_Func5_Xvel[4] = { 32, 24, -32, -24 };
-  static const int8 kEnding_Func5_Yvel[4] = { 8, -8, -8, 8 };
-  if (sprite_delay_main[k] < 64) {
-    sprite_C[k] = sprite_C[k] + 1 & 3;
-    sprite_A[k]++;
-  } else {
-    int j = sprite_C[k];
-    sprite_x_vel[k] = kEnding_Func5_Xvel[j];
-    sprite_y_vel[k] = kEnding_Func5_Yvel[j];
-    Sprite_MoveXY(k);
-  }
-}
-
-void Credits_SpriteDraw_CirclingBirds(int k) {  // 8eae63
-  static const int8 kEnding_MoveSprite_Func1_TargetX[2] = { 0x20, -0x20 };
-  static const int8 kEnding_MoveSprite_Func1_TargetY[2] = { 0x10, -0x10 };
-
-  int j = sprite_D[k] & 1;
-  sprite_x_vel[k] += j ? -1 : 1;
-  if (sprite_x_vel[k] == (uint8)kEnding_MoveSprite_Func1_TargetX[j])
-    sprite_D[k]++;
-  if (!(frame_counter & 1)) {
-    j = sprite_head_dir[k] & 1;
-    sprite_y_vel[k] += j ? -1 : 1;
-    if (sprite_y_vel[k] == (uint8)kEnding_MoveSprite_Func1_TargetY[j])
-      sprite_head_dir[k]++;
-  }
-  Sprite_MoveXY(k);
-}
-
-void Credits_HandleCameraScrollControl() {  // 8eaea6
-  if (link_y_vel != 0) {
-    uint8 yvel = link_y_vel;
-    BG2VOFS_copy2 += (int8)yvel;
-    uint16 *which = sign8(yvel) ? &overworld_unk1 : &overworld_unk1_neg;
-    *which += abs8(yvel);
-    if (!sign16(*which - 0x10)) {
-      *which -= 0x10;
-      overworld_screen_trans_dir_bits2 |= sign8(yvel) ? 8 : 4;
-    }
-    *(sign8(yvel) ? &overworld_unk1_neg : &overworld_unk1) = -*which;
-    uint16 r4 = (int8)yvel, subp;
-    WORD(byte_7E069E[0]) = r4;
-    uint8 oi = BYTE(overlay_index);
-    if (oi != 0x97 && oi != 0x9d) {
-      if (oi == 0xb5 || oi == 0xbe) {
-        subp = (r4 & 3) << 14;
-        r4 >>= 2;
-        if (r4 >= 0x3000)
-          r4 |= 0xf000;
-      } else {
-        subp = (r4 & 1) << 15;
-        r4 >>= 1;
-        if (r4 >= 0x7000)
-          r4 |= 0xf000;
-      }
-      uint32 tmp = BG1VOFS_subpixel | BG1VOFS_copy2 << 16;
-      tmp += subp | r4 << 16;
-      BG1VOFS_subpixel = (uint16)(tmp);
-      BG1VOFS_copy2 = (uint16)(tmp >> 16);
-    }
-  }
-
-  if (link_x_vel != 0) {
-    uint8 xvel = link_x_vel;
-    BG2HOFS_copy2 += (int8)xvel;
-    uint16 *which = sign8(xvel) ? &overworld_unk3 : &overworld_unk3_neg;
-    *which += abs8(xvel);
-    if (!sign16(*which - 0x10)) {
-      *which -= 0x10;
-      overworld_screen_trans_dir_bits2 |= sign8(xvel) ? 2 : 1;
-    }
-    *(sign8(xvel) ? &overworld_unk3_neg : &overworld_unk3) = -*which;
-
-    uint16 r4 = (int8)xvel, subp;
-    WORD(byte_7E069E[1]) = r4;
-    uint8 oi = BYTE(overlay_index);
-    if (oi != 0x97 && oi != 0x9d && r4 != 0) {
-      if (oi == 0x95 || oi == 0x9e) {
-        subp = (r4 & 3) << 14;
-        r4 >>= 2;
-        if (r4 >= 0x3000)
-          r4 |= 0xf000;
-      } else {
-        subp = (r4 & 1) << 15;
-        r4 >>= 1;
-        if (r4 >= 0x7000)
-          r4 |= 0xf000;
-      }
-      uint32 tmp = BG1HOFS_subpixel | BG1HOFS_copy2 << 16;
-      tmp += subp | r4 << 16;
-      BG1HOFS_subpixel = (uint16)(tmp), BG1HOFS_copy2 = (uint16)(tmp >> 16);
-    }
-  }
-
-  if (BYTE(overlay_index) == 0x9c) {
-    uint32 tmp = BG1VOFS_subpixel | BG1VOFS_copy2 << 16;
-    tmp -= 0x2000;
-    BG1VOFS_subpixel = (uint16)(tmp), BG1VOFS_copy2 = (uint16)(tmp >> 16) + WORD(byte_7E069E[0]);
-    BG1HOFS_copy2 = BG2HOFS_copy2;
-  } else if (BYTE(overlay_index) == 0x97 || BYTE(overlay_index) == 0x9d) {
-    uint32 tmp = BG1VOFS_subpixel | BG1VOFS_copy2 << 16;
-    tmp += 0x2000;
-    BG1VOFS_subpixel = (uint16)(tmp), BG1VOFS_copy2 = (uint16)(tmp >> 16);
-    tmp = BG1HOFS_subpixel | BG1HOFS_copy2 << 16;
-    tmp += 0x2000;
-    BG1HOFS_subpixel = (uint16)(tmp), BG1HOFS_copy2 = (uint16)(tmp >> 16);
-  }
-
-  if (dungeon_room_index == 0x181) {
-    BG1VOFS_copy2 = BG2VOFS_copy2 | 0x100;
-    BG1HOFS_copy2 = BG2HOFS_copy2;
-  }
-}
-
-void EndSequence_32() {  // 8ebc6d
-  EnableForceBlank();
-  EraseTileMaps_triforce();
-  TransferFontToVRAM();
-  Credits_LoadCoolBackground();
-  Credits_InitializePolyhedral();
-  INIDISP_copy = 128;
-  overworld_palette_aux_or_main = 0x200;
-  hud_palette = 1;
-  Palette_Load_HUD();
-  flag_update_cgram_in_nmi++;
-  deaths_per_palace[4] = 0;
-  deaths_per_palace[13] += death_save_counter;
-  int sum = deaths_per_palace[13];
-  for (int i = 12; i >= 0; i--)
-    sum += deaths_per_palace[i];
-  death_var2 = sum;
-  death_save_counter = 0;
-  link_health_current = kHealthAfterDeath[link_health_capacity >> 3];
-  savegame_is_darkworld = 0x40;
-  SaveGameFile();
-  aux_palette_buffer[38] = 0;
-  main_palette_buffer[38] = 0;
-  aux_palette_buffer[0] = 0;
-  main_palette_buffer[0] = 0;
-  TM_copy = 0x16;
-  TS_copy = 0;
-  R16 = 0x6800;
-  R18 = 0;
-  ending_which_dung = 0;
-  BG2VOFS_copy2 = -0x48;
-  BG2HOFS_copy2 = 0x90;
-  BG3VOFS_copy2 = 0;
-  BG3HOFS_copy2 = 0;
-  Credits_AddNextAttribution();
-  music_control = 0x22;
-  CGWSEL_copy = 0;
-  CGADSUB_copy = 162;
-  // real zelda does 0x12 here but this seems to work too
-  zelda_ppu_write(BG2SC, 0x13);
-  COLDATA_copy0 = 0x3f;
-  COLDATA_copy1 = 0x5f;
-  COLDATA_copy2 = 0x9f;
-  subsubmodule_index = 64;
-  INIDISP_copy = 0;
-
-  HdmaSetup(0, 0xebd53, 0x42, 0, (uint8)BG2HOFS, 0);
-  HDMAEN_copy = 0x80;
-
-  BG2HOFS_copy = BG2HOFS_copy2;
-  BG2VOFS_copy = BG2VOFS_copy2;
-  BG1HOFS_copy = BG1HOFS_copy2;
-  BG1VOFS_copy = BG1VOFS_copy2;
-}
-
-void Credits_FadeOutFixedCol() {  // 8ebd66
-  if (--subsubmodule_index == 0) {
-    subsubmodule_index = 16;
-    if (COLDATA_copy0 != 32) {
-      COLDATA_copy0--;
-    } else if (COLDATA_copy1 != 64) {
-      COLDATA_copy1--;
-    } else if (COLDATA_copy2 != 128) {
-      COLDATA_copy2--;
-    }
-  }
-}
-
-void Credits_FadeColorAndBeginAnimating() {  // 8ebd8b
-  Credits_FadeOutFixedCol();
-  nmi_disable_core_updates = 1;
-  Credits_AnimateTheTriangles();
-  if (!(frame_counter & 3)) {
-    if (++BG2HOFS_copy2 == 0xc00) {
-      // real zelda writes 0x00 to BG1SC here but that doesn't seem needed
-      zelda_ppu_write(BG2SC, 0x13);
-    }
-    room_bounds_y.a1 = BG2HOFS_copy2 >> 1;
-    room_bounds_y.a0 = room_bounds_y.a1 + BG2HOFS_copy2;
-    room_bounds_y.b0 = room_bounds_y.a0 >> 1;
-    room_bounds_y.b1 = room_bounds_y.a1 >> 1;
-    if (BG3VOFS_copy2 == 3288) {
-      R16 = 0x80;
-      submodule_index++;
-    } else {
-      BG3VOFS_copy2++;
-      if ((BG3VOFS_copy2 & 7) == 0) {
-        R18 = BG3VOFS_copy2 >> 3;
-        Credits_AddNextAttribution();
-      }
-    }
-  }
-  BG2HOFS_copy = BG2HOFS_copy2;
-  BG2VOFS_copy = BG2VOFS_copy2;
-  BG1HOFS_copy = BG1HOFS_copy2;
-  BG1VOFS_copy = BG1VOFS_copy2;
-}
-
-void Credits_AddNextAttribution() {  // 8ebe24
-  static const uint8 kEnding_Func9_Tab2[14] = { 1, 0, 2, 3, 10, 6, 5, 8, 11, 9, 7, 12, 13, 15 };
-  static const uint16 kEnding_Digits_ScrollY[14] = { 0x290, 0x298, 0x2a0, 0x2a8, 0x2b0, 0x2ba, 0x2c2, 0x2ca, 0x2d2, 0x2da, 0x2e2, 0x2ea, 0x2f2, 0x310 };
-  static const uint16 kEnding_Credits_DigitChar[2] = { 0x3ce6, 0x3cf6 };
-
-  uint16 *dst = vram_upload_data + (vram_upload_offset >> 1);
-
-  dst[0] = swap16(R16);
-  dst[1] = 0x3e40;
-  dst[2] = kEnding_MapData[159];
-  dst += 3;
-
-  if (R18 < 394) {
-    const uint8 *src = &kEnding_Credits_Text[kEnding_Credits_Offs[R18]];
-    if (*src != 0xff) {
-      *dst++ = swap16(R16 + *src++);
-      int n = *src++;
-      *dst++ = swap16(n);
-      n = (n + 1) >> 1;
-      do {
-        *dst++ = kEnding_MapData[*src++];
-      } while (--n);
-    }
-
-    if ((ending_which_dung & 1) || R18 * 2 == kEnding_Digits_ScrollY[ending_which_dung >> 1]) {
-      int t = kEnding_Credits_DigitChar[ending_which_dung & 1];
-      WORD(g_ram[0xce]) = t;
-
-      dst[0] = swap16(R16 + 0x19);
-      dst[1] = 0x500;
-
-      uint16 deaths = deaths_per_palace[kEnding_Func9_Tab2[ending_which_dung >> 1]];
-      if (deaths >= 1000)
-        deaths = 999;
-
-      dst[4] = t + deaths % 10, deaths /= 10;
-      dst[3] = t + deaths % 10, deaths /= 10;
-      dst[2] = t + deaths;
-      dst += 5;
-      ending_which_dung++;
-    }
-  }
-
-  R16 += 0x20;
-  if (!(R16 & 0x3ff))
-    R16 = (R16 & 0x6800) ^ 0x800;
-  vram_upload_offset = (char *)dst - (char *)vram_upload_data;
-  BYTE(*dst) = 0xff;
-  nmi_load_bg_from_vram = 1;
-}
-
-void Credits_AddEndingSequenceText() {  // 8ec303
-
-  uint16 *dst = vram_upload_data;
-  dst[0] = 0x60;
-  dst[1] = 0xfe47;
-  dst[2] = kEnding_MapData[159];
-  dst += 3;
-
-  const uint8 *curo = &kEnding0_Data[kEnding0_Offs[submodule_index >> 1]];
-  const uint8 *endo = &kEnding0_Data[kEnding0_Offs[(submodule_index >> 1) + 1]];
-  do {
-    dst[0] = WORD(curo[0]);
-    dst[1] = WORD(curo[2]);
-    int m = (dst[1] >> 9) & 0x7f;
-    dst += 2, curo += 4;
-    do {
-      *dst++ = kEnding_MapData[*curo++];
-    } while (--m >= 0);
-  } while (curo != endo);
-
-  vram_upload_offset = (char *)dst - (char *)vram_upload_data;
-  BYTE(*dst) = 0xff;
-  nmi_load_bg_from_vram = 1;
-}
-
-void Credits_BrightenTriangles() {  // 8ec37c
-  if (!(frame_counter & 15) && ++INIDISP_copy == 15)
-    submodule_index++;
-  Credits_AnimateTheTriangles();
-}
-
-void Credits_StopCreditsScroll() {  // 8ec391
-  if (!--BYTE(R16)) {
-    darkening_or_lightening_screen = 0;
-    palette_filter_countdown = 0;
-    WORD(mosaic_target_level) = 0x1f;
-    submodule_index++;
-    R16 = 0xc0;
-    R18 = 0;
-  }
-  Credits_AnimateTheTriangles();
-}
-
-void Credits_FadeAndDisperseTriangles() {  // 8ec3b8
-  BYTE(R16)--;
-  if (!BYTE(R18)) {
-    ApplyPaletteFilter_bounce();
-    if (BYTE(palette_filter_countdown)) {
-      Credits_AnimateTheTriangles();
-      return;
-    }
-    BYTE(R18)++;
-  }
-  if (BYTE(R16)) {
-    Credits_AnimateTheTriangles();
-    return;
-  }
-  submodule_index++;
-  PaletteFilter_WishPonds_Inner();
-}
-
-void Credits_FadeInTheEnd() {  // 8ec3d5
-  if (!(frame_counter & 7)) {
-    PaletteFilter_SP5F();
-    if (!BYTE(palette_filter_countdown))
-      submodule_index++;;
-  }
-  Credits_HangForever();
-}
-
-void Credits_HangForever() {  // 8ec41a
-  SetOamPlain(&oam_buf[0], -96, -72, 0x00, 0x3b, 2);
-  SetOamPlain(&oam_buf[1], -80, -72, 0x02, 0x3b, 2);
-  SetOamPlain(&oam_buf[2], -64, -72, 0x04, 0x3b, 2);
-  SetOamPlain(&oam_buf[3], -48, -72, 0x06, 0x3b, 2);
-}
-
-void CrystalCutscene_InitializePolyhedral() {  // 9ecdd9
-  poly_config1 = 156;
-  poly_config_color_mode = 1;
-  is_nmi_thread_active = 1;
-  intro_did_run_step = 1;
-  poly_base_x = 32;
-  poly_base_y = 32;
-  BYTE(poly_var1) = 32;
-  poly_which_model = 0;
-  poly_a = 16;
-  TS_copy = 0;
-  TM_copy = 0x16;
-}
-
--- a/ending.h
+++ /dev/null
@@ -1,92 +1,0 @@
-#pragma once
-
-typedef struct IntroSpriteEnt {
-  int8 x, y;
-  uint8 charnum, flags;
-  uint8 ext;
-} IntroSpriteEnt;
-
-void Intro_SetupScreen();
-void Intro_LoadTextPointersAndPalettes();
-void Credits_LoadScene_Overworld_PrepGFX();
-void Credits_LoadScene_Overworld_Overlay();
-void Credits_LoadScene_Overworld_LoadMap();
-void Credits_OperateScrollingAndTileMap();
-void Credits_LoadCoolBackground();
-void Credits_LoadScene_Dungeon();
-void Module18_GanonEmerges();
-void Module19_TriforceRoom();
-void Intro_InitializeBackgroundSettings();
-void Polyhedral_InitializeThread();
-void Module00_Intro();
-void Intro_Init();
-void Intro_Init_Continue();
-void Intro_Clear1kbBlocksOfWRAM();
-void Intro_InitializeMemory_darken();
-void IntroZeldaFadein();
-void Intro_FadeInBg();
-void Intro_SwordComingDown();
-void Intro_WaitPlayer();
-void FadeMusicAndResetSRAMMirror();
-void Intro_InitializeTriforcePolyThread();
-void Intro_InitGfx_Helper();
-void LoadTriforceSpritePalette();
-void Intro_HandleAllTriforceAnimations();
-void Scene_AnimateEverySprite();
-void Intro_AnimateTriforce();
-void Intro_RunStep();
-void Intro_AnimOneObj(int k);
-void Intro_SpriteType_A_0(int k);
-void Intro_SpriteType_B_0(int k);
-void AnimateSceneSprite_DrawTriangle(int k);
-void Intro_CopySpriteType4ToOam(int k);
-void EXIT_0CCA90(int k);
-void InitializeSceneSprite_Copyright(int k);
-void AnimateSceneSprite_Copyright(int k);
-void InitializeSceneSprite_Sparkle(int k);
-void AnimateSceneSprite_Sparkle(int k);
-void AnimateSceneSprite_AddObjectsToOamBuffer(int k, const IntroSpriteEnt *src, int num);
-void AnimateSceneSprite_MoveTriangle(int k);
-void TriforceRoom_PrepGFXSlotForPoly();
-void Credits_InitializePolyhedral();
-void AdvancePolyhedral();
-void TriforceRoom_HandlePoly();
-void Credits_AnimateTheTriangles();
-void InitializeSceneSprite_TriforceRoomTriangle(int k);
-void Intro_SpriteType_B_456(int k);
-void AnimateTriforceRoomTriangle_HandleContracting(int k);
-void InitializeSceneSprite_CreditsTriangle(int k);
-void AnimateSceneSprite_CreditsTriangle(int k);
-void Intro_DisplayLogo();
-void Intro_SetupSwordAndIntroFlash();
-void Intro_PeriodicSwordAndIntroFlash();
-void Module1A_Credits();
-void Credits_LoadNextScene_Overworld();
-void Credits_LoadNextScene_Dungeon();
-void Credits_PrepAndLoadSprites();
-void Credits_ScrollScene_Overworld();
-void Credits_ScrollScene_Dungeon();
-void Credits_HandleSceneFade();
-void Credits_SpriteDraw_DrawShadow(int k);
-void EndSequence_DrawShadow2(int k);
-void Ending_Func2(int k, uint8 ain);
-void Credits_SpriteDraw_ActivateAndRunSprite(int k, uint8 a);
-void Credits_SpriteDraw_PreexistingSpriteDraw(int k, uint8 a);
-void Credits_SpriteDraw_Single(int k, uint8 a, uint8 j);
-void Credits_SpriteDraw_SetShadowProp(int k, uint8 a);
-void Credits_SpriteDraw_AddSparkle(int j_count, uint8 xb, uint8 yb);
-void Credits_SpriteDraw_WalkLinkAwayFromPedestal(int k);
-void Credits_SpriteDraw_MoveSquirrel(int k);
-void Credits_SpriteDraw_CirclingBirds(int k);
-void Credits_HandleCameraScrollControl();
-void EndSequence_32();
-void Credits_FadeOutFixedCol();
-void Credits_FadeColorAndBeginAnimating();
-void Credits_AddNextAttribution();
-void Credits_AddEndingSequenceText();
-void Credits_BrightenTriangles();
-void Credits_StopCreditsScroll();
-void Credits_FadeAndDisperseTriangles();
-void Credits_FadeInTheEnd();
-void Credits_HangForever();
-void CrystalCutscene_InitializePolyhedral();
--- /dev/null
+++ b/extract_assets.bat
@@ -1,0 +1,25 @@
+@echo off
+
+2>nul (del zelda3_assets.dat)
+python assets/restool.py --extract-from-rom
+IF NOT ERRORLEVEL 0 goto ERROR
+
+IF NOT EXIST "zelda3_assets.dat" (
+  ECHO ERROR: The python program didn't generate zelda3_assets.dat successfully.
+  goto ERROR  
+) ELSE (
+  REM
+)
+
+goto DONE
+
+
+:ERROR
+ECHO:
+ECHO ERROR: Asset extraction failed!
+pause
+EXIT /B 1
+
+:DONE
+echo Complete!
+pause
\ No newline at end of file
--- a/features.h
+++ /dev/null
@@ -1,65 +1,0 @@
-// This file declares extensions to the base game
-#ifndef ZELDA3_FEATURES_H_
-#define ZELDA3_FEATURES_H_
-
-#include "types.h"
-
-// Special RAM locations that are unused but I use for compat things.
-enum {
-  kRam_APUI00 = 0x648,
-  kRam_CrystalRotateCounter = 0x649,
-  kRam_BugsFixed = 0x64a,
-  kRam_Features0 = 0x64c,
-};
-
-enum {
-  // Poly rendered uses correct speed
-  kBugFix_PolyRenderer = 1,
-  kBugFix_AncillaOverwrites = 1,
-  kBugFix_Latest = 1,
-};
-
-// Enum values for kRam_Features0
-enum {
-  kFeatures0_ExtendScreen64 = 1,
-  kFeatures0_SwitchLR = 2,
-  kFeatures0_TurnWhileDashing = 4,
-  kFeatures0_MirrorToDarkworld = 8,
-  kFeatures0_CollectItemsWithSword = 16,
-  kFeatures0_BreakPotsWithSword = 32,
-  kFeatures0_DisableLowHealthBeep = 64,
-  kFeatures0_SkipIntroOnKeypress = 128,
-  kFeatures0_ShowMaxItemsInYellow = 256,
-  kFeatures0_MoreActiveBombs = 512,
-
-  // This is set for visual fixes that don't affect game behavior but will affect ram compare.
-  kFeatures0_WidescreenVisualFixes = 1024,
-
-  kFeatures0_CarryMoreRupees = 2048,
-
-  kFeatures0_MiscBugFixes = 4096,
-
-  kFeatures0_CancelBirdTravel = 8192,
-
-  kFeatures0_GameChangingBugFixes = 16384,
-
-  kFeatures0_SwitchLRLimit = 32768,
-
-  kFeatures0_DimFlashes = 65536,
-};
-
-#define enhanced_features0 (*(uint32*)(g_ram+0x64c))
-#define msu_curr_sample (*(uint32*)(g_ram+0x650))
-#define msu_volume (*(uint8*)(g_ram+0x654))
-#define msu_track (*(uint8*)(g_ram+0x655))
-#define hud_inventory_order ((uint8*)(g_ram + 0x225)) // 4x6 bytes
-#define hud_cur_item_x (*(uint8*)(g_ram+0x656))
-#define hud_cur_item_l (*(uint8*)(g_ram+0x657))
-#define hud_cur_item_r (*(uint8*)(g_ram+0x658))
-
-
-
-extern uint32 g_wanted_zelda_features;
-
-
-#endif  // ZELDA3_FEATURES_H_
--- a/glsl_shader.c
+++ /dev/null
@@ -1,659 +1,0 @@
-// This file is heavily influenced by Snes9x
-#include "third_party/gl_core/gl_core_3_1.h"
-#include "glsl_shader.h"
-#include "util.h"
-#include "config.h"
-#include <stdio.h>
-#include <assert.h>
-#include <string.h>
-#define STB_IMAGE_IMPLEMENTATION
-#define STBI_NO_THREAD_LOCALS
-#define STBI_ONLY_PNG
-#define STBI_MAX_DIMENSIONS 4096
-#define STBI_NO_FAILURE_STRINGS
-#include "third_party/stb/stb_image.h"
-
-static GlslPass *ParseConfigKeyPass(GlslShader *gs, const char *key, const char *match) {
-  char *endp;
-  for (; *match; key++, match++) {
-    if (*key != *match)
-      return NULL;
-  }
-  if ((uint8)(*key - '0') >= 10)
-    return NULL;
-  uint pass = strtoul(key, &endp, 10);
-  if (pass >= gs->n_pass || *endp != 0)
-    return NULL;
-  return gs->pass + pass + 1;
-}
-
-static uint8 ParseScaleType(const char *s) {
-  return StringEqualsNoCase(s, "source") ? GLSL_SOURCE : 
-         StringEqualsNoCase(s, "viewport") ? GLSL_VIEWPORT :
-         StringEqualsNoCase(s, "absolute") ? GLSL_ABSOLUTE : GLSL_NONE;
-}
-
-static uint ParseWrapMode(const char *s) {
-  return StringEqualsNoCase(s, "repeat") ? GL_REPEAT :
-         StringEqualsNoCase(s, "clamp_to_edge") ? GL_CLAMP_TO_EDGE :
-         StringEqualsNoCase(s, "clamp") ? GL_CLAMP : GL_CLAMP_TO_BORDER;
-}
-
-static void GlslPass_Initialize(GlslPass *pass) {
-  pass->scale_x = 1.0f;
-  pass->scale_y = 1.0f;
-  pass->wrap_mode = GL_CLAMP_TO_BORDER;
-}
-
-static void ParseTextures(GlslShader *gs, char *value) {
-  char *id;
-  GlslTexture **nextp = &gs->first_texture;
-  for (int num = 0; (id = NextDelim(&value, ';')) != NULL && num < kGlslMaxTextures; num++) {
-    GlslTexture *t = calloc(sizeof(GlslTexture), 1);
-    t->id = strdup(id);
-    t->wrap_mode = GL_CLAMP_TO_BORDER;
-    t->filter = GL_NEAREST;
-    *nextp = t;
-    nextp = &t->next;
-  }
-}
-
-static bool ParseTextureKeyValue(GlslShader *gs, const char *key, const char *value) {
-  for (GlslTexture *t = gs->first_texture; t != NULL; t = t->next) {
-    const char *key2 = SkipPrefix(key, t->id);
-    if (!key2) continue;
-    if (*key2 == 0) {
-      StrSet(&t->filename, value);
-      return true;
-    } else if (!strcmp(key2, "_wrap_mode")) {
-      t->wrap_mode = ParseWrapMode(value);
-      return true;
-    } else if (!strcmp(key2, "_mipmap")) {
-      t->mipmap = ParseBool(value, NULL);
-      return true;
-    } else if (!strcmp(key2, "_linear")) {
-      t->filter = ParseBool(value, NULL) ? GL_LINEAR : GL_NEAREST;
-      return true;
-    }
-  }
-  return false;
-}
-
-static GlslParam *GlslShader_GetParam(GlslShader *gs, const char *id) {
-  GlslParam **pp = &gs->first_param;
-  for (; (*pp) != NULL; pp = &(*pp)->next)
-    if (!strcmp((*pp)->id, id))
-      return *pp;
-  GlslParam *p = (GlslParam *)calloc(1, sizeof(GlslParam));
-  *pp = p;
-  p->id = strdup(id);
-  return p;
-}
-
-static void ParseParameters(GlslShader *gs, char *value) {
-  char *id;
-  while ((id = NextDelim(&value, ';')) != NULL)
-    GlslShader_GetParam(gs, id);
-}
-
-static bool ParseParameterKeyValue(GlslShader *gs, const char *key, const char *value) {
-  for (GlslParam *p = gs->first_param; p != NULL; p = p->next) {
-    if (strcmp(p->id, key) == 0) {
-      p->value = atof(value);
-      p->has_value = true;
-      return true;
-    }
-  }
-  return false;
-}
-
-static void GlslShader_InitializePasses(GlslShader *gs, int passes) {
-  gs->n_pass = passes;
-  gs->pass = (GlslPass *)calloc(gs->n_pass + 1, sizeof(GlslPass));
-  for (int i = 0; i < gs->n_pass; i++)
-    GlslPass_Initialize(gs->pass + i + 1);
-}
-
-static bool GlslShader_ReadPresetFile(GlslShader *gs, const char *filename) {
-  char *data = (char *)ReadWholeFile(filename, NULL), *data_org = data, *line;
-  GlslPass *pass;
-  if (data == NULL)
-    return false;
-  for (int lineno = 1; (line = NextLineStripComments(&data)) != NULL; lineno++) {
-    char *value = SplitKeyValue(line), *t;
-    if (value == NULL) {
-      if (*line)
-        fprintf(stderr, "%s:%d: Expecting key=value\n", filename, lineno);
-      continue;
-    }
-    if (*value == '"') {
-      for (t = ++value; *t && *t != '"'; t++);
-      if (*t) *t = 0;
-    }
-
-    if (gs->n_pass == 0) {
-      if (strcmp(line, "shaders") != 0) {
-        fprintf(stderr, "%s:%d: Expecting 'shaders'\n", filename, lineno);
-        break;
-      }
-      int passes = strtoul(value, NULL, 10);
-      if (passes < 1 || passes > kGlslMaxPasses)
-        break;
-      GlslShader_InitializePasses(gs, passes);
-      continue;
-    }
-    if ((pass = ParseConfigKeyPass(gs, line, "filter_linear")) != NULL)
-      pass->filter = ParseBool(value, NULL) ? GL_LINEAR : GL_NEAREST;
-    else if ((pass = ParseConfigKeyPass(gs, line, "scale_type")) != NULL)
-      pass->scale_type_x = pass->scale_type_y = ParseScaleType(value);
-    else if ((pass = ParseConfigKeyPass(gs, line, "scale_type_x")) != NULL)
-      pass->scale_type_x = ParseScaleType(value);
-    else if ((pass = ParseConfigKeyPass(gs, line, "scale_type_y")) != NULL)
-      pass->scale_type_y = ParseScaleType(value);
-    else if ((pass = ParseConfigKeyPass(gs, line, "scale")) != NULL)
-      pass->scale_x = pass->scale_y = atof(value);
-    else if ((pass = ParseConfigKeyPass(gs, line, "scale_x")) != NULL)
-      pass->scale_x = atof(value);
-    else if ((pass = ParseConfigKeyPass(gs, line, "scale_y")) != NULL)
-      pass->scale_y = atof(value);
-    else if ((pass = ParseConfigKeyPass(gs, line, "shader")) != NULL)
-      StrSet(&pass->filename, value);
-    else if ((pass = ParseConfigKeyPass(gs, line, "wrap_mode")) != NULL)
-      pass->wrap_mode = ParseWrapMode(value);
-    else if ((pass = ParseConfigKeyPass(gs, line, "mipmap_input")) != NULL)
-      pass->mipmap_input = ParseBool(value, NULL);
-    else if ((pass = ParseConfigKeyPass(gs, line, "frame_count_mod")) != NULL)
-      pass->frame_count_mod = atoi(value);
-    else if ((pass = ParseConfigKeyPass(gs, line, "float_framebuffer")) != NULL)
-      pass->float_framebuffer = ParseBool(value, NULL);
-    else if ((pass = ParseConfigKeyPass(gs, line, "srgb_framebuffer")) != NULL)
-      pass->srgb_framebuffer = ParseBool(value, NULL);
-    else if ((pass = ParseConfigKeyPass(gs, line, "alias")) != NULL)
-      ;
-    else if (strcmp(line, "textures") == 0 && gs->first_texture == NULL)
-      ParseTextures(gs, value);
-    else if (strcmp(line, "parameters") == 0)
-      ParseParameters(gs, value);
-    else if (!ParseTextureKeyValue(gs, line, value) && !ParseParameterKeyValue(gs, line, value))
-      fprintf(stderr, "%s:%d: Unknown key '%s'\n", filename, lineno, line);
-  }
-  free(data_org);
-  return gs->n_pass != 0;
-}
-
-void GlslShader_ReadShaderFile(GlslShader *gs, const char *filename, ByteArray *result) {
-  char *data = (char *)ReadWholeFile(filename, NULL), *data_org = data, *line;
-  if (data == NULL) {
-    fprintf(stderr, "Unable to read file '%s'\n", filename);
-    return;
-  }
-  while ((line = NextDelim(&data, '\n')) != NULL) {
-    size_t linelen = strlen(line);
-    if (linelen >= 8 && memcmp(line, "#include", 8) == 0) {
-      char *tt = line + 8;
-      char *new_filename = ReplaceFilenameWithNewPath(filename, NextPossiblyQuotedString(&tt));
-      GlslShader_ReadShaderFile(gs, new_filename, result);
-      free(new_filename);
-    } else if (linelen >= 17 && memcmp(line, "#pragma parameter", 17) == 0) {
-      char *tt = line + 17;
-      GlslParam *param = GlslShader_GetParam(gs, NextPossiblyQuotedString(&tt));
-      NextPossiblyQuotedString(&tt); // skip name
-      float value = atof(NextPossiblyQuotedString(&tt));
-      if (!param->has_value)
-        param->value = value;
-      param->min = atof(NextPossiblyQuotedString(&tt));
-      param->max = atof(NextPossiblyQuotedString(&tt));
-      // skip step
-    } else {
-      line[linelen] = '\n';
-      ByteArray_AppendData(result, (uint8 *)line, linelen + 1);
-    }
-  }
-  free(data_org);
-}
-
-size_t LengthOfInitialComments(const uint8 *data, size_t size) {
-  const uint8 *data_org = data, *data_end = data + size;
-  while (data != data_end) {
-    uint8 c = *data++;
-    if (c == ' ' || c == '\t' || c == '\r' || c == '\n')
-      continue;
-    if (c != '/' || data == data_end) {
-      data--;
-      break;
-    }
-    c = *data++;
-    if (c == '/') {
-      while (data != data_end && *data++ != '\n') {}
-    } else if (c == '*') {
-      do {
-        if (data_end - data < 2)
-          return 0;
-      } while (*data++ != '*' || data[0] != '/');
-      data++;
-    } else {
-      data--;
-      break;
-    }
-  }
-  return data - data_org;
-}
-
-static bool GlslPass_Compile(GlslPass *p, uint type, const uint8 *data, size_t size, bool use_opengl_es) {
-  static const char kVertexPrefix[] =   "#define VERTEX\n#define PARAMETER_UNIFORM\n";
-  static const char kFragmentPrefixCore[] = "#define FRAGMENT\n#define PARAMETER_UNIFORM\n";
-  static const char kFragmentPrefixEs[] = "#define FRAGMENT\n#define PARAMETER_UNIFORM\n" \
-					"precision mediump float;";
-  const GLchar *strings[3];
-  GLint lengths[3];
-  char buffer[256];
-  GLint compile_status = 0;
-  size_t skip = 0;
-
-  size_t commsize = LengthOfInitialComments(data, size);
-  data += commsize, size -= commsize;
-
-  if (size < 8 || memcmp(data, "#version", 8) != 0) {
-    if (!use_opengl_es) {
-      strings[0] = "#version 330\n";
-      lengths[0] = sizeof("#version 330\n") - 1;
-    } else {
-      strings[0] = "#version 300 es\n";
-      lengths[0] = sizeof("#version 300 es\n") - 1;
-    }
-  } else {
-    while (skip < size && data[skip++] != '\n') {}
-    strings[0] = (char*)data;
-    lengths[0] = (int)skip;
-  }
-  if (type == GL_VERTEX_SHADER) {
-    strings[1] = (char *)kVertexPrefix;
-    lengths[1] = sizeof(kVertexPrefix) - 1;
-  } else {
-    strings[1] = (use_opengl_es) ? (char *)kFragmentPrefixEs : kFragmentPrefixCore;
-    lengths[1] = (use_opengl_es) ? sizeof(kFragmentPrefixEs) - 1 : sizeof(kFragmentPrefixCore) - 1;
-  }
-  strings[2] = (GLchar *)data + skip;
-  lengths[2] = (int)(size - skip);
-  uint shader = glCreateShader(type);
-  glShaderSource(shader, 3, strings, lengths);
-  glCompileShader(shader);
-  glGetShaderiv(shader, GL_COMPILE_STATUS, &compile_status);
-  buffer[0] = 0;
-  glGetShaderInfoLog(shader, sizeof(buffer), NULL, buffer);
-  if (compile_status != GL_TRUE || buffer[0]) {
-    fprintf(stderr, "%s compiling %s shader in file '%s':\n%s\n",
-            compile_status != GL_TRUE ? "Error" : "While",
-            type == GL_VERTEX_SHADER ? "vertex" : "fragment", p->filename, buffer);
-  }
-  if (compile_status == GL_TRUE)
-    glAttachShader(p->gl_program, shader);
-  glDeleteShader(shader);
-  return (compile_status == GL_TRUE);
-}
-
-static void GlslTextureUniform_Read(uint program, const char *prefix, int i, GlslTextureUniform *result) {
-  char buf[40];
-  char *e = &buf[snprintf(buf, sizeof(buf), i >= 0 ? "%s%u" : "%s", prefix, i)];
-  memcpy(e, "Texture", 8);
-  result->Texture = glGetUniformLocation(program, buf);
-  memcpy(e, "InputSize", 10);
-  result->InputSize = glGetUniformLocation(program, buf);
-  memcpy(e, "TextureSize", 12);
-  result->TextureSize = glGetUniformLocation(program, buf);
-  memcpy(e, "TexCoord", 9);
-  result->TexCoord = glGetAttribLocation(program, buf);
-}
-
-static const float kMvpMatrixOrtho[16] = {
-   2.0f,  0.0f,  0.0f,  0.0f,
-   0.0f,  2.0f,  0.0f,  0.0f,
-   0.0f,  0.0f, -1.0f,  0.0f,
-  -1.0f, -1.0f,  0.0f,  1.0f
-};
-
-static void GlslShader_GetUniforms(GlslShader *gs) {
-  int pass_idx = 1;
-  gs->max_prev_frame = 0;
-  for (GlslPass *p = gs->pass + 1, *p_end = p + gs->n_pass; p < p_end; p++, pass_idx++) {
-    uint program = p->gl_program;
-    glUseProgram(program);
-
-    GLint MVPMatrix = glGetUniformLocation(program, "MVPMatrix");
-    if (MVPMatrix >= 0)
-      glUniformMatrix4fv(MVPMatrix, 1, GL_FALSE, kMvpMatrixOrtho);
-
-    GlslTextureUniform_Read(program, "", -1, &p->unif.Top);
-    p->unif.OutputSize = glGetUniformLocation(program, "OutputSize");
-    p->unif.FrameCount = glGetUniformLocation(program, "FrameCount");
-    p->unif.FrameDirection = glGetUniformLocation(program, "FrameDirection");
-    p->unif.LUTTexCoord = glGetAttribLocation(program, "LUTTexCoord");
-    p->unif.VertexCoord = glGetAttribLocation(program, "VertexCoord");
-    GlslTextureUniform_Read(program, "Orig", -1, &p->unif.Orig);
-    for (int j = 0; j < 7; j++) {
-      GlslTextureUniform_Read(program, "Prev", j ? j : -1, &p->unif.Prev[j]);
-      if (p->unif.Prev[j].Texture >= 0)
-        gs->max_prev_frame = j + 1;
-    }
-    for (int j = 0; j < gs->n_pass; j++) {
-      GlslTextureUniform_Read(program, "Pass", j, &p->unif.Pass[j]);
-      GlslTextureUniform_Read(program, "PassPrev", j, &p->unif.PassPrev[j]);
-    }
-    GlslTexture *t = gs->first_texture;
-    for (int j = 0; t != NULL; t = t->next, j++)
-      p->unif.Texture[j] = glGetUniformLocation(program, t->id);
-    for (GlslParam *pa = gs->first_param; pa != NULL; pa = pa->next)
-      pa->uniform[pass_idx] = glGetUniformLocation(program, pa->id);
-  }
-  glUseProgram(0);
-}
-
-static bool IsGlslFilename(const char *filename) {
-  size_t len = strlen(filename);
-  return len >= 5 && memcmp(filename + len - 5, ".glsl", 5) == 0;
-}
-
-GlslShader *GlslShader_CreateFromFile(const char *filename, bool opengl_es) {
-  char buffer[256];
-  GLint link_status;
-  ByteArray shader_code = { 0 };
-  bool success = false;
-  GlslShader *gs = (GlslShader *)calloc(sizeof(GlslShader), 1);
-  if (!gs)
-    return gs;
-
-  if (IsGlslFilename(filename)) {
-    GlslShader_InitializePasses(gs, 1);
-    gs->pass[1].filename = strdup(filename);
-    filename = "";
-  } else {
-    if (!GlslShader_ReadPresetFile(gs, filename)) {
-      fprintf(stderr, "Unable to read file '%s'\n", filename);
-      goto FAIL;
-    }
-  }
-  for (int i = 1; i <= gs->n_pass; i++) {
-    GlslPass *p = gs->pass + i;
-    shader_code.size = 0;
-
-    if (p->filename == NULL) {
-      fprintf(stderr, "shader%d attribute missing\n", i - 1);
-      goto FAIL;
-    }
-
-    char *new_filename = ReplaceFilenameWithNewPath(filename, p->filename);
-    GlslShader_ReadShaderFile(gs, new_filename, &shader_code);
-    free(new_filename);
-
-    if (shader_code.size == 0) {
-      fprintf(stderr, "Couldn't read shader in file '%s'\n", p->filename);
-      goto FAIL;
-    }
-    p->gl_program = glCreateProgram();
-    if (!GlslPass_Compile(p, GL_VERTEX_SHADER, shader_code.data, shader_code.size, opengl_es) ||
-        !GlslPass_Compile(p, GL_FRAGMENT_SHADER, shader_code.data, shader_code.size, opengl_es)) {
-      goto FAIL;
-    }
-    glLinkProgram(p->gl_program);
-    glGetProgramiv(p->gl_program, GL_LINK_STATUS, &link_status);
-    buffer[0] = 0;
-    glGetProgramInfoLog(p->gl_program, sizeof(buffer), NULL, buffer);
-    if (link_status != GL_TRUE || buffer[0])
-      fprintf(stderr, "%s linking shader in file '%s':\n%s\n",
-              link_status != GL_TRUE ? "Error" : "While", p->filename, buffer);
-    if (link_status != GL_TRUE)
-      goto FAIL;
-    glGenFramebuffers(1, &p->gl_fbo);
-    glGenTextures(1, &p->gl_texture);
-  }
-  for (GlslTexture *t = gs->first_texture; t; t = t->next) {
-    glGenTextures(1, &t->gl_texture);
-    glBindTexture(GL_TEXTURE_2D, t->gl_texture);
-    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, t->wrap_mode);
-    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, t->wrap_mode);
-    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, t->filter);
-    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, t->mipmap ? 
-                    (t->filter == GL_LINEAR ? GL_LINEAR_MIPMAP_LINEAR : GL_NEAREST_MIPMAP_NEAREST) : t->filter);
-    if (t->filename) {
-      char *new_filename = ReplaceFilenameWithNewPath(filename, t->filename);
-      int imw, imh, imn;
-      unsigned char *data = stbi_load(new_filename, &imw, &imh, &imn, 0);
-      if (!data) {
-        fprintf(stderr, "Unable to read PNG '%s'\n", new_filename);
-      } else {
-        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, imw, imh, 0, 
-                     (imn == 4) ? GL_RGBA : (imn == 3) ? GL_RGB : GL_LUMINANCE, GL_UNSIGNED_BYTE, data);
-      }
-      free(data);
-      free(new_filename);
-    }
-    if (t->mipmap)
-      glGenerateMipmap(GL_TEXTURE_2D);
-  }
-  for (GlslParam *p = gs->first_param; p; p = p->next)
-    p->value = (p->value < p->min) ? p->min : (p->value > p->max) ? p->max : p->value;
-
-  GlslShader_GetUniforms(gs);
-
-  for (int i = 0; i < gs->max_prev_frame; i++)
-    glGenTextures(1, &gs->prev_frame[-i - 1 & 7].gl_texture);
-
-  static const GLfloat kTexCoords[16] = {
-    0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f,
-    0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f
-  };
-  glGenBuffers(1, &gs->gl_vbo);
-  glBindBuffer(GL_ARRAY_BUFFER, gs->gl_vbo);
-  glBufferData(GL_ARRAY_BUFFER, sizeof(kTexCoords), kTexCoords, GL_STATIC_DRAW);
-  glBindBuffer(GL_ARRAY_BUFFER, 0);
-
-  success = true;
-FAIL:
-  if (!success) {
-    GlslShader_Destroy(gs);
-    gs = NULL;
-  }
-  ByteArray_Destroy(&shader_code);
-  return gs;
-}
-
-void GlslShader_Destroy(GlslShader *gs) {
-  for (GlslPass *p = gs->pass + 1, *p_end = p + gs->n_pass; p < p_end; p++) {
-    glDeleteProgram(p->gl_program);
-    glDeleteTextures(1, &p->gl_texture);
-    glDeleteFramebuffers(1, &p->gl_fbo);
-    free(p->filename);
-  }
-  free(gs->pass);
-  GlslTexture *t;
-  while ((t = gs->first_texture) != NULL) {
-    gs->first_texture = t->next;
-    glDeleteTextures(1, &t->gl_texture);
-    free(t->id);
-    free(t->filename);
-    free(t);
-  }
-  GlslParam *pp;
-  while ((pp = gs->first_param) != NULL) {
-    gs->first_param = pp->next;
-    free(pp->id);
-    free(pp);
-  }
-  for (int i = 0; i < 8; i++)
-    glDeleteTextures(1, &gs->prev_frame[i].gl_texture);
-  glDeleteBuffers(1, &gs->gl_vbo);
-  free(gs);
-}
-
-enum {
-  kMaxVaosInRenderCtx = 11 + kGlslMaxPasses * 2
-};
-
-typedef struct RenderCtx {
-  uint texture_unit;
-  uint offset;
-  uint num_vaos;
-  uint vaos[kMaxVaosInRenderCtx];
-} RenderCtx;
-
-static void RenderCtx_SetTexture(RenderCtx *ctx, int textureu, uint texture_id) {
-  if (textureu >= 0) {
-    glActiveTexture(GL_TEXTURE0 + ctx->texture_unit);
-    glBindTexture(GL_TEXTURE_2D, texture_id);
-    glUniform1i(textureu, ctx->texture_unit++);
-  }
-}
-
-static void RenderCtx_SetTexCoords(RenderCtx *ctx, int tex_coord, uintptr_t offset) {
-  if (tex_coord >= 0) {
-    assert(ctx->num_vaos < kMaxVaosInRenderCtx);
-    ctx->vaos[ctx->num_vaos++] = tex_coord;
-    glVertexAttribPointer(tex_coord, 2, GL_FLOAT, GL_FALSE, 0, (void *)offset);
-    glEnableVertexAttribArray(tex_coord);
-  }
-}
-
-static void RenderCtx_SetGlslTextureUniform(RenderCtx *ctx, GlslTextureUniform *u,
-                                            int width, int height, uint texture) {
-  float size[2] = { width, height };
-  RenderCtx_SetTexture(ctx, u->Texture, texture);
-  if (u->InputSize >= 0)
-    glUniform2fv(u->InputSize, 1, size);
-  if (u->TextureSize >= 0)
-    glUniform2fv(u->TextureSize, 1, size);
-  RenderCtx_SetTexCoords(ctx, u->TexCoord, ctx->offset);
-}
-
-static void GlslShader_SetShaderVars(GlslShader *gs, RenderCtx *ctx, int pass) {
-  GlslPass *p = &gs->pass[pass];
-    
-  RenderCtx_SetGlslTextureUniform(ctx, &p->unif.Top, p[-1].width, p[-1].height, p[-1].gl_texture);
-  if (p->unif.OutputSize >= 0) {
-    float output_size[2] = { (float)p[0].width, (float)p[0].height };
-    glUniform2fv(p->unif.OutputSize, 1, output_size);
-  }
-  if (p->unif.FrameCount >= 0)
-    glUniform1i(p->unif.FrameCount, p->frame_count_mod ? 
-                gs->frame_count % p->frame_count_mod : gs->frame_count);
-  if (p->unif.FrameDirection >= 0)
-    glUniform1i(p->unif.FrameDirection, 1);
-  RenderCtx_SetTexCoords(ctx, p->unif.LUTTexCoord, ctx->offset);
-  RenderCtx_SetTexCoords(ctx, p->unif.VertexCoord, 0);
-  RenderCtx_SetGlslTextureUniform(ctx, &p->unif.Orig, gs->pass[0].width, gs->pass[0].height, gs->pass[0].gl_texture);
-  // Prev, Prev1-Prev6 uniforms
-  for (int i = 0; i < gs->max_prev_frame; i++) {
-    GlTextureWithSize *t = &gs->prev_frame[(gs->frame_count - 1 - i) & 7];
-    assert(t->gl_texture != 0);
-    if (t->width)
-      RenderCtx_SetGlslTextureUniform(ctx, &p->unif.Prev[i], t->width, t->height, t->gl_texture);
-  }
-  // Texture uniforms
-  int tctr = 0;
-  for (GlslTexture *t = gs->first_texture; t; t = t->next, tctr++)
-    RenderCtx_SetTexture(ctx, p->unif.Texture[tctr], t->gl_texture);
-  // PassX uniforms
-  for (int i = 1; i < pass; i++)
-    RenderCtx_SetGlslTextureUniform(ctx, &p->unif.Pass[i], gs->pass[i].width, gs->pass[i].height, gs->pass[i].gl_texture);
-  // PassPrevX uniforms
-  for (int i = 1; i < pass; i++)
-    RenderCtx_SetGlslTextureUniform(ctx, &p->unif.PassPrev[pass - i], gs->pass[i].width, gs->pass[i].height, gs->pass[i].gl_texture);
-  // #parameter uniforms
-  for (GlslParam *pa = gs->first_param; pa != NULL; pa = pa->next)
-    if (pa->uniform[pass] >= 0)
-      glUniform1f(pa->uniform[pass], pa->value);
-
-  glActiveTexture(GL_TEXTURE0);
-}
-
-void GlslShader_Render(GlslShader *gs, GlTextureWithSize *tex, int viewport_x, int viewport_y, int viewport_width, int viewport_height) {
-  gs->pass[0].gl_texture = tex->gl_texture;
-  gs->pass[0].width = tex->width;
-  gs->pass[0].height = tex->height;
-
-  GLint previous_framebuffer;
-  glGetIntegerv(GL_FRAMEBUFFER_BINDING, &previous_framebuffer);
-  glBindBuffer(GL_ARRAY_BUFFER, gs->gl_vbo);
-
-  for (int pass = 1; pass <= gs->n_pass; pass++) {
-    bool last_pass = pass == gs->n_pass;
-    GlslPass *p = gs->pass + pass;
-
-    switch (p->scale_type_x) {
-    case GLSL_ABSOLUTE: p->width = (uint16)p->scale_x; break;
-    case GLSL_SOURCE: p->width = (uint16)(p[-1].width * p->scale_x); break;
-    case GLSL_VIEWPORT: p->width = (uint16)(viewport_width * p->scale_x); break;
-    default: p->width = (uint16)(last_pass ? viewport_width : (p[-1].width * p->scale_x)); break;
-    }
-
-    switch (p->scale_type_y) {
-    case GLSL_ABSOLUTE: p->height = (uint16)p->scale_y; break;
-    case GLSL_SOURCE: p->height = (uint16)(p[-1].height * p->scale_y); break;
-    case GLSL_VIEWPORT: p->height = (uint16)(viewport_height * p->scale_y); break;
-    default: p->height = (uint16)(last_pass ? viewport_height : (p[-1].height * p->scale_y)); break;
-    }
-
-    if (!last_pass) {
-      // output to a texture
-      glBindTexture(GL_TEXTURE_2D, p->gl_texture);
-      if (p->srgb_framebuffer) {
-        glEnable(GL_FRAMEBUFFER_SRGB);
-        glTexImage2D(GL_TEXTURE_2D, 0, GL_SRGB8_ALPHA8, p->width, p->height, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, NULL);
-      } else {
-        glTexImage2D(GL_TEXTURE_2D, 0, p->float_framebuffer ? GL_RGBA32F : GL_RGBA,
-                     p->width, p->height, 0, GL_RGBA,
-                     p->float_framebuffer ? GL_FLOAT : GL_UNSIGNED_INT_8_8_8_8, NULL);
-      }
-      glViewport(0, 0, p->width, p->height);
-      glBindFramebuffer(GL_FRAMEBUFFER, p->gl_fbo);
-      glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, p->gl_texture, 0);
-    } else {
-      // output to screen
-      glBindFramebuffer(GL_FRAMEBUFFER, previous_framebuffer);
-      glViewport(viewport_x, viewport_y, viewport_width, viewport_height);
-    }
-
-    glBindTexture(GL_TEXTURE_2D, p[-1].gl_texture);
-
-    uint filter = p->filter ? p->filter : (last_pass && g_config.linear_filtering) ? GL_LINEAR : GL_NEAREST;
-    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter);
-    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, p->mipmap_input ? 
-                    (filter == GL_LINEAR ? GL_LINEAR_MIPMAP_LINEAR : GL_NEAREST_MIPMAP_NEAREST) : filter);
-    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, p->wrap_mode);
-    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, p->wrap_mode);
-    if (p->mipmap_input)
-      glGenerateMipmap(GL_TEXTURE_2D);
-    glUseProgram(p->gl_program);
-
-    RenderCtx ctx;
-    ctx.texture_unit = ctx.num_vaos = 0;
-    ctx.offset = last_pass ? sizeof(float) * 8 : 0;
-    GlslShader_SetShaderVars(gs, &ctx, pass);
-    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
-    for(int i = 0; i < ctx.num_vaos; i++)
-      glDisableVertexAttribArray(ctx.vaos[i]);
-    if (p->srgb_framebuffer)
-      glDisable(GL_FRAMEBUFFER_SRGB);
-  }
-
-  glBindFramebuffer(GL_FRAMEBUFFER, previous_framebuffer);
-  glUseProgram(0);
-  glBindTexture(GL_TEXTURE_2D, 0);
-  glBindBuffer(GL_ARRAY_BUFFER, 0);
-
-  // Store the input frame in the prev array, and extract the next one.
-  if (gs->max_prev_frame != 0) {
-    // 01234567
-    //    43210
-    // ^-- store pos
-    //    ^-- load pos
-    GlTextureWithSize *store_pos = &gs->prev_frame[gs->frame_count & 7];
-    GlTextureWithSize *load_pos = &gs->prev_frame[gs->frame_count - gs->max_prev_frame & 7];
-    assert(store_pos->gl_texture == 0);
-    *store_pos = *tex;
-    *tex = *load_pos;
-    memset(load_pos, 0, sizeof(GlTextureWithSize));
-  }
-
-  gs->frame_count++;
-}
-
--- a/glsl_shader.h
+++ /dev/null
@@ -1,99 +1,0 @@
-#ifndef ZELDA3_GLSL_SHADER_H_
-#define ZELDA3_GLSL_SHADER_H_
-
-#include "types.h"
-
-enum {
-  kGlslMaxPasses = 20,
-  kGlslMaxTextures = 10,
-};
-
-enum GLSLScaleType {
-  GLSL_NONE,
-  GLSL_SOURCE,
-  GLSL_VIEWPORT,
-  GLSL_ABSOLUTE
-};
-
-typedef struct GlslTextureUniform {
-  int Texture;
-  int InputSize;
-  int TextureSize;
-  int TexCoord;
-} GlslTextureUniform;
-
-typedef struct GlslUniforms {
-  GlslTextureUniform Top;
-  int OutputSize;
-  int FrameCount, FrameDirection;
-  int LUTTexCoord;
-  int VertexCoord;
-  GlslTextureUniform Orig;
-  GlslTextureUniform Prev[7];
-  GlslTextureUniform Pass[kGlslMaxPasses];
-  GlslTextureUniform PassPrev[kGlslMaxPasses];
-  int Texture[kGlslMaxTextures];
-} GlslUniforms;
-
-typedef struct GlslPass {
-  char *filename;
-  uint8 scale_type_x, scale_type_y;
-  bool float_framebuffer;
-  bool srgb_framebuffer;
-  bool mipmap_input;
-  float scale_x, scale_y;
-  uint wrap_mode;
-  uint frame_count_mod;
-  uint frame_count;
-  uint gl_program, gl_fbo;
-  uint filter;
-  uint gl_texture;
-  uint16 width, height;
-  GlslUniforms unif;
-} GlslPass;
-
-typedef struct GlTextureWithSize {
-  uint gl_texture;
-  uint16 width, height;
-} GlTextureWithSize;
-
-typedef struct GlslTexture {
-  struct GlslTexture *next;
-  char *id;
-  char *filename;
-  uint filter;
-  uint gl_texture;
-  uint wrap_mode;
-  bool mipmap;
-  int width;
-  int height;
-} GlslTexture;
-
-typedef struct GlslParam {
-  struct GlslParam *next;
-  char *id;
-  bool has_value;
-  float value;
-  float min;
-  float max;
-  uint uniform[kGlslMaxPasses];
-} GlslParam;
-
-typedef struct GlslShader {
-  int n_pass;
-  GlslPass *pass;
-  GlslParam *first_param;
-  GlslTexture *first_texture;
-  uint *gl_vao;
-  uint gl_vbo;
-  uint frame_count;
-  int max_prev_frame;
-  GlTextureWithSize prev_frame[8];
-} GlslShader;
-
-GlslShader *GlslShader_CreateFromFile(const char *filename, bool opengl_es);
-void GlslShader_Destroy(GlslShader *gs);
-void GlslShader_Render(GlslShader *gs, GlTextureWithSize *tex, int viewport_x, int viewport_y, int viewport_width, int viewport_height);
-
-
-#endif  // ZELDA3_GLSL_SHADER_H_
--- a/hud.c
+++ /dev/null
@@ -1,1554 +1,0 @@
-#include "hud.h"
-#include "zelda_rtl.h"
-
-#include "variables.h"
-#include "messaging.h"
-
-enum {
-  kNewStyleInventory = 0,
-  kHudItemCount = kNewStyleInventory ? 24 : 20,
-};
-
-typedef struct ItemBoxGfx {
-  uint16 v[4];
-} ItemBoxGfx;
-
-static void Hud_DrawItem(uint16 *dst, const ItemBoxGfx *src);
-static bool Hud_DoWeHaveThisItem(uint8 item);
-static void Hud_EquipPrevItem(uint8 *item);
-static void Hud_EquipNextItem(uint8 *item);
-static int Hud_GetItemPosition(int item);
-static void Hud_ReorderItem(int direction);
-static void Hud_Update_Magic();
-static void Hud_Update_Inventory();
-static void Hud_Update_Hearts();
-
-const uint8 kMaxBombsForLevel[] = { 10, 15, 20, 25, 30, 35, 40, 50 };
-const uint8 kMaxArrowsForLevel[] = { 30, 35, 40, 45, 50, 55, 60, 70 };
-static const uint8 kMaxHealthForLevel[] = { 9, 9, 9, 9, 9, 9, 9, 9, 17, 17, 17, 17, 17, 17, 17, 25, 25, 25, 25, 25, 25 };
-
-#define HUDXY(x, y) ((x) + (y) * 32)
-
-static const uint16 kHudItemInVramPtr_New[24] = {
-  HUDXY(2,  7), HUDXY(5,  7), HUDXY(8,  7), HUDXY(11,  7), HUDXY(14,  7), HUDXY(17, 7),
-  HUDXY(2, 10), HUDXY(5, 10), HUDXY(8, 10), HUDXY(11, 10), HUDXY(14, 10), HUDXY(17, 10),
-  HUDXY(2, 13), HUDXY(5, 13), HUDXY(8, 13), HUDXY(11, 13), HUDXY(14, 13), HUDXY(17, 13),
-  HUDXY(2, 16), HUDXY(5, 16), HUDXY(8, 16), HUDXY(11, 16), HUDXY(14, 16), HUDXY(17, 16),
-};
-
-static const uint16 kHudItemInVramPtr_Old[20] = {
-  HUDXY(4,  7), HUDXY(7,  7), HUDXY(10,  7), HUDXY(13,  7), HUDXY(16,  7),
-  HUDXY(4, 10), HUDXY(7, 10), HUDXY(10, 10), HUDXY(13, 10), HUDXY(16, 10),
-  HUDXY(4, 13), HUDXY(7, 13), HUDXY(10, 13), HUDXY(13, 13), HUDXY(16, 13),
-  HUDXY(4, 16), HUDXY(7, 16), HUDXY(10, 16), HUDXY(13, 16), HUDXY(16, 16),
-};
-
-
-#define kHudItemInVramPtr (kNewStyleInventory ? kHudItemInVramPtr_New : kHudItemInVramPtr_Old)
-
-static const ItemBoxGfx kHudItemBottles[9] = {
-  {{0x20f5, 0x20f5, 0x20f5, 0x20f5}},
-  {{0x2044, 0x2045, 0x2046, 0x2047}},
-  {{0x2837, 0x2838, 0x2cc3, 0x2cd3}},
-  {{0x24d2, 0x64d2, 0x24e2, 0x24e3}},
-  {{0x3cd2, 0x7cd2, 0x3ce2, 0x3ce3}},
-  {{0x2cd2, 0x6cd2, 0x2ce2, 0x2ce3}},
-  {{0x2855, 0x6855, 0x2c57, 0x2c5a}},
-  {{0x2837, 0x2838, 0x2839, 0x283a}},
-  {{0x2837, 0x2838, 0x2839, 0x283a}},
-};
-static const ItemBoxGfx kHudItemBow[5] = {
-  {{0x20f5, 0x20f5, 0x20f5, 0x20f5}},
-  {{0x28ba, 0x28e9, 0x28e8, 0x28cb}},
-  {{0x28ba, 0x284a, 0x2849, 0x28cb}},
-  {{0x28ba, 0x28e9, 0x28e8, 0x28cb}},
-  {{0x28ba, 0x28bb, 0x24ca, 0x28cb}},
-};
-static const ItemBoxGfx kHudItemBoomerang[3] = {
-  {{0x20f5, 0x20f5, 0x20f5, 0x20f5}},
-  {{0x2cb8, 0x2cb9, 0x2cf5, 0x2cc9}},
-  {{0x24b8, 0x24b9, 0x24f5, 0x24c9}},
-};
-static const ItemBoxGfx kHudItemHookshot[2] = {
-  {{0x20f5, 0x20f5, 0x20f5, 0x20f5}},
-  {{0x24f5, 0x24f6, 0x24c0, 0x24f5}},
-};
-static const ItemBoxGfx kHudItemBombs[2] = {
-  {{0x20f5, 0x20f5, 0x20f5, 0x20f5}},
-  {{0x2cb2, 0x2cb3, 0x2cc2, 0x6cc2}},
-};
-static const ItemBoxGfx kHudItemMushroom[3] = {
-  {{0x20f5, 0x20f5, 0x20f5, 0x20f5}},
-  {{0x2444, 0x2445, 0x2446, 0x2447}},
-  {{0x203b, 0x203c, 0x203d, 0x203e}},
-};
-static const ItemBoxGfx kHudItemFireRod[2] = {
-  {{0x20f5, 0x20f5, 0x20f5, 0x20f5}},
-  {{0x24b0, 0x24b1, 0x24c0, 0x24c1}},
-};
-static const ItemBoxGfx kHudItemIceRod[2] = {
-  {{0x20f5, 0x20f5, 0x20f5, 0x20f5}},
-  {{0x2cb0, 0x2cbe, 0x2cc0, 0x2cc1}},
-};
-static const ItemBoxGfx kHudItemBombos[2] = {
-  {{0x20f5, 0x20f5, 0x20f5, 0x20f5}},
-  {{0x287d, 0x287e, 0xe87e, 0xe87d}},
-};
-static const ItemBoxGfx kHudItemEther[2] = {
-  {{0x20f5, 0x20f5,  0x20f5,  0x20f5}},
-  {{0x2876, 0x2877, 0xE877, 0xE876}},
-};
-static const ItemBoxGfx kHudItemQuake[2] = {
-  {{0x20f5, 0x20f5,  0x20f5,  0x20f5}},
-  {{0x2866, 0x2867, 0xE867, 0xE866}},
-};
-static const ItemBoxGfx kHudItemTorch[2] = {
-  {{0x20f5, 0x20f5, 0x20f5, 0x20f5}},
-  {{0x24bc, 0x24bd, 0x24cc, 0x24cd}},
-};
-static const ItemBoxGfx kHudItemHammer[2] = {
-  {{0x20f5, 0x20f5, 0x20f5, 0x20f5}},
-  {{0x20b6, 0x20b7, 0x20c6, 0x20c7}},
-};
-static const ItemBoxGfx kHudItemFlute[4] = {
-  {{0x20f5, 0x20f5, 0x20f5, 0x20f5}},
-  {{0x20d0, 0x20d1, 0x20e0, 0x20e1}},
-  {{0x2cd4, 0x2cd5, 0x2ce4, 0x2ce5}},
-  {{0x2cd4, 0x2cd5, 0x2ce4, 0x2ce5}},
-};
-static const ItemBoxGfx kHudItemBugNet[2] = {
-  {{0x20f5, 0x20f5, 0x20f5, 0x20f5}},
-  {{0x3c40, 0x3c41, 0x2842, 0x3c43}},
-};
-static const ItemBoxGfx kHudItemBookMudora[2] = {
-  {{0x20f5, 0x20f5, 0x20f5, 0x20f5}},
-  {{0x3ca5, 0x3ca6, 0x3cd8, 0x3cd9}},
-};
-static const ItemBoxGfx kHudItemCaneSomaria[2] = {
-  {{0x20f5, 0x20f5, 0x20f5, 0x20f5}},
-  {{0x24dc, 0x24dd, 0x24ec, 0x24ed}},
-};
-static const ItemBoxGfx kHudItemCaneByrna[2] = {
-  {{0x20f5, 0x20f5, 0x20f5, 0x20f5}},
-  {{0x2cdc, 0x2cdd, 0x2cec, 0x2ced}},
-};
-static const ItemBoxGfx kHudItemCape[2] = {
-  {{0x20f5, 0x20f5, 0x20f5, 0x20f5}},
-  {{0x24b4, 0x24b5, 0x24c4, 0x24c5}},
-};
-static const ItemBoxGfx kHudItemMirror[4] = {
-  {{0x20f5, 0x20f5, 0x20f5, 0x20f5}},
-  {{0x28de, 0x28df, 0x28ee, 0x28ef}},
-  {{0x2c62, 0x2c63, 0x2c72, 0x2c73}},
-  {{0x2886, 0x2887, 0x2888, 0x2889}},
-};
-static const ItemBoxGfx kHudItemGloves[3] = {
-  {{0x20f5, 0x20f5, 0x20f5, 0x20f5}},
-  {{0x2130, 0x2131, 0x2140, 0x2141}},
-  {{0x28da, 0x28db, 0x28ea, 0x28eb}},
-};
-static const ItemBoxGfx kHudItemBoots[2] = {
-  {{0x20f5, 0x20f5, 0x20f5, 0x20f5}},
-  {{0x3429, 0x342a, 0x342b, 0x342c}},
-};
-static const ItemBoxGfx kHudItemFlippers[2] = {
-  {{0x20f5, 0x20f5, 0x20f5, 0x20f5}},
-  {{0x2c9a, 0x2c9b, 0x2c9d, 0x2c9e}},
-};
-static const ItemBoxGfx kHudItemMoonPearl[2] = {
-  {{0x20f5, 0x20f5, 0x20f5, 0x20f5}},
-  {{0x2433, 0x2434, 0x2435, 0x2436}},
-};
-static const ItemBoxGfx kHudItemEmpty[1] = {
-  {{0x20f5, 0x20f5, 0x20f5, 0x20f5}},
-};
-static const ItemBoxGfx kHudItemSword[5] = {
-  {{0x20f5, 0x20f5, 0x20f5, 0x20f5}},
-  {{0x2c64, 0x2cce, 0x2c75, 0x3d25}},
-  {{0x2c8a, 0x2c65, 0x2474, 0x3d26}},
-  {{0x248a, 0x2465, 0x3c74, 0x2d48}},
-  {{0x288a, 0x2865, 0x2c74, 0x2d39}},
-};
-static const ItemBoxGfx kHudItemShield[4] = {
-  {{0x24f5, 0x24f5, 0x24f5, 0x24f5}},
-  {{0x2cfd, 0x6cfd, 0x2cfe, 0x6cfe}},
-  {{0x34ff, 0x74ff, 0x349f, 0x749f}},
-  {{0x2880, 0x2881, 0x288d, 0x288e}},
-};
-static const ItemBoxGfx kHudItemArmor[5] = {
-  {{0x3c68, 0x7c68, 0x3c78, 0x7c78}},
-  {{0x2c68, 0x6c68, 0x2c78, 0x6c78}},
-  {{0x2468, 0x6468, 0x2478, 0x6478}},
-};
-
-
-static const ItemBoxGfx * const kHudItemBoxGfxPtrs[] = {
-  kHudItemBow,
-  kHudItemBoomerang,
-  kHudItemHookshot,
-  kHudItemBombs,
-  kHudItemMushroom,
-  kHudItemFireRod,
-  kHudItemIceRod,
-  kHudItemBombos,
-  kHudItemEther,
-  kHudItemQuake,
-  kHudItemTorch,
-  kHudItemHammer,
-  kHudItemFlute,
-  kHudItemBugNet,
-  kHudItemBookMudora,
-  kHudItemBottles,
-  kHudItemCaneSomaria,
-  kHudItemCaneByrna,
-  kHudItemCape,
-  kHudItemMirror,
-  kHudItemGloves,
-  kHudItemBoots,
-  kHudItemFlippers,
-  kHudItemMoonPearl,
-  kHudItemEmpty,
-  kHudItemSword,
-  kHudItemShield,
-  kHudItemArmor,
-  kHudItemBottles,
-  kHudItemBottles,
-  kHudItemBottles,
-  kHudItemBottles,
-
-};
-static const uint16 kUpdateMagicPowerTilemap[17][4] = {
-  {0x3cf5, 0x3cf5, 0x3cf5, 0x3cf5},
-  {0x3cf5, 0x3cf5, 0x3cf5, 0x3c5f},
-  {0x3cf5, 0x3cf5, 0x3cf5, 0x3c4c},
-  {0x3cf5, 0x3cf5, 0x3cf5, 0x3c4d},
-  {0x3cf5, 0x3cf5, 0x3cf5, 0x3c4e},
-  {0x3cf5, 0x3cf5, 0x3c5f, 0x3c5e},
-  {0x3cf5, 0x3cf5, 0x3c4c, 0x3c5e},
-  {0x3cf5, 0x3cf5, 0x3c4d, 0x3c5e},
-  {0x3cf5, 0x3cf5, 0x3c4e, 0x3c5e},
-  {0x3cf5, 0x3c5f, 0x3c5e, 0x3c5e},
-  {0x3cf5, 0x3c4c, 0x3c5e, 0x3c5e},
-  {0x3cf5, 0x3c4d, 0x3c5e, 0x3c5e},
-  {0x3cf5, 0x3c4e, 0x3c5e, 0x3c5e},
-  {0x3c5f, 0x3c5e, 0x3c5e, 0x3c5e},
-  {0x3c4c, 0x3c5e, 0x3c5e, 0x3c5e},
-  {0x3c4d, 0x3c5e, 0x3c5e, 0x3c5e},
-  {0x3c4e, 0x3c5e, 0x3c5e, 0x3c5e},
-};
-static const uint16 kDungFloorIndicator_Gfx0[11] = { 0x2508, 0x2509, 0x2509, 0x250a, 0x250b, 0x250c, 0x250d, 0x251d, 0xe51c, 0x250e, 0x7f };
-static const uint16 kDungFloorIndicator_Gfx1[11] = { 0x2518, 0x2519, 0xa509, 0x251a, 0x251b, 0x251c, 0x2518, 0xa51d, 0xe50c, 0xa50e, 0x7f };
-
-
-void Hud_RefreshIcon() {
-  Hud_SearchForEquippedItem();
-  Hud_UpdateHud();
-  Hud_Rebuild();
-  overworld_map_state = 0;
-}
-
-uint8 CheckPalaceItemPosession() {
-  switch (cur_palace_index_x2 >> 1) {
-  case 2: return link_item_bow != 0;
-  case 3: return link_item_gloves != 0;
-  case 5: return link_item_hookshot != 0;
-  case 6: return link_item_hammer != 0;
-  case 7: return link_item_cane_somaria != 0;
-  case 8: return link_item_fire_rod != 0;
-  case 9: return link_armor != 0;
-  case 10: return link_item_moon_pearl != 0;
-  case 11: return link_item_gloves != 1;
-  case 12: return link_shield_type == 3;
-  case 13: return link_armor == 2;
-  default:
-    return 0;
-  }
-}
-
-// Returns the zero based index of the currently selected hud item,
-// or -1 if the item is item 0.
-static int Hud_GetItemPosition(int item) {
-  if (item <= 0)
-    return -1;
-  if (hud_inventory_order[0] != 0) {
-    int i = 0;
-    for (; i < kHudItemCount - 1 && hud_inventory_order[i] != item; i++) {}
-    return i;
-  } else {
-    return item ? item - 1 : item;
-  }
-}
-
-static void Hud_GotoPrevItem(uint8 *item, uint8 first_item_index) {
-  if (hud_inventory_order[0] != 0) {
-    int pos = Hud_GetItemPosition(*item);
-    *item = (pos == 0 && !first_item_index) ? 0 :
-        hud_inventory_order[(pos <= 0 ? kHudItemCount : pos) - 1];
-  } else {
-    *item = (*item > first_item_index) ? *item - 1 : kHudItemCount;
-  }
-}
-
-static void Hud_GotoNextItem(uint8 *item, uint8 first_item_index) {
-  if (hud_inventory_order[0] != 0) {
-    int i = Hud_GetItemPosition(*item);
-    *item = hud_inventory_order[((uint)i >= kHudItemCount - 1) ? 0 : i + 1];
-  } else {
-    *item = (*item < kHudItemCount) ? *item + 1 : first_item_index;
-  }
-}
-
-void Hud_FloorIndicator() {  // 8afd0c
-  uint16 a = hud_floor_changed_timer;
-  if (a == 0) {
-    Hud_RemoveSuperBombIndicator();
-    return;
-  }
-  a += 1;
-  if (a == 0xc0)
-    a = 0;
-  WORD(hud_floor_changed_timer) = a;
-
-  hud_tile_indices_buffer[0xf2 / 2] = 0x251e;
-  hud_tile_indices_buffer[0x134 / 2] = 0x251f;
-  hud_tile_indices_buffer[0x132 / 2] = 0x2520;
-  hud_tile_indices_buffer[0xf4 / 2] = 0x250f;
-
-  int k = 0, j;
-
-  if (!sign8(dung_cur_floor)) {
-    if (!WORD(dung_cur_floor) && dungeon_room_index != 2 && sram_progress_indicator < 2)
-      sound_effect_ambient = 3;
-    j = dung_cur_floor;
-  } else {
-    sound_effect_ambient = 5;
-    k++;
-    j = dung_cur_floor ^ 0xff;
-  }
-  hud_tile_indices_buffer[k + 0xf2 / 2] = kDungFloorIndicator_Gfx0[j];
-  hud_tile_indices_buffer[k + 0x132 / 2] = kDungFloorIndicator_Gfx1[j];
-  flag_update_hud_in_nmi++;
-}
-
-void Hud_RemoveSuperBombIndicator() {  // 8afd90
-  hud_tile_indices_buffer[0xf2 / 2] = 0x7f;
-  hud_tile_indices_buffer[0x132 / 2] = 0x7f;
-  hud_tile_indices_buffer[0xf4 / 2] = 0x7f;
-  hud_tile_indices_buffer[0x134 / 2] = 0x7f;
-}
-
-void Hud_SuperBombIndicator() {  // 8afda8
-  if (!super_bomb_indicator_unk1) {
-    if (sign8(super_bomb_indicator_unk2))
-      goto remove;
-    super_bomb_indicator_unk2--;
-    super_bomb_indicator_unk1 = 62;
-  }
-  super_bomb_indicator_unk1--;
-  if (sign8(super_bomb_indicator_unk2)) {
-remove:
-    super_bomb_indicator_unk2 = 0xff;
-    Hud_RemoveSuperBombIndicator();
-    return;
-  }
-
-  int r = super_bomb_indicator_unk2 % 10;
-  int q = super_bomb_indicator_unk2 / 10;
-
-  int j = sign8(r - 1) ? 9 : r - 1;
-  hud_tile_indices_buffer[0xf4 / 2] = kDungFloorIndicator_Gfx0[j];
-  hud_tile_indices_buffer[0x134 / 2] = kDungFloorIndicator_Gfx1[j];
-
-  j = sign8(q - 1) ? 10 : q - 1;
-  hud_tile_indices_buffer[0xf2 / 2] = kDungFloorIndicator_Gfx0[j];
-  hud_tile_indices_buffer[0x132 / 2] = kDungFloorIndicator_Gfx1[j];
-}
-
-static int MaxRupees() {
-  return enhanced_features0 & kFeatures0_CarryMoreRupees ? 9999 : 999;
-}
-
-void Hud_RefillLogic() {  // 8ddb92
-  if (overworld_map_state)
-    return;
-  if (link_magic_filler) {
-    if (link_magic_power >= 128) {
-      link_magic_power = 128;
-      link_magic_filler = 0;
-    } else {
-      link_magic_filler--;
-      link_magic_power++;
-      if ((frame_counter & 3) == 0 && sound_effect_1 == 0)
-        sound_effect_1 = 45;
-    }
-  }
-
-  uint16 a = link_rupees_actual;
-  if (a != link_rupees_goal) {
-    if (a >= link_rupees_goal) {
-      if ((int16)--a < 0)
-        link_rupees_goal = a = 0;
-    } else {
-      int m = MaxRupees();
-      if (++a > m)
-        link_rupees_goal = a = m;
-    }
-    link_rupees_actual = a;
-    if (sound_effect_1 == 0) {
-      if ((rupee_sfx_sound_delay++ & 7) == 0)
-        sound_effect_1 = 41;
-    } else {
-      rupee_sfx_sound_delay = 0;
-    }
-  } else {
-    rupee_sfx_sound_delay = 0;
-  }
-
-  if (link_bomb_filler) {
-    link_bomb_filler--;
-    if (link_item_bombs != kMaxBombsForLevel[link_bomb_upgrades])
-      link_item_bombs++;
-  }
-
-  if (link_arrow_filler) {
-    link_arrow_filler--;
-    if (link_num_arrows != kMaxArrowsForLevel[link_arrow_upgrades])
-      link_num_arrows++;
-    if (link_item_bow && (link_item_bow & 1) == 1) {
-      link_item_bow++;
-      Hud_RefreshIcon();
-    }
-  }
-
-  if (!flag_is_link_immobilized && !link_hearts_filler &&
-      link_health_current < kMaxHealthForLevel[link_health_capacity >> 3]) {
-    if (link_lowlife_countdown_timer_beep) {
-      link_lowlife_countdown_timer_beep--;
-    } else if (!sound_effect_1) {
-      if (!(enhanced_features0 & kFeatures0_DisableLowHealthBeep))
-        sound_effect_1 = 43;
-      link_lowlife_countdown_timer_beep = 32 - 1;
-    }
-  }
-
-  if (is_doing_heart_animation)
-    goto doing_animation;
-  if (link_hearts_filler) {
-    if (link_health_current < link_health_capacity) {
-      link_health_current += 8;
-      if (link_health_current >= link_health_capacity)
-        link_health_current = link_health_capacity;
-
-      if (sound_effect_2 == 0)
-        sound_effect_2 = 13;
-
-      link_hearts_filler -= 8;
-      is_doing_heart_animation++;
-      animate_heart_refill_countdown = 7;
-
-doing_animation:
-      Hud_Update_Magic();
-      Hud_Update_Inventory();
-      Hud_AnimateHeartRefill();
-      flag_update_hud_in_nmi++;
-      return;
-    }
-    link_health_current = link_health_capacity;
-    link_hearts_filler = 0;
-  }
-  Hud_Update_Hearts();
-  Hud_Update_Magic();
-  Hud_Update_Inventory();
-  flag_update_hud_in_nmi++;
-}
-
-void Hud_Module_Run() {  // 8ddd36
-  byte_7E0206++;
-  switch (overworld_map_state) {
-  case 0: Hud_ClearTileMap(); break;
-  case 1: Hud_Init(); break;
-  case 2: Hud_BringMenuDown(); break;
-  case 3: Hud_ChooseNextMode(); break;
-  case 4: Hud_NormalMenu(); break;
-  case 5: Hud_UpdateHud(); break;
-  case 6: Hud_CloseMenu(); break;
-  case 7: Hud_GotoBottleMenu(); break;
-  case 8: Hud_InitBottleMenu(); break;
-  case 9: Hud_ExpandBottleMenu(); break;
-  case 10: Hud_BottleMenu(); break;
-  case 11: Hud_EraseBottleMenu(); break;
-  case 12: Hud_RestoreNormalMenu(); break;
-  default:
-    assert(0);
-  }
-}
-
-void Hud_ClearTileMap() {  // 8ddd5a
-  uint16 *target = (uint16 *)&g_ram[0x1000];
-  for (int i = 0; i < 1024; i++)
-    target[i] = 0x207f;
-  sound_effect_2 = 17;
-  nmi_subroutine_index = 1;
-  BYTE(nmi_load_target_addr) = 0x22;
-  overworld_map_state++;
-}
-
-bool Hud_HaveAnyItems() { // new
-  for (int i = 0; i < 20; i++)
-    if ((&link_item_bow)[i])
-      return true;
-  return false;
-}
-
-void Hud_Init() {  // 8dddab
-  Hud_SearchForEquippedItem();
-  Hud_DrawYButtonItems();
-  Hud_DrawAbilityBox();
-  Hud_DrawProgressIcons();
-  Hud_DrawEquipmentBox();
-  Hud_DrawSelectedYButtonItem();
-
-  if (Hud_HaveAnyItems()) {   
-    // This causes bottle flicker because it's not early enough
-    int first_bottle = 0;
-    while (first_bottle < 4 && link_bottle_info[first_bottle] == 0)
-      first_bottle++;
-    if (first_bottle == 4)
-      link_item_bottle_index = 0;
-    else if (link_item_bottle_index == 0)
-      link_item_bottle_index = first_bottle + 1;
-
-    if (hud_cur_item == kHudItem_BottleOld && !kNewStyleInventory) {
-      timer_for_flashing_circle = 16;
-      Hud_DrawBottleMenu();
-    }
-  }
-
-  timer_for_flashing_circle = 16;
-  nmi_subroutine_index = 1;
-  BYTE(nmi_load_target_addr) = 0x22;
-  overworld_map_state++;
-}
-
-void Hud_BringMenuDown() {  // 8dde59
-  BG3VOFS_copy2 -= 8;
-  if (BG3VOFS_copy2 == 0xff18)
-    overworld_map_state++;
-}
-
-void Hud_ChooseNextMode() {  // 8dde6e
-  if (Hud_HaveAnyItems()) {
-    nmi_subroutine_index = 1;
-    BYTE(nmi_load_target_addr) = 0x22;
-
-    Hud_DrawSelectedYButtonItem();
-
-    // Pick either the bottle state or normal one
-    overworld_map_state = (hud_cur_item == kHudItem_BottleOld && !kNewStyleInventory) ? 10 : 4;
-  } else {
-    if (filtered_joypad_H)
-      overworld_map_state = 5;
-  }
-}
-
-static bool Hud_DoWeHaveThisItem(uint8 item) {  // 8ddeb0
-  if (item == 0)
-    return true;  // for the x item, 0 is valid
-
-  if (item == kHudItem_Flute && kNewStyleInventory)
-    return link_item_flute >= 2;
-
-  if (item == kHudItem_Shovel && kNewStyleInventory)
-    return link_item_flute >= 1;
-
-  if (item >= kHudItem_Bottle1)
-    return link_bottle_info[item - kHudItem_Bottle1] != 0;
-
-  return (&link_item_bow)[item - 1] != 0;
-}
-
-static void Hud_EquipPrevItem(uint8 *item) {  // 8dded9
-  do {
-    Hud_GotoPrevItem(item, item == &hud_cur_item);
-  } while (!Hud_DoWeHaveThisItem(*item));
-}
-
-static void Hud_EquipNextItem(uint8 *item) {  // 8ddee2
-  do {
-    Hud_GotoNextItem(item, item == &hud_cur_item);
-  } while (!Hud_DoWeHaveThisItem(*item));
-}
-
-static void Hud_EquipItemAbove(uint8 *item) {  // 8ddeeb
-  do {
-    for(int i = 0; i < (kNewStyleInventory ? 6 : 5); i++)
-      Hud_GotoPrevItem(item, 1);
-  } while (!Hud_DoWeHaveThisItem(*item));
-}
-
-static void Hud_EquipItemBelow(uint8 *item) {  // 8ddf00
-  int num = *item == 0 ? 1 : (kNewStyleInventory ? 6 : 5);
-  do {
-    for (int i = 0; i < num; i++)
-      Hud_GotoNextItem(item, 1);
-  } while (!Hud_DoWeHaveThisItem(*item));
-}
-
-int GetCurrentItemButtonIndex() {
-  if (enhanced_features0 & kFeatures0_SwitchLR) {
-    return (joypad1L_last & kJoypadL_X) ? 1 :
-           (joypad1L_last & kJoypadL_L) ? 2 :
-           (joypad1L_last & kJoypadL_R) ? 3 : 0;
-  }
-  return 0;
-}
-
-uint8 *GetCurrentItemButtonPtr(int i) {
-  return (i == 0) ? &hud_cur_item : 
-         (i == 1) ? &hud_cur_item_x : 
-         (i == 2) ? &hud_cur_item_l : &hud_cur_item_r;
-}
-
-void Hud_NormalMenu() {  // 8ddf15
-  timer_for_flashing_circle++;
-  if (!BYTE(joypad1H_last))
-    BYTE(hud_tmp1) = 0;
-
-  if (filtered_joypad_H & kJoypadH_Start) {
-    overworld_map_state = 5;
-    sound_effect_2 = 18;
-    return;
-  }
-
-  // Allow select to open the save/exit thing
-  if (joypad1H_last & kJoypadH_Select && sram_progress_indicator) {
-    BG3VOFS_copy2 = -8;
-    Hud_CloseMenu();
-    DisplaySelectMenu();
-    return;
-  }
-
-  if (joypad1H_last & kJoypadH_Y && !(joypad1L_last & kJoypadL_X) && (enhanced_features0 & kFeatures0_SwitchLR)) {
-    if (filtered_joypad_H & kJoypadH_Up) {
-      Hud_ReorderItem(kNewStyleInventory ? -6 : -5);
-    } else if (filtered_joypad_H & kJoypadH_Down) {
-      Hud_ReorderItem(kNewStyleInventory ? 6 : 5);
-    } else if (filtered_joypad_H & kJoypadH_Left) {
-      Hud_ReorderItem(-1);
-    } else if (filtered_joypad_H & kJoypadH_Right) {
-      Hud_ReorderItem(1);
-    }
-  } else if (!BYTE(hud_tmp1)) {
-    // If Special Key button is down, then move their circle
-    int btn_index = GetCurrentItemButtonIndex();
-    uint8 *item_p = GetCurrentItemButtonPtr(btn_index);
-    uint16 old_item = *item_p;
-    if (filtered_joypad_H & kJoypadH_Up) {
-      Hud_EquipItemAbove(item_p);
-    } else if (filtered_joypad_H & kJoypadH_Down) {
-      Hud_EquipItemBelow(item_p);
-    } else if (filtered_joypad_H & kJoypadH_Left) {
-      Hud_EquipPrevItem(item_p);
-    } else if (filtered_joypad_H & kJoypadH_Right) {
-      Hud_EquipNextItem(item_p);
-    }
-    BYTE(hud_tmp1) = filtered_joypad_H;
-    if (*item_p != old_item) {
-      timer_for_flashing_circle = 16;
-      sound_effect_2 = 32;
-    }
-  }
-  Hud_DrawYButtonItems();
-  Hud_DrawSelectedYButtonItem();
-  if (hud_cur_item == kHudItem_BottleOld && !kNewStyleInventory)
-    overworld_map_state = 7;
-
-  nmi_subroutine_index = 1;
-  BYTE(nmi_load_target_addr) = 0x22;
-  //g_ram[0x15d0] = 0;
-}
-
-void Hud_UpdateHud() {  // 8ddfa9
-  overworld_map_state++;
-  Hud_Rebuild();
-  Hud_UpdateEquippedItem();
-}
-
-uint8 Hud_LookupInventoryItem(uint8 item) {
-  static const uint8 kHudItemToItemOrg[21] = {
-    0,
-    3,  2, 14, 1,  10,  5,
-    6, 15, 16, 17,  9,  4,
-    8,  7, 12, 11, 18, 13,
-    19, 20,
-  };
-
-  static const uint8 kHudItemToItemNew[25] = {
-    0,
-    3,  2, 14, 1,  10,  5,
-    6, 15, 16, 17,  9,  4,
-    8,  7, 12, 21, 18, 13, // 8 is ocarina / shovel combined. moved shovel to 21.
-    19, 20,11, 11, 11, 11, // 11 means bottle
-  };
-  return kNewStyleInventory ? kHudItemToItemNew[item] : kHudItemToItemOrg[item];
-}
-
-void Hud_UpdateEquippedItem() {  // 8ddfaf
-  if (hud_cur_item >= kHudItem_Bottle1)
-    link_item_bottle_index = hud_cur_item - kHudItem_Bottle1 + 1;
-
-  assert(hud_cur_item < 25);
-  current_item_y = Hud_LookupInventoryItem(hud_cur_item);
-}
-
-void Hud_CloseMenu() {  // 8ddfba
-  BG3VOFS_copy2 += 8;
-  if (BG3VOFS_copy2)
-    return;
-  Hud_Rebuild();
-  overworld_map_state = 0;
-  submodule_index = 0;
-  main_module_index = saved_module_for_menu;
-  if (submodule_index)
-    Hud_RestoreTorchBackground();
-  if (current_item_y != 5 && current_item_y != 6) {
-    eq_debug_variable = 2;
-    link_debug_value_1 = 0;
-  } else {
-    assert(!link_debug_value_1);
-    eq_debug_variable = 0;
-  }
-}
-
-void Hud_GotoBottleMenu() {  // 8ddffb
-  bottle_menu_expand_row = 0;
-  overworld_map_state++;
-}
-
-void Hud_InitBottleMenu() {  // 8de002
-  int r = bottle_menu_expand_row;
-  uint16 *dst = uvram_screen.row[0].col + (kNewStyleInventory ? 1 : 0);
-  for (int i = 21; i <= 30; i++)
-    dst[HUDXY(i, 11 + r)] = 0x207f;
-
-  if (++bottle_menu_expand_row == 19) {
-    overworld_map_state++;
-    bottle_menu_expand_row = 17;
-  }
-  nmi_subroutine_index = 1;
-  BYTE(nmi_load_target_addr) = 0x22;
-}
-
-void Hud_ExpandBottleMenu() {  // 8de08c
-  static const uint16 kBottleMenuTop[] = { 0x28FB, 0x28F9, 0x28F9, 0x28F9, 0x28F9, 0x28F9, 0x28F9, 0x28F9, 0x28F9, 0x68FB };
-  static const uint16 kBottleMenuTop2[] = { 0x28FC, 0x24F5, 0x24F5, 0x24F5, 0x24F5, 0x24F5, 0x24F5, 0x24F5, 0x24F5, 0x68FC };
-  static const uint16 kBottleMenuBottom[] = { 0xA8FB, 0xA8F9, 0xA8F9, 0xA8F9, 0xA8F9, 0xA8F9, 0xA8F9, 0xA8F9, 0xA8F9, 0xE8FB };
-
-  int r = bottle_menu_expand_row;
-  uint16 *dst = uvram_screen.row[0].col + (kNewStyleInventory ? 1 : 0);
-  memcpy(&dst[HUDXY(21, 11 + r)], kBottleMenuTop, sizeof(uint16) * 10);
-  memcpy(&dst[HUDXY(21, 12 + r)], kBottleMenuTop2, sizeof(uint16) * 10);
-  memcpy(&dst[HUDXY(21, 29)], kBottleMenuBottom, sizeof(uint16) * 10);
-
-  if (sign8(--bottle_menu_expand_row))
-    overworld_map_state++;
-  nmi_subroutine_index = 1;
-  BYTE(nmi_load_target_addr) = 0x22;
-}
-
-void Hud_BottleMenu() {  // 8de0df
-  timer_for_flashing_circle++;
-  if (filtered_joypad_H & kJoypadH_Start) {
-    sound_effect_2 = 18;
-    overworld_map_state = 5;
-  } else if (filtered_joypad_H & (kJoypadH_Left | kJoypadH_Right)) {
-    if (filtered_joypad_H & kJoypadH_Left) {
-      Hud_EquipPrevItem(&hud_cur_item);
-    } else {
-      Hud_EquipNextItem(&hud_cur_item);
-    }
-    timer_for_flashing_circle = 16;
-    sound_effect_2 = 32;
-    Hud_DrawYButtonItems();
-    Hud_DrawSelectedYButtonItem();
-    overworld_map_state++;
-    bottle_menu_expand_row = 0;
-    return;
-  }
-  Hud_DrawBottleMenu_Update();
-  if (filtered_joypad_H & (kJoypadH_Down | kJoypadH_Up)) {
-    uint8 old_val = link_item_bottle_index - 1, val = old_val;
-
-    if (filtered_joypad_H & kJoypadH_Up) {
-      do {
-        val = (val - 1) & 3;
-      } while (!link_bottle_info[val]);
-    } else {
-      do {
-        val = (val + 1) & 3;
-      } while (!link_bottle_info[val]);
-    }
-    if (old_val != val) {
-      link_item_bottle_index = val + 1;
-      timer_for_flashing_circle = 16;
-      sound_effect_2 = 32;
-    }
-  }
-}
-
-static void Hud_DrawItem(uint16 *dst, const ItemBoxGfx *src) {  // new
-  dst[0] = src->v[0];
-  dst[1] = src->v[1];
-  dst[32] = src->v[2];
-  dst[33] = src->v[3];
-}
-
-static void Hud_DrawNxN(uint16 *dst, const uint16 *src, int w, int h) {  // new
-  for (int y = 0; y < h; y++) {
-    memcpy(dst, src, sizeof(uint16) * w);
-    dst += 32, src += w;
-  }
-}
-
-static void Hud_Copy2x2(uint16 *dst, uint16 *src) {  // new
-  dst[0] = src[0];
-  dst[1] = src[1];
-  dst[32] = src[32];
-  dst[33] = src[33];
-}
-
-static void Hud_DrawBox(uint16 *dst, int x1, int y1, int x2, int y2, uint8 palette) {  // new
-  uint16 t;
-
-  t = 0x20fb | palette << 10;
-  dst[HUDXY(x1, y1)] = t;
-  dst[HUDXY(x2, y1)] = t + 0x4000;
-  dst[HUDXY(x1, y2)] = t + 0x8000;
-  dst[HUDXY(x2, y2)] = t + 0xc000;
-
-  t = 0x20fc | palette << 10;
-  for (int y = y1 + 1; y < y2; y++) {
-    dst[HUDXY(x1, y)] = t;
-    dst[HUDXY(x2, y)] = t + 0x4000;
-  }
-
-  t = 0x20f9 | palette << 10;
-  for (int x = x1 + 1; x < x2; x++) {
-    dst[HUDXY(x, y1)] = t;
-    dst[HUDXY(x, y2)] = t + 0x8000;
-  }
-
-  for (int y = y1 + 1; y < y2; y++) {
-    for (int x = x1 + 1; x < x2; x++)
-      dst[HUDXY(x, y)] = 0x24F5;
-  }
-}
-
-static void Hud_DrawFlashingCircle(uint16 *p, uint8 palette) {  // new
-  int pp = palette << 10;
-  p[HUDXY(0, -1)] = pp | 0x2061;
-  p[HUDXY(1, -1)] = pp | 0x2061 | 0x4000;
-  p[HUDXY(-1, 0)] = pp | 0x2070;
-  p[HUDXY(2, 0)] = pp | 0x2070 | 0x4000;
-  p[HUDXY(-1, 1)] = pp | 0xa070;
-  p[HUDXY(2, 1)] = pp | 0xa070 | 0x4000;
-  p[HUDXY(0, 2)] = pp | 0xa061;
-  p[HUDXY(1, 2)] = pp | 0xa061 | 0x4000;
-  p[HUDXY(-1, -1)] = pp | 0x2060;
-  p[HUDXY(2, -1)] = pp | 0x2060 | 0x4000;
-  p[HUDXY(2, 2)] = pp | 0x2060 | 0xC000;
-  p[HUDXY(-1, 2)] = pp | 0x2060 | 0x8000;
-}
-
-void Hud_DrawBottleMenu() {  // 8def67
-  uint16 *dst = uvram_screen.row[0].col + (kNewStyleInventory ? 1 : 0);
-  Hud_DrawBox(dst, 21, 11, 30, 29, 2);
-  for (int i = 0; i < 4; i++)
-    Hud_DrawItem(dst + HUDXY(25, 13 + i * 4), &kHudItemBottles[link_bottle_info[i]]);
-  const ItemBoxGfx *p = &kHudItemBottles[link_bottle_info[link_item_bottle_index - 1]];
-  Hud_DrawItem(uvram_screen.row[0].col + kHudItemInVramPtr[15], p);
-  if (timer_for_flashing_circle & 0x10)
-    Hud_DrawFlashingCircle(dst + HUDXY(25, 13 + (link_item_bottle_index - 1) * 4), 7);
-}
-
-
-void Hud_DrawBottleMenu_Update() {  // 8de17f
-  Hud_DrawBottleMenu();
-  Hud_DrawSelectedYButtonItem();
-
-  nmi_subroutine_index = 1;
-  BYTE(nmi_load_target_addr) = 0x22;
-}
-
-void Hud_EraseBottleMenu() {  // 8de2fd
-  uint16 *dst = uvram_screen.row[0].col + (kNewStyleInventory ? 1 : 0);
-  int r = bottle_menu_expand_row;
-  for (int i = 0; i < 10; i++)
-    dst[HUDXY(21 + i, 11 + r)] = 0x207f;
-  if (++bottle_menu_expand_row == 19)
-    overworld_map_state++;
-  nmi_subroutine_index = 1;
-  BYTE(nmi_load_target_addr) = 0x22;
-}
-
-void Hud_RestoreNormalMenu() {  // 8de346
-  Hud_DrawProgressIcons();
-  Hud_DrawEquipmentBox();
-  overworld_map_state = 4;
-  nmi_subroutine_index = 1;
-  BYTE(nmi_load_target_addr) = 0x22;
-}
-
-void Hud_SearchForEquippedItem() {  // 8de399
-  if (!Hud_HaveAnyItems()) {
-    hud_cur_item = 0;
-    hud_var1 = 0;
-  } else {
-    if (!hud_cur_item)
-      hud_cur_item = 1;
-    if (!Hud_DoWeHaveThisItem(hud_cur_item))
-      Hud_EquipNextItem(&hud_cur_item);
-  }
-}
-
-static const ItemBoxGfx *Hud_GetIconForItem(int i) {
-  if (i <= 0)
-    return kHudItemEmpty;
-
-  if (i >= kHudItem_Bottle1)
-    return &kHudItemBottles[link_bottle_info[i - kHudItem_Bottle1]];
-  if (i == kHudItem_Shovel && kNewStyleInventory)
-    return &kHudItemFlute[link_item_flute >= 1];
-
-  uint8 item_val = (&link_item_bow)[i - 1];
-  if (i == kHudItem_Bombs) // bombs
-    item_val = (item_val != 0);
-  else if (i == kHudItem_BottleOld && !kNewStyleInventory)
-    item_val = link_item_bottle_index ? link_bottle_info[link_item_bottle_index - 1] : 0;
-  return &kHudItemBoxGfxPtrs[i - 1][item_val];
-}
-
-static void CopyTilesForSwitchLR(int switch_lr) {
-#define PV(a0,a1,a2,a3,a4,a5,a6,a7)  ((a0 & 1) << 7 | (a0 >> 1 & 1) << 15 | (a1 & 1) << 6 | (a1 >> 1 & 1) << 14 | (a2 & 1) <<5 | (a2 >> 1&1) <<13 | (a3 & 1) << 4 | (a3>> 1 & 1) << 12 | (a4 & 1) << 3 | (a4 >> 1 & 1) << 11 | (a5 & 1) << 2 | (a5 >> 1 & 1) << 10 | (a6 & 1) << 1 | (a6 >> 1 & 1) << 9 | (a7 & 1) << 0 | (a7 >> 1 & 1) << 8) 
-    
-  if (switch_lr == 3) {
-    static const uint16 kBytesForNewTile0xC_TopOfR[8] = {
-      PV(1,1,1,1,1,1,3,3),
-      PV(1,1,1,1,1,1,1,3),
-      PV(1,1,1,1,1,1,1,1),
-      PV(1,1,1,3,3,1,1,1),
-      PV(1,1,1,3,3,1,1,1),
-      PV(1,1,1,3,3,1,1,1),
-      PV(1,1,1,3,3,1,1,1),
-      PV(1,1,1,1,1,1,1,3)
-    };
-    memcpy(&g_zenv.vram[0x7000 + 0xc * 8], kBytesForNewTile0xC_TopOfR, sizeof(kBytesForNewTile0xC_TopOfR));
-
-    static const uint16 kBytesForNewTile0xD_BottomofR[8] = {
-      PV(1,1,1,1,1,1,3,3),
-      PV(1,1,1,3,1,1,1,3),
-      PV(1,1,1,3,3,1,1,1),
-      PV(1,1,1,3,3,1,1,1),
-      PV(1,1,1,3,3,1,1,1),
-      PV(1,1,1,3,3,1,1,1),
-      PV(1,1,1,3,3,1,1,1),
-      PV(1,1,1,3,3,1,1,1)
-    };
-    memcpy(&g_zenv.vram[0x7000 + 0xd * 8], kBytesForNewTile0xD_BottomofR, sizeof(kBytesForNewTile0xD_BottomofR));
-  } else if (switch_lr == 2) {
-    static const uint16 kBytesForNewTile0xE_TopOfL[8] = {
-      PV(1,1,1,3,3,3,3,3),
-      PV(1,1,1,3,3,3,3,3),
-      PV(1,1,1,3,3,3,3,3),
-      PV(1,1,1,3,3,3,3,3),
-      PV(1,1,1,3,3,3,3,3),
-      PV(1,1,1,3,3,3,3,3),
-      PV(1,1,1,3,3,3,3,3),
-      PV(1,1,1,3,3,3,3,3)
-    };
-    memcpy(&g_zenv.vram[0x7000 + 0xe * 8], kBytesForNewTile0xE_TopOfL, sizeof(kBytesForNewTile0xE_TopOfL));
-
-    static const uint16 kBytesForNewTile0xF_BottomofL[8] = {
-      PV(1,1,1,3,3,3,3,3),
-      PV(1,1,1,3,3,3,3,3),
-      PV(1,1,1,3,3,3,3,3),
-      PV(1,1,1,3,3,3,3,3),
-      PV(1,1,1,3,3,3,3,3),
-      PV(1,1,1,1,1,1,1,1),
-      PV(1,1,1,1,1,1,1,1),
-      PV(1,1,1,1,1,1,1,1)
-    };
-    memcpy(&g_zenv.vram[0x7000 + 0xf * 8], kBytesForNewTile0xF_BottomofL, sizeof(kBytesForNewTile0xF_BottomofL));
-  }
-#undef PV
-}
-
-static const uint8 kSwitchLR_palettes[] = { 7, 3, 4, 4 };
-
-void Hud_DrawYButtonItems() {  // 8de3d9
-  uint16 *dst = uvram_screen.row[0].col;
-  int x = kNewStyleInventory ? 0 : 1;
-
-  int btn_index = GetCurrentItemButtonIndex();
-  CopyTilesForSwitchLR(btn_index);
-  Hud_DrawBox(dst, x, 5, 20 - x, 19, kSwitchLR_palettes[btn_index]);
-  static const uint16 kEquipmentLetterTiles[4][2] = {
-    {0x3CF0, 0x3CF1},  // Y
-    {0x2CF0, 0x2CF0 | 0x8000},  // X
-    {0x200E | 4 << 10, 0x200F | 4 << 10},  // L
-    {0x200C | 4 << 10, 0x200D | 4 << 10}   // R
-   };
-
-  if (!kNewStyleInventory) {
-    dst[HUDXY(2, 6)] = kEquipmentLetterTiles[btn_index][0];
-    dst[HUDXY(2, 7)] = kEquipmentLetterTiles[btn_index][1]; 
-  }
-  dst[HUDXY(x + 2, 5)] = 0x246E;
-  dst[HUDXY(x + 3, 5)] = 0x246F;
-
-  for (int i = 0; i < kHudItemCount; i++) {
-    int j = hud_inventory_order[i];
-    Hud_DrawItem(dst + kHudItemInVramPtr[i], Hud_GetIconForItem(j == 0 ? i + 1: j) );
-  }
-}
-
-void Hud_DrawAbilityBox() {  // 8de6b6
-  static const uint16 kHudAbilityText[80] = {
-    0x2cf5, 0x2cf5, 0x2cf5, 0x2cf5, 0x2cf5, 0x2d5b, 0x2d58, 0x2d55, 0x2d63, 0x2d27,
-    0x2cf5, 0x2cf5, 0x2cf5, 0x2cf5, 0x2cf5, 0x2cf5, 0x2d61, 0x2d54, 0x2d50, 0x2d53,
-    0x2cf5, 0x2cf5, 0x2cf5, 0x2cf5, 0x2cf5, 0x2cf5, 0x2d63, 0x2d50, 0x2d5b, 0x2d5a,
-    0x207f, 0x207f, 0x207f, 0x207f, 0x207f, 0x207f, 0x207f, 0x207f, 0x207f, 0x207f,
-    0x2cf5, 0x2cf5, 0x2c2e, 0x2cf5, 0x2cf5, 0x2d5f, 0x2d64, 0x2d5b, 0x2d5b, 0x2cf5,
-    0x2cf5, 0x2cf5, 0x2cf5, 0x2cf5, 0x2cf5, 0x2cf5, 0x2d61, 0x2d64, 0x2d5d, 0x2cf5,
-    0x2cf5, 0x2cf5, 0x2cf5, 0x2cf5, 0x2cf5, 0x2cf5, 0x2d62, 0x2d66, 0x2d58, 0x2d5c,
-    0x2cf5, 0x2cf5, 0x2cf5, 0x207f, 0x207f, 0x2c01, 0x2c18, 0x2c28, 0x207f, 0x207f,
-  };
-  static const uint16 kHudGlovesText[20] = {
-    0x2cf5, 0x2cf5, 0x2cf5, 0x2cf5, 0x2cf5, 0x2d5b, 0x2d58, 0x2d55, 0x2d63, 0x2d28,
-    0x2cf5, 0x2cf5, 0x2cf5, 0x2cf5, 0x2cf5, 0x2d5b, 0x2d58, 0x2d55, 0x2d63, 0x2d29,
-  };
-  uint16 *dst = uvram_screen.row[0].col;
-  int x = kNewStyleInventory ? 0 : 1;
-
-  Hud_DrawBox(dst, x, 21, 19, 29, 1);
-
-  uint8 flags = link_ability_flags;
-  for (int i = 0; i < 2; i++, flags <<= 1) {
-    for (int j = 0; j < 3; j++, flags <<= 1) {
-      if (flags & 0x80)
-        Hud_DrawNxN(dst + HUDXY(4 + j * 5, 22 + i * 2), kHudAbilityText + i * 40 + j * 10, 5, 2);
-    }
-  }
-  // A
-  if (!kNewStyleInventory) {
-    dst[HUDXY(2, 22)] = 0xA4F0;
-    dst[HUDXY(2, 23)] = 0x24F2;
-  }
-  // DO text
-  dst[HUDXY(x + 2, 21)] = 0x2482;
-  dst[HUDXY(x + 3, 21)] = 0x2483;
-
-  Hud_DrawItem(dst + HUDXY(8, 27), &kHudItemGloves[link_item_gloves]);
-  Hud_DrawItem(dst + HUDXY(4, 27), &kHudItemBoots[link_item_boots]);
-  Hud_DrawItem(dst + HUDXY(12, 27), &kHudItemFlippers[link_item_flippers]);
-  Hud_DrawItem(dst + HUDXY(16, 27), &kHudItemMoonPearl[link_item_moon_pearl]);
-  if (link_item_gloves)
-    Hud_DrawNxN(dst + HUDXY(4, 22), kHudGlovesText + (link_item_gloves != 1) * 10, 5, 2);
-}
-
-void Hud_DrawProgressIcons() {  // 8de9c8
-  if (sram_progress_indicator < 3)
-    Hud_DrawProgressIcons_Pendants();
-  else
-    Hud_DrawProgressIcons_Crystals();
-}
-
-void Hud_DrawProgressIcons_Pendants() {  // 8de9d3
-  static const uint16 kProgressIconPendantsBg[90] = {
-    0x28fb, 0x28f9, 0x28f9, 0x28f9, 0x28f9, 0x28f9, 0x28f9, 0x28f9, 0x28f9, 0x68fb,
-    0x28fc, 0x2521, 0x2522, 0x2523, 0x2524, 0x253f, 0x24f5, 0x24f5, 0x24f5, 0x68fc,
-    0x28fc, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x68fc,
-    0x28fc, 0x24f5, 0x24f5, 0x24f5, 0x213b, 0x213c, 0x24f5, 0x24f5, 0x24f5, 0x68fc,
-    0x28fc, 0x24f5, 0x24f5, 0x24f5, 0x213d, 0x213e, 0x24f5, 0x24f5, 0x24f5, 0x68fc,
-    0x28fc, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x68fc,
-    0x28fc, 0x24f5, 0x213b, 0x213c, 0x24f5, 0x24f5, 0x213b, 0x213c, 0x24f5, 0x68fc,
-    0x28fc, 0x24f5, 0x213d, 0x213e, 0x24f5, 0x24f5, 0x213d, 0x213e, 0x24f5, 0x68fc,
-    0xa8fb, 0xa8f9, 0xa8f9, 0xa8f9, 0xa8f9, 0xa8f9, 0xa8f9, 0xa8f9, 0xa8f9, 0xe8fb,
-  };
-  static const ItemBoxGfx kHudPendants0[2] = {
-    {{0x313b, 0x313c, 0x313d, 0x313e}},
-    {{0x252b, 0x252c, 0x252d, 0x252e}},
-  };
-  static const ItemBoxGfx kHudPendants1[2] = {
-    {{0x313b, 0x313c, 0x313d, 0x313e}},
-    {{0x2d2b, 0x2d2c, 0x2d2d, 0x2d2e}},
-  };
-  static const ItemBoxGfx kHudPendants2[2] = {
-    {{0x313b, 0x313c, 0x313d, 0x313e}},
-    {{0x3d2b, 0x3d2c, 0x3d2d, 0x3d2e}},
-  };
-  uint16 *dst = uvram_screen.row[0].col + (kNewStyleInventory ? HUDXY(22, 11) : HUDXY(21, 11));
-  Hud_DrawNxN(dst, kProgressIconPendantsBg, 10, 9);
-  Hud_DrawItem(dst + HUDXY(4, 3), &kHudPendants0[(link_which_pendants >> 0) & 1]);
-  Hud_DrawItem(dst + HUDXY(2, 6), &kHudPendants1[(link_which_pendants >> 1) & 1]);
-  Hud_DrawItem(dst + HUDXY(6, 6), &kHudPendants2[(link_which_pendants >> 2) & 1]);
-}
-
-void Hud_DrawProgressIcons_Crystals() {  // 8dea62
-  static const uint16 kProgressIconCrystalsBg[90] = {
-    0x28fb, 0x28f9, 0x28f9, 0x28f9, 0x28f9, 0x28f9, 0x28f9, 0x28f9, 0x28f9, 0x68fb,
-    0x28fc, 0x252f, 0x2534, 0x2535, 0x2536, 0x2537, 0x24f5, 0x24f5, 0x24f5, 0x68fc,
-    0x28fc, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x68fc,
-    0x28fc, 0x24f5, 0x24f5, 0x3146, 0x3147, 0x3146, 0x3147, 0x24f5, 0x24f5, 0x68fc,
-    0x28fc, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x68fc,
-    0x28fc, 0x24f5, 0x3146, 0x3147, 0x3146, 0x3147, 0x3146, 0x3147, 0x24f5, 0x68fc,
-    0x28fc, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x68fc,
-    0x28fc, 0x24f5, 0x24f5, 0x3146, 0x3147, 0x3146, 0x3147, 0x24f5, 0x24f5, 0x68fc,
-    0xa8fb, 0xa8f9, 0xa8f9, 0xa8f9, 0xa8f9, 0xa8f9, 0xa8f9, 0xa8f9, 0xa8f9, 0xe8fb,
-  };
-
-  uint16 *dst = uvram_screen.row[0].col + (kNewStyleInventory ? HUDXY(22, 11) : HUDXY(21, 11));
-  Hud_DrawNxN(dst, kProgressIconCrystalsBg, 10, 9);
-
-  uint8 f = link_has_crystals;
-  if (f & 1) {
-    dst[HUDXY(3, 3)] = 0x2D44;
-    dst[HUDXY(4, 3)] = 0x2D45;
-  }
-  if (f & 2) {
-    dst[HUDXY(5, 3)] = 0x2D44;
-    dst[HUDXY(6, 3)] = 0x2D45;
-  }
-  if (f & 4) {
-    dst[HUDXY(2, 5)] = 0x2D44;
-    dst[HUDXY(3, 5)] = 0x2D45;
-  }
-  if (f & 8) {
-    dst[HUDXY(4, 5)] = 0x2D44;
-    dst[HUDXY(5, 5)] = 0x2D45;
-  }
-  if (f & 16) {
-    dst[HUDXY(6, 5)] = 0x2D44;
-    dst[HUDXY(7, 5)] = 0x2D45;
-  }
-  if (f & 32) {
-    dst[HUDXY(3, 7)] = 0x2D44;
-    dst[HUDXY(4, 7)] = 0x2D45;
-  }
-  if (f & 64) {
-    dst[HUDXY(5, 7)] = 0x2D44;
-    dst[HUDXY(6, 7)] = 0x2D45;
-  }
-}
-
-void Hud_DrawSelectedYButtonItem() {  // 8deb3a
-  static const uint16 kHudBottlesItemText[128] = {
-    0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x255c, 0x2564, 0x2562, 0x2557, 0x2561, 0x255e, 0x255e, 0x255c,
-    0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x2551, 0x255e, 0x2563, 0x2563, 0x255b, 0x2554, 0x24f5, 0x24f5,
-    0x255b, 0x2558, 0x2555, 0x2554, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x255c, 0x2554, 0x2553, 0x2558, 0x2552, 0x2558, 0x255d, 0x2554,
-    0x255c, 0x2550, 0x2556, 0x2558, 0x2552, 0x24f5, 0x24f5, 0x24f5, 0x255c, 0x2554, 0x2553, 0x2558, 0x2552, 0x2558, 0x255d, 0x2554,
-    0x2552, 0x2564, 0x2561, 0x2554, 0x256a, 0x2550, 0x255b, 0x255b, 0x255c, 0x2554, 0x2553, 0x2558, 0x2552, 0x2558, 0x255d, 0x2554,
-    0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x2555, 0x2550, 0x2554, 0x2561, 0x2558, 0x2554, 0x24f5, 0x24f5,
-    0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x2551, 0x2554, 0x2554, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5,
-    0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x2556, 0x255e, 0x255e, 0x2553, 0x24f5, 0x2551, 0x2554, 0x2554,
-  };
-  static const uint16 kHudMushroomItemText[16] = {
-    0x255c, 0x2550, 0x2556, 0x2558, 0x2552, 0x24f5, 0x24f5, 0x24f5,
-    0x24f5, 0x255f, 0x255e, 0x2566, 0x2553, 0x2554, 0x2561, 0x24f5,
-  };
-  static const uint16 kHudFluteItemText[32] = {
-    0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x2555, 0x255b, 0x2564, 0x2563, 0x2554, 0x24f5, 0x24f5, 0x24f5,
-    0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x2555, 0x255b, 0x2564, 0x2563, 0x2554, 0x24f5, 0x24f5, 0x24f5
-  };
-  static const uint16 kHudMirrorItemText[16] = {
-    0x255c, 0x2550, 0x2556, 0x2558, 0x2552, 0x24f5, 0x24f5, 0x24f5,
-    0x24f5, 0x24f5, 0x255c, 0x2558, 0x2561, 0x2561, 0x255e, 0x2561
-  };
-  static const uint16 kHudBowItemText[48] = {
-    0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x256b, 0x256c, 0x256e, 0x256f, 0x257c, 0x257d, 0x257e, 0x257f,
-    0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x256b, 0x256c, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5,
-    0x256b, 0x256c, 0x24f5, 0x256e, 0x256f, 0x24f5, 0x24f5, 0x24f5, 0x2578, 0x2579, 0x257a, 0x257b, 0x257c, 0x257d, 0x257e, 0x257f,
-  };
-  static const uint16 kHudItemText[320] = {
-    0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x256b, 0x256c, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5,
-    0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x2570, 0x2571, 0x2572, 0x2573, 0x2574, 0x2575, 0x2576, 0x2577,
-    0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x2557, 0x255e, 0x255e, 0x255a, 0x2562, 0x2557, 0x255e, 0x2563,
-    0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x2551, 0x255e, 0x255c, 0x2551, 0x24f5, 0x24f5, 0x24f5, 0x24f5,
-    0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x255c, 0x2564, 0x2562, 0x2557, 0x2561, 0x255e, 0x255e, 0x255c,
-    
-    0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x2555, 0x2558, 0x2561, 0x2554, 0x2561, 0x255e, 0x2553, 0x24f5,
-    0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x2558, 0x2552, 0x2554, 0x2561, 0x255e, 0x2553, 0x24f5, 0x24f5,
-    0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x2551, 0x255e, 0x255c, 0x2551, 0x255e, 0x2562, 0x24f5, 0x24f5,
-    0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x2554, 0x2563, 0x2557, 0x2554, 0x2561, 0x24f5, 0x24f5, 0x24f5,
-    0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x2560, 0x2564, 0x2550, 0x255a, 0x2554, 0x24f5, 0x24f5, 0x24f5,
-    0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x255b, 0x2550, 0x255c, 0x255f, 0x24f5, 0x24f5, 0x24f5, 0x24f5,
-    0x255c, 0x2550, 0x2556, 0x2558, 0x2552, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x2557, 0x2550, 0x255c, 0x255c, 0x2554, 0x2561,
-    0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x2562, 0x2557, 0x255e, 0x2565, 0x2554, 0x255b, 0x24f5, 0x24f5,
-    0x2400, 0x2401, 0x2402, 0x2403, 0x2404, 0x2405, 0x2406, 0x2407, 0x2408, 0x2409, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5,
-    0x2551, 0x255e, 0x255e, 0x255a, 0x24f5, 0x255e, 0x2555, 0x24f5, 0x255c, 0x2564, 0x2553, 0x255e, 0x2561, 0x2550, 0x24f5, 0x24f5,
-    0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x255c, 0x2564, 0x2562, 0x2557, 0x2561, 0x255e, 0x255e, 0x255c,
-    0x2552, 0x2550, 0x255d, 0x2554, 0x24f5, 0x255e, 0x2555, 0x24f5, 0x24f5, 0x2562, 0x255e, 0x255c, 0x2550, 0x2561, 0x2558, 0x2550,
-    0x2552, 0x2550, 0x255d, 0x2554, 0x24f5, 0x255e, 0x2555, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x2551, 0x2568, 0x2561, 0x255d, 0x2550,
-    0x255c, 0x2550, 0x2556, 0x2558, 0x2552, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x2552, 0x2550, 0x255f, 0x2554, 0x24f5,
-    0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5,
-  };
-
-#define L(x) (x == ' ' ? 0x24f5 : 0x2550 + x - 'A')
-  const uint16 kNotAssignedItemText[16] = {
-    L('N'), L('O'), L('T'), L(' '), L(' '), L(' '), L(' '), L(' '),
-    L('A'), L('S'), L('S'), L('I'), L('G'), L('N'), L('E'), L('D'),
-  };
-#undef L
-
-  uint16 *dst_org = uvram_screen.row[0].col;
-  uint16 *dst_box = dst_org + (kNewStyleInventory ? 1 : 0);
-  
-  int btn_index = GetCurrentItemButtonIndex();
-  int item = *GetCurrentItemButtonPtr(btn_index);
-  Hud_DrawBox(dst_box, 21, 5, 21 + 9, 10, kSwitchLR_palettes[btn_index]);
-
-  // Display either the current item or the item assigned
-  // to the x, l, or r key.
-  if (item != 0) {
-    uint16 *p = dst_org + kHudItemInVramPtr[Hud_GetItemPosition(item)];
-    Hud_Copy2x2(dst_box + HUDXY(25, 6), p);
-    if (timer_for_flashing_circle & 0x10)
-      Hud_DrawFlashingCircle(p, kSwitchLR_palettes[btn_index]);
-  }
-
-  const uint16 *src_p;
-  if (item == kHudItem_BottleOld && !kNewStyleInventory && link_item_bottle_index) {
-    src_p = &kHudBottlesItemText[(link_bottle_info[link_item_bottle_index - 1] - 1) * 16];
-  } else if (item == 5 && link_item_mushroom != 1) {
-    src_p = &kHudMushroomItemText[(link_item_mushroom - 2) * 16];
-  } else if (item == 20 && link_item_mirror != 1) {
-    src_p = &kHudMirrorItemText[(link_item_mirror - 2) * 16];
-  } else if (item == 13 && link_item_flute != 1) {
-    src_p = &kHudFluteItemText[(link_item_flute - 2) * 16];
-  } else if (item == 1 && link_item_bow != 1) {
-    src_p = &kHudBowItemText[(link_item_bow - 2) * 16];
-  } else if (item >= kHudItem_Bottle1 && item <= kHudItem_Bottle4) {
-    src_p = &kHudBottlesItemText[(link_bottle_info[item - kHudItem_Bottle1] - 1) * 16];
-  } else if (item == kHudItem_Shovel) {
-    src_p = &kHudItemText[(13 - 1) * 16];
-  } else if (item == 0) {
-    src_p = btn_index ? kNotAssignedItemText : &kHudItemText[(20 - 1) * 16];
-  } else {
-    src_p = &kHudItemText[(item - 1) * 16];
-  }
-  Hud_DrawNxN(dst_box + HUDXY(22, 8), src_p, 8, 2);
-}
-
-void Hud_DrawEquipmentBox() {  // 8ded29
-  uint16 *dst = uvram_screen.row[0].col + (kNewStyleInventory ? 1 : 0);
-
-  Hud_DrawBox(dst, 21, 21, 30, 29, 2);
-
-  // Draw dotted lines
-  for (int i = 0; i < 8; i++)
-    dst[HUDXY(22 + i, 25)] = 0x28D7;
-
-  static const uint16 kHudEquipmentDungeonItemText[16] = {
-    0x2479, 0x247a, 0x247b, 0x247c, 0x248c, 0x24f5, 0x24f5, 0x24f5,
-    0x2469, 0x246a, 0x246b, 0x246c, 0x246d, 0x246e, 0x246f, 0x24f5,
-  };
-  memcpy(dst + HUDXY(22, 22), &kHudEquipmentDungeonItemText[0], 8 * sizeof(uint16));
-  memcpy(dst + HUDXY(22, 26), &kHudEquipmentDungeonItemText[8], 8 * sizeof(uint16));
-
-  static const ItemBoxGfx kHudItemHeartPieces[4] = {
-    {{0x2484, 0x6484, 0x2485, 0x6485}},
-    {{0x24ad, 0x6484, 0x2485, 0x6485}},
-    {{0x24ad, 0x6484, 0x24ae, 0x6485}},
-    {{0x24ad, 0x64ad, 0x24ae, 0x6485}},
-  };
-  if (cur_palace_index_x2 == 0xff) {
-    for (int i = 0; i < 8; i++)
-      dst[HUDXY(22 + i, 26)] = 0x24F5;
-    Hud_DrawItem(dst + HUDXY(25, 27), &kHudItemHeartPieces[link_heart_pieces]);
-  }
-  Hud_DrawItem(dst + HUDXY(22, 23), &kHudItemSword[link_sword_type == 0xff ? 0 : link_sword_type]);
-  Hud_DrawItem(dst + HUDXY(25, 23), &kHudItemShield[link_shield_type]);
-  Hud_DrawItem(dst + HUDXY(28, 23), &kHudItemArmor[link_armor]);
-
-  static const ItemBoxGfx kHudItemPalaceItem[2] = {
-    {{0x28d6, 0x68d6, 0x28e6, 0x28e7}},
-    {{0x354b, 0x354c, 0x354d, 0x354e}},
-  };
-  static const ItemBoxGfx kHudItemDungeonMap[1] = {
-    {{0x28de, 0x28df, 0x28ee, 0x28ef}},
-  };
-  static const ItemBoxGfx kHudItemDungeonCompass[1] = {
-    {{0x24bf, 0x64bf, 0x2ccf, 0x6ccf}},
-  };
-  if (cur_palace_index_x2 != 0xff &&
-     (link_bigkey << (cur_palace_index_x2 >> 1)) & 0x8000) {
-    Hud_DrawItem(dst + HUDXY(28, 27), &kHudItemPalaceItem[CheckPalaceItemPosession()]);
-  }
-  if (cur_palace_index_x2 != 0xff &&
-     (link_dungeon_map << (cur_palace_index_x2 >> 1)) & 0x8000) {
-    Hud_DrawItem(dst + HUDXY(22, 27), &kHudItemDungeonMap[0]);
-  }
-  if (cur_palace_index_x2 != 0xff &&
-     (link_compass << (cur_palace_index_x2 >> 1)) & 0x8000) {
-    Hud_DrawItem(dst + HUDXY(25, 27), &kHudItemDungeonCompass[0]);
-  }
-}
-
-static void Hud_IntToDecimal(unsigned int number, uint8 *out) {  // 8df0f7
-  out[0] = number / 1000 + 0x90;
-  out[1] = (number %= 1000) / 100 + 0x90;
-  out[2] = (number %= 100) / 10 + 0x90;
-  out[3] = (number % 10) + 0x90;
-}
-
-bool Hud_RefillHealth() {  // 8df128
-  if (link_health_current >= link_health_capacity) {
-    link_health_current = link_health_capacity;
-    link_hearts_filler = 0;
-    return (is_doing_heart_animation == 0);
-  }
-  link_hearts_filler = 160;
-  return false;
-}
-
-void Hud_AnimateHeartRefill() {  // 8df14f
-  if (--animate_heart_refill_countdown)
-    return;
-  uint16 n = ((uint16)((link_health_current & ~7) - 1) >> 3) << 1;
-  uint16 *p = hud_tile_indices_buffer + HUDXY(20, 1);
-  if (n >= 20) {
-    n -= 20;
-    p += 0x20;
-  }
-  n &= 0xff;
-  animate_heart_refill_countdown = 1;
-
-  static const uint16 kAnimHeartPartial[4] = { 0x24A3, 0x24A4, 0x24A3, 0x24A0 };
-  p[n >> 1] = kAnimHeartPartial[animate_heart_refill_countdown_subpos];
-
-  animate_heart_refill_countdown_subpos = (animate_heart_refill_countdown_subpos + 1) & 3;
-  if (!animate_heart_refill_countdown_subpos) {
-    Hud_Rebuild();
-    is_doing_heart_animation = 0;
-  }
-}
-
-bool Hud_RefillMagicPower() {  // 8df1b3
-  if (link_magic_power >= 0x80)
-    return true;
-  link_magic_filler = 0x80;
-  return false;
-}
-
-void Hud_RestoreTorchBackground() {  // 8dfa33
-  if (!link_item_torch || !dung_want_lights_out || hdr_dungeon_dark_with_lantern ||
-      dung_num_lit_torches)
-    return;
-  hdr_dungeon_dark_with_lantern = 1;
-  if (dung_hdr_bg2_properties != 2)
-    TS_copy = 1;
-}
-
-void Hud_RebuildIndoor() {  // 8dfa60
-  overworld_fixed_color_plusminus = 0;
-  link_num_keys = 0xff;
-  Hud_Rebuild();
-}
-
-static void Hud_UpdateItemBox() {  // 8dfafd
-  // Update r
-  if (hud_cur_item)
-    Hud_DrawItem(&hud_tile_indices_buffer[HUDXY(5, 1)], Hud_GetIconForItem(hud_cur_item));
-}
-
-static void Hud_UpdateHearts_Inner(uint16 *dst, const uint16 *src, int n) {  // 8dfdab
-  int x = 0;
-  while (n > 0) {
-    if (x >= 10) {
-      dst += 0x20;
-      x = 0;
-    }
-    dst[x] = src[n >= 5 ? 2 : 1];
-    x++;
-    n -= 8;
-  }
-}
-
-static void DrawHudComponents(uint16 *dst, const uint16 *src, int w, int h) {
-  do {
-    memcpy(dst, src, w * sizeof(uint16));
-  } while (src += w, dst += 32, --h);
-}
-
-static void Hud_Update_Hearts() {  // 8dfb94
-  static const uint16 kHudItemBoxTab1[] = { 0x24A2, 0x24A2, 0x24A2 };
-  static const uint16 kHudItemBoxTab2[] = { 0x24A2, 0x24A1, 0x24A0 };
-  // The life meter
-  Hud_UpdateHearts_Inner(&hud_tile_indices_buffer[HUDXY(20, 1)], kHudItemBoxTab1, link_health_capacity);
-  Hud_UpdateHearts_Inner(&hud_tile_indices_buffer[HUDXY(20, 1)], kHudItemBoxTab2, (link_health_current + 3) & ~3);
-}
-
-static void Hud_Update_Magic() {  // 8dfc09
-  uint16 *dst = &hud_tile_indices_buffer[HUDXY(2, 0)];
-  if (link_magic_consumption >= 1) {
-    dst[HUDXY(0, 0)] = 0x28F7;
-    dst[HUDXY(1, 0)] = 0x2851;
-    dst[HUDXY(2, 0)] = 0x28FA;
-  }
-  const uint16 *src = kUpdateMagicPowerTilemap[(link_magic_power + 7) >> 3];
-  dst[HUDXY(1, 1)] = src[0];
-  dst[HUDXY(1, 2)] = src[1];
-  dst[HUDXY(1, 3)] = src[2];
-  dst[HUDXY(1, 4)] = src[3];
-}
-
-static void Hud_Update_Inventory() {  // 8dfc09
-  uint8 d[4];
-  Hud_IntToDecimal(link_rupees_actual, d);
-
-  const uint16 base_tiles[2] = {
-    0x2400,
-    (enhanced_features0 & kFeatures0_ShowMaxItemsInYellow) ? 0x3400 : 0x2400,
-  };
-
-  int inv_offs = (d[0] == 0x90) ? 1 : 0;
-
-  static const uint16 kHudInventoryBg[26] = {
-    0x207f, 0x207f, 0x3ca8, 0x207f, 0x207f, 0x2c88, 0x2c89, 0x207f, 0x20a7, 0x20a9, 0x207f, 0x2871, 0x207f,
-    0x207f, 0x207f, 0x207f, 0x207f, 0x207f, 0x207f, 0x207f, 0x207f, 0x207f, 0x207f, 0x207f, 0x207f, 0x207f,
-  };
-
-  uint16 *dst = &hud_tile_indices_buffer[HUDXY(8, 0)];
-  memcpy(dst + HUDXY(0, 0), kHudInventoryBg +  0 + inv_offs, 12 * sizeof(uint16));
-  memcpy(dst + HUDXY(0, 1), kHudInventoryBg + 13 + inv_offs, 12 * sizeof(uint16));
-
-  if (link_item_bow) {
-    if (link_item_bow >= 3) {
-      hud_tile_indices_buffer[HUDXY(15, 0)] = 0x2486;
-      hud_tile_indices_buffer[HUDXY(16, 0)] = 0x2487;
-      link_item_bow = link_num_arrows ? 4 : 3;
-    } else {
-      link_item_bow = link_num_arrows ? 2 : 1;
-    }
-  }
-
-  // Offset everything if we have many coins?
-  int base_tile = base_tiles[link_rupees_actual == MaxRupees()];
-  if (inv_offs == 0) {
-    dst++;
-    dst[HUDXY(-1, 1)] = base_tile | d[0];
-  }
-  dst[HUDXY(0, 1)] = base_tile | d[1];
-  dst[HUDXY(1, 1)] = base_tile | d[2];
-  dst[HUDXY(2, 1)] = base_tile | d[3];
-
-  Hud_IntToDecimal(link_item_bombs, d);
-  base_tile = base_tiles[link_item_bombs == kMaxBombsForLevel[link_bomb_upgrades]];
-  dst[HUDXY(4, 1)] = base_tile | d[2];
-  dst[HUDXY(5, 1)] = base_tile | d[3];
-
-  Hud_IntToDecimal(link_num_arrows, d);
-  base_tile = base_tiles[link_num_arrows == kMaxArrowsForLevel[link_arrow_upgrades]];
-  dst[HUDXY(7, 1)] = base_tile | d[2];
-  dst[HUDXY(8, 1)] = base_tile | d[3];
-
-  // Show keys
-  d[3] = 0x7f;
-  if (link_num_keys != 0xff)
-    Hud_IntToDecimal(link_num_keys, d);
-  dst[HUDXY(10, 1)] = 0x2400 | d[3];
-  if (dst[HUDXY(10, 1)] == 0x247f)
-    dst[HUDXY(10, 0)] = 0x247f;
-}
-
-void Hud_Rebuild() {  // 8dfa70
-  // Ensure all of the 165 hud words are initialized.
-  // This was broken by my previous reorg... quick fix for now.
-  if (hud_tile_indices_buffer[HUDXY(8, 2)] == 0) {
-    for (int i = 0; i < 165; i++)
-      hud_tile_indices_buffer[i] = 0x207f;
-  }
-
-
-  // The magic meter and item box
-  static const uint16 kHudTilemapLeftPart[8 * 6] = {
-    0x207f, 0x207f, 0x2850, 0xa856, 0x2852, 0x285b, 0x285b, 0x285c,
-    0x207f, 0x207f, 0x2854, 0x2871, 0x2858, 0x207f, 0x207f, 0x285d,
-    0x207f, 0x207f, 0x2854, 0x304e, 0x2858, 0x207f, 0x207f, 0x285d,
-    0x207f, 0x207f, 0x2854, 0x305e, 0x2859, 0xa85b, 0xa85b, 0xa85c,
-    0x207f, 0x207f, 0x2854, 0x305e, 0x6854, 0x207f, 0x207f, 0x207f,
-    0x207f, 0x207f, 0xa850, 0x2856, 0xe850, 
-  };
-  DrawHudComponents(hud_tile_indices_buffer, kHudTilemapLeftPart, 8, 6);
-
-  static const uint16 kHudTilemapRightPart[12 * 5] = {
-    0x207f, 0x207f, 0x288b, 0x288f, 0x24ab, 0x24ac, 0x688f, 0x688b, 0x207f, 0x207f, 0x207f, 0x207f,
-    0x207f, 0x207f, 0x207f, 0x207f, 0x207f, 0x207f, 0x207f, 0x207f, 0x207f, 0x207f, 0x207f, 0x207f,
-    0x207f, 0x207f, 0x207f, 0x207f, 0x207f, 0x207f, 0x207f, 0x207f, 0x207f, 0x207f, 0x207f, 0x207f,
-    0x207f, 0x207f, 0x207f, 0x207f, 0x207f, 0x207f, 0x207f, 0x207f, 0x207f, 0x207f, 0x207f, 0x207f,
-    0x207f, 0x207f, 0x207f, 0x207f, 0x207f, 0x207f, 0x207f, 0x207f, 0x207f, 0x207f, 0x207f, 0x207f,
-  };
-  DrawHudComponents(&hud_tile_indices_buffer[HUDXY(20, 0)], kHudTilemapRightPart, 12, 5);
-
-
-  Hud_Update_Hearts();
-  Hud_Update_Magic();
-  Hud_Update_Inventory();
-  Hud_UpdateItemBox();
-  flag_update_hud_in_nmi++;
-}
-
-
-const uint16 *Hud_GetItemBoxPtr(int item) {
-  return kHudItemBoxGfxPtrs[item]->v;
-}
-
-void Hud_HandleItemSwitchInputs() {
-  if (!(enhanced_features0 & kFeatures0_SwitchLR))
-    return;
-  
-  bool direction;
-  
-  if (filtered_joypad_L & kJoypadL_L && (hud_cur_item_l == 0))
-    direction = (hud_cur_item_r != 0);
-  else if (filtered_joypad_L & kJoypadL_R && (hud_cur_item_r == 0))
-    direction = true;
-  else
-    return;
-
-  uint8 item = hud_cur_item;
-  for (int i = 0; i < kHudItemCount; i++) {
-    if (!direction)
-      Hud_GotoPrevItem(&item, 1);
-    else
-      Hud_GotoNextItem(&item, 1);
-    if (Hud_DoWeHaveThisItem(item) && (!(enhanced_features0 & kFeatures0_SwitchLRLimit) || Hud_GetItemPosition(item) <= 3)) {
-      if (item != hud_cur_item) {
-        hud_cur_item = item;
-        sound_effect_2 = 32;
-        Hud_UpdateEquippedItem();
-        Hud_UpdateItemBox();
-        flag_update_hud_in_nmi++;
-      }
-      break;
-    }
-  }
-}
-
-static void Hud_ReorderItem(int direction) {
-  // Initialize inventory order on first use
-  if (hud_inventory_order[0] == 0) {
-    for (int i = 0; i < 24; i++)
-      hud_inventory_order[i] = i + 1;
-  }
-  int old_pos = Hud_GetItemPosition(hud_cur_item), new_pos = old_pos + direction;
-  if (new_pos < 0)
-    new_pos += kHudItemCount;
-  else if (new_pos >= kHudItemCount)
-    new_pos -= kHudItemCount;
-  uint8 t = hud_inventory_order[old_pos];
-  hud_inventory_order[old_pos] = hud_inventory_order[new_pos];
-  hud_inventory_order[new_pos] = t;
-  Hud_DrawYButtonItems();
-  sound_effect_2 = 32;
-}
--- a/hud.h
+++ /dev/null
@@ -1,62 +1,0 @@
-#pragma once
-#include "types.h"
-
-enum kHudItems {
-
-  kHudItem_Bombs = 4,
-  kHudItem_Mushroom = 5,
-  kHudItem_Hammer = 12,
-  kHudItem_Flute = 13,
-  kHudItem_BookMudora = 15,
-  kHudItem_BottleOld = 16,
-  
-  kHudItem_Shovel = 16,
-  kHudItem_Bottle1 = 21,
-  kHudItem_Bottle2 = 22,
-  kHudItem_Bottle3 = 23,
-  kHudItem_Bottle4 = 24,
-};
-
-void Hud_RefreshIcon();
-uint8 CheckPalaceItemPosession();
-void Hud_FloorIndicator();
-void Hud_RemoveSuperBombIndicator();
-void Hud_SuperBombIndicator();
-void Hud_RefillLogic();
-void Hud_Module_Run();
-void Hud_ClearTileMap();
-void Hud_Init();
-void Hud_BringMenuDown();
-void Hud_ChooseNextMode();
-void Hud_NormalMenu();
-void Hud_UpdateHud();
-uint8 Hud_LookupInventoryItem(uint8 item);
-void Hud_UpdateEquippedItem();
-void Hud_CloseMenu();
-void Hud_GotoBottleMenu();
-void Hud_InitBottleMenu();
-void Hud_ExpandBottleMenu();
-void Hud_BottleMenu();
-void Hud_DrawBottleMenu_Update();
-void Hud_EraseBottleMenu();
-void Hud_RestoreNormalMenu();
-void Hud_SearchForEquippedItem();
-void Hud_DrawYButtonItems();
-void Hud_DrawAbilityBox();
-void Hud_DrawProgressIcons();
-void Hud_DrawProgressIcons_Pendants();
-void Hud_DrawProgressIcons_Crystals();
-void Hud_DrawSelectedYButtonItem();
-void Hud_DrawEquipmentBox();
-void Hud_DrawBottleMenu();
-bool Hud_RefillHealth();
-void Hud_AnimateHeartRefill();
-bool Hud_RefillMagicPower();
-void Hud_RestoreTorchBackground();
-void Hud_RebuildIndoor();
-void Hud_Rebuild();
-const uint16 *Hud_GetItemBoxPtr(int item);
-int GetCurrentItemButtonIndex();
-uint8 *GetCurrentItemButtonPtr(int i);
-
-void Hud_HandleItemSwitchInputs();
--- a/load_gfx.c
+++ /dev/null
@@ -1,2182 +1,0 @@
-#include "zelda_rtl.h"
-#include "variables.h"
-#include "snes/snes_regs.h"
-#include "overworld.h"
-#include "load_gfx.h"
-#include "player.h"
-#include "sprite.h"
-#include "assets.h"
-
-// Allow this to be overwritten
-uint16 kGlovesColor[2] = {0x52f6, 0x376};
-
-static const uint16 kPaletteFilteringBits[64] = {
-  0xffff, 0xffff, 0xfffe, 0xffff, 0x7fff, 0x7fff, 0x7fdf, 0xfbff, 0x7f7f, 0x7f7f, 0x7df7, 0xefbf, 0x7bdf, 0x7bdf, 0x77bb, 0xddef,
-  0x7777, 0x7777, 0x6edd, 0xbb77, 0x6db7, 0x6db7, 0x5b6d, 0xb6db, 0x5b5b, 0x5b5b, 0x56b6, 0xad6b, 0x5555, 0xad6b, 0x5555, 0xaaab,
-  0x5555, 0x5555, 0x2a55, 0x5555, 0x2a55, 0x2a55, 0x294a, 0x5295, 0x2525, 0x2525, 0x2492, 0x4925, 0x1249, 0x1249, 0x1122, 0x4489,
-  0x1111, 0x1111,  0x844, 0x2211,  0x421,  0x421,  0x208, 0x1041,  0x101,  0x101,   0x20,  0x401,      1,      1,      0,      1,
-};
-static const uint16 kPaletteFilter_Agahnim_Tab[3] = {0x160, 0x180, 0x1a0};
-static const uint8 kMainTilesets[37][8] = {
-  {  0,   1,  16,   6, 14, 31, 24, 15},
-  {  0,   1,  16,   8, 14, 34, 27, 15},
-  {  0,   1,  16,   6, 14, 31, 24, 15},
-  {  0,   1,  19,   7, 14, 35, 28, 15},
-  {  0,   1,  16,   7, 14, 33, 24, 15},
-  {  0,   1,  16,   9, 14, 32, 25, 15},
-  {  2,   3,  18,  11, 14, 33, 26, 15},
-  {  0,   1,  17,  12, 14, 36, 27, 15},
-  {  0,   1,  17,   8, 14, 34, 27, 15},
-  {  0,   1,  17,  12, 14, 37, 26, 15},
-  {  0,   1,  17,  12, 14, 38, 27, 15},
-  {  0,   1,  20,  10, 14, 39, 29, 15},
-  {  0,   1,  17,  10, 14, 40, 30, 15},
-  {  2,   3,  18,  11, 14, 41, 22, 15},
-  {  0,   1,  21,  13, 14, 42, 24, 15},
-  {  0,   1,  16,   7, 14, 35, 28, 15},
-  {  0,   1,  19,   7, 14,  4,  5, 15},
-  {  0,   1,  19,   7, 14,  4,  5, 15},
-  {  0,   1,  16,   9, 14, 32, 27, 15},
-  {  0,   1,  16,   9, 14, 42, 23, 15},
-  {  2,   3,  18,  11, 14, 33, 28, 15},
-  {  0,   8,  17,  27, 34, 46, 93, 91},
-  {  0,   8,  16,  24, 32, 43, 93, 91},
-  {  0,   8,  16,  24, 32, 43, 93, 91},
-  { 58,  59,  60,  61, 83, 77, 62, 91},
-  { 66,  67,  68,  69, 32, 43, 63, 93},
-  {  0,   8,  16,  24, 32, 43, 93, 91},
-  {  0,   8,  16,  24, 32, 43, 93, 91},
-  {  0,   8,  16,  24, 32, 43, 93, 91},
-  {  0,   8,  16,  24, 32, 43, 93, 91},
-  {  0,   8,  16,  24, 32, 43, 93, 91},
-  {113, 114, 113, 114, 32, 43, 93, 91},
-  { 58,  59,  60,  61, 83, 77, 62, 91},
-  { 66,  67,  68,  69, 32, 43, 63, 89},
-  {  0, 114, 113, 114, 32, 43, 93, 15},
-  { 22,  57,  29,  23, 64, 65, 57, 30},
-  {  0,  70,  57, 114, 64, 65, 57, 15},
-};
-static const uint8 kSpriteTilesets[144][4] = {
-  { 0, 73,   0,  0},
-  {70, 73,  12, 29},
-  {72, 73,  19, 29},
-  {70, 73,  19, 14},
-  {72, 73,  12, 17},
-  {72, 73,  12, 16},
-  {79, 73,  74, 80},
-  {14, 73,  74, 17},
-  {70, 73,  18,  0},
-  { 0, 73,   0, 80},
-  { 0, 73,   0, 17},
-  {72, 73,  12,  0},
-  { 0,  0,  55, 54},
-  {72, 73,  76, 17},
-  {93, 44,  12, 68},
-  { 0,  0,  78,  0},
-  {15,  0,  18, 16},
-  { 0,  0,   0, 76},
-  { 0, 13,  23,  0},
-  {22, 13,  23, 27},
-  {22, 13,  23, 20},
-  {21, 13,  23, 21},
-  {22, 13,  24, 25},
-  {22, 13,  23, 25},
-  {22, 13,   0,  0},
-  {22, 13,  24, 27},
-  {15, 73,  74, 17},
-  {75, 42,  92, 21},
-  {22, 73,  23, 29},
-  { 0,  0,   0, 21},
-  {22, 13,  23, 16},
-  {22, 73,  18,  0},
-  {22, 73,  12, 17},
-  { 0,  0,  18, 16},
-  {22, 13,   0, 17},
-  {22, 73,  12,  0},
-  {22, 13,  76, 17},
-  {14, 13,  74, 17},
-  {22, 26,  23, 27},
-  {79, 52,  74, 80},
-  {53, 77, 101, 54},
-  {74, 52,  78,  0},
-  {14, 52,  74, 17},
-  {81, 52,  93, 89},
-  {75, 73,  76, 17},
-  {45,  0,   0,  0},
-  {93,  0,  18, 89},
-  { 0,  0,   0,  0},
-  { 0,  0,   0,  0},
-  { 0,  0,   0,  0},
-  { 0,  0,   0,  0},
-  { 0,  0,   0,  0},
-  { 0,  0,   0,  0},
-  { 0,  0,   0,  0},
-  { 0,  0,   0,  0},
-  { 0,  0,   0,  0},
-  { 0,  0,   0,  0},
-  { 0,  0,   0,  0},
-  { 0,  0,   0,  0},
-  { 0,  0,   0,  0},
-  { 0,  0,   0,  0},
-  { 0,  0,   0,  0},
-  { 0,  0,   0,  0},
-  { 0,  0,   0,  0},
-  {71, 73,  43, 45},
-  {70, 73,  28, 82},
-  { 0, 73,  28, 82},
-  {93, 73,   0, 82},
-  {70, 73,  19, 82},
-  {75, 77,  74, 90},
-  {71, 73,  28, 82},
-  {75, 77,  57, 54},
-  {31, 44,  46, 82},
-  {31, 44,  46, 29},
-  {47, 44,  46, 82},
-  {47, 44,  46, 49},
-  {31, 30,  48, 82},
-  {81, 73,  19,  0},
-  {79, 73,  19, 80},
-  {79, 77,  74, 80},
-  {75, 73,  76, 43},
-  {31, 32,  34, 83},
-  {85, 61,  66, 67},
-  {31, 30,  35, 82},
-  {31, 30,  57, 58},
-  {31, 30,  58, 62},
-  {31, 30,  60, 61},
-  {64, 30,  39, 63},
-  {85, 26,  66, 67},
-  {31, 30,  42, 82},
-  {31, 30,  56, 82},
-  {31, 32,  40, 82},
-  {31, 32,  38, 82},
-  {31, 44,  37, 82},
-  {31, 32,  39, 82},
-  {31, 30,  41, 82},
-  {31, 44,  59, 82},
-  {70, 73,  36, 82},
-  {33, 65,  69, 51},
-  {31, 44,  40, 49},
-  {31, 13,  41, 82},
-  {31, 30,  39, 82},
-  {31, 32,  39, 83},
-  {72, 73,  19, 82},
-  {14, 30,  74, 80},
-  {31, 32,  38, 83},
-  {21,  0,   0,  0},
-  {31,  0,  42, 82},
-  { 0,  0,   0,  0},
-  { 0,  0,   0,  0},
-  { 0,  0,   0,  0},
-  { 0,  0,   0,  0},
-  { 0,  0,   0,  0},
-  { 0,  0,   0,  0},
-  { 0,  0,   0,  0},
-  { 0,  0,   0,  0},
-  { 0,  0,   0,  0},
-  { 0,  0,   0,  0},
-  { 0,  0,   0,  0},
-  { 0,  0,   0,  0},
-  { 0,  0,   0,  0},
-  { 0,  0,   0,  0},
-  { 0,  0,   0,  0},
-  { 0,  0,   0,  0},
-  { 0,  0,   0,  0},
-  {50,  0,   0,  8},
-  {93, 73,   0, 82},
-  {85, 73,  66, 67},
-  {97, 98,  99, 80},
-  {97, 98,  99, 80},
-  {97, 98,  99, 80},
-  {97, 98,  99, 80},
-  {97, 98,  99, 80},
-  {97, 98,  99, 80},
-  {97, 86,  87, 80},
-  {97, 98,  99, 80},
-  {97, 98,  99, 80},
-  {97, 86,  87, 80},
-  {97, 86,  99, 80},
-  {97, 86,  87, 80},
-  {97, 86,  51, 80},
-  {97, 86,  87, 80},
-  {97, 98,  99, 80},
-  {97, 98,  99, 80},
-};
-static const uint8 kAuxTilesets[82][4] = {
-  {  6,   0,  31,  24},
-  {  8,   0,  34,  27},
-  {  6,   0,  31,  24},
-  {  7,   0,  35,  28},
-  {  7,   0,  33,  24},
-  {  9,   0,  32,  25},
-  { 11,   0,  33,  26},
-  { 12,   0,  36,  25},
-  {  8,   0,  34,  27},
-  { 12,   0,  37,  27},
-  { 12,   0,  38,  27},
-  { 10,   0,  39,  29},
-  { 10,   0,  40,  30},
-  { 11,   0,  41,  22},
-  { 13,   0,  42,  24},
-  {  7,   0,  35,  28},
-  {  7,   0,   4,   5},
-  {  7,   0,   4,   5},
-  {  9,   0,  32,  27},
-  {  9,   0,  42,  23},
-  { 11,   0,  33,  28},
-  {  9,   0,  32,  25},
-  { 11,   0,  33,  26},
-  {  9,   0,  36,  27},
-  {  8,   0,  34,  27},
-  {  9,   0,  37,  27},
-  {  9,   0,  38,  27},
-  { 10,   0,  39,  29},
-  {  9,   0,  40,  30},
-  { 12,   0,  41,  22},
-  { 13,   0,  42,  23},
-  {114,   0,  43,  93},
-  {  0,   0,   0,   0},
-  {  0,  87,  76,   0},
-  {  0,  86,  79,   0},
-  {  0,  83,  77,   0},
-  {  0,  82,  73,   0},
-  {  0,  85,  74,   0},
-  {  0,  83,  84,   0},
-  {  0,  81,  78,   0},
-  {  0,   0,   0,   0},
-  {  0,  80,  75,   0},
-  {  0,  83,  77,   0},
-  {  0,  85,  84,   0},
-  {  0,   0,   0,   0},
-  {  0,   0,   0,   0},
-  {  0,   0,   0,   0},
-  {  0,  71,  72,   0},
-  {  0,   0,   0,   0},
-  {  0,  87,  76,   0},
-  {  0,  86,  79,   0},
-  {  0,  83,  77,   0},
-  {  0,  82,  73,   0},
-  {  0,  85,  74,   0},
-  {  0,  83,  84,   0},
-  {  0,  81,  78,   0},
-  {  0,   0,   0,   0},
-  {  0,  80,  75,   0},
-  {  0,  83,   0,   0},
-  {  0,  53,  54,   0},
-  {  0,  96,  52,   0},
-  {  0,  43,  44,   0},
-  {  0,  45,  46,   0},
-  {  0,  47,  48,   0},
-  {  0,  55,  56,   0},
-  {  0,  51,  52,   0},
-  {  0,  49,  50,   0},
-  {  0,   0,   0,   0},
-  {  0,   0,   0,   0},
-  {  0,   0,   0,   0},
-  {  0,   0,   0,   0},
-  {  0,   0,   0,   0},
-  {  0,   0,   0,   0},
-  {  0,   0,   0,   0},
-  {  0,   0,   0,   0},
-  {  0,   0,   0,   0},
-  {  0,   0,   0,   0},
-  {  0,   0,   0,   0},
-  {  0,   0,   0,   0},
-  {  0,   0,   0,   0},
-  {114, 113, 114, 113},
-  { 23,  64,  65,  57},
-};
-static const uint16 kTagalongWhich[14] = {0, 0x600, 0x300, 0x300, 0x300, 0, 0, 0x900, 0x600, 0x600, 0x900, 0x900, 0x600, 0x900};
-static const uint16 kDecodeAnimatedSpriteTile_Tab[57] = {
-  0x9c0, 0x30, 0x60, 0x90, 0xc0, 0x300, 0x318, 0x330, 0x348, 0x360, 0x378, 0x390, 0x930, 0x3f0, 0x420, 0x450,
-  0x468, 0x600, 0x630, 0x660, 0x690, 0x6c0, 0x6f0, 0x720, 0x750, 0x768, 0x900, 0x930, 0x960, 0x990, 0x9f0, 0,
-  0xf0, 0xa20, 0xa50, 0x660, 0x600, 0x618, 0x630, 0x648, 0x678, 0x6d8, 0x6a8, 0x708, 0x738, 0x768, 0x960, 0x900,
-  0x3c0, 0x990, 0x9a8, 0x9c0, 0x9d8, 0xa08, 0xa38, 0x600, 0x630,
-};
-static const uint16 kSwordTypeToGfxOffs[5] = {0, 0, 0x120, 0x120, 0x120};
-static const uint16 kShieldTypeToGfxOffs[4] = {0x660, 0x660, 0x6f0, 0x900};
-static const int8 kOwBgPalInfo[93] = {
-  0, -1, 7, 0, 1, 7, 0, 2, 7, 0, 3, 7, 0, 4, 7, 0, 5, 7, 0, 6, 7, 7, 6, 5,
-  0, 8, 7, 0, 9, 7, 0, 10, 7, 0, 11, 7, 0, -1, 7, 0, -1, 7, 3, 4, 7, 4, 4, 3,
-  16, -1, 6, 16, 1, 6, 16, 17, 6, 16, 3, 6, 16, 4, 6, 16, 5, 6, 16, 6, 6, 18, 19, 4,
-  18, 5, 4, 16, 9, 6, 16, 11, 6, 16, 12, 6, 16, 13, 6, 16, 14, 6, 16, 15, 6,
-};
-static const int8 kOwSprPalInfo[40] = {
-  -1, -1, 3, 10, 3, 6, 3, 1, 0, 2, 3, 14, 3, 2, 19, 1, 11, 12, 17, 1, 7, 5, 17, 0,
-  9, 11, 15, 5, 3, 5, 3, 7, 15, 2, 10, 2, 5, 1, 12, 14,
-};
-static const int8 kSpotlight_delta_size[4] = {-7, 7, 7, 7};
-static const uint8 kSpotlight_goal[4] = {0, 126, 35, 126};
-static const uint8 kConfigureSpotlightTable_Helper_Tab[129] = {
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfd, 0xfd, 0xfd, 0xfc, 0xfc, 0xfc, 0xfb, 0xfb, 0xfb, 0xfa, 0xfa, 0xf9, 0xf9, 0xf8, 0xf8,
-  0xf7, 0xf7, 0xf6, 0xf6, 0xf5, 0xf5, 0xf4, 0xf3, 0xf3, 0xf2, 0xf1, 0xf1, 0xf0, 0xef, 0xee, 0xee, 0xed, 0xec, 0xeb, 0xea, 0xe9, 0xe9, 0xe8, 0xe7, 0xe6, 0xe5, 0xe4, 0xe3, 0xe2, 0xe1, 0xdf, 0xde,
-  0xdd, 0xdc, 0xdb, 0xda, 0xd8, 0xd7, 0xd6, 0xd5, 0xd3, 0xd2, 0xd0, 0xcf, 0xcd, 0xcc, 0xca, 0xc9, 0xc7, 0xc6, 0xc4, 0xc2, 0xc1, 0xbf, 0xbd, 0xbb, 0xb9, 0xb7, 0xb6, 0xb4, 0xb1, 0xaf, 0xad, 0xab,
-  0xa9, 0xa7, 0xa4, 0xa2, 0x9f, 0x9d, 0x9a, 0x97, 0x95, 0x92, 0x8f, 0x8c, 0x89, 0x86, 0x82, 0x7f, 0x7b, 0x78, 0x74, 0x70, 0x6c, 0x67, 0x63, 0x5e, 0x59, 0x53, 0x4d, 0x46, 0x3f, 0x37, 0x2d, 0x1f,
-  0,
-};
-static const uint8 kGraphicsHalfSlotPacks[20] = {
-  1, 1, 8, 8, 9, 9, 2, 2, 2, 2, 3, 3, 4, 4, 5, 5,
-  8, 8, 8, 8,
-};
-static const int8 kGraphicsLoadSp6[20] = {
-  10, -1, 3, -1, 0, -1, -1, -1, 1, -1, 2, -1, 0, -1, -1,
-  -1, -1, -1, -1, -1,
-};
-static const uint8 kMirrorWarp_LoadNext_NmiLoad[15] = {0, 14, 15, 16, 17, 0, 0, 0, 0, 0, 0, 18, 19, 20, 0};
-
-static const uint8 *GetCompSpritePtr(int i) {
-  return kSprGfx(i).ptr;
-}
-
-void ApplyPaletteFilter_bounce() {
-
-  const uint16 *load_ptr = kPaletteFilteringBits + (palette_filter_countdown >= 0x10);
-
-  int mask = kUpperBitmasks[palette_filter_countdown & 0xf];
-  int dt = darkening_or_lightening_screen ? 1 : -1;
-  int j = 0;
-  for (;;) {
-    uint16 c = main_palette_buffer[j], a = aux_palette_buffer[j];
-    if (!(load_ptr[(a & 0x1f) * 2] & mask))
-      c += dt;
-    if (!(load_ptr[(a & 0x3e0) >> 4] & mask))
-      c += dt << 5;
-    if (!(load_ptr[(a & 0x7c00) >> 9] & mask))
-      c += dt << 10;
-    main_palette_buffer[j] = c;
-    j++;
-    if (j == 1)
-      j = 0x20;
-    else if (j == 0xd8)
-      j = 0xe0;
-    else if (j == 0xf0)
-      break;
-  }
-  flag_update_cgram_in_nmi++;
-  if (!darkening_or_lightening_screen) {
-    if (++palette_filter_countdown != mosaic_target_level)
-      return;
-  } else {
-    if (palette_filter_countdown-- != mosaic_target_level)
-      return;
-  }
-  darkening_or_lightening_screen ^= 2;
-  palette_filter_countdown = 0;
-  subsubmodule_index++;
-}
-
-void PaletteFilter_Range(int from, int to) {
-  const uint16 *load_ptr = kPaletteFilteringBits + (palette_filter_countdown >= 0x10);
-  int mask = kUpperBitmasks[palette_filter_countdown & 0xf];
-  int dt = darkening_or_lightening_screen ? 1 : -1;
-  for (int j = from; j != to; j++) {
-    uint16 c = main_palette_buffer[j], a = aux_palette_buffer[j];
-    if (!(load_ptr[(a & 0x1f) * 2] & mask))
-      c += dt;
-    if (!(load_ptr[(a & 0x3e0) >> 4] & mask))
-      c += dt << 5;
-    if (!(load_ptr[(a & 0x7c00) >> 9] & mask))
-      c += dt << 10;
-    main_palette_buffer[j] = c;
-  }
-}
-
-void PaletteFilter_IncrCountdown() {
-  if (++palette_filter_countdown == 0x1f) {
-    palette_filter_countdown = 0;
-    darkening_or_lightening_screen ^= 2;
-    if (darkening_or_lightening_screen)
-      WORD(link_actual_vel_y)++; // wtf?
-  }
-  flag_update_cgram_in_nmi++;
-}
-
-uint8 *LoadItemAnimationGfxOne(uint8 *dst, int num, int r12, bool from_temp) {
-  static const uint8 kIntro_LoadGfx_Tab[10] = { 0, 11, 8, 38, 42, 45, 34, 3, 33, 46 };
-  const uint8 *src = from_temp ? &g_ram[0x14000] : GetCompSpritePtr(0);
-  const uint8 *base_src = src;
-  src += kIntro_LoadGfx_Tab[r12] * 24;
-  Expand3To4High(dst, src, base_src, num);
-  Expand3To4High(dst + 0x20 * num, src + 0x180, base_src, num);
-  return dst + 0x40 * num;
-}
-
-uint16 snes_divide(uint16 dividend, uint8 divisor) {
-  return divisor ? dividend / divisor : 0xffff;
-}
-
-void EraseTileMaps_normal() {
-  EraseTileMaps(0x7f, 0x1ec);
-}
-
-static void DecompAndUpload2bpp(uint16 *vram_ptr, uint8 pack) {
-  Decomp_spr(&g_ram[0x14000], pack);
-  const uint8 *src = &g_ram[0x14000];
-  memcpy(vram_ptr, src, 1024 * sizeof(uint16));
-}
-
-void RecoverPegGFXFromMapping() {
-  if (BYTE(orange_blue_barrier_state))
-    Dungeon_UpdatePegGFXBuffer(0x180, 0x0);
-  else
-    Dungeon_UpdatePegGFXBuffer(0x0, 0x180);
-}
-
-void LoadOverworldMapPalette() {
-  memcpy(main_palette_buffer, &kOverworldMapPaletteData[overworld_screen_index & 0x40 ? 0x80 : 0], 256);
-}
-
-void EraseTileMaps_triforce() {  // 808333
-  EraseTileMaps(0xa9, 0x7f);
-}
-
-void EraseTileMaps_dungeonmap() {  // 80833f
-  EraseTileMaps(0x7f, 0x300);
-}
-
-void EraseTileMaps(uint16 r2, uint16 r0) {  // 808355
-  uint16 *dst = g_zenv.vram;
-  for (int i = 0; i < 0x2000; i++)
-    dst[i] = r0;
-
-  dst = g_zenv.vram + 0x6000;
-  for (int i = 0; i < 0x800; i++)
-    dst[i] = r2;
-}
-
-void EnableForceBlank() {  // 80893d
-  INIDISP_copy = 0x80;
-  HDMAEN_copy = 0;
-}
-
-void LoadItemGFXIntoWRAM4BPPBuffer() {  // 80d231
-  uint8 *dst = &g_ram[0x9000 + 0x480];
-  dst = LoadItemAnimationGfxOne(dst, 7, 0, false);  // rod
-  dst = LoadItemAnimationGfxOne(dst, 7, 1, false);  // hammer
-  dst = LoadItemAnimationGfxOne(dst, 3, 2, false);  // bow
-
-  Decomp_spr(&g_ram[0x14000], 95);
-  dst = LoadItemAnimationGfxOne(dst, 4, 3, true);  // shovel
-  dst = LoadItemAnimationGfxOne(dst, 3, 4, true);  // sleeping zzz
-  dst = LoadItemAnimationGfxOne(dst, 1, 5, true);  // misc #2
-  dst = LoadItemAnimationGfxOne(dst, 4, 6, false); // hookshot
-
-  Decomp_spr(&g_ram[0x14000], 96);
-  dst = LoadItemAnimationGfxOne(dst, 14, 7, true); // bugnet
-  dst = LoadItemAnimationGfxOne(dst, 7, 8, true);  // cane
-
-  Decomp_spr(&g_ram[0x14000], 95);
-  dst = LoadItemAnimationGfxOne(dst, 2, 9, true);  // book of mudora
-  Decomp_spr(&g_ram[0x14000], 84);
-
-  dst = &g_ram[0xa480];
-  Expand3To4High(dst, &g_ram[0x14000], g_ram, 8);
-  Expand3To4High(dst + 8 * 0x20, &g_ram[0x14180], g_ram, 8);
-
-  // rupees
-  Decomp_spr(&g_ram[0x14000], 96);
-  dst = &g_ram[0xb280];
-  Expand3To4High(dst, &g_ram[0x14000], g_ram, 3);
-  Expand3To4High(dst + 3 * 0x20, &g_ram[0x14180], g_ram, 3);
-
-  LoadItemGFX_Auxiliary();
-}
-
-void DecompressSwordGraphics() {  // 80d2c8
-  Decomp_spr(&g_ram[0x14600], 0x5f);
-  Decomp_spr(&g_ram[0x14000], 0x5e);
-  const uint8 *src = &g_ram[0x14000] + kSwordTypeToGfxOffs[link_sword_type];
-  Expand3To4High(&g_ram[0x9000 + 0], src, g_ram, 12);
-  Expand3To4High(&g_ram[0x9000 + 0x180], src + 0x180, g_ram, 12);
-}
-
-void DecompressShieldGraphics() {  // 80d308
-  Decomp_spr(&g_ram[0x14600], 0x5f);
-  Decomp_spr(&g_ram[0x14000], 0x5e);
-  const uint8 *src = &g_ram[0x14000] + kShieldTypeToGfxOffs[link_shield_type];
-  Expand3To4High(&g_ram[0x9000 + 0x300], src, g_ram, 6);
-  Expand3To4High(&g_ram[0x9000 + 0x3c0], src + 0x180, g_ram,6);
-}
-
-void DecompressAnimatedDungeonTiles(uint8 a) {  // 80d337
-  Decomp_bg(&g_ram[0x14000], a);
-  Do3To4Low16Bit(&g_ram[0x9000 + 0x1680], &g_ram[0x14000], 48);
-  Decomp_bg(&g_ram[0x14000], 0x5c);
-  Do3To4Low16Bit(&g_ram[0x9000 + 0x1C80], &g_ram[0x14000], 48);
-
-  for (int i = 0; i < 256; i++) {
-    uint8 *p = &g_ram[0x9000 + i * 2];
-    uint16 x = WORD(p[0x1880]);
-    WORD(p[0x1880]) = WORD(p[0x1C80]);
-    WORD(p[0x1C80]) = WORD(p[0x1E80]);
-    WORD(p[0x1E80]) = WORD(p[0x1A80]);
-    WORD(p[0x1A80]) = x;
-  }
-  animated_tile_vram_addr = 0x3b00;
-}
-
-void DecompressAnimatedOverworldTiles(uint8 a) {  // 80d394
-  Decomp_bg(&g_ram[0x14000], a);
-  Do3To4Low16Bit(&g_ram[0x9000 + 0x1680], &g_ram[0x14000], 64);
-  Decomp_bg(&g_ram[0x14000], a + 1);
-  Do3To4Low16Bit(&g_ram[0x9000 + 0x1E80], &g_ram[0x14000], 32);
-  animated_tile_vram_addr = 0x3c00;
-}
-
-void LoadItemGFX_Auxiliary() {  // 80d3c6
-  Decomp_bg(&g_ram[0x14000], 0xf);
-  Do3To4Low16Bit(&g_ram[0x9000 + 0x2340], &g_ram[0x14000], 16);
-
-  Decomp_spr(&g_ram[0x14000], 0x58);
-  Do3To4Low16Bit(&g_ram[0x9000 + 0x2540], &g_ram[0x14000], 32);
-
-  Decomp_bg(&g_ram[0x14000], 0x5);
-  Do3To4Low16Bit(&g_ram[0x9000 + 0x2dc0], &g_ram[0x14480], 2);
-}
-
-void LoadFollowerGraphics() {  // 80d423
-  uint8 yv = 0x64;
-  if (follower_indicator != 1) {
-    yv = 0x66;
-    if (follower_indicator >= 9) {
-      yv = 0x59;
-      if (follower_indicator >= 12)
-        yv = 0x58;
-    }
-  }
-  Decomp_spr(&g_ram[0x14600], yv);
-  Decomp_spr(&g_ram[0x14000], 0x65);
-  Do3To4Low16Bit(&g_ram[0x9000] + 0x2940, &g_ram[0x14000 + kTagalongWhich[follower_indicator]], 0x20);
-}
-
-void WriteTo4BPPBuffer_at_7F4000(uint8 a) {  // 80d4db
-  uint8 *src = &g_ram[0x14000] + kDecodeAnimatedSpriteTile_Tab[a];
-  Expand3To4High(&g_ram[0x9000] + 0x2d40, src, g_ram, 2);
-  Expand3To4High(&g_ram[0x9000] + 0x2d40 + 0x40, src + 0x180, g_ram, 2);
-}
-
-void DecodeAnimatedSpriteTile_variable(uint8 a) {  // 80d4ed
-  uint8 y = (a == 0x23 || a >= 0x37) ? 0x5d :
-            (a == 0xc || a >= 0x24) ? 0x5c : 0x5b;
-  Decomp_spr(&g_ram[0x14600], y);
-  Decomp_spr(&g_ram[0x14000], 0x5a);
-  WriteTo4BPPBuffer_at_7F4000(a);
-}
-
-void Expand3To4High(uint8 *dst, const uint8 *src, const uint8 *base, int num) {  // 80d61c
-  do {
-    const uint8 *src2 = src + 0x10;
-    int n = 8;
-    do {
-      uint16 t = WORD(src[0]);
-      uint8 u = src2[0];
-      WORD(dst[0]) = t;
-      WORD(dst[0x10]) = (t | (t >> 8) | u) << 8 | u;
-      src += 2, src2 += 1, dst += 2;
-    } while (--n);
-    dst += 16, src = src2;
-    if (!(src - base & 0x78))
-      src += 0x180;
-  } while (--num);
-}
-
-void LoadTransAuxGFX() {  // 80d66e
-  uint8 *dst = &g_ram[0x6000];
-  const uint8 *p = kAuxTilesets[aux_tile_theme_index];
-  int len;
-
-  if (p[0]) {
-    aux_bg_subset_0 = p[0];
-    len = Decomp_bg(dst, aux_bg_subset_0);
-    assert(len == 0x600);
-  }
-  if (p[1]) {
-    aux_bg_subset_1 = p[1];
-    len = Decomp_bg(dst + 0x600, aux_bg_subset_1);
-    assert(len == 0x600);
-  }
-  if (p[2]) {
-    aux_bg_subset_2 = p[2];
-    len = Decomp_bg(dst + 0x600*2, aux_bg_subset_2);
-    assert(len == 0x600);
-  }
-  if (p[3]) {
-    aux_bg_subset_3 = p[3];
-    len = Decomp_bg(dst + 0x600*3, aux_bg_subset_3);
-    assert(len == 0x600);
-  }
-  Gfx_LoadSpritesInner(dst + 0x600 * 4 );
-}
-
-void LoadTransAuxGFX_sprite() {  // 80d6f9
-  Gfx_LoadSpritesInner(&g_ram[0x7800]);
-}
-
-void Gfx_LoadSpritesInner(uint8 *dst) {  // 80d706
-  const uint8 *p = kSpriteTilesets[sprite_graphics_index];
-  int len;
-
-  if (p[0])
-    sprite_gfx_subset_0 = p[0];
-  len = Decomp_spr(dst, sprite_gfx_subset_0);
-  assert(len == 0x600);
-  if (p[1])
-    sprite_gfx_subset_1 = p[1];
-  len = Decomp_spr(dst + 0x600, sprite_gfx_subset_1);
-  assert(len == 0x600);
-  if (p[2])
-    sprite_gfx_subset_2 = p[2];
-  len = Decomp_spr(dst + 0x600*2, sprite_gfx_subset_2);
-  assert(len == 0x600);
-  if (p[3])
-    sprite_gfx_subset_3 = p[3];
-  len = Decomp_spr(dst + 0x600*3, sprite_gfx_subset_3);
-  assert(len == 0x600);
-  incremental_counter_for_vram = 0;
-}
-
-void ReloadPreviouslyLoadedSheets() {  // 80d788
-  Decomp_bg(&g_ram[0x6000], aux_bg_subset_0);
-  Decomp_bg(&g_ram[0x6600], aux_bg_subset_1);
-  Decomp_bg(&g_ram[0x6c00], aux_bg_subset_2);
-  Decomp_bg(&g_ram[0x7200], aux_bg_subset_3);
-  Decomp_spr(&g_ram[0x7800], sprite_gfx_subset_0);
-  Decomp_spr(&g_ram[0x7e00], sprite_gfx_subset_1);
-  Decomp_spr(&g_ram[0x8400], sprite_gfx_subset_2);
-  Decomp_spr(&g_ram[0x8a00], sprite_gfx_subset_3);
-  incremental_counter_for_vram = 0;
-}
-
-void Attract_DecompressStoryGFX() {  // 80d80e
-  Decomp_spr(&g_ram[0x14000], 0x67);
-  Decomp_spr(&g_ram[0x14800], 0x68);
-}
-
-void AnimateMirrorWarp() {  // 80d864
-  int st = overworld_map_state++, tt;
-  nmi_subroutine_index = nmi_disable_core_updates = kMirrorWarp_LoadNext_NmiLoad[st];
-  uint8 t, xt = overworld_screen_index & 0x40 ? 8 : 0;
-  switch (st) {
-  case 0:
-    if (++mirror_vars.ctr2 != 32)
-      overworld_map_state = 0;
-    else
-      SetTargetOverworldWarpToPyramid();
-    break;
-  case 1:
-    AnimateMirrorWarp_DecompressNewTileSets();
-    Decomp_bg(&g_ram[0x14000], kVariousPacks[xt]);
-    Decomp_bg(&g_ram[0x14600], kVariousPacks[xt + 1]);
-    Do3To4High16Bit(&g_ram[0x10000], &g_ram[0x14000], 64);
-    Do3To4Low16Bit(&g_ram[0x10800], &g_ram[0x14600], 64);
-    break;
-  case 2:
-    Decomp_bg(&g_ram[0x14000], kVariousPacks[xt + 2]);
-    Decomp_bg(&g_ram[0x14600], kVariousPacks[xt + 3]);
-    Do3To4Low16Bit(&g_ram[0x10000], &g_ram[0x14000], 64);
-    Do3To4High16Bit(&g_ram[0x10800], &g_ram[0x14600], 64);
-    break;
-  case 3:
-    Decomp_bg(&g_ram[0x14000], aux_bg_subset_1);
-    Decomp_bg(&g_ram[0x14600], aux_bg_subset_2);
-    Do3To4High16Bit(&g_ram[0x10000], &g_ram[0x14000], 128);
-    break;
-  case 4:
-    Decomp_bg(&g_ram[0x14000], kVariousPacks[xt + 4]);
-    Decomp_bg(&g_ram[0x14600], kVariousPacks[xt + 5]);
-    Do3To4Low16Bit(&g_ram[0x10000], &g_ram[0x14000], 128);
-    break;
-  case 5:
-    PreOverworld_LoadOverlays();
-    if (BYTE(overworld_screen_index) == 27 || BYTE(overworld_screen_index) == 91)
-      TS_copy = 1;
-    submodule_index--;
-    nmi_subroutine_index = nmi_disable_core_updates = 12;
-    break;
-  case 6:
-  case 9:
-    nmi_subroutine_index = nmi_disable_core_updates = 13;
-    break;
-  case 7:
-    Overworld_DrawScreenAtCurrentMirrorPosition();
-    nmi_disable_core_updates++;
-    break;
-  case 8:
-    MirrorWarp_LoadSpritesAndColors();
-    nmi_subroutine_index = nmi_disable_core_updates = 12;
-    break;
-  case 10:
-    t = overworld_screen_index & 0xbf;
-    DecompressAnimatedOverworldTiles(t == 3 || t == 5 || t == 7 ? 0x58 : 0x5a);
-    break;
-  case 11:
-    t = overworld_screen_index;
-    TS_copy = (t == 0 || t == 0x70 || t == 0x40 || t == 0x5b || t == 3 || t == 5 || t == 7 || t == 0x43 || t == 0x45 || t == 0x47);
-    Do3To4High16Bit(&g_ram[0x10000], GetCompSpritePtr(kVariousPacks[xt + 6]), 64);
-    break;
-  case 12:
-    Decomp_spr(&g_ram[0x14000], sprite_gfx_subset_0);
-    Decomp_spr(&g_ram[0x14600], sprite_gfx_subset_1);
-    tt = WORD(sprite_gfx_subset_0);
-    if (tt == 0x52 || tt == 0x53 || tt == 0x5a || tt == 0x5b)
-      Do3To4High16Bit(&g_ram[0x10000], &g_ram[0x14000], 64);
-    else
-      Do3To4Low16Bit(&g_ram[0x10000], &g_ram[0x14000], 64);
-    Do3To4Low16Bit(&g_ram[0x10800], &g_ram[0x14600], 64);
-    break;
-  case 13:
-    Decomp_spr(&g_ram[0x14000], sprite_gfx_subset_2);
-    Decomp_spr(&g_ram[0x14600], sprite_gfx_subset_3);
-    Do3To4Low16Bit(&g_ram[0x10000], &g_ram[0x14000], 128);
-    HandleFollowersAfterMirroring();
-    break;
-  case 14:
-    overworld_map_state = 14;
-    break;
-  }
-}
-
-void AnimateMirrorWarp_DecompressNewTileSets() {  // 80d8fe
-  const uint8 *mt = kMainTilesets[main_tile_theme_index];
-  const uint8 *at = kAuxTilesets[aux_tile_theme_index];
-
-  aux_bg_subset_0 = at[0] ? at[0] : mt[3];
-  aux_bg_subset_1 = at[1] ? at[1] : mt[4];
-  aux_bg_subset_2 = at[2] ? at[2] : mt[5];
-  aux_bg_subset_3 = at[3] ? at[3] : mt[6];
-
-  const uint8 *p = kSpriteTilesets[sprite_graphics_index];
-  if (p[0]) sprite_gfx_subset_0 = p[0];
-  if (p[1]) sprite_gfx_subset_1 = p[1];
-  if (p[2]) sprite_gfx_subset_2 = p[2];
-  if (p[3]) sprite_gfx_subset_3 = p[3];
-}
-
-void Graphics_IncrementalVRAMUpload() {  // 80deff
-  if (incremental_counter_for_vram == 16)
-    return;
-
-  static const uint8 kGraphics_IncrementalVramUpload_Dst[16] = { 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f };
-  static const uint8 kGraphics_IncrementalVramUpload_Src[16] = { 0x0, 0x2, 0x4, 0x6, 0x8, 0xa, 0xc, 0xe, 0x10, 0x12, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e };
-
-  nmi_update_tilemap_dst = kGraphics_IncrementalVramUpload_Dst[incremental_counter_for_vram];
-  nmi_update_tilemap_src = kGraphics_IncrementalVramUpload_Src[incremental_counter_for_vram] << 8;
-  incremental_counter_for_vram++;
-}
-
-void PrepTransAuxGfx() {  // 80df1a
-  Do3To4High16Bit(&g_ram[0x10000], &g_ram[0x6000], 0x40);
-  if (aux_tile_theme_index >= 32) {
-    Do3To4High16Bit(&g_ram[0x10800], &g_ram[0x6600], 0x80);
-    Do3To4Low16Bit(&g_ram[0x11800], &g_ram[0x7200], 0x40);
-  } else {
-    Do3To4Low16Bit(&g_ram[0x10800], &g_ram[0x6600], 0xC0);
-  }
-}
-
-void Do3To4High16Bit(uint8 *dst, const uint8 *src, int num) {  // 80df4f
-  do {
-    const uint8 *src2 = src + 0x10;
-    int n = 8;
-    do {
-      uint16 t = WORD(src[0]);
-      uint8 u = src2[0];
-      WORD(dst[0]) = t;
-      WORD(dst[0x10]) = (t | (t >> 8) | u) << 8 | u;
-      src += 2, src2 += 1, dst += 2;
-    } while (--n);
-    dst += 16, src = src2;
-  } while (--num);
-
-}
-
-void Do3To4Low16Bit(uint8 *dst, const uint8 *src, int num) {  // 80dfb8
-  do {
-    const uint8 *src2 = src + 0x10;
-    int n = 8;
-    do {
-      WORD(dst[0]) = WORD(src[0]);
-      WORD(dst[0x10]) = src2[0];
-      src += 2, src2 += 1, dst += 2;
-    } while (--n);
-    dst += 16, src = src2;
-  } while (--num);
-}
-
-void LoadNewSpriteGFXSet() {  // 80e031
-  Do3To4Low16Bit(&g_ram[0x10000], &g_ram[0x7800], 0xC0);
-  if (sprite_gfx_subset_3 == 0x52 || sprite_gfx_subset_3 == 0x53 || sprite_gfx_subset_3 == 0x5a || sprite_gfx_subset_3 == 0x5b)
-    Do3To4High16Bit(&g_ram[0x11800], &g_ram[0x8a00], 0x40);
-  else
-    Do3To4Low16Bit(&g_ram[0x11800], &g_ram[0x8a00], 0x40);
-}
-
-void InitializeTilesets() {  // 80e19b
-  LoadCommonSprites();
-
-  const uint8 *p = kSpriteTilesets[sprite_graphics_index];
-  if (p[0]) sprite_gfx_subset_0 = p[0];
-  if (p[1]) sprite_gfx_subset_1 = p[1];
-  if (p[2]) sprite_gfx_subset_2 = p[2];
-  if (p[3]) sprite_gfx_subset_3 = p[3];
-
-  LoadSpriteGraphics(&g_zenv.vram[0x5000], sprite_gfx_subset_0, &g_ram[0x7800]);
-  LoadSpriteGraphics(&g_zenv.vram[0x5400], sprite_gfx_subset_1, &g_ram[0x7e00]);
-  LoadSpriteGraphics(&g_zenv.vram[0x5800], sprite_gfx_subset_2, &g_ram[0x8400]);
-  LoadSpriteGraphics(&g_zenv.vram[0x5c00], sprite_gfx_subset_3, &g_ram[0x8a00]);
-
-  const uint8 *mt = kMainTilesets[main_tile_theme_index];
-  const uint8 *at = kAuxTilesets[aux_tile_theme_index];
-
-  aux_bg_subset_0 = at[0] ? at[0] : mt[3];
-  aux_bg_subset_1 = at[1] ? at[1] : mt[4];
-  aux_bg_subset_2 = at[2] ? at[2] : mt[5];
-  aux_bg_subset_3 = at[3] ? at[3] : mt[6];
-
-  LoadBackgroundGraphics(&g_zenv.vram[0x2000], mt[0], 7, &g_ram[0x14000]);
-  LoadBackgroundGraphics(&g_zenv.vram[0x2400], mt[1], 6, &g_ram[0x14000]);
-  LoadBackgroundGraphics(&g_zenv.vram[0x2800], mt[2], 5, &g_ram[0x14000]);
-  LoadBackgroundGraphics(&g_zenv.vram[0x2c00], aux_bg_subset_0, 4, &g_ram[0x6000]);
-  LoadBackgroundGraphics(&g_zenv.vram[0x3000], aux_bg_subset_1, 3, &g_ram[0x6600]);
-  LoadBackgroundGraphics(&g_zenv.vram[0x3400], aux_bg_subset_2, 2, &g_ram[0x6c00]);
-  LoadBackgroundGraphics(&g_zenv.vram[0x3800], aux_bg_subset_3, 1, &g_ram[0x7200]);
-  LoadBackgroundGraphics(&g_zenv.vram[0x3c00], mt[7], 0, &g_ram[0x14000]);
-}
-
-void LoadDefaultGraphics() {  // 80e2d0
-  const uint8 *src = GetCompSpritePtr(0);
-
-  uint16 *vram_ptr = &g_zenv.vram[0x4000];
-  uint16 *tmp = (uint16 *)&g_ram[0xbf];
-  int num = 64;
-  do {
-    for (int i = 7; i >= 0; i--, src += 2) {
-      *vram_ptr++ = WORD(src[0]);
-      tmp[i] = src[0] | src[1];
-    }
-    for (int i = 7; i >= 0; i--, src++) {
-      *vram_ptr++ = src[0] | (src[0] | tmp[i]) << 8;
-    }
-  } while (--num);
-
-  // Load 2bpp graphics used for hud
-  DecompAndUpload2bpp(&g_zenv.vram[0x7000], 0x6a);
-  DecompAndUpload2bpp(&g_zenv.vram[0x7400], 0x6b);
-  DecompAndUpload2bpp(&g_zenv.vram[0x7800], 0x69);
-}
-
-void Attract_LoadBG3GFX() {  // 80e36d
-  // load 2bpp gfx for attract images
-  DecompAndUpload2bpp(&g_zenv.vram[0x7800], 0x67);
-}
-
-void Graphics_LoadChrHalfSlot() {  // 80e3fa
-  int k = load_chr_halfslot_even_odd;
-  if (k == 0)
-    return;
-
-  int8 sp6 = kGraphicsLoadSp6[k - 1];
-  if (sp6 >= 0) {
-    palette_sp6r_indoors = sp6;
-    if (k == 1) {
-      palette_sp6r_indoors = 10;
-      overworld_palette_aux_or_main = 0x200;
-      Palette_Load_SpriteEnvironment();
-      flag_update_cgram_in_nmi++;
-    } else {
-      overworld_palette_aux_or_main = 0x200;
-      Palette_Load_SpriteEnvironment_Dungeon();
-      flag_update_cgram_in_nmi++;
-    }
-  }
-  int tilebytes = 0x44;
-  int bank_offs = 0;
-  load_chr_halfslot_even_odd++;
-
-  if (load_chr_halfslot_even_odd & 1) {
-    load_chr_halfslot_even_odd = 0;
-    if (k != 18) {
-      bank_offs = 0x300;
-      tilebytes = 0x46;
-      if (k == 2)
-        flag_custom_spell_anim_active = 0;
-    }
-  }
-  BYTE(nmi_load_target_addr) = tilebytes;
-  nmi_subroutine_index = 11;
-
-  k = kGraphicsHalfSlotPacks[k - 1];
-  if (k == 1)
-    k = misc_sprites_graphics_index;
-
-  const uint8 *srcp = GetCompSpritePtr(k) + bank_offs;
-  uint8 sprdata[24];
-  int num = 32;
-  uint8 *dst = &g_ram[0x11000];
-
-  do {
-    for (int i = 0; i < 24; i++)
-      sprdata[i] = *srcp++;
-
-    uint8 *src = sprdata, *src2 = sprdata + 16;
-    int n = 8;
-    do {
-      uint16 t = WORD(src[0]);
-      uint8 u = src2[0];
-      WORD(dst[0]) = t;
-      WORD(dst[16]) = (t | (t >> 8) | u) << 8 | u;
-      src += 2, src2 += 1, dst += 2;
-    } while (--n);
-    dst += 16;
-  } while (--num);
-}
-
-void TransferFontToVRAM() {  // 80e556
-  memcpy(&g_zenv.vram[0x7000], FindIndexInMemblk(kDialogueFont(0), 0).ptr, 0x800 * sizeof(uint16));
-}
-
-void Do3To4High(uint16 *vram_ptr, const uint8 *decomp_addr) {  // 80e5af
-  for (int j = 0; j < 64; j++) {
-    uint16 *t = (uint16 *)&dung_line_ptrs_row0;
-    for (int i = 7; i >= 0; i--, decomp_addr += 2) {
-      uint16 d = *(uint16 *)decomp_addr;
-      t[i] = (d | (d >> 8)) & 0xff;
-      *vram_ptr++ = d;
-    }
-    for (int i = 7; i >= 0; i--, decomp_addr += 1) {
-      uint8 d = *decomp_addr;
-      *vram_ptr++ = d | (t[i] | d) << 8;
-    }
-  }
-}
-
-void Do3To4Low(uint16 *vram_ptr, const uint8 *decomp_addr) {  // 80e63c
-  for (int j = 0; j < 64; j++) {
-    for (int i = 0; i < 8; i++, decomp_addr += 2)
-      *vram_ptr++ = *(uint16 *)decomp_addr;
-    for (int i = 0; i < 8; i++, decomp_addr += 1)
-      *vram_ptr++ = *decomp_addr;
-  }
-}
-
-void LoadSpriteGraphics(uint16 *vram_ptr, int gfx_pack, uint8 *decomp_addr) {  // 80e583
-  Decomp_spr(decomp_addr, gfx_pack);
-  if (gfx_pack == 0x52 || gfx_pack == 0x53 || gfx_pack == 0x5a || gfx_pack == 0x5b ||
-      gfx_pack == 0x5c || gfx_pack == 0x5e || gfx_pack == 0x5f)
-    Do3To4High(vram_ptr, decomp_addr);
-  else
-    Do3To4Low(vram_ptr, decomp_addr);
-}
-
-void LoadBackgroundGraphics(uint16 *vram_ptr, int gfx_pack, int slot, uint8 *decomp_addr) {  // 80e609
-  Decomp_bg(decomp_addr, gfx_pack);
-  if ((main_tile_theme_index >= 0x20) ? (slot == 7 || slot == 2 || slot == 3 || slot == 4) : (slot >= 4))
-    Do3To4High(vram_ptr, decomp_addr);
-  else
-    Do3To4Low(vram_ptr, decomp_addr);
-}
-
-void LoadCommonSprites() {  // 80e6b7
-  Do3To4High(&g_zenv.vram[0x4400], GetCompSpritePtr(misc_sprites_graphics_index));
-  if (main_module_index != 1) {
-    Do3To4Low(&g_zenv.vram[0x4800], GetCompSpritePtr(6));
-    Do3To4Low(&g_zenv.vram[0x4c00], GetCompSpritePtr(7));
-  } else {
-    // select file
-    LoadSpriteGraphics(&g_zenv.vram[0x4800], 94, &g_ram[0x14000]);
-    LoadSpriteGraphics(&g_zenv.vram[0x4c00], 95, &g_ram[0x14000]);
-  }
-}
-
-int Decomp_spr(uint8 *dst, int gfx) {  // 80e772
-  if (gfx < 12)
-    gfx = 12; // ensure it wont decode bad sheets.
-  MemBlk blk = kSprGfx(gfx);
-  const uint8 *sprite_data = GetCompSpritePtr(gfx);
-  // If the size is not 0x600 then it's compressed
-  if (gfx >= 103 || blk.size != 0x600)
-    return Decompress(dst, blk.ptr);
-  memcpy(dst, blk.ptr, 0x600);
-  return 0x600;
-}
-
-int Decomp_bg(uint8 *dst, int gfx) {  // 80e78f
-  return Decompress(dst, kBgGfx(gfx).ptr);
-}
-
-int Decompress(uint8 *dst, const uint8 *src) {  // 80e79e
-  uint8 *dst_org = dst;
-  int len;
-  for (;;) {
-    uint8 cmd = *src++;
-    if (cmd == 0xff)
-      return dst - dst_org;
-    if ((cmd & 0xe0) != 0xe0) {
-      len = (cmd & 0x1f) + 1;
-      cmd &= 0xe0;
-    } else {
-      len = *src++;
-      len += ((cmd & 3) << 8) + 1;
-      cmd = (cmd << 3) & 0xe0;
-    }
-    //printf("%d: %d,%d\n", (int)(dst - dst_org), cmd, len);
-    if (cmd == 0) {
-      do {
-        *dst++ = *src++;
-      } while (--len);
-    } else if (cmd & 0x80) {
-      uint32 offs = *src++;
-      offs |= *src++ << 8;
-      do {
-        *dst++ = dst_org[offs++];
-      } while (--len);
-    } else if (!(cmd & 0x40)) {
-      uint8 v = *src++;
-      do {
-        *dst++ = v;
-      } while (--len);
-    } else if (!(cmd & 0x20)) {
-      uint8 lo = *src++;
-      uint8 hi = *src++;
-      do {
-        *dst++ = lo;
-        if (--len == 0)
-          break;
-        *dst++ = hi;
-      } while (--len);
-    } else {
-      // copy bytes with the byte incrementing by 1 in between
-      uint8 v = *src++;
-      do {
-        *dst++ = v;
-      } while (v++, --len);
-    }
-  }
-}
-
-void ResetHUDPalettes4and5() {  // 80eb29
-  for (int i = 0; i < 8; i++)
-    main_palette_buffer[16 + i] = 0;
-  palette_filter_countdown = 0;
-  darkening_or_lightening_screen = 2;
-  flag_update_cgram_in_nmi++;
-}
-
-void PaletteFilterHistory() {  // 80eb5e
-  PaletteFilter_Range(0x10, 0x18);
-  PaletteFilter_IncrCountdown();
-}
-
-void PaletteFilter_WishPonds() {  // 80ebc5
-  TS_copy = 2;
-  CGADSUB_copy = 0x30;
-  PaletteFilter_WishPonds_Inner();
-}
-
-void PaletteFilter_Crystal() {  // 80ebcf
-  TS_copy = 1;
-  PaletteFilter_WishPonds_Inner();
-}
-
-void PaletteFilter_WishPonds_Inner() {  // 80ebd3
-  for (int i = 0; i < 8; i++)
-    main_palette_buffer[0xd0 + i] = 0;
-  palette_filter_countdown = 0;
-  darkening_or_lightening_screen = 2;
-  flag_update_cgram_in_nmi++;
-}
-
-void PaletteFilter_RestoreSP5F() {  // 80ebf2
-  for (int i = 7; i >= 0; i--)
-    main_palette_buffer[208 + i] = aux_palette_buffer[208 + i];
-  TS_copy = 0;
-  CGADSUB_copy = 32;
-  flag_update_cgram_in_nmi++;
-}
-
-void PaletteFilter_SP5F() {  // 80ec0d
-  for (int i = 0; i != 2; i++) {
-    PaletteFilter_Range(208, 216);
-    PaletteFilter_IncrCountdown();
-    if (palette_filter_countdown == 0)
-      break;
-  }
-}
-
-void KholdstareShell_PaletteFiltering() {  // 80ec79
-  int t = (enhanced_features0 & kFeatures0_MiscBugFixes) ? 0x50 : 0x40;
-  if (subsubmodule_index == 0) {
-    memcpy(main_palette_buffer + t, aux_palette_buffer + t, 8 * sizeof(uint16));
-    palette_filter_countdown = 0;
-    darkening_or_lightening_screen = 0;
-    flag_update_cgram_in_nmi++;
-    subsubmodule_index = 1;
-    return;
-  }
-  for (int i = 0; i != 2; i++) {
-    PaletteFilter_Range(t, t + 8);
-    PaletteFilter_IncrCountdown();
-    if (palette_filter_countdown == 0) {
-      TS_copy = 0;
-      break;
-    }
-  }
-}
-
-void AgahnimWarpShadowFilter(int k) {  // 80ecca
-  palette_filter_countdown = agahnim_pal_setting[k];
-  darkening_or_lightening_screen = agahnim_pal_setting[k + 3];
-  int t = kPaletteFilter_Agahnim_Tab[k] >> 1;
-  for (int i = 0; i < 2; i++) {
-    PaletteFilter_Range(t, t + 8);
-    if (++palette_filter_countdown == 0x1f) {
-      palette_filter_countdown = 0;
-      darkening_or_lightening_screen ^= 2;
-      break;
-    }
-  }
-  agahnim_pal_setting[k] = palette_filter_countdown;
-  agahnim_pal_setting[k + 3] = darkening_or_lightening_screen;
-  flag_update_cgram_in_nmi++;
-}
-
-void Palette_FadeIntroOneStep() {  // 80ed7c
-  PaletteFilter_RestoreAdditive(0x100, 0x1a0);
-  PaletteFilter_RestoreAdditive(0xc0, 0x100);
-  BYTE(palette_filter_countdown) -= 1;
-  flag_update_cgram_in_nmi++;
-}
-
-void Palette_FadeIntro2() {  // 80ed8f
-  PaletteFilter_RestoreAdditive(0x40, 0xc0);
-  PaletteFilter_RestoreAdditive(0x40, 0xc0);
-  BYTE(palette_filter_countdown) -= 1;
-  flag_update_cgram_in_nmi++;
-}
-
-void PaletteFilter_RestoreAdditive(int from, int to) {  // 80edca
-  from >>= 1, to >>= 1;
-  do {
-    uint16 c = main_palette_buffer[from], cx = c;
-    uint16 d = aux_palette_buffer[from];
-    if ((c & 0x1f) != (d & 0x1f))
-      cx += 1;
-    if ((c & 0x3e0) != (d & 0x3e0))
-      cx += 0x20;
-    if ((c & 0x7c00) != (d & 0x7c00))
-      cx += 0x400;
-    main_palette_buffer[from] = cx;
-  } while (++from != to);
-}
-
-void PaletteFilter_RestoreSubtractive(uint16 from, uint16 to) {  // 80ee21
-  from >>= 1, to >>= 1;
-  do {
-    uint16 c = main_palette_buffer[from], cx = c;
-    uint16 d = aux_palette_buffer[from];
-    if ((c & 0x1f) != (d & 0x1f))
-      cx -= 1;
-    if ((c & 0x3e0) != (d & 0x3e0))
-      cx -= 0x20;
-    if ((c & 0x7c00) != (d & 0x7c00))
-      cx -= 0x400;
-    main_palette_buffer[from] = cx;
-  } while (++from != to);
-}
-
-void PaletteFilter_InitializeWhiteFilter() {  // 80ee78
-  for (int i = 0; i < 256; i++)
-    aux_palette_buffer[i] = 0x7fff;
-  main_palette_buffer[32] = main_palette_buffer[0];
-  palette_filter_countdown = 0;
-  darkening_or_lightening_screen = 2;
-  if (overworld_screen_index == 27) {
-    aux_palette_buffer[0] = aux_palette_buffer[32] = 0;
-    main_palette_buffer[0] = main_palette_buffer[32] = 0;
-  }
-  mirror_vars.ctr = 8;
-  mirror_vars.ctr2 = 0;
-}
-
-void MirrorWarp_RunAnimationSubmodules() {  // 80eee7
-  if (--mirror_vars.ctr) {
-    AnimateMirrorWarp();
-    return;
-  }
-  mirror_vars.ctr = 2;
-  PaletteFilter_BlindingWhite();
-}
-
-void PaletteFilter_BlindingWhite() {  // 80eef1
-  if (darkening_or_lightening_screen == 0xff)
-    return;
-
-  if (darkening_or_lightening_screen == 2) {
-    PaletteFilter_RestoreAdditive(0x40, 0x1b0);
-    PaletteFilter_RestoreAdditive(0x1c0, 0x1e0);
-  } else {
-    PaletteFilter_RestoreSubtractive(0x40, 0x1b0);
-    PaletteFilter_RestoreSubtractive(0x1c0, 0x1e0);
-  }
-  PaletteFilter_StartBlindingWhite();
-}
-
-void PaletteFilter_StartBlindingWhite() {  // 80ef27
-  main_palette_buffer[0] = main_palette_buffer[32];
-  if (!darkening_or_lightening_screen) {
-    if (++palette_filter_countdown == 66) {
-      darkening_or_lightening_screen = 0xff;
-      mirror_vars.ctr = 32;
-    }
-  } else {
-    if (++palette_filter_countdown == 31) {
-      darkening_or_lightening_screen ^= 2;
-      if (main_module_index != 21)
-        return;
-      zelda_snes_dummy_write(HDMAEN, 0);
-      HDMAEN_copy = 0;
-      for (int i = 0; i < 240; i++)
-        hdma_table_dynamic[i] = 0x778;
-      HDMAEN_copy = 0xc0;
-    }
-  }
-  flag_update_cgram_in_nmi++;
-}
-
-void PaletteFilter_BlindingWhiteTriforce() {  // 80ef8a
-  PaletteFilter_RestoreAdditive(0x40, 0x200);
-  PaletteFilter_StartBlindingWhite();
-}
-
-void PaletteFilter_WhirlpoolBlue() {  // 80ef97
-  if (frame_counter & 1) {
-    for (int i = 0x20; i != 0x100; i++) {
-      uint16 t = main_palette_buffer[i];
-      if ((t & 0x7C00) != 0x7C00)
-        t += 0x400;
-      main_palette_buffer[i] = t;
-    }
-    main_palette_buffer[0] = main_palette_buffer[32];
-    if (!(palette_filter_countdown & 1))
-      mosaic_level += 16;
-    if (++palette_filter_countdown == 31) {
-      palette_filter_countdown = 0;
-      subsubmodule_index++;
-      mosaic_level = 0xf0;
-    }
-  }
-  BGMODE_copy = 9;
-  MOSAIC_copy = mosaic_level | 3;
-  flag_update_cgram_in_nmi++;
-}
-
-void PaletteFilter_IsolateWhirlpoolBlue() {  // 80f00c
-  for (int i = 0x20; i != 0x100; i++) {
-    uint16 t = main_palette_buffer[i];
-    if (t & 0x3e0)
-      t -= 0x20;
-    if (t & 0x1f)
-      t -= 1;
-    main_palette_buffer[i] = t;
-  }
-  main_palette_buffer[0] = main_palette_buffer[32];
-  if (++palette_filter_countdown == 31) {
-    palette_filter_countdown = 0;
-    subsubmodule_index++;
-    mosaic_level = 0xf0;
-  }
-  BGMODE_copy = 9;
-  MOSAIC_copy = mosaic_level | 3;
-  flag_update_cgram_in_nmi++;
-}
-
-void PaletteFilter_WhirlpoolRestoreBlue() {  // 80f04a
-  if (frame_counter & 1) {
-    for (int i = 0x20; i != 0x100; i++) {
-      uint16 u = aux_palette_buffer[i] & 0x7c00;
-      uint16 t = main_palette_buffer[i];
-      if ((t & 0x7C00) != u)
-        t -= 0x400;
-      main_palette_buffer[i] = t;
-    }
-    main_palette_buffer[0] = main_palette_buffer[32];
-    if (!(palette_filter_countdown & 1))
-      mosaic_level -= 16;
-    if (++palette_filter_countdown == 31) {
-      palette_filter_countdown = 0;
-      subsubmodule_index++;
-      mosaic_level = 0;
-    }
-  }
-  BGMODE_copy = 9;
-  MOSAIC_copy = mosaic_level | 3;
-  flag_update_cgram_in_nmi++;
-}
-
-void PaletteFilter_WhirlpoolRestoreRedGreen() {  // 80f0c7
-  for (int i = 0x20; i != 0x100; i++) {
-    uint16 u0 = aux_palette_buffer[i] & 0x3e0;
-    uint16 u1 = aux_palette_buffer[i] & 0x1f;
-    uint16 t = main_palette_buffer[i];
-    if ((t & 0x3e0) != u0)
-      t += 0x20;
-    if ((t & 0x1f) != u1)
-      t += 1;
-    main_palette_buffer[i] = t;
-  }
-  main_palette_buffer[0] = main_palette_buffer[32];
-  if (++palette_filter_countdown == 31) {
-    palette_filter_countdown = 0;
-    subsubmodule_index++;
-  }
-  flag_update_cgram_in_nmi++;
-}
-
-void PaletteFilter_RestoreBGSubstractiveStrict() {  // 80f135
-  if (darkening_or_lightening_screen == 255)
-    return;
-  PaletteFilter_RestoreSubtractive(0x40, 0x100);
-  if (++palette_filter_countdown == 0x20) {
-    darkening_or_lightening_screen = 255;
-    WORD(TS_copy) = 0;
-  }
-  flag_update_cgram_in_nmi++;
-}
-
-void PaletteFilter_RestoreBGAdditiveStrict() {  // 80f169
-  PaletteFilter_RestoreAdditive(0x40, 0x100);
-  palette_filter_countdown++;
-  flag_update_cgram_in_nmi++;
-}
-
-void Trinexx_FlashShellPalette_Red() {  // 80f183
-  if (!byte_7E04BE) {
-    for (int i = 0; i < 7; i++) {
-      uint16 v = main_palette_buffer[0x41 + i];
-      main_palette_buffer[0x41 + i] = (v & 0xffe0) | ((v & 0x1f) + ((v & 0x1f) != 0x1f));
-    }
-    flag_update_cgram_in_nmi++;
-    if (++byte_7E04C0 >= 12) {
-      byte_7E04C0 = byte_7E04BE = 0;
-      return;
-    }
-    byte_7E04BE = 3;
-  }
-  byte_7E04BE--;
-}
-
-void Trinexx_UnflashShellPalette_Red() {  // 80f1cf
-  if (!byte_7E04BE) {
-    for (int i = 0; i < 7; i++) {
-      uint16 u = aux_palette_buffer[0x41 + i];
-      uint16 v = main_palette_buffer[0x41 + i];
-      main_palette_buffer[0x41 + i] = (v & 0xffe0) | ((v & 0x1f) - ((v & 0x1f) != (u & 0x1f)));
-    }
-    flag_update_cgram_in_nmi++;
-    if (++byte_7E04C0 >= 12) {
-      byte_7E04C0 = byte_7E04BE = 0;
-      return;
-    }
-    byte_7E04BE = 3;
-  }
-  byte_7E04BE--;
-}
-
-void Trinexx_FlashShellPalette_Blue() {  // 80f207
-  if (!byte_7E04BF) {
-    for (int i = 0; i < 7; i++) {
-      uint16 v = main_palette_buffer[0x41 + i];
-      main_palette_buffer[0x41 + i] = (v & ~0x7c00) | (v & 0x7c00) + (((v & 0x7c00) != 0x7c00) << 10);
-    }
-    flag_update_cgram_in_nmi++;
-    if (++byte_7E04C1 >= 12) {
-      byte_7E04C1 = byte_7E04BF = 0;
-      return;
-    }
-    byte_7E04BF = 3;
-  }
-  byte_7E04BF--;
-
-}
-
-void Trinexx_UnflashShellPalette_Blue() {  // 80f253
-  if (!byte_7E04BF) {
-    for (int i = 0; i < 7; i++) {
-      uint16 u = aux_palette_buffer[0x41 + i];
-      uint16 v = main_palette_buffer[0x41 + i];
-      main_palette_buffer[0x41 + i] = (v & ~0x7c00) | (v & 0x7c00) - (((v & 0x7c00) != (u & 0x7c00)) << 10);
-    }
-    flag_update_cgram_in_nmi++;
-    if (++byte_7E04C1 >= 12) {
-      byte_7E04C1 = byte_7E04BF = 0;
-      return;
-    }
-    byte_7E04BF = 3;
-  }
-  byte_7E04BF--;
-}
-
-void IrisSpotlight_close() {  // 80f28b
-  SpotlightInternal(0x7e, 0);
-}
-
-void Spotlight_open() {  // 80f295
-  SpotlightInternal(0, 2);
-}
-
-void SpotlightInternal(uint8 x, uint8 y) {  // 80f29d
-  spotlight_var1 = x;
-  spotlight_var2 = y;
-
-  zelda_snes_dummy_write(HDMAEN, 0);
-  HdmaSetup(0xF2FB, 0xF2FB, 0x41, (uint8)WH0, (uint8)WH0, 0);
-
-  W12SEL_copy = 0x33;
-  W34SEL_copy = 3;
-  WOBJSEL_copy = 0x33;
-  TMW_copy = TM_copy;
-  TSW_copy = TS_copy;
-  if (!player_is_indoors) {
-    COLDATA_copy0 = 0x20;
-    COLDATA_copy1 = 0x40;
-    COLDATA_copy2 = 0x80;
-  }
-  IrisSpotlight_ConfigureTable();
-  HDMAEN_copy = 0x80;
-  INIDISP_copy = 0xf;
-}
-
-void IrisSpotlight_ConfigureTable() {  // 80f312
-  uint16 r14 = link_y_coord - BG2VOFS_copy2 + 12;
-  spotlight_y_lower = r14 - spotlight_var1;
-  spotlight_y_upper = r14 + spotlight_var1;
-  spotlight_var3 = link_x_coord - BG2HOFS_copy2 + 8;
-  spotlight_var4 = spotlight_var1;
-  uint16 r6 = r14 * 2;
-  if (r6 < 224)
-    r6 = 224;
-  uint16 r4 = r14 * 2 - r6;
-  for(;;) {
-    uint16 r8 = 0xff;
-    if (r6 < spotlight_y_upper) {
-      uint8 t = spotlight_var4;
-      if (spotlight_var4)
-        spotlight_var4--;
-      r8 = IrisSpotlight_CalculateCircleValue(t);
-    }
-    if (r4 < 240)
-      hdma_table_dynamic[r4] = r8;
-    if (r6 < 240)
-      hdma_table_dynamic[r6] = r8;
-    if (r4 == r14)
-      break;
-    r4++, r6--;
-  }
-
-  for (int i = 224; i < 240; i++)
-    hdma_table_dynamic[i] = 0;
-
-  memcpy(hdma_table_unused, hdma_table_dynamic, 224  * sizeof(uint16));
-
-  spotlight_var1 += kSpotlight_delta_size[spotlight_var2 >> 1];
-
-  if (spotlight_var1 != kSpotlight_goal[spotlight_var2 >> 1])
-    return;
-
-  if (!spotlight_var2) {
-    INIDISP_copy = 0x80;
-  } else {
-    IrisSpotlight_ResetTable();
-  }
-  subsubmodule_index = 0;
-  submodule_index = 0;
-
-  if (main_module_index == 7 || main_module_index == 16) {
-    if (!player_is_indoors)
-      sound_effect_ambient = overworld_music[BYTE(overworld_screen_index)] >> 4;
-    if (queued_music_control != 0xff)
-      music_control = queued_music_control;
-  }
-  main_module_index = saved_module_for_menu;
-  if (main_module_index == 6)
-    Sprite_ResetAll();
-}
-
-void IrisSpotlight_ResetTable() {  // 80f427
-  for (int i = 0; i < 240; i++)
-    hdma_table_dynamic[i] = 0xff00;
-}
-
-uint16 IrisSpotlight_CalculateCircleValue(uint8 a) {  // 80f4cc
-  uint8 t = snes_divide(a << 8, spotlight_var1) >> 1;
-  uint8 r10 = kConfigureSpotlightTable_Helper_Tab[t];
-  uint16 p = 2 * (uint8)(r10 * (uint8)spotlight_var1 >> 8);
-  if (!r10)
-    return 0xff;
-  uint16 r2 = spotlight_var3 + p;
-  uint16 r0 = spotlight_var3 - p;
-  r0 = ((int16)r0 < 0) ? 0 :
-         r0 < 255 ? r0 : 255;
-  r2 = r2 < 255 ? r2 : 255;
-  r0 |= r2 << 8;
-  return r0 == 0xffff ? 0xff : r0;
-}
-
-void AdjustWaterHDMAWindow() {  // 80f649
-  uint16 r10 = water_hdma_var1 - BG2VOFS_copy2;
-  spotlight_y_lower = r10 - water_hdma_var2;
-  spotlight_y_upper = r10 + water_hdma_var2;
-  AdjustWaterHDMAWindow_X(r10);
-}
-
-void AdjustWaterHDMAWindow_X(uint16 r10) {  // 80f660
-  spotlight_var3 = water_hdma_var0 - BG2HOFS_copy2;
-  uint16 r12 = water_hdma_var3 ? water_hdma_var3 - 1 : 0;
-  uint16 r2 = spotlight_var3 + r12;
-  uint16 r0 = spotlight_var3 - r12;
-
-  r0 = (r0 < 255) ? r0 : 255;
-  r2 = (r2 < 255) ? r2 : 255;
-  r12 = r0 | r2 << 8;
-
-  uint16 r6 = r10 * 2;
-  if (r6 < 0xe0)
-    r6 = 0xe0;
-  uint16 r4 = 2 * r10 - r6;
-  uint16 a;
-
-  do {
-    if (!sign16(r4)) {
-      if (!sign16(spotlight_y_lower) && r4 < spotlight_y_lower)
-        a = 0xff;
-      else
-        a = r12;
-      if (r4 < 240)
-        hdma_table_dynamic[r4] = (a != 0xffff) ? a : 0xff;
-    }
-    if (r6 >= spotlight_y_upper) {
-      a = 0xff;
-    } else {
-      if (r6 >= 225 && word_7E0678)
-        word_7E0678--;
-      a = r12;
-    }
-    if (r6 < 240)
-      hdma_table_dynamic[r6] = (a != 0xffff) ? a : 0xff;
-  } while (r6--, r10 != r4++);
-}
-
-void FloodDam_PrepFloodHDMA() {  // 80f734
-  spotlight_y_lower = water_hdma_var1 - BG2VOFS_copy2;
-  spotlight_var3 = water_hdma_var0 - BG2HOFS_copy2;
-  uint16 r14 = water_hdma_var3 ^ 1;
-  uint16 r12 = (spotlight_var3 + r14) << 8 | (uint8)(spotlight_var3 - r14);
-
-  int r4 = 0;
-  do {
-    hdma_table_dynamic[r4] = 0xff00;
-  } while (++r4 != spotlight_y_upper);
-
-  r12 = r14 - 7 + 8;
-  r12 = (spotlight_var3 + r12) << 8 | (uint8)(spotlight_var3 - r12);
-  uint16 r10 = (spotlight_y_upper + water_hdma_var2) ^ 1;
-
-  do {
-    if (r4 >= r10) {
-      hdma_table_dynamic[r4] = 0xff;
-    } else {
-      uint16 a = r4;
-      do {
-        a *= 2;
-      } while (a >= 480);
-      hdma_table_dynamic[a >> 1] = r12 == 0xffff ? 0xff : r12;
-    }
-  } while (++r4 < 225);
-}
-
-void ResetStarTileGraphics() {  // 80fda4
-  byte_7E04BC = 0;
-  Dungeon_RestoreStarTileChr();
-}
-
-void Dungeon_RestoreStarTileChr() {  // 80fda7
-  int xx = 0, yy = 32;
-  if (byte_7E04BC)
-    xx = 32, yy = 0;
-  uint16 *p = messaging_buf;
-  memcpy(p, g_ram + 0xbdc0 + xx, 32);
-  memcpy(p + 16, g_ram + 0xbdc0 + yy, 32);
-  nmi_subroutine_index = 0x18;
-}
-
-void LinkZap_HandleMosaic() {  // 81fed2
-  int level = mosaic_level;
-  if (!mosaic_inc_or_dec) {
-    level += 0x10;
-    if (level == 0xc0)
-      mosaic_inc_or_dec = 1;
-  } else {
-    level -= 0x10;
-    if (level == 0)
-      mosaic_inc_or_dec = 0;
-  }
-  mosaic_level = level;
-  MOSAIC_copy = mosaic_level >> 1 | 3;
-  BGMODE_copy = 9;
-}
-
-void Player_SetCustomMosaicLevel(uint8 a) {  // 81fef0
-  mosaic_inc_or_dec = 0;
-  mosaic_level = a;
-  MOSAIC_copy = mosaic_level >> 1 | 3;
-  BGMODE_copy = 9;
-}
-
-void Module07_16_UpdatePegs_Step1() {  // 829739
-  if (BYTE(orange_blue_barrier_state))
-    Dungeon_UpdatePegGFXBuffer(0x80, 0x100);
-  else
-    Dungeon_UpdatePegGFXBuffer(0x100, 0x80);
-}
-
-void Module07_16_UpdatePegs_Step2() {  // 82974d
-  if (BYTE(orange_blue_barrier_state))
-    Dungeon_UpdatePegGFXBuffer(0x100, 0x80);
-  else
-    Dungeon_UpdatePegGFXBuffer(0x80, 0x100);
-}
-
-void Dungeon_UpdatePegGFXBuffer(int x, int y) {  // 829773
-  uint16 *src = (uint16 *)&g_ram[0xb340];
-  for (int i = 0; i < 64; i++)
-    messaging_buf[i] = src[(x >> 1) + i];
-  for (int i = 0; i < 64; i++)
-    messaging_buf[64 + i] = src[(y >> 1) + i];
-  nmi_subroutine_index = 23;
-}
-
-void Dungeon_HandleTranslucencyAndPalette() {  // 82a1e9
-  if (palette_swap_flag)
-    Palette_RevertTranslucencySwap();
-
-  CGWSEL_copy = 2;
-  CGADSUB_copy = 0xb3;
-
-  uint8 torch = dung_num_lit_torches;
-  if (!dung_want_lights_out) {
-    uint8 a = 0x20;
-    if ((a = 0x20, dung_hdr_bg2_properties != 0) &&
-        (a = 0x32, dung_hdr_bg2_properties != 7) &&
-        (a = 0x62, dung_hdr_bg2_properties != 4) &&
-        (a = 0x20, dung_hdr_bg2_properties == 2)) {
-      Palette_AssertTranslucencySwap();
-      if (BYTE(dungeon_room_index) == 13) {
-        agahnim_pal_setting[0] = 0;
-        agahnim_pal_setting[1] = 0;
-        agahnim_pal_setting[2] = 0;
-        agahnim_pal_setting[3] = 0;
-        agahnim_pal_setting[4] = 0;
-        agahnim_pal_setting[5] = 0;
-        Palette_LoadAgahnim();
-      }
-      a = 0x70;
-    }
-    CGADSUB_copy = a;
-    torch = 3;
-  }
-  overworld_fixed_color_plusminus = kLitTorchesColorPlus[torch];
-  palette_filter_countdown = 31;
-  mosaic_target_level = 0;
-  darkening_or_lightening_screen = 2;
-  overworld_palette_aux_or_main = 0;
-  Palette_Load_DungeonSet();
-  Palette_Load_Sp0L();
-  Palette_Load_Sp5L();
-  Palette_Load_Sp6L();
-  subsubmodule_index += 1;
-}
-
-void Overworld_LoadAllPalettes() {  // 82c5b2
-  memset(aux_palette_buffer + 0x180 / 2, 0, 128);
-  memset(main_palette_buffer, 0, 512);
-
-  overworld_palette_mode = 5;
-  overworld_palette_aux1_bp2to4_hi = 3;
-  overworld_palette_aux2_bp5to7_hi = 3;
-  overworld_palette_aux3_bp7_lo = 0;
-  palette_sp6r_indoors = 5;
-  palette_sp0l = 11;
-  palette_swap_flag = 0;
-  overworld_palette_aux_or_main = 0;
-  Palette_BgAndFixedColor_Black();
-  Palette_Load_Sp0L();
-  Palette_Load_SpriteMain();
-  Palette_Load_OWBGMain();
-  Palette_Load_OWBG1();
-  Palette_Load_OWBG2();
-  Palette_Load_OWBG3();
-  Palette_Load_SpriteEnvironment_Dungeon();
-  Palette_Load_HUD();
-
-  for (int i = 0; i < 8; i++)
-    main_palette_buffer[0x1b0 / 2 + i] = aux_palette_buffer[0x1d0 / 2 + i];
-}
-
-void Dungeon_LoadPalettes() {  // 82c630
-  overworld_palette_aux_or_main = 0;
-  Palette_BgAndFixedColor_Black();
-  Palette_Load_Sp0L();
-  Palette_Load_SpriteMain();
-  Palette_Load_Sp5L();
-  Palette_Load_Sp6L();
-  Palette_Load_Sword();
-  Palette_Load_Shield();
-  Palette_Load_SpriteEnvironment();
-  Palette_Load_LinkArmorAndGloves();
-  Palette_Load_HUD();
-  Palette_Load_DungeonSet();
-  Overworld_LoadPalettesInner();
-}
-
-void Overworld_LoadPalettesInner() {  // 82c65f
-  overworld_pal_unk1 = palette_main_indoors;
-  overworld_pal_unk2 = overworld_palette_aux3_bp7_lo;
-  overworld_pal_unk3 = byte_7E0AB7;
-  darkening_or_lightening_screen = 2;
-  palette_filter_countdown = 0;
-  WORD(mosaic_target_level) = 0;
-  Overworld_CopyPalettesToCache();
-}
-
-void OverworldLoadScreensPaletteSet() {  // 82c692
-  uint8 sc = overworld_screen_index & 0x3f;
-  uint8 x = (sc == 3 || sc == 5 || sc == 7) ? 2 : 0;
-  x += (overworld_screen_index & 0x40) ? 1 : 0;
-  Overworld_LoadAreaPalettesEx(x);
-}
-
-void Overworld_LoadAreaPalettesEx(uint8 x) {  // 82c6ad
-  overworld_palette_mode = x;
-  overworld_palette_aux_or_main &= 0xff;
-  Palette_Load_SpriteMain();
-  Palette_Load_SpriteEnvironment();
-  Palette_Load_Sp5L();
-  Palette_Load_Sp6L();
-  Palette_Load_Sword();
-  Palette_Load_Shield();
-  Palette_Load_LinkArmorAndGloves();
-  palette_sp0l = (savegame_is_darkworld & 0x40) ? 3 : 1;
-  Palette_Load_Sp0L();
-  Palette_Load_HUD();
-  Palette_Load_OWBGMain();
-}
-
-void SpecialOverworld_CopyPalettesToCache() {  // 82c6eb
-  for (int i = 32; i < 32 * 8; i++)
-    main_palette_buffer[i] = 0;
-  for (int i = 0; i < 8; i++) {
-    main_palette_buffer[i] = aux_palette_buffer[i];
-    main_palette_buffer[i + 0x8] = aux_palette_buffer[i + 0x8];
-    main_palette_buffer[i + 0x10] = aux_palette_buffer[i + 0x10];
-    main_palette_buffer[i + 0x18] = aux_palette_buffer[i + 0x18];
-    main_palette_buffer[i + 0xd8] = aux_palette_buffer[i + 0xd8];
-    main_palette_buffer[i + 0xe8] = aux_palette_buffer[i + 0xe8];
-    main_palette_buffer[i + 0xf0] = aux_palette_buffer[i + 0xf0];
-    main_palette_buffer[i + 0xf8] = aux_palette_buffer[i + 0xf8];
-  }
-  MOSAIC_copy = 0xf7;
-  mosaic_level = 0xf7;
-  flag_update_cgram_in_nmi++;
-}
-
-void Overworld_CopyPalettesToCache() {  // 82c769
-  memcpy(main_palette_buffer, aux_palette_buffer, 512);
-  flag_update_cgram_in_nmi += 1;
-}
-
-void Overworld_LoadPalettes(uint8 bg, uint8 spr) {  // 8ed5a8
-  overworld_palette_aux_or_main = 0;
-
-  const int8 *d = kOwBgPalInfo + bg * 3;
-  if (d[0] >= 0)
-    overworld_palette_aux1_bp2to4_hi = d[0];
-  if (d[1] >= 0)
-    overworld_palette_aux2_bp5to7_hi = d[1];
-  if (d[2] >= 0)
-    overworld_palette_aux3_bp7_lo = d[2];
-
-  d = kOwSprPalInfo + spr * 2;
-  if (d[0] >= 0)
-    palette_sp5l = d[0];
-  if (d[1] >= 0)
-    palette_sp6l = d[1];
-  Palette_Load_OWBG1();
-  Palette_Load_OWBG2();
-  Palette_Load_OWBG3();
-  Palette_Load_Sp5L();
-  Palette_Load_Sp6L();
-}
-
-void Palette_BgAndFixedColor_Black() {  // 8ed5f4
-  Palette_SetBgAndFixedColor(0);
-}
-
-void Palette_SetBgAndFixedColor(uint16 color) {  // 8ed5f9
-  main_palette_buffer[0] = color;
-  main_palette_buffer[32] = color;
-  aux_palette_buffer[0] = color;
-  aux_palette_buffer[32] = color;
-  SetBackdropcolorBlack();
-}
-
-void SetBackdropcolorBlack() {  // 8ed60b
-  COLDATA_copy0 = 0x20;
-  COLDATA_copy1 = 0x40;
-  COLDATA_copy2 = 0x80;
-}
-
-void Palette_SetOwBgColor() {  // 8ed618
-  Palette_SetBgAndFixedColor(Palette_GetOwBgColor());
-}
-
-void Palette_SpecialOw() {  // 8ed61d
-  uint16 c = Palette_GetOwBgColor();
-  aux_palette_buffer[0] = c;
-  aux_palette_buffer[32] = c;
-  SetBackdropcolorBlack();
-}
-
-uint16 Palette_GetOwBgColor() {  // 8ed622
-  if (overworld_screen_index < 0x80)
-    return overworld_screen_index & 0x40 ? 0x2A32 : 0x2669;
-  if (dungeon_room_index == 0x180 || dungeon_room_index == 0x182 || dungeon_room_index == 0x183)
-    return 0x19C6;
-  return 0x2669;
-}
-
-void Palette_AssertTranslucencySwap() {  // 8ed657
-  Palette_SetTranslucencySwap(true);
-}
-
-void Palette_SetTranslucencySwap(bool v) {  // 8ed65c
-  palette_swap_flag = v;
-  uint16 a, b;
-  for (int i = 0; i < 8; i++) {
-    a = aux_palette_buffer[i + 0x80];
-    b = aux_palette_buffer[i + 0xf0];
-    main_palette_buffer[i + 0xf0] = aux_palette_buffer[i + 0xf0] = a;
-    main_palette_buffer[i + 0x80] = aux_palette_buffer[i + 0x80] = b;
-
-    a = aux_palette_buffer[i + 0x88];
-    b = aux_palette_buffer[i + 0xf8];
-    main_palette_buffer[i + 0xf8] = aux_palette_buffer[i + 0xf8] = a;
-    main_palette_buffer[i + 0x88] = aux_palette_buffer[i + 0x88] = b;
-
-    a = aux_palette_buffer[i + 0xb8];
-    b = aux_palette_buffer[i + 0xd8];
-    main_palette_buffer[i + 0xd8] = aux_palette_buffer[i + 0xd8] = a;
-    main_palette_buffer[i + 0xb8] = aux_palette_buffer[i + 0xb8] = b;
-  }
-  flag_update_cgram_in_nmi++;
-}
-
-void Palette_RevertTranslucencySwap() {  // 8ed6bb
-  Palette_SetTranslucencySwap(false);
-}
-
-void LoadActualGearPalettes() {  // 8ed6c0
-  LoadGearPalettes(link_sword_type, link_shield_type, link_armor);
-  if (enhanced_features0 & kFeatures0_MiscBugFixes)
-    Palette_UpdateGlovesColor();
-}
-
-void Palette_ElectroThemedGear() {  // 8ed6d1
-  LoadGearPalettes(2, 2, 4);
-}
-
-void LoadGearPalettes_bunny() {  // 8ed6dd
-  LoadGearPalettes(link_sword_type, link_shield_type, 3);
-}
-
-void LoadGearPalettes(uint8 sword, uint8 shield, uint8 armor) {  // 8ed6e8
-  const uint16 *src = kPalette_Sword + (sword && sword != 255 ? sword - 1 : 0) * 3;
-  Palette_LoadMultiple_Arbitrary(src, 0x1b2, 2);
-
-  src = kPalette_Shield + (shield ? shield - 1 : 0) * 4;
-  Palette_LoadMultiple_Arbitrary(src, 0x1b8, 3);
-
-  src = kPalette_ArmorAndGloves + armor * 15;
-  Palette_LoadMultiple_Arbitrary(src, 0x1e2, 14);
-  flag_update_cgram_in_nmi++;
-}
-
-void LoadGearPalette(int dst, const uint16 *src, int n) {  // 8ed741
-  memcpy(&aux_palette_buffer[dst >> 1], src, sizeof(uint16) * n);
-  memcpy(&main_palette_buffer[dst >> 1], src, sizeof(uint16) * n);
-}
-
-void Filter_Majorly_Whiten_Bg() {  // 8ed757
-  for (int i = 32; i < 128; i++)
-    main_palette_buffer[i] = Filter_Majorly_Whiten_Color(aux_palette_buffer[i]);
-  main_palette_buffer[0] = aux_palette_buffer[0] ? main_palette_buffer[32] : 0;
-}
-
-uint16 Filter_Majorly_Whiten_Color(uint16 c) {  // 8ed7fe
-  int amt = (enhanced_features0 & kFeatures0_DimFlashes) ? 3 : 14;
-  int r = (c & 0x1f) + amt;
-  int g = (c & 0x3e0) + (amt << 5);
-  int b = (c & 0x7c00) + (amt << 10);
-  if (r > 0x1f) r = 0x1f;
-  if (g > 0x3e0) g = 0x3e0;
-  if (b > 0x7c00) b = 0x7c00;
-  return r | g | b;
-}
-
-void Palette_Restore_BG_From_Flash() {  // 8ed83a
-  for (int i = 32; i < 128; i++)
-    main_palette_buffer[i] = aux_palette_buffer[i];
-  main_palette_buffer[0] = main_palette_buffer[32];
-  Palette_Restore_Coldata();
-}
-
-void Palette_Restore_Coldata() {  // 8ed8ae
-  if (!player_is_indoors) {
-    uint32 rgb;
-    switch (BYTE(overworld_screen_index)) {
-    case 3: case 5: case 7:
-      rgb = 0x8c4c26;
-      break;
-    case 0x43: case 0x45: case 0x47:
-      rgb = 0x874a26;
-      break;
-    case 0x5b:
-      rgb = 0x894f33;
-      break;
-    default:
-      rgb = 0x804020;
-    }
-    COLDATA_copy0 = (uint8)(rgb);
-    COLDATA_copy1 = (uint8)(rgb >> 8);
-    COLDATA_copy2 = (uint8)(rgb >> 16);
-  }
-}
-
-void Palette_Restore_BG_And_HUD() {  // 8ed8fb
-  memcpy(main_palette_buffer, aux_palette_buffer, 256);
-  flag_update_cgram_in_nmi++;
-  Palette_Restore_Coldata();
-}
-
-/* Summary of sprite palette usage 
-0l: kPalette_SpriteAux3[palette_sp0l]
-0r: kPalette_MiscSprite[7 / 9] or kPalette_DungBgMain[(palette_main_indoors >> 1) * 90]
-1 : common sprites
-2 :      -"-
-3 :      -"-
-4 :      -"-
-5l: palette_sp5l
-5r: link sword/shield
-6l: palette_sp6l
-6r: kPalette_MiscSprite[6 / 8] or kPalette_MiscSprite[palette_sp6r_indoors]
-7 : link armor and gloves
-*/
-
-enum {
-  kPal_sp0l = 0x102,
-  kPal_sp0r = 0x112,
-  kPal_sp1to4 = 0x122,   // This is used for 64 colors, colors switched if in darkworld mode
-  kPal_sp5l = 0x1a2,
-  kPal_Sword = 0x1b2,
-  kPal_Shield = 0x1b8,
-  kPal_sp6l = 0x1c2,
-  kPal_sp6r = 0x1d2,
-  kPal_sp7l = 0x1e2,
-  kPal_sp7r = 0x1f2,
-  kPal_ArmorGloves = 0x1e2,
-  kPal_PalaceMap = 0x182,
-};
-
-void Palette_Load_Sp0L() {  // 9bec77
-  const uint16 *src = kPalette_SpriteAux3 + palette_sp0l * 7;
-  Palette_LoadSingle(src, palette_swap_flag ? kPal_sp7l : kPal_sp0l, 6);
-}
-
-void Palette_Load_SpriteMain() {  // 9bec9e
-  const uint16 *src = kPalette_MainSpr + (overworld_screen_index & 0x40 ? 60 : 0);
-  Palette_LoadMultiple(src, kPal_sp1to4, 14, 3);
-}
-
-void Palette_Load_Sp5L() {  // 9becc5
-  const uint16 *src = kPalette_SpriteAux1 + (palette_sp5l) * 7;
-  Palette_LoadSingle(src, kPal_sp5l, 6);
-}
-
-void Palette_Load_Sp6L() {  // 9bece4
-  const uint16 *src = kPalette_SpriteAux1 + (palette_sp6l) * 7;
-  Palette_LoadSingle(src, kPal_sp6l, 6);
-}
-
-void Palette_Load_Sword() {  // 9bed03
-  const uint16 *src = kPalette_Sword + ((int8)link_sword_type > 0 ? link_sword_type - 1 : 0) * 3;  // wtf: zelda reads offset 0xff
-  Palette_LoadMultiple_Arbitrary(src, kPal_Sword, 2);
-  flag_update_cgram_in_nmi += 1;
-}
-
-void Palette_Load_Shield() {  // 9bed29
-  const uint16 *src = kPalette_Shield + (link_shield_type ? link_shield_type - 1 : 0) * 4;
-  Palette_LoadMultiple_Arbitrary(src, kPal_Shield, 3);
-  flag_update_cgram_in_nmi += 1;
-}
-
-void Palette_Load_SpriteEnvironment() {  // 9bed6e
-  if (player_is_indoors)
-    Palette_Load_SpriteEnvironment_Dungeon();
-  else
-    Palette_MiscSprite_Outdoors();
-}
-
-// avoid renaming in assets.dat
-#define kPalette_MiscSprite kPalette_MiscSprite_Indoors
-
-void Palette_Load_SpriteEnvironment_Dungeon() {  // 9bed72
-  const uint16 *src = kPalette_MiscSprite + palette_sp6r_indoors * 7;
-  Palette_LoadSingle(src, kPal_sp6r, 6);
-}
-
-void Palette_MiscSprite_Outdoors() {  // 9bed91
-  int t = (overworld_screen_index & 0x40) ? 9 : 7;
-  const uint16 *src = kPalette_MiscSprite + t * 7;
-  Palette_LoadSingle(src, palette_swap_flag ? kPal_sp7r : kPal_sp0r, 6);
-  Palette_LoadSingle(src - 7, kPal_sp6r, 6);
-}
-
-void Palette_Load_DungeonMapSprite() {  // 9beddd
-  Palette_LoadMultiple(kPalette_PalaceMapSpr, kPal_PalaceMap, 6, 2);
-}
-
-void Palette_Load_LinkArmorAndGloves() {  // 9bedf9
-  const uint16 *src = kPalette_ArmorAndGloves + link_armor * 15;
-  Palette_LoadMultiple_Arbitrary(src, kPal_ArmorGloves, 14);
-  Palette_UpdateGlovesColor();
-}
-
-void Palette_UpdateGlovesColor() {  // 9bee1b
-  if (link_item_gloves)
-    main_palette_buffer[0xfd] = aux_palette_buffer[0xfd] = kGlovesColor[link_item_gloves - 1];
-  flag_update_cgram_in_nmi += 1;
-}
-
-void Palette_Load_DungeonMapBG() {  // 9bee3a
-  Palette_LoadMultiple(kPalette_PalaceMapBg, 0x40, 15, 5);
-}
-
-void Palette_Load_HUD() {  // 9bee52
-  const uint16 *src = kHudPalData + hud_palette * 32;
-  Palette_LoadMultiple(src, 0x0, 15, 1);
-}
-
-void Palette_Load_DungeonSet() {  // 9bee74
-  const uint16 *src = kPalette_DungBgMain + (palette_main_indoors >> 1) * 90;
-  Palette_LoadMultiple(src, 0x42, 14, 5);
-  Palette_LoadSingle(src, palette_swap_flag ? kPal_sp7r : kPal_sp0r, 6);
-}
-
-void Palette_Load_OWBG3() {  // 9beea8
-  const uint16 *src = kPalette_OverworldBgAux3 + overworld_palette_aux3_bp7_lo * 7;
-  Palette_LoadSingle(src, 0xE2, 6);
-}
-
-void Palette_Load_OWBGMain() {  // 9beec7
-  const uint16 *src = kPalette_OverworldBgMain + overworld_palette_mode * 35;
-  Palette_LoadMultiple(src, 0x42, 6, 4);
-}
-
-void Palette_Load_OWBG1() {  // 9beee8
-  const uint16 *src = kPalette_OverworldBgAux12 + overworld_palette_aux1_bp2to4_hi * 21;
-  Palette_LoadMultiple(src, 0x52, 6, 2);
-}
-
-void Palette_Load_OWBG2() {  // 9bef0c
-  const uint16 *src = kPalette_OverworldBgAux12 + overworld_palette_aux2_bp5to7_hi * 21;
-  Palette_LoadMultiple(src, 0xB2, 6, 2);
-}
-
-void Palette_LoadSingle(const uint16 *src, int dst, int x_ents) {  // 9bef30
-  memcpy(&aux_palette_buffer[(dst + overworld_palette_aux_or_main) >> 1], src, sizeof(uint16) * (x_ents + 1));
-}
-
-void Palette_LoadMultiple(const uint16 *src, int dst, int x_ents, int y_pals) {  // 9bef4b
-  x_ents++;
-  do {
-    memcpy(&aux_palette_buffer[(dst + overworld_palette_aux_or_main) >> 1], src, sizeof(uint16) * x_ents);
-    src += x_ents;
-    dst += 32;
-  } while (--y_pals >= 0);
-}
-
-void Palette_LoadMultiple_Arbitrary(const uint16 *src, int dst, int x_ents) {  // 9bef7b
-  memcpy(&aux_palette_buffer[dst >> 1], src, sizeof(uint16) * (x_ents + 1));
-  memcpy(&main_palette_buffer[dst >> 1], src, sizeof(uint16) * (x_ents + 1));
-}
-
-void Palette_LoadForFileSelect() {  // 9bef96
-  uint8 *src = g_zenv.sram;
-  for (int i = 0; i < 3; i++) {
-    Palette_LoadForFileSelect_Armor(i * 0x20, src[kSrmOffs_Armor], src[kSrmOffs_Gloves]);
-    Palette_LoadForFileSelect_Sword(i * 0x20, src[kSrmOffs_Sword]);
-    Palette_LoadForFileSelect_Shield(i * 0x20, src[kSrmOffs_Shield]);
-    src += 0x500;
-  }
-  for (int i = 0; i < 7; i++) {
-    aux_palette_buffer[0xe8 + i] = main_palette_buffer[0xe8 + i] = kPalette_MainSpr[7 + i];
-    aux_palette_buffer[0xf8 + i] = main_palette_buffer[0xf8 + i] = kPalette_MainSpr[15 + 7 + i];
-  }
-}
-
-void Palette_LoadForFileSelect_Armor(int k, uint8 armor, uint8 gloves) {  // 9bf032
-  const uint16 *pal = kPalette_ArmorAndGloves + armor * 15;
-  for (int i = 0; i != 15; i++)
-    aux_palette_buffer[k + 0x81 + i] = main_palette_buffer[k + 0x81 + i] = pal[i];
-  if (gloves)
-    aux_palette_buffer[k + 0x8d] = main_palette_buffer[k + 0x8d] = kGlovesColor[gloves - 1];
-}
-
-void Palette_LoadForFileSelect_Sword(int k, uint8 sword) {  // 9bf072
-  const uint16 *src = kPalette_Sword + (sword ? sword - 1 : 0) * 3;
-  for (int i = 0; i != 3; i++)
-    aux_palette_buffer[k + 0x99 + i] = main_palette_buffer[k + 0x99 + i] = src[i];
-}
-
-void Palette_LoadForFileSelect_Shield(int k, uint8 shield) {  // 9bf09a
-  const uint16 *src = kPalette_Shield + (shield ? shield - 1 : 0) * 4;
-  for (int i = 0; i != 4; i++)
-    aux_palette_buffer[k + 0x9c + i] = main_palette_buffer[k + 0x9c + i] = src[i];
-}
-
-void Palette_LoadAgahnim() {  // 9bf0c2
-  const uint16 *src = kPalette_SpriteAux1 + 14 * 7;
-  Palette_LoadMultiple_Arbitrary(src, 0x162, 6);
-  Palette_LoadMultiple_Arbitrary(src, 0x182, 6);
-  Palette_LoadMultiple_Arbitrary(src, 0x1a2, 6);
-  src = kPalette_SpriteAux1 + 21 * 7;
-  Palette_LoadMultiple_Arbitrary(src, 0x1c2, 6);
-  flag_update_cgram_in_nmi++;
-}
-
-void HandleScreenFlash() {  // 9de9b6
-  int j = intro_times_pal_flash;
-  if (!j || submodule_index != 0)
-    return;
-  if (!--intro_times_pal_flash) {
-    Palette_Restore_BG_And_HUD();
-    return;
-  }
-
-  if (j & 1)
-    Filter_Majorly_Whiten_Bg();
-  else
-    Palette_Restore_BG_From_Flash();
-
-  flag_update_cgram_in_nmi++;
-}
-
--- a/load_gfx.h
+++ /dev/null
@@ -1,164 +1,0 @@
-#ifndef ZELDA3_LOAD_GFX_H_
-#define ZELDA3_LOAD_GFX_H_
-
-enum {
-  kSrmOffs_Gloves = 0x354,
-  kSrmOffs_Sword = 0x359,
-  kSrmOffs_Shield = 0x35a,
-  kSrmOffs_Armor = 0x35b,
-  kSrmOffs_DiedCounter = 0x405,
-  kSrmOffs_Name = 0x3d9,
-  kSrmOffs_Health = 0x36c,
-};
-
-extern uint16 kGlovesColor[2];
-
-void ApplyPaletteFilter_bounce();
-void PaletteFilter_Range(int from, int to);
-void PaletteFilter_IncrCountdown();
-uint8 *LoadItemAnimationGfxOne(uint8 *dst, int num, int r12, bool from_temp);
-uint16 snes_divide(uint16 dividend, uint8 divisor);
-void EraseTileMaps_normal();
-void RecoverPegGFXFromMapping();
-void LoadOverworldMapPalette();
-void EraseTileMaps_triforce();
-void EraseTileMaps_dungeonmap();
-void EraseTileMaps(uint16 r2, uint16 r0);
-void EnableForceBlank();
-void LoadItemGFXIntoWRAM4BPPBuffer();
-void DecompressSwordGraphics();
-void DecompressShieldGraphics();
-void DecompressAnimatedDungeonTiles(uint8 a);
-void DecompressAnimatedOverworldTiles(uint8 a);
-void LoadItemGFX_Auxiliary();
-void LoadFollowerGraphics();
-void WriteTo4BPPBuffer_at_7F4000(uint8 a);
-void DecodeAnimatedSpriteTile_variable(uint8 a);
-void Expand3To4High(uint8 *dst, const uint8 *src, const uint8 *base, int num);
-void LoadTransAuxGFX();
-void LoadTransAuxGFX_sprite();
-void Gfx_LoadSpritesInner(uint8 *dst);
-void ReloadPreviouslyLoadedSheets();
-void Attract_DecompressStoryGFX();
-void AnimateMirrorWarp();
-void AnimateMirrorWarp_DecompressNewTileSets();
-void Graphics_IncrementalVRAMUpload();
-void PrepTransAuxGfx();
-void Do3To4High16Bit(uint8 *dst, const uint8 *src, int num);
-void Do3To4Low16Bit(uint8 *dst, const uint8 *src, int num);
-void LoadNewSpriteGFXSet();
-void InitializeTilesets();
-void LoadDefaultGraphics();
-void Attract_LoadBG3GFX();
-void Graphics_LoadChrHalfSlot();
-void TransferFontToVRAM();
-void Do3To4High(uint16 *vram_ptr, const uint8 *decomp_addr);
-void Do3To4Low(uint16 *vram_ptr, const uint8 *decomp_addr);
-void LoadSpriteGraphics(uint16 *vram_ptr, int gfx_pack, uint8 *decomp_addr);
-void LoadBackgroundGraphics(uint16 *vram_ptr, int gfx_pack, int slot, uint8 *decomp_addr);
-void LoadCommonSprites();
-int Decomp_spr(uint8 *dst, int gfx);
-int Decomp_bg(uint8 *dst, int gfx);
-int Decompress(uint8 *dst, const uint8 *src);
-void ResetHUDPalettes4and5();
-void PaletteFilterHistory();
-void PaletteFilter_WishPonds();
-void PaletteFilter_Crystal();
-void PaletteFilter_WishPonds_Inner();
-void PaletteFilter_RestoreSP5F();
-void PaletteFilter_SP5F();
-void KholdstareShell_PaletteFiltering();
-void AgahnimWarpShadowFilter(int k);
-void Palette_FadeIntroOneStep();
-void Palette_FadeIntro2();
-void PaletteFilter_RestoreAdditive(int from, int to);
-void PaletteFilter_RestoreSubtractive(uint16 from, uint16 to);
-void PaletteFilter_InitializeWhiteFilter();
-void MirrorWarp_RunAnimationSubmodules();
-void PaletteFilter_BlindingWhite();
-void PaletteFilter_StartBlindingWhite();
-void PaletteFilter_BlindingWhiteTriforce();
-void PaletteFilter_WhirlpoolBlue();
-void PaletteFilter_IsolateWhirlpoolBlue();
-void PaletteFilter_WhirlpoolRestoreBlue();
-void PaletteFilter_WhirlpoolRestoreRedGreen();
-void PaletteFilter_RestoreBGSubstractiveStrict();
-void PaletteFilter_RestoreBGAdditiveStrict();
-void Trinexx_FlashShellPalette_Red();
-void Trinexx_UnflashShellPalette_Red();
-void Trinexx_FlashShellPalette_Blue();
-void Trinexx_UnflashShellPalette_Blue();
-void IrisSpotlight_close();
-void Spotlight_open();
-void SpotlightInternal(uint8 x, uint8 y);
-void IrisSpotlight_ConfigureTable();
-void IrisSpotlight_ResetTable();
-uint16 IrisSpotlight_CalculateCircleValue(uint8 a);
-void AdjustWaterHDMAWindow();
-void AdjustWaterHDMAWindow_X(uint16 r10);
-void FloodDam_PrepFloodHDMA();
-void ResetStarTileGraphics();
-void Dungeon_RestoreStarTileChr();
-void LinkZap_HandleMosaic();
-void Player_SetCustomMosaicLevel(uint8 a);
-void Module07_16_UpdatePegs_Step1();
-void Module07_16_UpdatePegs_Step2();
-void Dungeon_UpdatePegGFXBuffer(int x, int y);
-void Dungeon_HandleTranslucencyAndPalette();
-void Overworld_LoadAllPalettes();
-void Dungeon_LoadPalettes();
-void Overworld_LoadPalettesInner();
-void OverworldLoadScreensPaletteSet();
-void Overworld_LoadAreaPalettesEx(uint8 x);
-void SpecialOverworld_CopyPalettesToCache();
-void Overworld_CopyPalettesToCache();
-void Overworld_LoadPalettes(uint8 bg, uint8 spr);
-void Palette_BgAndFixedColor_Black();
-void Palette_SetBgAndFixedColor(uint16 color);
-void SetBackdropcolorBlack();
-void Palette_SetOwBgColor();
-void Palette_SpecialOw();
-uint16 Palette_GetOwBgColor();
-void Palette_AssertTranslucencySwap();
-void Palette_SetTranslucencySwap(bool v);
-void Palette_RevertTranslucencySwap();
-void LoadActualGearPalettes();
-void Palette_ElectroThemedGear();
-void LoadGearPalettes_bunny();
-void LoadGearPalettes(uint8 sword, uint8 shield, uint8 armor);
-void LoadGearPalette(int dst, const uint16 *src, int n);
-void Filter_Majorly_Whiten_Bg();
-uint16 Filter_Majorly_Whiten_Color(uint16 c);
-void Palette_Restore_BG_From_Flash();
-void Palette_Restore_Coldata();
-void Palette_Restore_BG_And_HUD();
-void Palette_Load_Sp0L();
-void Palette_Load_SpriteMain();
-void Palette_Load_Sp5L();
-void Palette_Load_Sp6L();
-void Palette_Load_Sword();
-void Palette_Load_Shield();
-void Palette_Load_SpriteEnvironment();
-void Palette_Load_SpriteEnvironment_Dungeon();
-void Palette_MiscSprite_Outdoors();
-void Palette_Load_DungeonMapSprite();
-void Palette_Load_LinkArmorAndGloves();
-void Palette_UpdateGlovesColor();
-void Palette_Load_DungeonMapBG();
-void Palette_Load_HUD();
-void Palette_Load_DungeonSet();
-void Palette_Load_OWBG3();
-void Palette_Load_OWBGMain();
-void Palette_Load_OWBG1();
-void Palette_Load_OWBG2();
-void Palette_LoadSingle(const uint16 *src, int dst, int x_ents);
-void Palette_LoadMultiple(const uint16 *src, int dst, int x_ents, int y_pals);
-void Palette_LoadMultiple_Arbitrary(const uint16 *src, int dst, int x_ents);
-void Palette_LoadForFileSelect();
-void Palette_LoadForFileSelect_Armor(int k, uint8 armor, uint8 gloves);
-void Palette_LoadForFileSelect_Sword(int k, uint8 sword);
-void Palette_LoadForFileSelect_Shield(int k, uint8 shield);
-void Palette_LoadAgahnim();
-void HandleScreenFlash();
-
-#endif // ZELDA3_LOAD_GFX_H_
--- a/main.c
+++ /dev/null
@@ -1,872 +1,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdint.h>
-#include <stdbool.h>
-#include <SDL.h>
-#ifdef _WIN32
-#include "platform/win32/volume_control.h"
-#include <direct.h>
-#else
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-#endif
-
-#include "snes/ppu.h"
-
-#include "types.h"
-#include "variables.h"
-
-#include "zelda_rtl.h"
-#include "zelda_cpu_infra.h"
-
-#include "config.h"
-#include "assets.h"
-#include "load_gfx.h"
-#include "util.h"
-#include "audio.h"
-
-static bool g_run_without_emu = 0;
-
-// Forwards
-static bool LoadRom(const char *filename);
-static void LoadLinkGraphics();
-static void RenderNumber(uint8 *dst, size_t pitch, int n, bool big);
-static void HandleInput(int keyCode, int modCode, bool pressed);
-static void HandleCommand(uint32 j, bool pressed);
-static int RemapSdlButton(int button);
-static void HandleGamepadInput(int button, bool pressed);
-static void HandleGamepadAxisInput(int gamepad_id, int axis, int value);
-static void OpenOneGamepad(int i);
-static void HandleVolumeAdjustment(int volume_adjustment);
-static void LoadAssets();
-static void SwitchDirectory();
-
-enum {
-  kDefaultFullscreen = 0,
-  kMaxWindowScale = 10,
-  kDefaultFreq = 44100,
-  kDefaultChannels = 2,
-  kDefaultSamples = 2048,
-};
-
-static const char kWindowTitle[] = "The Legend of Zelda: A Link to the Past";
-static uint32 g_win_flags = SDL_WINDOW_RESIZABLE;
-static SDL_Window *g_window;
-
-static uint8 g_paused, g_turbo, g_replay_turbo = true, g_cursor = true;
-static uint8 g_current_window_scale;
-static uint8 g_gamepad_buttons;
-static int g_input1_state;
-static bool g_display_perf;
-static int g_curr_fps;
-static int g_ppu_render_flags = 0;
-static int g_snes_width, g_snes_height;
-static int g_sdl_audio_mixer_volume = SDL_MIX_MAXVOLUME;
-static struct RendererFuncs g_renderer_funcs;
-static uint32 g_gamepad_modifiers;
-static uint16 g_gamepad_last_cmd[kGamepadBtn_Count];
-
-void NORETURN Die(const char *error) {
-#if defined(NDEBUG) && defined(_WIN32)
-  SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, kWindowTitle, error, NULL);
-#endif
-  fprintf(stderr, "Error: %s\n", error);
-  exit(1);
-}
-
-void ChangeWindowScale(int scale_step) {
-  if ((SDL_GetWindowFlags(g_window) & (SDL_WINDOW_FULLSCREEN_DESKTOP | SDL_WINDOW_FULLSCREEN | SDL_WINDOW_MINIMIZED | SDL_WINDOW_MAXIMIZED)) != 0)
-    return;
-  int screen = SDL_GetWindowDisplayIndex(g_window);
-  if (screen < 0) screen = 0;
-  int max_scale = kMaxWindowScale;
-  SDL_Rect bounds;
-  int bt = -1, bl, bb, br;
-  // note this takes into effect Windows display scaling, i.e., resolution is divided by scale factor
-  if (SDL_GetDisplayUsableBounds(screen, &bounds) == 0) {
-    // this call may take a while before it is reported by Windows (or not at all in my testing)
-    if (SDL_GetWindowBordersSize(g_window, &bt, &bl, &bb, &br) != 0) {
-      // guess based on Windows 10/11 defaults
-      bl = br = bb = 1;
-      bt = 31;
-    }
-    // Allow a scale level slightly above the max that fits on screen
-    int mw = (bounds.w - bl - br + g_snes_width / 4) / g_snes_width;
-    int mh = (bounds.h - bt - bb + g_snes_height / 4) / g_snes_height;
-    max_scale = IntMin(mw, mh);
-  }
-  int new_scale = IntMax(IntMin(g_current_window_scale + scale_step, max_scale), 1);
-  g_current_window_scale = new_scale;
-  int w = new_scale * g_snes_width;
-  int h = new_scale * g_snes_height;
-
-  //SDL_RenderSetLogicalSize(g_renderer, w, h);
-  SDL_SetWindowSize(g_window, w, h);
-  if (bt >= 0) {
-    // Center the window on top of the mouse
-    int mx, my;
-    SDL_GetGlobalMouseState(&mx, &my);
-    int wx = IntMax(IntMin(mx - w / 2, bounds.x + bounds.w - bl - br - w), bounds.x + bl);
-    int wy = IntMax(IntMin(my - h / 2, bounds.y + bounds.h - bt - bb - h), bounds.y + bt);
-    SDL_SetWindowPosition(g_window, wx, wy);
-  } else {
-    SDL_SetWindowPosition(g_window, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED);
-  }
-}
-
-#define RESIZE_BORDER 20
-static SDL_HitTestResult HitTestCallback(SDL_Window *win, const SDL_Point *pt, void *data) {
-  uint32 flags = SDL_GetWindowFlags(win);
-  if ((flags & SDL_WINDOW_FULLSCREEN_DESKTOP) != 0 || (flags & SDL_WINDOW_FULLSCREEN) != 0)
-    return SDL_HITTEST_NORMAL;
-
-  if ((SDL_GetModState() & KMOD_CTRL) != 0)
-    return SDL_HITTEST_DRAGGABLE;
-
-  int w, h;
-  SDL_GetWindowSize(win, &w, &h);
-
-  if (pt->y < RESIZE_BORDER) {
-    return (pt->x < RESIZE_BORDER) ? SDL_HITTEST_RESIZE_TOPLEFT :
-           (pt->x >= w - RESIZE_BORDER) ? SDL_HITTEST_RESIZE_TOPRIGHT : SDL_HITTEST_RESIZE_TOP;
-  } else if (pt->y >= h - RESIZE_BORDER) {
-    return (pt->x < RESIZE_BORDER) ? SDL_HITTEST_RESIZE_BOTTOMLEFT :
-           (pt->x >= w - RESIZE_BORDER) ? SDL_HITTEST_RESIZE_BOTTOMRIGHT : SDL_HITTEST_RESIZE_BOTTOM;
-  } else {
-    if (pt->x < RESIZE_BORDER) {
-      return SDL_HITTEST_RESIZE_LEFT;
-    } else if (pt->x >= w - RESIZE_BORDER) {
-      return SDL_HITTEST_RESIZE_RIGHT;
-    }
-  }
-  return SDL_HITTEST_NORMAL;
-}
-
-static void DrawPpuFrameWithPerf() {
-  int render_scale = PpuGetCurrentRenderScale(g_zenv.ppu, g_ppu_render_flags);
-  uint8 *pixel_buffer = 0;
-  int pitch = 0;
-
-  g_renderer_funcs.BeginDraw(g_snes_width * render_scale,
-                             g_snes_height * render_scale,
-                             &pixel_buffer, &pitch);
-  if (g_display_perf || g_config.display_perf_title) {
-    static float history[64], average;
-    static int history_pos;
-    uint64 before = SDL_GetPerformanceCounter();
-    ZeldaDrawPpuFrame(pixel_buffer, pitch, g_ppu_render_flags);
-    uint64 after = SDL_GetPerformanceCounter();
-    float v = (double)SDL_GetPerformanceFrequency() / (after - before);
-    average += v - history[history_pos];
-    history[history_pos] = v;
-    history_pos = (history_pos + 1) & 63;
-    g_curr_fps = average * (1.0f / 64);
-  } else {
-    ZeldaDrawPpuFrame(pixel_buffer, pitch, g_ppu_render_flags);
-  }
-  if (g_display_perf)
-    RenderNumber(pixel_buffer + pitch * render_scale, pitch, g_curr_fps, render_scale == 4);
-  g_renderer_funcs.EndDraw();
-}
-
-static SDL_mutex *g_audio_mutex;
-static uint8 *g_audiobuffer, *g_audiobuffer_cur, *g_audiobuffer_end;
-static int g_frames_per_block;
-static uint8 g_audio_channels;
-
-static void SDLCALL AudioCallback(void *userdata, Uint8 *stream, int len) {
-  if (SDL_LockMutex(g_audio_mutex)) Die("Mutex lock failed!");
-  while (len != 0) {
-    if (g_audiobuffer_end - g_audiobuffer_cur == 0) {
-      ZeldaRenderAudio((int16*)g_audiobuffer, g_frames_per_block, g_audio_channels);
-      g_audiobuffer_cur = g_audiobuffer;
-      g_audiobuffer_end = g_audiobuffer + g_frames_per_block * g_audio_channels * sizeof(int16);
-    }
-    int n = IntMin(len, g_audiobuffer_end - g_audiobuffer_cur);
-    if (g_sdl_audio_mixer_volume == SDL_MIX_MAXVOLUME) {
-      memcpy(stream, g_audiobuffer_cur, n);
-    } else {
-      SDL_memset(stream, 0, n);
-      SDL_MixAudioFormat(stream, g_audiobuffer_cur, AUDIO_S16, n, g_sdl_audio_mixer_volume);
-    }
-    g_audiobuffer_cur += n;
-    stream += n;
-    len -= n;
-  }
-
-  ZeldaDiscardUnusedAudioFrames();
-  SDL_UnlockMutex(g_audio_mutex);
-}
-
-// State for sdl renderer
-static SDL_Renderer *g_renderer;
-static SDL_Texture *g_texture;
-static SDL_Rect g_sdl_renderer_rect;
-
-static bool SdlRenderer_Init(SDL_Window *window) {
-
-  if (g_config.shader)
-    fprintf(stderr, "Warning: Shaders are supported only with the OpenGL backend\n");
-
-  SDL_Renderer *renderer = SDL_CreateRenderer(g_window, -1,
-                                              g_config.output_method == kOutputMethod_SDLSoftware ? SDL_RENDERER_SOFTWARE :
-                                              SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
-  if (renderer == NULL) {
-    printf("Failed to create renderer: %s\n", SDL_GetError());
-    return false;
-  }
-  SDL_RendererInfo renderer_info;
-  SDL_GetRendererInfo(renderer, &renderer_info);
-  if (kDebugFlag) {
-    printf("Supported texture formats:");
-    for (int i = 0; i < renderer_info.num_texture_formats; i++)
-      printf(" %s", SDL_GetPixelFormatName(renderer_info.texture_formats[i]));
-    printf("\n");
-  }
-  g_renderer = renderer;
-  if (!g_config.ignore_aspect_ratio)
-    SDL_RenderSetLogicalSize(renderer, g_snes_width, g_snes_height);
-  if (g_config.linear_filtering)
-    SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "best");
-
-  int tex_mult = (g_ppu_render_flags & kPpuRenderFlags_4x4Mode7) ? 4 : 1;
-  g_texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING,
-                                g_snes_width * tex_mult, g_snes_height * tex_mult);
-  if (g_texture == NULL) {
-    printf("Failed to create texture: %s\n", SDL_GetError());
-    return false;
-  }
-  return true;
-}
-
-static void SdlRenderer_Destroy() {
-  SDL_DestroyTexture(g_texture);
-  SDL_DestroyRenderer(g_renderer);
-}
-
-static void SdlRenderer_BeginDraw(int width, int height, uint8 **pixels, int *pitch) {
-  g_sdl_renderer_rect.w = width;
-  g_sdl_renderer_rect.h = height;
-  if (SDL_LockTexture(g_texture, &g_sdl_renderer_rect, (void **)pixels, pitch) != 0) {
-    printf("Failed to lock texture: %s\n", SDL_GetError());
-    return;
-  }
-}
-
-static void SdlRenderer_EndDraw() {
-
-//  uint64 before = SDL_GetPerformanceCounter();
-  SDL_UnlockTexture(g_texture);
-//  uint64 after = SDL_GetPerformanceCounter();
-//  float v = (double)(after - before) / SDL_GetPerformanceFrequency();
-//  printf("%f ms\n", v * 1000);
-  SDL_RenderClear(g_renderer);
-  SDL_RenderCopy(g_renderer, g_texture, &g_sdl_renderer_rect, NULL);
-  SDL_RenderPresent(g_renderer); // vsyncs to 60 FPS?
-}
-
-static const struct RendererFuncs kSdlRendererFuncs  = {
-  &SdlRenderer_Init,
-  &SdlRenderer_Destroy,
-  &SdlRenderer_BeginDraw,
-  &SdlRenderer_EndDraw,
-};
-
-void OpenGLRenderer_Create(struct RendererFuncs *funcs, bool use_opengl_es);
-
-#undef main
-int main(int argc, char** argv) {
-  argc--, argv++;
-  const char *config_file = NULL;
-  if (argc >= 2 && strcmp(argv[0], "--config") == 0) {
-    config_file = argv[1];
-    argc -= 2, argv += 2;
-  } else {
-    SwitchDirectory();
-  }
-  ParseConfigFile(config_file);
-  LoadAssets();
-  LoadLinkGraphics();
-
-  ZeldaInitialize();
-  g_zenv.ppu->extraLeftRight = UintMin(g_config.extended_aspect_ratio, kPpuExtraLeftRight);
-  g_snes_width = (g_config.extended_aspect_ratio * 2 + 256);
-  g_snes_height = (g_config.extend_y ? 240 : 224);
-
-
-  // Delay actually setting those features in ram until any snapshots finish playing.
-  g_wanted_zelda_features = g_config.features0;
-
-  g_ppu_render_flags = g_config.new_renderer * kPpuRenderFlags_NewRenderer |
-                       g_config.enhanced_mode7 * kPpuRenderFlags_4x4Mode7 |
-                       g_config.extend_y * kPpuRenderFlags_Height240 |
-                       g_config.no_sprite_limits * kPpuRenderFlags_NoSpriteLimits;
-  ZeldaEnableMsu(g_config.enable_msu);
-  ZeldaSetLanguage(g_config.language);
-
-  if (g_config.fullscreen == 1)
-    g_win_flags ^= SDL_WINDOW_FULLSCREEN_DESKTOP;
-  else if (g_config.fullscreen == 2)
-    g_win_flags ^= SDL_WINDOW_FULLSCREEN;
-
-  // Window scale (1=100%, 2=200%, 3=300%, etc.)
-  g_current_window_scale = (g_config.window_scale == 0) ? 2 : IntMin(g_config.window_scale, kMaxWindowScale);
-
-  // audio_freq: Use common sampling rates (see user config file. values higher than 48000 are not supported.)
-  if (g_config.audio_freq < 11025 || g_config.audio_freq > 48000)
-    g_config.audio_freq = kDefaultFreq;
-
-  // Currently, the SPC/DSP implementation only supports up to stereo.
-  if (g_config.audio_channels < 1 || g_config.audio_channels > 2)
-    g_config.audio_channels = kDefaultChannels;
-
-  // audio_samples: power of 2
-  if (g_config.audio_samples <= 0 || ((g_config.audio_samples & (g_config.audio_samples - 1)) != 0))
-    g_config.audio_samples = kDefaultSamples;
-
-  // set up SDL
-  if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_GAMECONTROLLER) != 0) {
-    printf("Failed to init SDL: %s\n", SDL_GetError());
-    return 1;
-  }
-
-  bool custom_size  = g_config.window_width != 0 && g_config.window_height != 0;
-  int window_width  = custom_size ? g_config.window_width  : g_current_window_scale * g_snes_width;
-  int window_height = custom_size ? g_config.window_height : g_current_window_scale * g_snes_height;
-
-  if (g_config.output_method == kOutputMethod_OpenGL ||
-      g_config.output_method == kOutputMethod_OpenGL_ES) {
-    g_win_flags |= SDL_WINDOW_OPENGL;
-    OpenGLRenderer_Create(&g_renderer_funcs, (g_config.output_method == kOutputMethod_OpenGL_ES));
-  } else {
-    g_renderer_funcs = kSdlRendererFuncs;
-  }
-
-  SDL_Window* window = SDL_CreateWindow(kWindowTitle, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, window_width, window_height, g_win_flags);
-  if(window == NULL) {
-    printf("Failed to create window: %s\n", SDL_GetError());
-    return 1;
-  }
-  g_window = window;
-  SDL_SetWindowHitTest(window, HitTestCallback, NULL);
-
-  if (!g_renderer_funcs.Initialize(window))
-    return 1;
-
-  SDL_AudioDeviceID device = 0;
-  SDL_AudioSpec want = { 0 }, have;
-  g_audio_mutex = SDL_CreateMutex();
-  if (!g_audio_mutex) Die("No mutex");
-
-  if (g_config.enable_audio) {
-    want.freq = g_config.audio_freq;
-    want.format = AUDIO_S16;
-    want.channels = g_config.audio_channels;
-    want.samples = g_config.audio_samples;
-    want.callback = &AudioCallback;
-    device = SDL_OpenAudioDevice(NULL, 0, &want, &have, 0);
-    if (device == 0) {
-      printf("Failed to open audio device: %s\n", SDL_GetError());
-      return 1;
-    }
-    g_audio_channels = have.channels;
-    g_frames_per_block = (534 * have.freq) / 32000;
-    g_audiobuffer = malloc(g_frames_per_block * have.channels * sizeof(int16));
-  }
-
-  if (argc >= 1 && !g_run_without_emu)
-    LoadRom(argv[0]);
-
-#if defined(_WIN32)
-  _mkdir("saves");
-#else
-  mkdir("saves", 0755);
-#endif
-
-  ZeldaReadSram();
-
-  for (int i = 0; i < SDL_NumJoysticks(); i++)
-    OpenOneGamepad(i);
-
-  bool running = true;
-  SDL_Event event;
-  uint32 lastTick = SDL_GetTicks();
-  uint32 curTick = 0;
-  uint32 frameCtr = 0;
-  bool audiopaused = true;
-
-  if (g_config.autosave)
-    HandleCommand(kKeys_Load + 0, true);
-
-  while(running) {
-    while(SDL_PollEvent(&event)) {
-      switch(event.type) {
-      case SDL_CONTROLLERDEVICEADDED:
-        OpenOneGamepad(event.cdevice.which);
-        break;
-      case SDL_CONTROLLERAXISMOTION:
-        HandleGamepadAxisInput(event.caxis.which, event.caxis.axis, event.caxis.value);
-        break;
-      case SDL_CONTROLLERBUTTONDOWN:
-      case SDL_CONTROLLERBUTTONUP: {
-        int b = RemapSdlButton(event.cbutton.button);
-        if (b >= 0)
-          HandleGamepadInput(b, event.type == SDL_CONTROLLERBUTTONDOWN);
-        break;
-      }
-      case SDL_MOUSEWHEEL:
-        if (SDL_GetModState() & KMOD_CTRL && event.wheel.y != 0)
-          ChangeWindowScale(event.wheel.y > 0 ? 1 : -1);
-        break;
-      case SDL_MOUSEBUTTONDOWN:
-        if (event.button.button == SDL_BUTTON_LEFT && event.button.state == SDL_PRESSED && event.button.clicks == 2) {
-          if ((g_win_flags & SDL_WINDOW_FULLSCREEN_DESKTOP) == 0 && (g_win_flags & SDL_WINDOW_FULLSCREEN) == 0 && SDL_GetModState() & KMOD_SHIFT) {
-            g_win_flags ^= SDL_WINDOW_BORDERLESS;
-            SDL_SetWindowBordered(g_window, (g_win_flags & SDL_WINDOW_BORDERLESS) == 0);
-          }
-        }
-        break;
-      case SDL_KEYDOWN:
-        HandleInput(event.key.keysym.sym, event.key.keysym.mod, true);
-        break;
-      case SDL_KEYUP:
-        HandleInput(event.key.keysym.sym, event.key.keysym.mod, false);
-        break;
-      case SDL_QUIT:
-        running = false;
-        break;
-      }
-    }
-
-    if (g_paused != audiopaused) {
-      audiopaused = g_paused;
-      if (device)
-        SDL_PauseAudioDevice(device, audiopaused);
-    }
-
-    if (g_paused) {
-      SDL_Delay(16);
-      continue;
-    }
-
-    // Clear gamepad inputs when joypad directional inputs to avoid wonkiness
-    int inputs = g_input1_state;
-    if (g_input1_state & 0xf0)
-      g_gamepad_buttons = 0;
-    inputs |= g_gamepad_buttons;
-
-    SDL_LockMutex(g_audio_mutex);
-    bool is_replay = ZeldaRunFrame(inputs);
-    SDL_UnlockMutex(g_audio_mutex);
-
-    frameCtr++;
-
-    if ((g_turbo ^ (is_replay & g_replay_turbo)) && (frameCtr & (g_turbo ? 0xf : 0x7f)) != 0) {
-      continue;
-    }
-
-    DrawPpuFrameWithPerf();
-
-    if (g_config.display_perf_title) {
-      char title[60];
-      snprintf(title, sizeof(title), "%s | FPS: %d", kWindowTitle, g_curr_fps);
-      SDL_SetWindowTitle(g_window, title);
-    }
-
-    // if vsync isn't working, delay manually
-    curTick = SDL_GetTicks();
-
-    if (!g_config.disable_frame_delay) {
-      static const uint8 delays[3] = { 17, 17, 16 }; // 60 fps
-      lastTick += delays[frameCtr % 3];
-
-      if (lastTick > curTick) {
-        uint32 delta = lastTick - curTick;
-        if (delta > 500) {
-          lastTick = curTick - 500;
-          delta = 500;
-        }
-//        printf("Sleeping %d\n", delta);
-        SDL_Delay(delta);
-      } else if (curTick - lastTick > 500) {
-        lastTick = curTick;
-      }
-    }
-  }
-  if (g_config.autosave)
-    HandleCommand(kKeys_Save + 0, true);
-
-  // clean sdl
-  if (g_config.enable_audio) {
-    SDL_PauseAudioDevice(device, 1);
-    SDL_CloseAudioDevice(device);
-  }
-
-  SDL_DestroyMutex(g_audio_mutex);
-  free(g_audiobuffer);
-
-  g_renderer_funcs.Destroy();
-
-  SDL_DestroyWindow(window);
-  SDL_Quit();
-  //SaveConfigFile();
-  return 0;
-}
-
-static void RenderDigit(uint8 *dst, size_t pitch, int digit, uint32 color, bool big) {
-  static const uint8 kFont[] = {
-    0x1c, 0x36, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x36, 0x1c,
-    0x18, 0x1c, 0x1e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7e,
-    0x3e, 0x63, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x03, 0x63, 0x7f,
-    0x3e, 0x63, 0x60, 0x60, 0x3c, 0x60, 0x60, 0x60, 0x63, 0x3e,
-    0x30, 0x38, 0x3c, 0x36, 0x33, 0x7f, 0x30, 0x30, 0x30, 0x78,
-    0x7f, 0x03, 0x03, 0x03, 0x3f, 0x60, 0x60, 0x60, 0x63, 0x3e,
-    0x1c, 0x06, 0x03, 0x03, 0x3f, 0x63, 0x63, 0x63, 0x63, 0x3e,
-    0x7f, 0x63, 0x60, 0x60, 0x30, 0x18, 0x0c, 0x0c, 0x0c, 0x0c,
-    0x3e, 0x63, 0x63, 0x63, 0x3e, 0x63, 0x63, 0x63, 0x63, 0x3e,
-    0x3e, 0x63, 0x63, 0x63, 0x7e, 0x60, 0x60, 0x60, 0x30, 0x1e,
-  };
-  const uint8 *p = kFont + digit * 10;
-  if (!big) {
-    for (int y = 0; y < 10; y++, dst += pitch) {
-      int v = *p++;
-      for (int x = 0; v; x++, v >>= 1) {
-        if (v & 1)
-          ((uint32 *)dst)[x] = color;
-      }
-    }
-  } else {
-    for (int y = 0; y < 10; y++, dst += pitch * 2) {
-      int v = *p++;
-      for (int x = 0; v; x++, v >>= 1) {
-        if (v & 1) {
-          ((uint32 *)dst)[x * 2 + 1] = ((uint32 *)dst)[x * 2] = color;
-          ((uint32 *)(dst+pitch))[x * 2 + 1] = ((uint32 *)(dst + pitch))[x * 2] = color;
-        }
-      }
-    }
-  }
-}
-
-static void RenderNumber(uint8 *dst, size_t pitch, int n, bool big) {
-  char buf[32], *s;
-  int i;
-  sprintf(buf, "%d", n);
-  for (s = buf, i = 2 * 4; *s; s++, i += 8 * 4)
-    RenderDigit(dst + ((pitch + i + 4) << big), pitch, *s - '0', 0x404040, big);
-  for (s = buf, i = 2 * 4; *s; s++, i += 8 * 4)
-    RenderDigit(dst + (i << big), pitch, *s - '0', 0xffffff, big);
-}
-
-static void HandleCommand_Locked(uint32 j, bool pressed);
-
-static void HandleCommand(uint32 j, bool pressed) {
-  if (j <= kKeys_Controls_Last) {
-    static const uint8 kKbdRemap[] = { 0, 4, 5, 6, 7, 2, 3, 8, 0, 9, 1, 10, 11 };
-    if (pressed)
-      g_input1_state |= 1 << kKbdRemap[j];
-    else
-      g_input1_state &= ~(1 << kKbdRemap[j]);
-    return;
-  }
-
-  if (j == kKeys_Turbo) {
-    g_turbo = pressed;
-    return;
-  }
-
-  // Everything that might access audio state
-  // (like SaveLoad and Reset) must have the lock.
-  SDL_LockMutex(g_audio_mutex);
-  HandleCommand_Locked(j, pressed);
-  SDL_UnlockMutex(g_audio_mutex);
-}
-
-void ZeldaApuLock() {
-  SDL_LockMutex(g_audio_mutex);
-}
-
-void ZeldaApuUnlock() {
-  SDL_UnlockMutex(g_audio_mutex);
-}
-
-
-static void HandleCommand_Locked(uint32 j, bool pressed) {
-  if (!pressed)
-    return;
-  if (j <= kKeys_Load_Last) {
-    SaveLoadSlot(kSaveLoad_Load, j - kKeys_Load);
-  } else if (j <= kKeys_Save_Last) {
-    SaveLoadSlot(kSaveLoad_Save, j - kKeys_Save);
-  } else if (j <= kKeys_Replay_Last) {
-    SaveLoadSlot(kSaveLoad_Replay, j - kKeys_Replay);
-  } else if (j <= kKeys_LoadRef_Last) {
-    SaveLoadSlot(kSaveLoad_Load, 256 + j - kKeys_LoadRef);
-  } else if (j <= kKeys_ReplayRef_Last) {
-    SaveLoadSlot(kSaveLoad_Replay, 256 + j - kKeys_ReplayRef);
-  } else {
-    switch (j) {
-    case kKeys_CheatLife: PatchCommand('w'); break;
-    case kKeys_CheatEquipment: PatchCommand('W'); break;
-    case kKeys_CheatKeys: PatchCommand('o'); break;
-    case kKeys_CheatWalkThroughWalls: PatchCommand('E'); break;
-    case kKeys_ClearKeyLog: PatchCommand('k'); break;
-    case kKeys_StopReplay: PatchCommand('l'); break;
-    case kKeys_Fullscreen:
-      g_win_flags ^= SDL_WINDOW_FULLSCREEN_DESKTOP;
-      SDL_SetWindowFullscreen(g_window, g_win_flags & SDL_WINDOW_FULLSCREEN_DESKTOP);
-      g_cursor = !g_cursor;
-      SDL_ShowCursor(g_cursor);
-      break;
-    case kKeys_Reset:
-      ZeldaReset(true);
-      break;
-    case kKeys_Pause: g_paused = !g_paused; break;
-    case kKeys_PauseDimmed:
-      g_paused = !g_paused;
-      // SDL_RenderPresent may not be called more than once per frame.
-      // Seems to work on Windows still. Temporary measure until it's fixed.
-#ifdef _WIN32
-      if (g_paused) {
-        SDL_SetRenderDrawBlendMode(g_renderer, SDL_BLENDMODE_BLEND);
-        SDL_SetRenderDrawColor(g_renderer, 0, 0, 0, 159);
-        SDL_RenderFillRect(g_renderer, NULL);
-        SDL_RenderPresent(g_renderer);
-      }
-#endif
-      break;
-    case kKeys_ReplayTurbo: g_replay_turbo = !g_replay_turbo; break;
-    case kKeys_WindowBigger: ChangeWindowScale(1); break;
-    case kKeys_WindowSmaller: ChangeWindowScale(-1); break;
-    case kKeys_DisplayPerf: g_display_perf ^= 1; break;
-    case kKeys_ToggleRenderer: g_ppu_render_flags ^= kPpuRenderFlags_NewRenderer; break;
-    case kKeys_VolumeUp:
-    case kKeys_VolumeDown: HandleVolumeAdjustment(j == kKeys_VolumeUp ? 1 : -1); break;
-    default: assert(0);
-    }
-  }
-}
-
-static void HandleInput(int keyCode, int keyMod, bool pressed) {
-  int j = FindCmdForSdlKey(keyCode, keyMod);
-  if (j != 0)
-    HandleCommand(j, pressed);
-}
-
-static void OpenOneGamepad(int i) {
-  if (SDL_IsGameController(i)) {
-    SDL_GameController *controller = SDL_GameControllerOpen(i);
-    if (!controller)
-      fprintf(stderr, "Could not open gamepad %d: %s\n", i, SDL_GetError());
-  }
-}
-
-static int RemapSdlButton(int button) {
-  switch (button) {
-  case SDL_CONTROLLER_BUTTON_A: return kGamepadBtn_A;
-  case SDL_CONTROLLER_BUTTON_B: return kGamepadBtn_B;
-  case SDL_CONTROLLER_BUTTON_X: return kGamepadBtn_X;
-  case SDL_CONTROLLER_BUTTON_Y: return kGamepadBtn_Y;
-  case SDL_CONTROLLER_BUTTON_BACK: return kGamepadBtn_Back;
-  case SDL_CONTROLLER_BUTTON_GUIDE: return kGamepadBtn_Guide;
-  case SDL_CONTROLLER_BUTTON_START: return kGamepadBtn_Start;
-  case SDL_CONTROLLER_BUTTON_LEFTSTICK: return kGamepadBtn_L3;
-  case SDL_CONTROLLER_BUTTON_RIGHTSTICK: return kGamepadBtn_R3;
-  case SDL_CONTROLLER_BUTTON_LEFTSHOULDER: return kGamepadBtn_L1;
-  case SDL_CONTROLLER_BUTTON_RIGHTSHOULDER: return kGamepadBtn_R1;
-  case SDL_CONTROLLER_BUTTON_DPAD_UP: return kGamepadBtn_DpadUp;
-  case SDL_CONTROLLER_BUTTON_DPAD_DOWN: return kGamepadBtn_DpadDown;
-  case SDL_CONTROLLER_BUTTON_DPAD_LEFT: return kGamepadBtn_DpadLeft;
-  case SDL_CONTROLLER_BUTTON_DPAD_RIGHT: return kGamepadBtn_DpadRight;
-  default: return -1;
-  }
-}
-
-static void HandleGamepadInput(int button, bool pressed) {
-  if (!!(g_gamepad_modifiers & (1 << button)) == pressed)
-    return;
-  g_gamepad_modifiers ^= 1 << button;
-  if (pressed)
-    g_gamepad_last_cmd[button] = FindCmdForGamepadButton(button, g_gamepad_modifiers);
-  if (g_gamepad_last_cmd[button] != 0)
-    HandleCommand(g_gamepad_last_cmd[button], pressed);
-}
-
-static void HandleVolumeAdjustment(int volume_adjustment) {
-#if SYSTEM_VOLUME_MIXER_AVAILABLE
-  int current_volume = GetApplicationVolume();
-  int new_volume = IntMin(IntMax(0, current_volume + volume_adjustment * 5), 100);
-  SetApplicationVolume(new_volume);
-  printf("[System Volume]=%i\n", new_volume);
-#else
-  g_sdl_audio_mixer_volume = IntMin(IntMax(0, g_sdl_audio_mixer_volume + volume_adjustment * (SDL_MIX_MAXVOLUME >> 4)), SDL_MIX_MAXVOLUME);
-  printf("[SDL mixer volume]=%i\n", g_sdl_audio_mixer_volume);
-#endif
-}
-
-// Approximates atan2(y, x) normalized to the [0,4) range
-// with a maximum error of 0.1620 degrees
-// normalized_atan(x) ~ (b x + x^2) / (1 + 2 b x + x^2)
-static float ApproximateAtan2(float y, float x) {
-  uint32 sign_mask = 0x80000000;
-  float b = 0.596227f;
-  // Extract the sign bits
-  uint32 ux_s = sign_mask & *(uint32 *)&x;
-  uint32 uy_s = sign_mask & *(uint32 *)&y;
-  // Determine the quadrant offset
-  float q = (float)((~ux_s & uy_s) >> 29 | ux_s >> 30);
-  // Calculate the arctangent in the first quadrant
-  float bxy_a = b * x * y;
-  if (bxy_a < 0.0f) bxy_a = -bxy_a;  // avoid fabs
-  float num = bxy_a + y * y;
-  float atan_1q = num / (x * x + bxy_a + num + 0.000001f);
-  // Translate it to the proper quadrant
-  uint32_t uatan_2q = (ux_s ^ uy_s) | *(uint32 *)&atan_1q;
-  return q + *(float *)&uatan_2q;
-}
-
-static void HandleGamepadAxisInput(int gamepad_id, int axis, int value) {
-  static int last_gamepad_id, last_x, last_y;
-  if (axis == SDL_CONTROLLER_AXIS_LEFTX || axis == SDL_CONTROLLER_AXIS_LEFTY) {
-    // ignore other gamepads unless they have a big input
-    if (last_gamepad_id != gamepad_id) {
-      if (value > -16000 && value < 16000)
-        return;
-      last_gamepad_id = gamepad_id;
-      last_x = last_y = 0;
-    }
-    *(axis == SDL_CONTROLLER_AXIS_LEFTX ? &last_x : &last_y) = value;
-    int buttons = 0;
-    if (last_x * last_x + last_y * last_y >= 10000 * 10000) {
-      // in the non deadzone part, divide the circle into eight 45 degree
-      // segments rotated by 22.5 degrees that control which direction to move.
-      // todo: do this without floats?
-      static const uint8 kSegmentToButtons[8] = {
-        1 << 4,           // 0 = up
-        1 << 4 | 1 << 7,  // 1 = up, right
-        1 << 7,           // 2 = right
-        1 << 7 | 1 << 5,  // 3 = right, down
-        1 << 5,           // 4 = down
-        1 << 5 | 1 << 6,  // 5 = down, left
-        1 << 6,           // 6 = left
-        1 << 6 | 1 << 4,  // 7 = left, up
-      };
-      uint8 angle = (uint8)(int)(ApproximateAtan2(last_y, last_x) * 64.0f + 0.5f);
-      buttons = kSegmentToButtons[(uint8)(angle + 16 + 64) >> 5];
-    }
-    g_gamepad_buttons = buttons;
-  } else if ((axis == SDL_CONTROLLER_AXIS_TRIGGERLEFT || axis == SDL_CONTROLLER_AXIS_TRIGGERRIGHT)) {
-    if (value < 12000 || value >= 16000)  // hysteresis
-      HandleGamepadInput(axis == SDL_CONTROLLER_AXIS_TRIGGERLEFT ? kGamepadBtn_L2 : kGamepadBtn_R2, value >= 12000);
-  }
-}
-
-static bool LoadRom(const char *filename) {
-  size_t length = 0;
-  uint8 *file = ReadWholeFile(filename, &length);
-  if(!file) Die("Failed to read file");
-  bool result = EmuInitialize(file, length);
-  free(file);
-  return result;
-}
-
-static bool ParseLinkGraphics(uint8 *file, size_t length) {
-  if (length < 27 || memcmp(file, "ZSPR", 4) != 0)
-    return false;
-  uint32 pixel_offs = DWORD(file[9]);
-  uint32 pixel_length = WORD(file[13]);
-  uint32 palette_offs = DWORD(file[15]);
-  uint32 palette_length = WORD(file[19]);
-  if ((uint64)pixel_offs + pixel_length > length ||
-      (uint64)palette_offs + palette_length > length ||
-      pixel_length != 0x7000)
-    return false;
-  if (kPalette_ArmorAndGloves_SIZE != 150 || kLinkGraphics_SIZE != 0x7000)
-    Die("ParseLinkGraphics: Invalid asset sizes");
-  memcpy(kLinkGraphics, file + pixel_offs, 0x7000);
-  if (palette_length >= 120)
-    memcpy(kPalette_ArmorAndGloves, file + palette_offs, 120);
-  if (palette_length >= 124)
-    memcpy(kGlovesColor, file + palette_offs + 120, 4);
-  return true;
-}
-
-static void LoadLinkGraphics() {
-  if (g_config.link_graphics) {
-    fprintf(stderr, "Loading Link Graphics: %s\n", g_config.link_graphics);
-    size_t length = 0;
-    uint8 *file = ReadWholeFile(g_config.link_graphics, &length);
-    if (file == NULL || !ParseLinkGraphics(file, length))
-      Die("Unable to load file");
-    free(file);
-  }
-}
-
-
-const uint8 *g_asset_ptrs[kNumberOfAssets];
-uint32 g_asset_sizes[kNumberOfAssets];
-
-static void LoadAssets() {
-  size_t length = 0;
-  uint8 *data = ReadWholeFile("tables/zelda3_assets.dat", &length);
-  if (!data)
-    data = ReadWholeFile("zelda3_assets.dat", &length);
-  if (!data) Die("Failed to read zelda3_assets.dat. Please see the README for information about how you get this file.");
-
-  static const char kAssetsSig[] = { kAssets_Sig };
-
-  if (length < 16 + 32 + 32 + 8 + kNumberOfAssets * 4 ||
-      memcmp(data, kAssetsSig, 48) != 0 ||
-      *(uint32*)(data + 80) != kNumberOfAssets)
-    Die("Invalid assets file");
-
-  uint32 offset = 88 + kNumberOfAssets * 4 + *(uint32 *)(data + 84);
-
-  for (size_t i = 0; i < kNumberOfAssets; i++) {
-    uint32 size = *(uint32 *)(data + 88 + i * 4);
-    offset = (offset + 3) & ~3;
-    if ((uint64)offset + size > length)
-      Die("Assets file corruption");
-    g_asset_sizes[i] = size;
-    g_asset_ptrs[i] = data + offset;
-    offset += size;
-  }
-
-  if (g_config.features0 & kFeatures0_DimFlashes) { // patch dungeon floor palettes
-    kPalette_DungBgMain[0x484] = 0x70;
-    kPalette_DungBgMain[0x485] = 0x95;
-    kPalette_DungBgMain[0x486] = 0x57;
-  }
-}
-
-// Go some steps up and find zelda3.ini
-static void SwitchDirectory() {
-  char buf[4096];
-  if (!getcwd(buf, sizeof(buf) - 32))
-    return;
-  size_t pos = strlen(buf);
-
-  for (int step = 0; pos != 0 && step < 3; step++) {
-    memcpy(buf + pos, "/zelda3.ini", 12);
-    FILE *f = fopen(buf, "rb");
-    if (f) {
-      fclose(f);
-      buf[pos] = 0;
-      if (step != 0) {
-        printf("Found zelda3.ini in %s\n", buf);
-        int err = chdir(buf);
-        (void)err;
-      }
-      return;
-    }
-    pos--;
-    while (pos != 0 && buf[pos] != '/' && buf[pos] != '\\')
-      pos--;
-  }
-}
-
-MemBlk FindInAssetArray(int asset, int idx) {
-  return FindIndexInMemblk((MemBlk) { g_asset_ptrs[asset], g_asset_sizes[asset] }, idx);
-}
--- a/messaging.c
+++ /dev/null
@@ -1,2935 +1,0 @@
-#include "messaging.h"
-#include "zelda_rtl.h"
-#include "variables.h"
-#include "snes/snes_regs.h"
-#include "dungeon.h"
-#include "hud.h"
-#include "load_gfx.h"
-#include "dungeon.h"
-#include "overworld.h"
-#include "variables.h"
-#include "ancilla.h"
-#include "player.h"
-#include "misc.h"
-#include "sprite.h"
-#include "player_oam.h"
-#include "attract.h"
-#include "nmi.h"
-#include "assets.h"
-
-static void WorldMap_AddSprite(int spr, uint8 big, uint8 flags, uint8 ch, uint16 x, uint16 y);
-static bool WorldMap_CalculateOamCoordinates(Point16U *pt);
-
-static const int8 kDungMap_Tab0[14] = {-1, -1, -1, -1, -1, 2, 0, 10, 4, 8, -1, 6, 12, 14};
-static const uint16 kDungMap_Tab1[8] = {0x2108, 0x2109, 0x2109, 0x210a, 0x210b, 0x210c, 0x210d, 0x211d};
-static const uint16 kDungMap_Tab2[8] = {0x2118, 0x2119, 0xa109, 0x211a, 0x211b, 0x211c, 0x2118, 0xa11d};
-static const uint8 kDungMap_Tab3[14] = {0x60, 0x84, 0, 0xb, 0x32, 0x21, 0x33, 0x21, 0x38, 0x21, 0x3a, 0x21, 0x7f, 0x20};
-static const uint8 kDungMap_Tab4[14] = {0x60, 0xa4, 0, 0xb, 0x42, 0x21, 0x43, 0x21, 0x49, 0x21, 0x4a, 0x21, 0x7f, 0x20};
-static const uint16 kDungMap_Tab8[7] = {0x1b28, 0x1b29, 0x1b2a, 0x1b2b, 0x1b2c, 0x1b2d, 0x1b2e};
-static const uint16 kDungMap_Tab6[21] = {0xaa10, 0x100, 0x1b2f, 0xc910, 0x300, 0x1b2f, 0x1b2e, 0xe510, 0xb00, 0x1b2f, 0x1b2e, 0x5b2f, 0x1b2f, 0x1b2e, 0x1b2e, 0x311, 0x100, 0x1b2f, 0x411, 0xc40, 0x1b2e};
-static const uint16 kDungMap_Tab5[14] = {0x21, 0x23, 0x20, 0x21, 0x70, 0x12, 0x11, 0x212, 2, 0x217, 0x160, 0x12, 0x113, 0x171};
-static const uint16 kDungMap_Tab7[9] = {0x1223, 0x1263, 0x12a3, 0x12e3, 0x1323, 0x11e3, 0x11a3, 0x1163, 0x1123};
-static const uint16 kDungMap_Tab9[8] = {0xf26, 0xf27, 0x4f27, 0x4f26, 0x8f26, 0x8f27, 0xcf27, 0xcf26};
-static const uint16 kDungMap_Tab10[4] = {0xe2, 0xf8, 0x3a2, 0x3b8};
-static const uint16 kDungMap_Tab11[4] = {0x1f19, 0x5f19, 0x9f19, 0xdf19};
-static const uint16 kDungMap_Tab12[2] = {0xe4, 0x3a4};
-static const uint16 kDungMap_Tab13[2] = {0x1f1a, 0x9f1a};
-static const uint16 kDungMap_Tab14[2] = {0x122, 0x138};
-static const uint16 kDungMap_Tab15[2] = {0x1f1b, 0x5f1b};
-static const uint16 kDungMap_Tab16[8] = {0x1f1e, 0x1f1f, 0x1f20, 0x1f21, 0x1f22, 0x1f23, 0x1f24, 0x1f25};
-static const uint16 kDungMap_Tab23[744] = {
-  0xb61, 0x5361, 0x8b61, 0x8b62, 0xb60, 0xb63, 0x8b60, 0xb64, 0xb00, 0xb00, 0xb65, 0xb66, 0xb67, 0x4b67, 0x9367, 0xd367, 0xb60, 0x5360, 0x8b60, 0xcb60, 0xb6a, 0x4b6a, 0x4b6d, 0xb6d, 0x1368, 0x1369, 0xb00, 0xb00, 0xb6a, 0x136b, 0xb6c, 0xb6d,
-  0x136e, 0x4b6e, 0xb00, 0xb00, 0x136f, 0xb00, 0xb00, 0xb00, 0x1340, 0xb00, 0xb78, 0x1744, 0x536d, 0x136d, 0x4b76, 0xb76, 0xb70, 0xb71, 0xb72, 0x8b71, 0xb75, 0xb76, 0x8b75, 0x8b76, 0xb00, 0xb53, 0xb00, 0xb55, 0x1354, 0x5354, 0xb00, 0xb00,
-  0x4b53, 0xb00, 0xb56, 0xb57, 0xb00, 0xb59, 0xb00, 0x135e, 0x135a, 0x135b, 0x135f, 0x535f, 0xb5c, 0xb5d, 0x535e, 0xcb58, 0xb50, 0x4b50, 0x1352, 0x5352, 0xb00, 0xb40, 0x1345, 0xb46, 0x8b42, 0xb47, 0xb42, 0xb49, 0x1348, 0x5348, 0x174a, 0x574a,
-  0x4b47, 0xcb42, 0x4b49, 0x4b42, 0xb00, 0xb4b, 0xb00, 0xb4d, 0xb4c, 0x4b4c, 0xb4e, 0x4b4e, 0xb51, 0xb44, 0xb00, 0xb00, 0xb4f, 0x4b4f, 0x934f, 0xd34f, 0xb00, 0xb00, 0xb00, 0xb40, 0xb00, 0xb41, 0xb00, 0xb42, 0xb00, 0xb00, 0xb43, 0xb43,
-  0xb00, 0xb00, 0x9344, 0xb00, 0x1340, 0xb00, 0x1341, 0xb00, 0x1740, 0xb40, 0xb42, 0xb7d, 0x4b7a, 0xb7a, 0xb7e, 0x4b7e, 0xb40, 0x8b4d, 0x4bba, 0xb55, 0xb40, 0x8b55, 0x1378, 0xcb53, 0x4b76, 0x4b75, 0x13bb, 0x53bb, 0x4b7f, 0x4b42, 0xb83, 0x13bc,
-  0xb00, 0xb00, 0xb79, 0xb00, 0xb6e, 0x4b7c, 0xb00, 0xb41, 0x1340, 0x8b55, 0xb42, 0xb7b, 0x8b42, 0x9344, 0x1341, 0xb00, 0xb53, 0x9344, 0x8b53, 0x9344, 0x8b42, 0x9344, 0xb42, 0x9344, 0x934d, 0xb00, 0x8b53, 0x9344, 0xb00, 0xb00, 0xb40, 0xb00,
-  0xb41, 0xb00, 0x1384, 0xb00, 0xbb8, 0x13b9, 0x4b85, 0xcb7c, 0xb87, 0x13b0, 0x4b7b, 0x9344, 0xb00, 0xb00, 0xb40, 0xb00, 0xb91, 0x5391, 0xb9c, 0x4b9c, 0x8b42, 0x1392, 0xb93, 0x1394, 0xb95, 0xb96, 0x9395, 0x8b96, 0xb97, 0xb98, 0x8b97, 0x8b98,
-  0x1799, 0x5799, 0x9799, 0xd799, 0x4b98, 0x4b97, 0xcb98, 0xcb97, 0x937b, 0xb00, 0xb7b, 0xb00, 0xba6, 0x4ba6, 0xcb7a, 0x8b7a, 0xb8e, 0x4b8e, 0x938e, 0xcb8e, 0x934d, 0xb8f, 0x1390, 0x5390, 0xb00, 0xb00, 0xb00, 0x8b48, 0xb00, 0x934e, 0xb00, 0x8b4d,
-  0x8b72, 0x1346, 0xb45, 0xb46, 0x5744, 0x1744, 0xb00, 0xb00, 0x134d, 0xb00, 0x8b54, 0xb00, 0x1349, 0x1349, 0xb00, 0xb00, 0xb4b, 0x8b48, 0xb72, 0x4b72, 0xb00, 0xb74, 0xb00, 0xbb0, 0xb71, 0x1747, 0x17af, 0xb4b, 0xb6f, 0x1370, 0xb4b, 0xb00,
-  0xb6b, 0x8b6c, 0x8b6b, 0xbad, 0xb73, 0xb00, 0x13ae, 0xb46, 0x176b, 0x576b, 0xb6a, 0x4b6a, 0x1368, 0x5368, 0x1369, 0x5369, 0x8b4e, 0xb00, 0x9354, 0xb00, 0xb00, 0xb00, 0xb00, 0x5377, 0xb00, 0x974d, 0xb00, 0x4b7b, 0xb40, 0x8b4d, 0xb51, 0xb8d,
-  0x537a, 0x137a, 0x4b42, 0x8b40, 0xb00, 0xb00, 0xb00, 0xb00, 0xb00, 0xb00, 0xb40, 0xb00, 0xcb7a, 0x576e, 0xb00, 0xb00, 0xb6e, 0xb9f, 0xb00, 0x4ba5, 0x13a0, 0x13a1, 0xba2, 0xba3, 0xba4, 0xb00, 0xba5, 0xb00, 0xb40, 0x8b55, 0xb42, 0xcb87,
-  0x8b95, 0xba7, 0x8b42, 0xbaf, 0x4b78, 0xb00, 0x4b78, 0xb00, 0x8b42, 0xb51, 0xb78, 0x8b51, 0xba8, 0xba9, 0xbac, 0x8ba9, 0xbaa, 0x17ab, 0x13b4, 0x8bab, 0x17b1, 0xb41, 0x4b44, 0x4b42, 0xb00, 0xbad, 0xb00, 0x13ae, 0x1340, 0xbb7, 0xb42, 0xbb6,
-  0xb00, 0xb00, 0x139d, 0x139e, 0xb00, 0xb00, 0xb00, 0xb79, 0xb00, 0xb00, 0x8b42, 0xb86, 0xb42, 0x8b7b, 0x8b42, 0xb7b, 0xb87, 0x8b7b, 0x9387, 0xb7b, 0xb40, 0x13b3, 0x1378, 0xb8d, 0x8b42, 0xb88, 0x5378, 0xb40, 0x4b44, 0xd342, 0x97b5, 0x4b78,
-  0x13b3, 0x8b55, 0x4b7b, 0xb8d, 0xb89, 0x138a, 0xb8b, 0xb8c, 0xb00, 0xb7c, 0xb00, 0xb00, 0xb00, 0x9348, 0xb00, 0xb56, 0xb00, 0xb00, 0xb88, 0xb00, 0xb00, 0xb48, 0xb00, 0xb00, 0xb00, 0x9348, 0x1786, 0xb65, 0xb00, 0xb00, 0xcb5a, 0xb00,
-  0xb00, 0x5388, 0xb00, 0xb00, 0x4b5a, 0xb00, 0xb00, 0xb00, 0xb00, 0xcb5b, 0x13ab, 0xbac, 0xcb5a, 0xb00, 0x137e, 0xb00, 0xb00, 0x137e, 0xb00, 0xb00, 0xb00, 0x8b48, 0x1783, 0x1384, 0xb00, 0xb00, 0x1385, 0xb00, 0xb00, 0x537e, 0xb00, 0xb00,
-  0xb00, 0x8b48, 0xb43, 0xcb43, 0xb00, 0xb00, 0x1379, 0x137a, 0xb5a, 0x137b, 0xb00, 0xb00, 0xb00, 0x8b48, 0x137f, 0x1380, 0xb00, 0xb00, 0x1381, 0x1382, 0xb00, 0xb48, 0xb00, 0xb00, 0xb00, 0xb00, 0x1387, 0x1377, 0x5746, 0xb47, 0x1349, 0xb48,
-  0x1375, 0x4b42, 0x174a, 0x574a, 0xb43, 0x1344, 0xb45, 0x1746, 0x1742, 0x5742, 0x8b42, 0xcb42, 0x1375, 0x5375, 0x8b42, 0xcb42, 0x4b40, 0x1340, 0xb41, 0x4b41, 0x4b46, 0xb71, 0x1786, 0x8b71, 0x1347, 0xb4d, 0xb65, 0xb5b, 0xb00, 0xb00, 0x9348, 0xb00,
-  0xb00, 0xb00, 0xb00, 0x8b48, 0x4b66, 0x8b65, 0x4b5b, 0xb65, 0x9365, 0xb66, 0xb63, 0x8b66, 0x4b51, 0xb5f, 0xcb76, 0xb60, 0xb64, 0x4b4f, 0x4b60, 0x8b76, 0x4b76, 0xb61, 0xd376, 0x1362, 0x4b61, 0xb76, 0xcb58, 0x8b51, 0xb00, 0xb00, 0x5746, 0xb5e,
-  0xb00, 0xb00, 0xb5e, 0xb46, 0xb00, 0xb00, 0x8b48, 0xb00, 0xb4f, 0xb51, 0xcb76, 0x8b76, 0x5351, 0xb51, 0x8b4f, 0x8b51, 0x4b76, 0xb76, 0xcb51, 0x8b58, 0xb54, 0xb00, 0x8b66, 0xb00, 0x9348, 0x8b48, 0xb56, 0x4b45, 0xb00, 0xb57, 0xb00, 0xb59,
-  0x4b50, 0xb58, 0xcb50, 0x8b50, 0x5758, 0x1751, 0xcb58, 0x8b51, 0xb56, 0x4b56, 0xb65, 0x5756, 0x9348, 0x8b48, 0xb4c, 0xb4b, 0xb4d, 0xb00, 0x8b54, 0xb00, 0xb4f, 0xb50, 0x8b4f, 0x8b50, 0x4b50, 0xb51, 0xcb58, 0x8b51, 0xb52, 0xb54, 0xb53, 0x9354,
-  0x9748, 0x9748, 0x138d, 0x138e, 0x1391, 0x1392, 0x138c, 0x138f, 0x1393, 0x1390, 0x9393, 0x138f, 0x1394, 0x1395, 0x138e, 0x138c, 0x175d, 0x1399, 0x975d, 0x538f, 0x1397, 0x1398, 0x179a, 0x138c, 0x1399, 0x1766, 0x138f, 0xd75d, 0x538e, 0x538f, 0x1391, 0x1392,
-  0x139b, 0x539b, 0x139c, 0x539c, 0x138f, 0x138e, 0x5392, 0x5391, 0x138a, 0x538a, 0x138b, 0x538b, 0xb00, 0xcb5b, 0xb00, 0x8b54, 0x4b74, 0x13a6, 0xb00, 0x4b48, 0x13a0, 0x13a1, 0x538e, 0x138e, 0xd38e, 0x53a3, 0x13a4, 0xb00, 0x97aa, 0xb00, 0x538e, 0x1399,
-  0x13a4, 0xb00, 0x138e, 0xb00, 0xb00, 0x5393, 0xb00, 0x574e, 0x4b7d, 0xb00, 0x8b7d, 0x139f, 0x97aa, 0x13a4, 0x13a9, 0x53a9, 0x13a5, 0x13a6, 0x93a5, 0xd3a5, 0xd38e, 0x938e, 0x13a4, 0x13aa, 0xb00, 0x13a6, 0xb00, 0x8b5f, 0x139b, 0x13a6, 0x139c, 0x53a2,
-  0xb00, 0xb00, 0x138c, 0xb00, 0x9394, 0x139e, 0xb00, 0xb00,
-};
-static const uint16 kDungMap_Tab21[3] = {137, 167, 79};
-static const uint16 kDungMap_Tab22[3] = {169, 119, 190};
-static const uint16 kDungMap_Tab24[2] = {0x1f, 0x7f};
-static const uint16 kDungMap_Tab25[14] = {15, 15, 200, 51, 32, 6, 90, 144, 41, 222, 7, 172, 164, 13};
-static const int16 kDungMap_Tab28[14] = {-1, -1, 1, 1, 6, 0xff, 0xff, 0xff, 0xfe, 0xf9, 5, 0xff, 0xfd, 6};
-static PlayerHandlerFunc *const kDungMapInit[] = {
-  &Module0E_03_01_00_PrepMapGraphics,
-  &Module0E_03_01_01_DrawLEVEL,
-  &Module0E_03_01_02_DrawFloorsBackdrop,
-  &Module0E_03_01_03_DrawRooms,
-  &DungeonMap_DrawRoomMarkers,
-};
-static const uint8 kDungMap_Tab38[4] = {0x39, 0x3b, 0x3d, 0x3b};
-static const int8 kDungMap_Tab29[4] = {-9, 8, -9, 8};
-static const int8 kDungMap_Tab30[4] = {-8, -8, 9, 9};
-static const uint8 kDungMap_Tab31[4] = {0xf1, 0xb1, 0x71, 0x31};
-static const uint8 kDungMap_Tab32[4] = {0xc, 0xc, 8, 0xa};
-static const uint8 kDungMap_Tab33[8] = {187, 171, 155, 139, 123, 107, 91, 75};
-static const uint8 kDungMap_Tab34[8] = {0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25};
-static const uint8 kDungMap_Tab35[2] = {0, 8};
-static const uint8 kDungMap_Tab36[4] = {0x37, 0x38, 0x38, 0x37};
-static const int16 kDungMap_Tab37[14] = { -1, -1, 0x808, 8, 0, 8, 0x808, 8, 0x808, 0x800, 0x404, 0x808, 8, 8 };
-static const int8 kDungMap_Tab39[2] = {-4, 4};
-static const int8 kDungMap_Tab40[2] = {4, -4};
-static const int16 kDungMap_Tab26[2] = {0x60, -0x60};
-static PlayerHandlerFunc *const kDungMapSubmodules[] = {
-  &DungMap_Backup,
-  &Module0E_03_01_DrawMap,
-  &DungMap_LightenUpMap,
-  &DungeonMap_HandleInputAndSprites,
-  &DungMap_4,
-  &DungMap_FadeMapToBlack,
-  &DungeonMap_RecoverGFX,
-  &ToggleStarTilesAndAdvance,
-  &DungMap_RestoreOld,
-};
-static const uint16 kText_Positions[2] = {0x6125, 0x6244};
-static const uint16 kSrmOffsets[4] = {0, 0x500, 0xa00, 0xf00};
-static const int8 kText_InitializationData[32] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0x39, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1c, 4, 0, 0, 0, 0, 0};
-static const uint16 kText_BorderTiles[9] = {0x28f3, 0x28f4, 0x68f3, 0x28c8, 0x387f, 0x68c8, 0xa8f3, 0xa8f4, 0xe8f3};
-static const uint8 kText_CommandLengths[25] = {
-  1, 1, 1, 1, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1,
-  2, 2, 2, 2, 1, 1, 1, 1, 1,
-};
-static const uint8 kVWF_RenderCharacter_setMasks[8] = {0x80, 0x40, 0x20, 0x10, 8, 4, 2, 1};
-static const uint16 kVWF_RenderCharacter_renderPos[3] = {0, 0x2a0, 0x540};
-static const uint16 kVWF_RenderCharacter_linePositions[3] = {0, 0x40, 0x80};
-static const uint16 kVWF_RowPositions[3] = {0, 2, 4};
-static const uint16 kText_WaitDurations[16] = {31, 63, 94, 125, 156, 188, 219, 250, 281, 313, 344, 375, 406, 438, 469, 500};
-static PlayerHandlerFunc *const kText_Render[] = {
-  &RenderText_Draw_Border,
-  &RenderText_Draw_BorderIncremental,
-  &RenderText_Draw_CharacterTilemap,
-  &RenderText_Draw_MessageCharacters,
-  &RenderText_Draw_Finish,
-};
-static PlayerHandlerFunc *const kMessaging_Text[] = {
-  &Text_Initialize,
-  &Text_Render,
-  &RenderText_PostDeathSaveOptions,
-};
-static const uint8 kOverworldMap_tab1[333] = {
-  0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xdf,
-  0xde, 0xdd, 0xdc, 0xdb, 0xda, 0xd8, 0xd7, 0xd6, 0xd5, 0xd4, 0xd3, 0xd2, 0xd1, 0xd0, 0xcf, 0xce,
-  0xcd, 0xcc, 0xcb, 0xca, 0xc9, 0xc7, 0xc6, 0xc5, 0xc4, 0xc3, 0xc2, 0xc1, 0xc0, 0xbf, 0xbe, 0xbd,
-  0xbc, 0xbb, 0xba, 0xb9, 0xb8, 0xb7, 0xb6, 0xb5, 0xb4, 0xb3, 0xb2, 0xb1, 0xb0, 0xaf, 0xae, 0xad,
-  0xac, 0xab, 0xaa, 0xa9, 0xa8, 0xa7, 0xa6, 0xa5, 0xa4, 0xa3, 0xa2, 0xa1, 0xa0, 0x9f, 0x9e, 0x9d,
-  0x9c, 0x9b, 0x9b, 0x9a, 0x99, 0x98, 0x97, 0x96, 0x95, 0x94, 0x93, 0x92, 0x91, 0x90, 0x8f, 0x8e,
-  0x8d, 0x8c, 0x8b, 0x8b, 0x8a, 0x89, 0x88, 0x87, 0x86, 0x85, 0x84, 0x83, 0x82, 0x81, 0x81, 0x80,
-  0x7f, 0x7e, 0x7d, 0x7c, 0x7b, 0x7a, 0x79, 0x79, 0x78, 0x77, 0x76, 0x75, 0x74, 0x73, 0x72, 0x72,
-  0x71, 0x70, 0x6f, 0x6e, 0x6d, 0x6c, 0x6c, 0x6b, 0x6a, 0x69, 0x68, 0x67, 0x67, 0x66, 0x65, 0x64,
-  0x63, 0x62, 0x62, 0x61, 0x60, 0x5f, 0x5e, 0x5d, 0x5d, 0x5c, 0x5b, 0x5a, 0x59, 0x59, 0x58, 0x57,
-  0x56, 0x55, 0x55, 0x54, 0x53, 0x52, 0x51, 0x51, 0x50, 0x4f, 0x4e, 0x4e, 0x4d, 0x4c, 0x4b, 0x4a,
-  0x4a, 0x49, 0x48, 0x47, 0x47, 0x46, 0x45, 0x44, 0x44, 0x43, 0x42, 0x41, 0x41, 0x40, 0x3f, 0x3e,
-  0x3e, 0x3d, 0x3c, 0x3c, 0x3b, 0x3a, 0x39, 0x39, 0x38, 0x37, 0x36, 0x36, 0x35, 0x34, 0x34, 0x33,
-  0x32, 0x32, 0x31, 0x30, 0x2f, 0x2f, 0x2e, 0x2d, 0x2d, 0x2c, 0x2b, 0x2b, 0x2a, 0x29, 0x29, 0x28,
-  0x27, 0x27, 0x26, 0x25, 0x25, 0x24, 0x23, 0x23, 0x22, 0x21, 0x21, 0x20, 0x1f, 0x1f, 0x1e, 0x1d,
-  0x1d, 0x1c, 0x1c, 0x1b, 0x1a, 0x1a, 0x19, 0x18, 0x18, 0x17, 0x17, 0x16, 0x15, 0x15, 0x14, 0x14,
-  0x13, 0x12, 0x12, 0x11, 0x10, 0x10,  0xf,  0xf,  0xe,  0xe,  0xd,  0xc,  0xc,  0xb,  0xb,  0xa,
-     9,    9,    8,    8,    7,    7,    6,    5,    5,    4,    4,    3,    3,    2,    1,    1,
-     0,    0,    0,    0, 0xff, 0xfe, 0xfe, 0xfd, 0xfc, 0xfc, 0xfb, 0xfb, 0xfa, 0xf9, 0xf9, 0xf8,
-  0xf7, 0xf7, 0xf6, 0xf5, 0xf4, 0xf4, 0xf3, 0xf2, 0xf2, 0xf1, 0xf0, 0xef, 0xee, 0xee, 0xed, 0xec,
-  0xeb, 0xea, 0xe9, 0xe8, 0xe8, 0xe7, 0xe6, 0xe5, 0xe4, 0xe3, 0xe2, 0xe1, 0xe0,
-};
-static const uint8 kOverworldMapData[7] = {0x79, 0x6e, 0x6f, 0x6d, 0x7c, 0x6c, 0x7f};
-static const uint8 kBirdTravel_tab1[8] = {0x7f, 0x79, 0x6c, 0x6d, 0x6e, 0x6f, 0x7c, 0x7d};
-static const uint8 kBirdTravel_x_lo[8] = {0x80, 0xcf, 0x10, 0xb8, 0x30, 0x70, 0x70, 0xf0};
-static const uint8 kBirdTravel_x_hi[8] = {6, 0xc, 2, 8, 0xf, 0, 7, 0xe};
-static const uint8 kBirdTravel_y_lo[8] = {0x5b, 0x98, 0xc0, 0x20, 0x50, 0xb0, 0x30, 0x80};
-static const uint8 kBirdTravel_y_hi[8] = {3, 5, 7, 0xb, 0xb, 0xf, 0xf, 0xf};
-static const uint8 kPendantBitMask[3] = {4, 1, 2};
-static const uint8 kCrystalBitMask[7] = {2, 0x40, 8, 0x20, 1, 4, 0x10};
-static const uint16 kOwMapCrystal0_x[9] = {0x7ff, 0x2c0, 0xd00, 0xf31, 0x6d, 0x7e0, 0xf40, 0xf40, 0x8dc};
-static const uint16 kOwMapCrystal0_y[9] = {0x730, 0x6a0, 0x710, 0x620, 0x70, 0x640, 0x620, 0x620, 0x30};
-static const uint16 kOwMapCrystal1_x[9] = {0xff00, 0xff00, 0xff00, 0x8d0, 0xff00, 0xff00, 0xff00, 0x82, 0xff00};
-static const uint16 kOwMapCrystal1_y[9] = {0xff00, 0xff00, 0xff00, 0x80, 0xff00, 0xff00, 0xff00, 0xb0, 0xff00};
-static const uint16 kOwMapCrystal2_x[9] = {0xff00, 0xff00, 0xff00, 0x108, 0xff00, 0xff00, 0xff00, 0xf11, 0xff00};
-static const uint16 kOwMapCrystal2_y[9] = {0xff00, 0xff00, 0xff00, 0xd70, 0xff00, 0xff00, 0xff00, 0x103, 0xff00};
-static const uint16 kOwMapCrystal3_x[9] = {0xff00, 0xff00, 0xff00, 0x6d, 0xff00, 0xff00, 0xff00, 0x1d0, 0xff00};
-static const uint16 kOwMapCrystal3_y[9] = {0xff00, 0xff00, 0xff00, 0x70, 0xff00, 0xff00, 0xff00, 0x780, 0xff00};
-static const uint16 kOwMapCrystal4_x[9] = {0xff00, 0xff00, 0xff00, 0xff00, 0xff00, 0xff00, 0xff00, 0x100, 0xff00};
-static const uint16 kOwMapCrystal4_y[9] = {0xff00, 0xff00, 0xff00, 0xff00, 0xff00, 0xff00, 0xff00, 0xca0, 0xff00};
-static const uint16 kOwMapCrystal5_x[9] = {0xff00, 0xff00, 0xff00, 0xff00, 0xff00, 0xff00, 0xff00, 0xca0, 0xff00};
-static const uint16 kOwMapCrystal5_y[9] = {0xff00, 0xff00, 0xff00, 0xff00, 0xff00, 0xff00, 0xff00, 0xda0, 0xff00};
-static const uint16 kOwMapCrystal6_x[9] = {0xff00, 0xff00, 0xff00, 0xff00, 0xff00, 0xff00, 0xff00, 0x759, 0xff00};
-static const uint16 kOwMapCrystal6_y[9] = {0xff00, 0xff00, 0xff00, 0xff00, 0xff00, 0xff00, 0xff00, 0xed0, 0xff00};
-static const uint16 kOwMapCrystal0_tab[9] = {0, 0, 0, 0x6038, 0x6234, 0x6632, 0x6434, 0x6434, 0x6632};
-static const uint16 kOwMapCrystal1_tab[9] = {0, 0, 0, 0x6032, 0, 0, 0, 0x6434, 0};
-static const uint16 kOwMapCrystal2_tab[9] = {0, 0, 0, 0x6034, 0, 0, 0, 0x6434, 0};
-static const uint16 kOwMapCrystal3_tab[9] = {0, 0, 0, 0x6234, 0, 0, 0, 0x6434, 0};
-static const uint16 kOwMapCrystal4_tab[9] = {0, 0, 0, 0, 0, 0, 0, 0x6434, 0};
-static const uint16 kOwMapCrystal5_tab[9] = {0, 0, 0, 0, 0, 0, 0, 0x6434, 0};
-static const uint16 kOwMapCrystal6_tab[9] = {0, 0, 0, 0, 0, 0, 0, 0x6434, 0};
-static const uint8 kOwMap_tab2[4] = {0x68, 0x69, 0x78, 0x69};
-static const uint8 kOverworldMap_Table4[4] = {0x34, 0x74, 0xf4, 0xb4};
-static const uint8 kOverworldMap_Timer[2] = {33, 12};
-static const int16 kOverworldMap_Table3[8] = {0, 0, 1, 2, -1, -2, 1, 2};
-static const int16 kOverworldMap_Table2[8] = {0, 0, 224, 480, -72, -224, 0, 0};
-static PlayerHandlerFunc *const kMessagingSubmodules[12] = {
-  &Module_Messaging_0,
-  &Hud_Module_Run,
-  &RenderText,
-  &Module0E_03_DungeonMap,
-  &Module0E_04_RedPotion,
-  &Module0E_05_DesertPrayer,
-  &Module_Messaging_6,
-  &Messaging_OverworldMap,
-  &Module0E_08_GreenPotion,
-  &Module0E_09_BluePotion,
-  &Module0E_0A_FluteMenu,
-  &Module0E_0B_SaveMenu,
-};
-static const uint8 kDeath_AnimCtr0[15] = {0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 4, 5, 5};
-static const uint8 kDeath_AnimCtr1[15] = {5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 3, 3, 0x62};
-static const uint8 kDeath_SprFlags[2] = {0x20, 0x10};
-static const uint8 kDeath_SprChar0[2] = {0xea, 0xec};
-static const uint8 kDeath_SprY0[3] = {0x7f, 0x8f, 0x9f};
-const uint8 kHealthAfterDeath[21] = {
-  0x18, 0x18, 0x18, 0x18, 0x18, 0x20, 0x20, 0x28, 0x28, 0x30, 0x30, 0x38, 0x38, 0x38, 0x40, 0x40,
-  0x40, 0x48, 0x48, 0x48, 0x50,
-};
-static PlayerHandlerFunc *const kModule_Death[16] = {
-  &GameOver_AdvanceImmediately,
-  &Death_Func1,
-  &GameOver_DelayBeforeIris,
-  &GameOver_IrisWipe,
-  &Death_Func4,
-  &GameOver_SplatAndFade,
-  &Death_Func6,
-  &Animate_GAMEOVER_Letters_bounce,
-  &GameOver_Finalize_GAMEOVR,
-  &GameOver_SaveAndOrContinue,
-  &GameOver_InitializeRevivalFairy,
-  &RevivalFairy_Main_bounce,
-  &GameOver_RiseALittle,
-  &GameOver_Restore0D,
-  &GameOver_Restore0E,
-  &GameOver_ResituateLink,
-};
-static const uint8 kLocationMenuStartPos[3] = {0, 1, 6};
-static void RunInterface();
-const uint8 *GetDungmapFloorLayout() {
-  return kDungMap_FloorLayout(cur_palace_index_x2 >> 1).ptr;
-}
-
-uint8 GetOtherDungmapInfo(int count) {
-  const uint8 *p = kDungMap_Tiles(cur_palace_index_x2 >> 1).ptr;
-  return p[count];
-}
-
-void DungMap_4() {
-  BG2VOFS_copy2 += dungmap_var4;
-  dungmap_var5 -= dungmap_var4;
-  if (!--bottle_menu_expand_row)
-    overworld_map_state--;
-}
-
-void Module_Messaging_6() {
-  assert(0);
-}
-
-void OverworldMap_SetupHdma() {
-  static const uint32 kOverworldMap_TableLow[2] = {0xabdcf, 0xabdd6};
-  uint32 a = kOverworldMap_TableLow[overworld_map_flags];
-  HdmaSetup(a, a, 0x42, (uint8)M7A, (uint8)M7D, 10);
-}
-
-const uint8 *GetLightOverworldTilemap() {
-  return kLightOverworldTilemap;
-}
-
-void SaveGameFile() {  // 80894a
-  int offs = ((srm_var1 >> 1) - 1) * 0x500;
-  memcpy(g_zenv.sram + offs, save_dung_info, 0x500);
-  memcpy(g_zenv.sram + offs + 0xf00, save_dung_info, 0x500);
-  uint16 t = 0x5a5a;
-  for (int i = 0; i < 0x4fe; i += 2)
-    t -= *(uint16 *)((char *)save_dung_info + i);
-  word_7EF4FE = t;
-  WORD(g_zenv.sram[offs + 0x4fe]) = t;
-  WORD(g_zenv.sram[offs + 0x4fe + 0xf00]) = t;
-  ZeldaWriteSram();
-}
-
-void TransferMode7Characters() {  // 80e399
-  uint16 *dst = g_zenv.vram;
-  const uint8 *src = kOverworldMapGfx;
-  for (int i = 0; i != 0x4000; i++)
-    HIBYTE(dst[i]) = src[i];
-}
-
-void Module0E_Interface() {  // 80f800
-  bool skip_run = false;
-  if (player_is_indoors) {
-    if (submodule_index == 3) {
-      skip_run = (overworld_map_state != 0 && overworld_map_state != 7);
-    } else {
-      Dungeon_PushBlock_Handler();
-    }
-  } else {
-    skip_run = ((submodule_index == 7 || submodule_index == 10) && overworld_map_state);
-  }
-  if (!skip_run) {
-    Sprite_Main();
-    LinkOam_Main();
-    if (!player_is_indoors)
-      OverworldOverlay_HandleRain();
-    Hud_RefillLogic();
-    if (submodule_index != 2)
-      OrientLampLightCone();
-  }
-  RunInterface();
-  BG2HOFS_copy = BG2HOFS_copy2 + bg1_x_offset;
-  BG2VOFS_copy = BG2VOFS_copy2 + bg1_y_offset;
-  BG1HOFS_copy = BG1HOFS_copy2 + bg1_x_offset;
-  BG1VOFS_copy = BG1VOFS_copy2 + bg1_y_offset;
-}
-
-void Module_Messaging_0() {  // 80f875
-  assert(0);
-}
-
-static void RunInterface() {  // 80f89a
-  kMessagingSubmodules[submodule_index]();
-}
-
-void Module0E_05_DesertPrayer() {  // 80f8b1
-  switch (subsubmodule_index) {
-  case 0: ResetTransitionPropsAndAdvance_ResetInterface(); break;
-  case 1: ApplyPaletteFilter_bounce(); break;
-  case 2:
-    DesertPrayer_InitializeIrisHDMA();
-    BYTE(palette_filter_countdown) = mosaic_target_level - 1;
-    mosaic_target_level = 0;
-    BYTE(darkening_or_lightening_screen) = 2;
-    break;
-  case 3:
-    ApplyPaletteFilter_bounce();
-    // fall through
-  case 4:
-    DesertPrayer_BuildIrisHDMATable();
-    break;
-  }
-}
-
-void Module0E_04_RedPotion() {  // 80f8fb
-  if (Hud_RefillHealth()) {
-    button_mask_b_y &= ~0x40;
-    flag_update_hud_in_nmi++;
-    submodule_index = 0;
-    main_module_index = saved_module_for_menu;
-  }
-}
-
-void Module0E_08_GreenPotion() {  // 80f911
-  if (Hud_RefillMagicPower()) {
-    button_mask_b_y &= ~0x40;
-    flag_update_hud_in_nmi++;
-    submodule_index = 0;
-    main_module_index = saved_module_for_menu;
-  }
-}
-
-void Module0E_09_BluePotion() {  // 80f918
-  if (Hud_RefillHealth())
-    submodule_index = 8;
-  if (Hud_RefillMagicPower())
-    submodule_index = 4;
-}
-
-void Module0E_0B_SaveMenu() {  // 80f9fa
-  // This is the continue / save and quit menu
-  if (!player_is_indoors)
-    Overworld_DwDeathMountainPaletteAnimation();
-  RenderText();
-  flag_update_hud_in_nmi = 0;
-  nmi_disable_core_updates = 0;
-  if (subsubmodule_index < 3)
-    subsubmodule_index++;
-  else
-    nmi_load_bg_from_vram = 0;
-  if (!submodule_index) {
-    subsubmodule_index = 0;
-    nmi_load_bg_from_vram = 1;
-    if (choice_in_multiselect_box) {
-      sound_effect_ambient = 15;
-      main_module_index = 23;
-      submodule_index = 1;
-      index_of_changable_dungeon_objs[0] = 0;
-      index_of_changable_dungeon_objs[1] = 0;
-    } else {
-      choice_in_multiselect_box = choice_in_multiselect_box_bak;
-    }
-  }
-}
-
-void Module1B_SpawnSelect() {  // 828586
-  RenderText();
-  if (submodule_index)
-    return;
-  nmi_load_bg_from_vram = 0;
-  EnableForceBlank();
-  EraseTileMaps_normal();
-  uint8 bak = which_starting_point;
-  which_starting_point = kLocationMenuStartPos[choice_in_multiselect_box];
-  subsubmodule_index = 0;
-  LoadDungeonRoomRebuildHUD();
-  which_starting_point = bak;
-}
-
-void CleanUpAndPrepDesertPrayerHDMA() {  // 82c7b8
-  HdmaSetup(0, 0x2c80c, 0x41, 0, (uint8)WH0, 0);
-
-  W12SEL_copy = 0x33;
-  W34SEL_copy = 3;
-  WOBJSEL_copy = 0x33;
-  TMW_copy = TM_copy;
-  TSW_copy = TS_copy;
-  HDMAEN_copy = 0x80;
-  memset(hdma_table_dynamic, 0, 240 * sizeof(uint16));
-}
-
-void DesertPrayer_InitializeIrisHDMA() {  // 87ea06
-  CleanUpAndPrepDesertPrayerHDMA();
-  spotlight_var1 = 0x26;
-  BYTE(spotlight_var2) = 0;
-  DesertPrayer_BuildIrisHDMATable();
-  subsubmodule_index++;
-}
-
-void DesertPrayer_BuildIrisHDMATable() {  // 87ea27
-  uint16 r14 = link_y_coord - BG2VOFS_copy2 + 12;
-  spotlight_y_lower = r14 - spotlight_var1;
-  uint16 r4 = sign16(spotlight_y_lower) ? spotlight_y_lower : 0;
-  uint16 k;
-  spotlight_y_upper = spotlight_y_lower + spotlight_var1 * 2;
-  spotlight_var3 = link_x_coord - BG2HOFS_copy2 + 8;
-  spotlight_var4 = 1;
-  do {
-    uint16 r0 = 0x100, r2 = 0x100;
-    if (!(sign16(spotlight_y_lower) || (r4 >= spotlight_y_lower && r4 < spotlight_y_upper))) {
-      k = (r4 - 1);
-    } else if (spotlight_var1 < spotlight_var4) {
-      spotlight_var4 = 1;
-      spotlight_y_lower = 0;
-      r4 = spotlight_y_upper;
-      if (r4 >= 225)
-        break;
-      k = (r4 - 1);
-    } else {
-      Pair16U pair = DesertHDMA_CalculateIrisShapeLine();
-      if (pair.a == 0) {
-        spotlight_y_lower = 0;
-      } else {
-        r2 = spotlight_var3 + pair.b;
-        r0 = spotlight_var3 - pair.b;
-      }
-      k = (r14 - BYTE(spotlight_var4) - 1);
-    }
-    uint8 t6 = (r0 < 256) ? r0 : (r0 < 512) ? 255 : 0;
-    uint8 t7 = (r2 < 256) ? r2 : 255;
-    uint16 r6 = t7 << 8 | t6;
-    if (k < 240)
-     hdma_table_dynamic[k] = (r6 == 0xffff) ? 0xff : r6;
-    if (sign16(spotlight_y_lower) || (r4 >= spotlight_y_lower && r4 < spotlight_y_upper)) {
-      k = BYTE(spotlight_var4) - 2 + r14;
-      if (k < 240)
-        hdma_table_dynamic[k] = (r6 == 0xffff) ? 0xff : r6;
-      spotlight_var4++;
-    }
-    r4++;
-  } while (sign16(r4) || r4 < 225);
-
-  if (subsubmodule_index != 4)
-    return;
-  if (BYTE(spotlight_var2) != 1 && (filtered_joypad_H | filtered_joypad_L) & 0xc0) {
-    BYTE(spotlight_var2) = 1;
-    BYTE(spotlight_var1) >>= 1;
-  }
-  if (BYTE(spotlight_var2) && (BYTE(spotlight_var1) += 8) >= 0xc0) {
-    byte_7E02F0 ^= 1;
-    music_control = 0xf3;
-    sound_effect_ambient = 0;
-    flag_unk1 = 0;
-    some_animation_timer_steps = 0;
-    button_mask_b_y = 0;
-    link_state_bits = 0;
-    link_cant_change_direction &= ~1;
-    subsubmodule_index = 0;
-    submodule_index = 0;
-    main_module_index = saved_module_for_menu;
-    TMW_copy = 0;
-    TSW_copy = 0;
-    W12SEL_copy = 0;
-    W34SEL_copy = 0;
-    WOBJSEL_copy = 0;
-    IrisSpotlight_ResetTable();
-  } else {
-    static const uint8 kPrayingScene_Delays[5] = {22, 22, 22, 64, 1};
-    if (sign8(--link_delay_timer_spin_attack)) {
-      int i = some_animation_timer_steps + 1;
-      if (i != 4)
-        some_animation_timer_steps = i;
-      link_delay_timer_spin_attack = kPrayingScene_Delays[i];
-    }
-  }
-}
-
-Pair16U DesertHDMA_CalculateIrisShapeLine() {  // 87ecdc
-  static const uint8 kPrayingScene_Tab1[129] = {
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xfe, 0xfe, 0xfe,
-    0xfd, 0xfd, 0xfd, 0xfd, 0xfc, 0xfc, 0xfc, 0xfb, 0xfb, 0xfb, 0xfa, 0xfa, 0xf9, 0xf9, 0xf8, 0xf8,
-    0xf7, 0xf7, 0xf6, 0xf6, 0xf5, 0xf5, 0xf4, 0xf3, 0xf3, 0xf2, 0xf1, 0xf1, 0xf0, 0xef, 0xee, 0xee,
-    0xed, 0xec, 0xeb, 0xea, 0xe9, 0xe9, 0xe8, 0xe7, 0xe6, 0xe5, 0xe4, 0xe3, 0xe2, 0xe1, 0xdf, 0xde,
-    0xdd, 0xdc, 0xdb, 0xda, 0xd8, 0xd7, 0xd6, 0xd5, 0xd3, 0xd2, 0xd0, 0xcf, 0xcd, 0xcc, 0xca, 0xc9,
-    0xc7, 0xc6, 0xc4, 0xc2, 0xc1, 0xbf, 0xbd, 0xbb, 0xb9, 0xb7, 0xb6, 0xb4, 0xb1, 0xaf, 0xad, 0xab,
-    0xa9, 0xa7, 0xa4, 0xa2, 0x9f, 0x9d, 0x9a, 0x97, 0x95, 0x92, 0x8f, 0x8c, 0x89, 0x86, 0x82, 0x7f,
-    0x7b, 0x78, 0x74, 0x70, 0x6c, 0x67, 0x63, 0x5e, 0x59, 0x53, 0x4d, 0x46, 0x3f, 0x37, 0x2d, 0x1f,
-    0,
-  };
-  static const uint8 kPrayingScene_Tab0[129] = {
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xfe, 0xfd, 0xfd, 0xfc, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8,
-    0xf7, 0xf6, 0xf5, 0xf4, 0xf3, 0xf1, 0xf0, 0xee, 0xed, 0xeb, 0xe9, 0xe8, 0xe6, 0xe4, 0xe2, 0xdf,
-    0xdd, 0xdb, 0xd8, 0xd6, 0xd3, 0xd0, 0xcd, 0xca, 0xc7, 0xc4, 0xc1, 0xbd, 0xb9, 0xb6, 0xb1, 0xad,
-    0xa9, 0xa4, 0x9f, 0x9a, 0x95, 0x8f, 0x89, 0x82, 0x7b, 0x74, 0x6c, 0x63, 0x59, 0x4d, 0x3f, 0x2d,
-    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
-    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
-    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
-    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
-    0,
-  };
-  uint8 t = snes_divide(BYTE(spotlight_var4) << 8, BYTE(spotlight_var1)) >> 1;
-  uint8 r6 = BYTE(spotlight_var2) ? kPrayingScene_Tab1[t] : kPrayingScene_Tab0[t];
-  uint16 r8 = r6 * BYTE(spotlight_var1) >> 8;
-  if (BYTE(spotlight_var2))
-    r8 <<= 1;
-  Pair16U ret = { r6, r8 };
-  return ret;
-}
-
-void Animate_GAMEOVER_Letters() {  // 88f4ca
-  switch (ancilla_type[0]) {
-  case 0:
-    submodule_index++;
-    break;
-  case 1:
-    GameOverText_SweepLeft();
-    break;
-  case 2:
-    GameOverText_UnfurlRight();
-    break;
-  case 3:
-    GameOverText_Draw();
-    break;
-  }
-}
-
-void GameOverText_SweepLeft() {  // 88f4f6
-  static const uint8 kGameOverText_Tab1[8] = {0x40, 0x50, 0x60, 0x70, 0x88, 0x98, 0xa8, 0x40};
-
-  int k = flag_for_boomerang_in_place;
-  cur_object_index = k;
-  ancilla_x_vel[k] = 0x80;
-  Ancilla_MoveX(k);
-  if (Ancilla_GetX(k) < kGameOverText_Tab1[k]) {
-    ancilla_x_lo[k] = kGameOverText_Tab1[k];
-    flag_for_boomerang_in_place = ++k;
-    if (k == 8) {
-      flag_for_boomerang_in_place = 7;
-      ancilla_type[0]++;
-      hookshot_effect_index = 0;
-      sound_effect_2 = 38;
-      goto draw;
-    }
-  }
-  if (k == 7) {
-    int j = 6;
-    while (j != hookshot_effect_index)
-      ancilla_x_lo[j--] = ancilla_x_lo[k];
-    if (Ancilla_GetX(k) < kGameOverText_Tab1[hookshot_effect_index])
-      hookshot_effect_index--;
-  }
-draw:
-  GameOverText_Draw();
-}
-
-void GameOverText_UnfurlRight() {  // 88f56d
-  static const uint8 kGameOverText_Tab2[8] = {0x58, 0x60, 0x68, 0x70, 0x88, 0x90, 0x98, 0xa0};
-
-  int k = flag_for_boomerang_in_place, end;
-  cur_object_index = k;
-  ancilla_x_vel[k] = 0x60;
-  Ancilla_MoveX(k);
-  int j = hookshot_effect_index;
-  if (ancilla_x_lo[k] >= kGameOverText_Tab2[j]) {
-    ancilla_x_lo[j] = kGameOverText_Tab2[j];
-    if (++hookshot_effect_index == 8) {
-      submodule_index++;
-      ancilla_type[0]++;
-      goto draw;
-    }
-  }
-  end = hookshot_effect_index - 1;
-  k = flag_for_boomerang_in_place;
-  j = k;
-  do {
-    ancilla_x_lo[j] = ancilla_x_lo[k];
-  } while (--j != end);
-draw:
-  GameOverText_Draw();
-}
-
-void Module12_GameOver() {  // 89f290
-  kModule_Death[submodule_index]();
-  if (submodule_index != 9)
-    LinkOam_Main();
-}
-
-void GameOver_AdvanceImmediately() {  // 89f2a2
-  submodule_index++;
-  Death_Func1();
-}
-
-void Death_Func1() {  // 89f2a4
-  music_unk1_death = music_unk1;
-  sound_effect_ambient_last_death = sound_effect_ambient_last;
-  music_control = 241;
-  sound_effect_ambient = 5;
-  overworld_map_state = 5;
-  link_on_conveyor_belt = 0;
-  byte_7E0322 = 0;
-  link_cape_mode = 0;
-  mapbak_bg1_x_offset = palette_filter_countdown;
-  mapbak_bg1_y_offset = darkening_or_lightening_screen;
-  memcpy(mapbak_palette, aux_palette_buffer, 256);
-  memset(aux_palette_buffer + 32, 0, 192);
-  palette_filter_countdown = 0;
-  darkening_or_lightening_screen = 0;
-  bg1_x_offset = 0;
-  bg1_y_offset = 0;
-  mapbak_CGWSEL = WORD(CGWSEL_copy);
-  some_menu_ctr = 32;
-  hud_floor_changed_timer = 0;
-  Hud_FloorIndicator();
-  flag_update_hud_in_nmi++;
-  sound_effect_ambient = 5;
-  submodule_index++;
-}
-
-void GameOver_DelayBeforeIris() {  // 89f33b
-  if (--some_menu_ctr)
-    return;
-  Death_InitializeGameOverLetters();
-  IrisSpotlight_close();
-  WOBJSEL_copy = 0x30;
-  W34SEL_copy = 0;
-  submodule_index++;
-}
-
-void GameOver_IrisWipe() {  // 89f350
-  PaletteFilter_RestoreBGSubstractiveStrict();
-  main_palette_buffer[0] = main_palette_buffer[32];
-  uint8 bak = main_module_index;
-  IrisSpotlight_ConfigureTable();
-  main_module_index = bak;
-  if (submodule_index)
-    return;
-  for (int i = 0; i < 16; i++) {
-    main_palette_buffer[0x20 + i] = 0x18;
-    main_palette_buffer[0x30 + i] = 0x18;
-    main_palette_buffer[0x40 + i] = 0x18;
-    main_palette_buffer[0x50 + i] = 0x18;
-    main_palette_buffer[0x60 + i] = 0x18;
-    main_palette_buffer[0x70 + i] = 0x18;
-  }
-  main_palette_buffer[0] = main_palette_buffer[32] = 0x18;
-
-  IrisSpotlight_ResetTable();
-  COLDATA_copy0 = 32;
-  COLDATA_copy1 = 64;
-  COLDATA_copy2 = 128;
-  W12SEL_copy = 0;
-  W34SEL_copy = 0;
-  WOBJSEL_copy = 0;
-  submodule_index = 4;
-  flag_update_cgram_in_nmi++;
-  INIDISP_copy = 15;
-  TM_copy = 20;
-  TS_copy = 0;
-  CGADSUB_copy = 32;
-  some_menu_ctr = 64;
-  BYTE(palette_filter_countdown) = 0;
-  BYTE(darkening_or_lightening_screen) = 0;
-  Death_PrepFaint();
-}
-
-void GameOver_SplatAndFade() {  // 89f3de
-  if (some_menu_ctr) {
-    some_menu_ctr--;
-    return;
-  }
-  PaletteFilter_RestoreBGSubstractiveStrict();
-  main_palette_buffer[0] = main_palette_buffer[32];
-  if (BYTE(darkening_or_lightening_screen) != 0xff)
-    return;
-  mosaic_level = 0;
-  mosaic_inc_or_dec = 0;
-  MOSAIC_copy = 3;
-
-  for (int i = 0; i != 4; i++) {
-    if (link_bottle_info[i] == 6) {
-      link_bottle_info[i] = 2;
-      some_menu_ctr = 12;
-      load_chr_halfslot_even_odd = 15;
-      Graphics_LoadChrHalfSlot();
-      load_chr_halfslot_even_odd = 0;
-      submodule_index = 10;
-      return;
-    }
-  }
-  index_of_changable_dungeon_objs[0] = 0;
-  index_of_changable_dungeon_objs[1] = 0;
-  nmi_subroutine_index = 22;
-  nmi_disable_core_updates = 22;
-  submodule_index++;
-}
-
-void Death_Func6() {  // 89f458
-  some_menu_ctr = 12;
-  load_chr_halfslot_even_odd = 15;
-  Graphics_LoadChrHalfSlot();
-  load_chr_halfslot_even_odd = 0;
-  palette_sp6r_indoors = 5;
-  overworld_palette_aux_or_main = 0x200;
-  Palette_Load_SpriteEnvironment_Dungeon();
-  Palette_Load_SpriteMain();
-  flag_update_cgram_in_nmi++;
-  submodule_index++;
-  Death_PlayerSwoon();
-}
-
-void Death_Func4() {  // 89f47e
-  Death_PlayerSwoon();
-}
-
-void Animate_GAMEOVER_Letters_bounce() {  // 89f483
-  Animate_GAMEOVER_Letters();
-}
-
-void GameOver_Finalize_GAMEOVR() {  // 89f488
-  Animate_GAMEOVER_Letters();
-  uint8 bak1 = main_module_index;
-  uint8 bak2 = submodule_index;
-  messaging_module = 2;
-  RenderText();
-  submodule_index = bak2 + 1;
-  main_module_index = bak1;
-  some_menu_ctr = 2;
-  music_control = 11;
-}
-
-void GameOver_SaveAndOrContinue() {  // 89f4c1
-  GameOver_AnimateChoiceFairy();
-  if (ancilla_type)
-    Animate_GAMEOVER_Letters();
-
-  if (filtered_joypad_H & 0x20)
-    goto do_inc;
-
-  if (!--some_menu_ctr) {
-    some_menu_ctr = 1;
-    if (joypad1H_last & 12) {
-      if (joypad1H_last & 4) {
-do_inc:
-        if (++subsubmodule_index >= 3)
-          subsubmodule_index = 0;
-      } else {
-        if (sign8(--subsubmodule_index))
-          subsubmodule_index = 2;
-      }
-      some_menu_ctr = 12;
-      sound_effect_2 = 32;
-    }
-  }
-  if (!((filtered_joypad_L & 0xc0 | filtered_joypad_H) & 0xd0))
-    return;
-  sound_effect_1 = 44;
-  // Only death with save/continue or save/quit counts as a death
-  Death_Func15(subsubmodule_index != 2);
-}
-
-void Death_Func15(bool count_as_death) {  // 89f50f
-  music_control = 0xf1;
-  if (player_is_indoors)
-    Dungeon_FlagRoomData_Quadrants();
-  AdjustLinkBunnyStatus();
-  if (sram_progress_indicator < 3) {
-    savegame_is_darkworld = 0;
-    if (!link_item_moon_pearl)
-      ForceNonbunnyStatus();
-  }
-  if (dungeon_room_index == 0)
-    player_is_indoors = 0;
-
-  ResetSomeThingsAfterDeath((uint8)dungeon_room_index);
-  if (follower_indicator == 6 || follower_indicator == 9 || follower_indicator == 10 || follower_indicator == 13)
-    follower_indicator = 0;
-
-  death_var4 = link_health_current = kHealthAfterDeath[link_health_capacity >> 3];
-  uint8 i = BYTE(cur_palace_index_x2);
-  if (i != 0xff)
-    link_keys_earned_per_dungeon[(i == 2 ? 0 : i) >> 1] = link_num_keys;
-  Sprite_ResetAll();
-  if (death_var2 == 0xffff && (!(enhanced_features0 & kFeatures0_MiscBugFixes) || count_as_death))
-    death_save_counter++;
-  death_var5++;
-  if (subsubmodule_index != 1) {
-    if (!player_is_indoors)
-      goto outdoors;
-
-    if (follower_indicator != 1 && BYTE(cur_palace_index_x2) != 255) {
-      death_var4 = 0;
-    } else {
-      queued_music_control = 0;
-      player_is_indoors = 0;
-    outdoors:
-      if (savegame_is_darkworld)
-        dungeon_room_index = 32;
-    }
-
-    if (sram_progress_indicator) {
-      if (subsubmodule_index == 0)
-        SaveGameFile();
-      main_module_index = 5;
-      submodule_index = 0;
-      nmi_load_bg_from_vram = 0;
-    } else {
-      uint8 slot = srm_var1;
-      int offs = kSrmOffsets[(slot >> 1) - 1];
-      WORD(g_ram[0]) = offs;
-      death_var5 = 0;
-      CopySaveToWRAM();
-    }
-  } else {
-    if (sram_progress_indicator)
-      SaveGameFile();
-    TM_copy = 16;
-    player_is_indoors = 0;
-    Death_Func31();
-    death_var4 = 0;
-    death_var5 = 0;
-    queued_music_control = 0;
-    BG1HOFS_copy2 = 0;
-    BG2HOFS_copy2 = 0;
-    BG3HOFS_copy2 = 0;
-    BG1VOFS_copy2 = 0;
-    BG2VOFS_copy2 = 0;
-    BG3VOFS_copy2 = 0;
-    BG1HOFS_copy = 0;
-    BG2HOFS_copy = 0;
-    BG1VOFS_copy = 0;
-    BG2VOFS_copy = 0;
-    memset(save_dung_info, 0, 256 * 5);
-    flag_which_music_type = 0;
-    LoadOverworldSongs();
-  }
-}
-
-void GameOver_AnimateChoiceFairy() {  // 89f67a
-  SetOamPlain(&oam_buf[0x14], 0x34, kDeath_SprY0[subsubmodule_index], kDeath_SprChar0[frame_counter >> 3 & 1], 0x78, 2);
-}
-
-void GameOver_InitializeRevivalFairy() {  // 89f6a4
-  ConfigureRevivalAncillae();
-  link_hearts_filler = 56;
-  submodule_index += 1;
-  overworld_map_state = 0;
-}
-
-void RevivalFairy_Main_bounce() {  // 89f6b4
-  RevivalFairy_Main();
-}
-
-void GameOver_RiseALittle() {  // 89f6b9
-  if (link_hearts_filler == 0) {
-    memcpy(aux_palette_buffer, mapbak_palette, 256);
-    memset(main_palette_buffer + 32, 0, 192);
-    main_palette_buffer[0] = 0;
-    palette_filter_countdown = 0;
-    darkening_or_lightening_screen = 2;
-    WORD(CGWSEL_copy) = mapbak_CGWSEL;
-    submodule_index++;
-  }
-  RevivalFairy_Main();
-  Hud_RefillLogic();
-}
-
-void GameOver_Restore0D() {  // 89f71d
-  if (!is_doing_heart_animation) {
-    load_chr_halfslot_even_odd = 1;
-    Graphics_LoadChrHalfSlot();
-    Dungeon_ApproachFixedColor_variable(overworld_fixed_color_plusminus);
-    submodule_index++;
-  }
-  RevivalFairy_Main();
-  Hud_RefillLogic();
-}
-
-void GameOver_Restore0E() {  // 89f735
-  Graphics_LoadChrHalfSlot();
-  TS_copy = mapbak_TS;
-  submodule_index++;
-}
-
-void GameOver_ResituateLink() {  // 89f742
-  PaletteFilter_RestoreBGAdditiveStrict();
-  main_palette_buffer[0] = main_palette_buffer[32];
-  if (BYTE(palette_filter_countdown) != 32)
-    return;
-  if (!player_is_indoors)
-    Overworld_SetFixedColAndScroll();
-  TS_copy = mapbak_TS;
-  main_module_index = saved_module_for_menu;
-  submodule_index = 0;
-  countdown_for_blink = 144;
-  music_control = music_unk1_death;
-  sound_effect_ambient = sound_effect_ambient_last_death;
-  palette_filter_countdown = mapbak_bg1_x_offset;
-  darkening_or_lightening_screen = mapbak_bg1_y_offset;
-}
-
-void Module0E_0A_FluteMenu() {  // 8ab730
-  switch (overworld_map_state) {
-  case 0:
-    WorldMap_FadeOut();
-    break;
-  case 1:
-    birdtravel_var1[0] = 0;
-    WorldMap_LoadLightWorldMap();
-    break;
-  case 2:
-    WorldMap_LoadSpriteGFX();
-    break;
-  case 3:
-    WorldMap_Brighten();
-    break;
-  case 4:
-    some_menu_ctr = 0x10;
-    overworld_map_state++;
-    break;
-  case 5:
-    FluteMenu_HandleSelection();
-    break;
-  case 6:
-    WorldMap_RestoreGraphics();
-    break;
-  case 7:
-    FluteMenu_LoadSelectedScreen();
-    break;
-  case 8:
-    Overworld_LoadOverlayAndMap();
-    break;
-  case 9:
-    FluteMenu_FadeInAndQuack();
-    break;
-  default:
-    assert(0);
-  }
-}
-
-void FluteMenu_HandleSelection() {  // 8ab78b
-  Point16U pt;
-
-  if (some_menu_ctr == 0) {
-    if ((joypad1L_last | joypad1H_last) & 0xc0) {
-
-      if (enhanced_features0 & kFeatures0_CancelBirdTravel)
-        some_menu_ctr = joypad1L_last;
-
-      overworld_map_state++;
-      return;
-    }
-  } else {
-    some_menu_ctr--;
-  }
-  if (filtered_joypad_H & 10) {
-    birdtravel_var1[0]--;
-    sound_effect_2 = 32;
-  }
-  if (filtered_joypad_H & 5) {
-    birdtravel_var1[0]++;
-    sound_effect_2 = 32;
-  }
-  birdtravel_var1[0] = birdtravel_var1[0] & 7;
-  if (frame_counter & 0x10 && WorldMap_CalculateOamCoordinates(&pt))
-    WorldMap_AddSprite(16, 2, 0x3e, 0, pt.x - 4, pt.y - 4);
-
-  uint16 ybak = link_y_coord_spexit;
-  uint16 xbak = link_x_coord_spexit;
-  for (int i = 7; i >= 0; i--) {
-    bird_travel_x_lo[i] = kBirdTravel_x_lo[i];
-    bird_travel_x_hi[i] = kBirdTravel_x_hi[i];
-    link_x_coord_spexit = kBirdTravel_x_hi[i] << 8 | kBirdTravel_x_lo[i];
-
-    bird_travel_y_lo[i] = kBirdTravel_y_lo[i];
-    bird_travel_y_hi[i] = kBirdTravel_y_hi[i];
-    link_y_coord_spexit = kBirdTravel_y_hi[i] << 8 | kBirdTravel_y_lo[i];
-
-    if (WorldMap_CalculateOamCoordinates(&pt))
-      WorldMap_AddSprite(i, 0, (i == birdtravel_var1[0]) ? 0x30 + (frame_counter & 6) : 0x32, kBirdTravel_tab1[i], pt.x, pt.y);
-  }
-  link_x_coord_spexit = xbak;
-  link_y_coord_spexit = ybak;
-}
-
-void FluteMenu_LoadSelectedScreen() {  // 8ab8c5
-  save_ow_event_info[0x3b] &= ~0x20;
-  save_ow_event_info[0x7b] &= ~0x20;
-  save_dung_info[267] &= ~0x80;
-  save_dung_info[40] &= ~0x100;
-
-  // This is kFeatures0_CancelBirdTravel
-  if (!(some_menu_ctr & 0x40))
-    FluteMenu_LoadTransport();
-
-  FluteMenu_LoadSelectedScreenPalettes();
-  uint8 t = overworld_screen_index & 0xbf;
-  DecompressAnimatedOverworldTiles((t == 3 || t == 5 || t == 7) ? 0x58 : 0x5a);
-  Overworld_SetFixedColAndScroll();
-  overworld_palette_aux_or_main = 0;
-  hud_palette = 0;
-  InitializeTilesets();
-  overworld_map_state++;
-  BYTE(dung_draw_width_indicator) = 0;
-  Overworld_LoadOverlays2();
-  submodule_index--;
-  sound_effect_2 = 16;
-  uint8 m = overworld_music[BYTE(overworld_screen_index)];
-  sound_effect_ambient = m >> 4;
-  music_control = ZeldaIsPlayingMusicTrack(m & 0xf) ? 0xf3 : m & 0xf;
-}
-
-void Overworld_LoadOverlayAndMap() {  // 8ab948
-  uint16 bak1 = WORD(main_module_index);
-  uint16 bak2 = WORD(overworld_map_state);
-  Overworld_LoadAndBuildScreen();
-  WORD(overworld_map_state) = bak2 + 1;
-  WORD(main_module_index) = bak1;
-}
-
-void FluteMenu_FadeInAndQuack() {  // 8ab964
-  if (++INIDISP_copy == 15) {
-    BirdTravel_Finish_Doit();
-  } else {
-    Sprite_Main();
-  }
-}
-
-void BirdTravel_Finish_Doit() {  // 8ab96c
-  overworld_map_state = 0;
-  subsubmodule_index = 0;
-  main_module_index = saved_module_for_menu;
-  submodule_index = 0;
-  HDMAEN_copy = mapbak_HDMAEN;
-  AddBirdTravelSomething(0x27, 4);
-  Sprite_Main();
-}
-
-void Messaging_OverworldMap() {  // 8ab98b
-  switch (overworld_map_state) {
-  case 0:
-    WorldMap_FadeOut();
-    break;
-  case 1:
-    WorldMap_LoadLightWorldMap();
-    break;
-  case 2:
-    WorldMap_LoadDarkWorldMap();
-    break;
-  case 3:
-    WorldMap_LoadSpriteGFX();
-    break;
-  case 4:
-    WorldMap_Brighten();
-    break;
-  case 5:
-    WorldMap_PlayerControl();
-    break;
-  case 6:
-    WorldMap_RestoreGraphics();
-    break;
-  case 7:
-    WorldMap_ExitMap();
-    break;
-  }
-}
-
-void WorldMap_FadeOut() {  // 8ab9a3
-  if (--INIDISP_copy)
-    return;
-  mapbak_HDMAEN = HDMAEN_copy;
-  EnableForceBlank();
-  MOSAIC_copy = 3;
-  overworld_map_state++;
-  WORD(mapbak_TM) = WORD(TM_copy);
-  mapbak_BG1HOFS_copy2 = BG1HOFS_copy2;
-  mapbak_BG2HOFS_copy2 = BG2HOFS_copy2;
-  mapbak_BG1VOFS_copy2 = BG1VOFS_copy2;
-  mapbak_BG2VOFS_copy2 = BG2VOFS_copy2;
-  BG1HOFS_copy2 = BG2HOFS_copy2 = BG3HOFS_copy2 = 0;
-  BG1VOFS_copy2 = BG2VOFS_copy2 = BG3VOFS_copy2 = 0;
-  WORD(mapbak_CGWSEL) = WORD(CGWSEL_copy);
-  link_dma_graphics_index = 0x1fc;
-  if (BYTE(overworld_screen_index) < 0x80) {
-    link_y_coord_spexit = link_y_coord;
-    link_x_coord_spexit = link_x_coord;
-  }
-  if (sram_progress_indicator < 2) {
-    CGWSEL_copy = 0x80;
-    CGADSUB_copy = 0x61;
-  }
-  sound_effect_2 = 16;
-  sound_effect_ambient = 5;
-  music_control = 0xf2;
-  BGMODE_copy = 7;
-}
-
-void WorldMap_LoadLightWorldMap() {  // 8aba30
-  WorldMap_FillTilemapWithEF();
-  TM_copy = 0x11;
-  TS_copy = 0;
-  TransferMode7Characters();
-  WorldMap_SetUpHDMA();
-  LoadOverworldMapPalette();
-  LoadActualGearPalettes();
-  flag_update_cgram_in_nmi++;
-  nmi_subroutine_index = 7;
-  INIDISP_copy = 0;
-  nmi_disable_core_updates++;
-  overworld_map_state++;
-}
-
-void WorldMap_LoadDarkWorldMap() {  // 8aba7a
-  if (overworld_screen_index & 0x40) {
-    memcpy(&uvram, kDarkOverworldTilemap, 1024);
-    nmi_subroutine_index = 21;
-  }
-  overworld_map_state++;
-}
-
-void WorldMap_LoadSpriteGFX() {  // 8aba9a
-  load_chr_halfslot_even_odd = 0x10;
-  Graphics_LoadChrHalfSlot();
-  load_chr_halfslot_even_odd = 0;
-  overworld_map_state++;
-}
-
-void WorldMap_Brighten() {  // 8abaaa
-  if (++INIDISP_copy == 15)
-    overworld_map_state++;
-}
-
-bool DidPressButtonForMap() {
-  if (hud_cur_item_x != 0)
-    return filtered_joypad_H & 0x20;  // select
-  else
-    return filtered_joypad_L & 0x40;  // x
-}
-
-void WorldMap_PlayerControl() {  // 8abae6
-  if (overworld_map_flags & 0x80) {
-    overworld_map_flags &= ~0x80;
-    OverworldMap_SetupHdma();
-  }
-
-  if (!overworld_map_flags && DidPressButtonForMap()) { // X
-    // getout
-    overworld_map_state++;
-    return;
-  }
-  if (BYTE(dung_draw_width_indicator)) {
-    BYTE(dung_draw_width_indicator)--;
-  } else if (filtered_joypad_L & 0x30 || DidPressButtonForMap()) {
-    // next zoom level
-    sound_effect_2 = 36;
-    BYTE(dung_draw_width_indicator) = 8;
-
-    int t = overworld_map_flags ^ 1;
-    overworld_map_flags = t | 0x80;
-    timer_for_mode7_zoom = kOverworldMap_Timer[t];
-    if (timer_for_mode7_zoom == 12) {
-      BG1VOFS_copy2 = ((link_y_coord_spexit >> 4) - 0x48 & ~1);
-      M7Y_copy = BG1VOFS_copy2 + 0x100;
-      uint16 t0 = (link_x_coord_spexit >> 4) - 0x80;
-      uint16 t1 = (uint16)(5 * (sign16(t0) ? -t0 : t0)) >> 1;
-      uint16 t2 = sign16(t0) ? -t1 : t1;
-      BG1HOFS_copy2 = t2 + 0x80 & ~1;
-    } else {
-      BG1VOFS_copy2 = 200;
-      M7Y_copy = 200 + 256;
-      BG1HOFS_copy2 = 128;
-    }
-  }
-
-  if (overworld_map_flags) {
-    int k = (joypad1H_last & 12) >> 1;
-    if (BG1VOFS_copy2 != (uint16)kOverworldMap_Table2[k]) {
-      BG1VOFS_copy2 += kOverworldMap_Table3[k];
-      M7Y_copy = BG1VOFS_copy2 + 0x100;
-    }
-    k = (joypad1H_last & 3) * 2 + 1;
-    if (BG1HOFS_copy2 != (uint16)kOverworldMap_Table2[k])
-      BG1HOFS_copy2 += kOverworldMap_Table3[k];
-  }
-  WorldMap_HandleSprites();
-}
-
-void WorldMap_RestoreGraphics() {  // 8abbd6
-  if (--INIDISP_copy)
-    return;
-  EnableForceBlank();
-  overworld_map_state++;
-  memcpy(main_palette_buffer, aux_palette_buffer, 512);
-  WORD(CGWSEL_copy) = WORD(mapbak_CGWSEL);
-  BG3HOFS_copy2 = BG3VOFS_copy2 = 0;
-  BG1HOFS_copy2 = mapbak_BG1HOFS_copy2;
-  BG2HOFS_copy2 = mapbak_BG2HOFS_copy2;
-  BG1VOFS_copy2 = mapbak_BG1VOFS_copy2;
-  BG2VOFS_copy2 = mapbak_BG2VOFS_copy2;
-  WORD(TM_copy) = WORD(mapbak_TM);
-  Attract_SetUpConclusionHDMA();
-}
-
-void Attract_SetUpConclusionHDMA() {  // 8abc33
-  HdmaSetup(0xABDDD, 0xABDDD, 0x42, (uint8)M7A, (uint8)M7D, 0);
-  HDMAEN_copy = 0x80;
-  BGMODE_copy = 9;
-  nmi_disable_core_updates = 0;
-}
-
-void WorldMap_ExitMap() {  // 8abc54
-  overworld_palette_aux_or_main = 0;
-  hud_palette = 0;
-  InitializeTilesets();
-  flag_update_cgram_in_nmi++;
-  BYTE(dung_draw_width_indicator) = 0;
-  overworld_map_state = 0;
-  subsubmodule_index = 0;
-  main_module_index = saved_module_for_menu;
-  submodule_index = 32;
-  vram_upload_offset = 0;
-  HDMAEN_copy = mapbak_HDMAEN;
-  sound_effect_ambient = overworld_music[BYTE(overworld_screen_index)] >> 4;
-  sound_effect_2 = 0x10;
-  music_control = 0xf3;
-}
-
-void WorldMap_SetUpHDMA() {  // 8abc96
-  BG1HOFS_copy2 = 0x80;
-  BG1VOFS_copy2 = 0xc8;
-  M7Y_copy = 0x1c9;
-  M7X_copy = 0x100;
-  W12SEL_copy = 0;
-  W34SEL_copy = 0;
-  WOBJSEL_copy = 0;
-  TMW_copy = 0;
-  TSW_copy = 0;
-
-  if (main_module_index == 20) {
-    HdmaSetup(0xABDDD, 0xABDDD, 0x42, (uint8)M7A, (uint8)M7D, 0);
-    HDMAEN_copy = 0xc0;
-  } else if (submodule_index != 10) {
-    byte_7E0635 = 4;
-    timer_for_mode7_zoom = 12;
-    overworld_map_flags = 1;
-    BG1VOFS_copy2 = ((link_y_coord_spexit >> 4) - 0x48 & ~1);
-    M7Y_copy = BG1VOFS_copy2 + 0x100;
-    uint16 t0 = (link_x_coord_spexit >> 4) - 0x80;
-    uint16 t1 = (uint16)(5 * (sign16(t0) ? -t0 : t0)) >> 1;
-    uint16 t2 = sign16(t0) ? -t1 : t1;
-    BG1HOFS_copy2 = t2 + 0x80 & ~1;
-    OverworldMap_SetupHdma();
-    HDMAEN_copy = 0xc0;
-  } else {
-    byte_7E0635 = 4;
-    timer_for_mode7_zoom = 33;
-    overworld_map_flags = 0;
-    HdmaSetup(0xABDCF, 0xABDCF, 0x42, (uint8)M7A, (uint8)M7D, 10);
-    HDMAEN_copy = 0xc0;
-  }
-}
-
-void WorldMap_FillTilemapWithEF() {  // 8abda5
-  uint16 *dst = g_zenv.vram;
-  for (int i = 0; i != 0x4000; i++)
-    BYTE(dst[i]) = 0xef;
-}
-
-void WorldMap_HandleSprites() {  // 8abf66
-  Point16U pt;
-
-  if (frame_counter & 0x10 && WorldMap_CalculateOamCoordinates(&pt))
-    WorldMap_AddSprite(0, 2, 0x3e, 0, pt.x - 4, pt.y - 4);
-
-  uint16 ybak = link_y_coord_spexit;
-  uint16 xbak = link_x_coord_spexit;
-
-  int k = 15;
-  if (BYTE(overworld_screen_index) < 0x40 && (bird_travel_x_lo[k] | bird_travel_x_hi[k] | bird_travel_y_lo[k] | bird_travel_y_hi[k])) {
-    if (!frame_counter)
-      birdtravel_var1[k]++;
-    link_x_coord_spexit = bird_travel_x_hi[k] << 8 | bird_travel_x_lo[k];
-    link_y_coord_spexit = bird_travel_y_hi[k] << 8 | bird_travel_y_lo[k];
-    if (WorldMap_CalculateOamCoordinates(&pt))
-      WorldMap_AddSprite(15, 2, kOverworldMap_Table4[frame_counter >> 1 & 3], 0x6a, pt.x, pt.y);
-  }
-
-  if (save_ow_event_info[0x5b] & 0x20 || (((savegame_map_icons_indicator >= 6) ^ is_in_dark_world) & 1))
-    goto out;
-
-  k = savegame_map_icons_indicator;
-
-  if (!OverworldMap_CheckForPendant(0) && !OverworldMap_CheckForCrystal(0) && !sign16(kOwMapCrystal0_x[k])) {
-    link_x_coord_spexit = kOwMapCrystal0_x[k];
-    link_y_coord_spexit = kOwMapCrystal0_y[k];
-    uint8 t = kOwMapCrystal0_tab[k] >> 8;
-    if (t != 0) {
-      if (t != 100 && frame_counter & 0x10)
-        goto endif_crystal0;
-      link_x_coord_spexit -= 4, link_y_coord_spexit -= 4;
-    }
-    if (WorldMap_CalculateOamCoordinates(&pt)) {
-      uint16 info = kOwMapCrystal0_tab[k];
-      uint8 ext = 2;
-      if (!(info >> 8))
-        info = kOwMap_tab2[frame_counter >> 3 & 3] << 8 | 0x32, ext = 0;
-      WorldMap_AddSprite(14, ext, (uint8)info, (uint8)(info >> 8), pt.x, pt.y);
-    }
-  endif_crystal0:;
-  }
-
-  if (!OverworldMap_CheckForPendant(1) && !OverworldMap_CheckForCrystal(1) && !sign16(kOwMapCrystal1_x[k])) {
-    link_x_coord_spexit = kOwMapCrystal1_x[k];
-    link_y_coord_spexit = kOwMapCrystal1_y[k];
-    uint8 t = kOwMapCrystal1_tab[k] >> 8;
-    if (t != 0) {
-      if (t != 100 && frame_counter & 0x10)
-        goto endif_crystal1;
-      link_x_coord_spexit -= 4, link_y_coord_spexit -= 4;
-    }
-    if (WorldMap_CalculateOamCoordinates(&pt)) {
-      uint16 info = kOwMapCrystal1_tab[k];
-      uint8 ext = 2;
-      if (!(info >> 8))
-        info = kOwMap_tab2[frame_counter >> 3 & 3] << 8 | 0x32, ext = 0;
-      WorldMap_AddSprite(13, ext, (uint8)info, (uint8)(info >> 8), pt.x, pt.y);
-    }
-  endif_crystal1:;
-  }
-
-  if (!OverworldMap_CheckForPendant(2) && !OverworldMap_CheckForCrystal(2) && !sign16(kOwMapCrystal2_x[k])) {
-    link_x_coord_spexit = kOwMapCrystal2_x[k];
-    link_y_coord_spexit = kOwMapCrystal2_y[k];
-    uint8 t = kOwMapCrystal2_tab[k] >> 8;
-    if (t != 0) {
-      if (t != 100 && frame_counter & 0x10)
-        goto endif_crystal2;
-      link_x_coord_spexit -= 4, link_y_coord_spexit -= 4;
-    }
-    if (WorldMap_CalculateOamCoordinates(&pt)) {
-      uint16 info = kOwMapCrystal2_tab[k];
-      uint8 ext = 2;
-      if (!(info >> 8))
-        info = kOwMap_tab2[frame_counter >> 3 & 3] << 8 | 0x32, ext = 0;
-      WorldMap_AddSprite(12, ext, (uint8)info, (uint8)(info >> 8), pt.x, pt.y);
-    }
-  endif_crystal2:;
-  }
-
-  if (!OverworldMap_CheckForCrystal(3) && !sign16(kOwMapCrystal3_x[k])) {
-    link_x_coord_spexit = kOwMapCrystal3_x[k];
-    link_y_coord_spexit = kOwMapCrystal3_y[k];
-    uint8 t = kOwMapCrystal3_tab[k] >> 8;
-    if (t != 0) {
-      if (t != 100 && frame_counter & 0x10)
-        goto endif_crystal3;
-      link_x_coord_spexit -= 4, link_y_coord_spexit -= 4;
-    }
-    if (WorldMap_CalculateOamCoordinates(&pt)) {
-      uint16 info = kOwMapCrystal3_tab[k];
-      uint8 ext = 2;
-      if (!(info >> 8))
-        info = kOwMap_tab2[frame_counter >> 3 & 3] << 8 | 0x32, ext = 0;
-      WorldMap_AddSprite(11, ext, (uint8)info, (uint8)(info >> 8), pt.x, pt.y);
-    }
-  endif_crystal3:;
-  }
-
-  if (!OverworldMap_CheckForCrystal(4) && !sign16(kOwMapCrystal4_x[k])) {
-    link_x_coord_spexit = kOwMapCrystal4_x[k];
-    link_y_coord_spexit = kOwMapCrystal4_y[k];
-    uint8 t = kOwMapCrystal4_tab[k] >> 8;
-    if (t != 0) {
-      if (t != 100 && frame_counter & 0x10)
-        goto endif_crystal4;
-      link_x_coord_spexit -= 4, link_y_coord_spexit -= 4;
-    }
-    if (WorldMap_CalculateOamCoordinates(&pt)) {
-      uint16 info = kOwMapCrystal4_tab[k];
-      uint8 ext = 2;
-      if (!(info >> 8))
-        info = kOwMap_tab2[frame_counter >> 3 & 3] << 8 | 0x32, ext = 0;
-      WorldMap_AddSprite(10, ext, (uint8)info, (uint8)(info >> 8), pt.x, pt.y);
-    }
-  endif_crystal4:;
-  }
-
-  if (!OverworldMap_CheckForCrystal(5) && !sign16(kOwMapCrystal5_x[k])) {
-    link_x_coord_spexit = kOwMapCrystal5_x[k];
-    link_y_coord_spexit = kOwMapCrystal5_y[k];
-    uint8 t = kOwMapCrystal5_tab[k] >> 8;
-    if (t != 0) {
-      if (t != 100 && frame_counter & 0x10)
-        goto endif_crystal5;
-      link_x_coord_spexit -= 4, link_y_coord_spexit -= 4;
-    }
-    if (WorldMap_CalculateOamCoordinates(&pt)) {
-      uint16 info = kOwMapCrystal5_tab[k];
-      uint8 ext = 2;
-      if (!(info >> 8))
-        info = kOwMap_tab2[frame_counter >> 3 & 3] << 8 | 0x32, ext = 0;
-      WorldMap_AddSprite(9, ext, (uint8)info, (uint8)(info >> 8), pt.x, pt.y);
-    }
-  endif_crystal5:;
-  }
-
-  if (!OverworldMap_CheckForCrystal(6) && !sign16(kOwMapCrystal6_x[k])) {
-    link_x_coord_spexit = kOwMapCrystal6_x[k];
-    link_y_coord_spexit = kOwMapCrystal6_y[k];
-    uint8 t = kOwMapCrystal6_tab[k] >> 8;
-    if (t != 0) {
-      if (t != 100 && frame_counter & 0x10)
-        goto endif_crystal6;
-      link_x_coord_spexit -= 4, link_y_coord_spexit -= 4;
-    }
-    if (WorldMap_CalculateOamCoordinates(&pt)) {
-      uint16 info = kOwMapCrystal6_tab[k];
-      uint8 ext = 2;
-      if (!(info >> 8))
-        info = kOwMap_tab2[frame_counter >> 3 & 3] << 8 | 0x32, ext = 0;
-      WorldMap_AddSprite(8, ext, (uint8)info, (uint8)(info >> 8), pt.x, pt.y);
-    }
-  endif_crystal6:;
-  }
-
-out:
-  link_x_coord_spexit = xbak;
-  link_y_coord_spexit = ybak;
-}
-
-static bool WorldMap_CalculateOamCoordinates(Point16U *pt) {  // 8ac39f
-  if (overworld_map_flags == 0) {
-    int j = -(link_y_coord_spexit >> 4) + M7Y_copy + (link_y_coord_spexit >> 3 & 1) - 0xc0;
-    uint8 t0 = kOverworldMap_tab1[j];
-    uint8 yval = 13 * t0 >> 4;
-
-    uint8 at = link_x_coord_spexit >> 4;
-    bool below = at < 0x80;
-    at -= 0x80;
-    if (sign8(at)) at = ~at;
-
-    uint8 t1 = ((yval < 224 ? yval : 0) * 0x54 >> 8) + 0xb2;
-    uint8 t2 = at * t1 >> 8;
-    uint8 t3 = (below) ? 0x80 - t2 : t2 + 0x80;
-
-    pt->x = t3 - BG1HOFS_copy2 + 0x80;
-    pt->y = yval + 12;
-    return true;
-  } else {
-    uint16 t0 = -(link_y_coord_spexit >> 4) + M7Y_copy - 0x80;
-    if (t0 >= 0x100)
-      return false;
-    uint16 t1 = t0 * 37 >> 4;
-    if (t1 >= 333)
-      return false;
-    uint8 yval = kOverworldMap_tab1[t1];
-    uint16 t2 = link_x_coord_spexit;
-    bool below = t2 < 0x7F8;
-    t2 -= 0x7f8;
-    if (sign16(t2))
-      t2 = -t2;
-    uint8 t3 = yval < 226 ? yval : 0;
-    uint8 t4 = (t3 * 84 >> 8) + 178;  // r0
-    uint8 t5 = (uint8)t2 * t4 >> 8; // r1
-    uint16 t6 = (uint8)(t2 >> 8) * t4 + t5;
-    uint16 t7 = (below) ? 0x800 - t6 : t6 + 0x800;
-    bool below2 = t7 < 0x800;
-    t7 -= 0x800;
-    uint16 t8 = below2 ? -t7 : t7;
-    uint8 t9 = (uint8)t8 * 45 >> 8;
-    uint16 t10 = ((t8 >> 8) * 45) + t9;
-    uint16 t11 = below2 ? 0x80 - t10 : t10 + 0x80;
-    uint16 xval = t11 - BG1HOFS_copy2;
-    int xt = enhanced_features0 & kFeatures0_ExtendScreen64 ? 0x48 : 0;
-    if ((uint16)(xval + 0x80 + xt) >= (0x100 + xt * 2))
-      return false;
-    pt->x = xval + 0x81;
-    pt->y = yval + 16;
-    return true;
-  }
-}
-
-static void WorldMap_AddSprite(int spr, uint8 big, uint8 flags, uint8 ch, uint16 x, uint16 y) {  // 8ac51c
-  if (!(frame_counter & 0x10) && ch == 100) {
-    assert(spr >= 8);
-    ch = kOverworldMapData[spr - 8];
-    flags = 0x32;
-    big = 0;
-  } else {
-    x -= 4;
-    y -= 4;
-  }
-  if (enhanced_features0 & kFeatures0_ExtendScreen64)
-    big |= (x >> 8 & 1);
-  SetOamPlain(&oam_buf[spr], x, y, ch, flags, big);
-}
-
-bool OverworldMap_CheckForPendant(int k) {  // 8ac5a9
-  return (savegame_map_icons_indicator == 3) && (link_which_pendants & kPendantBitMask[k]) != 0;
-}
-
-bool OverworldMap_CheckForCrystal(int k) {  // 8ac5c6
-  return (savegame_map_icons_indicator == 7) && (link_has_crystals & kCrystalBitMask[k]) != 0;
-}
-
-void Module0E_03_DungeonMap() {  // 8ae0b0
-  kDungMapSubmodules[overworld_map_state]();
-}
-
-void Module0E_03_01_DrawMap() {  // 8ae0dc
-  kDungMapInit[dungmap_init_state]();
-}
-
-void Module0E_03_01_00_PrepMapGraphics() {  // 8ae0e4
-  uint8 hdmaen_bak = HDMAEN_copy;
-  HDMAEN_copy = 0;
-  mapbak_main_tile_theme_index = main_tile_theme_index;
-  mapbak_sprite_graphics_index = sprite_graphics_index;
-  mapbak_aux_tile_theme_index = aux_tile_theme_index;
-  mapbak_TM = TM_copy;
-  mapbak_TS = TS_copy;
-  main_tile_theme_index = 32;
-  sprite_graphics_index = 0x80 | BYTE(cur_palace_index_x2) >> 1;
-  aux_tile_theme_index = 64;
-  TM_copy = 0x16;
-  TS_copy = 1;
-  EraseTileMaps_dungeonmap();
-  InitializeTilesets();
-  overworld_palette_aux_or_main = 0x200;
-  Palette_Load_DungeonMapBG();
-  Palette_Load_DungeonMapSprite();
-  hud_palette = 1;
-  Palette_Load_HUD();
-  LoadActualGearPalettes();
-  flag_update_cgram_in_nmi++;
-  dungmap_init_state++;
-  HDMAEN_copy = hdmaen_bak;
-  nmi_load_bg_from_vram = 9;
-  nmi_disable_core_updates = 9;
-}
-
-void Module0E_03_01_01_DrawLEVEL() {  // 8ae1a4
-  // Display FLOOR instead of MAP
-  int i = kDungMap_Tab0[cur_palace_index_x2 >> 1] >> 1;
-  if (i >= 0) {
-    uint8 *dst = (uint8 *)&vram_upload_data[0];
-    dst[32] = 0xff;
-    WORD(dst[14   ]) = kDungMap_Tab1[i];
-    WORD(dst[14+16]) = kDungMap_Tab2[i];
-    for (int i = 13; i >= 0; i--) {
-      dst[i] = kDungMap_Tab3[i];
-      dst[i+16] = kDungMap_Tab4[i];
-    }
-    nmi_load_bg_from_vram = 1;
-  }
-  dungmap_init_state++;
-}
-
-void Module0E_03_01_02_DrawFloorsBackdrop() {  // 8ae1f3
-  int offs = 0;
-  uint16 t5 = kDungMap_Tab5[cur_palace_index_x2 >> 1];
-  if (t5 & 0x100) {
-    for (int i = 0; i < 21; i++)
-      vram_upload_data[offs++] = kDungMap_Tab6[i];
-    uint16 t = 0x1123;
-    for (int i = 0; i < 16; i++, t += 0x20, offs += 3) {
-      vram_upload_data[offs + 0] = swap16(t);
-      vram_upload_data[offs + 1] = 0xE40;
-      vram_upload_data[offs + 2] = 0x1B2E;
-    }
-  }
-  int t7 = kDungMap_Tab7[(uint8)t5 >= 0x50 ? (((uint8)t5 >> 4) - 4) : (t5 & 0xf) >= 5 ? (t5 & 0xf) : 0], t7_org = t7;
-  int j = 0;
-  do {
-    vram_upload_data[offs++] = swap16(t7);
-    vram_upload_data[offs++] = 0xe40;
-    vram_upload_data[offs++] = kDungMap_Tab8[j] + (t5 & 0x200 ? 0x400 : 0);
-    j += (j != 6);
-  } while (t7 += 0x20, t7 < 0x1360);
-  vram_upload_offset = offs * 2;
-  DungeonMap_BuildFloorListBoxes(t5, t7_org);
-  ((uint8 *)vram_upload_data)[vram_upload_offset] = 0xff;
-  dungmap_init_state++;
-  nmi_load_bg_from_vram = 1;
-}
-
-void DungeonMap_BuildFloorListBoxes(uint8 t5, uint16 r14) {  // 8ae2f5
-  int n = (t5 & 0xf) + (t5 >> 4);
-  r14 -= 0x40 - 2;
-  r14 += (t5 & 0xf) * 0x40;
-  int offs = vram_upload_offset >> 1;
-  int i = 0;
-  do {
-    int x = 0;
-loop2:
-    vram_upload_data[offs++] = swap16(r14);
-    vram_upload_data[offs++] = 0x700;
-    do {
-      vram_upload_data[offs++] = kDungMap_Tab9[x++];
-      if (x == 4) {
-        r14 += 0x20;
-        goto loop2;
-      }
-    } while (x != 8);
-
-    r14 -= 0x40 + 0x20;
-  } while (++i < n);
-  vram_upload_offset = offs * 2;
-}
-
-void Module0E_03_01_03_DrawRooms() {  // 8ae384
-  dungmap_var2 = 0;
-  dungmap_idx = 0;
-  uint8 t = -(kDungMap_Tab5[cur_palace_index_x2 >> 1] & 0xf);
-  if (WORD(dung_cur_floor) != t) {
-    dungmap_cur_floor = dung_cur_floor;
-  } else {
-    dungmap_cur_floor = WORD(dung_cur_floor) + 1;
-    dungmap_idx += 2;
-  }
-  DungeonMap_DrawFloorNumbersByRoom(0, ~0x1000);
-  DungeonMap_DrawBorderForRooms(0, ~0x1000);
-  DungeonMap_DrawDungeonLayout(0);
-  BYTE(dungmap_cur_floor)--;
-  DungeonMap_DrawFloorNumbersByRoom(0x300, ~0x1000);
-  DungeonMap_DrawBorderForRooms(0x300, ~0x1000);
-  DungeonMap_DrawDungeonLayout(0x300);
-  dungmap_cur_floor++;
-  WORD(g_ram[6]) = 0;
-  WORD(g_ram[10]) = 0;
-  nmi_subroutine_index = 8;
-  BYTE(nmi_load_target_addr) = 0x22;
-  dungmap_init_state++;
-}
-
-void DungeonMap_DrawBorderForRooms(uint16 pd, uint16 mask) {  // 8ae449
-  for (int i = 0; i != 4; i++)
-    messaging_buf[((kDungMap_Tab10[i] + pd) & 0xfff) >> 1] = kDungMap_Tab11[i] & mask;
-  for (int i = 0; i != 2; i++) {
-    int r4 = kDungMap_Tab12[i] + pd;
-    for (int j = 0; j != 20; j+=2)
-      messaging_buf[((r4 + j) & 0xfff) >> 1] = kDungMap_Tab13[i] & mask;
-  }
-
-  for (int i = 0; i != 2; i++) {
-    int r4 = kDungMap_Tab14[i] + pd;
-    for (int j = 0; j != 0x280; j+=0x40)
-      messaging_buf[((r4 + j) & 0xfff) >> 1] = kDungMap_Tab15[i] & mask;
-  }
-}
-
-void DungeonMap_DrawFloorNumbersByRoom(uint16 pd, uint16 r8) {  // 8ae4f9
-  uint16 p = 0xDE;
-  do {
-    int t = ((p + pd) & 0xfff) >> 1;
-    messaging_buf[t] = 0xf00;
-    messaging_buf[t+1] = 0xf00;
-  } while (p += 0x40, p != 0x39e);
-  int t = ((0x35e + pd) & 0xfff) >> 1;
-  uint16 q1 = (dungmap_cur_floor & 0x80) ? 0x1F1C : kDungMap_Tab16[dungmap_cur_floor & 0xf];
-  uint16 q2 = (dungmap_cur_floor & 0x80) ? kDungMap_Tab16[(uint8)~dungmap_cur_floor] : 0x1F1D;
-  messaging_buf[t+0] = q1 & r8;
-  messaging_buf[t+1] = q2 & r8;
-}
-
-void DungeonMap_DrawDungeonLayout(int pd) {  // 8ae579
-  for (int i = 0; i < 5; i++)
-    DungeonMap_DrawSingleRowOfRooms(i, ((292 + 128 * i + pd) & 0xfff) >> 1);
-}
-
-void DungeonMap_DrawSingleRowOfRooms(int i, int arg_x) {  // 8ae5bc
-  uint16 t5 = kDungMap_Tab5[cur_palace_index_x2 >> 1];
-  int dungmask = kUpperBitmasks[cur_palace_index_x2 >> 1];
-
-  for (int j = 0; j < 5; j++, arg_x += 2) {
-    int r14 = (uint8)(dungmap_cur_floor + (t5 & 0xf));
-    const uint8 *curp = GetDungmapFloorLayout();
-    uint8 v = curp[r14 * 25 + i * 5 + j];
-    uint16 yv, av;
-    if (v == 0xf) {
-      yv = 0x51;
-    } else {
-      r14 = save_dung_info[v] & 0xf;
-      int k = 0, count = 0;
-      for(; curp[k] != v; k++)
-        count += (curp[k] != 0xf);
-      yv = GetOtherDungmapInfo(count);
-    }
-
-    uint16 r12 = kDungMap_Tab23[yv * 4 + 0], r12_org = r12;
-    if (r12 != 0xB00 && (r14 & 8) == 0) {
-      if (!(r12 & 0x1000)) {
-        r12 = 0x400;
-      } else if (link_dungeon_map & dungmask) {
-        av = (r12 & ~0x1c00) | 0xc00;
-        goto write_3;
-      } else {
-        r12 = 0;
-      }
-    } else {
-      r12 = 0;
-    }
-    av = ((link_dungeon_map & dungmask) || (r14 & 8)) ? r12 + r12_org : 0xb00;
-  write_3:
-    messaging_buf[arg_x] = av;
-
-    r12 = kDungMap_Tab23[yv * 4 + 1], r12_org = r12;
-    if (r12 != 0xB00 && (r14 & 4) == 0) {
-      if (!(r12 & 0x1000)) {
-        r12 = 0x400;
-      } else if (link_dungeon_map & dungmask) {
-        av = (r12 & ~0x1c00) | 0xc00;
-        goto write_4;
-      } else {
-        r12 = 0;
-      }
-    } else {
-      r12 = 0;
-    }
-    av = ((link_dungeon_map & dungmask) || (r14 & 4)) ? r12 + r12_org : 0xb00;
-  write_4:
-    messaging_buf[arg_x + 1] = av;
-
-    r12 = kDungMap_Tab23[yv * 4 + 2], r12_org = r12;
-    if (r12 != 0xB00 && (r14 & 2) == 0) {
-      if (!(r12 & 0x1000)) {
-        r12 = 0x400;
-      } else if (link_dungeon_map & dungmask) {
-        av = (r12 & ~0x1c00) | 0xc00;
-        goto write_5;
-      } else {
-        r12 = 0;
-      }
-    } else {
-      r12 = 0;
-    }
-    av = ((link_dungeon_map & dungmask) || (r14 & 2)) ? r12 + r12_org : 0xb00;
-  write_5:
-    messaging_buf[arg_x + 32] = av;
-
-    r12 = kDungMap_Tab23[yv * 4 + 3], r12_org = r12;
-    if (r12 != 0xB00 && (r14 & 1) == 0) {
-      if (!(r12 & 0x1000)) {
-        r12 = 0x400;
-      } else if (link_dungeon_map & dungmask) {
-        av = (r12 & ~0x1c00) | 0xc00;
-        goto write_6;
-      } else {
-        r12 = 0;
-      }
-    } else {
-      r12 = 0;
-    }
-    av = ((link_dungeon_map & dungmask) || (r14 & 1)) ? r12 + r12_org : 0xb00;
-  write_6:
-    messaging_buf[arg_x + 33] = av;
-  }
-}
-
-void DungeonMap_DrawRoomMarkers() {  // 8ae823
-  int dung = cur_palace_index_x2 >> 1;
-  uint8 t5 = (kDungMap_Tab5[dung] & 0xf);
-  uint8 floor1 = t5 + dung_cur_floor;
-
-  uint16 room = dungeon_room_index;
-  for (int i = 0; i != 3; i++) {
-    if (room == kDungMap_Tab21[i])
-      room = kDungMap_Tab22[i];
-  }
-  const uint8 *roomp = GetDungmapFloorLayout();
-  const uint8 *curp = &roomp[floor1 * 25];
-  int i;
-
-  uint8 xcoord = 0, ycoord = 0;
-  for(i = 0; i < 25 && *curp++ != (uint8)room; i++) {
-    if (xcoord < 64)
-      xcoord += 16;
-    else
-      xcoord = 0, ycoord += 16;
-  }
-  dungmap_var3 = xcoord + 0x90;
-  dungmap_var3 += (link_x_coord & 0x1e0) >> 5;
-
-  dungmap_var6 = ycoord;
-
-  dungmap_var5 = ycoord + kDungMap_Tab24[dungmap_idx >> 1];
-  dungmap_var5 += (link_y_coord & 0x1e0) >> 5;
-
-  uint8 floor2 = t5 + kDungMap_Tab28[dung];
-  curp = &roomp[floor2 * 25];
-
-  dungmap_var8 = dungmap_var7 = 0x40;
-
-  uint8 lookfor = kDungMap_Tab25[dung];
-  for (int j = 24; j >= 0; j--) {
-    if (curp[j] != 0xf && curp[j] == lookfor)
-      break;
-    if ((int16)(dungmap_var7 -= 0x10) < 0) {
-      dungmap_var7 = 0x40;
-      BYTE(dungmap_var8) -= 0x10;
-    }
-  }
-
-  int8 floor3 = dungmap_cur_floor - kDungMap_Tab28[dung];
-  dungmap_var8 += 0x60 * floor3;
-  dungmap_var8 += kDungMap_Tab24[0];
-  overworld_map_state++;
-  INIDISP_copy = 0;
-  dungmap_init_state = 0;
-}
-
-void DungeonMap_HandleInputAndSprites() {  // 8ae954
-  DungeonMap_HandleInput();
-  DungeonMap_DrawSprites();
-}
-
-static inline bool WantExitDungeonMap() {
-  if (hud_cur_item_x != 0)
-    return filtered_joypad_H & 0x20;  // Select
-  else
-    return filtered_joypad_L & 0x40;  // X
-}
-
-void DungeonMap_HandleInput() {  // 8ae95b
-  if (WantExitDungeonMap()) {
-    overworld_map_state += 2;
-    dungmap_init_state = 0;
-  } else {
-    DungeonMap_HandleMovementInput();
-  }
-}
-
-void DungeonMap_HandleMovementInput() {  // 8ae979
-  DungeonMap_HandleFloorSelect();
-  if (dungmap_var2)
-    DungeonMap_ScrollFloors();
-}
-
-void DungeonMap_HandleFloorSelect() {  // 8ae986
-  uint8 r2 = (kDungMap_Tab5[cur_palace_index_x2 >> 1] >> 4 & 0xf);
-  uint8 r3 = (kDungMap_Tab5[cur_palace_index_x2 >> 1] & 0xf);
-  if (r2 + r3 < 3 || dungmap_var2 || !(joypad1H_last & 0xc))
-    return;
-  dungmap_cur_floor &= 0xff;
-  uint16 r6 = WORD(g_ram[6]);
-  if (joypad1H_last & 8) {
-    if (r2 - 1 == dungmap_cur_floor)
-      return;
-    dungmap_cur_floor++;
-    r6 = (r6 - 0x300) & 0xfff;
-  } else {
-    if ((uint8)(-r3 + 1) == dungmap_cur_floor)
-      return;
-    dungmap_cur_floor -= 2;
-    r6 = (r6 + 0x600) & 0xfff;
-  }
-  DungeonMap_DrawFloorNumbersByRoom(r6, ~0x1000);
-  DungeonMap_DrawBorderForRooms(r6, ~0x1000);
-  DungeonMap_DrawDungeonLayout(r6);
-  dungmap_var2++;
-  WORD(g_ram[10]) = joypad1H_last;
-  int x = joypad1H_last >> 3 & 1;
-  dungmap_var4 = BG2VOFS_copy2 + kDungMap_Tab26[x];
-  if (!x) {
-    r6 = (r6 - 0x300) & 0xfff;
-    dungmap_cur_floor++;
-  }
-  WORD(g_ram[6]) = r6;
-  nmi_subroutine_index = 8;
-}
-
-void DungeonMap_ScrollFloors() {  // 8aea7f
-  int x = WORD(g_ram[10]) >> 3 & 1;
-  dungmap_var5 += kDungMap_Tab39[x];
-  dungmap_var8 += kDungMap_Tab39[x];
-  BG2VOFS_copy2 += kDungMap_Tab40[x];
-  if (BG2VOFS_copy2 == dungmap_var4)
-    dungmap_var2 = 0;
-}
-
-void DungeonMap_DrawSprites() {  // 8aeab2
-  int dung = cur_palace_index_x2 >> 1;
-  uint8 r2 = (kDungMap_Tab5[dung] & 0xf);
-  uint8 floor = r2 + dung_cur_floor;
-
-  int spr_pos = 0;
-  uint8 r14 = 0;
-  DungeonMap_DrawLinkPointing(spr_pos++, r2, floor);
-  do {
-    spr_pos = DungeonMap_DrawLocationMarker(spr_pos, r14);
-    r14 += 1;
-  } while (spr_pos != 9);
-  spr_pos = DungeonMap_DrawBlinkingIndicator(spr_pos);
-  spr_pos = DungeonMap_DrawBossIcon(spr_pos);
-  spr_pos = DungeonMap_DrawFloorNumberObjects(spr_pos);
-  DungeonMap_DrawFloorBlinker();
-}
-
-void DungeonMap_DrawLinkPointing(int spr_pos, uint8 r2, uint8 r3) {  // 8aeaf0
-  int dung = cur_palace_index_x2 >> 1;
-  uint8 t5 = kDungMap_Tab5[dung];
-  if (4 - r2 >= 0) {
-    r3 += 4 - r2;
-    int8 a = (t5 >> 4) - 4;
-    if (a >= 0)
-      r3 -= a;
-  }
-  SetOamPlain(&oam_buf[spr_pos], 0x19, kDungMap_Tab33[r3] - 4, 0, palette_swap_flag ? 0x30 : 0x3e, 2);
-}
-
-int DungeonMap_DrawBlinkingIndicator(int spr_pos) {  // 8aeb50
-  SetOamPlain(&oam_buf[spr_pos], dungmap_var3 - 3, ((dungmap_var5 < 256) ? dungmap_var5 : 0xf0) - 3, 0x34, kDungMap_Tab38[frame_counter >> 2 & 3], 0);
-  return spr_pos + 1;
-}
-
-int DungeonMap_DrawLocationMarker(int spr_pos, uint16 r14) {  // 8aeba8
-  for (int i = 3; i >= 0; i--, spr_pos++) {
-    uint8 r15 = dungmap_var6 + kDungMap_Tab24[r14];
-    int fr = (frame_counter >> 2) & 1;
-    if ((dungmap_var5 + 1 & 0xf0) == r15 + 1 && dungmap_var5 < 256)
-      fr += 2;
-    SetOamPlain(&oam_buf[spr_pos], kDungMap_Tab29[i] + (dungmap_var3 & 0xf0),
-                r15 + kDungMap_Tab30[i],
-                0, kDungMap_Tab32[fr] | kDungMap_Tab31[i], 2);
-  }
-  return spr_pos;
-}
-
-int DungeonMap_DrawFloorNumberObjects(int spr_pos) {  // 8aec0a
-  uint8 r2 = (kDungMap_Tab5[cur_palace_index_x2 >> 1] >> 4 & 0xf);
-  uint8 r3 = (kDungMap_Tab5[cur_palace_index_x2 >> 1] & 0xf);
-  uint8 yv = 7;
-  if (r2 + r3 != 8 && r2 < 4) {
-    yv = 6;
-    for (int i = 3; i != 0 && i != r2; i--)
-      yv--;
-    if (r3 >= 5) {
-      for (int i = 5; i != r3 && r3 != 8; i++)
-        yv++;
-    }
-  }
-
-  uint8 r4 = kDungMap_Tab33[yv] + 1;
-  r2--;
-  r3 = -r3;
-  do {
-    SetOamPlain(&oam_buf[spr_pos + 0], 0x30, r4, sign8(r2) ? 0x1c : kDungMap_Tab34[r2], 0x3d, 0);
-    SetOamPlain(&oam_buf[spr_pos + 1], 0x38, r4, sign8(r2) ? kDungMap_Tab34[r2 ^ 0xff] : 0x1d, 0x3d, 0);
-    r4 += 16;
-  } while (spr_pos += 2, r2-- != r3);
-  return spr_pos;
-}
-
-void DungeonMap_DrawFloorBlinker() {  // 8aeccf
-  uint8 floor = dungmap_cur_floor;
-  uint8 t5 = kDungMap_Tab5[cur_palace_index_x2 >> 1];
-  uint8 flag = ((t5 >> 4 & 0xf) + (t5 & 0xf) != 1);
-  floor -= flag;
-  uint8 r0;
-  uint8 i = flag;
-  do {
-    r0 = floor + (t5 & 0xf);
-    int8 a = 4 - (t5 & 0xf);
-    if (a >= 0) {
-      r0 += a;
-      a = (t5 >> 4) - 4;
-      if (a >= 0)
-        r0 -= a;
-    }
-    floor += 1;
-  } while (i--);
-  if (!(frame_counter & 0x10))
-    return;
-  uint8 y = kDungMap_Tab33[r0] - 4;
-  do {
-    uint8 x = 40;
-    int spr_pos = 0x40 + kDungMap_Tab35[flag];
-    for (int i = 3; i >= 0; i--, spr_pos++) {
-      uint8 t = 0x3d | (i ? 0 : 0x40);
-      SetOamPlain(&oam_buf[spr_pos + 0], x, y + flag * 16 + 0, kDungMap_Tab36[i], t, 0);
-      SetOamPlain(&oam_buf[spr_pos + 4], x, y + flag * 16 + 8, kDungMap_Tab36[i], t | 0x80, 0);
-      x += 8;
-    }
-  } while (flag--);
-}
-
-int DungeonMap_DrawBossIcon(int spr_pos) {  // 8aede4
-  int dung = cur_palace_index_x2 >> 1;
-  if (save_dung_info[kDungMap_Tab25[dung]] & 0x800 || !(link_compass & kUpperBitmasks[dung]) || kDungMap_Tab28[dung] < 0)
-    return spr_pos;
-  spr_pos = DungeonMap_DrawBossIconByFloor(spr_pos);
-  if ((frame_counter & 0xf) >= 10)
-    return spr_pos;
-  uint16 xy = kDungMap_Tab37[dung];
-  SetOamPlain(&oam_buf[spr_pos], (xy >> 8) + dungmap_var7 + 0x90, (dungmap_var8 < 256) ? xy + dungmap_var8 : 0xf0, 0x31, 0x33, 0);
-  return spr_pos + 1;
-}
-
-int DungeonMap_DrawBossIconByFloor(int spr_pos) {  // 8aee95
-  int dung = cur_palace_index_x2 >> 1;
-  uint8 t5 = kDungMap_Tab5[dung];
-  uint8 r2 = t5 & 0xf;
-  uint8 r3 = r2 + kDungMap_Tab28[dung];
-  if (4 - r2 >= 0) {
-    r3 += 4 - r2;
-    int8 a = (t5 >> 4) - 4;
-    if (a >= 0)
-      r3 -= a;
-  }
-  if ((frame_counter & 0xf) >= 10)
-    return spr_pos;
-  SetOamPlain(&oam_buf[spr_pos], 0x4c, kDungMap_Tab33[r3], 0x31, 0x33, 0);
-  return spr_pos + 1;
-}
-
-void DungeonMap_RecoverGFX() {  // 8aef19
-  uint8 hdmaen_bak = HDMAEN_copy;
-  HDMAEN_copy = 0;
-  EraseTileMaps_normal();
-
-  TM_copy = mapbak_TM;
-  TS_copy = mapbak_TS;
-  main_tile_theme_index = mapbak_main_tile_theme_index;
-  sprite_graphics_index = mapbak_sprite_graphics_index;
-  aux_tile_theme_index = mapbak_aux_tile_theme_index;
-  InitializeTilesets();
-  overworld_palette_aux_or_main = 0;
-  hud_palette = 0;
-  Hud_Rebuild();
-
-  overworld_screen_transition = 0;
-  dung_cur_quadrant_upload = 0;
-  do {
-    WaterFlood_BuildOneQuadrantForVRAM();
-    NMI_UploadTilemap();
-    Dungeon_PrepareNextRoomQuadrantUpload();
-    NMI_UploadTilemap();
-  } while (dung_cur_quadrant_upload != 0x10);
-
-  nmi_subroutine_index = 0;
-  subsubmodule_index = 0;
-  HDMAEN_copy = hdmaen_bak;
-
-  memcpy(main_palette_buffer, mapbak_palette, sizeof(uint16) * 256);
-  COLDATA_copy0 |= overworld_fixed_color_plusminus;
-  COLDATA_copy1 |= overworld_fixed_color_plusminus;
-  COLDATA_copy2 |= overworld_fixed_color_plusminus;
-
-  sound_effect_2 = 16;
-  music_control = 0xf3;
-  RecoverPegGFXFromMapping();
-  flag_update_cgram_in_nmi++;
-  overworld_map_state++;
-  INIDISP_copy = 0;
-  nmi_disable_core_updates = 0;
-}
-
-void ToggleStarTilesAndAdvance() {  // 8aefc9
-  Dungeon_RestoreStarTileChr();
-  overworld_map_state++;
-}
-
-void Death_InitializeGameOverLetters() {  // 8afe20
-  flag_for_boomerang_in_place = 0;
-  for (int i = 0; i < 8; i++) {
-    ancilla_x_lo[i] = 0xb0;
-    ancilla_x_hi[i] = 0;
-  }
-  ancilla_type[0] = 1;
-  hookshot_effect_index = 6;
-}
-
-void CopySaveToWRAM() {  // 8ccfbb
-  int k = 0xf;
-  bird_travel_x_hi[k] = 0;
-  bird_travel_y_hi[k] = 0;
-  bird_travel_x_lo[k] = 0;
-  bird_travel_y_lo[k] = 0;
-  birdtravel_var1[k] = 0;
-
-  memcpy(save_dung_info, &g_zenv.sram[WORD(g_ram[0])], 0x500);
-
-  bg_tile_animation_countdown = 7;
-  word_7EC013 = 7;
-  word_7EC00F = 0;
-  word_7EC015 = 0;
-  word_7E0219 = 0x6040;
-  word_7E021D = 0x4841;
-  word_7E021F = 0x7f;
-  word_7E0221 = 0xffff;
-
-  // If you save / quit in the middle of a mosaic effect, such as
-  // being electrocuted by a buzz blob, the resumed game will skip
-  // the location prompt and start in the sanctuary.
-  if (enhanced_features0 & kFeatures0_MiscBugFixes)
-    mosaic_level = 0;
-
-  hud_var1 = 128;
-  main_module_index = 5;
-  submodule_index = 0;
-  which_entrance = 0;
-  nmi_disable_core_updates = 0;
-  hud_palette = 0;
-}
-
-void RenderText() {  // 8ec440
-  kMessaging_Text[messaging_module]();
-}
-
-void RenderText_PostDeathSaveOptions() {  // 8ec455
-  dialogue_message_index = 3;
-  Text_Initialize_initModuleStateLoop();
-  text_msgbox_topleft = 0x61e8;
-  text_render_state = 2;
-  for (int i = 0; i < 5; i++)
-    Text_Render();
-}
-
-void Text_Initialize() {  // 8ec483
-  if (main_module_index == 20)
-    ResetHUDPalettes4and5();
-  Attract_DecompressStoryGFX();
-  Text_Initialize_initModuleStateLoop();
-}
-
-void Text_Initialize_initModuleStateLoop() {  // 8ec493
-  memcpy(&text_msgbox_topleft_copy, kText_InitializationData, 32);
-  Text_InitVwfState();
-  RenderText_SetDefaultWindowPosition();
-  text_tilemap_cur = 0x3980;
-  Text_LoadCharacterBuffer();
-  memset(messaging_buf, 0, 0x7e0);
-  nmi_subroutine_index = 2;
-  nmi_disable_core_updates = 2;
-}
-
-void Text_InitVwfState() {  // 8ec4c9
-  vwf_curline = 0;
-  vwf_flag_next_line = 0;
-  vwf_var1 = 0;
-  vwf_line_ptr = 0;
-}
-
-enum {
-  kTextCommandStart_US = 0x67,
-  kTextDictBase = 0x88,
-
-  kTextCmd_NextPic = 0,
-  kTextCmd_Choose = 1,
-  kTextCmd_Item = 2,
-  kTextCmd_Name = 3,
-  kTextCmd_Window = 4,  // Only used with 2
-  kTextCmd_Number = 5,
-  kTextCmd_Position = 6,
-  kTextCmd_ScrollSpd = 7,
-  kTextCmd_Selchg = 8,
-  kTextCmd_Choose3 = 10,
-  kTextCmd_Choose2 = 11,
-  kTextCmd_Scroll = 12,
-  kTextCmd_1 = 13,
-  kTextCmd_2 = 14,
-  kTextCmd_3 = 15,
-  kTextCmd_Color = 16,
-  kTextCmd_Wait = 17,
-  kTextCmd_Sound = 18,
-  kTextCmd_Speed = 19,
-  kTextCmd_Mark = 20,     // Unused
-  kTextCmd_Mark2 = 21,    // Unused
-  kTextCmd_Clear = 22,    // Unused
-  kTextCmd_Waitkey = 23,
-  kTextCmd_EndMessage = 24,
-
-  kTextCmd_IsLetter = 25, // Pseudo cmd
-};
-
-enum {
-  kTextCmd_EU_Scroll = 0x80,  // frequency 875
-  kTextCmd_EU_Waitkey = 0x81, // frequency 362
-  kTextCmd_EU_1 = 0x82,       // frequency 25
-  kTextCmd_EU_2 = 0x83,       // frequency 496
-  kTextCmd_EU_3 = 0x84,       // frequency 347
-  kTextCmd_EU_Name = 0x85,    // frequency 64
-  kTextCmd_EU_Rest = 0x87,    
-};
-
-#define TEXTCMD_MULTIBYTE(a) ((a) & 1)
-#define TEXTCMD_CMD(a) (((a) >> 1) & 0x1f)
-#define TEXTCMD_PARAM(a) ((a) >> 6)
-#define TEXTCMD_MK(c, x, m) ((c) << 6 | (x) << 1 | (m))
-
-uint32 Text_DecodeCmd(uint8 a, const uint8 *src) {
-  if ((g_zenv.dialogue_flags & 1) == 0) {
-    // US encoding
-    if (a < kTextCommandStart_US)
-      return TEXTCMD_MK(a, kTextCmd_IsLetter, 0);
-    if (a >= 0x80)
-      return TEXTCMD_MK(26, kTextCmd_IsLetter, 0); // could happen when loading snapshots
-    assert(a < 0x80);
-    static const uint8 kText_CommandLengths_US[] = { 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0 };
-    if (kText_CommandLengths_US[a - kTextCommandStart_US])
-      return TEXTCMD_MK(*src, a - kTextCommandStart_US, 1);
-    else
-      return TEXTCMD_MK(0, a - kTextCommandStart_US, 0);
-  } else {
-    // EU encoding
-    if (a < 0x7f)
-      return TEXTCMD_MK(a, kTextCmd_IsLetter, 0);
-    static const uint8 kSoundLut[] = {45};
-    static const uint8 kReturns_Simple[] = {
-      TEXTCMD_MK(0, kTextCmd_EndMessage, 0),
-      TEXTCMD_MK(0, kTextCmd_Scroll, 0),
-      TEXTCMD_MK(0, kTextCmd_Waitkey, 0),
-      TEXTCMD_MK(0, kTextCmd_1, 0),
-      TEXTCMD_MK(0, kTextCmd_2, 0),
-      TEXTCMD_MK(0, kTextCmd_3, 0),
-      TEXTCMD_MK(0, kTextCmd_Name, 0),
-      TEXTCMD_MK(0, kTextCmd_Name, 0), // Unused
-    };
-    if (a < kTextCmd_EU_Rest)
-      return kReturns_Simple[a - 0x7f];
-    a = *src;
-    switch (a >> 4) {
-    case 0: return TEXTCMD_MK(a & 0xF, kTextCmd_Wait, 1);
-    case 1: return TEXTCMD_MK(a & 0xF, kTextCmd_Color, 1);
-    case 2: return TEXTCMD_MK(a & 0xF, kTextCmd_Number, 1);
-    case 3: return TEXTCMD_MK(a & 0xF, kTextCmd_Speed, 1);
-    case 4: return TEXTCMD_MK(kSoundLut[a & 0xF], kTextCmd_Sound, 1);
-    case 8: {
-      static const uint8 kReturns_Ext[] = {
-        TEXTCMD_MK(0, kTextCmd_Choose, 1),
-        TEXTCMD_MK(0, kTextCmd_Choose2, 1),
-        TEXTCMD_MK(0, kTextCmd_Choose3, 1),
-        TEXTCMD_MK(0, kTextCmd_Selchg, 1),
-        TEXTCMD_MK(0, kTextCmd_Item, 1),
-        TEXTCMD_MK(0, kTextCmd_NextPic, 1),
-        TEXTCMD_MK(2, kTextCmd_Window, 1),
-        TEXTCMD_MK(0, kTextCmd_Position, 1),
-        TEXTCMD_MK(1, kTextCmd_Position, 1),
-      };
-      return kReturns_Ext[a - 0x80];
-    }
-    default:
-      assert(0);
-      return TEXTCMD_MK(26, kTextCmd_IsLetter, 0);
-    }
-  }
-}
-
-// Perform initial parsing of the string, expanding words, processing some commands, etc.
-void Text_LoadCharacterBuffer() {  // 8ec4e2
-  MemBlk dictionary = FindIndexInMemblk(g_zenv.dialogue_blk, 0);
-  MemBlk dialogue = FindIndexInMemblk(g_zenv.dialogue_blk, 1);
-  MemBlk text_str = FindIndexInMemblk(dialogue, dialogue_message_index);
-  const uint8 *src = text_str.ptr, *src_end = src + text_str.size, *src_org = src;
-  uint8 *dst = messaging_text_buffer;
-  while (src < src_end) {
-    uint8 c = *src++;
-    if (c >= kTextDictBase) {
-      MemBlk blk = FindIndexInMemblk(dictionary, c - kTextDictBase);
-      memcpy(dst, blk.ptr, blk.size);
-      dst += blk.size;
-      continue;
-    }
-    // Decode the next byte or multibyte character (in case we support that in the future)
-    // This is dependent on the current language cause US / PAL encode commands differently
-    uint32 cmd = Text_DecodeCmd(c, src);
-    switch (TEXTCMD_CMD(cmd)) {
-    case kTextCmd_Name: dst = Text_WritePlayerName(dst); break;
-    case kTextCmd_Window:  // RenderText_ExtendedCommand_SetWindowType
-      text_render_state = TEXTCMD_PARAM(cmd);
-      break;
-    case kTextCmd_Number: {  // Text_WritePreloadedNumber
-      uint8 t = TEXTCMD_PARAM(cmd);
-      uint8 v = dialogue_number[t >> 1];
-      *dst++ = 0x34 + ((t & 1) ? v >> 4 : v & 0xf);
-      break;
-    }
-    case kTextCmd_Position:
-      text_msgbox_topleft = kText_Positions[TEXTCMD_PARAM(cmd)];
-      break;
-    case kTextCmd_Color:
-      text_tilemap_cur = ((0x387F & 0xe300) | 0x180) | (TEXTCMD_PARAM(cmd) << 10) & 0x3c00;
-      break;
-    default:
-      // This combination is handled when rendering instead of here
-      *dst++ = c;
-      if (TEXTCMD_MULTIBYTE(cmd))
-        *dst++ = *src;
-      break;
-    }
-    src += TEXTCMD_MULTIBYTE(cmd);
-  }
-  *dst = 0x7f;
-  dialogue_msg_read_pos = 0;
-}
-
-uint8 *Text_WritePlayerName(uint8 *p) {  // 8ec5b3
-  uint8 slot = srm_var1;
-  int offs = ((slot>>1) - 1) * 0x500;
-  for (int i = 0; i < 6; i++) {
-    uint8 *pp = &g_zenv.sram[0x3d9 + offs + i * 2];
-    uint16 a = WORD(*pp);
-    p[i] = Text_FilterPlayerNameCharacters(a & 0xf | (a >> 1) & 0xf0);
-  }
-  int i = 6;
-  while (i && p[i - 1] == 0x59)
-    i--;
-  return p + i;
-}
-
-uint8 Text_FilterPlayerNameCharacters(uint8 a) {  // 8ec639
-  if (a >= 0x5f) {
-    if (a >= 0x76)
-      a -= 0x42;
-    else if (a == 0x5f)
-      a = 8;
-    else if (a == 0x60)
-      a = 0x22;
-    else if (a == 0x61)
-      a = 0x3e;
-  }
-  return a;
-}
-
-void Text_Render() {  // 8ec8d9
-  kText_Render[text_render_state]();
-}
-
-void RenderText_Draw_Border() {  // 8ec8ea
-  RenderText_DrawBorderInitialize();
-  uint16 *d = RenderText_DrawBorderRow(vram_upload_data, 0);
-  for(int i = 0; i != 6; i++)
-    d = RenderText_DrawBorderRow(d, 6);
-  d = RenderText_DrawBorderRow(d, 12);
-  nmi_load_bg_from_vram = 1;
-  text_render_state = 2;
-}
-
-void RenderText_Draw_BorderIncremental() {  // 8ec919
-  nmi_load_bg_from_vram = 1;
-  uint8 a = text_incremental_state;
-  uint16 *d = vram_upload_data;
-  if (a)
-    a = (a < 7) ? 1 : 2;
-  switch (a) {
-  case 0:
-    RenderText_DrawBorderInitialize();
-    d = RenderText_DrawBorderRow(d, 0);
-    text_incremental_state++;
-    break;
-  case 1:
-    d = RenderText_DrawBorderRow(d, 6);
-    text_incremental_state++;
-    break;
-  case 2:
-    text_render_state = 2;
-    d = RenderText_DrawBorderRow(d, 12);
-    text_incremental_state++;
-    break;
-  }
-}
-
-void RenderText_Draw_CharacterTilemap() {  // 8ec97d
-  Text_BuildCharacterTilemap();
-  text_render_state++;
-}
-
-void RenderText_Draw_MessageCharacters() {  // 8ec984
-RESTART:;
-  uint32 cmd = Text_DecodeCmd(messaging_text_buffer[dialogue_msg_read_pos],
-      &messaging_text_buffer[dialogue_msg_read_pos + 1]);
-
-  switch (TEXTCMD_CMD(cmd)) {
-  case kTextCmd_IsLetter:
-    if (vwf_line_speed_cur >= 2) {
-      vwf_line_speed_cur--;
-      break;
-    }
-    VWF_RenderSingle(TEXTCMD_PARAM(cmd));
-    dialogue_msg_read_pos += 1 + TEXTCMD_MULTIBYTE(cmd);
-    if (vwf_line_speed_cur == 0)
-      goto RESTART;
-    break;
-  case kTextCmd_NextPic:  // RenderText_Draw_NextImage
-    if (main_module_index == 20) {
-      PaletteFilterHistory();
-      if (!BYTE(palette_filter_countdown))
-        goto COMMAND_DONE;
-    } else {
-      goto COMMAND_DONE;
-    }
-    break;
-  case kTextCmd_Choose:  // RenderText_Draw_Choose2LowOr3
-    RenderText_Draw_Choose2LowOr3();
-    break;
-  case kTextCmd_Item:  // RenderText_Draw_ChooseItem
-    RenderText_Draw_ChooseItem();
-    break;
-  case kTextCmd_Name:
-  case kTextCmd_Window:
-  case kTextCmd_Number:
-  case kTextCmd_Position:
-  case kTextCmd_Color:
-    // These get handled in Text_LoadCharacterBuffer
-    assert(0);
-    break;
-  // These are unused
-  case kTextCmd_Mark:
-  case kTextCmd_Mark2:
-  case kTextCmd_Clear:
-    assert(0);
-    break;
-  case kTextCmd_ScrollSpd:
-    dialogue_scroll_speed = TEXTCMD_PARAM(cmd);
-    goto COMMAND_DONE;
-  case kTextCmd_Selchg:   // RenderText_Draw_Choose2HiOr3
-    RenderText_Draw_Choose2HiOr3();
-    break;
-  case kTextCmd_Choose3:  // RenderText_Draw_Choose3
-    RenderText_Draw_Choose3();
-    break;
-  case kTextCmd_Choose2:  // RenderText_Draw_Choose1Or2
-    RenderText_Draw_Choose1Or2();
-    break;
-  case kTextCmd_Scroll:  // RenderText_Draw_Scroll
-    if (RenderText_Draw_Scroll())
-      goto COMMAND_DONE;
-    break;
-  case kTextCmd_1:  //
-  case kTextCmd_2:  //
-  case kTextCmd_3:  // VWF_SetLine
-    vwf_curline = kVWF_RowPositions[TEXTCMD_CMD(cmd) - kTextCmd_1];
-    vwf_flag_next_line = 1;
-    goto COMMAND_DONE;
-  case kTextCmd_Wait:  // RenderText_Draw_Wait
-    switch (joypad1L_last & 0x80 ? 1 : text_wait_countdown) {
-    case 0:
-      text_wait_countdown = kText_WaitDurations[TEXTCMD_PARAM(cmd)] - 1;
-      break;
-    case 1:
-      BYTE(text_wait_countdown) = 0;
-      goto COMMAND_DONE;
-    default:
-      text_wait_countdown--;
-      break;
-    }
-    break;
-  case kTextCmd_Sound:  // RenderText_Draw_PlaySfx
-    sound_effect_2 = TEXTCMD_PARAM(cmd);
-    goto COMMAND_DONE;
-  case kTextCmd_Speed:  // RenderText_Draw_SetSpeed
-    vwf_line_speed = vwf_line_speed_cur = TEXTCMD_PARAM(cmd);
-    goto COMMAND_DONE;
-  case kTextCmd_Waitkey:  // RenderText_Draw_PauseForInput
-    if (text_wait_countdown2 != 0) {
-      if (--text_wait_countdown2 == 1)
-        sound_effect_2 = 36;
-    } else {
-      if ((filtered_joypad_H | filtered_joypad_L) & 0xc0) {
-        text_wait_countdown2 = 28;
-        goto COMMAND_DONE;
-      }
-    }
-    break;
-  case kTextCmd_EndMessage:  // RenderText_Draw_Terminate
-    if (text_wait_countdown2 != 0) {
-      if (--text_wait_countdown2 == 1)
-        sound_effect_2 = 36;
-    } else {
-      if ((filtered_joypad_H | filtered_joypad_L)) {
-        text_render_state = 4;
-        text_wait_countdown2 = 28;
-      }
-    }
-    break;
-  }
-  if (0) COMMAND_DONE: {
-    dialogue_msg_read_pos += 1 + TEXTCMD_MULTIBYTE(cmd);
-  }
-  nmi_subroutine_index = 2;
-  nmi_disable_core_updates = 2;
-}
-
-void RenderText_Draw_Finish() {  // 8eca35
-  RenderText_DrawBorderInitialize();
-  uint16 *d = vram_upload_data;
-  d[0] = swap16(text_msgbox_topleft_copy);
-  d[1] = 0x2E42;
-  d[2] = 0x387F;
-  d[3] = 0xffff;
-  nmi_load_bg_from_vram = 1;
-  messaging_module = 0;
-  submodule_index = 0;
-  main_module_index = saved_module_for_menu;
-}
-
-void VWF_RenderSingle(int c) {  // 8ecab8
-  if (c != 0x59)
-    sound_effect_2 = 12;
-  vwf_line_speed_cur = vwf_line_speed;
-
-  if (vwf_flag_next_line) {
-    vwf_line_ptr = kVWF_RenderCharacter_renderPos[vwf_curline>>1];
-    vwf_var1 = kVWF_RenderCharacter_linePositions[vwf_curline>>1];
-    vwf_flag_next_line = 0;
-  }
-  
-  const uint8 *kFontData = FindIndexInMemblk(g_zenv.dialogue_font_blk, 0).ptr;
-  uint8 width = FindIndexInMemblk(g_zenv.dialogue_font_blk, 1).ptr[c];
-  assert(width <= 8);
-
-  int i = vwf_var1++;
-  uint8 arrval = vwf_arr[i];
-  vwf_arr[i + 1] = arrval + width;
-  uint16 r10 = (c & 0x70) * 2 + (c & 0xf);
-  uint16 r0 = arrval * 2;
-  const uint16 *src2 = (uint16*)(kFontData + r10 * 16);
-  uint8 *mbuf = (uint8 *)messaging_buf;
-  for (int i = 0; i != 16; i += 2) {
-    uint16 r4 = *src2++;
-    int y = r0 + vwf_line_ptr;
-    int x = (y & 0xff0) + i;
-    y = (y >> 1) & 7;
-    uint8 r3 = width;
-    do {
-      if (r4 & 0x0080)
-        mbuf[x + 0] ^= kVWF_RenderCharacter_setMasks[y];
-      else
-        mbuf[x + 0] &= ~kVWF_RenderCharacter_setMasks[y];
-      if (r4 & 0x8000)
-        mbuf[x + 1] ^= kVWF_RenderCharacter_setMasks[y];
-      else
-        mbuf[x + 1] &= ~kVWF_RenderCharacter_setMasks[y];
-      r4 = (r4 & ~0x8080) << 1;
-      //r4 <<= 1;
-    } while (--r3 && ++y != 8);
-    x += 16;
-    if (r4 != 0)
-      WORD(mbuf[x + 0]) = r4;
-  }
-  uint16 r8 = vwf_line_ptr + 0x150;
-  const uint16 *src3 = (uint16*)(kFontData + (r10 + 16) * 16);
-  for (int i = 0; i != 16; i += 2) {
-    uint16 r4 = *src3++;
-    int y = r8 + r0;
-    int x = (y & 0xff0) + i;
-    y = (y >> 1) & 7;
-    uint8 r3 = width;
-    do {
-      if (r4 & 0x0080)
-        mbuf[x + 0] ^= kVWF_RenderCharacter_setMasks[y];
-      else
-        mbuf[x + 0] &= ~kVWF_RenderCharacter_setMasks[y];
-      if (r4 & 0x8000)
-        mbuf[x + 1] ^= kVWF_RenderCharacter_setMasks[y];
-      else
-        mbuf[x + 1] &= ~kVWF_RenderCharacter_setMasks[y];
-      //r4 <<= 1;
-      r4 = (r4 & ~0x8080) << 1;
-    } while (--r3 && ++y != 8);
-    x += 16;
-    if (r4 != 0)
-      WORD(mbuf[x + 0]) = r4;
-  }
-}
-
-void RenderText_Draw_Choose2LowOr3() {  // 8ecd1a
-  if (text_wait_countdown2 != 0) {
-    if (--text_wait_countdown2 == 1)
-      sound_effect_2 = 36;
-  } else if ((filtered_joypad_H | filtered_joypad_L) & 0xc0) {
-    sound_effect_1 = 43;
-    text_render_state = 4;
-  } else if (filtered_joypad_H & 12) {
-    int t = filtered_joypad_H & 8 ? 0 : 1;
-    if (choice_in_multiselect_box == t)
-      return;
-    choice_in_multiselect_box = t;
-    sound_effect_2 = 32;
-    dialogue_message_index = t + 1;
-    Text_LoadCharacterBuffer();
-    Text_InitVwfState();
-  }
-}
-
-void RenderText_Draw_ChooseItem() {  // 8ecd88
-  if (text_wait_countdown2 != 0) {
-    if (--text_wait_countdown2 == 1)
-      RenderText_FindYItem_Next();
-  } else if ((filtered_joypad_H | filtered_joypad_L) & 0xc0) {
-    text_render_state = 4;
-  } else {
-    if (filtered_joypad_H & 5) {
-      choice_in_multiselect_box++;
-    } else if (filtered_joypad_H & 10) {
-      choice_in_multiselect_box--;
-      RenderText_FindYItem_Previous();
-      RenderText_Refresh();
-      return;
-    }
-    RenderText_FindYItem_Next();
-    RenderText_Refresh();
-  }
-}
-
-void RenderText_FindYItem_Previous() {  // 8ecdc8
-  for (;;) {
-    uint8 x = choice_in_multiselect_box;
-    if (sign8(x))
-      choice_in_multiselect_box = x = 31;
-    if (x != 15 && ((&link_item_bow)[x] || x == 32 && (&link_item_bow)[x + 1]))
-      break;
-    choice_in_multiselect_box--;
-  }
-  RenderText_DrawSelectedYItem();
-}
-
-void RenderText_FindYItem_Next() {  // 8ecded
-  for (;;) {
-    uint8 x = choice_in_multiselect_box;
-    if (x >= 32)
-      choice_in_multiselect_box = x = 0;
-    if (x != 15 && ((&link_item_bow)[x] || x == 32 && (&link_item_bow)[x + 1]))
-      break;
-    choice_in_multiselect_box++;
-  }
-  RenderText_DrawSelectedYItem();
-}
-
-void RenderText_DrawSelectedYItem() {  // 8ece14
-  int item = choice_in_multiselect_box;
-  const uint16 *p = Hud_GetItemBoxPtr(item);
-  p += ((item == 3 || item == 32) ? 1 : (&link_item_bow)[item]) * 4;
-  uint8 *vwf300 = &g_ram[0x1300];
-  memcpy(vwf300 + 0xc2, p, 4);
-  memcpy(vwf300 + 0xec, p + 2, 4);
-}
-
-void RenderText_Draw_Choose2HiOr3() {  // 8ece83
-  if (text_wait_countdown2 != 0) {
-    if (--text_wait_countdown2 == 1)
-      sound_effect_2 = 36;
-  } else if ((filtered_joypad_H | filtered_joypad_L) & 0xc0) {
-    sound_effect_1 = 43;
-    text_render_state = 4;
-  } else if (filtered_joypad_H & 12) {
-    int t = filtered_joypad_H & 8 ? 0 : 1;
-    if (choice_in_multiselect_box == t)
-      return;
-    choice_in_multiselect_box = t;
-    sound_effect_2 = 32;
-    dialogue_message_index = t + 11;
-    Text_LoadCharacterBuffer();
-    Text_InitVwfState();
-  }
-}
-
-void RenderText_Draw_Choose3() {  // 8ecef7
-  uint8 y;
-  if (text_wait_countdown2 != 0) {
-    if (--text_wait_countdown2 == 1)
-      sound_effect_2 = 36;
-  } else if ((y = filtered_joypad_L & 0xc0 | filtered_joypad_H) & 0xd0) {
-    sound_effect_1 = 43;
-    text_render_state = 4;
-  } else if (y & 12) {
-    int choice = choice_in_multiselect_box;
-    if (y & 8)
-      choice = (choice == 0) ? 2 : choice - 1;
-    else
-      choice = (choice == 2) ? 0 : choice + 1;
-    choice_in_multiselect_box = choice;
-    sound_effect_2 = 32;
-    dialogue_message_index = choice + 6;
-    Text_LoadCharacterBuffer();
-    Text_InitVwfState();
-  }
-}
-
-void RenderText_Draw_Choose1Or2() {  // 8ecf72
-  uint8 y;
-  if (text_wait_countdown2 != 0) {
-    if (--text_wait_countdown2 == 1)
-      sound_effect_2 = 36;
-  } else if ((y = filtered_joypad_L & 0xc0 | filtered_joypad_H) & 0xd0) {
-    sound_effect_1 = 43;
-    text_render_state = 4;
-  } else if (y & 12) {
-    int t = y & 8 ? 0 : 1;
-    if (choice_in_multiselect_box == t)
-      return;
-    choice_in_multiselect_box = t;
-    sound_effect_2 = 32;
-    dialogue_message_index = t + 9;
-    Text_LoadCharacterBuffer();
-    Text_InitVwfState();
-  }
-}
-
-bool RenderText_Draw_Scroll() {  // 8ecfe2
-  uint8 r2 = dialogue_scroll_speed;
-  do {
-    for (int i = 0; i < 0x7e0; i += 16) {
-      uint16 *p = (uint16 *)((uint8 *)messaging_buf + i);
-      p[0] = p[1];
-      p[1] = p[2];
-      p[2] = p[3];
-      p[3] = p[4];
-      p[4] = p[5];
-      p[5] = p[6];
-      p[6] = p[7];
-      p[7] = p[168];
-    }
-    uint16 *p = messaging_buf;
-    for (int i = 0x34f; i <= 0x3ef; i += 8)
-      p[i] = 0;
-
-    if ((++byte_7E1CDF & 0xf) == 0) {
-      vwf_curline = 4;
-      vwf_flag_next_line = 1;
-      return true;
-    }
-  } while (r2--);
-  return false;
-}
-
-void RenderText_SetDefaultWindowPosition() {  // 8ed280
-  uint16 y = link_y_coord - BG2VOFS_copy2;
-  int flag = (y < 0x78);
-  text_msgbox_topleft = kText_Positions[flag];
-}
-
-void RenderText_DrawBorderInitialize() {  // 8ed29c
-  text_msgbox_topleft_copy = text_msgbox_topleft;
-}
-
-uint16 *RenderText_DrawBorderRow(uint16 *d, int y) {  // 8ed2ab
-  y >>= 1;
-  *d++ = swap16(text_msgbox_topleft_copy);
-  text_msgbox_topleft_copy += 0x20;
-  *d++ = 0x2F00;
-  *d++ = kText_BorderTiles[y];
-  for(int i = 0; i < 22; i++)
-    *d++ = kText_BorderTiles[y+1];
-  *d++ = kText_BorderTiles[y+2];
-  *d = 0xffff;
-  return d;
-}
-
-void Text_BuildCharacterTilemap() {  // 8ed2ec
-  uint16 *vwf300 = (uint16 *)&g_ram[0x1300];
-  for (int i = 0; i < 126; i++)
-    vwf300[i] = text_tilemap_cur++;
-  RenderText_Refresh();
-}
-
-void RenderText_Refresh() {  // 8ed307
-  RenderText_DrawBorderInitialize();
-  text_msgbox_topleft_copy += 0x21;
-  uint16 *d = vram_upload_data;
-  uint16 *s = (uint16 *)&g_ram[0x1300];
-  for (int j = 0; j != 6; j++) {
-    *d++ = swap16(text_msgbox_topleft_copy);
-    text_msgbox_topleft_copy += 0x20;
-    *d++ = 0x2900;
-    for (int i = 0; i != 21; i++)
-      *d++ = *s++;
-  }
-  *d = 0xffff;
-  nmi_load_bg_from_vram = 1;
-}
-
-
-void Text_GenerateMessagePointers() {  // 8ed3eb
-  // This is not actually used. Only for ram compat.
-  MemBlk dialogue = FindIndexInMemblk(g_zenv.dialogue_blk, 1);
-  uint32 p = 0x1c8000;
-  uint8 *dst = kTextDialoguePointers;
-  for (int i = 0; i < 398; i++) {
-    if (i == 359)
-      p = 0xedf40;
-    WORD(dst[0]) = p;
-    dst[2] = p >> 16;
-    dst += 3;
-    p += (uint32)FindIndexInMemblk(dialogue, i).size + 1;
-  }
-}
-
-void DungMap_LightenUpMap() {  // 8ed940
-  if (++INIDISP_copy == 0xf)
-    overworld_map_state++;
-}
-
-void DungMap_Backup() {  // 8ed94c
-  if (--INIDISP_copy)
-    return;
-  MOSAIC_copy = 3;
-  mapbak_HDMAEN = HDMAEN_copy;
-  EnableForceBlank();
-  overworld_map_state++;
-  dungmap_init_state = 0;
-  COLDATA_copy0 = 0x20;
-  COLDATA_copy1 = 0x40;
-  COLDATA_copy2 = 0x80;
-  link_dma_graphics_index = 0x250;
-  memcpy(mapbak_palette, main_palette_buffer, sizeof(uint16) * 256);
-  mapbak_bg1_x_offset = bg1_x_offset;
-  mapbak_bg1_y_offset = bg1_y_offset;
-  bg1_x_offset = 0;
-  bg1_y_offset = 0;
-  mapbak_BG1HOFS_copy2 = BG1HOFS_copy2;
-  mapbak_BG2HOFS_copy2 = BG2HOFS_copy2;
-  mapbak_BG1VOFS_copy2 = BG1VOFS_copy2;
-  mapbak_BG2VOFS_copy2 = BG2VOFS_copy2;
-  BG1HOFS_copy2 = BG1VOFS_copy2 = 0;
-  BG2HOFS_copy2 = BG2VOFS_copy2 = 0;
-  BG3HOFS_copy2 = BG3VOFS_copy2 = 0;
-  mapbak_CGWSEL = WORD(CGWSEL_copy);
-  CGWSEL_copy = 0x02;
-  CGADSUB_copy = 0x20;
-  for (int i = 0; i < 2048; i++)
-    messaging_buf[i] = 0x300;
-  sound_effect_2 = 16;
-  music_control = 0xf2;
-}
-
-void DungMap_FadeMapToBlack() {  // 8eda37
-  if (--INIDISP_copy)
-    return;
-  EnableForceBlank();
-  overworld_map_state++;
-  WORD(CGWSEL_copy) = mapbak_CGWSEL;
-  BG1HOFS_copy2 =  mapbak_BG1HOFS_copy2;
-  BG2HOFS_copy2 =  mapbak_BG2HOFS_copy2;
-  BG1VOFS_copy2 =  mapbak_BG1VOFS_copy2;
-  BG2VOFS_copy2 =  mapbak_BG2VOFS_copy2;
-  BG3VOFS_copy2 = BG3HOFS_copy2 = 0;
-  bg1_x_offset = mapbak_bg1_x_offset;
-  bg1_y_offset = mapbak_bg1_y_offset;
-  flag_update_cgram_in_nmi++;
-}
-
-void DungMap_RestoreOld() {  // 8eda79
-  OrientLampLightCone();
-  if (++INIDISP_copy != 0xf)
-    return;
-  main_module_index = saved_module_for_menu;
-  submodule_index = 0;
-  overworld_map_state = 0;
-  subsubmodule_index = 0;
-  INIDISP_copy = 0xf;
-  HDMAEN_copy = mapbak_HDMAEN;
-}
-
-void Death_PlayerSwoon() {  // 8ff5e3
-  int k = link_var30d;
-  if (sign8(--some_animation_timer)) {
-    k++;
-    if (k == 15)
-      return;
-    if (k == 14)
-      submodule_index++;
-    link_var30d = k;
-    some_animation_timer_steps = kDeath_AnimCtr0[k];
-    some_animation_timer = kDeath_AnimCtr1[k];
-  }
-  if (k != 13 || link_visibility_status == 12)
-    return;
-  uint8 y = link_y_coord + 16 - BG2VOFS_copy2;
-  uint8 x = link_x_coord + 7 - BG2HOFS_copy2;
-  SetOamPlain(&oam_buf[0x74], x, y, 0xaa, kDeath_SprFlags[link_is_on_lower_level] | 2, 2);
-}
-
-void Death_PrepFaint() {  // 8ffa6f
-  link_direction_facing = 2;
-  player_unk1 = 1;
-  link_var30d = 0;
-  some_animation_timer_steps = 0;
-  some_animation_timer = 5;
-  link_hearts_filler = 0;
-  link_health_current = 0;
-  Link_ResetProperties_C();
-  player_on_somaria_platform = 0;
-  draw_water_ripples_or_grass = 0;
-  link_is_bunny_mirror = 0;
-  bitmask_of_dragstate = 0;
-  flag_is_ancilla_to_pick_up = 0;
-  link_auxiliary_state = 0;
-  link_incapacitated_timer = 0;
-  link_give_damage = 0;
-  link_is_transforming = 0;
-  link_speed_setting = 0;
-  link_need_for_poof_for_transform = 0;
-  if (link_item_moon_pearl)
-    link_is_bunny = 0;
-  link_timer_tempbunny = 0;
-  //bugfix: dying as permabunny doesn't restore link palette during death animation
-  if (enhanced_features0 & kFeatures0_MiscBugFixes)
-    LoadActualGearPalettes();
-  sound_effect_1 = 0x27 | Link_CalculateSfxPan();
-  for (int i = 0; i != 4; i++) {
-    if (link_bottle_info[i] == 6)
-      return;
-  }
-  index_of_changable_dungeon_objs[0] = index_of_changable_dungeon_objs[1] = 0;
-}
-
-
-
-void DisplaySelectMenu() {
-  choice_in_multiselect_box_bak = choice_in_multiselect_box;
-  dialogue_message_index = 0x186;
-  uint8 bak = main_module_index;
-  Main_ShowTextMessage();
-  main_module_index = bak;
-  subsubmodule_index = 0;
-  submodule_index = 11;
-  saved_module_for_menu = main_module_index;
-  main_module_index = 14;
-}
--- a/messaging.h
+++ /dev/null
@@ -1,133 +1,0 @@
-#pragma once
-#include "types.h"
-
-const uint8 *GetDungmapFloorLayout();
-uint8 GetOtherDungmapInfo(int count);
-void DungMap_4();
-void Module_Messaging_6();
-void OverworldMap_SetupHdma();
-const uint8 *GetLightOverworldTilemap();
-void SaveGameFile();
-void TransferMode7Characters();
-void Module0E_Interface();
-void Module_Messaging_0();
-void Module0E_05_DesertPrayer();
-void Module0E_04_RedPotion();
-void Module0E_08_GreenPotion();
-void Module0E_09_BluePotion();
-void Module0E_0B_SaveMenu();
-void Module1B_SpawnSelect();
-void CleanUpAndPrepDesertPrayerHDMA();
-void DesertPrayer_InitializeIrisHDMA();
-void DesertPrayer_BuildIrisHDMATable();
-Pair16U DesertHDMA_CalculateIrisShapeLine();
-void Animate_GAMEOVER_Letters();
-void GameOverText_SweepLeft();
-void GameOverText_UnfurlRight();
-void Module12_GameOver();
-void GameOver_AdvanceImmediately();
-void Death_Func1();
-void GameOver_DelayBeforeIris();
-void GameOver_IrisWipe();
-void GameOver_SplatAndFade();
-void Death_Func6();
-void Death_Func4();
-void Animate_GAMEOVER_Letters_bounce();
-void GameOver_Finalize_GAMEOVR();
-void GameOver_SaveAndOrContinue();
-void Death_Func15(bool count_as_death);
-void GameOver_AnimateChoiceFairy();
-void GameOver_InitializeRevivalFairy();
-void RevivalFairy_Main_bounce();
-void GameOver_RiseALittle();
-void GameOver_Restore0D();
-void GameOver_Restore0E();
-void GameOver_ResituateLink();
-void Module0E_0A_FluteMenu();
-void FluteMenu_HandleSelection();
-void FluteMenu_LoadSelectedScreen();
-void Overworld_LoadOverlayAndMap();
-void FluteMenu_FadeInAndQuack();
-void BirdTravel_Finish_Doit();
-void Messaging_OverworldMap();
-void WorldMap_FadeOut();
-void WorldMap_LoadLightWorldMap();
-void WorldMap_LoadDarkWorldMap();
-void WorldMap_LoadSpriteGFX();
-void WorldMap_Brighten();
-void WorldMap_PlayerControl();
-void WorldMap_RestoreGraphics();
-void Attract_SetUpConclusionHDMA();
-void WorldMap_ExitMap();
-void WorldMap_SetUpHDMA();
-void WorldMap_FillTilemapWithEF();
-void WorldMap_HandleSprites();
-bool OverworldMap_CheckForPendant(int k);
-bool OverworldMap_CheckForCrystal(int k);
-void Module0E_03_DungeonMap();
-void Module0E_03_01_DrawMap();
-void Module0E_03_01_00_PrepMapGraphics();
-void Module0E_03_01_01_DrawLEVEL();
-void Module0E_03_01_02_DrawFloorsBackdrop();
-void DungeonMap_BuildFloorListBoxes(uint8 t5, uint16 r14);
-void Module0E_03_01_03_DrawRooms();
-void DungeonMap_DrawBorderForRooms(uint16 pd, uint16 mask);
-void DungeonMap_DrawFloorNumbersByRoom(uint16 pd, uint16 r8);
-void DungeonMap_DrawDungeonLayout(int pd);
-void DungeonMap_DrawSingleRowOfRooms(int i, int arg_x);
-void DungeonMap_DrawRoomMarkers();
-void DungeonMap_HandleInputAndSprites();
-void DungeonMap_HandleInput();
-void DungeonMap_HandleMovementInput();
-void DungeonMap_HandleFloorSelect();
-void DungeonMap_ScrollFloors();
-void DungeonMap_DrawSprites();
-void DungeonMap_DrawLinkPointing(int spr_pos, uint8 r2, uint8 r3);
-int DungeonMap_DrawBlinkingIndicator(int spr_pos);
-int DungeonMap_DrawLocationMarker(int spr_pos, uint16 r14);
-int DungeonMap_DrawFloorNumberObjects(int spr_pos);
-void DungeonMap_DrawFloorBlinker();
-int DungeonMap_DrawBossIcon(int spr_pos);
-int DungeonMap_DrawBossIconByFloor(int spr_pos);
-void DungeonMap_RecoverGFX();
-void ToggleStarTilesAndAdvance();
-void Death_InitializeGameOverLetters();
-void CopySaveToWRAM();
-void RenderText();
-void RenderText_PostDeathSaveOptions();
-void Text_Initialize();
-void Text_Initialize_initModuleStateLoop();
-void Text_InitVwfState();
-void Text_LoadCharacterBuffer();
-uint8 *Text_WritePlayerName(uint8 *p);
-uint8 Text_FilterPlayerNameCharacters(uint8 a);
-void Text_Render();
-void RenderText_Draw_Border();
-void RenderText_Draw_BorderIncremental();
-void RenderText_Draw_CharacterTilemap();
-void RenderText_Draw_MessageCharacters();
-void RenderText_Draw_Finish();
-void VWF_RenderSingle();
-void RenderText_Draw_Choose2LowOr3();
-void RenderText_Draw_ChooseItem();
-void RenderText_FindYItem_Previous();
-void RenderText_FindYItem_Next();
-void RenderText_DrawSelectedYItem();
-void RenderText_Draw_Choose2HiOr3();
-void RenderText_Draw_Choose3();
-void RenderText_Draw_Choose1Or2();
-bool RenderText_Draw_Scroll();
-void RenderText_SetDefaultWindowPosition();
-void RenderText_DrawBorderInitialize();
-uint16 *RenderText_DrawBorderRow(uint16 *d, int y);
-void Text_BuildCharacterTilemap();
-void RenderText_Refresh();
-void Text_GenerateMessagePointers();
-void DungMap_LightenUpMap();
-void DungMap_Backup();
-void DungMap_FadeMapToBlack();
-void DungMap_RestoreOld();
-void Death_PlayerSwoon();
-void Death_PrepFaint();
-void DisplaySelectMenu();
-bool DidPressButtonForMap();
--- a/misc.c
+++ /dev/null
@@ -1,960 +1,0 @@
-#include "misc.h"
-#include "variables.h"
-#include "hud.h"
-#include "dungeon.h"
-#include "overworld.h"
-#include "load_gfx.h"
-#include "sprite.h"
-#include "poly.h"
-#include "ancilla.h"
-#include "select_file.h"
-#include "tile_detect.h"
-#include "player.h"
-#include "player_oam.h"
-#include "messaging.h"
-#include "ending.h"
-#include "attract.h"
-#include "snes/snes_regs.h"
-#include "assets.h"
-
-static void KillAgahnim_LoadMusic();
-static void KillAghanim_Init();
-static void KillAghanim_Func2();
-static void KillAghanim_Func3();
-static void KillAghanim_Func4();
-static void KillAghanim_Func5();
-static void KillAghanim_Func6();
-static void KillAghanim_Func7();
-static void KillAghanim_Func8();
-static void KillAghanim_Func12();
-static uint8 PlaySfx_SetPan(uint8 a);
-
-const uint8 kReceiveItem_Tab1[76] = {
-  0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0, 2, 2, 2,
-  2, 2, 2, 0, 2, 0, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2,
-  2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2,
-  2, 2, 2, 2, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-  2, 2, 0, 0, 2, 0, 2, 2, 2, 0, 2, 2,
-};
-static const int8 kReceiveItem_Tab2[76] = {
-  -5, -5, -5, -5, -5, -4, -4, -5, -5, -4, -4, -4, -2, -4, -4, -4,
-  -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4,
-  -4, -4, -4, -5, -4, -4, -4, -4, -4, -4, -2, -4, -4, -4, -4, -4,
-  -4, -4, -4, -4, -2, -2, -2, -4, -4, -4, -4, -4, -4, -4, -4, -4,
-  -4, -4, -2, -2, -4, -2, -4, -4, -4, -5, -4, -4,
-};
-static const uint8 kReceiveItem_Tab3[76] = {
-  4, 4, 4, 4, 4, 0, 0, 4, 4, 4, 4, 4, 5, 0, 0, 0,
-  0, 0, 0, 4, 0, 4, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0,
-  0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0,
-  0, 0, 0, 0, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-  0, 0, 4, 4, 0, 4, 0, 0, 0, 4, 0, 0,
-};
-const uint8 kReceiveItemGfx[76] = {
-  6, 0x18, 0x18, 0x18, 0x2d, 0x20, 0x2e,    9,    9,  0xa,    8,    5, 0x10,  0xb, 0x2c, 0x1b,
-  0x1a, 0x1c, 0x14, 0x19,  0xc,    7, 0x1d, 0x2f,    7, 0x15, 0x12,  0xd,  0xd,  0xe, 0x11, 0x17,
-  0x28, 0x27,    4,    4,  0xf, 0x16,    3, 0x13,    1, 0x1e, 0x10,    0,    0,    0,    0,    0,
-  0, 0x30, 0x22, 0x21, 0x24, 0x24, 0x24, 0x23, 0x23, 0x23, 0x29, 0x2a, 0x2c, 0x2b,    3,    3,
-  0x34, 0x35, 0x31, 0x33,    2, 0x32, 0x36, 0x37, 0x2c,    6,  0xc, 0x38,
-};
-const uint16 kMemoryLocationToGiveItemTo[76] = {
-  0xf359, 0xf359, 0xf359, 0xf359,
-  0xf35a, 0xf35a, 0xf35a, 0xf345,
-  0xf346, 0xf34b, 0xf342, 0xf340,
-  0xf341, 0xf344, 0xf35c, 0xf347,
-  0xf348, 0xf349, 0xf34a, 0xf34c,
-  0xf34c, 0xf350, 0xf35c, 0xf36b,
-  0xf351, 0xf352, 0xf353, 0xf354,
-  0xf354, 0xf34e, 0xf356, 0xf357,
-  0xf37a, 0xf34d, 0xf35b, 0xf35b,
-  0xf36f, 0xf364, 0xf36c, 0xf375,
-  0xf375, 0xf344, 0xf341, 0xf35c,
-  0xf35c, 0xf35c, 0xf36d, 0xf36e,
-  0xf36e, 0xf375, 0xf366, 0xf368,
-  0xf360, 0xf360, 0xf360, 0xf374,
-  0xf374, 0xf374, 0xf340, 0xf340,
-  0xf35c, 0xf35c, 0xf36c, 0xf36c,
-  0xf360, 0xf360, 0xf372, 0xf376,
-  0xf376, 0xf373, 0xf360, 0xf360,
-  0xf35c, 0xf359, 0xf34c, 0xf355,
-};
-static const int8 kValueToGiveItemTo[76] = {
-     1,   2,   3,  4,
-     1,   2,   3,  1,
-     1,   1,   1,  1,
-     1,   2,  -1,  1,
-     1,   1,   1,  1,
-     2,   1,  -1, -1,
-     1,   1,   2,  1,
-     2,   1,   1,  1,
-    -1,   1,  -1,  2,
-    -1,  -1,  -1, -1,
-    -1,  -1,   2, -1,
-    -1,  -1,  -1, -1,
-    -1,  -1,  -1, -1,
-    -1,  -5, -20, -1,
-    -1,  -1,   1,  3,
-    -1,  -1,  -1, -1,
-  -100, -50,  -1,  1,
-    10,  -1,  -1, -1,
-    -1,   1,   3,  1,
-};
-static const uint8 kDungeon_DefaultAttr[384] = {
-  1, 1, 1, 0, 2, 1, 2, 0, 1, 1, 2, 2, 2, 2, 2, 2,
-  2, 2, 2, 0, 0, 1, 0, 0, 2, 0, 0, 2, 2, 2, 2, 2,
-  2, 2, 2, 2, 1, 1, 1, 2, 2, 2, 2, 2, 1, 1, 0, 0,
-  2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 1, 1, 0, 0,
-  0, 0, 0, 0x2a, 1, 0x20, 1, 1, 4, 1, 1, 0x18, 1, 2, 0x1c, 1,
-  0x28, 0x28, 0x2a, 0x2a, 1, 2, 1, 1, 4, 0, 0, 0, 0x28, 1, 0xa, 0,
-  1, 1, 0xc, 0xc, 2, 2, 2, 2, 0x28, 0x2a, 0x20, 0x20, 0x20, 2, 8, 0,
-  4, 4, 1, 1, 1, 2, 2, 2, 0, 0, 0x20, 0x20, 0, 2, 0, 0,
-  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2,
-  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0x18, 0x10, 0x10, 1, 1, 1,
-  1, 1, 4, 4, 4, 4, 4, 4, 1, 2, 2, 0, 0, 0, 0, 0,
-  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2,
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x62, 0x62,
-  0, 0, 0x24, 0x24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x62, 0x62,
-  0x27, 2, 2, 2, 0x27, 0x27, 1, 0, 0, 0, 0, 0x24, 0, 0, 0, 0,
-  0x27, 0x27, 0x27, 0x27, 0x27, 0x10, 2, 1, 0, 0, 0, 0x24, 0, 0, 0, 0,
-  0x27, 2, 2, 2, 0x27, 0x27, 0x27, 0x27, 2, 2, 2, 0x24, 0, 0, 0, 0,
-  0x27, 0x27, 0x27, 0x27, 0x27, 0x20, 2, 2, 1, 2, 2, 0x23, 2, 0, 0, 0,
-  0x27, 0x27, 0x27, 0x27, 0x27, 0x20, 2, 0x27, 2, 0x54, 0, 0, 0x27, 2, 2, 2,
-  0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 2, 0x27, 2, 0x54, 0, 0, 0x27, 2, 2, 2,
-  0x27, 0x27, 0, 0x27, 0x60, 0x60, 1, 1, 1, 1, 2, 2, 0xd, 0, 0, 0x4b,
-  0x67, 0x67, 0x67, 0x67, 0x66, 0x66, 0x66, 0x66, 0, 0, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-  0x27, 0x63, 0x27, 0x55, 0x55, 1, 0x44, 0, 1, 0x20, 2, 2, 0x1c, 0x3a, 0x3b, 0,
-  0x27, 0x63, 0x27, 0x53, 0x53, 1, 0x44, 1, 0xd, 0, 0, 0, 9, 9, 9, 9,
-};
-static PlayerHandlerFunc *const kModule_BossVictory[6] = {
-  &BossVictory_Heal,
-  &Dungeon_StartVictorySpin,
-  &Dungeon_RunVictorySpin,
-  &Dungeon_CloseVictorySpin,
-  &Dungeon_PrepExitWithSpotlight,
-  &Spotlight_ConfigureTableAndControl,
-};
-static PlayerHandlerFunc *const kModule_KillAgahnim[13] = {
-  &KillAgahnim_LoadMusic,
-  &KillAghanim_Init,
-  &KillAghanim_Func2,
-  &KillAghanim_Func3,
-  &KillAghanim_Func4,
-  &KillAghanim_Func5,
-  &KillAghanim_Func6,
-  &KillAghanim_Func7,
-  &KillAghanim_Func8,
-  &BossVictory_Heal,
-  &Dungeon_StartVictorySpin,
-  &Dungeon_RunVictorySpin,
-  &KillAghanim_Func12,
-};
-static PlayerHandlerFunc *const kMainRouting[28] = {
-  &Module00_Intro,
-  &Module01_FileSelect,
-  &Module02_CopyFile,
-  &Module03_KILLFile,
-  &Module04_NameFile,
-  &Module05_LoadFile,
-  &Module_PreDungeon,
-  &Module07_Dungeon,
-  &Module08_OverworldLoad,
-  &Module09_Overworld,
-  &Module08_OverworldLoad,
-  &Module09_Overworld,
-  &Module_Unknown0,
-  &Module_Unknown1,
-  &Module0E_Interface,
-  &Module0F_SpotlightClose,
-  &Module10_SpotlightOpen,
-  &Module11_DungeonFallingEntrance,
-  &Module12_GameOver,
-  &Module13_BossVictory_Pendant,
-  &Module14_Attract,
-  &Module15_MirrorWarpFromAga,
-  &Module16_BossVictory_Crystal,
-  &Module17_SaveAndQuit,
-  &Module18_GanonEmerges,
-  &Module19_TriforceRoom,
-  &Module1A_Credits,
-  &Module1B_SpawnSelect,
-};
-
-const uint16 *SrcPtr(uint16 src) {
-  return &kPredefinedTileData[src >> 1];
-}
-
-uint8 Ancilla_Sfx2_Near(uint8 a) {
-  return sound_effect_1 = PlaySfx_SetPan(a);
-}
-
-void Ancilla_Sfx3_Near(uint8 a) {
-  sound_effect_2 = PlaySfx_SetPan(a);
-}
-
-void LoadDungeonRoomRebuildHUD() {
-  mosaic_level = 0;
-  MOSAIC_copy = 7;
-  Hud_SearchForEquippedItem();
-  Hud_Rebuild();
-  Hud_UpdateEquippedItem();
-  Module_PreDungeon();
-}
-
-void Module_Unknown0() {
-  assert(0);
-}
-
-void Module_Unknown1() {
-  assert(0);
-}
-
-static void KillAgahnim_LoadMusic() {
-  nmi_disable_core_updates = 0;
-  overworld_map_state++;
-  submodule_index++;
-  LoadOWMusicIfNeeded();
-}
-
-static void KillAghanim_Init() {
-  music_control = 8;
-  BYTE(overworld_screen_trans_dir_bits) = 8;
-  InitializeMirrorHDMA();
-  overworld_map_state = 0;
-  PaletteFilter_InitializeWhiteFilter();
-  Overworld_LoadGFXAndScreenSize();
-  submodule_index++;
-  link_player_handler_state = kPlayerState_Mirror;
-  bg1_x_offset = 0;
-  bg1_y_offset = 0;
-  dung_savegame_state_bits = 0;
-  WORD(link_y_vel) = 0;
-  main_palette_buffer[0] = 0x7fff;
-  main_palette_buffer[32] = 0x7fff;
-  Ancilla_TerminateSelectInteractives(0);
-  Link_ResetProperties_A();
-}
-
-static void KillAghanim_Func2() {
-  HDMAEN_copy = 192;
-  MirrorWarp_BuildWavingHDMATable();
-  submodule_index++;
-  subsubmodule_index = 0;
-}
-
-static void KillAghanim_Func3() {
-  MirrorWarp_BuildWavingHDMATable();
-  if (subsubmodule_index) {
-    subsubmodule_index = 0;
-    submodule_index++;
-  }
-}
-
-static void KillAghanim_Func4() {
-  MirrorWarp_BuildDewavingHDMATable();
-  if (subsubmodule_index) {
-    subsubmodule_index = 0;
-    submodule_index++;
-  }
-}
-
-static void KillAghanim_Func5() {
-  HdmaSetup(0, 0xf2fb, 0x41, 0, (uint8)WH0, 0);
-  for (int i = 0; i < 240; i++)
-    hdma_table_dynamic[i] = 0xff00;
-  palette_filter_countdown = 0;
-  darkening_or_lightening_screen = 0;
-  dialogue_message_index = 0x35;
-  Main_ShowTextMessage();
-  ReloadPreviouslyLoadedSheets();
-  Hud_RebuildIndoor();
-  HDMAEN_copy = 0x80;
-  main_module_index = 21;
-  submodule_index = 6;
-  subsubmodule_index = 24;
-}
-
-static void KillAghanim_Func6() {
-  if (!--subsubmodule_index) {
-    submodule_index++;
-    sound_effect_ambient = 9;
-  }
-}
-
-static void KillAghanim_Func7() {
-  RenderText();
-  if (!submodule_index) {
-    overworld_map_state = 0;
-    sound_effect_ambient = 5;
-    if (!link_item_moon_pearl) {
-      dialogue_message_index = 0x36;
-      Main_ShowTextMessage();
-      sound_effect_ambient = 0;
-      main_module_index = 21;
-      submodule_index = 8;
-    } else {
-      submodule_index = 9;
-    }
-  }
-}
-
-static void KillAghanim_Func8() {
-  RenderText();
-  if (!submodule_index) {
-    subsubmodule_index = 32;
-    submodule_index = 12;
-  }
-}
-
-static void KillAghanim_Func12() {
-  if (--subsubmodule_index)
-    return;
-  ResetAncillaAndCutscene();
-  Overworld_SetSongList();
-  save_ow_event_info[0x1b] |= 32;
-  BYTE(cur_palace_index_x2) = 255;
-  submodule_index = 0;
-  overworld_map_state = 0;
-  nmi_disable_core_updates = 0;
-  main_module_index = 9;
-  BYTE(BG1VOFS_copy2) = 0;
-  music_control = link_item_moon_pearl ? 9 : 4;
-  savegame_map_icons_indicator = 6;
-}
-
-void Module_MainRouting() {  // 8080b5
-  kMainRouting[main_module_index]();
-}
-
-void NMI_PrepareSprites() {  // 8085fc
-  static const uint16 kLinkDmaSources1[303] = {
-    0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x8040, 0x8040, 0x8040, 0x8040, 0x8040, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000,
-    0x9440, 0x8080, 0x8080, 0x8080, 0x9400, 0x8040, 0x80c0, 0x80c0, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000,
-    0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x8040, 0x8040, 0x8040, 0x8040, 0x8040, 0x8000, 0xa8c0, 0xa900, 0x8000, 0xa8c0, 0xa900,
-    0x9100, 0x8080, 0x8080, 0x90c0, 0x8040, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x9a00, 0x9140, 0x9180, 0x8000, 0x9500,
-    0x9480, 0x94c0, 0x94c0, 0x9ae0, 0x8080, 0x8080, 0x9a60, 0x80c0, 0x80c0, 0x9aa0, 0x8000, 0x8000, 0x9aa0, 0x8000, 0x8000, 0x8080,
-    0x8080, 0x8100, 0x8100, 0x85c0, 0x8000, 0x8000, 0x85c0, 0x8000, 0x8000, 0xadc0, 0xadc0, 0xadc0, 0xadc0, 0xadc0, 0xad40, 0xad40,
-    0xad40, 0xad40, 0xad40, 0xad80, 0xad80, 0xad80, 0xad80, 0xad80, 0xad80, 0x8040, 0x9400, 0x8040, 0x8000, 0x8080, 0x8080, 0x9440,
-    0x8000, 0x8000, 0x8000, 0x8000, 0x8080, 0x8040, 0x8040, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0xc440, 0x8140, 0x8140,
-    0xca40, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8040, 0x85c0, 0x8040, 0x85c0, 0x8100, 0x80c0, 0x91c0, 0x8080, 0x8080,
-    0x8040, 0x8040, 0x8000, 0x8000, 0x8000, 0x8000, 0x8080, 0x8080, 0x9100, 0xa0c0, 0xa100, 0xa100, 0xa1c0, 0xa400, 0xa440, 0xa1c0,
-    0xa400, 0xa440, 0x8080, 0xc480, 0x8080, 0x8040, 0x8040, 0xca80, 0xca80, 0xca00, 0xc400, 0xca00, 0xc400, 0x81c0, 0x8080, 0x8080,
-    0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x8040, 0x8040, 0x8040, 0x8040, 0x8040, 0x8040, 0x8040, 0x8000, 0xa8c0, 0xa900,
-    0x8000, 0x8000, 0xa8c0, 0xa900, 0x8000, 0xa8c0, 0xa900, 0x8000, 0x8000, 0xa8c0, 0xa900, 0x8040, 0x8040, 0x8040, 0x8080, 0x8080,
-    0x8040, 0x8040, 0x8040, 0x8040, 0x8000, 0x8000, 0x8000, 0x8000, 0xd080, 0x8080, 0x90c0, 0xd000, 0x9080, 0xd040, 0x9080, 0xd040,
-    0xd080, 0xd080, 0xd080, 0xd080, 0xd080, 0xd000, 0xd000, 0xd000, 0xd000, 0xd000, 0xd040, 0xd040, 0xd040, 0xd040, 0xd040, 0xd040,
-    0x8040, 0xd000, 0x85c0, 0x85c0, 0x85c0, 0xdc40, 0xdc40, 0xdc40, 0x85c0, 0x85c0, 0x85c0, 0xdc40, 0xdc40, 0xdc40, 0xe1c0, 0xd000,
-    0x8000, 0xe400, 0xe400, 0xe440, 0x90c0, 0x90c0, 0xd000, 0x8000, 0x8000, 0xd040, 0x8000, 0x8000, 0xd040, 0xe400, 0xe400, 0xe400,
-    0x9080, 0xa5c0, 0xac40, 0xe480, 0x8180, 0x90c0, 0x80c0, 0xe180, 0xd000, 0xe4c0, 0xe4c0, 0xe840, 0xe840, 0xe840, 0xe540, 0xe540,
-    0xe540, 0xe900, 0xe900, 0xe900, 0xe900, 0x8080, 0x8080, 0x8000, 0xa9c0, 0x8080, 0x8140, 0x91c0, 0x8040, 0xa800, 0xa840,
-  };
-  static const uint16 kLinkDmaSources2[303] = {
-    0x8840, 0x8800, 0x8580, 0x8800, 0x8580, 0x84c0, 0x8500, 0x8540, 0x8500, 0x8540, 0x8400, 0x8440, 0x8480, 0x8400, 0x8440, 0x8480,
-    0x9640, 0x8c40, 0x8c80, 0xad00, 0x9600, 0x8980, 0x8c00, 0xacc0, 0x8880, 0x88c0, 0x8900, 0x8940, 0x8880, 0x88c0, 0x8900, 0x8940,
-    0xb0c0, 0xb100, 0xb140, 0xb100, 0xb140, 0xb000, 0xb040, 0xb080, 0xec80, 0xecc0, 0xb180, 0xd440, 0xb1c0, 0xb180, 0xd440, 0xb1c0,
-    0x8c80, 0xad00, 0x95c0, 0x99c0, 0xb440, 0x9580, 0xb480, 0xb4c0, 0x9580, 0xb480, 0xb4c0, 0x9c20, 0x8000, 0x8000, 0x8000, 0x9700,
-    0x9680, 0x96c0, 0x96c0, 0x9ce0, 0x8c80, 0xb540, 0x9c60, 0xb580, 0x8c00, 0x9ca0, 0x8900, 0xb500, 0x9ca0, 0x8900, 0xb500, 0x8c40,
-    0xec40, 0x8c00, 0xec00, 0x8dc0, 0x9540, 0x89c0, 0x8dc0, 0x9540, 0x89c0, 0xb940, 0xb980, 0xb9c0, 0xb980, 0xb9c0, 0xb5c0, 0xb800,
-    0xb840, 0xb800, 0xb840, 0xb880, 0xb8c0, 0xb900, 0xb880, 0xb8c0, 0xb900, 0x8980, 0x9600, 0xbcc0, 0x8400, 0xbc80, 0x8c40, 0x9640,
-    0xa040, 0xa080, 0xa000, 0xbc40, 0xbd40, 0x8500, 0xbd00, 0xbd80, 0xbd80, 0x88c0, 0x8900, 0xe9c0, 0x8900, 0xc640, 0xc040, 0xc000,
-    0xcc40, 0x8940, 0x88c0, 0x8900, 0xe9c0, 0x8900, 0x8940, 0x8d40, 0x8d80, 0x8d40, 0x8d80, 0xbd00, 0xb000, 0xb000, 0xa480, 0xa480,
-    0xa480, 0xa480, 0xac00, 0xac00, 0xac00, 0xac00, 0xa140, 0xa180, 0xa180, 0xa4c0, 0xa4c0, 0xa500, 0x9d40, 0x9d80, 0x9dc0, 0x9d40,
-    0x9d80, 0x9dc0, 0x8d00, 0xc680, 0xc180, 0xc140, 0x8c00, 0xcc80, 0xcc80, 0xcc00, 0xc600, 0xcc00, 0xc600, 0xbd00, 0x8580, 0x8800,
-    0xc9c0, 0xccc0, 0xcdc0, 0xcd00, 0xcd40, 0xcd80, 0x8500, 0x8540, 0xc940, 0xc980, 0x8540, 0xc940, 0xc980, 0x8440, 0x8480, 0xc1c0,
-    0xc900, 0xc580, 0xc5c0, 0xc8c0, 0x8440, 0x8480, 0xc1c0, 0xc900, 0xc580, 0xc5c0, 0xc8c0, 0xbd00, 0xacc0, 0xc040, 0xd540, 0xd580,
-    0xd4c0, 0xd500, 0xd4c0, 0xd500, 0xd440, 0xd480, 0xd440, 0xd480, 0xd1c0, 0xd400, 0xd100, 0xd100, 0xd140, 0xd180, 0xd140, 0xd180,
-    0xb0c0, 0xb100, 0xb140, 0xb100, 0xb140, 0xdd40, 0xdd80, 0xddc0, 0xdd80, 0xddc0, 0xdc80, 0xdcc0, 0xdd00, 0xdc80, 0xdcc0, 0xdd00,
-    0xd100, 0xd100, 0xe000, 0xe040, 0xe080, 0xe0c0, 0xe100, 0xe140, 0xe000, 0xe040, 0xe080, 0xe0c0, 0xe100, 0xe140, 0x8000, 0xd0c0,
-    0x8000, 0xb940, 0xb980, 0xb940, 0xdd40, 0xdd80, 0xdd40, 0xdc80, 0xdcc0, 0xc0c0, 0xdc80, 0xdcc0, 0xc0c0, 0xb9c0, 0xb980, 0xb9c0,
-    0xa560, 0xa5a0, 0xac80, 0xed00, 0x8000, 0x8cc0, 0xbd00, 0xe380, 0xbdc0, 0xe500, 0xe500, 0xe880, 0xe8c0, 0xe8c0, 0xe800, 0xe5c0,
-    0xe5c0, 0xe940, 0xe980, 0xe940, 0xe980, 0xbd40, 0x8c80, 0xa080, 0x8000, 0xa980, 0xbd00, 0xbdc0, 0xb400, 0xa880, 0xedc0,
-  };
-  static const uint16 kLinkDmaSources3[27] = {
-    0x9a40, 0x9e00, 0x9d20, 0x9f20, 0x9b20, 0xbc20, 0xbc20, 0xbe20, 0xbe20, 0xbe00, 0xbe00, 0xbe00, 0xbe00, 0xa540, 0xa540, 0xa540,
-    0xa540, 0xbc00, 0xbc00, 0xbc00, 0xbc00, 0xa740, 0xa740, 0xa740, 0xa740, 0xe780, 0xe780,
-  };
-  static const uint16 kLinkDmaSources4[8] = { 0x9000, 0x9020, 0x9060, 0x91e0, 0x90a0, 0x90c0, 0x9100, 0x9140 };
-  static const uint16 kLinkDmaSources5[3] = { 0x9300, 0x9340, 0x9380 };
-  static const uint16 kLinkDmaSources6[128] = {
-    0x9480, 0x94c0, 0x94e0, 0x95c0, 0x9500, 0x9520, 0x9540, 0x9480, 0x9640, 0x9680, 0x96a0, 0x9780, 0x96c0, 0x96e0, 0x9700, 0x9480,
-    0x9800, 0x9840, 0x98a0, 0x9480, 0x9480, 0x9480, 0x9480, 0x9480, 0x9ac0, 0x9b00, 0x9480, 0x9480, 0x9480, 0x9480, 0x9480, 0x9480,
-    0x9bc0, 0x9c00, 0x9c40, 0x9c80, 0x9cc0, 0x9d00, 0x9d40, 0x9480, 0x9f40, 0x9f80, 0x9fc0, 0x9fe0, 0xa000, 0x9480, 0x9480, 0x9480,
-    0xa100, 0x9480, 0x9480, 0x9480, 0x9480, 0x9480, 0x9480, 0x9480, 0x9480, 0x9480, 0x9480, 0x9480, 0x9480, 0x9480, 0x9480, 0x9480,
-    0x98c0, 0x9900, 0x99c0, 0x99e0, 0x9a00, 0x9a20, 0x9a40, 0x9a60, 0x9480, 0x9480, 0x9480, 0x9480, 0x9480, 0x9480, 0x9480, 0x9480,
-    0x9a80, 0x9480, 0x9480, 0x9480, 0x9480, 0x9480, 0x9480, 0x9480, 0x9480, 0x9480, 0x9480, 0x9480, 0x9480, 0x9480, 0x9480, 0x9480,
-    0x9480, 0x9480, 0x9480, 0x9480, 0x9480, 0x9480, 0x9480, 0x9480, 0x9480, 0x9480, 0x9480, 0x9480, 0x9480, 0x9480, 0x9480, 0x9480,
-    0x9480, 0x9480, 0x9480, 0x9480, 0x9480, 0x9480, 0x9480, 0x9480, 0x9480, 0x9480, 0x9480, 0x9480, 0x9480, 0x9480, 0x9480, 0x9480,
-  };
-  static const uint16 kLinkDmaSources7[16] = { 0xe0, 0xe0, 0x60, 0x80, 0x1c0, 0xe0, 0x40, 0, 0x80, 0, 0x40, 0, 0, 0, 0, 0 };
-  static const uint16 kLinkDmaCtrs0[6] = { 14, 4, 6, 16, 6, 8 };
-  static const uint16 kLinkDmaSources9[15] = { 0, 0x20, 0x40, 0, 0x20, 0x40, 0, 0x40, 0x80, 0, 0x40, 0x80, 0xb340, 0xb400, 0xb4c0 };
-  static const uint16 kLinkDmaSources8[4] = { 0xa480, 0xa4c0, 0xa500, 0xa540 };
-
-  for (int i = 0; i < 32; i++) {
-    extended_oam[i] = bytewise_extended_oam[3 + 4 * i] << 6 |
-      bytewise_extended_oam[2 + 4 * i] << 4 |
-      bytewise_extended_oam[1 + 4 * i] << 2 |
-      bytewise_extended_oam[0 + 4 * i] << 0;
-  }
-
-  dma_source_addr_3 = kLinkDmaSources1[link_dma_graphics_index >> 1];
-  dma_source_addr_0 = dma_source_addr_3 + 0x200;
-  dma_source_addr_4 = kLinkDmaSources2[link_dma_graphics_index >> 1];
-  dma_source_addr_1 = dma_source_addr_4 + 0x200;
-  dma_source_addr_5 = kLinkDmaSources3[link_dma_var1 >> 1];
-  dma_source_addr_2 = kLinkDmaSources3[link_dma_var2 >> 1];
-
-
-  dma_source_addr_6 = kLinkDmaSources4[link_dma_var3 >> 1];
-  dma_source_addr_11 = dma_source_addr_6 + 0x180;
-
-  if (link_dma_var4 == 0x8b) {
-    dma_source_addr_7 = 0xe099;
-  } else {
-    dma_source_addr_7 = kLinkDmaSources5[link_dma_var4 >> 1];
-  }
-  dma_source_addr_12 = dma_source_addr_7 + 0xc0;
-
-
-  int j = (link_dma_var5 & 0xf8) >> 3;
-  dma_source_addr_8 = kLinkDmaSources6[link_dma_var5];
-  dma_source_addr_13 = dma_source_addr_8 + kLinkDmaSources7[j];
-  dma_source_addr_10 = kLinkDmaSources8[pushedblocks_some_index & 3];
-  dma_source_addr_15 = dma_source_addr_10 + 0x100;
-
-  if (--bg_tile_animation_countdown == 0) {
-    bg_tile_animation_countdown = (BYTE(overlay_index) == 0xb5 || BYTE(overlay_index) == 0xbc) ? 0x17 : 9;
-
-    uint16 t = word_7EC00F + 0x400;
-    if (t == 0xc00)
-      t = 0;
-    word_7EC00F = t;
-    animated_tile_data_src = 0xa680 + word_7EC00F;
-  }
-
-  if (--word_7EC013 == 0) {
-    int t = word_7EC015 + 2;
-    if (t == 12)
-      t = 0;
-    word_7EC015 = t;
-    word_7EC013 = kLinkDmaCtrs0[t >> 1];
-    dma_source_addr_9 = kLinkDmaSources9[t >> 1] + 0xb280;
-    dma_source_addr_14 = dma_source_addr_9 + 0x60;
-  }
-
-  dma_source_addr_16 = 0xB940 + dma_var6 * 2;
-  dma_source_addr_18 = dma_source_addr_16 + 0x200;
-
-  dma_source_addr_17 = 0xB940 + dma_var7 * 2;
-  dma_source_addr_19 = dma_source_addr_17 + 0x200;
-
-  dma_source_addr_20 = 0xB540 + flag_travel_bird * 2;
-  dma_source_addr_21 = dma_source_addr_20 + 0x200;
-}
-
-void Sound_LoadIntroSongBank() {  // 808901
-  LoadSongBank(kSoundBank_intro);
-}
-
-void LoadOverworldSongs() {  // 808913
-  LoadSongBank(kSoundBank_intro);
-}
-
-void LoadDungeonSongs() {  // 808925
-  LoadSongBank(kSoundBank_indoor);
-}
-
-void LoadCreditsSongs() {  // 808931
-  LoadSongBank(kSoundBank_ending);
-}
-
-void Dungeon_LightTorch() {  // 81f3ec
-  if ((byte_7E0333 & 0xf0) != 0xc0) {
-    byte_7E0333 = 0;
-    return;
-  }
-  uint8 r8 = (uint8)dungeon_room_index == 0 ? 0x80 : 0xc0;
-
-  int i = (byte_7E0333 & 0xf) + (dung_index_of_torches_start >> 1);
-  int opos = dung_object_pos_in_objdata[i];
-  if (dung_object_tilemap_pos[i] & 0x8000)
-    return;
-  dung_object_tilemap_pos[i] |= 0x8000;
-  if (r8 == 0)
-    dung_torch_data[opos] = dung_object_tilemap_pos[i];
-
-  uint16 x = dung_object_tilemap_pos[i] & 0x3fff;
-  RoomDraw_AdjustTorchLightingChange(x, 0xeca, x);
-
-  sound_effect_1 = 42 | CalculateSfxPan_Arbitrary((x & 0x7f) * 2);
-
-  nmi_copy_packets_flag = 1;
-  if (dung_want_lights_out) {
-    if (dung_num_lit_torches++ < 3) {
-      TS_copy = 0;
-      overworld_fixed_color_plusminus = kLitTorchesColorPlus[dung_num_lit_torches];
-      submodule_index = 10;
-      subsubmodule_index = 0;
-    }
-  }
-
-  dung_torch_timers[byte_7E0333 & 0xf] = r8;
-  byte_7E0333 = 0;
-}
-
-void RoomDraw_AdjustTorchLightingChange(uint16 x, uint16 y, uint16 r8) {  // 81f746
-  const uint16 *ptr = SrcPtr(y);
-  x >>= 1;
-  overworld_tileattr[x + 0] = ptr[0];
-  overworld_tileattr[x + 64] = ptr[1];
-  overworld_tileattr[x + 1] = ptr[2];
-  overworld_tileattr[x + 65] = ptr[3];
-  Dungeon_PrepOverlayDma_nextPrep(0, r8);
-}
-
-int Dungeon_PrepOverlayDma_nextPrep(int dst, uint16 r8) {  // 81f764
-  uint16 r6 = 0x880 + ((r8 & 0x3f) >= 0x3a);
-  return Dungeon_PrepOverlayDma_watergate(dst, r8, r6, 4);
-}
-
-int Dungeon_PrepOverlayDma_watergate(int dst, uint16 r8, uint16 r6, int loops) {  // 81f77c
-  for (int k = 0; k < loops; k++) {
-    int x = r8 >> 1;
-    vram_upload_tile_buf[dst + 0] = ((r8 & 0x40) << 4) | ((r8 & 0x303f) >> 1) | ((r8 & 0xf80) >> 2);
-    vram_upload_tile_buf[dst + 1] = r6;
-    vram_upload_tile_buf[dst + 2] = overworld_tileattr[x + 0];
-    if (!(r6 & 1)) {
-      vram_upload_tile_buf[dst + 3] = overworld_tileattr[x + 1];
-      vram_upload_tile_buf[dst + 4] = overworld_tileattr[x + 2];
-      vram_upload_tile_buf[dst + 5] = overworld_tileattr[x + 3];
-      r8 += 128;
-    } else {
-      vram_upload_tile_buf[dst + 3] = overworld_tileattr[x + 64];
-      vram_upload_tile_buf[dst + 4] = overworld_tileattr[x + 128];
-      vram_upload_tile_buf[dst + 5] = overworld_tileattr[x + 192];
-      r8 += 2;
-    }
-    dst += 6;
-  }
-  vram_upload_tile_buf[dst] = 0xffff;
-  return dst;
-}
-
-void Module05_LoadFile() {  // 828136
-  EnableForceBlank();
-  overworld_map_state = 0;
-  dung_unk6 = 0;
-  byte_7E02D4 = 0;
-  byte_7E02D7 = 0;
-  tagalong_var5 = 0;
-  byte_7E0379 = 0;
-  byte_7E03FD = 0;
-  EraseTileMaps_normal();
-  LoadDefaultGraphics();
-  Sprite_LoadGraphicsProperties();
-  Init_LoadDefaultTileAttr();
-  DecompressSwordGraphics();
-  DecompressShieldGraphics();
-  Link_Initialize();
-  LoadFollowerGraphics();
-  sprite_gfx_subset_0 = 70;
-  sprite_gfx_subset_1 = 70;
-  sprite_gfx_subset_2 = 70;
-  sprite_gfx_subset_3 = 70;
-  word_7E02CD = 0x200;
-  virq_trigger = 48;
-  if (savegame_is_darkworld) {
-    if (player_is_indoors) {
-      LoadDungeonRoomRebuildHUD();
-      return;
-    }
-    Hud_SearchForEquippedItem();
-    Hud_Rebuild();
-    Hud_UpdateEquippedItem();
-    death_var5 = 0;
-    dungeon_room_index = 32;
-    main_module_index = 8;
-    submodule_index = 0;
-    subsubmodule_index = 0;
-    death_var4 = 0;
-  } else {
-    if (mosaic_level || death_var5 != 0 && !death_var4 || sram_progress_indicator < 2 || which_starting_point == 5) {
-      LoadDungeonRoomRebuildHUD();
-      return;
-    }
-    dialogue_message_index = (link_item_mirror == 2) ? 0x185 : 0x184;
-    Main_ShowTextMessage();
-    Dungeon_LoadPalettes();
-    INIDISP_copy = 15;
-    TM_copy = 4;
-    TS_copy = 0;
-    main_module_index = 27;
-  }
-}
-
-void Module13_BossVictory_Pendant() {  // 829c4a
-  kModule_BossVictory[submodule_index]();
-  Sprite_Main();
-  LinkOam_Main();
-}
-
-void BossVictory_Heal() {  // 829c59
-  if (!Hud_RefillMagicPower())
-    overworld_map_state++;
-  if (!Hud_RefillHealth())
-    overworld_map_state++;
-  if (!overworld_map_state) {
-    button_mask_b_y &= ~0x40;
-    Dungeon_ResetTorchBackgroundAndPlayerInner();
-    link_direction_facing = 2;
-    link_direction_last = 2 << 1;
-    flag_update_hud_in_nmi++;
-    submodule_index++;
-    subsubmodule_index = 16;
-    flag_is_link_immobilized++;
-  }
-  overworld_map_state = 0;
-  Hud_RefillLogic();
-}
-
-void Dungeon_StartVictorySpin() {  // 829c93
-  if (--subsubmodule_index)
-    return;
-  flag_is_link_immobilized = 0;
-  link_direction_facing = 2;
-  Link_AnimateVictorySpin();
-  Ancilla_TerminateSelectInteractives(0);
-  AncillaAdd_VictorySpin();
-  submodule_index++;
-}
-
-void Dungeon_RunVictorySpin() {  // 829cad
-  Link_Main();
-  if (link_player_handler_state != 0)
-    return;
-  if (link_sword_type + 1 & 0xfe)
-    sound_effect_1 = 0x2C;
-  link_force_hold_sword_up = 1;
-  subsubmodule_index = 32;
-  submodule_index++;
-}
-
-void Dungeon_CloseVictorySpin() {  // 829cd1
-  if (--subsubmodule_index)
-    return;
-  submodule_index++;
-  link_y_vel = 0;
-  link_x_vel = 0;
-  overworld_fixed_color_plusminus = 0;
-}
-
-void Module15_MirrorWarpFromAga() {  // 829cfc
-  kModule_KillAgahnim[submodule_index]();
-  if (submodule_index < 2 || submodule_index >= 5) {
-    Sprite_Main();
-    LinkOam_Main();
-  }
-}
-
-void Module16_BossVictory_Crystal() {  // 829e8a
-  switch (submodule_index) {
-  case 0: BossVictory_Heal(); break;
-  case 1: Dungeon_StartVictorySpin(); break;
-  case 2: Dungeon_RunVictorySpin(); break;
-  case 3: Dungeon_CloseVictorySpin(); break;
-  case 4: Module16_04_FadeAndEnd(); break;
-  }
-  Sprite_Main();
-  LinkOam_Main();
-}
-
-void Module16_04_FadeAndEnd() {  // 829e9a
-  if (--INIDISP_copy)
-    return;
-  bg1_x_offset = 0;
-  bg1_y_offset = 0;
-  link_y_vel = 0;
-  flag_is_link_immobilized = 0;
-  Palette_RevertTranslucencySwap();
-  link_player_handler_state = kPlayerState_Ground;
-  link_receiveitem_index = 0;
-  link_pose_for_item = 0;
-  link_disable_sprite_damage = 0;
-  main_module_index = saved_module_for_menu;
-  submodule_index = 0;
-  subsubmodule_index = 0;
-  OpenSpotlight_Next2();
-}
-
-static uint8 PlaySfx_SetPan(uint8 a) {  // 878036
-  byte_7E0CF8 = a;
-  return a | Link_CalculateSfxPan();
-}
-
-void TriforceRoom_LinkApproachTriforce() {  // 87f49c
-  uint8 y = link_y_coord;
-  if (y < 152) {
-    link_animation_steps = 0;
-    link_direction = 0;
-    link_direction_last = 0;
-    if (!--link_delay_timer_spin_attack) {
-      link_pose_for_item = 2;
-      subsubmodule_index++;
-    }
-  } else {
-    if (y < 169)
-      link_speed_setting = 0x14;
-    link_direction = 8;
-    link_direction_last = 8;
-    link_direction_facing = 0;
-    link_delay_timer_spin_attack = 64;
-  }
-}
-
-void AncillaAdd_ItemReceipt(uint8 ain, uint8 yin, int chest_pos) {  // 8985e8
-  int ancilla = Ancilla_AddAncilla(ain, yin);
-  if (ancilla < 0)
-    return;
-
-  flag_is_link_immobilized = (link_receiveitem_index == 0x20) ? 2 : 1;
-  uint8 t;
-
-  int j = link_receiveitem_index;
-  if (j == 0) {
-    g_ram[kMemoryLocationToGiveItemTo[4]] = kValueToGiveItemTo[0];
-  }
-
-  uint8 v = kValueToGiveItemTo[j];
-  uint8 *p = &g_ram[kMemoryLocationToGiveItemTo[j]];
-  if (!sign8(v))
-    *p = v;
-
-  if (j == 0x1f)
-    link_is_bunny = 0;
-  else if (j == 0x4b || j == 0x1e)
-    link_ability_flags |= (j == 0x4b) ? 4 : 2;
-
-  if (j == 0x1b || j == 0x1c) {
-    Palette_UpdateGlovesColor();
-  } else if ((t = 4, j == 0x37) || (t = 1, j == 0x38) || (t = 2, j == 0x39)) {
-    *p |= t;
-    if ((*p & 7) == 7)
-      savegame_map_icons_indicator = 4;
-    overworld_map_state++;
-  } else if (j == 0x22) {
-    if (*p == 0)
-      *p = 1;
-  } else if (j == 0x25 || j == 0x32 || j == 0x33) {
-    WORD(*p) |= 0x8000 >> (BYTE(cur_palace_index_x2) >> 1);
-  } else if (j == 0x3e) {
-    if (link_state_bits & 0x80)
-      link_picking_throw_state = 2;
-  } else if (j == 0x20) {
-    overworld_map_state++;
-    for (int i = 4; i >= 0; i--) {
-      if (ancilla_type[i] == 7 || ancilla_type[i] == 0x2c) {
-        ancilla_type[i] = 0;
-        link_state_bits = 0;
-        link_picking_throw_state = 0;
-      }
-    }
-    if (link_cape_mode) {
-      link_bunny_transform_timer = 32;
-      link_disable_sprite_damage = 0;
-      link_cape_mode = 0;
-      AncillaAdd_CapePoof(0x23, 4);
-      sound_effect_1 = 0x15 | Link_CalculateSfxPan();
-    }
-  } else if (j == 0x29) {
-    if (link_item_mushroom != 2) {
-      *p = 1;
-      Hud_RefreshIcon();
-    }
-  } else if ((t = 1, j == 0x24) || item_receipt_method != 2 && (j == 0x27 || (t = 3, j == 0x28) || (t = 10, j == 0x31))) {
-    *p += t;
-    if (*p > 99)
-      *p = 99;
-    Hud_RefreshIcon();
-  } else if (j == 0x17) {
-    *p = (*p + 1) & 3;
-    sound_effect_2 = 0x2d | Link_CalculateSfxPan();
-  } else if (j == 1) {
-    Overworld_SetSongList();
-  } else {
-    ItemReceipt_GiveBottledItem(j);
-  }
-
-  uint8 gfx = kReceiveItemGfx[j];
-  if (gfx == 0xff) {
-    gfx = 0;
-  } else if (gfx == 0x20 || gfx == 0x2d || gfx == 0x2e) {
-    DecompressShieldGraphics();
-    Palette_Load_Shield();
-  }
-  DecodeAnimatedSpriteTile_variable(gfx);
-
-  if ((gfx == 6 || gfx == 0x18) && j != 0) {
-    DecompressSwordGraphics();
-    Palette_Load_Sword();
-  }
-
-  ancilla_item_to_link[ancilla] = j;
-  ancilla_arr1[ancilla] = 0;
-
-  if (j == 1 && item_receipt_method != 2) {
-    ancilla_timer[ancilla] = 160;
-    submodule_index = 43;
-    BYTE(palette_filter_countdown) = 0;
-    AncillaAdd_MSCutscene(0x35, 4);
-    ancilla_arr3[ancilla] = 2;
-  } else {
-    ancilla_arr3[ancilla] = 9;
-  }
-  ancilla_arr4[ancilla] = 5;
-  ancilla_step[ancilla] = item_receipt_method;
-
-  ancilla_aux_timer[ancilla] =
-    (j == 0x20 || j == 0x37 || j == 0x38 || j == 0x39) ? 0x68 :
-    (j == 0x26) ? 0x2 : (item_receipt_method ? 0x38 : 0x60);
-
-  int x, y;
-
-  if (item_receipt_method == 1) {
-    y = (chest_pos & 0x1f80) >> 4;
-    x = (chest_pos & 0x7e) << 2;
-    y += dung_loade_bgoffs_v_copy & ~0xff;
-    x += dung_loade_bgoffs_h_copy & ~0xff;
-    y += kReceiveItem_Tab2[j];
-    x += kReceiveItem_Tab3[j];
-  } else {
-    if (ancilla_step[ancilla] == 0 && j == 1) {
-      sound_effect_1 = Link_CalculateSfxPan() | 0x2c;
-    } else if (j == 0x20 || j == 0x37 || j == 0x38 || j == 0x39) {
-      music_control = Link_CalculateSfxPan() | 0x13;
-    } else if (j != 0x3e && j != 0x17) {
-      sound_effect_2 = Link_CalculateSfxPan() | 0xf;
-    }
-    int method = item_receipt_method == 3 ? 0 : item_receipt_method;
-    x = (method != 0) ? kReceiveItem_Tab3[j] :
-      (kReceiveItem_Tab1[j] == 0) ? 10 : (j == 0x20) ? 0 : 6;
-    x += link_x_coord;
-    y = method ? kReceiveItem_Tab2[j] : -14;
-    y += link_y_coord + ((method == 2) ? -8 : 0);
-  }
-  Ancilla_SetXY(ancilla, x, y);
-}
-
-void ItemReceipt_GiveBottledItem(uint8 item) {  // 89893e
-  static const uint8 kBottleList[7] = { 0x16, 0x2b, 0x2c, 0x2d, 0x3d, 0x3c, 0x48 };
-  static const uint8 kPotionList[5] = { 0x2e, 0x2f, 0x30, 0xff, 0xe };
-  int j;
-  if ((j = FindInByteArray(kBottleList, item, 7)) >= 0) {
-    for (int i = 0; i != 4; i++) {
-      if (link_bottle_info[i] < 2) {
-        link_bottle_info[i] = j + 2;
-        return;
-      }
-    }
-  }
-  if ((j = FindInByteArray(kPotionList, item, 5)) >= 0) {
-    for (int i = 0; i != 4; i++) {
-      if (link_bottle_info[i] == 2) {
-        link_bottle_info[i] = j + 3;
-        return;
-      }
-    }
-  }
-}
-
-void Module17_SaveAndQuit() {  // 89f79f
-  switch (submodule_index) {
-  case 0:
-    submodule_index++;
-  case 1:
-    if (!--INIDISP_copy) {
-      MOSAIC_copy = 15;
-      subsubmodule_index = 1;
-      Death_Func15(false);
-    }
-    break;
-  }
-  Sprite_Main();
-  LinkOam_Main();
-}
-
-void WallMaster_SendPlayerToLastEntrance() {  // 8bffa8
-  SaveDungeonKeys();
-  Dungeon_FlagRoomData_Quadrants();
-  Sprite_ResetAll();
-  death_var4 = 0;
-  main_module_index = 17;
-  submodule_index = 0;
-  nmi_load_bg_from_vram = 0;
-  ResetSomeThingsAfterDeath(17);  // wtf: argument?
-}
-
-uint8 GetRandomNumber() {  // 8dba71
-  uint8 t = byte_7E0FA1 + frame_counter;
-  t = (t & 1) ? (t >> 1) : (t >> 1) ^ 0xb8;
-  byte_7E0FA1 = t;
-  return t;
-}
-
-uint8 Link_CalculateSfxPan() {  // 8dbb67
-  return CalculateSfxPan(link_x_coord);
-}
-
-void SpriteSfx_QueueSfx1WithPan(int k, uint8 a) {  // 8dbb6e
-  if (sound_effect_ambient == 0)
-    sound_effect_ambient = a | Sprite_CalculateSfxPan(k);
-}
-
-void SpriteSfx_QueueSfx2WithPan(int k, uint8 a) {  // 8dbb7c
-  if (sound_effect_1 == 0)
-    sound_effect_1 = a | Sprite_CalculateSfxPan(k);
-}
-
-void SpriteSfx_QueueSfx3WithPan(int k, uint8 a) {  // 8dbb8a
-  if (sound_effect_2 == 0)
-    sound_effect_2 = a | Sprite_CalculateSfxPan(k);
-}
-
-uint8 Sprite_CalculateSfxPan(int k) {  // 8dbba1
-  return CalculateSfxPan(Sprite_GetX(k));
-}
-
-uint8 CalculateSfxPan(uint16 x) {  // 8dbba8
-  static const uint8 kPanTable[] = { 0, 0x80, 0x40 };
-  int o = 0;
-  x -= BG2HOFS_copy2 + 80;
-  if (x >= 80)
-    o = 1 + ((int16)x >= 0);
-  return kPanTable[o];
-}
-
-uint8 CalculateSfxPan_Arbitrary(uint8 a) {  // 8dbbd0
-  static const uint8 kTorchPans[] = { 0x80, 0x80, 0x80, 0, 0, 0x40, 0x40, 0x40 };
-  return kTorchPans[((a - BG2HOFS_copy2) >> 5) & 7];
-}
-
-void Init_LoadDefaultTileAttr() {  // 8e97d9
-  memcpy(attributes_for_tile, kDungeon_DefaultAttr, 0x140);
-  memcpy(attributes_for_tile + 0x1c0, kDungeon_DefaultAttr + 0x140, 64);
-}
-
-void Main_ShowTextMessage() {  // 8ffdaa
-  if (main_module_index != 14) {
-    byte_7E0223 = 0;
-    messaging_module = 0;
-    submodule_index = 2;
-    saved_module_for_menu = main_module_index;
-    main_module_index = 14;
-  }
-}
-
-uint8 HandleItemTileAction_Overworld(uint16 x, uint16 y) {  // 9bbd7a
-  if (player_is_indoors)
-    return HandleItemTileAction_Dungeon(x, y);
-  else
-    return Overworld_ToolAndTileInteraction(x, y);
-}
-
--- a/misc.h
+++ /dev/null
@@ -1,76 +1,0 @@
-#include "types.h"
-#include "variables.h"
-#include "zelda_rtl.h"
-
-#pragma once
-
-
-
-
-
-
-
-
-
-static inline OamEnt *GetOamCurPtr() {
-  return (OamEnt *)&g_ram[oam_cur_ptr];
-}
-
-static inline int FindInByteArray(const uint8 *data, uint8 lookfor, size_t size) {
-  for (size_t i = size; i--;)
-    if (data[i] == lookfor)
-      return (int)i;
-  return -1;
-}
-
-static inline int FindInWordArray(const uint16 *data, uint16 lookfor, size_t size) {
-  for (size_t i = size; i--;)
-    if (data[i] == lookfor)
-      return (int)i;
-  return -1;
-}
-
-
-extern const uint16 kMemoryLocationToGiveItemTo[76];
-
-const uint16 *SrcPtr(uint16 src);
-uint8 Ancilla_Sfx2_Near(uint8 a);
-void Ancilla_Sfx3_Near(uint8 a);
-void LoadDungeonRoomRebuildHUD();
-void Module_Unknown0();
-void Module_Unknown1();
-void Module_MainRouting();
-void NMI_PrepareSprites();
-void Sound_LoadIntroSongBank();
-void LoadOverworldSongs();
-void LoadDungeonSongs();
-void LoadCreditsSongs();
-void Dungeon_LightTorch();
-void RoomDraw_AdjustTorchLightingChange(uint16 x, uint16 y, uint16 r8);
-int Dungeon_PrepOverlayDma_nextPrep(int dst, uint16 r8);
-int Dungeon_PrepOverlayDma_watergate(int dst, uint16 r8, uint16 r6, int loops);
-void Module05_LoadFile();
-void Module13_BossVictory_Pendant();
-void BossVictory_Heal();
-void Dungeon_StartVictorySpin();
-void Dungeon_RunVictorySpin();
-void Dungeon_CloseVictorySpin();
-void Module15_MirrorWarpFromAga();
-void Module16_BossVictory_Crystal();
-void Module16_04_FadeAndEnd();
-void TriforceRoom_LinkApproachTriforce();
-void AncillaAdd_ItemReceipt(uint8 ain, uint8 yin, int chest_pos);
-void ItemReceipt_GiveBottledItem(uint8 item);
-void Module17_SaveAndQuit();
-void WallMaster_SendPlayerToLastEntrance();
-uint8 GetRandomNumber();
-uint8 Link_CalculateSfxPan();
-void SpriteSfx_QueueSfx1WithPan(int k, uint8 a);
-void SpriteSfx_QueueSfx2WithPan(int k, uint8 a);
-void SpriteSfx_QueueSfx3WithPan(int k, uint8 a);
-uint8 Sprite_CalculateSfxPan(int k);
-uint8 CalculateSfxPan(uint16 x);
-uint8 CalculateSfxPan_Arbitrary(uint8 a);
-void Init_LoadDefaultTileAttr();
-void Main_ShowTextMessage();
-uint8 HandleItemTileAction_Overworld(uint16 x, uint16 y);
--- a/nmi.c
+++ /dev/null
@@ -1,461 +1,0 @@
-#include "nmi.h"
-#include "zelda_rtl.h"
-#include "variables.h"
-#include "messaging.h"
-#include "snes/snes_regs.h"
-#include "snes/ppu.h"
-#include "assets.h"
-#include "audio.h"
-
-static const uint8 kNmiVramAddrs[] = {
-  0, 0, 4, 8, 12, 8, 12, 0, 4, 0, 8, 4, 12, 4, 12, 0,
-  8, 16, 20, 24, 28, 24, 28, 16, 20, 16, 24, 20, 28, 20, 28, 16,
-  24, 96, 104,
-};
-static PlayerHandlerFunc *const kNmiSubroutines[25] = {
-  &NMI_UploadTilemap_doNothing,
-  &NMI_UploadTilemap,
-  &NMI_UploadBG3Text,
-  &NMI_UpdateOWScroll,
-  &NMI_UpdateSubscreenOverlay,
-  &NMI_UpdateBG1Wall,
-  &NMI_TileMapNothing,
-  &NMI_UpdateLoadLightWorldMap,
-  &NMI_UpdateBG2Left,
-  &NMI_UpdateBGChar3and4,
-  &NMI_UpdateBGChar5and6,
-  &NMI_UpdateBGCharHalf,
-  &NMI_UploadSubscreenOverlayLatter,
-  &NMI_UploadSubscreenOverlayFormer,
-  &NMI_UpdateBGChar0,
-  &NMI_UpdateBGChar1,
-  &NMI_UpdateBGChar2,
-  &NMI_UpdateBGChar3,
-  &NMI_UpdateObjChar0,
-  &NMI_UpdateObjChar2,
-  &NMI_UpdateObjChar3,
-  &NMI_UploadDarkWorldMap,
-  &NMI_UploadGameOverText,
-  &NMI_UpdatePegTiles,
-  &NMI_UpdateStarTiles,
-};
-void NMI_UploadSubscreenOverlayFormer() {
-  NMI_HandleArbitraryTileMap(&g_ram[0x12000], 0, 0x40);
-}
-
-void NMI_UploadSubscreenOverlayLatter() {
-  NMI_HandleArbitraryTileMap(&g_ram[0x13000], 0x40, 0x80);
-}
-
-static void CopyToVram(uint32 dstv, const uint8 *src, int len) {
-  memcpy(&g_zenv.vram[dstv], src, len);
-}
-
-static void CopyToVramVertical(uint32 dstv, const uint8 *src, int len) {
-  assert(!(len & 1));
-  uint16 *dst = &g_zenv.vram[dstv];
-  for (int i = 0, i_end = len >> 1; i < i_end; i++, dst += 32, src += 2)
-    *dst = WORD(*src);
-}
-
-static void CopyToVramLow(const uint8 *src, uint32 addr, int num) {
-  uint16 *dst = &g_zenv.vram[addr];
-  for (int i = 0; i < num; i++)
-    dst[i] = (dst[i] & ~0xff) | src[i];
-}
-
-void WritePpuRegisters() {
-  zelda_ppu_write(W12SEL, W12SEL_copy);
-  zelda_ppu_write(W34SEL, W34SEL_copy);
-  zelda_ppu_write(WOBJSEL, WOBJSEL_copy);
-  zelda_ppu_write(CGWSEL, CGWSEL_copy);
-  zelda_ppu_write(CGADSUB, CGADSUB_copy);
-  zelda_ppu_write(COLDATA, COLDATA_copy0);
-  zelda_ppu_write(COLDATA, COLDATA_copy1);
-  zelda_ppu_write(COLDATA, COLDATA_copy2);
-  zelda_ppu_write(TM, TM_copy);
-  zelda_ppu_write(TS, TS_copy);
-  zelda_ppu_write(TMW, TMW_copy);
-  zelda_ppu_write(TSW, TSW_copy);
-  zelda_ppu_write(BG1HOFS, BG1HOFS_copy);
-  zelda_ppu_write(BG1HOFS, BG1HOFS_copy >> 8);
-  zelda_ppu_write(BG1VOFS, BG1VOFS_copy);
-  zelda_ppu_write(BG1VOFS, BG1VOFS_copy >> 8);
-  zelda_ppu_write(BG2HOFS, BG2HOFS_copy);
-  zelda_ppu_write(BG2HOFS, BG2HOFS_copy >> 8);
-  zelda_ppu_write(BG2VOFS, BG2VOFS_copy);
-  zelda_ppu_write(BG2VOFS, BG2VOFS_copy >> 8);
-  zelda_ppu_write(BG3HOFS, BG3HOFS_copy2);
-  zelda_ppu_write(BG3HOFS, BG3HOFS_copy2 >> 8);
-  zelda_ppu_write(BG3VOFS, BG3VOFS_copy2);
-  zelda_ppu_write(BG3VOFS, BG3VOFS_copy2 >> 8);
-  zelda_ppu_write(INIDISP, INIDISP_copy);
-  zelda_ppu_write(MOSAIC, MOSAIC_copy);
-  zelda_ppu_write(BGMODE, BGMODE_copy);
-  if ((BGMODE_copy & 7) == 7) {
-    zelda_ppu_write(M7B, 0);
-    zelda_ppu_write(M7B, 0);
-    zelda_ppu_write(M7C, 0);
-    zelda_ppu_write(M7C, 0);
-    zelda_ppu_write(M7X, M7X_copy);
-    zelda_ppu_write(M7X, M7X_copy >> 8);
-    zelda_ppu_write(M7Y, M7Y_copy);
-    zelda_ppu_write(M7Y, M7Y_copy >> 8);
-  }
-  zelda_ppu_write(BG12NBA, 0x22);
-  zelda_ppu_write(BG34NBA, 7);
-}
-
-static void Interrupt_NMI_AudioParts_Locked() {
-  if (music_control == 0) {
-//    if (zelda_apu_read(APUI00) == last_music_control)
-//      zelda_apu_write(APUI00, 0);
-    // Zelda causes unwanted music change when going in a portal. last_music_control doesn't hold the 
-    // song but the last applied effect
-  } else if (!ZeldaIsPlayingMusicTrackWithBug(music_control)) {
-    last_music_control = music_control;
-    ZeldaPlayMsuAudioTrack(music_control);
-    if (music_control < 0xf2)
-      music_unk1 = music_control;
-    music_control = 0;
-  }
-
-  if (sound_effect_ambient == 0) {
-    if (zelda_apu_read(APUI01) == sound_effect_ambient_last)
-      zelda_apu_write(APUI01, 0);
-  } else {
-    sound_effect_ambient_last = sound_effect_ambient;
-    zelda_apu_write(APUI01, sound_effect_ambient);
-    sound_effect_ambient = 0;
-  }
-  zelda_apu_write(APUI02, sound_effect_1);
-  zelda_apu_write(APUI03, sound_effect_2);
-  sound_effect_1 = 0;
-  sound_effect_2 = 0;
-
-}
-
-void Interrupt_NMI(uint16 joypad_input) {  // 8080c9
-
-  Interrupt_NMI_AudioParts_Locked();
-
-  if (!nmi_boolean) {
-    nmi_boolean = true;
-    NMI_DoUpdates();
-    NMI_ReadJoypads(joypad_input);
-  }
-
-  if (is_nmi_thread_active) {
-    NMI_UpdateIRQGFX();
-    thread_other_stack = (thread_other_stack != 0x1f31) ? 0x1f31 : 0x1f2;
-  }
-  WritePpuRegisters();
-}
-
-void NMI_ReadJoypads(uint16 joypad_input) {  // 8083d1
-  uint16 both = joypad_input;
-  uint16 reversed = 0;
-  for (int i = 0; i < 16; i++, both >>= 1)
-    reversed = reversed * 2 + (both & 1);
-  uint8 r0 = reversed;
-  uint8 r1 = reversed >> 8;
-
-  joypad1L_last = r0;
-  filtered_joypad_L = (r0 ^ joypad1L_last2) & r0;
-  joypad1L_last2 = r0;
-
-  joypad1H_last = r1;
-  filtered_joypad_H = (r1 ^ joypad1H_last2) & r1;
-  joypad1H_last2 = r1;
-}
-
-void NMI_DoUpdates() {  // 8089e0
-  if (!nmi_disable_core_updates) {
-    memcpy(&g_zenv.vram[0x4100], &kLinkGraphics[dma_source_addr_0 - 0x8000], 0x40);
-    memcpy(&g_zenv.vram[0x4120], &kLinkGraphics[dma_source_addr_1 - 0x8000], 0x40);
-    memcpy(&g_zenv.vram[0x4140], &kLinkGraphics[dma_source_addr_2 - 0x8000], 0x20);
-
-    memcpy(&g_zenv.vram[0x4000], &kLinkGraphics[dma_source_addr_3 - 0x8000], 0x40);
-    memcpy(&g_zenv.vram[0x4020], &kLinkGraphics[dma_source_addr_4 - 0x8000], 0x40);
-    memcpy(&g_zenv.vram[0x4040], &kLinkGraphics[dma_source_addr_5 - 0x8000], 0x20);
-
-    memcpy(&g_zenv.vram[0x4050], &g_ram[dma_source_addr_6], 0x40);
-    memcpy(&g_zenv.vram[0x4070], &g_ram[dma_source_addr_7], 0x40);
-    memcpy(&g_zenv.vram[0x4090], &g_ram[dma_source_addr_8], 0x40);
-    memcpy(&g_zenv.vram[0x40b0], &g_ram[dma_source_addr_9], 0x20);
-    memcpy(&g_zenv.vram[0x40c0], &g_ram[dma_source_addr_10], 0x40);
-    memcpy(&g_zenv.vram[0x4150], &g_ram[dma_source_addr_11], 0x40);
-    memcpy(&g_zenv.vram[0x4170], &g_ram[dma_source_addr_12], 0x40);
-    memcpy(&g_zenv.vram[0x4190], &g_ram[dma_source_addr_13], 0x40);
-    memcpy(&g_zenv.vram[0x41b0], &g_ram[dma_source_addr_14], 0x20);
-    memcpy(&g_zenv.vram[0x41c0], &g_ram[dma_source_addr_15], 0x40);
-    memcpy(&g_zenv.vram[0x4200], &g_ram[dma_source_addr_16], 0x40);
-    memcpy(&g_zenv.vram[0x4220], &g_ram[dma_source_addr_17], 0x40);
-    memcpy(&g_zenv.vram[0x4240], &g_ram[0xbd40], 0x40);
-    memcpy(&g_zenv.vram[0x4300], &g_ram[dma_source_addr_18], 0x40);
-    memcpy(&g_zenv.vram[0x4320], &g_ram[dma_source_addr_19], 0x40);
-    memcpy(&g_zenv.vram[0x4340], &g_ram[0xbd80], 0x40);
-
-    if (BYTE(flag_travel_bird)) {
-      memcpy(&g_zenv.vram[0x40e0], &g_ram[dma_source_addr_20], 0x40);
-      memcpy(&g_zenv.vram[0x41e0], &g_ram[dma_source_addr_21], 0x40);
-    }
-
-    memcpy(&g_zenv.vram[animated_tile_vram_addr], &g_ram[animated_tile_data_src], 0x400);
-  }
-
-  if (flag_update_hud_in_nmi) {
-    memcpy(&g_zenv.vram[word_7E0219], hud_tile_indices_buffer, 165 * sizeof(uint16));
-  }
-
-  if (flag_update_cgram_in_nmi) {
-    memcpy(g_zenv.ppu->cgram, main_palette_buffer, 0x200);
-  }
-
-  flag_update_hud_in_nmi = 0;
-  flag_update_cgram_in_nmi = 0;
-
-  memcpy(g_zenv.ppu->oam, &g_ram[0x800], 0x220);
-
-  if (nmi_load_bg_from_vram) {
-    const uint8 *p;
-    switch (nmi_load_bg_from_vram) {
-    case 1: p = g_ram + 0x1002; break;
-    case 2: p = g_ram + 0x1000; break;
-    case 3: p = kBgTilemap_0; break;
-    case 4: p = g_ram + 0x21b; break;
-    case 5: p = kBgTilemap_1; break;
-    case 6: p = kBgTilemap_2; break;
-    case 7: p = kBgTilemap_3; break;
-    case 8: p = kBgTilemap_4; break;
-    case 9: p = kBgTilemap_5; break;
-    default: assert(0);
-    }
-    HandleStripes14(p);
-    if (nmi_load_bg_from_vram == 1)
-      vram_upload_offset = 0;
-    nmi_load_bg_from_vram = 0;
-  }
-
-  if (nmi_update_tilemap_dst) {
-    memcpy(&g_zenv.vram[nmi_update_tilemap_dst * 256], &g_ram[0x10000 + nmi_update_tilemap_src], 0x200);
-    nmi_update_tilemap_dst = 0;
-  }
-
-  if (nmi_copy_packets_flag) {
-    uint8 *p = (uint8 *)uvram.data;
-    do {
-      int dst = WORD(p[0]);
-      int vmain = p[2];
-      int len = p[3];
-      p += 4;
-      if (vmain == 0x80) {
-        // plain copy
-        memcpy(&g_zenv.vram[dst], p, len);
-      } else if (vmain == 0x81) {
-        // copy with other increment
-        assert((len & 1) == 0);
-        uint16 *dp = &g_zenv.vram[dst];
-        for (int i = 0; i < len; i += 2, dp += 32)
-          *dp = WORD(p[i]);
-      } else {
-        assert(0);
-      }
-      p += len;
-    } while (WORD(p[0]) != 0xffff);
-    nmi_copy_packets_flag = 0;
-    nmi_disable_core_updates = 0;
-  }
-
-  int idx = nmi_subroutine_index;
-  nmi_subroutine_index = 0;
-  kNmiSubroutines[idx]();
-}
-
-void NMI_UploadTilemap() {  // 808cb0
-  memcpy(&g_zenv.vram[kNmiVramAddrs[BYTE(nmi_load_target_addr)] << 8], &g_ram[0x1000], 0x800);
-
-  *(uint16 *)&g_ram[0x1000] = 0;
-  nmi_disable_core_updates = 0;
-}
-
-void NMI_UploadTilemap_doNothing() {  // 808ce3
-}
-
-void NMI_UploadBG3Text() {  // 808ce4
-  memcpy(&g_zenv.vram[0x7c00], &g_ram[0x10000], 0x7e0);
-  nmi_disable_core_updates = 0;
-}
-
-void NMI_UpdateOWScroll() {  // 808d13
-  uint8 *src = (uint8 *)uvram.data;
-  int f = WORD(src[0]);
-  int step = (f & 0x8000) ? 32 : 1;
-  int len = f & 0x3fff;
-  src += 2;
-  do {
-    uint16 *dst = &g_zenv.vram[WORD(src[0])];
-    src += 2;
-    for (int i = 0, i_end = len >> 1; i < i_end; i++, dst += step, src += 2)
-      *dst = WORD(*src);
-  } while (!(src[1] & 0x80));
-  nmi_disable_core_updates = 0;
-}
-
-void NMI_UpdateSubscreenOverlay() {  // 808d62
-  NMI_HandleArbitraryTileMap(&g_ram[0x12000], 0, 0x80);
-}
-
-void NMI_HandleArbitraryTileMap(const uint8 *src, int i, int i_end) {  // 808dae
-  uint16 *r10 = &word_7F4000;
-  do {
-    memcpy(&g_zenv.vram[r10[i >> 1]], src, 0x80);
-    src += 0x80;
-  } while ((i += 2) != i_end);
-  nmi_disable_core_updates = 0;
-}
-
-void NMI_UpdateBG1Wall() {  // 808e09
-  // Secret Wall Right
-  CopyToVramVertical(nmi_load_target_addr, &g_ram[0xc880], 0x40);
-  CopyToVramVertical(nmi_load_target_addr + 0x800, &g_ram[0xc8c0], 0x40);
-}
-
-void NMI_TileMapNothing() {  // 808e4b
-}
-
-void NMI_UpdateLoadLightWorldMap() {  // 808e54
-  static const uint16 kLightWorldTileMapDsts[4] = { 0, 0x20, 0x1000, 0x1020 };
-  const uint8 *src = GetLightOverworldTilemap();
-  for (int j = 0; j != 4; j++) {
-    int t = kLightWorldTileMapDsts[j];
-    for (int i = 0x20; i; i--) {
-      CopyToVramLow(src, t, 0x20);
-      src += 32;
-      t += 0x80;
-    }
-  }
-}
-
-void NMI_UpdateBG2Left() {  // 808ea9
-  CopyToVram(0, &g_ram[0x10000], 0x800);
-  CopyToVram(0x800, &g_ram[0x10800], 0x800);
-}
-
-void NMI_UpdateBGChar3and4() {  // 808ee7
-  memcpy(&g_zenv.vram[0x2c00], &g_ram[0x10000], 0x1000);
-  nmi_disable_core_updates = 0;
-}
-
-void NMI_UpdateBGChar5and6() {  // 808f16
-  memcpy(&g_zenv.vram[0x3400], &g_ram[0x11000], 0x1000);
-  nmi_disable_core_updates = 0;
-}
-
-void NMI_UpdateBGCharHalf() {  // 808f45
-  memcpy(&g_zenv.vram[BYTE(nmi_load_target_addr) * 256], &g_ram[0x11000], 0x400);
-}
-
-void NMI_UpdateBGChar0() {  // 808f72
-  NMI_RunTileMapUpdateDMA(0x2000);
-}
-
-void NMI_UpdateBGChar1() {  // 808f79
-  NMI_RunTileMapUpdateDMA(0x2800);
-}
-
-void NMI_UpdateBGChar2() {  // 808f80
-  NMI_RunTileMapUpdateDMA(0x3000);
-}
-
-void NMI_UpdateBGChar3() {  // 808f87
-  NMI_RunTileMapUpdateDMA(0x3800);
-}
-
-void NMI_UpdateObjChar0() {  // 808f8e
-  CopyToVram(0x4400, &g_ram[0x10000], 0x800);
-  nmi_disable_core_updates = 0;
-}
-
-void NMI_UpdateObjChar2() {  // 808fbd
-  NMI_RunTileMapUpdateDMA(0x5000);
-}
-
-void NMI_UpdateObjChar3() {  // 808fc4
-  NMI_RunTileMapUpdateDMA(0x5800);
-}
-
-void NMI_RunTileMapUpdateDMA(int dst) {  // 808fc9
-  CopyToVram(dst, &g_ram[0x10000], 0x1000);
-  nmi_disable_core_updates = 0;
-}
-
-void NMI_UploadDarkWorldMap() {  // 808ff3
-  const uint8 *src = g_ram + 0x1000;
-  int t = 0x810;
-  for (int i = 0x20; i; i--) {
-    CopyToVramLow(src, t, 0x20);
-    src += 32;
-    t += 0x80;
-  }
-}
-
-void NMI_UploadGameOverText() {  // 809038
-  CopyToVram(0x7800, &g_ram[0x2000], 0x800);
-  CopyToVram(0x7d00, &g_ram[0x3400], 0x600);
-}
-
-void NMI_UpdatePegTiles() {  // 80908b
-  CopyToVram(0x3d00, &g_ram[0x10000], 0x100);
-}
-
-void NMI_UpdateStarTiles() {  // 8090b7
-  CopyToVram(0x3ed0, &g_ram[0x10000], 0x40);
-}
-
-void HandleStripes14(const uint8 *p) {  // 8092a1
-  while (!(p[0] & 0x80)) {
-    uint16 vmem_addr = swap16(WORD(p[0]));
-    uint8 vram_incr_amount = (p[2] & 0x80) >> 7;
-    uint8 is_memset = p[2] & 0x40;  // Cpu BUS Address Step  (0=Increment, 2=Decrement, 1/3=Fixed) (DMA only)
-    int len = (swap16(WORD(p[2])) & 0x3fff) + 1;
-    p += 4;
-
-    if (vram_incr_amount == 0) {
-      uint16 *dst = &g_zenv.vram[vmem_addr];
-      if (is_memset) {
-        uint16 v = p[0] | p[1] << 8;
-        len = (len + 1) >> 1;
-        for (int i = 0; i < len; i++)
-          dst[i] = v;
-        p += 2;
-      } else {
-        memcpy(dst, p, len);
-        p += len;
-      }
-    } else {
-      // increment vram by 32 instead of 1
-      uint16 *dst = &g_zenv.vram[vmem_addr];
-      if (is_memset) {
-        uint16 v = p[0] | p[1] << 8;
-        len = (len + 1) >> 1;
-        for (int i = 0; i < len; i++, dst += 32)
-          *dst = v;
-        p += 2;
-      } else {
-        assert((len & 1) == 0);
-        len >>= 1;
-        for (int i = 0; i < len; i++, dst += 32, p += 2)
-          WORD(*dst) = WORD(*p);
-      }
-    }
-  }
-}
-
-void NMI_UpdateIRQGFX() {  // 809347
-  if (nmi_flag_update_polyhedral) {
-    memcpy(&g_zenv.vram[0x5800], &g_ram[0xe800], 0x800);
-    nmi_flag_update_polyhedral = 0;
-  }
-}
-
--- a/nmi.h
+++ /dev/null
@@ -1,35 +1,0 @@
-#pragma once
-#include "types.h"
-
-void NMI_UploadSubscreenOverlayFormer();
-void NMI_UploadSubscreenOverlayLatter();
-void Interrupt_NMI(uint16 joypad_input);
-void NMI_ReadJoypads(uint16 joypad_input);
-void NMI_DoUpdates();
-void NMI_UploadTilemap();
-void NMI_UploadTilemap_doNothing();
-void NMI_UploadBG3Text();
-void NMI_UpdateOWScroll();
-void NMI_UpdateSubscreenOverlay();
-void NMI_HandleArbitraryTileMap(const uint8 *src, int i, int i_end);
-void NMI_UpdateBG1Wall();
-void NMI_TileMapNothing();
-void NMI_UpdateLoadLightWorldMap();
-void NMI_UpdateBG2Left();
-void NMI_UpdateBGChar3and4();
-void NMI_UpdateBGChar5and6();
-void NMI_UpdateBGCharHalf();
-void NMI_UpdateBGChar0();
-void NMI_UpdateBGChar1();
-void NMI_UpdateBGChar2();
-void NMI_UpdateBGChar3();
-void NMI_UpdateObjChar0();
-void NMI_UpdateObjChar2();
-void NMI_UpdateObjChar3();
-void NMI_RunTileMapUpdateDMA(int dst);
-void NMI_UploadDarkWorldMap();
-void NMI_UploadGameOverText();
-void NMI_UpdatePegTiles();
-void NMI_UpdateStarTiles();
-void HandleStripes14(const uint8 *p);
-void NMI_UpdateIRQGFX();
--- a/opengl.c
+++ /dev/null
@@ -1,266 +1,0 @@
-#include "third_party/gl_core/gl_core_3_1.h"
-#include <SDL.h>
-#include <stdio.h>
-#include <stdbool.h>
-#include "types.h"
-#include "util.h"
-#include "glsl_shader.h"
-#include "config.h"
-
-#define CODE(...) #__VA_ARGS__
-
-static SDL_Window *g_window;
-static uint8 *g_screen_buffer;
-static size_t g_screen_buffer_size;
-static int g_draw_width, g_draw_height;
-static unsigned int g_program, g_VAO;
-static GlTextureWithSize g_texture;
-static GlslShader *g_glsl_shader;
-static bool g_opengl_es;
-
-static void GL_APIENTRY MessageCallback(GLenum source,
-                GLenum type,
-                GLuint id,
-                GLenum severity,
-                GLsizei length,
-                const GLchar *message,
-                const void *userParam) {
-  if (type == GL_DEBUG_TYPE_OTHER)
-    return;
-
-  fprintf(stderr, "GL CALLBACK: %s type = 0x%x, severity = 0x%x, message = %s\n",
-          (type == GL_DEBUG_TYPE_ERROR ? "** GL ERROR **" : ""),
-          type, severity, message);
-  if (type == GL_DEBUG_TYPE_ERROR)
-    Die("OpenGL error!\n");
-}
-
-static bool OpenGLRenderer_Init(SDL_Window *window) {
-  g_window = window;
-  SDL_GLContext context = SDL_GL_CreateContext(window);
-  (void)context;
-
-  SDL_GL_SetSwapInterval(1);
-  ogl_LoadFunctions();
-
-  if (!g_opengl_es) {
-    if (!ogl_IsVersionGEQ(3, 3))
-      Die("You need OpenGL 3.3");
-  } else {
-    int majorVersion = 0, minorVersion = 0;
-    SDL_GL_GetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, &majorVersion);
-    SDL_GL_GetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, &minorVersion);
-    if (majorVersion < 3)
-      Die("You need OpenGL ES 3.0");
-
-  }
-
-  if (kDebugFlag) {
-    glEnable(GL_DEBUG_OUTPUT);
-    glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
-    glDebugMessageCallback(MessageCallback, 0);
-  }
-
-  glGenTextures(1, &g_texture.gl_texture);
-
-  static const float kVertices[] = {
-    // positions          // texture coords
-    -1.0f,  1.0f, 0.0f,   0.0f, 0.0f, // top left
-    -1.0f, -1.0f, 0.0f,   0.0f, 1.0f, // bottom left
-     1.0f,  1.0f, 0.0f,   1.0f, 0.0f, // top right
-     1.0f, -1.0f, 0.0f,   1.0f, 1.0f,  // bottom right
-  };
-
-  // create a vertex buffer object
-  unsigned int vbo;
-  glGenBuffers(1, &vbo);
-
-  // vertex array object
-  glGenVertexArrays(1, &g_VAO);
-  // 1. bind Vertex Array Object
-  glBindVertexArray(g_VAO);
-  // 2. copy our vertices array in a buffer for OpenGL to use
-  glBindBuffer(GL_ARRAY_BUFFER, vbo);
-  glBufferData(GL_ARRAY_BUFFER, sizeof(kVertices), kVertices, GL_STATIC_DRAW);
-  // position attribute
-  glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void *)0);
-  glEnableVertexAttribArray(0);
-  // texture coord attribute
-  glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void *)(3 * sizeof(float)));
-  glEnableVertexAttribArray(1);
-
-  // vertex shader
-  const GLchar *vs_code_core = "#version 330 core\n" CODE(
-  layout(location = 0) in vec3 aPos;
-  layout(location = 1) in vec2 aTexCoord;
-  out vec2 TexCoord;
-  void main() {
-    gl_Position = vec4(aPos, 1.0);
-    TexCoord = vec2(aTexCoord.x, aTexCoord.y);
-  }
-);
-
-  const GLchar *vs_code_es = "#version 300 es\n" CODE(
-  layout(location = 0) in vec3 aPos;
-  layout(location = 1) in vec2 aTexCoord;
-  out vec2 TexCoord;
-  void main() {
-    gl_Position = vec4(aPos, 1.0);
-    TexCoord = vec2(aTexCoord.x, aTexCoord.y);
-  }
-);
-
-  const GLchar *vs_code = g_opengl_es ? vs_code_es : vs_code_core;
-  unsigned int vs = glCreateShader(GL_VERTEX_SHADER);
-  glShaderSource(vs, 1, &vs_code, NULL);
-  glCompileShader(vs);
-
-  int success;
-  char infolog[512];
-  glGetShaderiv(vs, GL_COMPILE_STATUS, &success);
-  if (!success) {
-    glGetShaderInfoLog(vs, 512, NULL, infolog);
-    printf("%s\n", infolog);
-  }
-
-  // fragment shader
-  const GLchar *fs_code_core = "#version 330 core\n" CODE(
-  out vec4 FragColor;
-  in vec2 TexCoord;
-  // texture samplers
-  uniform sampler2D texture1;
-  void main() {
-    FragColor = texture(texture1, TexCoord);
-  }
-);
-
-  const GLchar *fs_code_es = "#version 300 es\n" CODE(
-  precision mediump float;
-  out vec4 FragColor;
-  in vec2 TexCoord;
-  // texture samplers
-  uniform sampler2D texture1;
-  void main() {
-    FragColor = texture(texture1, TexCoord);
-  }
-);
-
-
-  const GLchar *fs_code = g_opengl_es ? fs_code_es : fs_code_core;
-  unsigned int fs = glCreateShader(GL_FRAGMENT_SHADER);
-  glShaderSource(fs, 1, &fs_code, NULL);
-  glCompileShader(fs);
-
-  glGetShaderiv(fs, GL_COMPILE_STATUS, &success);
-  if (!success) {
-    glGetShaderInfoLog(fs, 512, NULL, infolog);
-    printf("%s\n", infolog);
-  }
-
-  // create program
-  int program = g_program = glCreateProgram();
-  glAttachShader(program, vs);
-  glAttachShader(program, fs);
-  glLinkProgram(program);
-  glGetProgramiv(program, GL_LINK_STATUS, &success);
-
-  if (!success) {
-    glGetProgramInfoLog(program, 512, NULL, infolog);
-    printf("%s\n", infolog);
-  }
-
-  if (g_config.shader)
-    g_glsl_shader = GlslShader_CreateFromFile(g_config.shader, g_opengl_es);
-  
-  return true;
-}
-
-static void OpenGLRenderer_Destroy() {
-}
-
-static void OpenGLRenderer_BeginDraw(int width, int height, uint8 **pixels, int *pitch) {
-  int size = width * height;
-
-  if (size > g_screen_buffer_size) {
-    g_screen_buffer_size = size;
-    free(g_screen_buffer);
-    g_screen_buffer = malloc(size * 4);
-  }
-
-  g_draw_width = width;
-  g_draw_height = height;
-  *pixels = g_screen_buffer;
-  *pitch = width * 4;
-}
-
-static void OpenGLRenderer_EndDraw() {
-  int drawable_width, drawable_height;
-
-  SDL_GL_GetDrawableSize(g_window, &drawable_width, &drawable_height);
-  
-  int viewport_width = drawable_width, viewport_height = drawable_height;
-
-  if (!g_config.ignore_aspect_ratio) {
-    if (viewport_width * g_draw_height < viewport_height * g_draw_width)
-      viewport_height = viewport_width * g_draw_height / g_draw_width;  // limit height
-    else
-      viewport_width = viewport_height * g_draw_width / g_draw_height;  // limit width
-  }
-
-  int viewport_x = (drawable_width - viewport_width) >> 1;
-  int viewport_y = (viewport_height - viewport_height) >> 1;
-
-  glBindTexture(GL_TEXTURE_2D, g_texture.gl_texture);
-  if (g_draw_width == g_texture.width && g_draw_height == g_texture.height) {
-    if (!g_opengl_es)
-      glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, g_draw_width, g_draw_height, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, g_screen_buffer);
-    else
-      glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, g_draw_width, g_draw_height, GL_BGRA, GL_UNSIGNED_BYTE, g_screen_buffer);
-  } else {
-    g_texture.width = g_draw_width;
-    g_texture.height = g_draw_height;
-    if (!g_opengl_es)
-      glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, g_draw_width, g_draw_height, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, g_screen_buffer);
-    else
-      glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, g_draw_width, g_draw_height, 0, GL_BGRA, GL_UNSIGNED_BYTE, g_screen_buffer);
-  }
-
-  glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
-  glClear(GL_COLOR_BUFFER_BIT);
-
-  if (g_glsl_shader == NULL) {
-    glViewport(viewport_x, viewport_y, viewport_width, viewport_height);
-    glUseProgram(g_program);
-    int filter = g_config.linear_filtering ? GL_LINEAR : GL_NEAREST;
-    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter);
-    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter);
-    glBindVertexArray(g_VAO);
-    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
-  } else {
-    GlslShader_Render(g_glsl_shader, &g_texture, viewport_x, viewport_y, viewport_width, viewport_height);
-  }
-
-  SDL_GL_SwapWindow(g_window);
-}
-
-static const struct RendererFuncs kOpenGLRendererFuncs = {
-  &OpenGLRenderer_Init,
-  &OpenGLRenderer_Destroy,
-  &OpenGLRenderer_BeginDraw,
-  &OpenGLRenderer_EndDraw,
-};
-
-void OpenGLRenderer_Create(struct RendererFuncs *funcs, bool use_opengl_es) {
-  g_opengl_es = use_opengl_es;
-  if (!g_opengl_es) {
-    SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
-    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
-    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
-  } else {
-    SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
-    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
-    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
-  }
-  *funcs = kOpenGLRendererFuncs;
-}
-
--- a/overlord.c
+++ /dev/null
@@ -1,653 +1,0 @@
-#include "overlord.h"
-#include "sprite.h"
-#include "misc.h"
-#include "sprite_main.h"
-
-uint16 Overlord_GetX(int k) { return (overlord_x_lo[k] | overlord_x_hi[k] << 8); }
-uint16 Overlord_GetY(int k) { return (overlord_y_lo[k] | overlord_y_hi[k] << 8); }
-static HandlerFuncK *const kOverlordFuncs[26] = {
-  &Overlord01_PositionTarget,
-  &Overlord02_FullRoomCannons,
-  &Overlord03_VerticalCannon,
-  &Overlord_StalfosFactory,
-  &Overlord05_FallingStalfos,
-  &Overlord06_BadSwitchSnake,
-  &Overlord07_MovingFloor,
-  &Overlord08_BlobSpawner,
-  &Overlord09_WallmasterSpawner,
-  &Overlord0A_FallingSquare,
-  &Overlord0A_FallingSquare,
-  &Overlord0A_FallingSquare,
-  &Overlord0A_FallingSquare,
-  &Overlord0A_FallingSquare,
-  &Overlord0A_FallingSquare,
-  &Overlord10_PirogusuSpawner_left,
-  &Overlord10_PirogusuSpawner_left,
-  &Overlord10_PirogusuSpawner_left,
-  &Overlord10_PirogusuSpawner_left,
-  &Overlord14_TileRoom,
-  &Overlord15_WizzrobeSpawner,
-  &Overlord16_ZoroSpawner,
-  &Overlord17_PotTrap,
-  &Overlord18_InvisibleStalfos,
-  &Overlord19_ArmosCoordinator_bounce,
-  &Overlord06_BadSwitchSnake,
-};
-static inline uint8 ArmosMult(uint16 a, uint8 b);
-static inline int8 ArmosSin(uint16 a, uint8 b);
-void Overlord_StalfosFactory(int k) {
-  // unused
-  assert(0);
-}
-
-void Overlord_SetX(int k, uint16 v) {
-  overlord_x_lo[k] = v;
-  overlord_x_hi[k] = v >> 8;
-}
-
-void Overlord_SetY(int k, uint16 v) {
-  overlord_y_lo[k] = v;
-  overlord_y_hi[k] = v >> 8;
-}
-
-static inline uint8 ArmosMult(uint16 a, uint8 b) {
-  if (a >= 256)
-    return b;
-  int p = a * b;
-  return (p >> 8) + (p >> 7 & 1);
-}
-
-static inline int8 ArmosSin(uint16 a, uint8 b) {
-  uint8 t = ArmosMult(kSinusLookupTable[a & 0xff], b);
-  return (a & 0x100) ? -t : t;
-}
-
-void Overlord_SpawnBoulder() {  // 89b714
-  if (player_is_indoors || !byte_7E0FFD || (submodule_index | flag_unk1) || ++byte_7E0FFE & 63)
-    return;
-
-  if (sign8((BG2VOFS_copy2 >> 8) - (sprcoll_y_base >> 8) - 2))
-    return;
-
-  SpriteSpawnInfo info;
-  int j = Sprite_SpawnDynamically(0, 0xc2, &info);
-  if (j >= 0) {
-    Sprite_SetX(j, BG2HOFS_copy2 + (GetRandomNumber() & 127) + 64);
-    Sprite_SetY(j, BG2VOFS_copy2 - 0x30);
-    sprite_floor[j] = 0;
-    sprite_D[j] = 0;
-    sprite_z[j] = 0;
-  }
-}
-
-void Overlord_Main() {  // 89b773
-  Overlord_ExecuteAll();
-  Overlord_SpawnBoulder();
-}
-
-void Overlord_ExecuteAll() {  // 89b77e
-  if (submodule_index | flag_unk1)
-    return;
-  for (int i = 7; i >= 0; i--) {
-    if (overlord_type[i])
-      Overlord_ExecuteSingle(i);
-  }
-}
-
-void Overlord_ExecuteSingle(int k) {  // 89b793
-  int j = overlord_type[k];
-  Overlord_CheckIfActive(k);
-  kOverlordFuncs[j - 1](k);
-}
-
-void Overlord19_ArmosCoordinator_bounce(int k) {  // 89b7dc
-  static const uint8 kArmosCoordinator_BackWallX[6] = { 49, 77, 105, 131, 159, 187 };
-
-  if (overlord_gen2[k])
-    overlord_gen2[k]--;
-  switch (overlord_gen1[k]) {
-  case 0:  // wait for knight activation
-    if (sprite_A[0]) {
-      overlord_x_lo[k] = 120;
-      overlord_floor[k] = 255;
-      overlord_x_lo[2] = 64;
-      overlord_x_lo[0] = 192;
-      overlord_x_lo[1] = 1;
-      ArmosCoordinator_RotateKnights(k);
-    }
-    break;
-  case 1:  // wait knight under coercion
-    if (ArmosCoordinator_CheckKnights()) {
-      overlord_gen1[k]++;
-      overlord_gen2[k] = 0xff;
-    }
-    break;
-  case 2:  // timed rotate then transition
-  case 4:
-    ArmosCoordinator_RotateKnights(k);
-    break;
-  case 3:  // radial contraction
-    if (--overlord_x_lo[2] == 32) {
-      overlord_gen1[k]++;
-      overlord_gen2[k] = 64;
-    }
-    ArmosCoordinator_Rotate(k);
-    break;
-  case 5:  // radial dilation
-    if (++overlord_x_lo[2] == 64) {
-      overlord_gen1[k]++;
-      overlord_gen2[k] = 64;
-    }
-    ArmosCoordinator_Rotate(k);
-    break;
-  case 6:  // order knights to back wall
-    if (overlord_gen2[k])
-      return;
-    ArmosCoordinator_DisableCoercion(k);
-    for (int j = 5; j >= 0; j--) {
-      overlord_x_hi[j] = kArmosCoordinator_BackWallX[j];
-      overlord_gen2[j] = 48;
-    }
-    overlord_gen1[k]++;
-    overlord_gen2[k] = 255;
-    break;
-  case 7:  // cascade knights to front wall
-    if (overlord_gen2[k])
-      return;
-    for (int j = 5; j >= 0; j--) {
-      if (++overlord_gen2[j] == 192) {
-        overlord_gen1[k] = 1;
-        overlord_floor[k] = -overlord_floor[k];
-        ArmosCoordinator_DisableCoercion(k);
-        ArmosCoordinator_Rotate(k);
-        return;
-      }
-    }
-    break;
-  }
-}
-
-void Overlord18_InvisibleStalfos(int k) {  // 89b7f5
-  static const int8 kRedStalfosTrap_X[4] = { 0, 0, -48, 48 };
-  static const int8 kRedStalfosTrap_Y[4] = { -40, 56, 8, 8 };
-  static const uint8 kRedStalfosTrap_Delay[4] = { 0x30, 0x50, 0x70, 0x90 };
-
-  uint16 x = (overlord_x_lo[k] | overlord_x_hi[k] << 8);
-  uint16 y = (overlord_y_lo[k] | overlord_y_hi[k] << 8);
-  if ((uint16)(x - link_x_coord + 24) >= 48 || (uint16)(y - link_y_coord + 24) >= 48)
-    return;
-  overlord_type[k] = 0;
-  tmp_counter = 3;
-  do {
-    SpriteSpawnInfo info;
-    int j = Sprite_SpawnDynamicallyEx(k, 0xa7, &info, 12);
-    if (j < 0)
-      return;
-    Sprite_SetX(j, link_x_coord + kRedStalfosTrap_X[tmp_counter]);
-    Sprite_SetY(j, link_y_coord + kRedStalfosTrap_Y[tmp_counter]);
-    sprite_delay_main[j] = kRedStalfosTrap_Delay[tmp_counter];
-    sprite_floor[j] = overlord_floor[k];
-    sprite_E[j] = 1;
-    sprite_flags2[j] = 3;
-    sprite_D[j] = 2;
-  } while (!sign8(--tmp_counter));
-}
-
-void Overlord17_PotTrap(int k) {  // 89b884
-  uint16 x = (overlord_x_lo[k] | overlord_x_hi[k] << 8);
-  uint16 y = (overlord_y_lo[k] | overlord_y_hi[k] << 8);
-  if ((uint16)(x - link_x_coord + 32) < 64 &&
-      (uint16)(y - link_y_coord + 32) < 64) {
-    overlord_type[k] = 0;
-    byte_7E0B9E++;
-  }
-}
-
-void Overlord16_ZoroSpawner(int k) {  // 89b8d1
-  static const int8 kOverlordZoroFactory_X[8] = { -4, -2, 0, 2, 4, 6, 8, 12 };
-  overlord_gen2[k]--;
-  uint16 x = Overlord_GetX(k) + 8;
-  uint16 y = Overlord_GetY(k) + 8;
-  if (GetTileAttribute(overlord_floor[k], &x, y) != 0x82)
-    return;
-  if (overlord_gen2[k] >= 0x18 || (overlord_gen2[k] & 3) != 0)
-    return;
-  SpriteSpawnInfo info;
-  int j = Sprite_SpawnDynamicallyEx(k, 0x9c, &info, 12);
-  if (j >= 0) {
-    Sprite_SetX(j, info.r5_overlord_x + kOverlordZoroFactory_X[GetRandomNumber() & 7] + 8);
-    sprite_y_lo[j] = info.r7_overlord_y + 8;
-    sprite_y_hi[j] = info.r7_overlord_y >> 8;
-    sprite_floor[j] = overlord_floor[k];
-    sprite_flags4[j] = 1;
-    sprite_E[j] = 1;
-    sprite_ignore_projectile[j] = 1;
-    sprite_y_vel[j] = 16;
-    sprite_flags2[j] = 32;
-    sprite_oam_flags[j] = 13;
-    sprite_subtype2[j] = GetRandomNumber();
-    sprite_delay_main[j] = 48;
-    sprite_bump_damage[j] = 3;
-  }
-}
-
-void Overlord15_WizzrobeSpawner(int k) {  // 89b986
-  static const int8 kOverlordWizzrobe_X[4] = { 48, -48, 0, 0 };
-  static const int8 kOverlordWizzrobe_Y[4] = { 16, 16, 64, -32 };
-  static const uint8 kOverlordWizzrobe_Delay[4] = { 0, 16, 32, 48 };
-  if (overlord_gen2[k] != 128) {
-    if (frame_counter & 1)
-      overlord_gen2[k]--;
-    return;
-  }
-  overlord_gen2[k] = 127;
-  for (int i = 3; i >= 0; i--) {
-    SpriteSpawnInfo info;
-    int j = Sprite_SpawnDynamicallyEx(k, 0x9b, &info, 12);
-    if (j >= 0) {
-      Sprite_SetX(j, link_x_coord + kOverlordWizzrobe_X[i]);
-      Sprite_SetY(j, link_y_coord + kOverlordWizzrobe_Y[i]);
-      sprite_delay_main[j] = kOverlordWizzrobe_Delay[i];
-      sprite_floor[j] = overlord_floor[k];
-      sprite_B[j] = 1;
-    }
-  }
-  tmp_counter = 0xff;
-}
-
-void Overlord14_TileRoom(int k) {  // 89b9e8
-  uint16 x = (overlord_x_lo[k] | overlord_x_hi[k] << 8) - BG2HOFS_copy2;
-  uint16 y = (overlord_y_lo[k] | overlord_y_hi[k] << 8) - BG2VOFS_copy2;
-  if (x & 0xff00 || y & 0xff00)
-    return;
-  if (--overlord_gen2[k] != 0x80)
-    return;
-  int j = TileRoom_SpawnTile(k);
-  if (j < 0) {
-    overlord_gen2[k] = 0x81;
-    return;
-  }
-  if (++overlord_gen1[k] != 22)
-    overlord_gen2[k] = 0xE0;
-  else
-    overlord_type[k] = 0;
-}
-
-int TileRoom_SpawnTile(int k) {  // 89ba56
-  static const uint8 kSpawnFlyingTile_X[22] = {
-    0x70, 0x80, 0x60, 0x90, 0x90, 0x60, 0x70, 0x80, 0x80, 0x70, 0x50, 0xa0, 0xa0, 0x50, 0x50, 0xa0,
-    0xa0, 0x50, 0x70, 0x80, 0x80, 0x70,
-  };
-  static const uint8 kSpawnFlyingTile_Y[22] = {
-    0x80, 0x80, 0x70, 0x90, 0x70, 0x90, 0x60, 0xa0, 0x60, 0xa0, 0x60, 0xb0, 0x60, 0xb0, 0x80, 0x90,
-    0x80, 0x90, 0x70, 0x90, 0x70, 0x90,
-  };
-  SpriteSpawnInfo info;
-  int j = Sprite_SpawnDynamically(k, 0x94, &info);
-  if (j < 0)
-    return j;
-  sprite_E[j] = 1;
-  int i = overlord_gen1[k];
-  sprite_x_lo[j] = kSpawnFlyingTile_X[i];
-  sprite_y_lo[j] = kSpawnFlyingTile_Y[i] - 8;
-  sprite_y_hi[j] = overlord_y_hi[k];
-  sprite_x_hi[j] = overlord_x_hi[k];
-  sprite_floor[j] = overlord_floor[k];
-  sprite_health[j] = 4;
-  sprite_flags5[j] = 0;
-  sprite_health[j] = 0;
-  sprite_defl_bits[j] = 8;
-  sprite_flags2[j] = 4;
-  sprite_oam_flags[j] = 1;
-  sprite_bump_damage[j] = 4;
-  return j;
-}
-
-void Overlord10_PirogusuSpawner_left(int k) {  // 89baac
-  static const uint8 kOverlordPirogusu_A[4] = { 2, 3, 0, 1 };
-
-  tmp_counter = overlord_type[k] - 16;
-  if (overlord_gen2[k] != 128) {
-    overlord_gen2[k]--;
-    return;
-  }
-  overlord_gen2[k] = (GetRandomNumber() & 31) + 96;
-  int n = 0;
-  for (int i = 0; i != 16; i++) {
-    if (sprite_state[i] != 0 && sprite_type[i] == 0x10)
-      n++;
-  }
-  if (n >= 5)
-    return;
-  SpriteSpawnInfo info;
-  int j = Sprite_SpawnDynamicallyEx(k, 0x94, &info, 12);
-  if (j >= 0) {
-    Sprite_SetX(j, info.r5_overlord_x);
-    Sprite_SetY(j, info.r7_overlord_y);
-    sprite_floor[j] = overlord_floor[k];
-    sprite_delay_main[j] = 32;
-    sprite_D[j] = tmp_counter;
-    sprite_A[j] = kOverlordPirogusu_A[tmp_counter];
-  }
-}
-
-void Overlord0A_FallingSquare(int k) {  // 89bbb2
-  static const uint8 kCrumbleTilePathData[108 + 1] = {
-    2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 3, 3, 3,
-    3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 3, 1, 3, 0, 3, 1,
-    3, 0, 3, 1, 3, 0, 3, 1, 3, 0, 3, 1, 3, 0, 3, 1,
-    3, 0, 3, 1, 3, 0, 3, 1, 3, 0, 3, 1, 3, 0, 3, 1,
-    3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2,
-    2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-    1, 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0xff
-  };
-  static const uint8 kCrumbleTilePathOffs[7] = {
-    0, 25, 66, 77, 87, 98, 108
-  };
-  static const int8 kCrumbleTilePath_X[4] = { 16, -16, 0, 0 };
-  static const int8 kCrumbleTilePath_Y[4] = { 0, 0, 16, -16 };
-  if (overlord_gen2[k]) {
-    if (overlord_gen3[k]) {
-      overlord_gen2[k]--;
-      return;
-    }
-    uint16 x = Overlord_GetX(k) - BG2HOFS_copy2;
-    uint16 y = Overlord_GetY(k) - BG2VOFS_copy2;
-    if (!(x & 0xff00 || y & 0xff00))
-      overlord_gen3[k]++;
-    return;
-  }
-
-  overlord_gen2[k] = 16;
-  SpawnFallingTile(k);
-  int j = overlord_type[k] - 10;
-  int i = overlord_gen1[k]++;
-  if (i == kCrumbleTilePathOffs[j + 1] - kCrumbleTilePathOffs[j]) {
-    overlord_type[k] = 0;
-  }
-  int t = kCrumbleTilePathData[kCrumbleTilePathOffs[j] + i];
-  if (t == 0xff) {
-    Overlord_SetX(k, Overlord_GetX(k) + 0xc1a);
-    Overlord_SetY(k, Overlord_GetY(k) + 0xbb66);
-  } else {
-    Overlord_SetX(k, Overlord_GetX(k) + kCrumbleTilePath_X[t]);
-    Overlord_SetY(k, Overlord_GetY(k) + kCrumbleTilePath_Y[t]);
-  }
-}
-
-void SpawnFallingTile(int k) {  // 89bc31
-  int j = GarnishAlloc();
-  if (j >= 0) {
-    garnish_type[j] = 3;
-    garnish_x_hi[j] = overlord_x_hi[k];
-    garnish_x_lo[j] = overlord_x_lo[k];
-    sound_effect_1 = CalculateSfxPan_Arbitrary(garnish_x_lo[j]) | 0x1f;
-    int y = Overlord_GetY(k) + 16;
-    garnish_y_lo[j] = y;
-    garnish_y_hi[j] = y >> 8;
-    garnish_countdown[j] = 31;
-    garnish_active = 31;
-  }
-}
-
-void Overlord09_WallmasterSpawner(int k) {  // 89bc7b
-  if (overlord_gen2[k] != 128) {
-    if (!(frame_counter & 1))
-      overlord_gen2[k]--;
-    return;
-  }
-  overlord_gen2[k] = 127;
-  SpriteSpawnInfo info;
-  int j = Sprite_SpawnDynamicallyEx(k, 0x90, &info, 12);
-  if (j < 0)
-    return;
-  Sprite_SetX(j, link_x_coord);
-  Sprite_SetY(j, link_y_coord);
-  sprite_z[j] = 208;
-  SpriteSfx_QueueSfx2WithPan(j, 0x20);
-  sprite_floor[j] = link_is_on_lower_level;
-}
-
-void Overlord08_BlobSpawner(int k) {  // 89bcc3
-  if (overlord_gen2[k]) {
-    overlord_gen2[k]--;
-    return;
-  }
-  overlord_gen2[k] = 0xa0;
-  int n = 0;
-  for (int i = 0; i != 16; i++) {
-    if (sprite_state[i] != 0 && sprite_type[i] == 0x8f)
-      n++;
-  }
-  if (n >= 5)
-    return;
-
-  SpriteSpawnInfo info;
-  int j = Sprite_SpawnDynamicallyEx(k, 0x8f, &info, 12);
-  if (j >= 0) {
-    static const int8 kOverlordZol_X[4] = { 0, 0, -48, 48 };
-    static const int8 kOverlordZol_Y[4] = { -40, 56, 8, 8 };
-    int i = link_direction_facing >> 1;
-    Sprite_SetX(j, link_x_coord + kOverlordZol_X[i]);
-    Sprite_SetY(j, link_y_coord + kOverlordZol_Y[i]);
-    sprite_z[j] = 192;
-    sprite_floor[j] = link_is_on_lower_level;
-    sprite_ai_state[j] = 2;
-    sprite_E[j] = 2;
-    sprite_C[j] = 2;
-    sprite_head_dir[j] = GetRandomNumber() & 31 | 16;
-  }
-}
-
-void Overlord07_MovingFloor(int k) {  // 89bd3f
-  if (sprite_state[0] == 4) {
-    overlord_type[k] = 0;
-    BYTE(dung_floor_move_flags) = 1;
-    return;
-  }
-  if (!overlord_gen1[k]) {
-    if (++overlord_gen2[k] == 32) {
-      overlord_gen2[k] = 0;
-      BYTE(dung_floor_move_flags) = (GetRandomNumber() & (overlord_x_lo[k] ? 3 : 1)) * 2;
-      overlord_gen2[k] = (GetRandomNumber() & 127) + 128;
-      overlord_gen1[k]++;
-    } else {
-      BYTE(dung_floor_move_flags) = 1;
-    }
-  } else {
-    if (!--overlord_gen2[k])
-      overlord_gen1[k] = 0;
-  }
-}
-
-void Sprite_Overlord_PlayFallingSfx(int k) {  // 89bdfd
-  SpriteSfx_QueueSfx2WithPan(k, 0x20);
-}
-
-void Overlord05_FallingStalfos(int k) {  // 89be0f
-  static const uint8 kStalfosTrap_Trigger[8] = { 255, 224, 192, 160, 128, 96, 64, 32 };
-
-  uint16 x = (overlord_x_lo[k] | overlord_x_hi[k] << 8) - BG2HOFS_copy2;
-  uint16 y = (overlord_y_lo[k] | overlord_y_hi[k] << 8) - BG2VOFS_copy2;
-  if (x & 0xff00 || y & 0xff00)
-    return;
-  if (overlord_gen1[k] == 0) {
-    if (byte_7E0B9E)
-      overlord_gen1[k]++;
-    return;
-  }
-  if (overlord_gen1[k]++ == kStalfosTrap_Trigger[k]) {
-    overlord_type[k] = 0;
-    SpriteSpawnInfo info;
-    int j = Sprite_SpawnDynamicallyEx(k, 0x85, &info, 12);
-    if (j < 0)
-      return;
-    Sprite_SetX(j, info.r5_overlord_x);
-    Sprite_SetY(j, info.r7_overlord_y);
-    sprite_z[j] = 224;
-    sprite_floor[j] = overlord_floor[k];
-    sprite_D[j] = 0; // zelda bug: unitialized
-    Sprite_Overlord_PlayFallingSfx(j);
-  }
-}
-
-void Overlord06_BadSwitchSnake(int k) {  // 89be75
-  static const uint8 kSnakeTrapOverlord_Tab1[8] = { 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80, 0x90 };
-
-  uint8 a = overlord_gen1[k];
-  if (a == 0) {
-    if (activate_bomb_trap_overlord != 0)
-      overlord_gen1[k] = 1;
-    return;
-  }
-  overlord_gen1[k] = a + 1;
-
-  if (a != kSnakeTrapOverlord_Tab1[k])
-    return;
-
-  SpriteSpawnInfo info;
-  int j = Sprite_SpawnDynamically(k, 0x6e, &info);
-  if (j < 0)
-    return;
-  Sprite_SetX(j, info.r5_overlord_x);
-  Sprite_SetY(j, info.r7_overlord_y);
-
-  sprite_z[j] = 192;
-  sprite_E[j] = 192;
-
-  sprite_flags3[j] |= 0x10;
-  sprite_floor[j] = overlord_floor[k];
-  SpriteSfx_QueueSfx2WithPan(j, 0x20);
-  uint8 type = overlord_type[k];
-  overlord_type[k] = 0;
-  if (type == 26) {
-    sprite_type[j] = 74;
-    Sprite_TransmuteToBomb(j);
-    sprite_delay_aux1[j] = 112;
-  }
-}
-
-void Overlord02_FullRoomCannons(int k) {  // 89bf09
-  static const uint8 kAllDirectionMetalBallFactory_Idx[16] = { 2, 2, 2, 2, 1, 1, 1, 1, 3, 3, 3, 3, 0, 0, 0, 0 };
-  static const uint8 kAllDirectionMetalBallFactory_X[16] = { 64, 96, 144, 176, 240, 240, 240, 240, 176, 144, 96, 64, 0, 0, 0, 0 };
-  static const uint8 kAllDirectionMetalBallFactory_Y[16] = { 16, 16, 16, 16, 64, 96, 160, 192, 240, 240, 240, 240, 192, 160, 96, 64 };
-  uint16 x = (overlord_x_lo[k] | overlord_x_hi[k] << 8) - BG2HOFS_copy2;
-  uint16 y = (overlord_y_lo[k] | overlord_y_hi[k] << 8) - BG2VOFS_copy2;
-  if ((x | y) & 0xff00 || frame_counter & 0xf)
-    return;
-
-  byte_7E0FB6 = 0;
-  int j = GetRandomNumber() & 15;
-  tmp_counter = kAllDirectionMetalBallFactory_Idx[j];
-  overlord_x_lo[k] = kAllDirectionMetalBallFactory_X[j];
-  overlord_x_hi[k] = byte_7E0FB0;
-  overlord_y_lo[k] = kAllDirectionMetalBallFactory_Y[j];
-  overlord_y_hi[k] = byte_7E0FB1 + 1;
-  Overlord_SpawnCannonBall(k, 0);
-}
-
-void Overlord03_VerticalCannon(int k) {  // 89bf5b
-  uint16 x = (overlord_x_lo[k] | overlord_x_hi[k] << 8) - BG2HOFS_copy2;
-  if (x & 0xff00) {
-    overlord_gen2[k] = 255;
-    return;
-  }
-  if (!(frame_counter & 1) && overlord_gen2[k])
-    overlord_gen2[k]--;
-  tmp_counter = 2;
-  byte_7E0FB6 = 0;
-  if (!sign8(--overlord_gen1[k]))
-    return;
-  overlord_gen1[k] = 56;
-  int xd;
-  if (!overlord_gen2[k]) {
-    overlord_gen2[k] = 160;
-    byte_7E0FB6 = 160;
-    xd = 8;
-  } else {
-    xd = (GetRandomNumber() & 2) * 8;
-  }
-  Overlord_SpawnCannonBall(k, xd);
-}
-
-void Overlord_SpawnCannonBall(int k, int xd) {  // 89bfaf
-  static const int8 kOverlordSpawnBall_Xvel[4] = { 24, -24, 0, 0 };
-  static const int8 kOverlordSpawnBall_Yvel[4] = { 0, 0, 24, -24 };
-  SpriteSpawnInfo info;
-  int j = Sprite_SpawnDynamically(k, 0x50, &info);
-  if (j < 0)
-    return;
-
-  Sprite_SetX(j, info.r5_overlord_x + xd);
-  Sprite_SetY(j, info.r7_overlord_y - 1);
-
-  sprite_x_vel[j] = kOverlordSpawnBall_Xvel[tmp_counter];
-  sprite_y_vel[j] = kOverlordSpawnBall_Yvel[tmp_counter];
-  sprite_floor[j] = overlord_floor[k];
-  if (byte_7E0FB6) {
-    sprite_ai_state[j] = byte_7E0FB6;
-    sprite_y_lo[j] = sprite_y_lo[j] + 8;
-    sprite_flags2[j] = 3;
-    sprite_flags4[j] = 9;
-  }
-  sprite_delay_aux2[j] = 64;
-  SpriteSfx_QueueSfx3WithPan(j, 0x7);
-}
-
-void Overlord01_PositionTarget(int k) {  // 89c01e
-  byte_7E0FDE = k;
-}
-
-void Overlord_CheckIfActive(int k) {  // 89c08d
-  static const int16 kOverlordInRangeOffs[2] = { 0x130, -0x40 };
-  if (player_is_indoors)
-    return;
-  int j = frame_counter & 1;
-  uint16 x = BG2HOFS_copy2 + kOverlordInRangeOffs[j] - (overlord_x_lo[k] | overlord_x_hi[k] << 8);
-  uint16 y = BG2VOFS_copy2 + kOverlordInRangeOffs[j] - (overlord_y_lo[k] | overlord_y_hi[k] << 8);
-  if ((x >> 15) != j || (y >> 15) != j) {
-    overlord_type[k] = 0;
-    uint16 blk = overlord_offset_sprite_pos[k];
-    if (blk != 0xffff) {
-      uint8 loadedmask = (0x80 >> (blk & 7));
-      overworld_sprite_was_loaded[blk >> 3] &= ~loadedmask;
-    }
-  }
-}
-
-void ArmosCoordinator_RotateKnights(int k) {  // 9deccc
-  if (!overlord_gen2[k])
-    overlord_gen1[k]++;
-  ArmosCoordinator_Rotate(k);
-}
-
-void ArmosCoordinator_Rotate(int k) {  // 9decd4
-  static const uint16 kArmosCoordinator_Tab0[6] = { 0, 425, 340, 255, 170, 85 };
-
-  WORD(overlord_x_lo[0]) += (int8)overlord_floor[k];
-  for (int i = 0; i != 6; i++) {
-    int t0 = WORD(overlord_x_lo[0]) + kArmosCoordinator_Tab0[i];
-    uint8 size = overlord_x_lo[2];
-    int tx = (overlord_x_lo[k] | overlord_x_hi[k] << 8) + ArmosSin(t0, size);
-    overlord_x_hi[i] = tx;
-    overlord_y_hi[i] = tx >> 8;
-    int ty = (overlord_y_lo[k] | overlord_y_hi[k] << 8) + ArmosSin(t0 + 0x80, size);
-    overlord_gen2[i] = ty;
-    overlord_floor[i] = ty >> 8;
-  }
-  tmp_counter = 6;
-}
-
-bool ArmosCoordinator_CheckKnights() {  // 9dedb8
-  for (int j = 5; j >= 0; j--) {
-    if (sprite_state[j] && sprite_ai_state[j] == 0)
-      return false;
-  }
-  return true;
-}
-
-void ArmosCoordinator_DisableCoercion(int k) {  // 9dedcb
-  for (int j = 5; j >= 0; j--)
-    sprite_ai_state[j] = 0;
-}
-
--- a/overlord.h
+++ /dev/null
@@ -1,35 +1,0 @@
-#pragma once
-#include "types.h"
-
-void Overlord_StalfosFactory(int k);
-void Overlord_SetX(int k, uint16 v);
-void Overlord_SetY(int k, uint16 v);
-void Overlord_SpawnBoulder();
-void Overlord_Main();
-void Overlord_ExecuteAll();
-void Overlord_ExecuteSingle(int k);
-void Overlord19_ArmosCoordinator_bounce(int k);
-void Overlord18_InvisibleStalfos(int k);
-void Overlord17_PotTrap(int k);
-void Overlord16_ZoroSpawner(int k);
-void Overlord15_WizzrobeSpawner(int k);
-void Overlord14_TileRoom(int k);
-int TileRoom_SpawnTile(int k);
-void Overlord10_PirogusuSpawner_left(int k);
-void Overlord0A_FallingSquare(int k);
-void SpawnFallingTile(int k);
-void Overlord09_WallmasterSpawner(int k);
-void Overlord08_BlobSpawner(int k);
-void Overlord07_MovingFloor(int k);
-void Sprite_Overlord_PlayFallingSfx(int k);
-void Overlord05_FallingStalfos(int k);
-void Overlord06_BadSwitchSnake(int k);
-void Overlord02_FullRoomCannons(int k);
-void Overlord03_VerticalCannon(int k);
-void Overlord_SpawnCannonBall(int k, int xd);
-void Overlord01_PositionTarget(int k);
-void Overlord_CheckIfActive(int k);
-void ArmosCoordinator_RotateKnights(int k);
-void ArmosCoordinator_Rotate(int k);
-bool ArmosCoordinator_CheckKnights();
-void ArmosCoordinator_DisableCoercion(int k);
--- a/overworld.c
+++ /dev/null
@@ -1,4093 +1,0 @@
-#include "overworld.h"
-#include "hud.h"
-#include "load_gfx.h"
-#include "dungeon.h"
-#include "tagalong.h"
-#include "sprite.h"
-#include "ancilla.h"
-#include "player.h"
-#include "misc.h"
-#include "messaging.h"
-#include "player_oam.h"
-#include "snes/snes_regs.h"
-#include "assets.h"
-
-const uint16 kOverworld_OffsetBaseX[64] = {
-  0,     0, 0x400, 0x600, 0x600, 0xa00, 0xa00, 0xe00,
-  0,     0, 0x400, 0x600, 0x600, 0xa00, 0xa00, 0xe00,
-  0, 0x200, 0x400, 0x600, 0x800, 0xa00, 0xc00, 0xe00,
-  0,     0, 0x400, 0x600, 0x600, 0xa00, 0xc00, 0xc00,
-  0,     0, 0x400, 0x600, 0x600, 0xa00, 0xc00, 0xc00,
-  0, 0x200, 0x400, 0x600, 0x800, 0xa00, 0xc00, 0xe00,
-  0,     0, 0x400, 0x600, 0x800, 0xa00, 0xa00, 0xe00,
-  0,     0, 0x400, 0x600, 0x800, 0xa00, 0xa00, 0xe00,
-};
-const uint16 kOverworld_OffsetBaseY[64] = {
-      0,     0,     0,     0,     0,     0,     0,     0,
-      0,     0, 0x200,     0,     0,     0,     0, 0x200,
-  0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400,
-  0x600, 0x600, 0x600, 0x600, 0x600, 0x600, 0x600, 0x600,
-  0x600, 0x600, 0x800, 0x600, 0x600, 0x800, 0x600, 0x600,
-  0xa00, 0xa00, 0xa00, 0xa00, 0xa00, 0xa00, 0xa00, 0xa00,
-  0xc00, 0xc00, 0xc00, 0xc00, 0xc00, 0xc00, 0xc00, 0xc00,
-  0xc00, 0xc00, 0xe00, 0xe00, 0xe00, 0xc00, 0xc00, 0xe00,
-};
-static const uint16 kOverworld_UpDownScrollTarget[64] = {
-  0xff20, 0xff20, 0xff20, 0xff20, 0xff20, 0xff20, 0xff20, 0xff20,
-  0xff20, 0xff20,  0x120, 0xff20, 0xff20, 0xff20, 0xff20,  0x120,
-   0x320,  0x320,  0x320,  0x320,  0x320,  0x320,  0x320,  0x320,
-   0x520,  0x520,  0x520,  0x520,  0x520,  0x520,  0x520,  0x520,
-   0x520,  0x520,  0x720,  0x520,  0x520,  0x720,  0x520,  0x520,
-   0x920,  0x920,  0x920,  0x920,  0x920,  0x920,  0x920,  0x920,
-   0xb20,  0xb20,  0xb20,  0xb20,  0xb20,  0xb20,  0xb20,  0xb20,
-   0xb20,  0xb20,  0xd20,  0xd20,  0xd20,  0xb20,  0xb20,  0xd20,
-};
-static const uint16 kOverworld_LeftRightScrollTarget[64] = {
-  0xff00, 0xff00, 0x300, 0x500, 0x500, 0x900, 0x900, 0xd00,
-  0xff00, 0xff00, 0x300, 0x500, 0x500, 0x900, 0x900, 0xd00,
-  0xff00,  0x100, 0x300, 0x500, 0x700, 0x900, 0xb00, 0xd00,
-  0xff00, 0xff00, 0x300, 0x500, 0x500, 0x900, 0xb00, 0xb00,
-  0xff00, 0xff00, 0x300, 0x500, 0x500, 0x900, 0xb00, 0xb00,
-  0xff00,  0x100, 0x300, 0x500, 0x700, 0x900, 0xb00, 0xd00,
-  0xff00, 0xff00, 0x300, 0x500, 0x700, 0x900, 0x900, 0xd00,
-  0xff00, 0xff00, 0x300, 0x500, 0x700, 0x900, 0x900, 0xd00,
-};
-#if 0
-static const uint16 kSpExit_Top[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0x200, 0x200, 0, 0, 0, 0, 0, 0 };
-static const uint16 kSpExit_Bottom[16] = { 0x120, 0x20, 0x320, 0x20, 0, 0, 0x320, 0x320, 0x320, 0x220, 0, 0, 0, 0, 0x320, 0x320 };
-static const uint16 kSpExit_Left[16] = { 0, 0x100, 0x200, 0x600, 0x600, 0xa00, 0xc00, 0xc00, 0, 0x100, 0x200, 0x600, 0x600, 0xa00, 0xc00, 0xc00 };
-static const uint16 kSpExit_Right[16] = { 0, 0x100, 0x500, 0x600, 0x600, 0xa00, 0xc00, 0xc00, 0, 0x100, 0x400, 0x600, 0x600, 0xa00, 0xc00, 0xc00 };
-static const uint16 kSpExit_Tab4[16] = { 0xff20, 0xff20, 0xff20, 0xff20, 0xff20, 0xff20, 0xff20, 0xff20, 0xff20, 0xff20, 0x120, 0xff20, 0xff20, 0xff20, 0xff20, 0x120 };
-static const int16 kSpExit_Tab6[16] = { -4, 0x100, 0x300, 0x100, 0x500, 0x900, 0xb00, 0xb00, -4, 0x100, 0x300, 0x500, 0x500, 0x900, 0xb00, 0xb00 };
-static const int16 kSpExit_Tab5[16] = { -0xe0, -0xe0, -0xe0, -0xe0, -0xe0, -0xe0, 0x400, 0x400, -0xe0, -0xe0, 0x120, -0xe0, -0xe0, -0xe0, 0x400, 0x400 };
-static const uint16 kSpExit_Tab7[16] = { 4, 0x104, 0x300, 0x100, 0x500, 0x900, 0xb00, 0xb00, 4, 0x104, 0x300, 0x100, 0x500, 0x900, 0xb00, 0xb00 };
-static const uint16 kSpExit_LeftEdgeOfMap[16] = { 0, 0, 0x200, 0x600, 0x600, 0xa00, 0xc00, 0xc00, 0, 0, 0x200, 0x600, 0x600, 0xa00, 0xc00, 0xc00 };
-static const uint8 kSpExit_Dir[16] = { 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
-static const uint8 kSpExit_SprGfx[16] = { 0xc, 0xc, 0xe, 0xe, 0xe, 0x10, 0x10, 0x10, 0xe, 0xe, 0xe, 0xe, 0x10, 0x10, 0x10, 0x10 };
-static const uint8 kSpExit_AuxGfx[16] = { 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f };
-static const uint8 kSpExit_PalBg[16] = { 0xa, 0xa, 0xa, 0xa, 2, 2, 2, 0xa, 2, 2, 0xa, 2, 2, 2, 2, 0xa };
-static const uint8 kSpExit_PalSpr[16] = { 1, 8, 8, 8, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 2 };
-#endif
-#define turtlerock_ctr (some_menu_ctr)
-#define ganonentrance_ctr (some_menu_ctr)
-static PlayerHandlerFunc *const kOverworld_EntranceSequence[5] = {
-  &Overworld_AnimateEntrance_PoD,
-  &Overworld_AnimateEntrance_Skull,
-  &Overworld_AnimateEntrance_Mire,
-  &Overworld_AnimateEntrance_TurtleRock,
-  &Overworld_AnimateEntrance_GanonsTower,
-};
-#ifndef map16_decode_0
-#define map16_decode_0 ((uint8*)(g_ram+0x14400))
-#define map16_decode_1 ((uint8*)(g_ram+0x14410))
-#define map16_decode_2 ((uint8*)(g_ram+0x14420))
-#define map16_decode_3 ((uint8*)(g_ram+0x14430))
-#define map16_decode_last (*(uint16*)(g_ram+0x14440))
-#define map16_decode_tmp (*(uint16*)(g_ram+0x14442))
-#endif
-static const uint16 kSecondaryOverlayPerOw[128] = {
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-  0x1c0c, 0x1c0c, 0, 0, 0, 0, 0, 0, 0x1c0c, 0x1c0c, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-  0, 0, 0, 0, 0x3b0, 0x180c, 0x180c, 0x288, 0, 0, 0, 0, 0, 0x180c, 0x180c, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1ab6, 0x1ab6, 0, 0xe2e, 0xe2e, 0, 0, 0,
-  0x1ab6, 0x1ab6, 0, 0xe2e, 0xe2e, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x3b0, 0, 0, 0x288,
-  0, 0, 0, 0, 0, 0, 0, 0,
-};
-#define XY(x, y) ((y)*64+(x))
-// this alternate entry point is for scrolling OW area loads
-// b/c drawing a door only applies to when you transition from a dungeon to the OW
-// the exceptioon is OW areas 0x80 and above which are handled similar to entrances
-static const uint16 kOverworld_DrawStrip_Tab[3] = { 0x3d0, 0x410, 0xf410 };
-static const uint16 kOverworld_Func2_Tab[4] = { 8, 4, 2, 1 };
-static const uint16 kOverworld_Entrance_Tab0[44] = {
-  0xfe, 0xc5, 0xfe, 0x114, 0x115, 0x175, 0x156, 0xf5, 0xe2, 0x1ef, 0x119, 0xfe, 0x172, 0x177, 0x13f, 0x172, 0x112, 0x161, 0x172, 0x14c, 0x156, 0x1ef, 0xfe, 0xfe, 0xfe, 0x10b, 0x173, 0x143, 0x149, 0x175, 0x103, 0x100,
-  0x1cc, 0x15e, 0x167, 0x128, 0x131, 0x112, 0x16d, 0x163, 0x173, 0xfe, 0x113, 0x177,
-};
-static const uint16 kOverworld_Entrance_Tab1[44] = {
-  0x14a, 0xc4, 0x14f, 0x115, 0x114, 0x174, 0x155, 0xf5, 0xee, 0x1eb, 0x118, 0x146, 0x171, 0x155, 0x137, 0x174, 0x173, 0x121, 0x164, 0x155, 0x157, 0x128, 0x114, 0x123, 0x113, 0x109, 0x118, 0x161, 0x149, 0x117, 0x174, 0x101,
-  0x1cc, 0x131, 0x51, 0x14e, 0x131, 0x112, 0x17a, 0x163, 0x172, 0x1bd, 0x152, 0x167,
-};
-static const uint16 kDwPaletteAnim[35] = {
-  0x884, 0xcc7, 0x150a, 0x154d, 0x7ff6, 0x5944, 0x7ad1,
-  0x884, 0xcc7, 0x150a, 0x154d, 0x5bff, 0x7ad1, 0x21af,
-  0x1084, 0x48c0, 0x6186, 0x7e6d, 0x7fe0, 0x5944, 0x7e20,
-  0x1084, 0x000e, 0x1059, 0x291f, 0x7fe0, 0x5944, 0x7e20,
-  0x1084, 0x1508, 0x196c, 0x21af, 0x7ff6, 0x1d4c, 0x7ad1,
-};
-static const uint16 kDwPaletteAnim2[40] = {
-  0x7fff, 0x884, 0x1cc8, 0x1dce, 0x3694, 0x4718, 0x1d4a, 0x18ac,
-  0x7fff, 0x1908, 0x2d2f, 0x3614, 0x4eda, 0x471f, 0x1d4a, 0x390f,
-  0x7fff, 0x34cd, 0x5971, 0x5635, 0x7f1b, 0x7fff, 0x1d4a, 0x3d54,
-  0x7fff, 0x1908, 0x2d2f, 0x3614, 0x4eda, 0x471f, 0x1d4a, 0x390f,
-  0x7fff, 0x884, 0x52a, 0x21ef, 0x3ab5, 0x4b39, 0x1d4c, 0x18ac,
-};
-static const uint16 kSpecialSwitchArea_Map8[4] = { 0x105, 0x1e4, 0xad, 0xb9 };
-static const uint16 kSpecialSwitchArea_Screen[4] = { 0, 45, 15, 129 };
-static const uint8 kSpecialSwitchArea_Direction[4] = { 8, 2, 8, 8 };
-static const uint16 kSpecialSwitchArea_Exit[4] = { 0x180, 0x181, 0x182, 0x189 };
-const uint8 kVariousPacks[16] = {
-  0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x5b, 0x01, 0x5a,
-  0x42, 0x43, 0x44, 0x45, 0x3f, 0x59, 0x0b, 0x5a
-};
-static const uint16 kSpecialSwitchAreaB_Map8[3] = { 0x17c, 0x1e4, 0xad };
-static const uint16 kSpecialSwitchAreaB_Screen[3] = { 0x80, 0x80, 0x81 };
-static const uint16 kSpecialSwitchAreaB_Direction[3] = { 4, 1, 4 };
-static const int16 kSwitchAreaTab0[4] = { 0xf80, 0xf80, 0x3f, 0x3f };
-static const int16 kSwitchAreaTab1[256] = {
-  0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x1060, 0x1060, 0x1060, 0x1060, 0x60,
-  0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60,
-  0x60, 0x60, 0x60, 0x1060, 0x1060, 0x60, 0x1060, 0x1060, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60,
-  0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x1060, 0x1060, 0x60,
-  0x80, 0x80, 0x40, 0x80, 0x80, 0x80, 0x80, 0x40, 0x1080, 0x1080, 0x40, 0x1080, 0x1080, 0x1080, 0x1080, 0x40,
-  0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x80, 0x80, 0x40, 0x80, 0x80, 0x40, 0x80, 0x80,
-  0x1080, 0x1080, 0x40, 0x1080, 0x1080, 0x40, 0x1080, 0x1080, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
-  0x80, 0x80, 0x40, 0x40, 0x40, 0x80, 0x80, 0x40, 0x1080, 0x1080, 0x40, 0x40, 0x40, 0x1080, 0x1080, 0x40,
-  0x1800, 0x1840, 0x1800, 0x1800, 0x1840, 0x1800, 0x1840, 0x1800, 0x1800, 0x1840, 0x1800, 0x1800, 0x1840, 0x1800, 0x1840, 0x1800,
-  0x1800, 0x1800, 0x1800, 0x1800, 0x1800, 0x1800, 0x1800, 0x1800, 0x1800, 0x1840, 0x1800, 0x1800, 0x1840, 0x1800, 0x1800, 0x1840,
-  0x1800, 0x1840, 0x1800, 0x1800, 0x1840, 0x1800, 0x1800, 0x1840, 0x1800, 0x1800, 0x1800, 0x1800, 0x1800, 0x1800, 0x1800, 0x1800,
-  0x1800, 0x1840, 0x1800, 0x1800, 0x1800, 0x1800, 0x1840, 0x1800, 0x1800, 0x1840, 0x1800, 0x1800, 0x1800, 0x1800, 0x1840, 0x1800,
-  0x2000, 0x2040, 0x1000, 0x2000, 0x2040, 0x2000, 0x2040, 0x1000, 0x2000, 0x2040, 0x1000, 0x2000, 0x2040, 0x2000, 0x2040, 0x1000,
-  0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x2000, 0x2040, 0x1000, 0x2000, 0x2040, 0x1000, 0x2000, 0x2040,
-  0x2000, 0x2040, 0x1000, 0x2000, 0x2040, 0x1000, 0x2000, 0x2040, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000,
-  0x2000, 0x2040, 0x1000, 0x1000, 0x1000, 0x2000, 0x2040, 0x1000, 0x2000, 0x2040, 0x1000, 0x1000, 0x1000, 0x2000, 0x2040, 0x1000,
-};
-static const int16 kSwitchAreaTab3[4] = { 2, -2, 16, -16 };
-// kOverworldAreaHeads[i] != i for subregions of a big area
-static const uint8 kOverworldAreaHeads[64] = {
-  0,  0,  2,  3,  3,  5,  5,  7,
-  0,  0, 10,  3,  3,  5,  5, 15,
-  16, 17, 18, 19, 20, 21, 22, 23,
-  24, 24, 26, 27, 27, 29, 30, 30,
-  24, 24, 34, 27, 27, 37, 30, 30,
-  40, 41, 42, 43, 44, 45, 46, 47,
-  48, 48, 50, 51, 52, 53, 53, 55,
-  48, 48, 58, 59, 60, 53, 53, 63,
-};
-static const uint16 kOverworld_Size1[2] = { 0x11e, 0x31e };
-static const uint16 kOverworld_Size2[2] = { 0x100, 0x300 };
-static const uint16 kOverworld_UpDownScrollSize[2] = { 0x2e0, 0x4e0 };
-static const uint16 kOverworld_LeftRightScrollSize[2] = { 0x300, 0x500 };
-static const int16 kOverworld_Func6B_Tab1[4] = { -8, 8, -8, 8 };
-static const int16 kOverworld_Func6B_Tab2[4] = { 27, 27, 30, 30 };
-static const int16 kOverworld_Func6B_Tab3[4] = { -0x70, 0x70, -0x70, 0x70 };
-static const int16 kOverworld_Func6B_AreaDelta[4] = { -8, 8, -1, 1 };
-static const uint8 kOverworld_Func8_tab[4] = { 0xe0, 8, 0xe0, 0x10 };
-static const uint16 kDoorAnimTiles[56] = {
-  0xda8, 0xda9, 0xdaa, 0xdab,
-  0xdac, 0xdad, 0xdae, 0xdaf,
-  0xdb0, 0xdb1, 0xdb2, 0xdb3,
-  0xdb6, 0xdb7, 0xdb8, 0xdb9,
-  0xdba, 0xdbb, 0xdbc, 0xdbd,
-  0xdcd, 0xdce, 0xdcf, 0xdd0,
-  0xdd3, 0xdd4, 0xdd5, 0xdd6,
-  0xdd7, 0xdd8, 0xdd9, 0xdda,
-  0xdd1, 0xdd2, 0xdd3, 0xdd4,
-  0xdd1, 0xdd2, 0xdd7, 0xdd8,
-  0x918, 0x919, 0x91a, 0x91b,
-  0xddb, 0xddc, 0xddd, 0xdde,
-  0xdd1, 0xdd2, 0xddb, 0xddc,
-  0xe21, 0xe22, 0xe23, 0xe24,
-};
-static PlayerHandlerFunc *const kOverworldSubmodules[48] = {
-  &Module09_00_PlayerControl,
-  &Module09_LoadAuxGFX,
-  &Overworld_FinishTransGfx,
-  &Module09_LoadNewMapAndGFX,
-  &Module09_LoadNewSprites,
-  &Overworld_StartScrollTransition,
-  &Overworld_RunScrollTransition,
-  &Overworld_EaseOffScrollTransition,
-  &Overworld_FinalizeEntryOntoScreen,
-  &Module09_09_OpenBigDoorFromExiting,
-  &Module09_0A_WalkFromExiting_FacingDown,
-  &Module09_0B_WalkFromExiting_FacingUp,
-  &Module09_0C_OpenBigDoor,
-  &Overworld_StartMosaicTransition,
-  &PreOverworld_LoadOverlays,
-  &Module09_LoadAuxGFX,
-  &Overworld_FinishTransGfx,
-  &Module09_LoadNewMapAndGFX,
-  &Module09_LoadNewSprites,
-  &Overworld_StartScrollTransition,
-  &Overworld_RunScrollTransition,
-  &Overworld_EaseOffScrollTransition,
-  &Module09_FadeBackInFromMosaic,
-  &Overworld_StartMosaicTransition,
-  &Overworld_Func18,
-  &Overworld_Func19,
-  &Module09_LoadAuxGFX,
-  &Overworld_FinishTransGfx,
-  &Overworld_Func1C,
-  &Overworld_Func1D,
-  &Overworld_Func1E,
-  &Overworld_Func1F,
-  &Overworld_LoadOverlays2,
-  &Overworld_LoadAmbientOverlayFalse,
-  &Overworld_Func22,
-  &Module09_MirrorWarp,
-  &Overworld_StartMosaicTransition,
-  &Overworld_LoadOverlays,
-  &Module09_LoadAuxGFX,
-  &Overworld_FinishTransGfx,
-  &Overworld_LoadAndBuildScreen,
-  &Module09_FadeBackInFromMosaic,
-  &Module09_2A_RecoverFromDrowning,
-  &Overworld_Func2B,
-  &Module09_MirrorWarp,
-  &Overworld_WeathervaneExplosion,
-  &Module09_2E_Whirlpool,
-  &Overworld_Func2F,
-};
-static PlayerHandlerFunc *const kModule_PreOverworld[3] = {
-  &PreOverworld_LoadProperties,
-  &PreOverworld_LoadOverlays,
-  &Module08_02_LoadAndAdvance,
-};
-const uint8 *GetMap8toTileAttr() {
-  return kMap8DataToTileAttr;
-}
-
-const uint16 *GetMap16toMap8Table() {
-  return kMap16ToMap8;
-}
-
-bool LookupInOwEntranceTab(uint16 r0, uint16 r2) {
-  for (int i = countof(kOverworld_Entrance_Tab0) - 1; i >= 0; i--) {
-    if (r0 == kOverworld_Entrance_Tab0[i] && r2 == kOverworld_Entrance_Tab1[i])
-      return true;
-  }
-  return false;
-}
-
-int LookupInOwEntranceTab2(uint16 pos) {
-  for (int i = 128; i >= 0; i--) {
-    if (pos == kOverworld_Entrance_Pos[i] && overworld_area_index == kOverworld_Entrance_Area[i])
-      return i;
-  }
-  return -1;
-}
-
-bool CanEnterWithTagalong(int e) {
-  uint8 t = follower_indicator;
-  return t == 0 || t == 5 || t == 14 || t == 1 || (t == 7 || t == 8) && e >= 59;
-}
-
-int DirToEnum(int dir) {
-  int xx = 3;
-  while (!(dir & 1))
-    xx--, dir >>= 1;
-  return xx;
-}
-
-void Overworld_ResetMosaicDown() {
-  if (palette_filter_countdown & 1)
-    mosaic_level -= 0x10;
-  BGMODE_copy = 9;
-  MOSAIC_copy = mosaic_level | 7;
-}
-
-void Overworld_Func1D() {
-  assert(0);
-}
-
-void Overworld_Func1E() {
-  assert(0);
-}
-
-uint16 Overworld_GetSignText(int area) {
-  return kOverworld_SignText[area];
-}
-
-const uint8 *GetOverworldSpritePtr(int area) {
-  int base = (sram_progress_indicator == 3) ? 2 :
-    (sram_progress_indicator == 2) ? 1 : 0;
-  return kOverworldSprites + kOverworldSpriteOffs[area + base * 144];
-}
-
-uint8 GetOverworldBgPalette(int idx) {
-  return kOverworldBgPalettes[idx];
-}
-
-void Sprite_LoadGraphicsProperties() {  // 80fc41
-  memcpy(overworld_sprite_gfx + 64, kOverworldSpriteGfx + 0xc0, 64);
-  memcpy(overworld_sprite_palettes + 64, kOverworldSpritePalettes + 0xc0, 64);
-  Sprite_LoadGraphicsProperties_light_world_only();
-}
-
-void Sprite_LoadGraphicsProperties_light_world_only() {  // 80fc62
-  int i = sram_progress_indicator < 2 ? 0 :
-    sram_progress_indicator != 3 ? 1 : 2;
-  memcpy(overworld_sprite_gfx, kOverworldSpriteGfx + i * 64, 64);
-  memcpy(overworld_sprite_palettes, kOverworldSpritePalettes + i * 64, 64);
-}
-
-void InitializeMirrorHDMA() {  // 80fdee
-  HDMAEN_copy = 0;
-
-  mirror_vars.var0 = 0;
-  mirror_vars.var6 = 0;
-  mirror_vars.var5 = 0;
-  mirror_vars.var7 = 0;
-  mirror_vars.var8 = 0;
-
-  mirror_vars.var10 = mirror_vars.var11 = 8;
-  mirror_vars.var9 = 21;
-  mirror_vars.var1[0] = -0x200;
-  mirror_vars.var1[1] = 0x200;
-  mirror_vars.var3[0] = -0x40;
-  mirror_vars.var3[1] = 0x40;
-
-  HdmaSetup(0xF2FB, 0xF2FB, 0x42, (uint8)BG1HOFS, (uint8)BG2HOFS, 0);
-
-  uint16 v = BG2HOFS_copy2;
-  for (int i = 0; i < 240; i++)
-    hdma_table_dynamic[i] = v;
-  HDMAEN_copy = 0xc0;
-}
-
-void MirrorWarp_BuildWavingHDMATable() {  // 80fe64
-  MirrorWarp_RunAnimationSubmodules();
-  if (frame_counter & 1)
-    return;
-
-  int y = 240 - 8;
-  do {
-    hdma_table_dynamic[y] = hdma_table_dynamic[y + 2] = hdma_table_dynamic[y + 4] = hdma_table_dynamic[y + 6] = hdma_table_dynamic[y - 8];
-    y -= 8;
-  } while (y != 0);
-
-  int i = mirror_vars.var0 >> 1;
-  int t = mirror_vars.var6 + mirror_vars.var3[i];
-  if (!sign16(t - mirror_vars.var1[i] ^ mirror_vars.var1[i])) {
-    t = mirror_vars.var1[i];
-    mirror_vars.var5 = 0;
-    mirror_vars.var7 = 0;
-    mirror_vars.var0 ^= 2;
-  }
-  mirror_vars.var6 = t;
-  t += mirror_vars.var7;
-  mirror_vars.var7 = t & 0xff;
-  if (sign16(t))
-    t |= 0xff;
-  else
-    t &= ~0xff;
-  t = mirror_vars.var5 + swap16(t);
-  mirror_vars.var5 = t;
-  if (palette_filter_countdown >= 0x30 && !(t & ~7)) {
-    mirror_vars.var1[0] = -0x100;
-    mirror_vars.var1[1] = 0x100;
-    subsubmodule_index++;
-    t = 0;
-  }
-  hdma_table_dynamic[0] = hdma_table_dynamic[2] = hdma_table_dynamic[4] = hdma_table_dynamic[6] = t + BG2HOFS_copy2;
-}
-
-void MirrorWarp_BuildDewavingHDMATable() {  // 80ff2f
-  MirrorWarp_RunAnimationSubmodules();
-  if (frame_counter & 1)
-    return;
-  int y = 240 - 8;
-  do {
-    hdma_table_dynamic[y] = hdma_table_dynamic[y + 2] = hdma_table_dynamic[y + 4] = hdma_table_dynamic[y + 6] = hdma_table_dynamic[y - 8];
-    y -= 8;
-  } while (y != 0);
-
-  uint16 t = hdma_table_dynamic[0xc0] | hdma_table_dynamic[0xc8] | hdma_table_dynamic[0xd0] | hdma_table_dynamic[0xd8];
-  if (t == BG2HOFS_copy2) {
-    HDMAEN_copy = 0;
-    subsubmodule_index++;
-    Overworld_SetFixedColAndScroll();
-    if ((overworld_screen_index & 0x3f) != 0x1b) {
-      BG1HOFS_copy2 = BG1HOFS_copy = BG2HOFS_copy = BG2HOFS_copy2;
-      BG1VOFS_copy2 = BG1VOFS_copy = BG2VOFS_copy = BG2VOFS_copy2;
-    }
-  }
-}
-
-void TakeDamageFromPit() {  // 81ffd9
-  link_visibility_status = 12;
-  submodule_index = player_is_indoors ? 20 : 42;
-  link_health_current -= 8;
-  if (link_health_current >= 0xa8)
-    link_health_current = 0;
-}
-
-void Module08_OverworldLoad() {  // 8283bf
-  kModule_PreOverworld[submodule_index]();
-}
-
-void PreOverworld_LoadProperties() {  // 8283c7
-  CGWSEL_copy = 0x82;
-  dung_unk6 = 0;
-  AdjustLinkBunnyStatus();
-  if (main_module_index == 8)
-    LoadOverworldFromDungeon();
-  else
-    LoadOverworldFromSpecialOverworld();
-  Overworld_SetSongList();
-  link_num_keys = 0xff;
-  Hud_RefillLogic();
-
-  uint8 sc = overworld_screen_index, dr = dungeon_room_index;
-  uint8 ow_anim_tiles = 0x58;
-  uint8 xt = 2;
-
-  if (sc == 3 || sc == 5 || sc == 7) {
-    xt = 2;
-  } else if (sc == 0x43 || sc == 0x45 || sc == 0x47) {
-    xt = 9;
-  } else if (ow_anim_tiles = 0x5a, sc >= 0x40) {
-    goto dark;
-  } else if (dr == 0xe3 || dr == 0x18 || dr == 0x2f || dr == 0x1f && sc == 0x18) {
-    xt = sram_progress_indicator < 3 ? 7 : 2;
-  } else {
-    xt = savegame_has_master_sword_flags & 0x40 ? 2 : 5;
-    if (dr != 0 && dr != 0xe1) {
-dark:
-      xt = 0xf3;
-      if (queued_music_control == 0xf2)
-        goto setsong;
-      xt = sram_progress_indicator < 2 ? 3 : 2;
-    }
-  }
-  if (savegame_is_darkworld) {
-    xt = sc == 0x40 || sc == 0x43 || sc == 0x45 || sc == 0x47 ? 13 : 9;
-    if (!link_item_moon_pearl)
-      xt = 4;
-  }
-setsong:
-  queued_music_control = xt;
-  DecompressAnimatedOverworldTiles(ow_anim_tiles);
-  InitializeTilesets();
-  OverworldLoadScreensPaletteSet();
-  Overworld_LoadPalettes(kOverworldBgPalettes[sc], overworld_sprite_palettes[sc]);
-  Palette_SetOwBgColor();
-  if (main_module_index == 8) {
-    Overworld_LoadPalettesInner();
-  } else {
-    SpecialOverworld_CopyPalettesToCache();
-  }
-  Overworld_SetFixedColAndScroll();
-  overworld_fixed_color_plusminus = 0;
-  Follower_Initialize();
-
-  if (!(BYTE(overworld_screen_index) & 0x3f))
-    DecodeAnimatedSpriteTile_variable(0x1e);
-  saved_module_for_menu = 9;
-  Sprite_ReloadAll_Overworld();
-  if (!(overworld_screen_index & 0x40))
-    Sprite_InitializeMirrorPortal();
-  sound_effect_ambient = sram_progress_indicator < 2 ? 1 : 5;
-  if (follower_indicator == 6)
-    follower_indicator = 0;
-
-  is_standing_in_doorway = 0;
-  button_mask_b_y = 0;
-  button_b_frames = 0;
-  link_cant_change_direction = 0;
-  link_speed_setting = 0;
-  draw_water_ripples_or_grass = 0;
-  Dungeon_ResetTorchBackgroundAndPlayerInner();
-  if (!link_item_moon_pearl && savegame_is_darkworld) {
-    link_is_bunny = link_is_bunny_mirror = 1;
-    link_player_handler_state = kPlayerState_PermaBunny;
-    LoadGearPalettes_bunny();
-  }
-  BGMODE_copy = 9;
-  dung_want_lights_out = 0;
-  dung_hdr_collision = 0;
-  link_is_on_lower_level = 0;
-  link_is_on_lower_level_mirror = 0;
-  submodule_index++;
-  flag_update_hud_in_nmi++;
-  dung_savegame_state_bits = 0;
-  LoadOWMusicIfNeeded();
-}
-
-void AdjustLinkBunnyStatus() {  // 82856a
-  if (link_item_moon_pearl)
-    ForceNonbunnyStatus();
-}
-
-void ForceNonbunnyStatus() {  // 828570
-  link_player_handler_state = kPlayerState_Ground;
-  link_timer_tempbunny = 0;
-  link_need_for_poof_for_transform = 0;
-  link_is_bunny = 0;
-  link_is_bunny_mirror = 0;
-
-  if (enhanced_features0 & kFeatures0_TurnWhileDashing)
-    link_is_running = 0;
-}
-
-void RecoverPositionAfterDrowning() {  // 829583
-  link_x_coord = link_x_coord_cached;
-  link_y_coord = link_y_coord_cached;
-  ow_scroll_vars0.ystart = room_scroll_vars_y_vofs1_cached;
-  ow_scroll_vars0.xstart = room_scroll_vars_y_vofs2_cached;
-  ow_scroll_vars1.ystart = room_scroll_vars_x_vofs1_cached;
-  ow_scroll_vars1.xstart = room_scroll_vars_x_vofs2_cached;
-
-  up_down_scroll_target = up_down_scroll_target_cached;
-  up_down_scroll_target_end = up_down_scroll_target_end_cached;
-  left_right_scroll_target = left_right_scroll_target_cached;
-  left_right_scroll_target_end = left_right_scroll_target_end_cached;
-
-  if (player_is_indoors) {
-    camera_y_coord_scroll_low = camera_y_coord_scroll_low_cached;
-    camera_y_coord_scroll_hi = camera_y_coord_scroll_low + 2;
-    camera_x_coord_scroll_low = camera_x_coord_scroll_low_cached;
-    camera_x_coord_scroll_hi = camera_x_coord_scroll_low + 2;
-  }
-  WORD(quadrant_fullsize_x) = WORD(quadrant_fullsize_x_cached);
-  WORD(link_quadrant_x) = WORD(link_quadrant_x_cached);
-  if (!player_is_indoors) {
-    camera_y_coord_scroll_hi = camera_y_coord_scroll_low - 2;
-    camera_x_coord_scroll_hi = camera_x_coord_scroll_low - 2;
-  }
-
-  link_direction_facing = link_direction_facing_cached;
-  link_is_on_lower_level = link_is_on_lower_level_cached;
-  link_is_on_lower_level_mirror = link_is_on_lower_level_mirror_cached;
-  is_standing_in_doorway = is_standing_in_doorway_cahed;
-  dung_cur_floor = dung_cur_floor_cached;
-  link_visibility_status = 0;
-  countdown_for_blink = 0x90;
-  Dungeon_PlayBlipAndCacheQuadrantVisits();
-  link_disable_sprite_damage = 0;
-  Link_ResetStateAfterDamagingPit();
-  tagalong_var5 = 0;
-  Follower_Initialize();
-  dung_flag_statechange_waterpuzzle = 0;
-  overworld_map_state = 0;
-  subsubmodule_index = 0;
-  overworld_screen_transition = 0;
-  submodule_index = 0;
-  if (!link_health_current) {
-    mapbak_TM = TM_copy;
-    mapbak_TS = TS_copy;
-    saved_module_for_menu = main_module_index;
-    main_module_index = 18;
-    submodule_index = 1;
-    countdown_for_blink = 0;
-  }
-}
-
-void Module0F_SpotlightClose() {  // 829982
-  static const uint8 kTab[4] = { 8, 4, 2, 1 };
-  Sprite_Main();
-  if (submodule_index == 0)
-    Dungeon_PrepExitWithSpotlight();
-  else
-    Spotlight_ConfigureTableAndControl();
-
-  if (!player_is_indoors) {
-    if (BYTE(overworld_screen_index) == 0xf)
-      draw_water_ripples_or_grass = 1;
-    link_speed_setting = 6;
-    Link_HandleVelocity();
-    link_x_vel = link_y_vel = 0;
-  }
-
-  int i = link_direction_facing >> 1;
-  if (!player_is_indoors)
-    i = (which_entrance == 0x43) ? 1 : 0;
-
-  link_direction = link_direction_last = kTab[i];
-  Link_HandleMovingAnimation_FullLongEntry();
-  LinkOam_Main();
-}
-
-void Dungeon_PrepExitWithSpotlight() {  // 8299ca
-  is_nmi_thread_active = 0;
-  nmi_flag_update_polyhedral = 0;
-  if (!player_is_indoors) {
-    Ancilla_TerminateWaterfallSplashes();
-    link_y_coord_exit = link_y_coord;
-  }
-  uint8 m = ZeldaGetEntranceMusicTrack(which_entrance);
-  if (m != 3 || (m = sram_progress_indicator) >= 2) {
-    if (m != 0xf2)  // fade to 0x40
-      m = 0xf1;  // fade to zero
-    else if (music_unk1 == 12)
-      m = 7;
-    music_control = m;
-  }
-  hud_floor_changed_timer = 0;
-  Hud_FloorIndicator();
-  flag_update_hud_in_nmi++;
-  IrisSpotlight_close();
-  submodule_index++;
-}
-
-void Spotlight_ConfigureTableAndControl() {  // 829a19
-  IrisSpotlight_ConfigureTable();
-  is_nmi_thread_active = 0;
-  nmi_flag_update_polyhedral = 0;
-  if (submodule_index)
-    return;
-  if (main_module_index == 6)
-    link_y_coord = link_y_coord_exit;
-  OpenSpotlight_Next2();
-}
-
-void OpenSpotlight_Next2() {  // 829a37
-  if (main_module_index != 9) {
-    EnableForceBlank();
-    Link_ItemReset_FromOverworldThings();
-  }
-
-  if (main_module_index == 9) {
-    if (dungeon_room_index != 0x20)
-      submodule_index = link_direction_facing ? 0xa : 0xb;
-
-    ow_countdown_transition = 16;
-    if ((BYTE(ow_entrance_value) | BYTE(big_rock_starting_address)) && HIBYTE(big_rock_starting_address)) { // wtf
-      BYTE(door_open_closed_counter) = (big_rock_starting_address & 0x8000) ? 0x18 : 0;
-      big_rock_starting_address &= 0x7fff;
-      BYTE(door_animation_step_indicator) = 0;
-      submodule_index = 9;
-      subsubmodule_index = 0;
-      sound_effect_2 = 21;
-    }
-  }
-  W12SEL_copy = 0;
-  W34SEL_copy = 0;
-  WOBJSEL_copy = 0;
-  TMW_copy = 0;
-  TSW_copy = 0;
-  link_force_hold_sword_up = 0;
-
-  uint8 sc = overworld_screen_index;
-  if (sc == 3 || sc == 5 || sc == 7) {
-    COLDATA_copy0 = 0x26;
-    COLDATA_copy1 = 0x4c;
-    COLDATA_copy2 = 0x8c;
-  } else if (sc == 0x43 || sc == 0x45 || sc == 0x47) {
-    COLDATA_copy0 = 0x26;
-    COLDATA_copy1 = 0x4a;
-    COLDATA_copy2 = 0x87;
-  }
-}
-
-void Module10_SpotlightOpen() {  // 829ad7
-  Sprite_Main();
-  if (submodule_index == 0)
-    Module10_00_OpenIris();
-  else
-    Spotlight_ConfigureTableAndControl();
-  LinkOam_Main();
-}
-
-void Module10_00_OpenIris() {  // 829ae6
-  Spotlight_open();
-  submodule_index++;
-}
-
-void SetTargetOverworldWarpToPyramid() {  // 829e5f
-  if (main_module_index != 21)
-    return;
-  LoadOverworldFromDungeon();
-  DecompressAnimatedOverworldTiles(0x5a);
-  ResetAncillaAndCutscene();
-}
-
-void ResetAncillaAndCutscene() {  // 829e6e
-  Ancilla_TerminateSelectInteractives(0);
-  link_disable_sprite_damage = 0;
-  button_b_frames = 0;
-  button_mask_b_y = 0;
-  link_force_hold_sword_up = 0;
-  flag_is_link_immobilized = 0;
-}
-
-void Module09_Overworld() {  // 82a475
-  kOverworldSubmodules[submodule_index]();
-
-  int bg2x = BG2HOFS_copy2;
-  int bg2y = BG2VOFS_copy2;
-  int bg1x = BG1HOFS_copy2;
-  int bg1y = BG1VOFS_copy2;
-
-  BG2HOFS_copy2 = BG2HOFS_copy = bg2x + bg1_x_offset;
-  BG2VOFS_copy2 = BG2VOFS_copy = bg2y + bg1_y_offset;
-  BG1HOFS_copy2 = BG1HOFS_copy = bg1x + bg1_x_offset;
-  BG1VOFS_copy2 = BG1VOFS_copy = bg1y + bg1_y_offset;
-
-  Sprite_Main();
-
-  BG2HOFS_copy2 = bg2x;
-  BG2VOFS_copy2 = bg2y;
-  BG1HOFS_copy2 = bg1x;
-  BG1VOFS_copy2 = bg1y;
-
-  LinkOam_Main();
-  Hud_RefillLogic();
-  OverworldOverlay_HandleRain();
-}
-
-void OverworldOverlay_HandleRain() {  // 82a4cd
-  static const uint8 kOverworld_DrawBadWeather_X[4] = { 1, 0, 1, 0 };
-  static const uint8 kOverworld_DrawBadWeather_Y[4] = { 0, 17, 0, 17 };
-  if (BYTE(overworld_screen_index) != 0x70 && sram_progress_indicator >= 2 || (save_ow_event_info[0x70] & 0x20))
-    return;
-  if (frame_counter == 3 || frame_counter == 88) {
-    CGADSUB_copy = 0x32;
-  } else if (frame_counter == 5 || frame_counter == 44 || frame_counter == 90) {
-    CGADSUB_copy = 0x72;
-  } else if (frame_counter == 36) {
-    sound_effect_1 = 54;
-    CGADSUB_copy = 0x32;
-  }
-  if (frame_counter & 3)
-    return;
-  int i = (move_overlay_ctr + 1) & 3;
-  move_overlay_ctr = i;
-  BG1HOFS_copy2 += kOverworld_DrawBadWeather_X[i] << 8;
-  BG1VOFS_copy2 += kOverworld_DrawBadWeather_Y[i] << 8;
-}
-
-void Module09_00_PlayerControl() {  // 82a53c
-  if (!(flag_custom_spell_anim_active | flag_is_link_immobilized | flag_block_link_menu | trigger_special_entrance)) {
-    if (filtered_joypad_H & 0x10) {
-      overworld_map_state = 0;
-      submodule_index = 1;
-      saved_module_for_menu = main_module_index;
-      main_module_index = 14;
-      return;
-    }
-
-    if (DidPressButtonForMap()) {
-      overworld_map_state = 0;
-      submodule_index = 7;
-      saved_module_for_menu = main_module_index;
-      main_module_index = 14;
-      return;
-    }
-    if (joypad1H_last & 0x20) {
-      DisplaySelectMenu();
-      return;
-    }
-    Hud_HandleItemSwitchInputs();
-  }
-  if (trigger_special_entrance)
-    Overworld_AnimateEntrance();
-  Link_Main();
-  if (super_bomb_indicator_unk2 != 0xff)
-    Hud_SuperBombIndicator();
-  current_area_of_player = (link_y_coord & 0x1e00) >> 5 | (link_x_coord & 0x1e00) >> 8;
-  Graphics_LoadChrHalfSlot();
-  Overworld_OperateCameraScroll();
-  if (main_module_index != 11) {
-    Overworld_UseEntrance();
-    Overworld_DwDeathMountainPaletteAnimation();
-    OverworldHandleTransitions();
-  } else {
-    ScrollAndCheckForSOWExit();
-  }
-}
-
-void OverworldHandleTransitions() {  // 82a9c4
-  if (BYTE(overworld_screen_trans_dir_bits2))
-    OverworldHandleMapScroll();
-  int dir;
-  uint16 x, y, t;
-  if (link_y_vel != 0) {
-    dir = link_direction & 12;
-    t = link_y_coord - kOverworld_OffsetBaseY[BYTE(current_area_of_player) >> 1];
-    if ((y = 6, x = 8, t < 4) || (y = 4, x = 4, t >= overworld_right_bottom_bound_for_scroll))
-      goto compare;
-  }
-  if (link_x_vel != 0) {
-    dir = link_direction & 3;
-    t = link_x_coord - kOverworld_OffsetBaseX[BYTE(current_area_of_player) >> 1];
-    if ((y = 2, x = 2, t < 6) || (y = 0, x = 1, t >= (uint16)(overworld_right_bottom_bound_for_scroll + 4))) {
-compare:
-      if (x == dir && !Link_CheckForEdgeScreenTransition())
-        goto after;
-    }
-  }
-  Overworld_CheckSpecialSwitchArea();
-  return;
-after:
-  y >>= 1;
-  Dungeon_ResetTorchBackgroundAndPlayerInner();
-  map16_load_src_off &= kSwitchAreaTab0[y];
-  int pushed = ((current_area_of_player + kSwitchAreaTab3[y]) >> 1) & 0x3f;
-  map16_load_src_off += kSwitchAreaTab1[y * 64 + pushed];
-
-  uint8 old_screen = overworld_screen_index;
-  if (old_screen == 0x2a)
-    sound_effect_ambient = 0x80;
-
-  uint8 new_area = kOverworldAreaHeads[pushed] | savegame_is_darkworld;
-  BYTE(overworld_screen_index) = new_area;
-  BYTE(overworld_area_index) = new_area;
-  if (!savegame_is_darkworld || link_item_moon_pearl) {
-    uint8 music = overworld_music[new_area];
-    if ((music & 0xf0) == 0)
-      sound_effect_ambient = 5;
-    if (!ZeldaIsPlayingMusicTrack(music & 0xf))
-      music_control = 0xf1;
-  }
-  Overworld_LoadGFXAndScreenSize();
-  submodule_index = 1;
-  BYTE(overworld_screen_trans_dir_bits) = dir;
-  BYTE(overworld_screen_trans_dir_bits2) = dir;
-  byte_7E069C = overworld_screen_transition = DirToEnum(dir);
-  BYTE(ow_entrance_value) = 0;
-  BYTE(big_rock_starting_address) = 0;
-  transition_counter = 0;
-
-  if (!(old_screen & 0x3f) || !(overworld_screen_index & 0xbf)) {
-    subsubmodule_index = 0;
-    submodule_index = 13;
-    MOSAIC_copy = 0;
-    mosaic_level = 0;
-  } else {
-    uint8 sc = overworld_screen_index;
-    Overworld_LoadPalettes(kOverworldBgPalettes[sc], overworld_sprite_palettes[sc]);
-    Overworld_CopyPalettesToCache();
-  }
-}
-
-void Overworld_LoadGFXAndScreenSize() {  // 82ab08
-  int i = BYTE(overworld_screen_index);
-  incremental_counter_for_vram = 0;
-  sprite_graphics_index = overworld_sprite_gfx[i];
-  aux_tile_theme_index = kOverworldAuxTileThemeIndexes[i];
-
-  overworld_area_is_big_backup = overworld_area_is_big;
-  BYTE(overworld_area_is_big) = kOverworldMapIsSmall[i & 0x3f] ? 0 : 0x20;
-  ((uint8 *)&overworld_right_bottom_bound_for_scroll)[1] = kOverworldMapIsSmall[i & 0x3f] ? 1 : 3;
-  main_tile_theme_index = overworld_screen_index & 0x40 ? 0x21 : 0x20;
-  misc_sprites_graphics_index = kVariousPacks[6 + (overworld_screen_index & 0x40 ? 8 : 0)];
-
-  int j = overworld_screen_index & 0xbf;
-  overworld_offset_base_y = kOverworld_OffsetBaseY[j];
-  overworld_offset_base_x = kOverworld_OffsetBaseX[j] >> 3;
-
-  int m = overworld_area_is_big ? 0x3f0 : 0x1f0;
-  overworld_offset_mask_y = m;
-  overworld_offset_mask_x = m >> 3;
-}
-
-void ScrollAndCheckForSOWExit() {  // 82ab7b
-  if (BYTE(overworld_screen_trans_dir_bits2))
-    OverworldHandleMapScroll();
-
-  const uint16 *map8 = Overworld_GetMap16OfLink_Mult8();
-  int a = map8[0] & 0x1ff;
-  for (int i = 2; i >= 0; i--) {
-    if (kSpecialSwitchAreaB_Map8[i] == a && kSpecialSwitchAreaB_Screen[i] == overworld_screen_index) {
-      link_direction = kSpecialSwitchAreaB_Direction[i];
-      byte_7E069C = overworld_screen_transition = DirToEnum(link_direction);
-      submodule_index = 36;
-      subsubmodule_index = 0;
-      BYTE(dungeon_room_index) = 0;
-      break;
-    }
-  }
-}
-
-void Module09_LoadAuxGFX() {  // 82ab88
-  save_ow_event_info[0x3b] &= ~0x20;
-  save_ow_event_info[0x7b] &= ~0x20;
-  save_dung_info[267] &= ~0x80;
-  save_dung_info[40] &= ~0x100;
-  LoadTransAuxGFX();
-  PrepTransAuxGfx();
-  nmi_disable_core_updates = nmi_subroutine_index = 9;
-  submodule_index++;
-}
-
-void Overworld_FinishTransGfx() {  // 82abbc
-  nmi_disable_core_updates = nmi_subroutine_index = 10;
-  submodule_index++;
-}
-
-void Module09_LoadNewMapAndGFX() {  // 82abc6
-  word_7E04C8 = 0;
-  SomeTileMapChange();
-  nmi_disable_core_updates++;
-  CreateInitialNewScreenMapToScroll();
-  LoadNewSpriteGFXSet();
-}
-
-void Overworld_RunScrollTransition() {  // 82abda
-  Link_HandleMovingAnimation_FullLongEntry();
-  Graphics_IncrementalVRAMUpload();
-  uint8 rv = OverworldScrollTransition();
-  if (!(rv & 0xf)) {
-    BYTE(overworld_screen_trans_dir_bits2) = BYTE(overworld_screen_trans_dir_bits);
-    OverworldTransitionScrollAndLoadMap();
-    BYTE(overworld_screen_trans_dir_bits2) = 0;
-  }
-}
-
-void Module09_LoadNewSprites() {  // 82abed
-  if (overworld_screen_transition == 1) {
-    BG2VOFS_copy2 += 2;
-    link_y_coord += 2;
-  }
-  Sprite_OverworldReloadAll_justLoad();
-  num_memorized_tiles = 0;
-  if (sram_progress_indicator >= 2 && submodule_index != 18)
-    Overworld_SetFixedColAndScroll();
-  Overworld_StartScrollTransition();
-}
-
-void Overworld_StartScrollTransition() {  // 82ac27
-  submodule_index++;
-  if (BYTE(overworld_screen_trans_dir_bits) >= 4) {
-    BYTE(overworld_screen_trans_dir_bits2) = BYTE(overworld_screen_trans_dir_bits);
-    OverworldTransitionScrollAndLoadMap();
-    BYTE(overworld_screen_trans_dir_bits2) = 0;
-  }
-}
-
-void Overworld_EaseOffScrollTransition() {  // 82ac3a
-  if (kOverworldMapIsSmall[BYTE(overworld_screen_index)]) {
-    BYTE(overworld_screen_trans_dir_bits2) = BYTE(overworld_screen_trans_dir_bits);
-    OverworldTransitionScrollAndLoadMap();
-    BYTE(overworld_screen_trans_dir_bits2) = 0;
-  }
-  if (++subsubmodule_index < 8)
-    return;
-  if ((BYTE(overworld_screen_trans_dir_bits) == 8 || BYTE(overworld_screen_trans_dir_bits) == 2) && subsubmodule_index < 9)
-    return;
-
-  subsubmodule_index = 0;
-  BYTE(overworld_screen_trans_dir_bits) = 0;
-
-  if (kOverworldMapIsSmall[BYTE(overworld_screen_index)]) {
-    map16_load_src_off = orange_blue_barrier_state;
-    map16_load_dst_off = word_7EC174;
-    map16_load_var2 = word_7EC176;
-  }
-  submodule_index++;
-  Follower_Disable();
-}
-
-void Module09_0A_WalkFromExiting_FacingDown() {  // 82ac8f
-  link_direction_last = 4;
-  Link_HandleMovingAnimation_FullLongEntry();
-  link_y_coord += 1;
-  if (--ow_countdown_transition)
-    return;
-  submodule_index = 0;
-  link_y_coord += 3;
-  link_y_vel = 3;
-  Overworld_OperateCameraScroll();
-  if (BYTE(overworld_screen_trans_dir_bits2))
-    OverworldHandleMapScroll();
-}
-
-void Module09_0B_WalkFromExiting_FacingUp() {  // 82acc2
-  Link_HandleMovingAnimation_FullLongEntry();
-  link_y_coord -= 1;
-  if (--ow_countdown_transition)
-    return;
-  submodule_index = 0;
-}
-
-void Module09_09_OpenBigDoorFromExiting() {  // 82ad4a
-  if (BYTE(door_animation_step_indicator) != 3) {
-    Overworld_DoMapUpdate32x32_conditional();
-    return;
-  }
-  ow_countdown_transition = 36;
-  BYTE(overworld_screen_trans_dir_bits2) = 0;
-  submodule_index++;
-}
-
-void Overworld_DoMapUpdate32x32_B() {  // 82ad5c
-  Overworld_DoMapUpdate32x32();
-  BYTE(door_open_closed_counter) = 0;
-}
-
-void Module09_0C_OpenBigDoor() {  // 82ad6c
-  if (BYTE(door_animation_step_indicator) != 3) {
-    Overworld_DoMapUpdate32x32_conditional();
-    return;
-  }
-  submodule_index = 0;
-  subsubmodule_index = 0;
-  BYTE(overworld_screen_trans_dir_bits2) = 0;
-}
-
-void Overworld_DoMapUpdate32x32_conditional() {  // 82ad7b
-  if (door_open_closed_counter & 7)
-    BYTE(door_open_closed_counter)++;
-  else
-    Overworld_DoMapUpdate32x32();
-}
-
-void Overworld_DoMapUpdate32x32() {  // 82ad85
-  int i = num_memorized_tiles >> 1;
-  int j = door_open_closed_counter >> 1;
-  uint16 pos, tile;
-
-  memorized_tile_addr[i] = pos = big_rock_starting_address;
-  memorized_tile_value[i] = tile = kDoorAnimTiles[j + 0];
-  Overworld_DrawMap16_Persist(pos, tile);
-
-  memorized_tile_addr[i + 1] = pos = big_rock_starting_address + 2;
-  memorized_tile_value[i + 1] = tile = kDoorAnimTiles[j + 1];
-  Overworld_DrawMap16_Persist(pos, tile);
-
-  memorized_tile_addr[i + 2] = pos = big_rock_starting_address + 0x80;
-  memorized_tile_value[i + 2] = tile = kDoorAnimTiles[j + 2];
-  Overworld_DrawMap16_Persist(pos, tile);
-
-  memorized_tile_addr[i + 3] = pos = big_rock_starting_address + 0x82;
-  memorized_tile_value[i + 3] = tile = kDoorAnimTiles[j + 3];
-  Overworld_DrawMap16_Persist(pos, tile);
-  vram_upload_data[vram_upload_offset >> 1] = 0xffff;
-  num_memorized_tiles += 8;
-  door_animation_step_indicator += (door_open_closed_counter == 32) ? 2 : 1;
-  nmi_load_bg_from_vram = 1;
-  BYTE(door_open_closed_counter)++;
-}
-
-void Overworld_StartMosaicTransition() {  // 82ae5e
-  ConditionalMosaicControl();
-  switch (subsubmodule_index) {
-  case 0:
-    if (BYTE(overworld_screen_index) != 0x80) {
-      if (!ZeldaIsPlayingMusicTrack(overworld_music[BYTE(overworld_screen_index)] & 0xf))
-        music_control = 0xf1;
-    }
-    ResetTransitionPropsAndAdvance_ResetInterface();
-    break;
-  case 1:
-    ApplyPaletteFilter_bounce();
-    break;
-  default:
-    INIDISP_copy = 0x80;
-    subsubmodule_index = 0;
-    if (!(overworld_screen_index & 0x3f))
-      DecodeAnimatedSpriteTile_variable(0x1e);
-    if (BYTE(overworld_area_index) != 0 && main_module_index != 11) {
-      TM_copy = 0x16;
-      TS_copy = 1;
-      CGWSEL_copy = 0x82;
-      CGADSUB_copy = 0x20;
-      submodule_index++;
-      return;
-    }
-    if (submodule_index == 36) {
-      LoadOverworldFromSpecialOverworld();
-      if (!(overworld_screen_index & 0x3f))
-        DecodeAnimatedSpriteTile_variable(0x1e);
-    }
-    submodule_index++;
-    break;
-  }
-}
-
-void Overworld_LoadOverlays() {  // 82af0b
-  Sprite_InitializeSlots();
-  Sprite_ReloadAll_Overworld();
-  link_state_bits = 0;
-  link_picking_throw_state = 0;
-  sound_effect_ambient = 5;
-  Overworld_LoadOverlays2();
-
-}
-
-void PreOverworld_LoadOverlays() {  // 82af19
-  sound_effect_ambient = 5;
-  Overworld_LoadOverlays2();
-}
-
-void Overworld_LoadOverlays2() {  // 82af1e
-  uint16 xv;
-
-  overworld_screen_index_prev = overworld_screen_index;
-  map16_load_src_off_prev = map16_load_src_off;
-  map16_load_var2_prev = map16_load_var2;
-  map16_load_dst_off_prev = map16_load_dst_off;
-  overworld_screen_transition_prev = overworld_screen_transition;
-  overworld_screen_trans_dir_bits_prev = overworld_screen_trans_dir_bits;
-  overworld_screen_trans_dir_bits2_prev = overworld_screen_trans_dir_bits2;
-
-  overlay_index = 0;
-  BG1VOFS_subpixel = 0;
-  BG1HOFS_subpixel = 0;
-
-  int si = overworld_screen_index;
-  if (si >= 0x80) {
-    xv = 0x97;
-    if (dungeon_room_index == 0x180) {
-      if (save_ow_event_info[0x80] & 0x40)
-        goto getout; // master sword retrieved?
-      goto load_overlay;
-    }
-    if ((xv = 0x94, dungeon_room_index == 0x181) ||
-        (xv = 0x93, dungeon_room_index == 0x189))
-      goto load_overlay;
-
-    if (dungeon_room_index == 0x182 || dungeon_room_index == 0x183)
-      sound_effect_ambient = 1;  // zora falls
-getout:
-    TS_copy = 0;
-    submodule_index++;
-    return;
-  }
-
-  if ((si & 0x3f) == 0) {
-    xv = (!(si & 0x40) && save_ow_event_info[0x80] & 0x40) ? 0x9e : 0x9d;  // forest
-    goto load_overlay;
-  }
-
-  if ((xv = 0x95, si == 0x3 || si == 0x5 || si == 0x7) ||
-      (xv = 0x9c, si == 0x43 || si == 0x45 || si == 0x47))
-    goto load_overlay;
-  if (si == 0x70) {
-    if (!(save_ow_event_info[0x70] & 0x20))
-      xv = 0x9f; // rain
-  } else {
-    xv = (sram_progress_indicator < 2) ? 0x9f : 0x96;
-  }
-load_overlay:
-  map16_load_src_off = 0x390;
-  overlay_index = overworld_screen_index = xv;
-  map16_load_var2 = (map16_load_src_off - 0x400 & 0xf80) >> 7;
-  map16_load_dst_off = (map16_load_src_off - 0x10 & 0x3e) >> 1;
-  overworld_screen_transition = 0;
-  overworld_screen_trans_dir_bits = 0;
-  overworld_screen_trans_dir_bits2 = 0;
-  CGWSEL_copy = 0x82;
-  TM_copy = 0x16;
-  TS_copy = 1;
-  sound_effect_ambient = overworld_music[BYTE(overworld_screen_index)] >> 4;
-
-  if (xv == 0x97 || xv == 0x94 || xv == 0x93 || xv == 0x9d || xv == 0x9e || xv == 0x9f)
-    CGADSUB_copy = 0x72;
-  else if (xv == 0x95 || xv == 0x9c || BYTE(overworld_screen_index_prev) == 0x5b ||
-           BYTE(overworld_screen_index_prev) == 0x1b && (submodule_index == 35 || submodule_index == 44))
-    CGADSUB_copy = 0x20;
-  else
-    TS_copy = 0, CGADSUB_copy = 0x20;
-
-  LoadOverworldOverlay();
-  if (BYTE(overlay_index) == 0x94)
-    BG1VOFS_copy2 |= 0x100;
-
-  overworld_screen_index = overworld_screen_index_prev;
-  map16_load_src_off = map16_load_src_off_prev;
-  map16_load_var2 = map16_load_var2_prev;
-  map16_load_dst_off = map16_load_dst_off_prev;
-  overworld_screen_transition = overworld_screen_transition_prev;
-  overworld_screen_trans_dir_bits = overworld_screen_trans_dir_bits_prev;
-  overworld_screen_trans_dir_bits2 = overworld_screen_trans_dir_bits2_prev;
-}
-
-void Module09_FadeBackInFromMosaic() {  // 82b0d2
-  Overworld_ResetMosaicDown();
-  switch (subsubmodule_index) {
-  case 0: {
-    uint8 sc = overworld_screen_index;
-    Overworld_LoadPalettes(kOverworldBgPalettes[sc], overworld_sprite_palettes[sc]);
-    OverworldMosaicTransition_LoadSpriteGraphicsAndSetMosaic();
-    break;
-  }
-  case 1:
-    Graphics_IncrementalVRAMUpload();
-    ApplyPaletteFilter_bounce();
-    break;
-  default:
-    last_music_control = music_unk1;
-    if (BYTE(overworld_screen_index) != 0x80 && BYTE(overworld_screen_index) != 0x2a) {
-      uint8 m = overworld_music[BYTE(overworld_screen_index)];
-      sound_effect_ambient = (m >> 4) ? (m >> 4) : 5;
-      if (!ZeldaIsPlayingMusicTrack(m & 0xf))
-        music_control = (m & 0xf);
-    }
-    submodule_index = 8;
-    subsubmodule_index = 0;
-    if (main_module_index == 11) {
-      main_module_index = 9;
-      submodule_index = 31;
-      ow_countdown_transition = 12;
-    }
-  }
-}
-
-void Overworld_Func1C() {  // 82b150
-  Overworld_ResetMosaicDown();
-  switch (subsubmodule_index) {
-  case 0:
-    OverworldMosaicTransition_LoadSpriteGraphicsAndSetMosaic();
-    break;
-  case 1:
-    Graphics_IncrementalVRAMUpload();
-    ApplyPaletteFilter_bounce();
-    break;
-  default:
-    if (BYTE(overworld_screen_index) < 0x80)
-      music_control = (overworld_screen_index & 0x3f) ? 2 : 5;
-    submodule_index = 8;
-    subsubmodule_index = 0;
-    break;
-  }
-}
-
-void OverworldMosaicTransition_LoadSpriteGraphicsAndSetMosaic() {  // 82b171
-  LoadNewSpriteGFXSet();
-  INIDISP_copy = 0xf;
-  HDMAEN_copy = 0x80;
-  BYTE(palette_filter_countdown) = mosaic_target_level - 1;
-  mosaic_target_level = 0;
-  BYTE(darkening_or_lightening_screen) = 2;
-  subsubmodule_index++;
-}
-
-void Overworld_Func22() {  // 82b1bb
-  if (++INIDISP_copy == 15) {
-    submodule_index = 0;
-    subsubmodule_index = 0;
-  }
-}
-
-void Overworld_Func18() {  // 82b1c8
-  link_maybe_swim_faster = 0;
-  uint8 m = main_module_index;
-  uint8 sub = submodule_index;
-  Overworld_EnterSpecialArea();
-  Overworld_LoadOverlays();
-  submodule_index = sub + 1;
-  main_module_index = m;
-}
-
-void Overworld_Func19() {  // 82b1df
-  uint8 m = main_module_index;
-  uint8 sub = submodule_index;
-  Module08_02_LoadAndAdvance();
-  submodule_index = sub + 1;
-  main_module_index = m;
-}
-
-void Module09_MirrorWarp() {  // 82b1fa
-  nmi_disable_core_updates++;
-  switch (subsubmodule_index) {
-  case 0:
-    if (BYTE(overworld_screen_index) >= 0x80) {
-      submodule_index = 0;
-      subsubmodule_index = 0;
-      overworld_map_state = 0;
-      return;
-    }
-    music_control = 8;
-    flag_overworld_area_did_change = 8;
-    countdown_for_blink = 0x90;
-    InitializeMirrorHDMA();
-    savegame_is_darkworld ^= 0x40;
-    word_7E04C8 = 0;
-    BYTE(overworld_screen_index) = BYTE(overworld_area_index) = (overworld_screen_index & 0x3f) | savegame_is_darkworld;
-    overworld_map_state = 0;
-    PaletteFilter_InitializeWhiteFilter();
-    Overworld_LoadGFXAndScreenSize();
-    subsubmodule_index++;
-    break;
-  case 1:
-    subsubmodule_index++;
-    HDMAEN_copy = 0xc0;
-  case 2:
-    MirrorWarp_BuildWavingHDMATable();
-    break;
-  case 3:
-    MirrorWarp_BuildDewavingHDMATable();
-    break;
-  default:
-    MirrorWarp_FinalizeAndLoadDestination();
-    break;
-  }
-}
-
-void MirrorWarp_FinalizeAndLoadDestination() {  // 82b260
-  HdmaSetup(0, 0xf2fb, 0x41, 0, (uint8)WH0, 0);
-  IrisSpotlight_ResetTable();
-  palette_filter_countdown = 0;
-  darkening_or_lightening_screen = 0;
-  ReloadPreviouslyLoadedSheets();
-  Overworld_SetSongList();
-  HDMAEN_copy = 0x80;
-  uint8 m = overworld_music[BYTE(overworld_screen_index)];
-  music_control = m & 0xf;
-  sound_effect_ambient = m >> 4;
-  if (BYTE(overworld_screen_index) >= 0x40 && !link_item_moon_pearl)
-    music_control = 4;
-
-  saved_module_for_menu = submodule_index;
-  submodule_index = 0;
-  subsubmodule_index = 0;
-  overworld_map_state = 0;
-  nmi_disable_core_updates = 0;
-}
-
-void Overworld_DrawScreenAtCurrentMirrorPosition() {  // 82b2e6
-  uint16 bak1 = map16_load_src_off;
-  uint16 bak2 = map16_load_dst_off;
-  uint16 bak3 = map16_load_var2;
-  if (kOverworldMapIsSmall[BYTE(overworld_screen_index)]) {
-    map16_load_src_off = 0x390;
-    map16_load_var2 = (0x390 - 0x400 & 0xf80) >> 7;
-    map16_load_dst_off = (0x390 - 0x10 & 0x3e) >> 1;
-  }
-  Overworld_DrawQuadrantsAndOverlays();
-  if (submodule_index == 44)
-    MirrorBonk_RecoverChangedTiles();
-  map16_load_var2 = bak3;
-  map16_load_dst_off = bak2;
-  map16_load_src_off = bak1;
-}
-
-void MirrorWarp_LoadSpritesAndColors() {  // 82b334
-  countdown_for_blink = 0x90;
-  uint16 bak1 = map16_load_src_off;
-  uint16 bak2 = map16_load_dst_off;
-  uint16 bak3 = map16_load_var2;
-  if (kOverworldMapIsSmall[BYTE(overworld_screen_index)]) {
-    map16_load_src_off = 0x390;
-    map16_load_var2 = (0x390 - 0x400 & 0xf80) >> 7;
-    map16_load_dst_off = (0x390 - 0x10 & 0x3e) >> 1;
-  }
-  Map16ToMap8(&g_ram[0x2000], 0);
-  map16_load_var2 = bak3;
-  map16_load_dst_off = bak2;
-  map16_load_src_off = bak1;
-  OverworldLoadScreensPaletteSet();
-  uint8 sc = overworld_screen_index;
-  Overworld_LoadPalettes(kOverworldBgPalettes[sc], overworld_sprite_palettes[sc]);
-  Palette_SpecialOw();
-  Overworld_SetFixedColAndScroll();
-  if (BYTE(overworld_screen_index) == 0x1b || BYTE(overworld_screen_index) == 0x5b)
-    TS_copy = 1;
-  for (int i = 0; i < 16 * 6; i++)
-    main_palette_buffer[32 + i] = 0x7fff;
-  main_palette_buffer[0] = 0x7fff;
-  if (overworld_screen_index == 0x5b) {
-    main_palette_buffer[0] = 0;
-    main_palette_buffer[32] = 0;
-  }
-  Sprite_ResetAll();
-  Sprite_ReloadAll_Overworld();
-  Link_ItemReset_FromOverworldThings();
-  Dungeon_ResetTorchBackgroundAndPlayerInner();
-  link_player_handler_state = kPlayerState_Mirror;
-  if (!(overworld_screen_index & 0x40))
-    Sprite_InitializeMirrorPortal();
-}
-
-void Overworld_Func2B() {  // 82b40a
-  Palette_AnimGetMasterSword();
-}
-
-void Overworld_WeathervaneExplosion() {  // 82b40e
-  // empty
-}
-
-void Module09_2E_Whirlpool() {  // 82b40f
-  // this is called when entering the whirlpool
-  nmi_disable_core_updates++;
-  switch (subsubmodule_index) {
-  case 0:
-    sound_effect_1 = 0x34;
-    sound_effect_ambient = 5;
-    overworld_map_state = 0;
-    palette_filter_countdown = 0;
-    subsubmodule_index++;
-    break;
-  case 1:
-    PaletteFilter_WhirlpoolBlue();
-    break;
-  case 2:
-    PaletteFilter_IsolateWhirlpoolBlue();
-    break;
-  case 3:
-    COLDATA_copy2 = 0x9f;
-    overworld_palette_aux_or_main = 0;
-    hud_palette = 0;
-    FindPartnerWhirlpoolExit();
-    BYTE(dung_draw_width_indicator) = 0;
-    Overworld_LoadOverlays2();
-    submodule_index--;
-    nmi_subroutine_index = 12;
-    flag_update_cgram_in_nmi = 0;
-    COLDATA_copy2 = 0x80;
-    INIDISP_copy = 0xf;
-    nmi_disable_core_updates++;
-    subsubmodule_index++;
-    break;
-  case 4: case 6:
-    nmi_subroutine_index = 13;
-    nmi_disable_core_updates++;
-    subsubmodule_index++;
-    break;
-  case 5:
-    Overworld_LoadOverlayAndMap();
-    nmi_subroutine_index = 12;
-    INIDISP_copy = 0xf;
-    nmi_disable_core_updates++;
-    subsubmodule_index++;
-    break;
-  case 7:
-    Module09_LoadAuxGFX();
-    submodule_index--;
-    subsubmodule_index++;
-    break;
-  case 8:
-    Overworld_FinishTransGfx();
-    INIDISP_copy = 0xf;
-    nmi_disable_core_updates++;
-    submodule_index--;
-    subsubmodule_index++;
-    break;
-  case 9: {
-    overworld_palette_aux_or_main = 0;
-    Palette_Load_SpriteMain();
-    Palette_Load_SpriteEnvironment();
-    Palette_Load_Sp0L();
-    Palette_Load_HUD();
-    Palette_Load_OWBGMain();
-    uint8 sc = overworld_screen_index;
-    Overworld_LoadPalettes(kOverworldBgPalettes[sc], overworld_sprite_palettes[sc]);
-    Palette_SetOwBgColor();
-    Overworld_SetFixedColAndScroll();
-    LoadNewSpriteGFXSet();
-    COLDATA_copy2 = 0x80;
-    INIDISP_copy = 0xf;
-    nmi_disable_core_updates++;
-    subsubmodule_index++;
-    break;
-  }
-  case 10:
-    PaletteFilter_WhirlpoolRestoreRedGreen();
-    if (BYTE(palette_filter_countdown))
-      PaletteFilter_WhirlpoolRestoreRedGreen();
-    break;
-  case 11:
-    Graphics_IncrementalVRAMUpload();
-    PaletteFilter_WhirlpoolRestoreBlue();
-    break;
-  case 12:
-    countdown_for_blink = 144;
-    ReloadPreviouslyLoadedSheets();
-    HDMAEN_copy = 0x80;
-    sound_effect_ambient = overworld_music[BYTE(overworld_screen_index)] >> 4;
-    music_control = savegame_is_darkworld ? 9 : 2;
-    submodule_index = 0;
-    subsubmodule_index = 0;
-    overworld_map_state = 0;
-    nmi_disable_core_updates = 0;
-    break;
-  }
-}
-
-void Overworld_Func2F() {  // 82b521
-  dung_bg2[0x720 / 2] = 0x212;
-  Overworld_Memorize_Map16_Change(0x720, 0x212);
-  Overworld_DrawMap16(0x720, 0x212);
-  nmi_load_bg_from_vram = 1;
-  submodule_index = 0;
-}
-
-void Module09_2A_RecoverFromDrowning() {  // 82b528
-  // this is called for example when entering water without swim capability
-  switch (subsubmodule_index) {
-  case 0:  Module09_2A_00_ScrollToLand(); break;
-  default: RecoverPositionAfterDrowning(); break;
-  }
-}
-
-void Module09_2A_00_ScrollToLand() {  // 82b532
-  uint16 x = link_x_coord, xd = 0;
-  if (x != link_x_coord_cached) {
-    int16 d = (x > link_x_coord_cached) ? -1 : 1;
-    if ((x += d) != link_x_coord_cached)
-      x += d;
-    xd = x - link_x_coord;
-    link_x_coord = x;
-  }
-  uint16 y = link_y_coord, yd = 0;
-  if (y != link_y_coord_cached) {
-    int16 d = (y > link_y_coord_cached) ? -1 : 1;
-    if ((y += d) != link_y_coord_cached)
-      y += d;
-    yd = y - link_y_coord;
-    link_y_coord = y;
-  }
-  link_y_vel = yd;
-  link_x_vel = xd;
-  if (y == link_y_coord_cached && x == link_x_coord_cached) {
-    subsubmodule_index++;
-    link_incapacitated_timer = 0;
-    set_when_damaging_enemies = 0;
-  }
-  Overworld_OperateCameraScroll();
-  if (BYTE(overworld_screen_trans_dir_bits2))
-    OverworldHandleMapScroll();
-}
-
-void Overworld_OperateCameraScroll() {  // 82bb90
-  int z = (allow_scroll_z && link_z_coord != 0xffff) ? link_z_coord : 0;
-  uint16 y = link_y_coord - z + 12;
-
-  if (link_y_vel != 0) {
-    int vy = sign8(link_y_vel) ? -1 : 1;
-    int av = sign8(link_y_vel) ? (link_y_vel ^ 0xff) + 1 : link_y_vel;
-    uint16 r4 = 0, subp;
-    do {
-      if (sign8(link_y_vel)) {
-        if (y <= camera_y_coord_scroll_low)
-          r4 += OverworldCameraBoundaryCheck(6, 0, vy, 0);
-      } else {
-        if (y >= camera_y_coord_scroll_hi)
-          r4 += OverworldCameraBoundaryCheck(6, 2, vy, 0);
-      }
-    } while (--av);
-    WORD(byte_7E069E[0]) = r4;
-    uint8 oi = BYTE(overlay_index);
-    if (oi != 0x97 && oi != 0x9d && r4 != 0) {
-      if (oi == 0xb5 || oi == 0xbe) {
-        subp = (r4 & 3) << 14;
-        r4 >>= 2;
-        if (r4 >= 0x3000)
-          r4 |= 0xf000;
-      } else {
-        subp = (r4 & 1) << 15;
-        r4 >>= 1;
-        if (r4 >= 0x7000)
-          r4 |= 0xf000;
-      }
-      uint32 tmp = BG1VOFS_subpixel | BG1VOFS_copy2 << 16;
-      tmp += subp | r4 << 16;
-      BG1VOFS_subpixel = (uint16)(tmp);
-      BG1VOFS_copy2 = (uint16)(tmp >> 16);
-      if ((overworld_screen_index & 0x3f) == 0x1b) {
-        if (BG1VOFS_copy2 <= 0x600)
-          BG1VOFS_copy2 = 0x600;
-        else if (BG1VOFS_copy2 >= 0x6c0)
-          BG1VOFS_copy2 = 0x6c0;
-      }
-    }
-  }
-
-  uint16 x = link_x_coord + 8;
-  if (link_x_vel != 0) {
-    int vx = sign8(link_x_vel) ? -1 : 1;
-    int ax = sign8(link_x_vel) ? (link_x_vel ^ 0xff) + 1 : link_x_vel;
-    uint16 r4 = 0, subp;
-    do {
-      if (sign8(link_x_vel)) {
-        if (x <= camera_x_coord_scroll_low)
-          r4 += OverworldCameraBoundaryCheck(0, 4, vx, 4);
-      } else {
-        if (x >= camera_x_coord_scroll_hi)
-          r4 += OverworldCameraBoundaryCheck(0, 6, vx, 4);
-      }
-    } while (--ax);
-    WORD(byte_7E069E[1]) = r4;
-    uint8 oi = BYTE(overlay_index);
-    if (oi != 0x97 && oi != 0x9d && r4 != 0) {
-      if (oi == 0x95 || oi == 0x9e) {
-        subp = (r4 & 3) << 14;
-        r4 >>= 2;
-        if (r4 >= 0x3000)
-          r4 |= 0xf000;
-      } else {
-        subp = (r4 & 1) << 15;
-        r4 >>= 1;
-        if (r4 >= 0x7000)
-          r4 |= 0xf000;
-      }
-      uint32 tmp = BG1HOFS_subpixel | BG1HOFS_copy2 << 16;
-      tmp += subp | r4 << 16;
-      BG1HOFS_subpixel = (uint16)(tmp), BG1HOFS_copy2 = (uint16)(tmp >> 16);
-    }
-  }
-  if (BYTE(overworld_screen_index) != 0x47) {
-    if (BYTE(overlay_index) == 0x9c) {
-      uint32 tmp = BG1VOFS_subpixel | BG1VOFS_copy2 << 16;
-      tmp -= 0x2000;
-      BG1VOFS_subpixel = (uint16)(tmp), BG1VOFS_copy2 = (uint16)(tmp >> 16) + WORD(byte_7E069E[0]);
-      BG1HOFS_copy2 = BG2HOFS_copy2;
-    } else if (BYTE(overlay_index) == 0x97 || BYTE(overlay_index) == 0x9d) {
-      uint32 tmp = BG1VOFS_subpixel | BG1VOFS_copy2 << 16;
-      tmp += 0x2000;
-      BG1VOFS_subpixel = (uint16)(tmp), BG1VOFS_copy2 = (uint16)(tmp >> 16);
-      tmp = BG1HOFS_subpixel | BG1HOFS_copy2 << 16;
-      tmp += 0x2000;
-      BG1HOFS_subpixel = (uint16)(tmp), BG1HOFS_copy2 = (uint16)(tmp >> 16);
-    }
-  }
-
-  if (dungeon_room_index == 0x181) {
-    BG1VOFS_copy2 = BG2VOFS_copy2 | 0x100;
-    BG1HOFS_copy2 = BG2HOFS_copy2;
-  }
-}
-
-int OverworldCameraBoundaryCheck(int xa, int ya, int vd, int r8) {  // 82bd62
-  ya >>= 1, r8 >>= 1;
-
-  uint16 *xp = (xa ? &BG2VOFS_copy2 : &BG2HOFS_copy2);
-  uint16 *yp = &(&ow_scroll_vars0.ystart)[ya];
-  if (*xp == *yp) {
-    (&overworld_unk1)[ya] = 0;
-    (&overworld_unk1)[ya ^ 1] = 0;
-    return 0;
-  }
-  *xp += vd;
-
-  int tt = vd + (&camera_y_coord_scroll_hi)[r8];
-  (&camera_y_coord_scroll_hi)[r8] = tt;
-  (&camera_y_coord_scroll_low)[r8] = tt + 2;
-  uint16 *op = (&overworld_unk1) + ya;
-  if (!sign16(++(*op) - 0x10)) {
-    (*op) -= 0x10;
-    overworld_screen_trans_dir_bits2 |= kOverworld_Func2_Tab[ya];
-  }
-  (&overworld_unk1)[ya ^ 1] = -(&overworld_unk1)[ya];
-  return vd;
-}
-
-int OverworldScrollTransition() {  // 82c001
-  transition_counter++;
-  int y = overworld_screen_transition;
-  int d = kOverworld_Func6B_Tab1[y], rv;
-  if (y < 2) {
-    byte_7E069E[0] = d;
-    rv = (BG2VOFS_copy2 += d);
-    if (BYTE(overworld_screen_index) != 0x1b && BYTE(overworld_screen_index) != 0x5b)
-      BG1VOFS_copy2 = BG2VOFS_copy2;
-    if (transition_counter >= kOverworld_Func6B_Tab2[y])
-      link_y_coord += d;
-    if (rv != (&up_down_scroll_target)[y])
-      return rv;
-    if (y == 0)
-      BG2VOFS_copy2 -= 2;
-    link_y_coord &= ~7;
-    camera_y_coord_scroll_hi = link_y_coord + kOverworld_Func6B_Tab3[y] + 11;
-    camera_y_coord_scroll_low = camera_y_coord_scroll_hi + 2;
-    overworld_unk1 = overworld_unk1_neg = 0;
-  } else {
-    byte_7E069E[1] = d;
-    rv = (BG2HOFS_copy2 += d);
-    if (BYTE(overworld_screen_index) != 0x1b && BYTE(overworld_screen_index) != 0x5b)
-      BG1HOFS_copy2 = BG2HOFS_copy2;
-    if (transition_counter >= kOverworld_Func6B_Tab2[y])
-      link_x_coord += d;
-    if (rv != (&up_down_scroll_target)[y])
-      return rv;
-    link_x_coord &= ~7;
-    camera_x_coord_scroll_hi = link_x_coord + kOverworld_Func6B_Tab3[y] + 11;
-    camera_x_coord_scroll_low = camera_x_coord_scroll_hi + 2;
-    overworld_unk3 = overworld_unk3_neg = 0;
-  }
-  Overworld_SetCameraBoundaries(overworld_area_is_big != 0, (current_area_of_player >> 1) + kOverworld_Func6B_AreaDelta[y]);
-
-  flag_overworld_area_did_change = 1;
-  submodule_index += 1;
-  subsubmodule_index = 0;
-  transition_counter = 0;
-  Sprite_InitializeSlots();
-  return rv;
-}
-
-void Overworld_SetCameraBoundaries(int big, int area) {  // 82c0c3
-  ow_scroll_vars0.ystart = kOverworld_OffsetBaseY[area];
-  ow_scroll_vars0.yend = ow_scroll_vars0.ystart + kOverworld_Size1[big];
-  ow_scroll_vars0.xstart = kOverworld_OffsetBaseX[area];
-  ow_scroll_vars0.xend = ow_scroll_vars0.xstart + kOverworld_Size2[big];
-  up_down_scroll_target = kOverworld_UpDownScrollTarget[area];
-  up_down_scroll_target_end = up_down_scroll_target + kOverworld_UpDownScrollSize[big];
-  left_right_scroll_target = kOverworld_LeftRightScrollTarget[area];
-  left_right_scroll_target_end = left_right_scroll_target + kOverworld_LeftRightScrollSize[big];
-}
-
-void Overworld_FinalizeEntryOntoScreen() {  // 82c242
-  Link_HandleMovingAnimation_FullLongEntry();
-  int d = (byte_7E069C & 1) ? 2 : -2;
-  if (byte_7E069C & 2)
-    link_x_coord = (d += link_x_coord);
-  else
-    link_y_coord = (d += link_y_coord);
-  if ((d & 0xfe) == kOverworld_Func8_tab[byte_7E069C]) {
-    submodule_index = 0;
-    subsubmodule_index = 0;
-    uint8 m = overworld_music[BYTE(overworld_screen_index)];
-    sound_effect_ambient = m >> 4;
-    if (music_unk1 == 0xf1)
-      music_control = m & 0xf;
-  }
-  Overworld_OperateCameraScroll();
-  if (BYTE(overworld_screen_trans_dir_bits2))
-    OverworldHandleMapScroll();
-}
-
-void Overworld_Func1F() {  // 82c2a4
-  Link_HandleMovingAnimation_FullLongEntry();
-  int8 vel = byte_7E069C & 1 ? 1 : -1;
-  if (byte_7E069C & 2) {
-    link_x_coord += vel;
-    link_x_vel = vel;
-  } else {
-    link_y_coord += vel;
-    link_y_vel = vel;
-  }
-  if (!--ow_countdown_transition) {
-    main_module_index = 9;
-    subsubmodule_index = submodule_index = 0;
-  }
-  Overworld_OperateCameraScroll();
-}
-
-void ConditionalMosaicControl() {  // 82c2e4
-  if (palette_filter_countdown & 1)
-    mosaic_level += 0x10;
-  BGMODE_copy = 9;
-  MOSAIC_copy = mosaic_level | 7;
-}
-
-void Overworld_ResetMosaic_alwaysIncrease() {  // 82c2eb
-  mosaic_level += 0x10;
-  BGMODE_copy = 9;
-  MOSAIC_copy = mosaic_level | 7;
-}
-
-void Overworld_SetSongList() {  // 82c463
-  uint8 r0 = 2, y = 0xc0;
-  if (sram_progress_indicator < 3) {
-    y = 0x80;
-    if (link_sword_type < 2) {
-      r0 = 5;
-      y = 0x40;
-      if (sram_progress_indicator < 2)
-        y = 0;
-    }
-  }
-  memcpy(overworld_music, &kOwMusicSets[y], 64);
-  memcpy(overworld_music + 64, kOwMusicSets2, 96);
-  overworld_music[128] = r0;
-}
-
-void LoadOverworldFromDungeon() {  // 82e4a3
-  player_is_indoors = 0;
-  hdr_dungeon_dark_with_lantern = 0;
-  WORD(overworld_fixed_color_plusminus) = 0;
-  cur_palace_index_x2 = 0xff;
-  num_memorized_tiles = 0;
-
-  if (dungeon_room_index != 0x104 && dungeon_room_index < 0x180 && dungeon_room_index >= 0x100) {
-    LoadCachedEntranceProperties();
-  } else {
-
-    int k = 79;
-    do k--; while (kExitDataRooms[k] != dungeon_room_index);
-    BG1VOFS_copy2 = BG2VOFS_copy2 = BG1VOFS_copy = BG2VOFS_copy = kExitData_ScrollY[k];
-    BG1HOFS_copy2 = BG2HOFS_copy2 = BG1HOFS_copy = BG2HOFS_copy = kExitData_ScrollX[k];
-    link_y_coord = kExitData_YCoord[k];
-    link_x_coord = kExitData_XCoord[k];
-    map16_load_src_off = kExitData_Map16LoadSrcOff[k];
-    map16_load_var2 = (map16_load_src_off - 0x400 & 0xf80) >> 7;
-    map16_load_dst_off = (map16_load_src_off - 0x10 & 0x3e) >> 1;
-    camera_y_coord_scroll_low = kExitData_CameraYScroll[k];
-    camera_y_coord_scroll_hi = camera_y_coord_scroll_low - 2;
-    camera_x_coord_scroll_low = kExitData_CameraXScroll[k];
-    camera_x_coord_scroll_hi = camera_x_coord_scroll_low - 2;
-    WORD(link_direction_facing) = 2;
-    ow_entrance_value = kExitData_NormalDoor[k];
-    big_rock_starting_address = kExitData_FancyDoor[k];
-    overworld_area_index = overworld_screen_index = kExitData_ScreenIndex[k];
-    overworld_unk1 = kExitData_Unk1[k];
-    overworld_unk3 = kExitData_Unk3[k];
-    overworld_unk1_neg = -overworld_unk1;
-    overworld_unk3_neg = -overworld_unk3;
-  }
-  Overworld_LoadNewScreenProperties();
-}
-
-void Overworld_LoadNewScreenProperties() {  // 82e58b
-  tilemap_location_calc_mask = ~7;
-  Overworld_LoadGFXAndScreenSize();
-  BYTE(overworld_right_bottom_bound_for_scroll) = 0xe4;
-  overworld_area_is_big &= 0xff;
-  Overworld_SetCameraBoundaries(overworld_area_is_big != 0, overworld_screen_index & 0x3f);
-  link_quadrant_x = 0;
-  link_quadrant_y = 2;
-  quadrant_fullsize_x = 2;
-  quadrant_fullsize_y = 2;
-  player_oam_x_offset = player_oam_y_offset = 0x80;
-  link_direction_mask_a = link_direction_mask_b = 0xf;
-  BYTE(link_z_coord) = 0xff;
-  link_actual_vel_z = 0xff;
-}
-
-void LoadCachedEntranceProperties() {  // 82e5d4
-  overworld_area_index = overworld_area_index_exit;
-  WORD(TM_copy) = WORD(TM_copy_exit);
-  BG2VOFS_copy2 = BG2VOFS_copy = BG1VOFS_copy2 = BG1VOFS_copy = BG2VOFS_copy2_exit;
-  BG2HOFS_copy2 = BG2HOFS_copy = BG1HOFS_copy2 = BG1HOFS_copy = BG2HOFS_copy2_exit;
-  link_x_coord = link_x_coord_exit;
-  link_y_coord = link_y_coord_exit;
-  if (dungeon_room_index < 0x124)
-    link_y_coord -= 0x10;
-  WORD(link_direction_facing) = 2;
-  if (ow_entrance_value == 0xffff) {
-    link_y_coord += 0x20;
-    WORD(link_direction_facing) = 0;
-  }
-  overworld_screen_index = overworld_screen_index_exit;
-  map16_load_src_off = map16_load_src_off_exit;
-  map16_load_var2 = (map16_load_src_off - 0x400 & 0xf80) >> 7;
-  map16_load_dst_off = (map16_load_src_off - 0x10 & 0x3e) >> 1;
-  camera_y_coord_scroll_low = camera_y_coord_scroll_low_exit;
-  camera_y_coord_scroll_hi = camera_y_coord_scroll_low - 2;
-  camera_x_coord_scroll_low = camera_x_coord_scroll_low_exit;
-  camera_x_coord_scroll_hi = camera_x_coord_scroll_low - 2;
-  ow_scroll_vars0 = ow_scroll_vars0_exit;
-  up_down_scroll_target = up_down_scroll_target_exit;
-  up_down_scroll_target_end = up_down_scroll_target_end_exit;
-  left_right_scroll_target = left_right_scroll_target_exit;
-  left_right_scroll_target_end = left_right_scroll_target_end_exit;
-  overworld_unk1 = overworld_unk1_exit;
-  overworld_unk1_neg = overworld_unk1_neg_exit;
-  overworld_unk3 = overworld_unk3_exit;
-  overworld_unk3_neg = overworld_unk3_neg_exit;
-  byte_7E0AA0 = byte_7EC164;
-  main_tile_theme_index = main_tile_theme_index_exit;
-  aux_tile_theme_index = aux_tile_theme_index_exit;
-  sprite_graphics_index = sprite_graphics_index_exit;
-
-}
-
-void Overworld_EnterSpecialArea() {  // 82e851
-  num_memorized_tiles = 0;
-  overworld_area_index_spexit = overworld_area_index;
-  WORD(TM_copy_spexit) = WORD(TM_copy);
-  BG2VOFS_copy2_spexit = BG2VOFS_copy2;
-  BG2HOFS_copy2_spexit = BG2HOFS_copy2;
-
-  link_x_coord_spexit = link_x_coord;
-  link_y_coord_spexit = link_y_coord;
-
-  camera_y_coord_scroll_low_spexit = camera_y_coord_scroll_low;
-  camera_x_coord_scroll_low_spexit = camera_x_coord_scroll_low;
-  overworld_screen_index_spexit = overworld_screen_index;
-  map16_load_src_off_spexit = map16_load_src_off;
-  room_scroll_vars0_ystart_spexit = ow_scroll_vars0.ystart;
-  room_scroll_vars0_yend_spexit = ow_scroll_vars0.yend;
-  room_scroll_vars0_xstart_spexit = ow_scroll_vars0.xstart;
-  room_scroll_vars0_xend_spexit = ow_scroll_vars0.xend;
-
-  up_down_scroll_target_spexit = up_down_scroll_target;
-  up_down_scroll_target_end_spexit = up_down_scroll_target_end;
-  left_right_scroll_target_spexit = left_right_scroll_target;
-  left_right_scroll_target_end_spexit = left_right_scroll_target_end;
-  overworld_unk1_spexit = overworld_unk1;
-  overworld_unk1_neg_spexit = overworld_unk1_neg;
-  overworld_unk3_spexit = overworld_unk3;
-  overworld_unk3_neg_spexit = overworld_unk3_neg;
-  byte_7EC124 = byte_7E0AA0;
-  main_tile_theme_index_spexit = main_tile_theme_index;
-  aux_tile_theme_index_spexit = aux_tile_theme_index;
-  sprite_graphics_index_spexit = sprite_graphics_index;
-  LoadOverworldFromDungeon();
-  if (dungeon_room_index == 0x1010)
-    dungeon_room_index = 0x182;
-
-  uint8 roombak = dungeon_room_index;
-  int i = (BYTE(dungeon_room_index) -= 0x80);
-  link_direction_facing = kSpExit_Dir[i];
-  incremental_counter_for_vram = 0;
-  sprite_graphics_index = kSpExit_SprGfx[i];
-  aux_tile_theme_index = kSpExit_AuxGfx[i];
-  Overworld_LoadPalettes(kSpExit_PalBg[i], kSpExit_PalSpr[i]);
-
-  int j = dungeon_room_index & 0x3f;
-  overworld_offset_base_y = kSpExit_Top[j];
-  overworld_offset_base_x = kSpExit_LeftEdgeOfMap[j] >> 3;
-  overworld_offset_mask_y = 0x3f0;
-  overworld_offset_mask_x = 0x3f0 >> 3;
-
-  int k = dungeon_room_index & 0x7f;
-  ow_scroll_vars0.ystart = kSpExit_Top[k];
-  ow_scroll_vars0.yend = kSpExit_Bottom[k];
-  ow_scroll_vars0.xstart = kSpExit_Left[k];
-  ow_scroll_vars0.xend = kSpExit_Right[k];
-  up_down_scroll_target = kSpExit_Tab4[k];
-  up_down_scroll_target_end = kSpExit_Tab5[k];
-  left_right_scroll_target = kSpExit_Tab6[k];
-  left_right_scroll_target_end = kSpExit_Tab7[k];
-
-  BYTE(dungeon_room_index) = roombak;
-  Palette_SpecialOw();
-}
-
-void LoadOverworldFromSpecialOverworld() {  // 82e9bc
-  num_memorized_tiles = 0;
-  overworld_area_index = overworld_area_index_spexit;
-   WORD(TM_copy) = WORD(TM_copy_spexit);
-  BG2VOFS_copy2 = BG2VOFS_copy = BG1VOFS_copy2 = BG1VOFS_copy = BG2VOFS_copy2_spexit;
-  BG2HOFS_copy2 = BG2HOFS_copy = BG1HOFS_copy2 = BG1HOFS_copy = BG2HOFS_copy2_spexit;
-  link_x_coord = link_x_coord_spexit;
-  link_y_coord = link_y_coord_spexit;
-  overworld_screen_index = overworld_screen_index_spexit;
-  map16_load_src_off = map16_load_src_off_spexit;
-  map16_load_var2 = (map16_load_src_off - 0x400 & 0xf80) >> 7;
-  map16_load_dst_off = (map16_load_src_off - 0x10 & 0x3e) >> 1;
-  camera_y_coord_scroll_low = camera_y_coord_scroll_low_spexit;
-  camera_y_coord_scroll_hi = camera_y_coord_scroll_low - 2;
-  camera_x_coord_scroll_low = camera_x_coord_scroll_low_spexit;
-  camera_x_coord_scroll_hi = camera_x_coord_scroll_low - 2;
-  ow_scroll_vars0.ystart = room_scroll_vars0_ystart_spexit;
-  ow_scroll_vars0.yend = room_scroll_vars0_yend_spexit;
-  ow_scroll_vars0.xstart = room_scroll_vars0_xstart_spexit;
-  ow_scroll_vars0.xend = room_scroll_vars0_xend_spexit;
-  up_down_scroll_target = up_down_scroll_target_spexit;
-  up_down_scroll_target_end = up_down_scroll_target_end_spexit;
-  left_right_scroll_target = left_right_scroll_target_spexit;
-  left_right_scroll_target_end = left_right_scroll_target_end_spexit;
-  overworld_unk1 = overworld_unk1_spexit;
-  overworld_unk1_neg = overworld_unk1_neg_spexit;
-  overworld_unk3 = overworld_unk3_spexit;
-  overworld_unk3_neg = overworld_unk3_neg_spexit;
-  byte_7E0AA0 = byte_7EC124;
-  main_tile_theme_index = main_tile_theme_index_spexit;
-  aux_tile_theme_index = aux_tile_theme_index_spexit;
-  sprite_graphics_index = sprite_graphics_index_spexit;
-  uint8 sc = overworld_screen_index;
-  Overworld_LoadPalettes(kOverworldBgPalettes[sc], overworld_sprite_palettes[sc]);
-  Palette_SpecialOw();
-  link_quadrant_x = 0;
-  link_quadrant_y = 2;
-  quadrant_fullsize_x = 2;
-  quadrant_fullsize_y = 2;
-  player_oam_x_offset = player_oam_y_offset = 0x80;
-  link_direction_mask_a = link_direction_mask_b = 0xf;
-  BYTE(link_z_coord) = 0xff;
-  link_actual_vel_z = 0xff;
-  Link_ResetSwimmingState();
-  Overworld_LoadGFXAndScreenSize();
-  BYTE(overworld_right_bottom_bound_for_scroll) = 228;
-  overworld_area_is_big &= 0xff;
-}
-
-void FluteMenu_LoadTransport() {  // 82ec39
-  num_memorized_tiles = 0;
-  int k = birdtravel_var1[0];
-  WORD(birdtravel_var1[0]) <<= 1;
-  Overworld_LoadBirdTravelPos(k);
-}
-
-void Overworld_LoadBirdTravelPos(int k) {  // 82ec47
-  BG1VOFS_copy2 = BG2VOFS_copy2 = BG1VOFS_copy = BG2VOFS_copy = kBirdTravel_ScrollY[k];
-  BG1HOFS_copy2 = BG2HOFS_copy2 = BG1HOFS_copy = BG2HOFS_copy = kBirdTravel_ScrollX[k];
-  link_y_coord = kBirdTravel_LinkYCoord[k];
-  link_x_coord = kBirdTravel_LinkXCoord[k];
-  overworld_unk1 = kBirdTravel_Unk1[k];
-  overworld_unk3 = kBirdTravel_Unk3[k];
-  overworld_unk1_neg = -overworld_unk1;
-  overworld_unk3_neg = -overworld_unk3;
-  overworld_area_index = overworld_screen_index = kBirdTravel_ScreenIndex[k];
-
-  map16_load_src_off = kBirdTravel_Map16LoadSrcOff[k];
-  map16_load_var2 = (map16_load_src_off - 0x400 & 0xf80) >> 7;
-  map16_load_dst_off = (map16_load_src_off - 0x10 & 0x3e) >> 1;
-  camera_y_coord_scroll_low = kBirdTravel_CameraYScroll[k];
-  camera_y_coord_scroll_hi = camera_y_coord_scroll_low - 2;
-  camera_x_coord_scroll_low = kBirdTravel_CameraXScroll[k];
-  camera_x_coord_scroll_hi = camera_x_coord_scroll_low - 2;
-  ow_entrance_value = 0;
-  big_rock_starting_address = 0;
-  Overworld_LoadNewScreenProperties();
-  Sprite_ResetAll();
-  Sprite_ReloadAll_Overworld();
-  is_standing_in_doorway = 0;
-  Dungeon_ResetTorchBackgroundAndPlayerInner();
-}
-
-void FluteMenu_LoadSelectedScreenPalettes() {  // 82ecdd
-  OverworldLoadScreensPaletteSet();
-  uint8 sc = overworld_screen_index;
-  Overworld_LoadPalettes(kOverworldBgPalettes[sc], overworld_sprite_palettes[sc]);
-  Palette_SetOwBgColor();
-  Overworld_LoadPalettesInner();
-}
-
-void FindPartnerWhirlpoolExit() {  // 82ed08
-  int j = FindInWordArray(kWhirlpoolAreas, overworld_screen_index, kWhirlpoolAreas_SIZE / 2);
-  if (j >= 0) {
-    num_memorized_tiles = 0;
-    Overworld_LoadBirdTravelPos(j + 9);
-  }
-}
-
-void Overworld_LoadAmbientOverlay(bool load_map_data) {  // 82ed25
-  uint16 bak1 = map16_load_src_off;
-  uint16 bak2 = map16_load_dst_off;
-  uint16 bak3 = map16_load_var2;
-
-  if (kOverworldMapIsSmall[BYTE(overworld_screen_index)]) {
-    map16_load_src_off = 0x390;
-    map16_load_var2 = (0x390 - 0x400 & 0xf80) >> 7;
-    map16_load_dst_off = (0x390 - 0x10 & 0x3e) >> 1;
-  }
-
-  if (load_map_data)
-    Overworld_DrawQuadrantsAndOverlays();
-
-  Map16ToMap8(&g_ram[0x2000], 0);
-  map16_load_var2 = bak3;
-  map16_load_dst_off = bak2;
-  map16_load_src_off = bak1;
-
-  nmi_subroutine_index = 4;
-  nmi_disable_core_updates = 4;
-  submodule_index++;
-  INIDISP_copy = 0;
-}
-
-void Overworld_LoadAmbientOverlayFalse() {  // 82ed24
-  Overworld_LoadAmbientOverlay(false);
-}
-
-void Overworld_LoadAndBuildScreen() {  // 82ed59
-  Overworld_LoadAmbientOverlay(true);
-}
-
-void Module08_02_LoadAndAdvance() {  // 82edb9
-  Overworld_LoadAndBuildScreen();
-  main_module_index = 16;
-  submodule_index = 0;
-  subsubmodule_index = 0;
-}
-
-void Overworld_DrawQuadrantsAndOverlays() {  // 82eec5
-  Overworld_DecompressAndDrawAllQuadrants();
-  for (int i = 0; i < 16 * 4; i++)
-    dung_bg1[i] = 0xdc4;
-  uint16 pos = ow_entrance_value;
-  if (pos != 0 && pos != 0xffff) {
-    if (pos < 0x8000) {
-      dung_bg2[pos >> 1] = 0xDA4;
-      Overworld_Memorize_Map16_Change(pos, 0xda4);
-      dung_bg2[(pos + 2) >> 1] = 0xda6;
-      Overworld_Memorize_Map16_Change(pos + 2, 0xda6);
-    } else {
-      pos &= 0x1fff;
-      dung_bg2[pos >> 1] = 0xdb4;
-      Overworld_Memorize_Map16_Change(pos, 0xdb4);
-      dung_bg2[(pos + 2) >> 1] = 0xdb5;
-      Overworld_Memorize_Map16_Change(pos + 2, 0xdb5);
-    }
-    ow_entrance_value = 0;
-  }
-  Overworld_HandleOverlaysAndBombDoors();
-}
-
-void Overworld_HandleOverlaysAndBombDoors() {  // 82ef29
-  if (overworld_screen_index == 0x33)
-    dung_bg2[340] = 0x20f;
-  else if (overworld_screen_index == 0x2f)
-    dung_bg2[1497] = 0x20f;
-  if (BYTE(overworld_screen_index) < 0x80 && save_ow_event_info[BYTE(overworld_screen_index)] & 0x20)
-    Overworld_LoadEventOverlay();
-  if (save_ow_event_info[BYTE(overworld_screen_index)] & 2) {
-    int pos = kSecondaryOverlayPerOw[overworld_screen_index] >> 1;
-    dung_bg2[pos + 0] = 0xdb4;
-    dung_bg2[pos + 1] = 0xdb5;
-  }
-}
-
-void TriggerAndFinishMapLoadStripe_Y(int n) {  // 82ef7a
-  BYTE(overworld_screen_trans_dir_bits2) = 8;
-  nmi_subroutine_index = 3;
-  uint16 *dst = uvram.data;
-  *dst++ = 0x80;
-  do {
-    dst = BufferAndBuildMap16Stripes_Y(dst);
-    map16_load_src_off -= 0x80;
-    map16_load_var2 = (map16_load_var2 - 1) & 0x1f;
-  } while (--n);
-  *dst = 0xffff;
-}
-
-void TriggerAndFinishMapLoadStripe_X(int n) {  // 82efb3
-  BYTE(overworld_screen_trans_dir_bits2) = 2;
-  nmi_subroutine_index = 3;
-  uint16 *dst = uvram.data;
-  *dst++ = 0x8040;
-  do {
-    dst = BufferAndBuildMap16Stripes_X(dst);
-    map16_load_src_off -= 2;
-    map16_load_dst_off = (map16_load_dst_off - 1) & 0x1f;
-  } while (--n);
-  *dst = 0xffff;
-}
-
-void SomeTileMapChange() {  // 82efe8
-  Overworld_DecompressAndDrawAllQuadrants();
-  for (int i = 0; i < 64; i++)
-    dung_bg1[i] = 0xdc4;
-  Overworld_HandleOverlaysAndBombDoors();
-  submodule_index++;
-}
-
-void CreateInitialNewScreenMapToScroll() {  // 82f031
-  if (!kOverworldMapIsSmall[BYTE(overworld_screen_index)]) {
-    switch (BYTE(overworld_screen_trans_dir_bits2)) {
-    case 1: CreateInitialOWScreenView_Big_East(); break;
-    case 2: CreateInitialOWScreenView_Big_West(); break;
-    case 4: CreateInitialOWScreenView_Big_South(); break;
-    case 8: CreateInitialOWScreenView_Big_North(); break;
-    default:
-      assert(0);
-      submodule_index = 0;
-    }
-  } else {
-    switch (BYTE(overworld_screen_trans_dir_bits2)) {
-    case 1: CreateInitialOWScreenView_Small_East(); break;
-    case 2: CreateInitialOWScreenView_Small_West(); break;
-    case 4: CreateInitialOWScreenView_Small_South(); break;
-    case 8: CreateInitialOWScreenView_Small_North(); break;
-    default:
-      assert(0);
-      submodule_index = 0;
-    }
-  }
-}
-
-void CreateInitialOWScreenView_Big_North() {  // 82f06b
-  map16_load_src_off += 0x380;
-  map16_load_var2 = 31;
-  TriggerAndFinishMapLoadStripe_Y(7);
-}
-
-void CreateInitialOWScreenView_Big_South() {  // 82f087
-  uint16 pos = map16_load_src_off;
-  while (pos >= 0x80)
-    pos -= 0x80;
-  map16_load_src_off = pos + 0x780;
-  map16_load_var2 = 7;
-  TriggerAndFinishMapLoadStripe_Y(8);
-  map16_load_var2 = (map16_load_var2 + 9) & 0x1f;
-  map16_load_src_off -= 0xB80;
-}
-
-void CreateInitialOWScreenView_Big_West() {  // 82f0c0
-  map16_load_src_off += 14;
-  map16_load_dst_off = 31;
-  TriggerAndFinishMapLoadStripe_X(7);
-}
-
-void CreateInitialOWScreenView_Big_East() {  // 82f0dc
-  map16_load_src_off = map16_load_src_off - 0x60 + 0x1e;
-  map16_load_dst_off = 7;
-  TriggerAndFinishMapLoadStripe_X(8);
-  map16_load_dst_off = (map16_load_dst_off + 9) & 0x1f;
-  map16_load_src_off -= 0x2e;
-}
-
-void CreateInitialOWScreenView_Small_North() {  // 82f10f
-  orange_blue_barrier_state = map16_load_src_off - 0x700;
-  word_7EC174 = map16_load_dst_off;
-  word_7EC176 = 10;
-  map16_load_src_off = 0x1390;
-  map16_load_dst_off = 0;
-  map16_load_var2 = 31;
-  TriggerAndFinishMapLoadStripe_Y(7);
-}
-
-void CreateInitialOWScreenView_Small_South() {  // 82f141
-  orange_blue_barrier_state = BYTE(map16_load_src_off);
-  word_7EC174 = map16_load_dst_off;
-  word_7EC176 = 24;
-  map16_load_src_off = 0x790;
-  map16_load_dst_off = 0;
-  map16_load_var2 = 7;
-  TriggerAndFinishMapLoadStripe_Y(8);
-  map16_load_var2 = (map16_load_var2 + 9) & 0x1f;
-  map16_load_src_off -= 0xB80;
-}
-
-void CreateInitialOWScreenView_Small_West() {  // 82f185
-  orange_blue_barrier_state = map16_load_src_off - 0x20;
-  word_7EC174 = 8;
-  word_7EC176 = map16_load_var2;
-  map16_load_src_off = 0x44e;
-  map16_load_var2 = 0;
-  map16_load_dst_off = 31;
-  TriggerAndFinishMapLoadStripe_X(7);
-}
-
-void CreateInitialOWScreenView_Small_East() {  // 82f1b7
-  orange_blue_barrier_state = map16_load_src_off - 0x60;
-  word_7EC174 = 0x18;
-  word_7EC176 = map16_load_var2;
-  map16_load_src_off = 0x41e;
-  map16_load_var2 = 0;
-  map16_load_dst_off = 7;
-  TriggerAndFinishMapLoadStripe_X(8);
-  map16_load_dst_off = (map16_load_dst_off + 9) & 0x1f;
-  map16_load_src_off -= 0x2e;
-}
-
-void OverworldTransitionScrollAndLoadMap() {  // 82f20e
-  uint16 *dst = uvram.data;
-  switch (BYTE(overworld_screen_trans_dir_bits2)) {
-  case 1: dst = BuildFullStripeDuringTransition_East(dst); break;
-  case 2: dst = BuildFullStripeDuringTransition_West(dst); break;
-  case 4: dst = BuildFullStripeDuringTransition_South(dst); break;
-  case 8: dst = BuildFullStripeDuringTransition_North(dst); break;
-  default:
-    assert(0);
-    submodule_index = 0;
-  }
-  dst[0] = dst[1] = 0xffff;
-  if (dst != uvram.data)
-    nmi_subroutine_index = 3;
-}
-
-uint16 *BuildFullStripeDuringTransition_North(uint16 *dst) {  // 82f218
-  *dst++ = 0x80;
-  dst = BufferAndBuildMap16Stripes_Y(dst);
-  map16_load_src_off -= 0x80;
-  map16_load_var2 = (map16_load_var2 - 1) & 0x1f;
-  return dst;
-}
-
-uint16 *BuildFullStripeDuringTransition_South(uint16 *dst) {  // 82f238
-  *dst++ = 0x80;
-  dst = BufferAndBuildMap16Stripes_Y(dst);
-  map16_load_src_off += 0x80;
-  map16_load_var2 = (map16_load_var2 + 1) & 0x1f;
-  return dst;
-}
-
-uint16 *BuildFullStripeDuringTransition_West(uint16 *dst) {  // 82f241
-  *dst++ = 0x8040;
-  dst = BufferAndBuildMap16Stripes_X(dst);
-  map16_load_src_off -= 2;
-  map16_load_dst_off = (map16_load_dst_off - 1) & 0x1f;
-  return dst;
-}
-
-uint16 *BuildFullStripeDuringTransition_East(uint16 *dst) {  // 82f24a
-  *dst++ = 0x8040;
-  dst = BufferAndBuildMap16Stripes_X(dst);
-  map16_load_src_off += 2;
-  map16_load_dst_off = (map16_load_dst_off + 1) & 0x1f;
-  return dst;
-}
-
-void OverworldHandleMapScroll() {  // 82f273
-  uint16 *dst = uvram.data;
-  switch (BYTE(overworld_screen_trans_dir_bits2)) {
-  case 1:
-    dst = CheckForNewlyLoadedMapAreas_East(dst);
-    BYTE(overworld_screen_trans_dir_bits2) = 0;
-    break;
-  case 2:
-    dst = CheckForNewlyLoadedMapAreas_West(dst);
-    BYTE(overworld_screen_trans_dir_bits2) = 0;
-    break;
-  case 4:
-    dst = CheckForNewlyLoadedMapAreas_South(dst);
-    BYTE(overworld_screen_trans_dir_bits2) = 0;
-    break;
-  case 5:
-  case 6:
-    dst = CheckForNewlyLoadedMapAreas_South(dst);
-    BYTE(overworld_screen_trans_dir_bits2) &= 3;
-    break;
-  case 8:
-    dst = CheckForNewlyLoadedMapAreas_North(dst);
-    BYTE(overworld_screen_trans_dir_bits2) = 0;
-    break;
-  case 9:
-  case 10:
-    dst = CheckForNewlyLoadedMapAreas_North(dst);
-    BYTE(overworld_screen_trans_dir_bits2) &= 3;
-    break;
-  default:
-    assert(0);
-    submodule_index = 0;
-  }
-  dst[0] = dst[1] = 0xffff;
-  if (dst != uvram.data)
-    nmi_subroutine_index = 3;
-  overworld_screen_transition = overworld_screen_trans_dir_bits2;
-}
-
-uint16 *CheckForNewlyLoadedMapAreas_North(uint16 *dst) {  // 82f2dd
-  if (sign16(map16_load_src_off - 0x80))
-    return dst;
-  if (!kOverworldMapIsSmall[overworld_screen_index]) {
-    *dst++ = 0x80;
-    dst = BufferAndBuildMap16Stripes_Y(dst);
-  }
-  map16_load_src_off -= 0x80;
-  map16_load_var2 = (map16_load_var2 - 1) & 0x1f;
-  return dst;
-}
-
-uint16 *CheckForNewlyLoadedMapAreas_South(uint16 *dst) {  // 82f311
-  if (map16_load_src_off >= 0x1800)
-    return dst;
-  if (!kOverworldMapIsSmall[overworld_screen_index]) {
-    *dst++ = 0x80;
-    dst = BufferAndBuildMap16Stripes_Y(dst);
-  }
-  map16_load_src_off += 0x80;
-  map16_load_var2 = (map16_load_var2 + 1) & 0x1f;
-  return dst;
-}
-
-uint16 *CheckForNewlyLoadedMapAreas_West(uint16 *dst) {  // 82f345
-  uint16 pos = map16_load_src_off;
-  while (pos >= 0x80)
-    pos -= 0x80;
-  if (pos == 0)
-    return dst;
-  if (!kOverworldMapIsSmall[overworld_screen_index]) {
-    *dst++ = 0x8040;
-    dst = BufferAndBuildMap16Stripes_X(dst);
-  }
-  map16_load_src_off -= 2;
-  map16_load_dst_off = (map16_load_dst_off - 1) & 0x1f;
-  return dst;
-}
-
-uint16 *CheckForNewlyLoadedMapAreas_East(uint16 *dst) {  // 82f37f
-  uint16 pos = map16_load_src_off;
-  while (pos >= 0x80)
-    pos -= 0x80;
-  if (pos >= 0x60)
-    return dst;
-  if (!kOverworldMapIsSmall[overworld_screen_index]) {
-    *dst++ = 0x8040;
-    dst = BufferAndBuildMap16Stripes_X(dst);
-  }
-  map16_load_src_off += 2;
-  map16_load_dst_off = (map16_load_dst_off + 1) & 0x1f;
-  return dst;
-}
-
-uint16 *BufferAndBuildMap16Stripes_X(uint16 *dst) {  // 82f3b9
-  uint16 pos = map16_load_src_off - kOverworld_DrawStrip_Tab[overworld_screen_trans_dir_bits2 >> 1 & 1];
-  int d = map16_load_var2;
-  uint16 *tmp = dung_replacement_tile_state;
-  for (int i = 0; i < 32; i++) {
-    tmp[d] = (pos >= 0x2000) ? 0 : dung_bg2[pos >> 1];
-    d = (d + 1) & 0x1f, pos += 128;
-  }
-  const uint16 *map8 = GetMap16toMap8Table();
-  uint16 r0 = 0, of = map16_load_dst_off;
-  if (of >= 0x10)
-    of &= 0xf, r0 = 0x400;
-  r0 += of * 2;
-  for (int i = 0; i < 2; i++, r0 += 0x800) {
-    dst[0] = r0;
-    dst[33] = r0 + 1;
-    dst++;
-    for (int j = 0; j < 16; j++) {
-      int k = *tmp++;
-      assert(k < 0xea8);
-      const uint16 *s = map8 + k * 4;
-      dst[0] = s[0];
-      dst[33] = s[1];
-      dst[1] = s[2];
-      dst[34] = s[3];
-      dst += 2;
-    }
-    dst += 33;
-  }
-  return dst;
-}
-
-uint16 *BufferAndBuildMap16Stripes_Y(uint16 *dst) {  // 82f482
-  uint16 pos = map16_load_src_off - kOverworld_DrawStrip_Tab[1 + (overworld_screen_trans_dir_bits2 >> 2 & 1)];
-  int d = map16_load_dst_off;
-  uint16 *tmp = dung_replacement_tile_state;
-  for (int i = 0; i < 32; i++) {
-    tmp[d] = (pos >= 0x2000) ? 0 : dung_bg2[pos >> 1]; // fixed bug warning. can go negative
-    pos += 2;
-    d = (d + 1) & 0x1f;
-  }
-  const uint16 *map8 = GetMap16toMap8Table();
-  uint16 r0 = 0, of = map16_load_var2;
-  if (of >= 0x10)
-    of &= 0xf, r0 = 0x800;
-  r0 += of * 64;
-  for (int i = 0; i < 2; i++, r0 += 0x400) {
-    *dst++ = r0;
-    for (int j = 0; j < 16; j++) {
-      int k = *tmp++;
-      assert(k < 0xea8);
-      const uint16 *s = map8 + k * 4;
-      dst[0] = s[0];
-      dst[32] = s[2];
-      dst[1] = s[1];
-      dst[33] = s[3];
-      dst += 2;
-    }
-    dst += 32;
-  }
-  return dst;
-}
-
-void Overworld_DecompressAndDrawAllQuadrants() {  // 82f54a
-  int si = overworld_screen_index;
-  Overworld_DecompressAndDrawOneQuadrant((uint16 *)&g_ram[0x2000], si + 0);
-  Overworld_DecompressAndDrawOneQuadrant((uint16 *)&g_ram[0x2040], si + 1);
-  Overworld_DecompressAndDrawOneQuadrant((uint16 *)&g_ram[0x3000], si + 8);
-  Overworld_DecompressAndDrawOneQuadrant((uint16 *)&g_ram[0x3040], si + 9);
-}
-
-static const uint8 *GetOverworldHibytes(int i) {
-  return kOverworld_Hibytes_Comp(i).ptr;
-}
-
-static const uint8 *GetOverworldLobytes(int i) {
-  return kOverworld_Lobytes_Comp(i).ptr;
-}
-
-
-void Overworld_DecompressAndDrawOneQuadrant(uint16 *dst, int screen) {  // 82f595
-  Decompress_bank02(&g_ram[0x14400], GetOverworldHibytes(screen));
-  for (int i = 0; i < 256; i++)
-    g_ram[0x14001 + i * 2] = g_ram[0x14400 + i];
-
-  Decompress_bank02(&g_ram[0x14400], GetOverworldLobytes(screen));
-  for (int i = 0; i < 256; i++)
-    g_ram[0x14000 + i * 2] = g_ram[0x14400 + i];
-
-  map16_decode_last = 0xffff;
-
-  uint16 *src = (uint16 *)&g_ram[0x14000];
-  for (int j = 0; j < 16; j++) {
-    for (int i = 0; i < 16; i++) {
-      Overworld_ParseMap32Definition(dst, *src++ * 2);
-      dst += 2;
-    }
-    dst += 96;
-  }
-}
-
-void Overworld_ParseMap32Definition(uint16 *dst, uint16 input) {  // 82f691
-  uint16 a = input & ~7;
-  if (a != map16_decode_last) {
-    map16_decode_last = a;
-    map16_decode_tmp = a >> 1;
-    int x = (a >> 1) + (a >> 2);
-    const uint8 *ov;
-    ov = kMap32ToMap16_0 + x;
-
-    map16_decode_0[0] = ov[0];
-    map16_decode_0[2] = ov[1];
-    map16_decode_0[4] = ov[2];
-    map16_decode_0[6] = ov[3];
-    map16_decode_0[1] = ov[4] >> 4;
-    map16_decode_0[3] = ov[4] & 0xf;
-    map16_decode_0[5] = ov[5] >> 4;
-    map16_decode_0[7] = ov[5] & 0xf;
-    ov = kMap32ToMap16_1 + x;
-    map16_decode_1[0] = ov[0];
-    map16_decode_1[2] = ov[1];
-    map16_decode_1[4] = ov[2];
-    map16_decode_1[6] = ov[3];
-    map16_decode_1[1] = ov[4] >> 4;
-    map16_decode_1[3] = ov[4] & 0xf;
-    map16_decode_1[5] = ov[5] >> 4;
-    map16_decode_1[7] = ov[5] & 0xf;
-    ov = kMap32ToMap16_2 + x;
-    map16_decode_2[0] = ov[0];
-    map16_decode_2[2] = ov[1];
-    map16_decode_2[4] = ov[2];
-    map16_decode_2[6] = ov[3];
-    map16_decode_2[1] = ov[4] >> 4;
-    map16_decode_2[3] = ov[4] & 0xf;
-    map16_decode_2[5] = ov[5] >> 4;
-    map16_decode_2[7] = ov[5] & 0xf;
-    ov = kMap32ToMap16_3 + x;
-    map16_decode_3[0] = ov[0];
-    map16_decode_3[2] = ov[1];
-    map16_decode_3[4] = ov[2];
-    map16_decode_3[6] = ov[3];
-    map16_decode_3[1] = ov[4] >> 4;
-    map16_decode_3[3] = ov[4] & 0xf;
-    map16_decode_3[5] = ov[5] >> 4;
-    map16_decode_3[7] = ov[5] & 0xf;
-  }
-  dst[0] = WORD(map16_decode_0[input & 7]);
-  dst[64] = WORD(map16_decode_2[input & 7]);
-  dst[1] = WORD(map16_decode_1[input & 7]);
-  dst[65] = WORD(map16_decode_3[input & 7]);
-}
-
-void OverworldLoad_LoadSubOverlayMap32() {  // 82f7cb
-  int si = overworld_screen_index;
-  Overworld_DecompressAndDrawOneQuadrant((uint16 *)&g_ram[0x4000], si);
-}
-
-void LoadOverworldOverlay() {  // 82fd0d
-  OverworldLoad_LoadSubOverlayMap32();
-  Map16ToMap8(&g_ram[0x4000], 0x1000);
-  nmi_subroutine_index = nmi_disable_core_updates = 4;
-  submodule_index++;
-}
-
-void Map16ToMap8(const uint8 *src, int r20) {  // 82fd46
-  map16_load_src_off += 0x1000;
-  int n = 32;
-  int r14 = 0;
-  uint16 *r10 = &word_7F4000;
-  do {
-    OverworldCopyMap16ToBuffer(src, r20, r14, r10);
-    r14 += 0x100, r10 += 2;
-    map16_load_src_off -= 0x80;
-    map16_load_var2 = (map16_load_var2 - 1) & 0x1f;
-  } while (--n);
-}
-
-void OverworldCopyMap16ToBuffer(const uint8 *src, uint16 r20, int r14, uint16 *r10) {  // 82fd87
-  const uint16 *map8 = GetMap16toMap8Table();
-
-  int yr = map16_load_src_off - 0x410 & 0x1fff;
-  int xr = map16_load_dst_off;
-  uint16 *tmp = (uint16 *)(g_ram + 0x500);
-  int n = 32;
-  do {
-    WORD(tmp[xr]) = WORD(src[yr]);
-    xr = (xr + 1) & 0x1f;
-    yr = (yr + 2) & 0x1fff;
-  } while (--n);
-
-  uint16 r0 = 0, of = map16_load_var2;
-  if (of >= 0x10)
-    of &= 0xf, r0 = 0x800;
-  r0 += of * 64;
-
-  for (int i = 0; i < 2; i++, r0 += 0x400, r14 += 0x40) {
-    *r10++ = r0 | r20;
-    for (int j = 0; j < 16; j++, r14 += 4) {
-      const uint16 *m = map8 + 4 * *tmp++;
-      WORD(dung_bg2_attr_table[r14]) = WORD(m[0]);
-      WORD(dung_bg2_attr_table[r14 + 64]) = WORD(m[2]);
-      WORD(dung_bg2_attr_table[r14 + 2]) = WORD(m[1]);
-      WORD(dung_bg2_attr_table[r14 + 66]) = WORD(m[3]);
-    }
-  }
-
-}
-
-void MirrorBonk_RecoverChangedTiles() {  // 82fe47
-  for (int i = 0, i_end = num_memorized_tiles >> 1; i != i_end; i++) {
-    uint16 pos = memorized_tile_addr[i];
-    dung_bg2[pos >> 1] = memorized_tile_value[i];
-  }
-}
-
-void DecompressEnemyDamageSubclasses() {  // 82fe71
-  uint8 *tmp = &g_ram[0x14000];
-  memcpy(tmp, kEnemyDamageData, kEnemyDamageData_SIZE);
-  for (int i = 0; i < 0x1000; i += 2) {
-    uint8 t = *tmp++;
-    enemy_damage_data[i + 0] = t >> 4;
-    enemy_damage_data[i + 1] = t & 0xf;
-  }
-}
-
-int Decompress_bank02(uint8 *dst, const uint8 *src) {  // 82febb
-  uint8 *dst_org = dst;
-  int len;
-  for (;;) {
-    uint8 cmd = *src++;
-    if (cmd == 0xff)
-      return dst - dst_org;
-    if ((cmd & 0xe0) != 0xe0) {
-      len = (cmd & 0x1f) + 1;
-      cmd &= 0xe0;
-    } else {
-      len = *src++;
-      len += ((cmd & 3) << 8) + 1;
-      cmd = (cmd << 3) & 0xe0;
-    }
-    //printf("%d: %d,%d\n", (int)(dst - dst_org), cmd, len);
-    if (cmd == 0) {
-      do {
-        *dst++ = *src++;
-      } while (--len);
-    } else if (cmd & 0x80) {
-      uint32 offs = *src++ << 8;
-      offs |= *src++;
-      do {
-        *dst++ = dst_org[offs++];
-      } while (--len);
-    } else if (!(cmd & 0x40)) {
-      uint8 v = *src++;
-      do {
-        *dst++ = v;
-      } while (--len);
-    } else if (!(cmd & 0x20)) {
-      uint8 lo = *src++;
-      uint8 hi = *src++;
-      do {
-        *dst++ = lo;
-        if (--len == 0)
-          break;
-        *dst++ = hi;
-      } while (--len);
-    } else {
-      // copy bytes with the byte incrementing by 1 in between
-      uint8 v = *src++;
-      do {
-        *dst++ = v;
-      } while (v++, --len);
-    }
-  }
-}
-
-uint8 Overworld_ReadTileAttribute(uint16 x, uint16 y) {  // 85faa2
-  int t = ((x - overworld_offset_base_x) & overworld_offset_mask_x);
-  t |= ((y - overworld_offset_base_y) & overworld_offset_mask_y) << 3;
-  return kSomeTileAttr[dung_bg2[t >> 1]];
-}
-
-void Overworld_SetFixedColAndScroll() {  // 8bfe70
-  TS_copy = 0;
-  uint16 p = 0x19C6;
-  uint16 si = overworld_screen_index;
-  if (si == 0x80) {
-    if (dungeon_room_index == 0x181) {
-      TS_copy = 1;
-      p = si & 0x40 ? 0x2A32 : 0x2669;
-    }
-  } else if (si != 0x81) {
-    p = 0;
-    if (si != 0x5b && (si & 0xbf) != 3 && (si & 0xbf) != 5 && (si & 0xbf) != 7)
-      p = si & 0x40 ? 0x2A32 : 0x2669;
-  }
-  main_palette_buffer[0] = p;
-  aux_palette_buffer[0] = p;
-  main_palette_buffer[32] = p;
-  aux_palette_buffer[32] = p;
-
-  COLDATA_copy0 = 0x20;
-  COLDATA_copy1 = 0x40;
-  COLDATA_copy2 = 0x80;
-
-  uint32 cv;
-
-  if (si != 0 && si != 0x40 && si != 0x5b) {
-    if (si == 0x70)
-      goto getout;
-    cv = 0x8c4c26;
-    if (si != 3 && si != 5 && si != 7) {
-      cv = 0x874a26;
-      if (si != 0x43 && si != 0x45) {
-        flag_update_cgram_in_nmi += 1;
-        return;
-      }
-    }
-    COLDATA_copy0 = (uint8)(cv);
-    COLDATA_copy1 = (uint8)(cv >> 8);
-    COLDATA_copy2 = (uint8)(cv >> 16);
-  }
-
-  if (submodule_index != 4) {
-    BG1VOFS_copy2 = BG2VOFS_copy2;
-    BG1HOFS_copy2 = BG2HOFS_copy2;
-    if ((si & 0x3f) == 0x1b) {
-      int16 y = (int16)(BG2HOFS_copy2 - 0x778) >> 1;
-      BG1HOFS_copy2 = BG2HOFS_copy2 - y;
-      uint16 a = BG1VOFS_copy2;
-      if (a >= 0x6C0) {
-        a = (a - 0x600) & 0x3ff;
-        BG1VOFS_copy2 = (a < 0x180) ? (a >> 1) | 0x600 : 0x6c0;
-      } else {
-        BG1VOFS_copy2 = (a & 0xff) >> 1 | 0x600;
-      }
-    }
-  } else {
-    if ((si & 0x3f) == 0x1b) {
-      BG1HOFS_copy2 = (BYTE(overworld_screen_trans_dir_bits) != 8) ? 0x838 : BG2HOFS_copy2;
-      BG1VOFS_copy2 = 0x6c0;
-    }
-  }
-getout:
-  TS_copy = 1;
-  flag_update_cgram_in_nmi++;
-}
-
-void Overworld_Memorize_Map16_Change(uint16 pos, uint16 value) {  // 8edd40
-  if (value == 0xdc5 || value == 0xdc9)
-    return;
-
-  int x = num_memorized_tiles;
-  memorized_tile_value[x >> 1] = value;
-  memorized_tile_addr[x >> 1] = pos;
-  num_memorized_tiles = x + 2;
-}
-
-void HandlePegPuzzles(uint16 pos) {  // 8edd67
-  static const uint16 kLwTurtleRockPegPositions[3] = { 0x826, 0x5a0, 0x81a };
-
-  if (overworld_screen_index == 7) {
-    if (save_ow_event_info[7] & 0x20)
-      return;
-    if (word_7E04C8 != 0xffff && kLwTurtleRockPegPositions[word_7E04C8 >> 1] == pos) {
-      WORD(sound_effect_1) = 0x2d00;
-      word_7E04C8 += 2;
-      if (word_7E04C8 == 6) {
-        WORD(sound_effect_1) = 0x1b00;
-        save_ow_event_info[7] |= 0x20;
-        submodule_index = 47;
-      }
-    } else {
-      WORD(sound_effect_1) = 0x3c;
-      word_7E04C8 = 0xffff;
-    }
-  } else if (overworld_screen_index == 98) {
-    if (++word_7E04C8 == 22) {
-      save_ow_event_info[0x62] |= 0x20;
-      sound_effect_2 = 27;
-      door_open_closed_counter = 0x50;
-      big_rock_starting_address = 0xd20;
-      Overworld_DoMapUpdate32x32_B();
-    }
-  }
-  //assert(0);
-}
-
-void GanonTowerEntrance_Func1() {  // 8eddfc
-  if (!subsubmodule_index) {
-    sound_effect_1 = 0x2e;
-    Palette_AnimGetMasterSword2();
-  } else {
-    PaletteFilter_BlindingWhite();
-    if (darkening_or_lightening_screen == 255) {
-      palette_filter_countdown = 255;
-      subsubmodule_index++;
-    } else {
-      Palette_AnimGetMasterSword3();
-    }
-  }
-}
-
-void Overworld_CheckSpecialSwitchArea() {  // 8ede49
-  const uint16 *map8 = Overworld_GetMap16OfLink_Mult8();
-  int a = map8[0] & 0x1ff;
-  for (int i = 3; i >= 0; i--) {
-    if (kSpecialSwitchArea_Map8[i] == a && kSpecialSwitchArea_Screen[i] == overworld_screen_index) {
-      dungeon_room_index = kSpecialSwitchArea_Exit[i];
-      BYTE(overworld_screen_trans_dir_bits) = BYTE(overworld_screen_trans_dir_bits2) = link_direction = kSpecialSwitchArea_Direction[i];
-      WORD(byte_7E069C) = WORD(overworld_screen_transition) = DirToEnum(link_direction);
-      submodule_index = 23;
-      main_module_index = 11;
-      break;
-    }
-  }
-}
-
-const uint16 *Overworld_GetMap16OfLink_Mult8() {  // 8ede9a
-  const uint16 *map8 = GetMap16toMap8Table();
-  uint16 xc = (link_x_coord + 8) >> 3, yc = link_y_coord + 12;
-  uint16 pos = ((yc - overworld_offset_base_y) & overworld_offset_mask_y) * 8 +
-               ((xc - overworld_offset_base_x) & overworld_offset_mask_x);
-  return map8 + dung_bg2[pos >> 1] * 4;
-}
-
-void Palette_AnimGetMasterSword() {  // 8ef400
-  if (subsubmodule_index == 0) {
-    Palette_AnimGetMasterSword2();
-  } else {
-    PaletteFilter_BlindingWhite();
-    if (darkening_or_lightening_screen == 0xff) {
-      for (int i = 0; i < 8; i++)
-        main_palette_buffer[0x58 + i] = aux_palette_buffer[0x58 + i] = 0;
-      palette_filter_countdown = 0;
-      darkening_or_lightening_screen = 0;
-      submodule_index = 0;
-    } else {
-      Palette_AnimGetMasterSword3();
-    }
-  }
-}
-
-void Palette_AnimGetMasterSword2() {  // 8ef404
-  memcpy(mapbak_palette, aux_palette_buffer, 512);
-  for (int i = 0; i < 256; i++)
-    aux_palette_buffer[i] = 0x7fff;
-  main_palette_buffer[32] = main_palette_buffer[0];
-  palette_filter_countdown = 0;
-  darkening_or_lightening_screen = 2;
-  subsubmodule_index++;
-}
-
-void Palette_AnimGetMasterSword3() {  // 8ef48c
-  if (darkening_or_lightening_screen != 0 || palette_filter_countdown != 31)
-    return;
-  memcpy(aux_palette_buffer, mapbak_palette, 512);
-  TS_copy = 0;
-}
-
-void Overworld_DwDeathMountainPaletteAnimation() {  // 8ef582
-  if (trigger_special_entrance)
-    return;
-  uint8 sc = overworld_screen_index;
-  if (sc != 0x43 && sc != 0x45 && sc != 0x47)
-    return;
-  uint8 fc = frame_counter;
-  if (fc == 5 || fc == 44 || fc == 90) {
-    for (int i = 1; i < 8; i++) {
-      main_palette_buffer[0x30 + i] = aux_palette_buffer[0x30 + i];
-      main_palette_buffer[0x38 + i] = aux_palette_buffer[0x38 + i];
-      main_palette_buffer[0x48 + i] = aux_palette_buffer[0x48 + i];
-      main_palette_buffer[0x70 + i] = aux_palette_buffer[0x70 + i];
-      main_palette_buffer[0x78 + i] = aux_palette_buffer[0x78 + i];
-    }
-  } else if (fc == 3 || fc == 36 || fc == 88) {
-    if (fc == 36)
-      sound_effect_1 = 54;
-    for (int i = 1; i < 8; i++) {
-      main_palette_buffer[0x30 + i] = kDwPaletteAnim[i - 1 + 0];
-      main_palette_buffer[0x38 + i] = kDwPaletteAnim[i - 1 + 7];
-      main_palette_buffer[0x48 + i] = kDwPaletteAnim[i - 1 + 14];
-      main_palette_buffer[0x70 + i] = kDwPaletteAnim[i - 1 + 21];
-      main_palette_buffer[0x78 + i] = kDwPaletteAnim[i - 1 + 28];
-    }
-  }
-  flag_update_cgram_in_nmi++;
-  int yy = 32;
-  if (sc == 0x43 || sc == 0x45) {
-    if (save_ow_event_info[0x43] & 0x20)
-      return;
-    yy = (frame_counter & 0xc) * 2;
-  }
-  for (int i = 0; i < 8; i++)
-    main_palette_buffer[0x68 + i] = kDwPaletteAnim2[yy + i];
-}
-
-void Overworld_LoadEventOverlay() {  // 8ef652
-  int x;
-  uint16 *dst = dung_bg2;
-  switch (overworld_screen_index) {
-  case 0: case 1: case 2:
-    dst[XY(11, 16)] = 0xe32;
-    dst[XY(12, 16)] = 0xe32;
-    dst[XY(13, 16)] = 0xe32;
-    dst[XY(14, 16)] = 0xe32;
-    dst[XY(11, 17)] = 0xe32;
-    dst[XY(14, 17)] = 0xe32;
-    dst[XY(12, 17)] = 0xe33;
-    dst[XY(13, 17)] = 0xe34;
-    dst[XY(11, 18)] = 0xe35;
-    dst[XY(12, 18)] = 0xe36;
-    dst[XY(13, 18)] = 0xe37;
-    dst[XY(14, 18)] = 0xe38;
-    dst[XY(11, 19)] = 0xe39;
-    dst[XY(12, 19)] = 0xe3a;
-    dst[XY(13, 19)] = 0xe3b;
-    dst[XY(14, 19)] = 0xe3c;
-    dst[XY(12, 20)] = 0xe3d;
-    dst[XY(13, 20)] = 0xe3e;
-    break;
-  case 3: case 4: case 5: case 6: case 7:
-    dst[XY(16, 14)] = 0x212;
-    break;
-  case 8: case 9: case 10: case 11: case 12: case 13: case 14: case 15: case 16: case 17: case 18: case 19:
-    x = XY(3, 10);
-loc_8EF7B4:
-    dst[x + XY(0, 0)] = 0x918;
-    dst[x + XY(1, 0)] = 0x919;
-    dst[x + XY(0, 1)] = 0x91a;
-    dst[x + XY(1, 1)] = 0x91b;
-    break;
-  case 20:
-    dst[XY(25, 10)] = 0xdd1;
-    dst[XY(26, 10)] = 0xdd2;
-    dst[XY(25, 11)] = 0xdd7;
-    dst[XY(26, 11)] = 0xdd8;
-    dst[XY(25, 12)] = 0xdd9;
-    dst[XY(26, 12)] = 0xdda;
-    break;
-  case 21: case 22: case 23: case 24: case 25: case 32: case 33:
-    dst[XY(31, 24)] = 0xe21;
-    dst[XY(33, 24)] = 0xe21;
-    dst[XY(32, 24)] = 0xe22;
-    dst[XY(31, 25)] = 0xe23;
-    dst[XY(32, 25)] = 0xe24;
-    dst[XY(33, 25)] = 0xe25;
-    break;
-  case 26: case 27: case 28: case 35: case 36:
-    dst[XY(30, 39)] = 0xdc1;
-    dst[XY(31, 39)] = 0xdc2;
-    dst[XY(30, 40)] = 0xdbe;
-    dst[XY(31, 40)] = 0xdbf;
-    dst[XY(32, 39)] = 0xdc2;
-    dst[XY(33, 39)] = 0xdc3;
-    dst[XY(32, 40)] = 0xdbf;
-    dst[XY(33, 40)] = 0xdc0;
-    break;
-  case 29: case 30: case 31: case 34: case 37: case 38: case 39: case 40: case 41: case 42: case 43: case 107:
-    x = XY(24, 6);
-    goto loc_8EF7B4;
-  case 44: case 45: case 46: case 47: case 48: case 49: case 56: case 57:
-    x = XY(44, 6);
-    goto loc_8EF7B4;
-  case 50: case 51: case 52: case 53: case 54: case 55: case 119:
-    x = XY(6, 8);
-    goto loc_8EF7B4;
-  case 58:
-    x = XY(15, 20);
-    goto loc_8EF7B4;
-  case 59: case 123:
-    dst[XY(22, 7)] = 0xddf;
-    dst[XY(18, 8)] = 0xddf;
-    dst[XY(16, 9)] = 0xddf;
-    dst[XY(15, 10)] = 0xddf;
-    dst[XY(14, 12)] = 0xddf;
-    dst[XY(26, 14)] = 0xddf;
-    dst[XY(23, 7)] = 0xde0;
-    dst[XY(17, 9)] = 0xde0;
-    dst[XY(24, 7)] = 0xde1;
-    dst[XY(28, 8)] = 0xde1;
-    dst[XY(29, 9)] = 0xde1;
-    dst[XY(21, 11)] = 0xde1;
-    dst[XY(29, 14)] = 0xde1;
-    dst[XY(19, 8)] = 0xde2;
-    dst[XY(20, 8)] = 0xde2;
-    dst[XY(21, 8)] = 0xde2;
-    dst[XY(25, 8)] = 0xde2;
-    dst[XY(26, 8)] = 0xde2;
-    dst[XY(27, 8)] = 0xde2;
-    dst[XY(22, 8)] = 0xde3;
-    dst[XY(18, 9)] = 0xde3;
-    dst[XY(16, 10)] = 0xde3;
-    dst[XY(15, 12)] = 0xde3;
-    dst[XY(23, 8)] = 0xde4;
-    dst[XY(19, 9)] = 0xde4;
-    dst[XY(20, 9)] = 0xde4;
-    dst[XY(24, 9)] = 0xde4;
-    dst[XY(27, 9)] = 0xde4;
-    dst[XY(17, 10)] = 0xde4;
-    dst[XY(18, 10)] = 0xde4;
-    dst[XY(19, 10)] = 0xde4;
-    dst[XY(28, 10)] = 0xde4;
-    dst[XY(16, 11)] = 0xde4;
-    dst[XY(17, 11)] = 0xde4;
-    dst[XY(18, 11)] = 0xde4;
-    dst[XY(19, 11)] = 0xde4;
-    dst[XY(16, 12)] = 0xde4;
-    dst[XY(17, 12)] = 0xde4;
-    dst[XY(15, 13)] = 0xde4;
-    dst[XY(16, 13)] = 0xde4;
-    dst[XY(15, 14)] = 0xde4;
-    dst[XY(16, 14)] = 0xde4;
-    dst[XY(19, 16)] = 0xde4;
-    dst[XY(19, 17)] = 0xde4;
-    dst[XY(20, 17)] = 0xde4;
-    dst[XY(19, 18)] = 0xde4;
-    dst[XY(24, 8)] = 0xde5;
-    dst[XY(28, 9)] = 0xde5;
-    dst[XY(20, 11)] = 0xde5;
-    dst[XY(21, 12)] = 0xde5;
-    dst[XY(21, 9)] = 0xde6;
-    dst[XY(25, 9)] = 0xde6;
-    dst[XY(20, 10)] = 0xde6;
-    dst[XY(28, 11)] = 0xde6;
-    dst[XY(21, 17)] = 0xde6;
-    dst[XY(20, 18)] = 0xde6;
-    dst[XY(22, 9)] = 0xde7;
-    dst[XY(24, 10)] = 0xde7;
-    dst[XY(15, 15)] = 0xde7;
-    dst[XY(16, 15)] = 0xde7;
-    dst[XY(19, 19)] = 0xde7;
-    dst[XY(28, 19)] = 0xde7;
-    dst[XY(23, 9)] = 0xde8;
-    dst[XY(26, 9)] = 0xde8;
-    dst[XY(27, 10)] = 0xde8;
-    dst[XY(17, 15)] = 0xde8;
-    dst[XY(18, 16)] = 0xde8;
-    dst[XY(23, 10)] = 0xde9;
-    dst[XY(26, 10)] = 0xde9;
-    dst[XY(14, 15)] = 0xde9;
-    dst[XY(17, 16)] = 0xde9;
-    dst[XY(26, 18)] = 0xde9;
-    dst[XY(27, 19)] = 0xde9;
-    dst[XY(29, 10)] = 0xdea;
-    dst[XY(28, 12)] = 0xdea;
-    dst[XY(28, 13)] = 0xdea;
-    dst[XY(29, 18)] = 0xdea;
-    dst[XY(15, 11)] = 0xdeb;
-    dst[XY(27, 11)] = 0xdeb;
-    dst[XY(27, 12)] = 0xdeb;
-    dst[XY(14, 13)] = 0xdeb;
-    dst[XY(27, 13)] = 0xdeb;
-    dst[XY(14, 14)] = 0xdeb;
-    dst[XY(18, 17)] = 0xdeb;
-    dst[XY(18, 18)] = 0xdeb;
-    dst[XY(18, 12)] = 0xdec;
-    dst[XY(17, 13)] = 0xdec;
-    dst[XY(19, 12)] = 0xded;
-    dst[XY(20, 12)] = 0xdee;
-    dst[XY(18, 13)] = 0xdef;
-    dst[XY(27, 15)] = 0xdef;
-    dst[XY(19, 13)] = 0xdf0;
-    dst[XY(19, 14)] = 0xdf0;
-    dst[XY(20, 14)] = 0xdf0;
-    dst[XY(21, 14)] = 0xdf0;
-    dst[XY(21, 15)] = 0xdf0;
-    dst[XY(27, 16)] = 0xdf0;
-    dst[XY(28, 16)] = 0xdf0;
-    dst[XY(20, 13)] = 0xdf1;
-    dst[XY(28, 15)] = 0xdf1;
-    dst[XY(21, 13)] = 0xdf2;
-    dst[XY(17, 14)] = 0xdf3;
-    dst[XY(18, 15)] = 0xdf3;
-    dst[XY(20, 16)] = 0xdf3;
-    dst[XY(18, 14)] = 0xdf4;
-    dst[XY(19, 15)] = 0xdf5;
-    dst[XY(20, 15)] = 0xdf6;
-    dst[XY(27, 17)] = 0xdf6;
-    dst[XY(26, 15)] = 0xdf7;
-    dst[XY(29, 15)] = 0xdf8;
-    dst[XY(21, 16)] = 0xdf9;
-    dst[XY(26, 16)] = 0xdfa;
-    dst[XY(29, 16)] = 0xdfb;
-    dst[XY(26, 17)] = 0xdfc;
-    dst[XY(28, 17)] = 0xdfd;
-    dst[XY(29, 17)] = 0xdfe;
-    dst[XY(27, 18)] = 0xdff;
-    dst[XY(28, 18)] = 0xe00;
-    dst[XY(21, 10)] = 0xe01;
-    dst[XY(25, 10)] = 0xe01;
-    dst[XY(21, 18)] = 0xe01;
-    dst[XY(29, 11)] = 0xe02;
-    dst[XY(20, 19)] = 0xe02;
-    dst[XY(29, 19)] = 0xe02;
-    dst[XY(18, 19)] = 0xe03;
-    dst[XY(27, 14)] = 0xe04;
-    dst[XY(28, 14)] = 0xe05;
-    break;
-  case 60: case 61: case 62: case 63: case 64: case 65: case 72: case 73:
-    dst[XY(8, 11)] = 0xe13;
-    dst[XY(11, 11)] = 0xe14;
-    dst[XY(8, 12)] = 0xe15;
-    dst[XY(9, 12)] = 0xe16;
-    dst[XY(10, 12)] = 0xe17;
-    dst[XY(11, 12)] = 0xe18;
-    dst[XY(9, 13)] = 0xe19;
-    dst[XY(10, 13)] = 0xe1a;
-    dst[XY(9, 16)] = 0xe06;
-    dst[XY(10, 16)] = 0xe06;
-    dst[XY(8, 14)] = 0xe07;
-    dst[XY(8, 15)] = 0xe07;
-    dst[XY(9, 14)] = 0xe08;
-    dst[XY(9, 15)] = 0xe08;
-    dst[XY(10, 14)] = 0xe09;
-    dst[XY(10, 15)] = 0xe09;
-    dst[XY(11, 14)] = 0xe0a;
-    dst[XY(11, 15)] = 0xe0a;
-    break;
-  case 66: case 67: case 68: case 75: case 76:
-    dst[XY(47, 8)] = 0xe96;
-    dst[XY(48, 8)] = 0xe97;
-    dst[XY(47, 9)] = 0xe9c;
-    dst[XY(47, 10)] = 0xe9c;
-    dst[XY(48, 9)] = 0xe9d;
-    dst[XY(48, 10)] = 0xe9d;
-    dst[XY(47, 11)] = 0xe9a;
-    dst[XY(48, 11)] = 0xe9b;
-    break;
-  case 69: case 70: case 77: case 78:
-    x = XY(52, 16);
-    goto loc_8EF7B4;
-  case 71:
-    dst[XY(15, 19)] = 0xe78;
-    dst[XY(16, 19)] = 0xe79;
-    dst[XY(17, 19)] = 0xe7a;
-    dst[XY(18, 19)] = 0xe7b;
-    dst[XY(15, 20)] = 0xe7c;
-    dst[XY(16, 20)] = 0xe7d;
-    dst[XY(17, 20)] = 0xe7e;
-    dst[XY(18, 20)] = 0xe7f;
-    dst[XY(15, 21)] = 0xe80;
-    dst[XY(16, 21)] = 0xe81;
-    dst[XY(17, 21)] = 0xe82;
-    dst[XY(18, 21)] = 0xe83;
-    dst[XY(15, 22)] = 0xe84;
-    dst[XY(16, 22)] = 0xe85;
-    dst[XY(17, 22)] = 0xe86;
-    dst[XY(18, 22)] = 0xe87;
-    break;
-  case 74: case 79: case 80: case 81: case 82: case 83: case 84: case 85: case 86: case 87: case 88: case 89: case 96: case 97:
-    dst[XY(31, 26)] = 0xe1b;
-    dst[XY(32, 26)] = 0xe1c;
-    dst[XY(31, 27)] = 0xe1d;
-    dst[XY(32, 27)] = 0xe1e;
-    dst[XY(31, 28)] = 0xe1f;
-    dst[XY(32, 28)] = 0xe20;
-    break;
-  case 90: case 91: case 92: case 99: case 100:
-    dst[XY(30, 7)] = 0xe3f;
-    dst[XY(31, 7)] = 0xe40;
-    dst[XY(32, 7)] = 0xe41;
-    dst[XY(30, 8)] = 0xe42;
-    dst[XY(31, 8)] = 0xe43;
-    dst[XY(32, 8)] = 0xe44;
-    dst[XY(30, 9)] = 0xe45;
-    dst[XY(31, 9)] = 0xe46;
-    dst[XY(32, 9)] = 0xe47;
-    break;
-  case 93: case 94: case 95: case 102: case 103:
-    dst[XY(51, 3)] = 0xe31;
-    dst[XY(53, 4)] = 0xe2d;
-    dst[XY(53, 5)] = 0xe2e;
-    dst[XY(53, 6)] = 0xe2f;
-    break;
-  case 98:
-    x = XY(16, 26);
-    goto loc_8EF7B4;
-  case 101: case 104: case 105: case 106: case 108: case 109: case 110: case 111: case 112: case 113: case 120: case 121:
-    dst[XY(17, 10)] = 0xe64;
-    dst[XY(18, 10)] = 0xe65;
-    dst[XY(19, 10)] = 0xe66;
-    dst[XY(20, 10)] = 0xe67;
-    dst[XY(17, 11)] = 0xe68;
-    dst[XY(18, 11)] = 0xe69;
-    dst[XY(19, 11)] = 0xe6a;
-    dst[XY(20, 11)] = 0xe6b;
-    dst[XY(17, 12)] = 0xe6c;
-    dst[XY(18, 12)] = 0xe6d;
-    dst[XY(19, 12)] = 0xe6e;
-    dst[XY(20, 12)] = 0xe6f;
-    dst[XY(17, 13)] = 0xe70;
-    dst[XY(18, 13)] = 0xe71;
-    dst[XY(19, 13)] = 0xe72;
-    dst[XY(20, 13)] = 0xe73;
-    dst[XY(17, 14)] = 0xe74;
-    dst[XY(18, 14)] = 0xe75;
-    dst[XY(19, 14)] = 0xe76;
-    dst[XY(20, 14)] = 0xe77;
-    break;
-  case 114: case 115: case 116: case 117: case 118: case 122: case 124: case 125: case 126: case 127:
-    assert(0);
-  }
-}
-
-void Ancilla_TerminateWaterfallSplashes() {  // 8ffd3c
-  uint8 t = BYTE(overworld_screen_index);
-  if (t == 0xf) {
-    for (int i = 4; i >= 0; i--) {
-      if (ancilla_type[i] == 0x41)
-        ancilla_type[i] = 0;
-    }
-  }
-}
-
-void Overworld_GetPitDestination() {  // 9bb860
-  uint16 x = (link_x_coord & ~7);
-  uint16 y = (link_y_coord & ~7);
-  uint16 pos = ((y - overworld_offset_base_y) & overworld_offset_mask_y) << 3;
-  pos += (((x >> 3) - overworld_offset_base_x) & overworld_offset_mask_x);
-
-
-  int i = 36 / 2;
-  for (;;) {
-    if (kFallHole_Pos[i] == pos && kFallHole_Area[i] == overworld_area_index)
-      break;
-    if (--i < 0) {
-      savegame_is_darkworld = 0;
-      // Chris Houlihan's room
-      which_entrance = 130;
-      byte_7E010F = 0;
-      return;
-    }
-  }
-  which_entrance = kFallHole_Entrances[i];
-  byte_7E010F = 0;
-}
-
-void Overworld_UseEntrance() {  // 9bbbf4
-  uint16 xc = link_x_coord >> 3, yc = link_y_coord + 7;
-  uint16 pos = ((yc - overworld_offset_base_y) & overworld_offset_mask_y) * 8 +
-    ((xc - overworld_offset_base_x) & overworld_offset_mask_x);
-
-  int x = dung_bg2[pos >> 1] * 4;
-  const uint16 *map8p = GetMap16toMap8Table();
-
-  if (!link_direction_facing) {
-    uint16 a = map8p[x + 1] & 0x41ff;
-    if (a == 0xe9)
-      goto do_draw;
-
-    if (a == 0x149 || a == 0x169)
-      goto is_149_or_169;
-
-    x = dung_bg2[(pos >> 1) + 1] * 4;
-    a = map8p[x] & 0x41ff;
-    if (a == 0x40e9) {
-      pos -= 2;
-do_draw:
-      Overworld_DrawMap16_Persist(pos + 0, 0xDA4);
-      Overworld_DrawMap16_Persist(pos + 2, 0xDA6);
-      sound_effect_2 = 21;
-      nmi_load_bg_from_vram = 1;
-      return;
-    }
-    if (a == 0x4149 || a == 0x4169) {
-      pos -= 2;
-is_149_or_169:
-      door_open_closed_counter = 0;
-      if (a & 0x20) {
-        // 0x169
-        if ((sram_progress_indicator & 0xf) >= 3)
-          goto after;
-        door_open_closed_counter = 24;
-      }
-      big_rock_starting_address = pos - 0x80;
-      sound_effect_2 = 21;
-      subsubmodule_index = 0;
-      BYTE(door_animation_step_indicator) = 0;
-      submodule_index = 12;
-      return;
-    }
-  }
-after:
-  if (!LookupInOwEntranceTab(map8p[x + 2] & 0x1ff, map8p[x + 3] & 0x1ff)) {
-    big_key_door_message_triggered = 0;
-    return;
-  }
-
-  int lx = LookupInOwEntranceTab2(pos);
-  if (lx < 0)
-    return;
-
-  if (!follower_dropped && (link_pose_for_item == 1 || !CanEnterWithTagalong(kOverworld_Entrance_Id[lx] - 1))) {
-    if (!big_key_door_message_triggered) {
-      big_key_door_message_triggered = 1;
-      dialogue_message_index = 5;
-      Main_ShowTextMessage();
-    }
-  } else {
-    which_entrance = kOverworld_Entrance_Id[lx];
-    link_auxiliary_state = 0;
-    link_incapacitated_timer = 0;
-    main_module_index = 15;
-    saved_module_for_menu = 6;
-    submodule_index = 0;
-    subsubmodule_index = 0;
-  }
-}
-
-uint16 Overworld_ToolAndTileInteraction(uint16 x, uint16 y) {  // 9bbd82
-  word_7E04B2 = 0;
-  index_of_interacting_tile = 0;
-  uint16 pos = ((y - overworld_offset_base_y) & overworld_offset_mask_y) * 8 +
-    ((x - overworld_offset_base_x) & overworld_offset_mask_x);
-  uint16 attr = overworld_tileattr[pos >> 1], yv;
-
-  if (!(link_item_in_hand & 2)) {
-    if (!(link_item_in_hand & 0x40)) {
-      if (attr == 0x34 || attr == 0x71 || attr == 0x35 || attr == 0x10d ||
-          attr == 0x10f || attr == 0xe1 || attr == 0xe2 || attr == 0xda ||
-          attr == 0xf8 || attr == 0x10e) {  // shovelable
-        if (link_position_mode != 1)
-          return attr;
-        if (overworld_screen_index == 0x2a && pos == 0x492)
-          word_7E04B2 = pos;
-        yv = 0xdc9;
-        goto check_secret;
-      } else if (attr == 0x37e) {  // isThickGrass
-        if (link_position_mode == 1)
-          return attr;
-        scratch_0 = x * 8 - 8;
-        scratch_1 = (y - 8) & ~7;
-        index_of_interacting_tile = 3;
-        yv = 0xdc5;
-        goto check_secret;
-      }
-    }
-    if ((yv = 2, attr == 0x36) || (yv = 4, attr == 0x72a)) {
-      // is_bush
-      if (link_position_mode != 1) {
-        scratch_0 = (x & ~1) * 8;
-        scratch_1 = y & ~0xf;
-        index_of_interacting_tile = yv;
-        yv = (attr == 0x72a) ? 0xdc8 : 0xdc7;
-        uint32 result;
-check_secret:
-        result = Overworld_RevealSecret(pos);
-        if (result != 0)
-          yv = result;
-memoize_getout:
-        overworld_tileattr[pos >> 1] = yv;
-        Overworld_Memorize_Map16_Change(pos, yv);
-        Overworld_DrawMap16(pos, yv);
-        nmi_load_bg_from_vram = 1;
-      }
-      uint16 t;
-      t = GetMap16toMap8Table()[attr * 4 + ((y & 8) >> 2) + (x & 1)];
-      attr = kMap8DataToTileAttr[t & 0x1ff];
-      if (index_of_interacting_tile) {
-        Sprite_SpawnImmediatelySmashedTerrain(index_of_interacting_tile, scratch_0, scratch_1);
-        AncillaAdd_BushPoof(scratch_0, scratch_1);
-      }
-      return attr;
-    }
-    return attr;
-  } else {  // else_1
-    if (attr == 0x21b) {
-      sound_effect_1 = 17;
-      HandlePegPuzzles(pos);
-      yv = 0xdcb;
-      goto memoize_getout;
-    } else { // else_3
-      Overworld_PickHammerSfx(attr);
-      return attr;
-    }
-  }
-
-  return 0;
-}
-
-void Overworld_PickHammerSfx(uint16 a) {  // 9bbf1e
-  uint16 attr = kMap8DataToTileAttr[GetMap16toMap8Table()[a * 4] & 0x1ff];
-  uint8 y;
-  if (attr < 0x50) {
-    return;
-  } else if (attr < 0x52) {
-    y = 26;
-  } else if (attr < 0x54) {
-    y = 17;
-  } else if (attr < 0x58) {
-    y = 5;
-  } else {
-    return;
-  }
-  sound_effect_1 = y;
-}
-
-uint16 Overworld_GetLinkMap16Coords(Point16U *xy) {  // 9bbf64
-  uint16 x = (link_x_coord + kGetBestActionToPerformOnTile_x[link_direction_facing >> 1]) & ~0xf;
-  uint16 y = (link_y_coord + kGetBestActionToPerformOnTile_y[link_direction_facing >> 1]) & ~0xf;
-  xy->x = x;
-  xy->y = y;
-  uint16 rv = ((y - overworld_offset_base_y) & overworld_offset_mask_y) << 3;
-  return rv + (((x >> 3) - overworld_offset_base_x) & overworld_offset_mask_x);
-}
-
-uint8 Overworld_HandleLiftableTiles(Point16U *pt_arg) {  // 9bbf9d
-  uint16 pos = Overworld_GetLinkMap16Coords(pt_arg);
-  Point16U pt = *pt_arg;
-  uint16 a = overworld_tileattr[pos >> 1], y;
-  if ((y = 0, a == 0x36d) || (y = 1, a == 0x36e) || (y = 2, a == 0x374) || (y = 3, a == 0x375) ||
-      (y = 0, a == 0x23b) || (y = 1, a == 0x23c) || (y = 2, a == 0x23d) || (y = 3, a == 0x23e)) {
-    return SmashRockPile_fromLift(a, pos, y, pt);
-  } else if ((y = 0xdc7, a == 0x36) || (y = 0xdc8, a == 0x72a) || (y = 0xdca, a == 0x20f) || (y = 0xdca, a == 0x239) || (y = 0xdc6, a == 0x101)) {
-    return Overworld_LiftingSmallObj(a, pos, y, pt);
-  } else {
-    uint16 t = a * 4 + (pt.x & 8 ? 2 : 0) + (pt.y & 8 ? 1 : 0);
-    return kMap8DataToTileAttr[GetMap16toMap8Table()[t] & 0x1ff];
-  }
-}
-
-uint8 Overworld_LiftingSmallObj(uint16 a, uint16 pos, uint16 y, Point16U pt) {  // 9bc008
-  uint16 secret = Overworld_RevealSecret(pos);
-  if (secret != 0)
-    y = secret;
-  overworld_tileattr[pos >> 1] = y;
-  Overworld_Memorize_Map16_Change(pos, y);
-  Overworld_DrawMap16(pos, y);
-  nmi_load_bg_from_vram = 1;
-  uint16 t = a * 4 + (pt.x & 8 ? 2 : 0) + (pt.y & 8 ? 1 : 0);
-  return kMap8DataToTileAttr[GetMap16toMap8Table()[t] & 0x1ff];
-}
-
-int Overworld_SmashRockPile(bool down_one_tile, Point16U *pt) {  // 9bc055
-  uint16 bak = link_y_coord;
-  link_y_coord += down_one_tile ? 8 : 0;
-  uint16 pos = Overworld_GetLinkMap16Coords(pt);
-  link_y_coord = bak;
-  uint16 a = dung_bg2[pos >> 1];
-  uint8 y = 0;
-  if ((y = 0, a == 0x226) || (y = 1, a == 0x227) || (y = 2, a == 0x228) || (y = 3, a == 0x229)) {
-    return SmashRockPile_fromLift(a, pos, y, *pt);
-  } else if (a == 0x36) {
-    return Overworld_LiftingSmallObj(a, pos, 0xDC7, *pt);
-  } else {
-    return -1;
-  }
-}
-
-uint8 SmashRockPile_fromLift(uint16 a, uint16 pos, uint16 y, Point16U pt) {  // 9bc09f
-  static const int8 kBigRockTab1[] = { 0, -1, -64, -65 };
-  static const int8 kBigRockTabY[] = { 0, 0, -64, -64 };
-  static const int8 kBigRockTabX[] = { 0, -1, 0, -1 };
-  pos = 2 * ((pos >> 1) + kBigRockTab1[y]);
-  big_rock_starting_address = pos;
-  door_open_closed_counter = 40;
-
-  *(uint16 *)&g_ram[0] = pt.y;
-  *(uint16 *)&g_ram[2] = pt.x;
-
-  uint16 secret = Overworld_RevealSecret(pos);
-  pt.y = *(uint16 *)&g_ram[0];
-  pt.x = *(uint16 *)&g_ram[2];
-
-  if (secret == 0xffff) {
-    save_ow_event_info[overworld_screen_index] |= 0x20;
-    sound_effect_2 = 27;
-    door_open_closed_counter = 80;
-  }
-  pt.x += kBigRockTabX[y] * 2;
-  pt.y += kBigRockTabY[y] * 2;
-
-  Overworld_DoMapUpdate32x32_B(); // WARNING: The original destroys ram[0] and ram[2]
-
-  uint16 t = a * 4 + (pt.x & 8 ? 2 : 0) + (pt.y & 8 ? 1 : 0);
-  return kMap8DataToTileAttr[GetMap16toMap8Table()[t] & 0x1ff];
-}
-
-void Overworld_BombTiles32x32(uint16 x, uint16 y) {  // 9bc0f8
-  x = (x - 23) & ~7;
-  y = (y - 20) & ~7;
-
-  for (int yy = 3; yy != 0; yy--, y += 16) {
-    for (int xx = 3, xt = x; xx != 0; xx--, xt += 16) {
-      Overworld_BombTile(xt, y);
-    }
-  }
-  word_7E0486 = x, word_7E0488 = y;
-}
-
-void Overworld_BombTile(int x, int y) {  // 9bc155
-  int a, j, k;
-
-  int pos = ((y - overworld_offset_base_y & overworld_offset_mask_y) << 3) +
-    ((x >> 3) - overworld_offset_base_x & overworld_offset_mask_x);
-
-  if (follower_indicator == 13)
-    goto label_a;
-
-  a = dung_bg2[pos >> 1];
-
-  if (a == 0x36) {
-    k = 2, j = 0xdc7;
-  } else if (a == 0x72a) {
-    k = 4, j = 0xdc8;
-  } else if (a == 0x37e) {
-    k = 3, j = 0xdc5;
-  } else {
-    goto label_a;
-  }
-  a = Overworld_RevealSecret(pos);
-  if (a == 0)
-    a = j;
-  dung_bg2[pos >> 1] = a;
-  Overworld_Memorize_Map16_Change(pos, a);
-  Overworld_DrawMap16(pos, a);
-
-  Sprite_SpawnImmediatelySmashedTerrain(k, x & ~7, y & ~7);
-  nmi_load_bg_from_vram = 1;
-  return;
-
-label_a:
-  a = Overworld_RevealSecret(pos);
-  if (a == 0xdb4) {
-    dung_bg2[pos >> 1] = a;
-    Overworld_Memorize_Map16_Change(pos, a);
-    Overworld_DrawMap16(pos, a);
-
-    dung_bg2[(pos >> 1) + 1] = 0xDB5;
-    Overworld_Memorize_Map16_Change(pos, 0xDB5);  // wtf
-    Overworld_DrawMap16(pos + 2, 0xDB5);
-    nmi_load_bg_from_vram = 1;
-    save_ow_event_info[overworld_screen_index] |= 2;
-  }
-}
-
-void Overworld_AlterWeathervane() {  // 9bc21d
-  door_open_closed_counter = 0x68;
-  big_rock_starting_address = 0xc3e;
-  Overworld_DoMapUpdate32x32_B();
-  Overworld_DrawMap16_Persist(0xc42, 0xe21);
-  Overworld_DrawMap16_Persist(0xcc2, 0xe25);
-
-  save_ow_event_info[0x18] |= 0x20;
-  nmi_load_bg_from_vram = 1;
-}
-
-void OpenGargoylesDomain() {  // 9bc264
-  Overworld_DrawMap16_Persist(0xd3e, 0xe1b);
-  Overworld_DrawMap16_Persist(0xd40, 0xe1c);
-  Overworld_DrawMap16_Persist(0xdbe, 0xe1d);
-  Overworld_DrawMap16_Persist(0xdc0, 0xe1e);
-  Overworld_DrawMap16_Persist(0xe3e, 0xe1f);
-  Overworld_DrawMap16_Persist(0xe40, 0xe20);
-  save_ow_event_info[0x58] |= 0x20;
-  sound_effect_2 = 0x1b;
-  nmi_load_bg_from_vram = 1;
-}
-
-void CreatePyramidHole() {  // 9bc2a7
-  Overworld_DrawMap16_Persist(0x3bc, 0xe3f);
-  Overworld_DrawMap16_Persist(0x3be, 0xe40);
-  Overworld_DrawMap16_Persist(0x3c0, 0xe41);
-  Overworld_DrawMap16_Persist(0x43c, 0xe42);
-  Overworld_DrawMap16_Persist(0x43e, 0xe43);
-  Overworld_DrawMap16_Persist(0x440, 0xe44);
-  Overworld_DrawMap16_Persist(0x4bc, 0xe45);
-  Overworld_DrawMap16_Persist(0x4be, 0xe46);
-  Overworld_DrawMap16_Persist(0x4c0, 0xe47);
-  WORD(sound_effect_ambient) = 0x3515;
-  save_ow_event_info[0x5b] |= 0x20;
-  sound_effect_2 = 3;
-  nmi_load_bg_from_vram = 1;
-}
-
-// Strange return value in Carry/R14
-uint16 Overworld_RevealSecret(uint16 pos) {  // 9bc8a4
-  BYTE(dung_secrets_unk1) = 0;
-
-  if (overworld_screen_index >= 0x80) {
-fail:
-    AdjustSecretForPowder();
-    return 0;
-  }
-
-  const uint8 *ptr = kOverworldSecrets + kOverworldSecrets_Offs[overworld_screen_index];
-  for (;;) {
-    uint16 x = *(uint16 *)ptr;
-    if (x == 0xffff)
-      goto fail;
-    if ((x & 0x7fff) == pos)
-      break;
-    ptr += 3;
-  }
-  uint8 data = ptr[2];
-  if (data && data < 0x80)
-    BYTE(dung_secrets_unk1) |= data;
-  if (data < 0x80) {
-    AdjustSecretForPowder();
-    return 0; // carry set
-  }
-
-  BYTE(dung_secrets_unk1) = 0xff;
-  if (data != 0x84 && !(save_ow_event_info[overworld_screen_index] & 2)) {
-    if (overworld_screen_index == 0x5b && follower_indicator != 13)
-      goto fail;
-    sound_effect_2 = 0x1b;
-  // The discovery chime is missing when lifting the rock covering the magic portal leading to the Ice Temple
-  } else if (data == 0x82 && (enhanced_features0 & kFeatures0_MiscBugFixes)) {
-    sound_effect_2 = 0x1b;
-  }
-  static const uint16 kTileBelow[4] = { 0xDCC, 0x212, 0xFFFF, 0xDB4 };
-  AdjustSecretForPowder();
-  return kTileBelow[(data & 0xf) >> 1];
-
-}
-
-void AdjustSecretForPowder() {  // 9bc943
-  if (link_item_in_hand & 0x40)
-    dung_secrets_unk1 = 4;
-}
-
-void Overworld_DrawMap16_Persist(uint16 pos, uint16 value) {  // 9bc97c
-  dung_bg2[pos >> 1] = value;
-  Overworld_DrawMap16(pos, value);
-}
-
-void Overworld_DrawMap16(uint16 pos, uint16 value) {  // 9bc980
-  pos = Overworld_FindMap16VRAMAddress(pos);
-  uint16 *dst = &vram_upload_data[vram_upload_offset >> 1];
-  const uint16 *src = GetMap16toMap8Table() + value * 4;
-  dst[0] = swap16(pos);
-  dst[1] = 0x300;
-  dst[2] = src[0];
-  dst[3] = src[1];
-  dst[4] = swap16(pos + 0x20);
-  dst[5] = 0x300;
-  dst[6] = src[2];
-  dst[7] = src[3];
-  dst[8] = 0xffff;
-  vram_upload_offset += 16;
-}
-
-void Overworld_AlterTileHardcore(uint16 pos, uint16 value) {  // 9bc9de
-  dung_bg2[pos >> 1] = value;
-  pos = Overworld_FindMap16VRAMAddress(pos);
-  uint16 *dst = &vram_upload_data[vram_upload_offset >> 1];
-  const uint16 *src = GetMap16toMap8Table() + value * 4;
-  dst[0] = swap16(pos);
-  dst[1] = 0x300;
-  dst[2] = src[0];
-  dst[3] = src[1];
-  dst[4] = swap16(pos + 0x20);
-  dst[5] = 0x300;
-  dst[6] = src[2];
-  dst[7] = src[3];
-  dst[8] = 0xffff;
-  vram_upload_offset += 16;
-}
-
-uint16 Overworld_FindMap16VRAMAddress(uint16 addr) {  // 9bca69
-  return (((addr & 0x3f) >= 0x20) ? 0x400 : 0) + (((addr & 0xfff) >= 0x800) ? 0x800 : 0) + (addr & 0x1f) + ((addr & 0x780) >> 1);
-}
-
-void Overworld_AnimateEntrance() {  // 9bcac4
-  uint8 j = trigger_special_entrance;
-  flag_is_link_immobilized = j;
-  flag_unk1 = j;
-  nmi_disable_core_updates = j;
-  kOverworld_EntranceSequence[j - 1]();
-}
-
-void Overworld_AnimateEntrance_PoD() {  // 9bcade
-  switch (subsubmodule_index) {
-  case 0:
-    if (++overworld_entrance_sequence_counter != 0x40)
-      return;
-    OverworldEntrance_AdvanceAndBoom();
-    save_ow_event_info[0x5e] |= 0x20;
-    Overworld_DrawMap16_Persist(0x1e6, 0xe31);
-    Overworld_DrawMap16_Persist(0x2ea, 0xe30);
-    Overworld_DrawMap16_Persist(0x26a, 0xe26);
-    Overworld_DrawMap16_Persist(0x2ea, 0xe27);
-    nmi_load_bg_from_vram = 1;
-    break;
-  case 1:
-    if (++overworld_entrance_sequence_counter != 0x20)
-      return;
-    OverworldEntrance_AdvanceAndBoom();
-    Overworld_DrawMap16_Persist(0x26a, 0xe28);
-    Overworld_DrawMap16_Persist(0x2ea, 0xe29);
-    nmi_load_bg_from_vram = 1;
-    break;
-  case 2:
-    if (++overworld_entrance_sequence_counter != 0x20)
-      return;
-    OverworldEntrance_AdvanceAndBoom();
-    Overworld_DrawMap16_Persist(0x26a, 0xe2a);
-    Overworld_DrawMap16_Persist(0x2ea, 0xe2b);
-    Overworld_DrawMap16_Persist(0x36a, 0xe2c);
-    nmi_load_bg_from_vram = 1;
-    break;
-  case 3:
-    if (++overworld_entrance_sequence_counter != 0x20)
-      return;
-    OverworldEntrance_AdvanceAndBoom();
-    Overworld_DrawMap16_Persist(0x26a, 0xe2d);
-    Overworld_DrawMap16_Persist(0x2ea, 0xe2e);
-    Overworld_DrawMap16_Persist(0x36a, 0xe2f);
-    nmi_load_bg_from_vram = 1;
-    break;
-  case 4:
-    if (++overworld_entrance_sequence_counter != 0x20)
-      return;
-    OverworldEntrance_PlayJingle();
-    break;
-  }
-}
-
-// Dark Forest Palace
-void Overworld_AnimateEntrance_Skull() {  // 9bcba6
-  switch (subsubmodule_index) {
-  case 0:
-    if (++overworld_entrance_sequence_counter != 4)
-      return;
-    overworld_entrance_sequence_counter = 0;
-    subsubmodule_index++;
-    Overworld_DrawMap16_Persist(0x409 * 2, 0xe06);
-    Overworld_DrawMap16_Persist(0x40a * 2, 0xe06);
-    save_ow_event_info[BYTE(overworld_screen_index)] |= 0x20;
-    nmi_load_bg_from_vram = 1;
-    sound_effect_2 = 0x16;
-    break;
-  case 1:
-    if (++overworld_entrance_sequence_counter != 12)
-      return;
-    overworld_entrance_sequence_counter = 0;
-    subsubmodule_index++;
-    Overworld_DrawMap16_Persist(0x3c8 * 2, 0xe07);
-    Overworld_DrawMap16_Persist(0x3c9 * 2, 0xe08);
-    Overworld_DrawMap16_Persist(0x3ca * 2, 0xe09);
-    Overworld_DrawMap16_Persist(0x3cb * 2, 0xe0a);
-    nmi_load_bg_from_vram = 1;
-    sound_effect_2 = 0x16;
-    break;
-  case 2:
-    if (++overworld_entrance_sequence_counter != 12)
-      return;
-    overworld_entrance_sequence_counter = 0;
-    subsubmodule_index++;
-    Overworld_DrawMap16_Persist(0x388 * 2, 0xe07);
-    Overworld_DrawMap16_Persist(0x389 * 2, 0xe08);
-    Overworld_DrawMap16_Persist(0x38a * 2, 0xe09);
-    Overworld_DrawMap16_Persist(0x38b * 2, 0xe0a);
-    nmi_load_bg_from_vram = 1;
-    sound_effect_2 = 0x16;
-    break;
-  case 3:
-    if (++overworld_entrance_sequence_counter != 12)
-      return;
-    overworld_entrance_sequence_counter = 0;
-    subsubmodule_index++;
-    Overworld_DrawMap16_Persist(0x2c8 * 2, 0xe11);
-    Overworld_DrawMap16_Persist(0x2cb * 2, 0xe12);
-    Overworld_DrawMap16_Persist(0x308 * 2, 0xe0d);
-    Overworld_DrawMap16_Persist(0x309 * 2, 0xe0e);
-    Overworld_DrawMap16_Persist(0x30a * 2, 0xe0f);
-    Overworld_DrawMap16_Persist(0x30b * 2, 0xe10);
-    Overworld_DrawMap16_Persist(0x349 * 2, 0xe0b);
-    Overworld_DrawMap16_Persist(0x34a * 2, 0xe0c);
-    nmi_load_bg_from_vram = 1;
-    sound_effect_2 = 0x16;
-    break;
-  case 4:
-    if (++overworld_entrance_sequence_counter != 12)
-      return;
-    overworld_entrance_sequence_counter = 0;
-    subsubmodule_index++;
-    Overworld_DrawMap16_Persist(0x2c8 * 2, 0xe13);
-    Overworld_DrawMap16_Persist(0x2cb * 2, 0xe14);
-    Overworld_DrawMap16_Persist(0x308 * 2, 0xe15);
-    Overworld_DrawMap16_Persist(0x309 * 2, 0xe16);
-    Overworld_DrawMap16_Persist(0x30a * 2, 0xe17);
-    Overworld_DrawMap16_Persist(0x30b * 2, 0xe18);
-    Overworld_DrawMap16_Persist(0x349 * 2, 0xe19);
-    Overworld_DrawMap16_Persist(0x34a * 2, 0xe1a);
-    nmi_load_bg_from_vram = 1;
-    sound_effect_2 = 0x16;
-    OverworldEntrance_PlayJingle();
-    break;
-  }
-}
-
-void Overworld_AnimateEntrance_Mire() {  // 9bccd4
-  static const uint8 kMiseryMireEntranceBits[26] = {
-    0xff, 0xf7, 0xf7, 0xfb, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
-    0xaa, 0x88, 0x88, 0x88, 0x88, 0x80, 0x80, 0x80, 0x80, 0x80,
-  };
-
-  int j;
-  if (subsubmodule_index >= 2) {
-    bg1_x_offset = frame_counter & 1 ? -1 : 1;
-    bg1_y_offset = -bg1_x_offset;
-  }
-  switch (subsubmodule_index) {
-  case 0:
-    if ((j = ++overworld_entrance_sequence_counter) < 32)
-      break;
-    j -= 32;
-    if (j == 207)
-      subsubmodule_index = 1, overworld_entrance_sequence_counter = 0;
-    TS_copy = (kMiseryMireEntranceBits[j >> 3] & (0x80 >> (j & 7))) != 0;
-    break;
-  case 1: case 2:
-    if ((j = ++overworld_entrance_sequence_counter) == 16) {
-      subsubmodule_index++;
-      sound_effect_ambient = 7;
-    }
-    if (j != 72)
-      break;
-    OverworldEntrance_AdvanceAndBoom();
-    save_ow_event_info[BYTE(overworld_screen_index)] |= 0x20;
-    j = 0xe48;
-draw_misery_2:
-    Overworld_DrawMap16_Persist(0x622, j++);
-    Overworld_DrawMap16_Persist(0x624, j++);
-    Overworld_DrawMap16_Persist(0x626, j++);
-    Overworld_DrawMap16_Persist(0x628, j++);
-    Overworld_DrawMap16_Persist(0x6a2, j++);
-    Overworld_DrawMap16_Persist(0x6a4, j++);
-    Overworld_DrawMap16_Persist(0x6a6, j++);
-    Overworld_DrawMap16_Persist(0x6a8, j++);
-    Overworld_DrawMap16_Persist(0x722, j++);
-    Overworld_DrawMap16_Persist(0x724, j++);
-    Overworld_DrawMap16_Persist(0x726, j++);
-    Overworld_DrawMap16_Persist(0x728, j++);
-    nmi_load_bg_from_vram = 1;
-    break;
-  case 3:
-    if ((j = ++overworld_entrance_sequence_counter) != 72)
-      break;
-    OverworldEntrance_AdvanceAndBoom();
-    j = 0xe54;
-draw_misery_3:
-    Overworld_DrawMap16_Persist(0x5a2, j++);
-    Overworld_DrawMap16_Persist(0x5a4, j++);
-    Overworld_DrawMap16_Persist(0x5a6, j++);
-    Overworld_DrawMap16_Persist(0x5a8, j++);
-    goto draw_misery_2;
-  case 4:
-    if ((j = ++overworld_entrance_sequence_counter) != 80)
-      break;
-    OverworldEntrance_AdvanceAndBoom();
-    j = 0xe64;
-    Overworld_DrawMap16_Persist(0x522, j++);
-    Overworld_DrawMap16_Persist(0x524, j++);
-    Overworld_DrawMap16_Persist(0x526, j++);
-    Overworld_DrawMap16_Persist(0x528, j++);
-    goto draw_misery_3;
-  case 5:
-    if ((j = ++overworld_entrance_sequence_counter) != 128)
-      break;
-    OverworldEntrance_PlayJingle();
-    sound_effect_ambient = 5;
-    break;
-  }
-}
-
-void Overworld_AnimateEntrance_TurtleRock() {  // 9bce28
-  bg1_x_offset = frame_counter & 1 ? -1 : 1;
-  bg1_y_offset = -bg1_x_offset;
-
-  switch (subsubmodule_index) {
-  case 0:
-    save_ow_event_info[overworld_screen_index] |= 0x20;
-    Dungeon_ApproachFixedColor_variable(0);
-    vram_upload_data[0] = 0x10;
-common:
-    vram_upload_data[1] = 0xfe47;
-    vram_upload_data[2] = 0x1e3;
-    BYTE(vram_upload_data[3]) = 0xff;
-    subsubmodule_index++;
-    nmi_load_bg_from_vram = 1;
-    break;
-  case 1:
-    vram_upload_data[0] = 0x14;
-    goto common;
-  case 2:
-    vram_upload_data[0] = 0x18;
-    goto common;
-  case 3:
-    vram_upload_data[0] = 0x1c;
-    goto common;
-  case 4:
-    for (int i = 0; i < 8; i++)
-      main_palette_buffer[0x58 + i] = aux_palette_buffer[0x68 + i] = 0;
-    BG1VOFS_copy2 = BG2VOFS_copy2;
-    BG1HOFS_copy2 = BG2HOFS_copy2;
-    subsubmodule_index++;
-    flag_update_cgram_in_nmi++;
-    break;
-  case 5: {
-    OverworldEntrance_DrawManyTR();
-    TS_copy = 1;
-    CGWSEL_copy = 2;
-    CGADSUB_copy = 0x22;
-    uint16 *vram = vram_upload_data, *vram_end = vram + (vram_upload_offset >> 1);
-    do {
-      vram[0] |= 0x10;
-      if (vram[2] == 0x8aa)
-        vram[2] = 0x1e3;
-      if (vram[3] == 0x8aa)
-        vram[3] = 0x1e3;
-    } while ((vram += 4) != vram_end);
-    turtlerock_ctr = 0;
-    subsubmodule_index++;
-    break;
-  }
-  case 6:
-    if (!(frame_counter & 1)) {
-      if (!(turtlerock_ctr & 7)) {
-        PaletteFilter_RestoreAdditive(0xb0, 0xc0);
-        PaletteFilter_RestoreSubtractive(0xd0, 0xe0);
-        flag_update_cgram_in_nmi++;
-        sound_effect_2 = 2;
-      }
-      if (!--turtlerock_ctr) {
-        turtlerock_ctr = 0x30;
-        subsubmodule_index++;
-      }
-    }
-    break;
-  case 7:
-    if (!(frame_counter & 1) && !(turtlerock_ctr & 7))
-      sound_effect_2 = 2;
-    if (!--turtlerock_ctr) {
-      OverworldEntrance_DrawManyTR();
-      TS_copy = 0;
-      CGWSEL_copy = 0x82;
-      CGADSUB_copy = 0x20;
-      subsubmodule_index++;
-      sound_effect_ambient = 5;
-    }
-    break;
-  case 8:
-    OverworldEntrance_PlayJingle();
-    break;
-  }
-}
-
-void OverworldEntrance_PlayJingle() {  // 9bcf40
-  sound_effect_2 = 27;
-  trigger_special_entrance = 0;
-  subsubmodule_index = 0;
-  nmi_disable_core_updates = 0;
-  flag_is_link_immobilized = 0;
-  flag_unk1 = 0;
-  bg1_x_offset = 0;
-  bg1_y_offset = 0;
-}
-
-void OverworldEntrance_DrawManyTR() {  // 9bcf60
-  int j = 0xe78;
-  Overworld_DrawMap16_Persist(0x99e, j++);
-  Overworld_DrawMap16_Persist(0x9a0, j++);
-  Overworld_DrawMap16_Persist(0x9a2, j++);
-  Overworld_DrawMap16_Persist(0x9a4, j++);
-
-  Overworld_DrawMap16_Persist(0xa1e, j++);
-  Overworld_DrawMap16_Persist(0xa20, j++);
-  Overworld_DrawMap16_Persist(0xa22, j++);
-  Overworld_DrawMap16_Persist(0xa24, j++);
-
-  Overworld_DrawMap16_Persist(0xa9e, j++);
-  Overworld_DrawMap16_Persist(0xaa0, j++);
-  Overworld_DrawMap16_Persist(0xaa2, j++);
-  Overworld_DrawMap16_Persist(0xaa4, j++);
-
-  Overworld_DrawMap16_Persist(0xb1e, j++);
-  Overworld_DrawMap16_Persist(0xb20, j++);
-  Overworld_DrawMap16_Persist(0xb22, j++);
-  Overworld_DrawMap16_Persist(0xb24, j++);
-  nmi_load_bg_from_vram = 1;
-  nmi_disable_core_updates = 1;
-}
-
-void Overworld_AnimateEntrance_GanonsTower() {  // 9bcfd9
-  switch (subsubmodule_index) {
-  case 0:
-  case 1:
-    save_ow_event_info[BYTE(overworld_screen_index)] |= 0x20;
-    GanonTowerEntrance_Func1();
-    break;
-  case 2:
-    GanonTowerEntrance_Func1();
-    if (!TS_copy) {
-      TS_copy = 1;
-      if (++ganonentrance_ctr == 3) {
-        ganonentrance_ctr = 0;
-        sound_effect_ambient = 7;
-      } else {
-        subsubmodule_index = 0;
-      }
-    }
-    break;
-  case 3:
-    if (++ganonentrance_ctr != 48)
-      return;
-    OverworldEntrance_AdvanceAndBoom();
-    Overworld_DrawMap16_Persist(0x45e, 0xe88);
-    Overworld_DrawMap16_Persist(0x460, 0xe89);
-    Overworld_DrawMap16_Persist(0x4de, 0xea2);
-    Overworld_DrawMap16_Persist(0x4e0, 0xea3);
-    Overworld_DrawMap16_Persist(0x55e, 0xe8a);
-    Overworld_DrawMap16_Persist(0x560, 0xe8b);
-    nmi_load_bg_from_vram = 1;
-    break;
-  case 4:
-    if (++ganonentrance_ctr != 48)
-      return;
-    OverworldEntrance_AdvanceAndBoom();
-    Overworld_DrawMap16_Persist(0x45e, 0xe8c);
-    Overworld_DrawMap16_Persist(0x460, 0xe8d);
-    Overworld_DrawMap16_Persist(0x4de, 0xe8e);
-    Overworld_DrawMap16_Persist(0x4e0, 0xe8f);
-    Overworld_DrawMap16_Persist(0x55e, 0xe90);
-    Overworld_DrawMap16_Persist(0x560, 0xe91);
-    nmi_load_bg_from_vram = 1;
-    break;
-  case 5:
-    if (++ganonentrance_ctr != 52)
-      return;
-    OverworldEntrance_AdvanceAndBoom();
-    Overworld_DrawMap16_Persist(0x45e, 0xe92);
-    Overworld_DrawMap16_Persist(0x460, 0xe93);
-    Overworld_DrawMap16_Persist(0x4de, 0xe94);
-    Overworld_DrawMap16_Persist(0x4e0, 0xe94);
-    Overworld_DrawMap16_Persist(0x55e, 0xe95);
-    Overworld_DrawMap16_Persist(0x560, 0xe95);
-    nmi_load_bg_from_vram = 1;
-    break;
-  case 6:
-    if (++ganonentrance_ctr != 32)
-      return;
-    OverworldEntrance_AdvanceAndBoom();
-    Overworld_DrawMap16_Persist(0x45e, 0xe96);
-    Overworld_DrawMap16_Persist(0x460, 0xe97);
-    Overworld_DrawMap16_Persist(0x4de, 0xe98);
-    Overworld_DrawMap16_Persist(0x4e0, 0xe99);
-    nmi_load_bg_from_vram = 1;
-    break;
-  case 7:
-    if (++ganonentrance_ctr != 32)
-      return;
-    OverworldEntrance_AdvanceAndBoom();
-    Overworld_DrawMap16_Persist(0x4de, 0xe9a);
-    Overworld_DrawMap16_Persist(0x4e0, 0xe9b);
-    nmi_load_bg_from_vram = 1;
-    break;
-  case 8:
-    if (++ganonentrance_ctr != 32)
-      return;
-    OverworldEntrance_AdvanceAndBoom();
-    Overworld_DrawMap16_Persist(0x4de, 0xe9c);
-    Overworld_DrawMap16_Persist(0x4e0, 0xe9d);
-    Overworld_DrawMap16_Persist(0x55e, 0xe9e);
-    Overworld_DrawMap16_Persist(0x560, 0xe9f);
-    nmi_load_bg_from_vram = 1;
-    break;
-  case 9:
-    if (++ganonentrance_ctr != 32)
-      return;
-    OverworldEntrance_AdvanceAndBoom();
-    Overworld_DrawMap16_Persist(0x55e, 0xe9a);
-    Overworld_DrawMap16_Persist(0x560, 0xe9b);
-    nmi_load_bg_from_vram = 1;
-    break;
-  case 10:
-    if (++ganonentrance_ctr != 32)
-      return;
-    OverworldEntrance_AdvanceAndBoom();
-    Overworld_DrawMap16_Persist(0x55e, 0xe9c);
-    Overworld_DrawMap16_Persist(0x560, 0xe9d);
-    Overworld_DrawMap16_Persist(0x5de, 0xea0);
-    Overworld_DrawMap16_Persist(0x5e0, 0xea1);
-    nmi_load_bg_from_vram = 1;
-    break;
-  case 11:
-    if (++ganonentrance_ctr != 32)
-      return;
-    sound_effect_ambient = 5;
-    OverworldEntrance_AdvanceAndBoom();
-    Overworld_DrawMap16_Persist(0x5de, 0xe9a);
-    Overworld_DrawMap16_Persist(0x5e0, 0xe9b);
-    nmi_load_bg_from_vram = 1;
-    break;
-  case 12:
-    if (++ganonentrance_ctr != 72)
-      return;
-    OverworldEntrance_PlayJingle();
-    ganonentrance_ctr = 0;
-    music_control = 13;
-    sound_effect_ambient = 9;
-    break;
-  }
-}
-
-void OverworldEntrance_AdvanceAndBoom() {  // 9bd00e
-  subsubmodule_index++;
-  overworld_entrance_sequence_counter = 0;
-  sound_effect_1 = 12;
-  sound_effect_2 = 7;
-}
-
--- a/overworld.h
+++ /dev/null
@@ -1,175 +1,0 @@
-#pragma once
-#include "zelda_rtl.h"
-#include "variables.h"
-
-const uint8 *GetMap8toTileAttr();
-const uint16 *GetMap16toMap8Table();
-bool LookupInOwEntranceTab(uint16 r0, uint16 r2);
-int LookupInOwEntranceTab2(uint16 pos);
-bool CanEnterWithTagalong(int e);
-int DirToEnum(int dir);
-void Overworld_ResetMosaicDown();
-void Overworld_Func1D();
-void Overworld_Func1E();
-uint16 Overworld_GetSignText(int area);
-const uint8 *GetOverworldSpritePtr(int area);
-uint8 GetOverworldBgPalette(int idx);
-void Sprite_LoadGraphicsProperties();
-void Sprite_LoadGraphicsProperties_light_world_only();
-void InitializeMirrorHDMA();
-void MirrorWarp_BuildWavingHDMATable();
-void MirrorWarp_BuildDewavingHDMATable();
-void TakeDamageFromPit();
-void Module08_OverworldLoad();
-void PreOverworld_LoadProperties();
-void AdjustLinkBunnyStatus();
-void ForceNonbunnyStatus();
-void RecoverPositionAfterDrowning();
-void Module0F_SpotlightClose();
-void Dungeon_PrepExitWithSpotlight();
-void Spotlight_ConfigureTableAndControl();
-void OpenSpotlight_Next2();
-void Module10_SpotlightOpen();
-void Module10_00_OpenIris();
-void SetTargetOverworldWarpToPyramid();
-void ResetAncillaAndCutscene();
-void Module09_Overworld();
-void OverworldOverlay_HandleRain();
-void Module09_00_PlayerControl();
-void OverworldHandleTransitions();
-void Overworld_LoadGFXAndScreenSize();
-void ScrollAndCheckForSOWExit();
-void Module09_LoadAuxGFX();
-void Overworld_FinishTransGfx();
-void Module09_LoadNewMapAndGFX();
-void Overworld_RunScrollTransition();
-void Module09_LoadNewSprites();
-void Overworld_StartScrollTransition();
-void Overworld_EaseOffScrollTransition();
-void Module09_0A_WalkFromExiting_FacingDown();
-void Module09_0B_WalkFromExiting_FacingUp();
-void Module09_09_OpenBigDoorFromExiting();
-void Overworld_DoMapUpdate32x32_B();
-void Module09_0C_OpenBigDoor();
-void Overworld_DoMapUpdate32x32_conditional();
-void Overworld_DoMapUpdate32x32();
-void Overworld_StartMosaicTransition();
-void Overworld_LoadOverlays();
-void PreOverworld_LoadOverlays();
-void Overworld_LoadOverlays2();
-void Module09_FadeBackInFromMosaic();
-void Overworld_Func1C();
-void OverworldMosaicTransition_LoadSpriteGraphicsAndSetMosaic();
-void Overworld_Func22();
-void Overworld_Func18();
-void Overworld_Func19();
-void Module09_MirrorWarp();
-void MirrorWarp_FinalizeAndLoadDestination();
-void Overworld_DrawScreenAtCurrentMirrorPosition();
-void MirrorWarp_LoadSpritesAndColors();
-void Overworld_Func2B();
-void Overworld_WeathervaneExplosion();
-void Module09_2E_Whirlpool();
-void Overworld_Func2F();
-void Module09_2A_RecoverFromDrowning();
-void Module09_2A_00_ScrollToLand();
-void Overworld_OperateCameraScroll();
-int OverworldCameraBoundaryCheck(int xa, int ya, int vd, int r8);
-int OverworldScrollTransition();
-void Overworld_SetCameraBoundaries(int big, int area);
-void Overworld_FinalizeEntryOntoScreen();
-void Overworld_Func1F();
-void ConditionalMosaicControl();
-void Overworld_ResetMosaic_alwaysIncrease();
-void Overworld_SetSongList();
-void LoadOverworldFromDungeon();
-void Overworld_LoadNewScreenProperties();
-void LoadCachedEntranceProperties();
-void Overworld_EnterSpecialArea();
-void LoadOverworldFromSpecialOverworld();
-void FluteMenu_LoadTransport();
-void Overworld_LoadBirdTravelPos(int k);
-void FluteMenu_LoadSelectedScreenPalettes();
-void FindPartnerWhirlpoolExit();
-void Overworld_LoadAmbientOverlay(bool load_map_data);
-void Overworld_LoadAmbientOverlayFalse();
-void Overworld_LoadAndBuildScreen();
-void Module08_02_LoadAndAdvance();
-void Overworld_DrawQuadrantsAndOverlays();
-void Overworld_HandleOverlaysAndBombDoors();
-void TriggerAndFinishMapLoadStripe_Y(int n);
-void TriggerAndFinishMapLoadStripe_X(int n);
-void SomeTileMapChange();
-void CreateInitialNewScreenMapToScroll();
-void CreateInitialOWScreenView_Big_North();
-void CreateInitialOWScreenView_Big_South();
-void CreateInitialOWScreenView_Big_West();
-void CreateInitialOWScreenView_Big_East();
-void CreateInitialOWScreenView_Small_North();
-void CreateInitialOWScreenView_Small_South();
-void CreateInitialOWScreenView_Small_West();
-void CreateInitialOWScreenView_Small_East();
-void OverworldTransitionScrollAndLoadMap();
-uint16 *BuildFullStripeDuringTransition_North(uint16 *dst);
-uint16 *BuildFullStripeDuringTransition_South(uint16 *dst);
-uint16 *BuildFullStripeDuringTransition_West(uint16 *dst);
-uint16 *BuildFullStripeDuringTransition_East(uint16 *dst);
-void OverworldHandleMapScroll();
-uint16 *CheckForNewlyLoadedMapAreas_North(uint16 *dst);
-uint16 *CheckForNewlyLoadedMapAreas_South(uint16 *dst);
-uint16 *CheckForNewlyLoadedMapAreas_West(uint16 *dst);
-uint16 *CheckForNewlyLoadedMapAreas_East(uint16 *dst);
-uint16 *BufferAndBuildMap16Stripes_X(uint16 *dst);
-uint16 *BufferAndBuildMap16Stripes_Y(uint16 *dst);
-void Overworld_DecompressAndDrawAllQuadrants();
-void Overworld_DecompressAndDrawOneQuadrant(uint16 *dst, int screen);
-void Overworld_ParseMap32Definition(uint16 *dst, uint16 input);
-void OverworldLoad_LoadSubOverlayMap32();
-void LoadOverworldOverlay();
-void Map16ToMap8(const uint8 *src, int r20);
-void OverworldCopyMap16ToBuffer(const uint8 *src, uint16 r20, int r14, uint16 *r10);
-void MirrorBonk_RecoverChangedTiles();
-void DecompressEnemyDamageSubclasses();
-int Decompress_bank02(uint8 *dst, const uint8 *src);
-uint8 Overworld_ReadTileAttribute(uint16 x, uint16 y);
-void Overworld_SetFixedColAndScroll();
-void Overworld_Memorize_Map16_Change(uint16 pos, uint16 value);
-void HandlePegPuzzles(uint16 pos);
-void GanonTowerEntrance_Func1();
-void Overworld_CheckSpecialSwitchArea();
-const uint16 *Overworld_GetMap16OfLink_Mult8();
-void Palette_AnimGetMasterSword();
-void Palette_AnimGetMasterSword2();
-void Palette_AnimGetMasterSword3();
-void Overworld_DwDeathMountainPaletteAnimation();
-void Overworld_LoadEventOverlay();
-void Ancilla_TerminateWaterfallSplashes();
-void Overworld_GetPitDestination();
-void Overworld_UseEntrance();
-uint16 Overworld_ToolAndTileInteraction(uint16 x, uint16 y);
-void Overworld_PickHammerSfx(uint16 a);
-uint16 Overworld_GetLinkMap16Coords(Point16U *xy);
-uint8 Overworld_HandleLiftableTiles(Point16U *pt_arg);
-uint8 Overworld_LiftingSmallObj(uint16 a, uint16 pos, uint16 y, Point16U pt);
-int Overworld_SmashRockPile(bool down_one_tile, Point16U *pt);
-uint8 SmashRockPile_fromLift(uint16 a, uint16 pos, uint16 y, Point16U pt);
-void Overworld_BombTiles32x32(uint16 x, uint16 y);
-void Overworld_BombTile(int x, int y);
-void Overworld_AlterWeathervane();
-void OpenGargoylesDomain();
-void CreatePyramidHole();
-uint16 Overworld_RevealSecret(uint16 pos);
-void AdjustSecretForPowder();
-void Overworld_DrawMap16_Persist(uint16 pos, uint16 value);
-void Overworld_DrawMap16(uint16 pos, uint16 value);
-void Overworld_AlterTileHardcore(uint16 pos, uint16 value);
-uint16 Overworld_FindMap16VRAMAddress(uint16 addr);
-void Overworld_AnimateEntrance();
-void Overworld_AnimateEntrance_PoD();
-void Overworld_AnimateEntrance_Skull();
-void Overworld_AnimateEntrance_Mire();
-void Overworld_AnimateEntrance_TurtleRock();
-void OverworldEntrance_PlayJingle();
-void OverworldEntrance_DrawManyTR();
-void Overworld_AnimateEntrance_GanonsTower();
-void OverworldEntrance_AdvanceAndBoom();
--- a/platform/switch/.gitignore
+++ /dev/null
@@ -1,4 +1,0 @@
-/bin
-/*.nacp
-/*.nro
-/*.elf
\ No newline at end of file
--- a/platform/switch/Makefile
+++ /dev/null
@@ -1,224 +1,0 @@
-#---------------------------------------------------------------------------------
-.SUFFIXES:
-#---------------------------------------------------------------------------------
-
-ifeq ($(strip $(DEVKITPRO)),)
-$(error "Please set DEVKITPRO in your environment. export DEVKITPRO=<path to>/devkitpro")
-endif
-
-TOPDIR ?= $(CURDIR)
-include $(DEVKITPRO)/libnx/switch_rules
-
-#---------------------------------------------------------------------------------
-# TARGET is the name of the output
-# BUILD is the directory where object files & intermediate files will be placed
-# SOURCES is a list of directories containing source code
-# DATA is a list of directories containing data files
-# INCLUDES is a list of directories containing header files
-# ROMFS is the directory containing data to be added to RomFS, relative to the Makefile (Optional)
-#
-# NO_ICON: if set to anything, do not use icon.
-# NO_NACP: if set to anything, no .nacp file is generated.
-# APP_TITLE is the name of the app stored in the .nacp file (Optional)
-# APP_AUTHOR is the author of the app stored in the .nacp file (Optional)
-# APP_VERSION is the version of the app stored in the .nacp file (Optional)
-# APP_TITLEID is the titleID of the app stored in the .nacp file (Optional)
-# ICON is the filename of the icon (.jpg), relative to the project folder.
-#   If not set, it attempts to use one of the following (in this order):
-#     - <Project name>.jpg
-#     - icon.jpg
-#     - <libnx folder>/default_icon.jpg
-#
-# CONFIG_JSON is the filename of the NPDM config file (.json), relative to the project folder.
-#   If not set, it attempts to use one of the following (in this order):
-#     - <Project name>.json
-#     - config.json
-#   If a JSON file is provided or autodetected, an ExeFS PFS0 (.nsp) is built instead
-#   of a homebrew executable (.nro). This is intended to be used for sysmodules.
-#   NACP building is skipped as well.
-#---------------------------------------------------------------------------------
-SRC_DIR     := ../..
-TARGET		:=	zelda3
-BUILD		:=	bin
-SOURCES		:=  $(SRC_DIR) $(SRC_DIR)/snes $(SRC_DIR)/third_party/gl_core $(SRC_DIR)/third_party/opus-1.3.1-stripped
-
-CFILES := $(wildcard $(SRC_DIR)/*.c $(SRC_DIR)/snes/*.c) $(SRC_DIR)/third_party/gl_core/gl_core_3_1.c $(SRC_DIR)/third_party/opus-1.3.1-stripped/opus_decoder_amalgam.c
-
-INCLUDES	:=	include
-APP_TITLE   :=  The Legend of Zelda: A Link to the Past
-APP_AUTHOR  :=  snesrev & Lywx
-APP_VERSION :=  $(shell git rev-parse --short HEAD) $(shell git rev-parse --abbrev-ref HEAD)
-
-#---------------------------------------------------------------------------------
-# options for code generation
-#---------------------------------------------------------------------------------
-ARCH	:=	-march=armv8-a+crc+crypto -mtune=cortex-a57 -mtp=soft -fPIE
-
-CFLAGS	:=	-g -Wall -O2 -ffunction-sections -Wno-parentheses \
-			$(ARCH) $(DEFINES)
-
-CFLAGS	+=	-D__SWITCH__ $(INCLUDE) -DSTBI_NO_THREAD_LOCALS `sdl2-config --cflags`
-
-CXXFLAGS	:= $(CFLAGS) -fno-rtti -fno-exceptions
-CFLAGS += -std=gnu11
-
-ASFLAGS	:=	-g $(ARCH)
-LDFLAGS	=	-specs=$(DEVKITPRO)/libnx/switch.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map)
-
-LIBS :=  `$(PREFIX)pkg-config --libs sdl2` -lnx -lm
-
-#---------------------------------------------------------------------------------
-# list of directories containing libraries, this must be the top level containing
-# include and lib
-#---------------------------------------------------------------------------------
-LIBDIRS	:= $(PORTLIBS) $(LIBNX)
-
-#---------------------------------------------------------------------------------
-# no real need to edit anything past this point unless you need to add additional
-# rules for different file extensions
-#---------------------------------------------------------------------------------
-ifneq ($(BUILD),$(notdir $(CURDIR)))
-#---------------------------------------------------------------------------------
-
-export OUTPUT	:=	$(CURDIR)/$(TARGET)
-export TOPDIR	:=	$(CURDIR)
-
-export VPATH	:=	$(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \
-			$(foreach dir,$(DATA),$(CURDIR)/$(dir)) \
-
-
-export DEPSDIR	:=	$(CURDIR)/$(BUILD)
-
-#CFILES		:=	$(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
-#CFILES    :=  $(wildcard ../../*.c ../../snes/*.c) ../../third_party/gl_core/gl_core_3_1.c ../../third_party/opus-1.3.1-stripped/opus_decoder_amalgam.c
-#CPPFILES	:=	$(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp)))
-#SFILES		:=	$(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
-BINFILES	:=	$(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*)))
-
-#---------------------------------------------------------------------------------
-# use CXX for linking C++ projects, CC for standard C
-#---------------------------------------------------------------------------------
-export LD	:=	$(CXX)
-#---------------------------------------------------------------------------------
-
-export OFILES_BIN	:=	$(addsuffix .o,$(BINFILES))
-export OFILES_SRC	:=	$(CPPFILES:.cpp=.o) $(notdir $(CFILES:.c=.o)) $(SFILES:.s=.o)
-export OFILES 		:=	$(OFILES_BIN) $(OFILES_SRC)
-export HFILES_BIN	:=	$(addsuffix .h,$(subst .,_,$(BINFILES)))
-
-export INCLUDE	:=	$(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
-			$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
-			-I$(CURDIR)/$(BUILD)
-
-export LIBPATHS	:=	$(foreach dir,$(LIBDIRS),-L$(dir)/lib)
-
-$(info $(OFILES))
-
-ifeq ($(strip $(CONFIG_JSON)),)
-	jsons := $(wildcard *.json)
-	ifneq (,$(findstring $(TARGET).json,$(jsons)))
-		export APP_JSON := $(TOPDIR)/$(TARGET).json
-	else
-		ifneq (,$(findstring config.json,$(jsons)))
-			export APP_JSON := $(TOPDIR)/config.json
-		endif
-	endif
-else
-	export APP_JSON := $(TOPDIR)/$(CONFIG_JSON)
-endif
-
-ifeq ($(strip $(ICON)),)
-	icons := $(wildcard *.jpg)
-	ifneq (,$(findstring $(TARGET).jpg,$(icons)))
-		export APP_ICON := $(TOPDIR)/$(TARGET).jpg
-	else
-		ifneq (,$(findstring icon.jpg,$(icons)))
-			export APP_ICON := $(TOPDIR)/icon.jpg
-		endif
-	endif
-else
-	export APP_ICON := $(TOPDIR)/$(ICON)
-endif
-
-ifeq ($(strip $(NO_ICON)),)
-	export NROFLAGS += --icon=$(APP_ICON)
-endif
-
-ifeq ($(strip $(NO_NACP)),)
-	export NROFLAGS += --nacp=$(CURDIR)/$(TARGET).nacp
-endif
-
-ifneq ($(APP_TITLEID),)
-	export NACPFLAGS += --titleid=$(APP_TITLEID)
-endif
-
-ifneq ($(ROMFS),)
-	export NROFLAGS += --romfsdir=$(CURDIR)/$(ROMFS)
-endif
-
-.PHONY: $(BUILD) clean all
-
-#---------------------------------------------------------------------------------
-all: $(BUILD)
-
-$(BUILD):
-	@echo $(CFILES) ...
-	@[ -d $@ ] || mkdir -p $@
-	@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
-
-#---------------------------------------------------------------------------------
-clean:
-	@echo clean ...
-ifeq ($(strip $(APP_JSON)),)
-	@rm -fr $(BUILD) $(TARGET).nro $(TARGET).nacp $(TARGET).elf
-else
-	@rm -fr $(BUILD) $(TARGET).nsp $(TARGET).nso $(TARGET).npdm $(TARGET).elf
-endif
-
-
-#---------------------------------------------------------------------------------
-else
-.PHONY:	all
-
-DEPENDS	:=	$(OFILES:.o=.d)
-
-#---------------------------------------------------------------------------------
-# main targets
-#---------------------------------------------------------------------------------
-ifeq ($(strip $(APP_JSON)),)
-
-all	:	$(OUTPUT).nro
-
-ifeq ($(strip $(NO_NACP)),)
-$(OUTPUT).nro	:	$(OUTPUT).elf $(OUTPUT).nacp
-else
-$(OUTPUT).nro	:	$(OUTPUT).elf
-endif
-
-else
-
-all	:	$(OUTPUT).nsp
-
-$(OUTPUT).nsp	:	$(OUTPUT).nso $(OUTPUT).npdm
-
-$(OUTPUT).nso	:	$(OUTPUT).elf
-
-endif
-
-$(OUTPUT).elf	:	$(OFILES)
-
-$(OFILES_SRC)	: $(HFILES_BIN)
-
-#---------------------------------------------------------------------------------
-# you need a rule like this for each extension you use as binary data
-#---------------------------------------------------------------------------------
-%.bin.o	%_bin.h :	%.bin
-#---------------------------------------------------------------------------------
-	@echo $(notdir $<)
-	@$(bin2o)
-
--include $(DEPENDS)
-
-#---------------------------------------------------------------------------------------
-endif
-#---------------------------------------------------------------------------------------
binary files a/platform/switch/icon.jpg /dev/null differ
--- a/platform/switch/zelda3.ini
+++ /dev/null
@@ -1,126 +1,0 @@
-[General]
-# Automatically save state on quit and reload on start
-Autosave = 0
-DisplayPerfInTitle = 0
-
-# Extended aspect ratio, either 16:9, 16:10, or 18:9. 4:3 means normal aspect ratio.
-# Add ", unchanged_sprites" to avoid changing sprite spawn/die behavior. Without this
-# replays will be incompatible.
-# Add ", no_visual_fixes" to avoid fixing some graphics glitches (for example with Cape).
-# It won't affect replays/game behavior but the memory compare will not work.
-# Add "extend_y, " right before the aspect radio specifier to display 240 lines instead of 224.
-ExtendedAspectRatio = 16:9
-
-
-[Graphics]
-# Window size ( Auto or WidthxHeight )
-WindowSize = 1280x720
-# Fullscreen mode (0=windowed, 1=desktop fullscreen, 2=fullscreen w/mode change)
-Fullscreen = 0
-# Window scale (1=100%, 2=200%, 3=300%, etc.)
-WindowScale = 1
-NewRenderer = 1
-EnhancedMode7 = 1
-IgnoreAspectRatio = 0
-
-# Enable this option to remove the sprite limits per scan line
-NoSpriteLimits = 1
-
-# Change the appearance of Link by loading a ZSPR file
-# See all sprites here: https://snesrev.github.io/sprites-gfx/snes/zelda3/link/
-# Download the files with "git clone https://github.com/snesrev/sprites-gfx.git"
-# LinkGraphics = sprites-gfx/snes/zelda3/link/sheets/megaman-x.2.zspr
-
-
-[Sound]
-EnableAudio = 1
-
-# DSP frequency in samples per second (e.g. 48000, 44100, 32000, 22050, 11025)
-AudioFreq = 44100
-# number of separate sound channels (1=mono, 2=stereo)
-AudioChannels = 2
-# Audio buffer size in samples (power of 2; e.g., 4096, 2048, 1024) [try 1024 if sound is crackly]. The higher the more lag before you hear sounds.
-AudioSamples = 1024
-
-# Enable MSU support for audio. Files need to be in a subfolder, msu/alttp_msu-*.pcm
-# Only works with 44100 hz and 2 channels
-EnableMSU = 0
-
-
-[Features]
-# Item switch on L/R. Also allows reordering of items in inventory by pressing Y+direction
-# Hold X inside of the item selection screen to reassign the X key into a separate item slot.
-# When X is assigned to an item, the Select key is used to enter the map. Press Select inside
-# of the Start menu to see the old select options.
-ItemSwitchLR = 0
-
-# Allow turning while dashing
-TurnWhileDashing = 0
-
-# Allow mirror to be used to warp to the Dark World
-MirrorToDarkworld = 0
-
-# Collect items (like hearts) with sword instead of having to touch them
-CollectItemsWithSword = 0
-
-# Level 2-4 sword can be used to break pots
-BreakPotsWithSword = 0
-
-# Disable the low health beep
-DisableLowHealthBeep = 0
-
-# Avoid waiting too much at the start
-SkipIntroOnKeypress = 0
-
-# Display max rupees/bombs/arrows with orange/yellow color
-ShowMaxItemsInYellow = 0
-
-# Allows up to four bombs active at a time instead of two.
-MoreActiveBombs = 0
-
-# Can carry 9999 rupees instead of 999
-CarryMoreRupees = 0
-
-# Enable various zelda bug fixes
-MiscBugFixes = 0
-
-# Enable some more advanced zelda bugfixes that change game behavior
-GameChangingBugFixes = 0
-
-# Allow bird travel to be cancelled by hitting the X key
-CancelBirdTravel = 0
-
-
-[KeyMap]
-# Change what keyboard keys map to the joypad
-# Order: Up, Down, Left, Right, Select, Start, A, B, X, Y, L, R
-
-# This default is suitable for QWERTY keyboards.
-Controls = Up, Down, Left, Right, Right Shift, Return, x, z, s, a, c, v
-
-# This default is suitable for QWERTZ keyboards.
-#Controls = Up, Down, Left, Right, Right Shift, Return, x, y, s, a, c, v
-
-# This one is suitable for AZERTY keyboards.
-#Controls = Up, Down, Left, Right, Right Shift, Return, x, w, s, q, c, v
-
-CheatLife = w
-CheatKeys = o
-CheatWalkThroughWalls = Ctrl+e
-ClearKeyLog = k
-StopReplay = l
-Fullscreen = Alt+Return
-Reset = Ctrl+r
-Pause = Shift+p
-PauseDimmed = p
-Turbo = Tab
-ReplayTurbo = t
-WindowBigger = Ctrl+Up
-WindowSmaller = Ctrl+Down
-
-Load =      F1,     F2,     F3,     F4,     F5,     F6,     F7,     F8,     F9,     F10
-Save = Shift+F1,Shift+F2,Shift+F3,Shift+F4,Shift+F5,Shift+F6,Shift+F7,Shift+F8,Shift+F9,Shift+F10
-Replay= Ctrl+F1,Ctrl+F2,Ctrl+F3,Ctrl+F4,Ctrl+F5,Ctrl+F6,Ctrl+F7,Ctrl+F8,Ctrl+F9,Ctrl+F10
-
-LoadRef = 1,2,3,4,5,6,7,8,9,0,-,=,Backspace
-ReplayRef = Ctrl+1,Ctrl+2,Ctrl+3,Ctrl+4,Ctrl+5,Ctrl+6,Ctrl+7,Ctrl+8,Ctrl+9,Ctrl+0,Ctrl+-,Ctrl+=,Ctrl+Backspace
--- a/platform/win32/resource.h
+++ /dev/null
@@ -1,16 +1,0 @@
-//{{NO_DEPENDENCIES}}
-// Microsoft Visual C++ generated include file.
-// Used by zelda3.rc
-//
-#define IDI_ICON1                       101
-
-// Next default values for new objects
-// 
-#ifdef APSTUDIO_INVOKED
-#ifndef APSTUDIO_READONLY_SYMBOLS
-#define _APS_NEXT_RESOURCE_VALUE        102
-#define _APS_NEXT_COMMAND_VALUE         40001
-#define _APS_NEXT_CONTROL_VALUE         1001
-#define _APS_NEXT_SYMED_VALUE           101
-#endif
-#endif
binary files a/platform/win32/triforce.ico /dev/null differ
--- a/platform/win32/volume_control.c
+++ /dev/null
@@ -1,82 +1,0 @@
-#include "volume_control.h"
-
-#define COBJMACROS
-#define CINTERFACE
-
-#define MICROSOFT_WINDOWS_WINBASE_H_DEFINE_INTERLOCKED_CPLUSPLUS_OVERLOADS 0
-
-#include <initguid.h>
-#include <audioclient.h>
-#include <audiopolicy.h>
-#include <mmdeviceapi.h>
-
-static ISimpleAudioVolume *GetSimpleAudioVolume();
-
-DEFINE_GUID(IID_IMMDeviceEnumerator, 0XA95664D2, 0X9614, 0X4F35, 0XA7, 0X46, 0XDE, 0X8D, 0XB6, 0X36, 0X17, 0XE6);
-DEFINE_GUID(CLSID_MMDeviceEnumerator, 0XBCDE0395, 0XE52F, 0X467C, 0X8E, 0X3D, 0XC4, 0X57, 0X92, 0X91, 0X69, 0X2E);
-DEFINE_GUID(IID_IAudioSessionManager, 0X77AA99A0, 0X1BD6, 0X484F, 0X8B, 0XC7, 0X2C, 0X65, 0X4C, 0X9A, 0X9B, 0X6F);
-
-static void InitializeCom() {
-  static bool com_initialized;
-  if (!com_initialized)
-    com_initialized = SUCCEEDED(CoInitialize(NULL));
-}
-
-int GetApplicationVolume() {
-  ISimpleAudioVolume *simple_audio_volume = GetSimpleAudioVolume();
-  if (!simple_audio_volume)
-    return false;
-  float volume_level = -1;
-  HRESULT result = ISimpleAudioVolume_GetMasterVolume(simple_audio_volume, &volume_level);
-  ISimpleAudioVolume_Release(simple_audio_volume);
-  return (int)(volume_level * 100);
-}
-
-bool SetApplicationVolume(int volume_level) {
-  ISimpleAudioVolume *simple_audio_volume = GetSimpleAudioVolume();
-  if (!simple_audio_volume)
-    return false;
-  HRESULT result = ISimpleAudioVolume_SetMasterVolume(simple_audio_volume, (float)(volume_level / 100.0), NULL);
-  ISimpleAudioVolume_Release(simple_audio_volume);
-  return SUCCEEDED(result);
-}
-
-bool SetApplicationMuted(bool muted) {
-  ISimpleAudioVolume *simple_audio_volume = GetSimpleAudioVolume();
-  if (!simple_audio_volume)
-    return false;
-  HRESULT result = ISimpleAudioVolume_SetMute(simple_audio_volume, muted, NULL);
-  ISimpleAudioVolume_Release(simple_audio_volume);
-  return SUCCEEDED(result);
-}
-
-static ISimpleAudioVolume *GetSimpleAudioVolume() {
-  HRESULT result;
-  IMMDeviceEnumerator *device_enumerator = NULL;
-  IMMDevice *device = NULL;
-  IAudioSessionManager *audio_session_manager = NULL;
-  ISimpleAudioVolume *simple_audio_volume = NULL;
-
-  InitializeCom();
-  
-  result = CoCreateInstance(&CLSID_MMDeviceEnumerator,
-      NULL, CLSCTX_INPROC_SERVER, &IID_IMMDeviceEnumerator, &device_enumerator);
-  if (FAILED(result) || device_enumerator == NULL)
-    goto done;
-  
-  result = IMMDeviceEnumerator_GetDefaultAudioEndpoint(device_enumerator, eRender, eConsole, &device);
-  if (FAILED(result) || device == NULL)
-    goto done;
-  
-  result = IMMDevice_Activate(device, &IID_IAudioSessionManager, CLSCTX_INPROC_SERVER, NULL, &audio_session_manager);
-  if (FAILED(result) || audio_session_manager == NULL)
-    goto done;
-  result = IAudioSessionManager_GetSimpleAudioVolume(audio_session_manager, &GUID_NULL, 0, &simple_audio_volume);
-
-done:
-  if (device_enumerator) IMMDeviceEnumerator_Release(device_enumerator);
-  if (device) IMMDevice_Release(device);
-  if (audio_session_manager) IAudioSessionManager_Release(audio_session_manager);
-
-  return simple_audio_volume;
-}
--- a/platform/win32/volume_control.h
+++ /dev/null
@@ -1,14 +1,0 @@
-#ifndef ZELDA3_PLATFORM_WIN32_VOLUME_CONTROL_H_
-#define ZELDA3_PLATFORM_WIN32_VOLUME_CONTROL_H_
-
-#include <stdbool.h>
-
-#ifndef SYSTEM_VOLUME_MIXER_AVAILABLE
-#define SYSTEM_VOLUME_MIXER_AVAILABLE 1
-#endif  // SYSTEM_VOLUME_MIXER_AVAILABLE
-
-int GetApplicationVolume();
-bool SetApplicationVolume(int volume_level);
-bool SetApplicationMuted(bool muted);
-
-#endif // ZELDA3_PLATFORM_WIN32_VOLUME_CONTROL_H_
--- a/platform/win32/zelda3.rc
+++ /dev/null
@@ -1,71 +1,0 @@
-// Microsoft Visual C++ generated resource script.
-//
-#include "resource.h"
-
-#define APSTUDIO_READONLY_SYMBOLS
-/////////////////////////////////////////////////////////////////////////////
-//
-// Generated from the TEXTINCLUDE 2 resource.
-//
-#include "winres.h"
-
-/////////////////////////////////////////////////////////////////////////////
-#undef APSTUDIO_READONLY_SYMBOLS
-
-/////////////////////////////////////////////////////////////////////////////
-// English (United States) resources
-
-#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
-LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
-#pragma code_page(1252)
-
-#ifdef APSTUDIO_INVOKED
-/////////////////////////////////////////////////////////////////////////////
-//
-// TEXTINCLUDE
-//
-
-1 TEXTINCLUDE 
-BEGIN
-    "platform\\win32\\resource.h\0"
-END
-
-2 TEXTINCLUDE 
-BEGIN
-    "#include ""winres.h""\r\n"
-    "\0"
-END
-
-3 TEXTINCLUDE 
-BEGIN
-    "\r\n"
-    "\0"
-END
-
-#endif    // APSTUDIO_INVOKED
-
-
-/////////////////////////////////////////////////////////////////////////////
-//
-// Icon
-//
-
-// Icon with lowest ID value placed first to ensure application icon
-// remains consistent on all systems.
-IDI_ICON1               ICON                    "platform\\win32\\triforce.ico"
-
-#endif    // English (United States) resources
-/////////////////////////////////////////////////////////////////////////////
-
-
-
-#ifndef APSTUDIO_INVOKED
-/////////////////////////////////////////////////////////////////////////////
-//
-// Generated from the TEXTINCLUDE 3 resource.
-//
-
-
-/////////////////////////////////////////////////////////////////////////////
-#endif    // not APSTUDIO_INVOKED
-
--- a/player.c
+++ /dev/null
@@ -1,6664 +1,0 @@
-#include "player.h"
-#include "zelda_rtl.h"
-#include "variables.h"
-#include "tile_detect.h"
-#include "ancilla.h"
-#include "sprite.h"
-#include "load_gfx.h"
-#include "hud.h"
-#include "overworld.h"
-#include "tagalong.h"
-#include "dungeon.h"
-#include "misc.h"
-#include "player_oam.h"
-#include "sprite_main.h"
-
-static bool g_ApplyLinksMovementToCamera_called;
-
-static const uint8 kSpinAttackDelays[] = { 1, 0, 0, 0, 0, 3, 0, 0, 1, 0, 3, 3, 3, 3, 4, 4, 1, 5 };
-static const uint8 kFireBeamSounds[] = { 1, 2, 3, 4, 0, 9, 18, 27 };
-static const int8 kTagalongArr1[] = { -1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
-static const int8 kTagalongArr2[] = { -1, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
-static const uint8 kLinkSpinGraphicsByDir[] = {
-  10, 11, 10, 6, 7, 8, 9, 2, 3, 4, 5, 10, 0, 1, 0, 2, 3, 4, 5, 6, 7, 8, 9, 0, 12, 13, 12, 4, 5, 6, 7, 8, 9, 2, 3, 12, 14, 15, 14, 8, 9, 2, 3, 4, 5, 6, 7, 14
-};
-static const uint8 kLinkSpinDelays[] = { 1, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5 };
-static const uint8 kGrabWallDirs[] = { 4, 8, 1, 2 };
-static const uint8 kGrabWall_AnimSteps[] = { 0, 1, 2, 3, 1, 2, 3 };
-static const uint8 kGrabWall_AnimTimer[] = { 0, 5, 5, 12, 5, 5, 12 };
-static const uint8 kCapeDepletionTimers[] = { 4, 8, 8 };
-static const int8 kAvoidJudder1[] = { 0, 1, 2, 3, 4, 5, 6, 7, 7, 6, 5, 4, 3, 2, 1, 0, 7, 6, 5, 4, 3, 2, 1, 0, 0, 1, 2, 3, 4, 5, 6, 7 };
-static const int8 kLink_DoMoveXCoord_Outdoors_Helper2_y[2] = { -8, 8 };
-static const int8 kLink_DoMoveXCoord_Outdoors_Helper2_y2[2] = { -16, 16 };
-static const uint8 kLink_DoMoveXCoord_Outdoors_Helper2_velz[8] = { 32, 32, 32, 40, 48, 56, 64, 72 };
-static const uint8 kLink_DoMoveXCoord_Outdoors_Helper2_velx[8] = { 16, 28, 28, 28, 28, 28, 28, 28 };
-static const uint8 kLink_Lift_tab[9] = { 0x54, 0x52, 0x50, 0xFF, 0x51, 0x53, 0x55, 0x56, 0x57 };
-static const uint8 kLink_Move_Helper6_tab0[] = { 8, 8, 23, 23, 8, 23, 8, 23 };
-static const uint8 kLink_Move_Helper6_tab1[] = { 0, 15, 0, 15, 0, 0, 15, 15 };
-static const uint8 kLink_Move_Helper6_tab2[] = { 23, 23, 8, 8, 8, 23, 8, 23 };
-static const uint8 kLink_Move_Helper6_tab3[] = { 0, 15, 0, 15, 15, 15, 0, 0 };
-const uint8 kSwimmingTab1[4] = { 2, 0, 1, 0 };
-const uint8 kSwimmingTab2[2] = { 32, 8 };
-static PlayerHandlerFunc *const kPlayerHandlers[31] = {
-  &LinkState_Default,
-  &LinkState_Pits,
-  &LinkState_Recoil,
-  &LinkState_SpinAttack,
-  &PlayerHandler_04_Swimming,
-  &LinkState_OnIce,
-  &LinkState_Recoil,
-  &LinkState_Zapped,
-  &LinkState_UsingEther,
-  &LinkState_UsingBombos,
-  &LinkState_UsingQuake,
-  &LinkHop_HoppingSouthOW,
-  &LinkState_HoppingHorizontallyOW,
-  &LinkState_HoppingDiagonallyUpOW,
-  &LinkState_HoppingDiagonallyDownOW,
-  &LinkState_0F,
-  &LinkState_0F,
-  &LinkState_Dashing,
-  &LinkState_ExitingDash,
-  &LinkState_Hookshotting,
-  &LinkState_CrossingWorlds,
-  &PlayerHandler_15_HoldItem,
-  &LinkState_Sleeping,
-  &PlayerHandler_17_Bunny,
-  &LinkState_HoldingBigRock,
-  &LinkState_ReceivingEther,
-  &LinkState_ReceivingBombos,
-  &LinkState_ReadingDesertTablet,
-  &LinkState_TemporaryBunny,
-  &LinkState_TreePull,
-  &LinkState_SpinAttack,
-};
-// forwards
-static const uint8 kLinkItem_MagicCosts[] = { 16, 8, 4, 32, 16, 8, 8, 4, 2, 8, 4, 2, 8, 4, 2, 16, 8, 4, 4, 2, 2, 8, 4, 2, 16, 8, 4 };
-static const uint8 kBombosAnimDelays[] = { 5, 5, 5, 5, 5, 5, 5, 5, 3, 3, 3, 3, 3, 7, 1, 1, 1, 1, 1, 13 };
-static const uint8 kBombosAnimStates[] = { 0, 1, 2, 3, 0, 1, 2, 3, 8, 9, 10, 11, 12, 10, 8, 13, 14, 15, 16, 17 };
-static const uint8 kEtherAnimDelays[] = { 5, 5, 5, 5, 5, 5, 5, 5, 7, 7, 3, 3 };
-static const uint8 kEtherAnimDelaysNoFlash[] = { 5, 5, 5, 5, 5, 5, 5, 5, 7, 7, 24, 24 };
-static const uint8 kEtherAnimStates[] = { 0, 1, 2, 3, 0, 1, 2, 3, 4, 5, 6, 7 };
-static const uint8 kQuakeAnimDelays[] = { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 19 };
-static const uint8 kQuakeAnimStates[] = { 0, 1, 2, 3, 0, 1, 2, 3, 18, 19, 20, 22 };
-static inline uint8 BitSum4(uint8 t);
-static inline uint8 BitSum4(uint8 t) {
-  return (t & 1) + ((t >> 1) & 1) + ((t >> 2) & 1) + ((t >> 3) & 1);
-}
-
-void Dungeon_HandleLayerChange() {  // 81ff05
-  link_is_on_lower_level_mirror = 1;
-  if (kind_of_in_room_staircase == 0)
-    BYTE(dungeon_room_index) += 16;
-  if (kind_of_in_room_staircase != 2)
-    link_is_on_lower_level = 1;
-  about_to_jump_off_ledge = 0;
-  SetAndSaveVisitedQuadrantFlags();
-}
-
-void CacheCameraProperties() {  // 81ff28
-  BG2HOFS_copy2_cached = BG2HOFS_copy2;
-  BG2VOFS_copy2_cached = BG2VOFS_copy2;
-  link_y_coord_cached = link_y_coord;
-  link_x_coord_cached = link_x_coord;
-  room_scroll_vars_y_vofs1_cached = room_bounds_y.a0;
-  room_scroll_vars_y_vofs2_cached = room_bounds_y.a1;
-  room_scroll_vars_x_vofs1_cached = room_bounds_x.a0;
-  room_scroll_vars_x_vofs2_cached = room_bounds_x.a1;
-  up_down_scroll_target_cached = up_down_scroll_target;
-  up_down_scroll_target_end_cached = up_down_scroll_target_end;
-  left_right_scroll_target_cached = left_right_scroll_target;
-  left_right_scroll_target_end_cached = left_right_scroll_target_end;
-  camera_y_coord_scroll_low_cached = camera_y_coord_scroll_low;
-  camera_x_coord_scroll_low_cached = camera_x_coord_scroll_low;
-  quadrant_fullsize_x_cached = quadrant_fullsize_x;
-  quadrant_fullsize_y_cached = quadrant_fullsize_y;
-  link_quadrant_x_cached = link_quadrant_x;
-  link_quadrant_y_cached = link_quadrant_y;
-  link_direction_facing_cached = link_direction_facing;
-  link_is_on_lower_level_cached = link_is_on_lower_level;
-  link_is_on_lower_level_mirror_cached = link_is_on_lower_level_mirror;
-  is_standing_in_doorway_cahed = is_standing_in_doorway;
-  dung_cur_floor_cached = dung_cur_floor;
-}
-
-void CheckAbilityToSwim() {  // 81ffb6
-  if (!link_is_bunny_mirror && link_item_flippers)
-    return;
-  if (link_item_moon_pearl)
-    link_is_bunny_mirror = 0;
-  link_visibility_status = 0xc;
-  submodule_index = player_is_indoors ? 20 : 42;
-}
-
-void Link_Main() {  // 878000
-//  RunEmulatedFunc(0x878000, 0, 0, 0, true, true, -2, 0);
-//  return;
-
-
-
-  link_x_coord_prev = link_x_coord;
-  link_y_coord_prev = link_y_coord;
-  flag_unk1 = 0;
-  if (!flag_is_link_immobilized)
-    Link_ControlHandler();
-  HandleSomariaAndGraves();
-}
-
-void Link_ControlHandler() {  // 87807f
-  if (link_give_damage) {
-    if (link_cape_mode) {
-      link_give_damage = 0;
-      link_auxiliary_state = 0;
-      link_incapacitated_timer = 0;
-    } else {
-      if (!link_disable_sprite_damage) {
-        uint8 dmg = link_give_damage;
-        link_give_damage = 0;
-        if (ancilla_type[0] == 5 && player_handler_timer == 0 && link_delay_timer_spin_attack) {
-          ancilla_type[0] = 0;
-          flag_for_boomerang_in_place = 0;
-        }
-        if (countdown_for_blink == 0)
-          countdown_for_blink = 58;
-        Ancilla_Sfx2_Near(38);
-        number_of_times_hurt_by_sprites++;
-        uint8 new_dmg = link_health_current - dmg;
-        if (new_dmg == 0 || new_dmg >= 0xa8) {
-          mapbak_TM = TM_copy;
-          mapbak_TS = TS_copy;
-          saved_module_for_menu = main_module_index;
-          main_module_index = 18;
-          submodule_index = 1;
-          countdown_for_blink = 0;
-          link_hearts_filler = 0;
-          new_dmg = 0;
-        }
-        link_health_current = new_dmg;
-      }
-    }
-  }
-  if (link_player_handler_state)
-    Player_CheckHandleCapeStuff();
-  kPlayerHandlers[link_player_handler_state]();
-}
-
-void LinkState_Default() {  // 878109
-  CacheCameraPropertiesIfOutdoors();
-  if (Link_HandleBunnyTransformation()) {
-    if (link_player_handler_state == 23)
-      PlayerHandler_17_Bunny();
-    return;
-  }
-  fallhole_var2 = 0;
-  if (link_auxiliary_state)
-    HandleLink_From1D();
-  else
-    PlayerHandler_00_Ground_3();
-}
-
-void HandleLink_From1D() {  // 878130
-  link_item_in_hand = 0;
-  link_position_mode = 0;
-  link_debug_value_1 = 0;
-  link_debug_value_2 = 0;
-  link_var30d = 0;
-  link_var30e = 0;
-  some_animation_timer_steps = 0;
-  bitfield_for_a_button = 0;
-  button_mask_b_y &= ~0x40;
-  link_state_bits = 0;
-  link_picking_throw_state = 0;
-  link_grabbing_wall = 0;
-  bitmask_of_dragstate = 0;
-  Link_ResetSwimmingState();
-  link_cant_change_direction &= ~1;
-  link_z_coord &= 0xff;
-  if (link_electrocute_on_touch != 0) {
-    if (link_cape_mode)
-      Link_ForceUnequipCape_quietly();
-    Link_ResetSwordAndItemUsage();
-    link_disable_sprite_damage = 1;
-    player_handler_timer = 0;
-    link_delay_timer_spin_attack = 2;
-    link_animation_steps = 0;
-    link_direction &= ~0xf;
-    Ancilla_Sfx3_Near(43);
-    link_player_handler_state = 7;
-    LinkState_Zapped();
-  } else {
-    link_moving_against_diag_tile = 0;
-    link_player_handler_state = 2;
-    LinkState_Recoil();
-  }
-}
-
-void PlayerHandler_00_Ground_3() {  // 8781a0
-  g_ApplyLinksMovementToCamera_called = false;
-
-  link_z_coord = 0xffff;
-  link_actual_vel_z = 0xff;
-  link_recoilmode_timer = 0;
-
-  if (!Link_HandleToss()) {
-    Link_HandleAPress();
-    if ((link_state_bits | link_grabbing_wall) == 0 && link_unk_master_sword == 0 && link_player_handler_state != kPlayerState_StartDash) {
-      Link_HandleYItem();
-      // Ensure we're not handling potions. Things further
-      // down don't assume this and change the module indexes randomly.
-      // This also fixes a bug where bombos, ether, quake get aborted if you use spin attack at the same time.
-      if ((enhanced_features0 & kFeatures0_MiscBugFixes) && (
-          main_module_index == 14 && submodule_index != 2 ||
-          link_player_handler_state == kPlayerState_Bombos ||
-          link_player_handler_state == kPlayerState_Ether ||
-          link_player_handler_state == kPlayerState_Quake))
-        goto getout_clear_vel;
-      if (sram_progress_indicator != 0) {
-        Link_HandleSwordCooldown();
-        if (link_player_handler_state == 3)
-          goto getout_clear_vel;
-      }
-    }
-  }
-
-  Link_HandleCape_passive_LiftCheck();
-  if (link_incapacitated_timer) {
-    link_moving_against_diag_tile = 0;
-    link_var30d = 0;
-    link_var30e = 0;
-    some_animation_timer_steps = 0;
-    bitfield_for_a_button = 0;
-    link_picking_throw_state = 0;
-    link_state_bits = 0;
-    link_grabbing_wall = 0;
-    if (!(button_mask_b_y & 0x80))
-      link_cant_change_direction &= ~1;
-    Link_HandleRecoilAndTimer(false);
-    return;
-  }
-
-  if (link_unk_master_sword) {
-    link_direction = 0;
-  } else if (!link_is_transforming && (link_grabbing_wall & ~2) == 0 && (link_state_bits & 0x7f) == 0 &&
-             ((link_state_bits & 0x80) == 0 || (link_picking_throw_state & 1) == 0) && !link_item_in_hand && !link_position_mode &&
-             (button_b_frames >= 9 || (button_mask_b_y & 0x20) != 0 || (button_mask_b_y & 0x80) == 0)) {
-    // if_4
-
-    if (link_flag_moving) {
-      swimcoll_var9[0] = swimcoll_var9[1] = 0x180;
-      Link_HandleSwimMovements();
-      return;
-    }
-    ResetAllAcceleration();
-    uint8 dir;
-
-    if ((dir = (force_move_any_direction & 0xf)) == 0) {
-      if (link_grabbing_wall & 2)
-        goto endif_3;
-      if ((dir = (joypad1H_last & kJoypadH_AnyDir)) == 0) {
-        link_x_vel = 0;
-        link_y_vel = 0;
-        link_direction = 0;
-        link_direction_last = 0;
-        link_animation_steps = 0;
-        bitmask_of_dragstate &= ~0xf;
-        link_timer_push_get_tired = 32;
-        link_timer_jump_ledge = 19;
-        goto endif_3;
-      }
-    }
-    link_direction = dir;
-    if (dir != link_direction_last) {
-      link_direction_last = dir;
-      link_subpixel_x = link_subpixel_y = 0;
-      link_moving_against_diag_tile = 0;
-      bitmask_of_dragstate = 0;
-      link_timer_push_get_tired = 32;
-      link_timer_jump_ledge = 19;
-    }
-  }
-  // endif_3
-endif_3:
-  Link_HandleDiagonalCollision();
-  Link_HandleVelocity();
-  Link_HandleCardinalCollision();
-  Link_HandleMovingAnimation_FullLongEntry();
-  if (link_unk_master_sword) getout_clear_vel: {
-    link_y_vel = link_x_vel = 0;
-  }
-
-  fallhole_var1 = 0;
-
-  // HandleIndoorCameraAndDoors must not be called twice in the same frame,
-  // this might mess up camera positioning. For example when using spin attack
-  // in between bumpers.
-  if (g_ApplyLinksMovementToCamera_called && (enhanced_features0 & kFeatures0_MiscBugFixes))
-    return;
-
-  HandleIndoorCameraAndDoors();
-}
-
-bool Link_HandleBunnyTransformation() {  // 8782da
-  if (!link_timer_tempbunny)
-    return false;
-
-  if (!link_need_for_poof_for_transform) {
-    if (link_player_handler_state == kPlayerState_PermaBunny || link_player_handler_state == kPlayerState_TempBunny) {
-      link_timer_tempbunny = 0;
-      return false;
-    }
-    if (link_picking_throw_state & 2)
-      link_state_bits = 0;
-    uint8 bak = link_state_bits & 0x80;
-    Link_ResetProperties_A();
-    link_state_bits = bak;
-
-    for (int i = 4; i >= 0; i--) {
-      if (ancilla_type[i] == 0x30 || ancilla_type[i] == 0x31)
-        ancilla_type[i] = 0;
-    }
-    Link_CancelDash();
-    AncillaAdd_CapePoof(0x23, 4);
-    Ancilla_Sfx2_Near(0x14);
-    link_bunny_transform_timer = 20;
-    link_disable_sprite_damage = 1;
-    link_need_for_poof_for_transform = 1;
-    link_visibility_status = 12;
-  }
-  if (sign8(--link_bunny_transform_timer)) {
-    link_player_handler_state = kPlayerState_TempBunny;
-    link_is_bunny_mirror = 1;
-    link_is_bunny = 1;
-    LoadGearPalettes_bunny();
-    link_visibility_status = 0;
-    link_disable_sprite_damage = 0;
-    link_need_for_poof_for_transform = 0;
-  }
-  return true;
-}
-
-void LinkState_TemporaryBunny() {  // 878365
-  if (!link_timer_tempbunny) {
-    AncillaAdd_CapePoof(0x23, 4);
-    Ancilla_Sfx2_Near(0x15);
-    link_bunny_transform_timer = 32;
-    link_player_handler_state = 0;
-    Link_ResetProperties_C();
-    link_need_for_poof_for_transform = 0;
-    link_is_bunny = 0;
-    link_is_bunny_mirror = 0;
-    LoadActualGearPalettes();
-    link_need_for_poof_for_transform = 0;
-    LinkState_Default();
-  } else {
-    link_timer_tempbunny--;
-    PlayerHandler_17_Bunny();
-  }
-}
-
-void PlayerHandler_17_Bunny() {  // 8783a1
-  CacheCameraPropertiesIfOutdoors();
-  fallhole_var2 = 0;
-  if (!link_is_in_deep_water) {
-    if (link_auxiliary_state == 0) {
-      Link_TempBunny_Func2();
-      return;
-    }
-    if (link_item_moon_pearl)
-      link_is_bunny_mirror = 0;
-  }
-  LinkState_Bunny_recache();
-}
-
-void LinkState_Bunny_recache() {  // 8783c7
-  link_need_for_poof_for_transform = 0;
-  link_timer_tempbunny = 0;
-  if (link_item_moon_pearl) {
-    link_is_bunny = 0;
-    link_auxiliary_state = 0;
-  }
-  link_animation_steps = 0;
-  link_is_transforming = 0;
-  link_cant_change_direction = 0;
-  Link_ResetSwimmingState();
-  link_player_handler_state = kPlayerState_RecoilWall;
-  if (link_item_moon_pearl) {
-    link_player_handler_state = kPlayerState_Ground;
-    LoadActualGearPalettes();
-  }
-}
-
-void Link_TempBunny_Func2() {  // 8783fa
-  if (link_incapacitated_timer != 0) {
-    Link_HandleRecoilAndTimer(false);
-    return;
-  }
-  link_z_coord = 0xffff;
-  link_actual_vel_z = 0xff;
-  link_recoilmode_timer = 0;
-  if (link_flag_moving) {
-    swimcoll_var9[0] = swimcoll_var9[1] = 0x180;
-    Link_HandleSwimMovements();
-    return;
-  }
-
-  ResetAllAcceleration();
-  Link_HandleYItem();
-  uint8 dir;
-  if (!(dir = force_move_any_direction & 0xf) && !(dir = joypad1H_last & kJoypadH_AnyDir)) {
-    link_x_vel = link_y_vel = 0;
-    link_direction = link_direction_last = 0;
-    link_animation_steps = 0;
-    bitmask_of_dragstate &= ~9;
-    link_timer_push_get_tired = 32;
-    link_timer_jump_ledge = 19;
-  } else {
-    link_direction = dir;
-    if (dir != link_direction_last) {
-      link_direction_last = dir;
-      link_subpixel_x = 0;
-      link_subpixel_y = 0;
-      link_moving_against_diag_tile = 0;
-      bitmask_of_dragstate = 0;
-      link_timer_push_get_tired = 32;
-      link_timer_jump_ledge = 19;
-    }
-  }
-  Link_HandleDiagonalCollision();
-  Link_HandleVelocity();
-  Link_HandleCardinalCollision();
-  Link_HandleMovingAnimation_FullLongEntry();
-  fallhole_var1 = 0;
-  HandleIndoorCameraAndDoors();
-}
-
-void LinkState_HoldingBigRock() {  // 878481
-  if (link_auxiliary_state) {
-    link_item_in_hand = 0;
-    link_position_mode = 0;
-    link_debug_value_1 = 0;
-    link_debug_value_2 = 0;
-    link_var30d = 0;
-    link_var30e = 0;
-    some_animation_timer_steps = 0;
-    bitfield_for_a_button = 0;
-    link_state_bits = 0;
-    link_picking_throw_state = 0;
-    link_grabbing_wall = 0;
-    bitmask_of_dragstate = 0;
-    link_cant_change_direction &= ~1;
-    link_z_coord &= ~0xff;
-    if (link_electrocute_on_touch) {
-      Link_ResetSwordAndItemUsage();
-      link_disable_sprite_damage = 1;
-      player_handler_timer = 0;
-      link_delay_timer_spin_attack = 2;
-      link_animation_steps = 0;
-      link_direction &= ~0xf;
-      Ancilla_Sfx3_Near(43);
-      link_player_handler_state = kPlayerState_Electrocution;
-      LinkState_Zapped();
-    } else {
-      link_player_handler_state = kPlayerState_RecoilWall;
-      LinkState_Recoil();
-    }
-    return;
-  }
-
-  link_z_coord = 0xffff;
-  link_actual_vel_z = 0xff;
-  link_recoilmode_timer = 0;
-  if (link_incapacitated_timer) {
-    link_var30d = 0;
-    link_var30e = 0;
-    some_animation_timer_steps = 0;
-    bitfield_for_a_button = 0;
-    link_state_bits = 0;
-    link_picking_throw_state = 0;
-    link_grabbing_wall = 0;
-    if (!(button_mask_b_y & 0x80))
-      link_cant_change_direction &= ~1;
-    Link_HandleRecoilAndTimer(false);
-    return;
-  }
-
-  Link_HandleAPress();
-  if (!(joypad1H_last & kJoypadH_AnyDir)) {
-    link_y_vel = 0;
-    link_x_vel = 0;
-    link_direction = 0;
-    link_direction_last = 0;
-    link_animation_steps = 0;
-    bitmask_of_dragstate &= ~9;
-    link_timer_push_get_tired = 32;
-    link_timer_jump_ledge = 19;
-  } else {
-    link_direction = joypad1H_last & kJoypadH_AnyDir;
-    if (link_direction != link_direction_last) {
-      link_direction_last = link_direction;
-      link_subpixel_x = 0;
-      link_subpixel_y = 0;
-      link_moving_against_diag_tile = 0;
-      bitmask_of_dragstate = 0;
-      link_timer_push_get_tired = 32;
-      link_timer_jump_ledge = 19;
-    }
-  }
-  Link_HandleMovingAnimation_FullLongEntry();
-  fallhole_var1 = 0;
-  HandleIndoorCameraAndDoors();
-}
-
-void EtherTablet_StartCutscene() {  // 87855a
-  button_b_frames = 0xc0;
-  link_delay_timer_spin_attack = 0;
-  link_player_handler_state = kPlayerState_ReceivingEther;
-  link_disable_sprite_damage = 1;
-  flag_block_link_menu = 1;
-}
-
-void LinkState_ReceivingEther() {  // 878570
-  link_auxiliary_state = 0;
-  link_incapacitated_timer = 0;
-  link_give_damage = 0;
-  int i = --WORD(button_b_frames);
-  if (sign16(i)) {
-    button_b_frames = 0;
-    link_delay_timer_spin_attack = 0;
-  } else if (i == 0xbf) {
-    link_force_hold_sword_up = 1;
-  } else if (i == 160) {
-    uint16 x = link_x_coord, y = link_y_coord;
-    link_x_coord = 0x6b0;
-    link_y_coord = 0x37;
-    AncillaAdd_EtherSpell(0x18, 0);
-    link_x_coord = x, link_y_coord = y;
-  } else if (i == 0) {
-    AncillaAdd_FallingPrize(0x29, 0, 4);
-    flag_is_link_immobilized = 1;
-    flag_block_link_menu = 0;
-  }
-}
-
-void BombosTablet_StartCutscene() {  // 8785e5
-  button_b_frames = 0xe0;
-  link_delay_timer_spin_attack = 0;
-  link_player_handler_state = kPlayerState_ReceivingBombos;
-  link_disable_sprite_damage = 1;
-  flag_custom_spell_anim_active = 1;
-}
-
-void LinkState_ReceivingBombos() {  // 8785fb
-  link_auxiliary_state = 0;
-  link_incapacitated_timer = 0;
-  link_give_damage = 0;
-  int i = --WORD(button_b_frames);
-  if (sign16(i)) {
-    button_b_frames = 0;
-    link_delay_timer_spin_attack = 0;
-  } else if (i == 223) {
-    link_force_hold_sword_up = 1;
-  } else if (i == 160) {
-    uint16 x = link_x_coord, y = link_y_coord;
-    link_x_coord = 0x378;
-    link_y_coord = 0xeb0;
-    AncillaAdd_BombosSpell(0x19, 0);
-    link_x_coord = x, link_y_coord = y;
-  } else if (i == 0) {
-    AncillaAdd_FallingPrize(0x29, 5, 4);
-    flag_is_link_immobilized = 1;
-  }
-}
-
-void LinkState_ReadingDesertTablet() {  // 87867b
-  if (!--button_b_frames) {
-    link_player_handler_state = kPlayerState_Ground;
-    Link_PerformDesertPrayer();
-  }
-}
-
-void HandleSomariaAndGraves() {  // 878689
-  if (!player_is_indoors && link_something_with_hookshot) {
-    int i = 4;
-    do {
-      if (ancilla_type[i] == 0x24)
-        Gravestone_Move(i);
-    } while (--i >= 0);
-  }
-  int i = 4;
-  do {
-    if (ancilla_type[i] == 0x2C) {
-      SomariaBlock_HandlePlayerInteraction(i);
-      return;
-    }
-  } while (--i >= 0);
-}
-
-void LinkState_Recoil() {  // 8786b5
-  link_y_coord_safe_return_lo = link_y_coord;
-  link_y_coord_safe_return_hi = link_y_coord >> 8;
-  link_x_coord_safe_return_lo = link_x_coord;
-  link_x_coord_safe_return_hi = link_x_coord >> 8;
-  Link_HandleChangeInZVelocity();
-  link_cant_change_direction = 0;
-  draw_water_ripples_or_grass = 0;
-  if (!sign8(link_z_coord) || !sign8(link_actual_vel_z)) {
-    Link_HandleRecoilAndTimer(false);
-    return;
-  }
-  TileDetect_MainHandler(5);
-  if (tiledetect_deepwater & 1) {
-    link_player_handler_state = kPlayerState_Swimming;
-    Link_SetToDeepWater();
-    Link_ResetSwordAndItemUsage();
-    AncillaAdd_Splash(21, 0);
-    Link_HandleRecoilAndTimer(true);
-  } else {
-    if (++link_recoilmode_timer != 4) {
-      uint8 t = link_actual_vel_z_copy, s = link_recoilmode_timer;
-      do {
-        t >>= 1;
-      } while (!--s); // wtf?
-      link_actual_vel_z = t;
-    } else {
-      link_recoilmode_timer = 3;
-    }
-    Link_HandleRecoilAndTimer(false);
-  }
-}
-
-void Link_HandleRecoilAndTimer(bool jump_into_middle) {  // 878711
-  if (jump_into_middle)
-    goto lbl_jump_into_middle;
-
-  link_x_page_movement_delta = 0;
-  link_y_page_movement_delta = 0;
-  link_num_orthogonal_directions = 0;
-  Link_HandleRecoiling();  // not
-  if (--link_incapacitated_timer == 0) {
-    link_incapacitated_timer = 1;
-    int8 z;
-    z = link_z_coord & 0xfe;
-    if (z <= 0 && (int8)link_actual_vel_z < 0) {
-      if (link_auxiliary_state != 0) {
-        link_disable_sprite_damage = 0;
-        scratch_0 = link_player_handler_state;
-        if (link_player_handler_state != 6) {
-          button_b_frames = 0;
-          button_mask_b_y = 0;
-          link_delay_timer_spin_attack = 0;
-          link_spin_attack_step_counter = 0;
-        }
-        Link_SplashUponLanding();
-        if (!link_is_bunny_mirror || !link_is_in_deep_water) {
-          if (link_want_make_noise_when_dashed) {
-            link_want_make_noise_when_dashed = 0;
-            Ancilla_Sfx2_Near(33);
-          } else if (scratch_0 != 2 && link_player_handler_state != 4) {
-            Ancilla_Sfx2_Near(33);
-          }
-          if (link_player_handler_state == 4) {
-            Link_ForceUnequipCape_quietly();
-            if (player_is_indoors && scratch_0 != 2 && link_item_flippers) {
-              link_is_on_lower_level = 1;
-            }
-            AncillaAdd_Splash(21, 0);
-          }
-          TileDetect_MainHandler(0);
-          if (tiledetect_thick_grass & 1)
-            Ancilla_Sfx2_Near(26);
-          if (tiledetect_shallow_water & 1 && sound_effect_1 != 36)
-            Ancilla_Sfx2_Near(28);
-
-          if (tiledetect_deepwater & 1) {
-            link_player_handler_state = kPlayerState_Swimming;
-            Link_SetToDeepWater();
-            Link_ResetSwordAndItemUsage();
-            AncillaAdd_Splash(21, 0);
-          }
-
-          // OMG something jumps to here...
-lbl_jump_into_middle:
-          if (link_is_on_lower_level == 2)
-            link_is_on_lower_level = 0;
-          if (about_to_jump_off_ledge)
-            Dungeon_HandleLayerChange();
-        }
-        link_z_coord = 0;
-        link_auxiliary_state = 0;
-        link_speed_setting = 0;
-        link_cant_change_direction = 0;
-        link_item_in_hand = 0;
-        link_position_mode = 0;
-        player_handler_timer = 0;
-        link_disable_sprite_damage = 0;
-        link_electrocute_on_touch = 0;
-        link_actual_vel_x = 0;
-        link_actual_vel_y = 0;
-      }
-      link_animation_steps = 0;
-      link_incapacitated_timer = 0;
-    }
-  }
-
-  if (link_player_handler_state != 5 && link_incapacitated_timer >= 33) {
-    if (!sign8(--byte_7E02C5))
-      goto timer_running;
-    byte_7E02C5 = link_incapacitated_timer >> 4;
-  }
-
-  Flag67WithDirections();
-  if (link_player_handler_state != 6) {
-    Link_HandleDiagonalCollision();  // not
-    if ((link_direction & 3) == 0)
-      link_actual_vel_x = 0;
-    if ((link_direction & 0xc) == 0)
-      link_actual_vel_y = 0;
-  }
-  Link_MovePosition(); // not
-timer_running:
-  if (link_player_handler_state != 6) {
-    Link_HandleCardinalCollision(); // not
-    fallhole_var1 = 0;
-  }
-  HandleIndoorCameraAndDoors();
-  if (BYTE(link_z_coord) == 0 || BYTE(link_z_coord) >= 0xe0) {
-    Player_TileDetectNearby();
-    if ((tiledetect_pit_tile & 0xf) == 0xf) {
-      link_player_handler_state = kPlayerState_FallingIntoHole;
-      link_speed_setting = 4;
-    }
-  }
-  HIBYTE(link_z_coord) = 0;
-}
-
-void LinkState_OnIce() {  // 878872
-  assert(0);
-}
-
-void Link_HandleChangeInZVelocity() {  // 878926
-  Player_ChangeZ(link_player_handler_state == kPlayerState_TurtleRock ? 1 : 2);
-}
-
-void Player_ChangeZ(uint8 zd) {  // 878932
-  if (sign8(link_actual_vel_z)) {
-    if (!(uint8)link_z_coord)
-      return;
-    if (sign8(link_z_coord)) {
-      link_z_coord = 0xffff;
-      link_actual_vel_z = 0xff;
-      return;
-    }
-  }
-  link_actual_vel_z -= zd;
-}
-
-void LinkHop_HoppingSouthOW() {  // 87894e
-  link_last_direction_moved_towards = 1;
-  link_cant_change_direction = 0;
-  link_actual_vel_x = 0;
-  link_actual_vel_y = 0;
-  draw_water_ripples_or_grass = 0;
-  if (!link_incapacitated_timer && !link_actual_vel_z_mirror) {
-    Ancilla_Sfx2_Near(32);
-    LinkHop_FindTileToLandOnSouth();
-    if (!player_is_indoors)
-      link_is_on_lower_level = 2;
-  }
-  link_actual_vel_z = link_actual_vel_z_mirror;
-  link_actual_vel_z_copy = link_actual_vel_z_copy_mirror;
-  link_z_coord = link_z_coord_mirror;
-  link_actual_vel_z -= 2;
-  Link_MovePosition();
-  if (sign8(link_actual_vel_z)) {
-    if (link_actual_vel_z < 0xa0)
-      link_actual_vel_z = 0xa0;
-    if (link_z_coord >= 0xfff0) {
-      link_z_coord = 0;
-      Link_SplashUponLanding();
-      // This is the place that caused the water walking bug after bonk, 
-      // player_near_pit_state was not reset.
-      if (player_near_pit_state)
-        link_player_handler_state = kPlayerState_FallingIntoHole;
-      if (link_player_handler_state != kPlayerState_Swimming &&
-          link_player_handler_state != kPlayerState_FallingIntoHole && !link_is_in_deep_water)
-        Ancilla_Sfx2_Near(33);
-      link_disable_sprite_damage = 0;
-      allow_scroll_z = 0;
-      link_auxiliary_state = 0;
-      link_actual_vel_z = 0xff;
-      link_z_coord = 0xffff;
-      link_incapacitated_timer = 0;
-      if (!player_is_indoors)
-        link_is_on_lower_level = 0;
-    } else {
-      link_y_vel = link_z_coord_mirror - link_z_coord;
-    }
-  } else {
-    link_y_vel = link_z_coord_mirror - link_z_coord;
-  }
-  link_actual_vel_z_mirror = link_actual_vel_z;
-  link_actual_vel_z_copy_mirror = link_actual_vel_z_copy;
-  link_z_coord_mirror = link_z_coord;
-}
-
-void LinkState_HandlingJump() {  // 878a05
-  link_actual_vel_z = link_actual_vel_z_mirror;
-  link_actual_vel_z_copy = link_actual_vel_z_copy_mirror;
-  BYTE(link_z_coord) = link_z_coord_mirror;
-  link_actual_vel_z -= 2;
-  Link_MovePosition();
-  if (sign8(link_actual_vel_z)) {
-    if (link_actual_vel_z < 0xa0)
-      link_actual_vel_z = 0xa0;
-    if ((uint8)link_z_coord >= 0xf0) {
-      link_z_coord = 0;
-      if (link_player_handler_state == kPlayerState_FallOfLeftRightLedge || link_player_handler_state == kPlayerState_JumpOffLedgeDiag) {
-        TileDetect_MainHandler(0);
-        if (tiledetect_deepwater & 1) {
-          link_player_handler_state = kPlayerState_Swimming;
-          Link_SetToDeepWater();
-          Link_ResetSwordAndItemUsage();
-          AncillaAdd_Splash(21, 0);
-        } else if (tiledetect_pit_tile & 1) {
-          byte_7E005C = 9;
-          link_this_controls_sprite_oam = 0;
-          player_near_pit_state = 1;
-          link_player_handler_state = kPlayerState_FallingIntoHole;
-          goto after_pit;
-        }
-      }
-      Link_SplashUponLanding();
-      if (link_player_handler_state != kPlayerState_Swimming && !link_is_in_deep_water)
-        Ancilla_Sfx2_Near(33);
-after_pit:
-      if (link_player_handler_state != kPlayerState_Swimming || !link_is_bunny_mirror)
-        link_disable_sprite_damage = 0;
-
-      allow_scroll_z = 0;
-      link_auxiliary_state = 0;
-      link_actual_vel_z = 0xff;
-      link_z_coord = 0xffff;
-      link_incapacitated_timer = 0;
-      if (!player_is_indoors)
-        link_is_on_lower_level = 0;
-    } else {
-      link_y_vel = link_z_coord_mirror - link_z_coord;
-    }
-  } else {
-    link_y_vel = link_z_coord_mirror - link_z_coord;
-  }
-  link_actual_vel_z_mirror = link_actual_vel_z;
-  link_actual_vel_z_copy_mirror = link_actual_vel_z_copy;
-  BYTE(link_z_coord_mirror) = link_z_coord;
-}
-
-void LinkHop_FindTileToLandOnSouth() {  // 878ad1
-  link_y_coord_original = link_y_coord;
-  link_y_vel = link_y_coord - link_y_coord_safe_return_lo;
-  for (;;) {
-    link_y_coord += kLink_DoMoveXCoord_Outdoors_Helper2_y[link_last_direction_moved_towards];
-    TileDetect_Movement_Y(link_last_direction_moved_towards);
-    uint8 k = tiledetect_normal_tiles | tiledetect_pit_tile | tiledetect_destruction_aftermath | tiledetect_thick_grass | tiledetect_deepwater;
-    if ((k & 7) == 7)
-      break;
-  }
-  if (tiledetect_deepwater & 7) {
-    link_is_in_deep_water = 1;
-    if (link_auxiliary_state != 4)
-      link_auxiliary_state = 2;
-    link_some_direction_bits = link_direction_last;
-    Link_ResetSwimmingState();
-    link_grabbing_wall = 0;
-    link_speed_setting = 0;
-  }
-  if (tiledetect_pit_tile & 7) {
-    byte_7E005C = 9;
-    link_this_controls_sprite_oam = 0;
-    player_near_pit_state = 1;
-  }
-  link_y_coord += kLink_DoMoveXCoord_Outdoors_Helper2_y2[link_last_direction_moved_towards];
-  link_y_coord_safe_return_lo = link_y_coord;
-  link_y_coord_safe_return_hi = link_y_coord >> 8;
-  link_incapacitated_timer = 1;
-  uint8 z = link_z_coord;
-  if (z >= 0xf0)
-    z = 0;
-  link_z_coord = link_z_coord_mirror = link_y_coord - link_y_coord_original + z;
-}
-
-// used on right ledges
-void LinkState_HoppingHorizontallyOW() {  // 878b74
-  link_direction = sign8(link_actual_vel_x) ? 6 : 5;
-  link_cant_change_direction = 0;
-  link_actual_vel_y = 0;
-  draw_water_ripples_or_grass = 0;
-  LinkState_HandlingJump();
-}
-
-void Link_HoppingHorizontally_FindTile_Y() {  // 878b9b
-  link_y_coord_original = link_y_coord;
-  link_y_vel = link_y_coord - link_y_coord_safe_return_lo;
-
-  link_y_coord += kLink_DoMoveXCoord_Outdoors_Helper2_y[link_last_direction_moved_towards];
-  TileDetect_Movement_Y(link_last_direction_moved_towards);
-
-  uint8 tt = tiledetect_normal_tiles | tiledetect_destruction_aftermath | tiledetect_thick_grass |
-    tiledetect_deepwater;
-
-  if ((tt & 7) != 7) {
-    link_y_coord = link_y_coord_original;
-    link_incapacitated_timer = 1;
-
-    int8 velx = link_actual_vel_x, org_velx = velx;
-    if (velx < 0) velx = -velx;
-    velx >>= 4;
-    link_actual_vel_z_mirror = link_actual_vel_z_copy_mirror = kLink_DoMoveXCoord_Outdoors_Helper2_velz[velx];
-
-    uint8 xt = kLink_DoMoveXCoord_Outdoors_Helper2_velx[velx];
-    if (org_velx < 0) xt = -xt;
-    link_actual_vel_x = xt;
-  } else {  // else_1
-    link_y_coord += kLink_DoMoveXCoord_Outdoors_Helper2_y2[link_last_direction_moved_towards];
-    link_y_coord_safe_return_lo = link_y_coord;
-    link_y_coord_safe_return_hi = link_y_coord >> 8;
-    link_incapacitated_timer = 1;
-    uint8 z = link_z_coord;
-    if (z == 255) z = 0;
-    link_z_coord_mirror = link_z_coord = link_y_coord - link_y_coord_original + z;
-  }  // endif_1
-
-  if (tiledetect_deepwater & 7) {
-    link_auxiliary_state = 2;
-    Link_SetToDeepWater();
-  }
-}
-
-void Link_SetToDeepWater() {  // 878c44
-  link_is_in_deep_water = 1;
-  link_some_direction_bits = link_direction_last;
-  Link_ResetSwimmingState();
-  link_grabbing_wall = 0;
-  link_speed_setting = 0;
-}
-
-void LinkState_0F() {  // 878c69
-  assert(0);
-}
-
-uint8 Link_HoppingHorizontally_FindTile_X(uint8 o) {  // 878d2b
-  assert(o == 0 || o == 2);
-  link_y_coord_original = link_x_coord;
-  int i = 7;
-  static const int8 kLink_DoMoveXCoord_Outdoors_Helper1_tab1[2] = { -8, 8 };
-  static const int8 kLink_DoMoveXCoord_Outdoors_Helper1_tab2[2] = { -32, 32 };
-  static const int8 kLink_DoMoveXCoord_Outdoors_Helper1_tab3[2] = { -16, 16 };
-  static const uint8 kLink_DoMoveXCoord_Outdoors_Helper1_velx[24] = { 20, 20, 20, 24, 24, 24, 24, 28, 28, 36, 36, 36, 36, 36, 36, 38, 38, 38, 38, 38, 38, 38, 40, 40 };
-  static const uint8 kLink_DoMoveXCoord_Outdoors_Helper1_velz[24] = { 20, 20, 20, 20, 20, 20, 20, 24, 24, 32, 32, 32, 36, 36, 36, 38, 38, 38, 38, 38, 38, 38, 40, 40 };
-  do {
-    link_x_coord += kLink_DoMoveXCoord_Outdoors_Helper1_tab1[o >> 1];
-    TileDetect_Movement_X(link_last_direction_moved_towards);
-
-    uint8 tt = tiledetect_normal_tiles | tiledetect_destruction_aftermath | tiledetect_thick_grass |
-      tiledetect_deepwater | tiledetect_pit_tile;
-
-    if ((tt & 7) == 7) {
-      if ((tiledetect_deepwater & 7) == 7) {
-        link_is_in_deep_water = 1;
-        link_auxiliary_state = 2;
-        link_some_direction_bits = link_direction_last;
-        swimming_countdown = 0;
-        link_speed_setting = 0;
-        link_grabbing_wall = 0;
-        ResetAllAcceleration();
-      }
-      goto finish;
-    }
-  } while (--i >= 0);
-
-  link_x_coord = link_y_coord_original + kLink_DoMoveXCoord_Outdoors_Helper1_tab2[o >> 1];
-finish:
-  link_x_coord += kLink_DoMoveXCoord_Outdoors_Helper1_tab3[o >> 1];
-  int16 xt = link_y_coord_original - link_x_coord;
-  if (xt < 0) xt = -xt;
-  xt >>= 3;
-  uint8 velx = kLink_DoMoveXCoord_Outdoors_Helper1_velx[xt];
-  if (o != 2) velx = -velx;
-  link_actual_vel_x = velx;
-  link_actual_vel_z_mirror = link_actual_vel_z_copy_mirror = kLink_DoMoveXCoord_Outdoors_Helper1_velz[xt];
-
-  return i;
-}
-
-// used on diag ledges
-void LinkState_HoppingDiagonallyUpOW() {  // 878dc6
-  draw_water_ripples_or_grass = 0;
-  Player_ChangeZ(2);
-  Link_MovePosition();
-  if (sign8(link_z_coord)) {
-    Link_SplashUponLanding();
-    if (link_player_handler_state != kPlayerState_Swimming && !link_is_in_deep_water)
-      Ancilla_Sfx2_Near(33);
-    link_disable_sprite_damage = 0;
-    link_auxiliary_state = 0;
-    link_actual_vel_z = 0xff;
-    link_z_coord = 0xffff;
-    link_incapacitated_timer = 0;
-    link_cant_change_direction = 0;
-  }
-}
-
-void LinkState_HoppingDiagonallyDownOW() {  // 878e15
-  uint8 dir = sign8(link_actual_vel_x) ? 2 : 3;
-  link_last_direction_moved_towards = dir;
-  link_cant_change_direction = 0;
-  link_actual_vel_y = 0;
-  draw_water_ripples_or_grass = 0;
-  if (!link_incapacitated_timer && !link_actual_vel_z_mirror) {
-    link_last_direction_moved_towards = 1;
-    uint16 old_x = link_x_coord;
-    Ancilla_Sfx2_Near(32);
-    LinkHop_FindLandingSpotDiagonallyDown();
-    link_x_coord = old_x;
-
-    static const uint8 kLedgeVelX[] = { 
-      4, 4, 4, 10, 10, 10, 11, 18,
-      18, 18, 20, 20, 20, 20, 22, 22,
-      26, 26, 26, 26, 28, 28, 28, 28
-    };
-
-    int t = (uint16)(link_y_coord - link_y_coord_original);
-    // Fix out of bounds read
-    int8 velx = kLedgeVelX[IntMin(t >> 3, 23)];
-    link_actual_vel_x = (dir != 2) ? velx : -velx;
-    if (!player_is_indoors)
-      link_is_on_lower_level = 2;
-  }
-  LinkState_HandlingJump();
-}
-
-void LinkHop_FindLandingSpotDiagonallyDown() {  // 878e7b
-  static const int8 kLink_Ledge_Func1_dx[2] = { -8, 8 };
-  static const int8 kLink_Ledge_Func1_dy[2] = { -9, 9 };
-  static const uint8 kLink_Ledge_Func1_bits[2] = { 6, 3 };
-  static const int8 kLink_Ledge_Func1_dy2[2] = { -24, 24 };
-  link_y_coord_original = link_y_coord;
-  link_y_vel = link_y_coord - link_y_coord_safe_return_lo;
-
-  uint8 scratch;
-  for (;;) {
-    int o = sign8(link_actual_vel_x) ? 0 : 1;
-
-    link_x_coord += kLink_Ledge_Func1_dx[o];
-    link_y_coord += kLink_Ledge_Func1_dy[link_last_direction_moved_towards];
-    TileDetect_Movement_Y(link_last_direction_moved_towards);
-    scratch = kLink_Ledge_Func1_bits[o];
-    uint8 k = tiledetect_normal_tiles | tiledetect_destruction_aftermath | tiledetect_thick_grass | tiledetect_deepwater;
-    if ((k & scratch) == scratch)
-      break;
-  }
-
-  if (tiledetect_deepwater & scratch) {
-    link_is_in_deep_water = 1;
-    link_auxiliary_state = 2;
-    link_some_direction_bits = link_direction_last;
-    Link_ResetSwimmingState();
-    link_speed_setting = 0;
-    link_grabbing_wall = 0;
-  }
-
-  link_y_coord += kLink_Ledge_Func1_dy2[link_last_direction_moved_towards];
-  link_y_coord_safe_return_lo = link_y_coord;
-  link_y_coord_safe_return_hi = link_y_coord >> 8;
-  link_incapacitated_timer = 1;
-  link_z_coord_mirror = link_y_coord - link_y_coord_original + (uint8)link_z_coord;
-  link_z_coord = link_z_coord_mirror;
-}
-
-void Link_SplashUponLanding() {  // 878f1d
-  if (link_is_bunny_mirror) {
-    if (link_is_in_deep_water) {
-      AncillaAdd_Splash(21, 0);
-      LinkState_Bunny_recache();
-      return;
-    }
-    link_player_handler_state = (link_item_moon_pearl) ? kPlayerState_TempBunny : kPlayerState_PermaBunny;
-  } else if (link_is_in_deep_water) {
-    if (link_player_handler_state != kPlayerState_RecoilOther)
-      AncillaAdd_Splash(21, 0);
-    Link_ForceUnequipCape_quietly();
-    link_player_handler_state = kPlayerState_Swimming;
-  } else {
-    link_player_handler_state = kPlayerState_Ground;
-  }
-}
-
-void LinkState_Dashing() {  // 878f86
-  CacheCameraPropertiesIfOutdoors();
-  if (Link_HandleBunnyTransformation()) {
-    if (link_player_handler_state == 23)
-      PlayerHandler_17_Bunny();
-    return;
-  }
-  if (!link_is_running) {
-    link_disable_sprite_damage = 0;
-    link_countdown_for_dash = 0;
-    link_speed_setting = 0;
-    link_player_handler_state = kPlayerState_Ground;
-    link_cant_change_direction = 0;
-    return;
-  }
-
-  if (button_mask_b_y & 0x80) {
-    if (button_b_frames >= 9)
-      button_b_frames = 9;
-  }
-  fallhole_var2 = 0;
-
-  if (link_auxiliary_state) {
-    link_disable_sprite_damage = 0;
-    link_countdown_for_dash = 0;
-    link_speed_setting = 0;
-    link_cant_change_direction = 0;
-    link_is_running = 0;
-    bitmask_of_dragstate = 0;
-    if (link_electrocute_on_touch) {
-      if (link_cape_mode)
-        Link_ForceUnequipCape_quietly();
-      Link_ResetSwordAndItemUsage();
-      link_disable_sprite_damage = 1;
-      player_handler_timer = 0;
-      link_delay_timer_spin_attack = 2;
-      link_animation_steps = 0;
-      link_direction &= ~0xf;
-      Ancilla_Sfx3_Near(43);
-      link_player_handler_state = kPlayerState_Electrocution;
-      LinkState_Zapped();
-    } else {
-      link_player_handler_state = kPlayerState_RecoilWall;
-      LinkState_Recoil();
-    }
-    return;
-  }
-  static const uint8 kDashTab1[] = { 7, 15, 15 };
-  static const uint8 kDashTab2[] = { 8, 4, 2, 1 };
-  uint8 a = link_countdown_for_dash;
-  if (a == 0)
-    a = index_of_dashing_sfx--;
-  if (!(kDashTab1[link_countdown_for_dash >> 4] & a))
-    Ancilla_Sfx2_Near(35);
-  if (sign8(--link_countdown_for_dash)) {
-    link_countdown_for_dash = 0;
-    if (follower_indicator == kTagalongArr1[follower_indicator])
-      follower_indicator = kTagalongArr2[follower_indicator];
-  } else {
-    index_of_dashing_sfx = 0;
-    if (!(joypad1L_last & kJoypadL_A)) {
-      link_animation_steps = 0;
-      link_countdown_for_dash = 0;
-      link_speed_setting = 0;
-      link_player_handler_state = kPlayerState_Ground;
-      link_is_running = 0;
-      if (!(button_mask_b_y & 0x80))
-        link_cant_change_direction = 0;
-      return;
-    }
-    AncillaAdd_DashDust_charging(30, 0);
-    link_x_vel = link_y_vel = 0;
-    link_dash_ctr = 64;
-    link_speed_setting = 16;
-    uint8 dir;
-    if (button_mask_b_y & 0x80 || is_standing_in_doorway || (dir = joypad1H_last & kJoypadH_AnyDir) == 0)
-      dir = kDashTab2[link_direction_facing >> 1];
-    link_some_direction_bits = link_direction = link_direction_last = dir;
-    link_moving_against_diag_tile = 0;
-    Link_HandleMovingAnimation_FullLongEntry();
-    uint16 org_x = link_x_coord, org_y = link_y_coord;
-    link_y_coord_safe_return_lo = link_y_coord;
-    link_y_coord_safe_return_hi = link_y_coord >> 8;
-    link_x_coord_safe_return_lo = link_x_coord;
-    link_x_coord_safe_return_hi = link_x_coord >> 8;
-    Link_HandleMovingFloor();
-    Link_ApplyConveyor();
-    if (player_on_somaria_platform)
-      Link_HandleVelocityAndSandDrag(org_x, org_y);
-    link_y_vel = link_y_coord - link_y_coord_safe_return_lo;
-    link_x_vel = link_x_coord - link_x_coord_safe_return_lo;
-    Link_HandleCardinalCollision();
-    HandleIndoorCameraAndDoors();
-    return;
-  }
-
-  if (link_animation_steps >= 6)
-    link_animation_steps = 0;
-
-  link_dash_ctr--;
-  if (link_dash_ctr < 32)
-    link_dash_ctr = 32;
-
-  AncillaAdd_DashDust(30, 0);
-  link_spin_attack_step_counter = 0;
-
-  if ((uint8)(link_sword_type + 1) & 0xfe)
-    TileDetect_MainHandler(7);
-
-  if (sram_progress_indicator) {
-    button_mask_b_y |= 0x80;
-    button_b_frames = 9;
-  }
-
-  link_incapacitated_timer = 0;
-
-  bool want_stop_dash = false;
-
-  if (enhanced_features0 & kFeatures0_TurnWhileDashing) {
-    if (!(joypad1L_last & kJoypadL_A)) {
-      link_countdown_for_dash = 0x11;
-      want_stop_dash = true;
-    } else {
-      static const uint8 kDashCtrlsToDir[16] = { 0, 1, 2, 0, 4, 4, 4, 0, 8, 8, 8, 0, 0, 0, 0, 0 };
-      uint8 t = kDashCtrlsToDir[joypad1H_last & kJoypadH_AnyDir];
-      if (t != 0 && t != link_direction_last) {
-        link_direction = link_direction_last = t;
-        link_some_direction_bits = t;
-        Link_HandleMovingAnimation_FullLongEntry();
-      }
-    }
-  } else {
-    want_stop_dash = (joypad1H_last & kJoypadH_AnyDir) && (joypad1H_last & kJoypadH_AnyDir) != kDashTab2[link_direction_facing >> 1];
-  }
-
-  if (want_stop_dash) {
-    link_player_handler_state = kPlayerState_StopDash;
-    button_mask_b_y &= ~0x80;
-    button_b_frames = 0;
-    link_delay_timer_spin_attack = 0;
-    LinkState_ExitingDash();
-    return;
-  }
-
-  if (link_speed_setting == 0 && (enhanced_features0 & kFeatures0_TurnWhileDashing))
-    link_speed_setting = 16;
-
-  uint8 dir = force_move_any_direction & 0xf;
-  if (dir == 0)
-    dir = kDashTab2[link_direction_facing >> 1];
-  link_direction = link_direction_last = dir;
-  Link_HandleDiagonalCollision();
-  Link_HandleVelocity();
-  Link_HandleCardinalCollision();
-  Link_HandleMovingAnimation_FullLongEntry();
-  fallhole_var1 = 0;
-  HandleIndoorCameraAndDoors();
-}
-
-void LinkState_ExitingDash() {  // 87915e
-  CacheCameraPropertiesIfOutdoors();
-  if (joypad1H_last & kJoypadH_AnyDir || link_countdown_for_dash >= 16) {
-    link_countdown_for_dash = 0;
-    link_speed_setting = 0;
-    link_player_handler_state = kPlayerState_Ground;
-    link_is_running = 0;
-    swimcoll_var5[0] &= 0xff00;
-    if (button_b_frames < 9)
-      link_cant_change_direction = 0;
-  } else {
-    link_countdown_for_dash++;
-  }
-  Link_HandleMovingAnimation_FullLongEntry();
-}
-
-void Link_CancelDash() {  // 879195
-  if (link_is_running) {
-    int i = 4;
-    do {
-      if (ancilla_type[i] == 0x1e)
-        ancilla_type[i] = 0;
-    } while (--i >= 0);
-    link_countdown_for_dash = 0;
-    link_speed_setting = 0;
-    link_is_running = 0;
-    link_cant_change_direction = 0;
-    swimcoll_var5[0] = 0;
-  }
-}
-
-void RepelDash() {  // 8791f1
-  if (link_is_running && link_dash_ctr != 64) {
-    Link_ResetSwimmingState();
-    AncillaAdd_DashTremor(29, 1);
-    Prepare_ApplyRumbleToSprites();
-    if ((sound_effect_2 & 0x3f) != 27 && (sound_effect_2 & 0x3f) != 50)
-      Ancilla_Sfx3_Near(3);
-    LinkApplyTileRebound();
-  }
-}
-
-void LinkApplyTileRebound() {  // 879222
-  static const int8 kDashTab6Y[] = { 24, -24, 0, 0 };
-  static const int8 kDashTab6X[] = { 0, 0, 24, -24 };
-  static const int8 kDashTabSw11Y[] = { 1, 0, 0, 0 };
-  static const int8 kDashTabSw11X[] = { 0, 0, 1, 0 };
-  static const uint16 kDashTabSw7Y[] = { 384, 384, 0, 0, 256, 256, 0, 0 };
-  static const uint16 kDashTabSw7X[] = { 0, 0, 384, 384, 0, 0, 256, 256 };
-  static const uint8 kDashTabDir[] = { 8,4,2,1 };
-
-  link_actual_vel_y = kDashTab6Y[link_last_direction_moved_towards];
-  link_actual_vel_x = kDashTab6X[link_last_direction_moved_towards];
-  link_incapacitated_timer = 24;
-  link_actual_vel_z = link_actual_vel_z_copy = 36;
-  if (link_flag_moving) {
-    link_some_direction_bits = link_direction = kDashTabDir[link_last_direction_moved_towards];
-    swimcoll_var11[0] = kDashTabSw11Y[link_last_direction_moved_towards];
-    swimcoll_var11[1] = kDashTabSw11X[link_last_direction_moved_towards];
-
-    int i = (link_flag_moving - 1) * 4 + link_last_direction_moved_towards;
-    swimcoll_var7[0] = kDashTabSw7Y[i];
-    swimcoll_var7[1] = kDashTabSw7X[i];
-  }
-  link_auxiliary_state = 1;
-  link_want_make_noise_when_dashed = 1;
-  BYTE(scratch_1) = 0;
-  link_electrocute_on_touch = 0;
-  link_speed_setting = 0;
-  link_cant_change_direction = 0;
-  link_moving_against_diag_tile = 0;
-  if (link_last_direction_moved_towards & 2)
-    link_y_vel = 0;
-  else
-    link_x_vel = 0;
-}
-
-void Sprite_RepelDash() {  // 879291
-  link_last_direction_moved_towards = link_direction_facing >> 1;
-  RepelDash();
-}
-
-void Flag67WithDirections() {  // 8792a0
-  link_direction = 0;
-  if (link_actual_vel_y)
-    link_direction |= sign8(link_actual_vel_y) ? 8 : 4;
-  if (link_actual_vel_x)
-    link_direction |= sign8(link_actual_vel_x) ? 2 : 1;
-}
-
-void LinkState_Pits() {  // 8792d3
-  link_direction = 0;
-  if (fallhole_var1 && ++fallhole_var2 == 0x20) {
-    fallhole_var2 = 31;
-  } else {
-    if (!link_is_running)
-      goto aux_state;
-    // If you use a turbo controller to perfectly spam the dash button,
-    // the check for Link being in a hole is endlessly skipped and you
-    // can levitate across chasms.
-    // Fix this by ensuring that the dash button is held down before proceeding to the dash state.
-    if (link_countdown_for_dash &&
-        (!(enhanced_features0 & kFeatures0_MiscBugFixes) || (joypad1L_last & kJoypadL_A))) {
-      LinkState_Dashing();
-      return;
-    }
-    if (joypad1H_last & kJoypadH_AnyDir && !(joypad1H_last & kJoypadH_AnyDir & link_direction)) {
-      Link_CancelDash();
-aux_state:
-      if (link_auxiliary_state != 1)
-        link_direction = joypad1H_last & kJoypadH_AnyDir;
-    }
-  }
-  TileDetect_MainHandler(4);
-  if (!(tiledetect_pit_tile & 1)) {
-    // Reset player_near_pit_state if we're no longer near a hole.
-    // This fixes a bug where you could walk on water
-    if (enhanced_features0 & kFeatures0_MiscBugFixes)
-      player_near_pit_state = 0;
-
-    if (link_is_running) {
-      LinkState_Dashing();
-      return;
-    }
-    link_speed_setting = 0;
-    Link_CancelDash();
-    if (!(button_mask_b_y & 0x80))
-      link_cant_change_direction &= ~1;
-    player_near_pit_state = 0;
-    link_player_handler_state = !link_is_bunny_mirror ? kPlayerState_Ground :
-      link_item_moon_pearl ? kPlayerState_TempBunny : kPlayerState_PermaBunny;
-    if (link_player_handler_state == kPlayerState_PermaBunny)
-      PlayerHandler_17_Bunny();
-    else if (link_player_handler_state == kPlayerState_TempBunny)
-      LinkState_TemporaryBunny();
-    else
-      LinkState_Default();
-    return;
-  }
-
-  Player_TileDetectNearby();
-  link_speed_setting = 4;
-  if (!(tiledetect_pit_tile & 0xf)) {
-    player_near_pit_state = 0;
-    link_speed_setting = 0;
-    link_player_handler_state = !link_is_bunny_mirror ? kPlayerState_Ground :
-      link_item_moon_pearl ? kPlayerState_TempBunny : kPlayerState_PermaBunny;
-    Link_CancelDash();
-    if (!(button_mask_b_y & 0x80))
-      link_cant_change_direction &= ~1;
-    return;
-  }
-
-  static const uint8 kFallHolePitDirs[] = { 12, 3, 10, 5 };
-  static const uint8 kFallHoleDirs[] = { 5, 6, 9, 10, 4, 8, 1, 2 };
-  static const uint8 kFallHoleDirs2[] = { 10, 9, 6, 5, 8, 4, 2, 1 };
-
-  if ((tiledetect_pit_tile & 0xf) != 0xf) {
-    int i = 3;
-    do {
-      if ((tiledetect_pit_tile & 0xf) == kFallHolePitDirs[i]) {
-        i += 4;
-        goto endif_1;
-      }
-    } while (--i >= 0);
-
-    i = 3;
-    uint8 pit_tile;
-    pit_tile= tiledetect_pit_tile;
-    while (!(pit_tile & 1)) {
-      i -= 1;
-      pit_tile >>= 1;
-    }
-    assert(i >= 0);
-endif_1:
-    byte_7E02C9 = i;
-    if (link_direction & kFallHoleDirs[i]) {
-      link_direction_last = link_direction;
-      link_speed_setting = 6;
-      Link_HandleMovingAnimation_FullLongEntry();
-    } else {
-      uint8 old_dir = link_direction;
-      link_direction |= kFallHoleDirs2[byte_7E02C9];
-      if (old_dir)
-        Link_HandleMovingAnimation_FullLongEntry();
-    }
-    Link_HandleDiagonalCollision();
-    Link_HandleVelocity();
-    Link_HandleCardinalCollision();
-    ApplyLinksMovementToCamera();
-    return;
-  }
-
-  // Initiate fall down
-  if (player_near_pit_state != 2) {
-    if (link_item_moon_pearl) {
-      link_need_for_poof_for_transform = 0;
-      link_is_bunny = 0;
-      link_is_bunny_mirror = 0;
-      link_timer_tempbunny = 0;
-    }
-    link_direction = 0;
-    player_near_pit_state = 2;
-    link_disable_sprite_damage = 1;
-    button_mask_b_y = 0;
-    button_b_frames = 0;
-    link_item_in_hand = 0;
-    link_position_mode = 0;
-    link_incapacitated_timer = 0;
-    link_auxiliary_state = 0;
-    Ancilla_Sfx3_Near(31);
-  }
-
-  link_cant_change_direction = 0;
-  link_incapacitated_timer = 0;
-  link_z_coord = 0;
-  link_actual_vel_z = 0;
-  link_auxiliary_state = 0;
-  link_give_damage = 0;
-  link_is_transforming = 0;
-  Link_ForceUnequipCape_quietly();
-  link_disable_sprite_damage++;
-  if (!sign8(--byte_7E005C))
-    return;
-  uint8 x = ++link_this_controls_sprite_oam;
-  byte_7E005C = 9;
-  if (follower_indicator != 13 && x == 1)
-    tagalong_var5 = x;
-
-  if (x == 6) {
-    Link_CancelDash();
-    submodule_index = 7;
-    link_this_controls_sprite_oam = 6;
-    player_near_pit_state = 3;
-    link_visibility_status = 12;
-    link_speed_modifier = 16;
-    uint16 y = (uint8)(link_y_coord - BG2VOFS_copy2);
-    link_state_bits = 0;
-    link_picking_throw_state = 0;
-    link_grabbing_wall = 0;
-    some_animation_timer = 0;
-    if (player_is_indoors) {
-      BYTE(dungeon_room_index_prev) = dungeon_room_index;
-      Dungeon_FlagRoomData_Quadrants();
-      if (Dungeon_IsPitThatHurtsPlayer()) {
-        DungeonPitDoDamage();
-        return;
-      }
-    }
-    BYTE(dungeon_room_index_prev) = dungeon_room_index;
-    BYTE(dungeon_room_index) = dung_hdr_travel_destinations[0];
-    tiledetect_which_y_pos[0] = link_y_coord;
-    link_y_coord = link_y_coord - y - 0x10;
-    if (player_is_indoors) {
-      HandleLayerOfDestination();
-    } else {
-      if ((uint8)overworld_screen_index != 5) {
-        Overworld_GetPitDestination();
-        main_module_index = 17;
-        submodule_index = 0;
-        subsubmodule_index = 0;
-      } else {
-        TakeDamageFromPit();
-      }
-    }
-  }
-}
-
-void HandleLayerOfDestination() {  // 8794f1
-  link_is_on_lower_level_mirror = (dung_hdr_hole_teleporter_plane >= 1);
-  link_is_on_lower_level = (dung_hdr_hole_teleporter_plane >= 2);
-}
-
-void DungeonPitDoDamage() {  // 879502
-  submodule_index = 20;
-  link_health_current -= 8;
-  if (link_health_current >= 0xa8)
-    link_health_current = 0;
-}
-
-void HandleDungeonLandingFromPit() {  // 879520
-  LinkOam_Main();
-  link_x_coord_prev = link_x_coord;
-  link_y_coord_prev = link_y_coord;
-  if (submodule_index == 7)
-    link_visibility_status = 0;
-  if (!(frame_counter & 3) && ++link_this_controls_sprite_oam == 10)
-    link_this_controls_sprite_oam = 6;
-  link_direction = 4;
-  Link_HandleVelocity();
-  if (sign16(link_y_coord) && !sign16(tiledetect_which_y_pos[0])) {
-    if (!sign16(-link_y_coord + tiledetect_which_y_pos[0]))
-      return;
-  } else {
-    if (tiledetect_which_y_pos[0] >= link_y_coord)
-      return;
-  }
-  //exploration glitch could also be armed without quitting
-  //by jumping off a dungeon ledge into an access pit
-  if (enhanced_features0 & kFeatures0_MiscBugFixes) {
-    about_to_jump_off_ledge = 0;
-  }
-  link_y_coord = tiledetect_which_y_pos[0];
-  link_animation_steps = 0;
-  link_speed_modifier = 0;
-  link_this_controls_sprite_oam = 0;
-  player_near_pit_state = 0;
-  link_speed_setting = 0;
-  subsubmodule_index = 0;
-  submodule_index = 0;
-  link_disable_sprite_damage = 0;
-  if (follower_indicator != 0 && follower_indicator != 3) {
-    tagalong_var5 = 0;
-    if (follower_indicator == 13) {
-      follower_indicator = 0;
-      super_bomb_indicator_unk2 = 0;
-      super_bomb_indicator_unk1 = 0;
-      follower_dropped = 0;
-    } else {
-      Follower_Initialize();
-    }
-  }
-  TileDetect_MainHandler(0);
-  if (tiledetect_shallow_water & 1)
-    Ancilla_Sfx2_Near(0x24);
-  Player_TileDetectNearby();
-  if ((sound_effect_1 & 0x3f) != 0x24)
-    Ancilla_Sfx2_Near(0x21);
-
-  if (dung_hdr_collision_2 == 2 && (tiledetect_water_staircase & 0xf))
-    byte_7E0322 = 3;
-  if ((tiledetect_deepwater & 0xf) == 0xf) {
-    link_is_in_deep_water = 1;
-    link_some_direction_bits = link_direction_last;
-    Link_ResetSwimmingState();
-    link_is_on_lower_level = 1;
-    AncillaAdd_Splash(0x15, 1);
-    link_player_handler_state = kPlayerState_Swimming;
-    Link_ForceUnequipCape_quietly();
-    link_state_bits = 0;
-    link_picking_throw_state = 0;
-    link_grabbing_wall = 0;
-    link_speed_setting = 0;
-  } else {
-    link_player_handler_state = (tiledetect_pit_tile & 0xf) ? kPlayerState_FallingIntoHole : kPlayerState_Ground;
-  }
-}
-
-void PlayerHandler_04_Swimming() {  // 87963b
-  if (link_auxiliary_state) {
-    link_player_handler_state = kPlayerState_RecoilWall;
-    link_z_coord &= 0xff;
-    ResetAllAcceleration();
-    link_maybe_swim_faster = 0;
-    link_swim_hard_stroke = 0;
-    link_cant_change_direction &= ~1;
-    LinkState_Recoil();
-    return;
-  }
-
-  button_mask_b_y = 0;
-  button_b_frames = 0;
-  link_delay_timer_spin_attack = 0;
-  link_spin_attack_step_counter = 0;
-  link_state_bits = 0;
-  link_picking_throw_state = 0;
-  if (!link_item_flippers)
-    return;
-
-  if (!(swimcoll_var7[0] | swimcoll_var7[1])) {
-    if ((uint8)swimcoll_var5[0] != 2 && (uint8)swimcoll_var5[1] != 2)
-      ResetAllAcceleration();
-    link_animation_steps &= 1;
-    if (++link_counter_var1 >= 16) {
-      link_counter_var1 = 0;
-      byte_7E02CC = 0;
-      link_animation_steps = (link_animation_steps & 1) ^ 1;
-    }
-  } else {
-    if (++link_counter_var1 >= 8) {
-      link_counter_var1 = 0;
-      link_animation_steps = (link_animation_steps + 1) & 3;
-      byte_7E02CC = kSwimmingTab1[link_animation_steps];
-    }
-  }
-
-  if (!link_swim_hard_stroke) {
-    uint8 t;
-    if (!(swimcoll_var7[0] | swimcoll_var7[1]) || (t = ((filtered_joypad_L & kJoypadL_A) | filtered_joypad_H) & 0xc0) == 0) {
-      Link_HandleSwimMovements();
-      return;
-    }
-    link_swim_hard_stroke = t;
-    Ancilla_Sfx2_Near(37);
-    link_maybe_swim_faster = 1;
-    swimming_countdown = 7;
-    Link_HandleSwimAccels();
-  }
-  if (sign8(--swimming_countdown)) {
-    swimming_countdown = 7;
-    if (++link_maybe_swim_faster == 5) {
-      link_maybe_swim_faster = 0;
-      link_swim_hard_stroke &= ~0xC0;
-    }
-  }
-
-  Link_HandleSwimMovements();
-}
-
-void Link_HandleSwimMovements() {  // 879715
-  uint8 t;
-
-  if (!(t = force_move_any_direction & 0xf) && !(t = joypad1H_last & kJoypadH_AnyDir)) {
-    link_y_vel = link_x_vel = 0;
-    Link_FlagMaxAccels();
-    if (link_flag_moving) {
-      if (link_is_running) {
-        t = link_some_direction_bits;
-      } else {
-        if (!(swimcoll_var7[0] | swimcoll_var7[1])) {
-          bitmask_of_dragstate = 0;
-          Link_ResetSwimmingState();
-        }
-        goto out;
-      }
-    } else {
-      if (link_player_handler_state != kPlayerState_Swimming)
-        link_animation_steps = 0;
-      goto out;
-    }
-  }
-
-  if (t != link_some_direction_bits) {
-    link_some_direction_bits = t;
-    link_subpixel_x = link_subpixel_y = 0;
-    link_moving_against_diag_tile = 0;
-    bitmask_of_dragstate = 0;
-  }
-  Link_SetIceMaxAccel();
-  Link_SetMomentum();
-  Link_SetTheMaxAccel();
-out:
-  Link_HandleDiagonalCollision();
-  Link_HandleVelocity();
-  Link_HandleCardinalCollision();
-  Link_HandleMovingAnimation_FullLongEntry();
-  fallhole_var1 = 0;
-  HandleIndoorCameraAndDoors();
-}
-
-void Link_FlagMaxAccels() {  // 879785
-  if (!link_flag_moving)
-    return;
-  for (int i = 1; i >= 0; i--) {
-    if (swimcoll_var7[i]) {
-      swimcoll_var9[i] = swimcoll_var7[i];
-      swimcoll_var5[i] = 1;
-    }
-  }
-}
-
-void Link_SetIceMaxAccel() {  // 8797a6
-  if (!link_flag_moving)
-    return;
-  swimcoll_var9[0] = 0x180;
-  swimcoll_var9[1] = 0x180;
-}
-
-void Link_SetMomentum() {  // 8797c7
-  uint8 joy = joypad1H_last & kJoypadH_AnyDir;
-  uint8 mask = 12, bit = 8;
-  for (int i = 0; i < 2; i++, mask >>= 2, bit >>= 2) {
-    if (joy & mask) {
-      swimcoll_var3[i] = link_flag_moving ? kSwimmingTab2[link_flag_moving - 1] : 32;
-      if (((link_some_direction_bits | link_direction) & mask) == mask) {
-        swimcoll_var5[i] = 2;
-      } else {
-        swimcoll_var11[i] = (joy & bit) ? 0 : 1;
-        swimcoll_var5[i] = 0;
-      }
-      if (!swimcoll_var9[i])
-        swimcoll_var9[i] = 240;
-    }
-  }
-}
-
-void Link_ResetSwimmingState() {  // 87983a
-  swimming_countdown = 0;
-  link_swim_hard_stroke = 0;
-  link_maybe_swim_faster = 0;
-  ResetAllAcceleration();
-}
-
-void Link_ResetStateAfterDamagingPit() {  // 87984b
-  Link_ResetSwimmingState();
-  link_player_handler_state = link_is_bunny && !link_item_moon_pearl ?
-    kPlayerState_PermaBunny : kPlayerState_Ground;
-  link_direction_last = link_some_direction_bits;
-  link_is_in_deep_water = 0;
-  link_disable_sprite_damage = 0;
-  link_this_controls_sprite_oam = 0;
-  player_near_pit_state = 0;
-}
-
-void ResetAllAcceleration() {  // 879873
-  swimcoll_var1[0] = 0;
-  swimcoll_var1[1] = 0;
-  swimcoll_var3[0] = 0;
-  swimcoll_var3[1] = 0;
-  swimcoll_var5[0] = 0;
-  swimcoll_var5[1] = 0;
-  swimcoll_var7[0] = 0;
-  swimcoll_var7[1] = 0;
-  swimcoll_var9[0] = 0;
-  swimcoll_var9[1] = 0;
-}
-
-void Link_HandleSwimAccels() {  // 8798a8
-  static const  uint16 kSwimmingTab3[] = { 128, 160, 192, 224, 256, 288, 320, 352, 384 };
-  uint8 mask = 12;
-  for (int i = 0; i < 2; i++, mask >>= 2) {
-    if (joypad1H_last & mask) {
-      if (swimcoll_var7[i] && swimcoll_var9[i] >= 384) {
-        uint16 t;
-        for (int j = 0; j < 9 && (t = kSwimmingTab3[j]) < swimcoll_var7[i]; j++) {}
-        swimcoll_var9[i] = t;
-      } else {
-        uint16 t = swimcoll_var9[i];
-        if (t) {
-          t += 160;
-          if (t >= 384)
-            t = 384;
-          swimcoll_var9[i] = t;
-        } else {
-          swimcoll_var7[i] = 1;
-          swimcoll_var9[i] = 240;
-        }
-      }
-    }
-  }
-}
-
-void Link_SetTheMaxAccel() {  // 879903
-  if (link_flag_moving || link_swim_hard_stroke)
-    return;
-  uint8 mask = 12;
-  for (int i = 0; i < 2; i++, mask >>= 2) {
-    if ((joypad1H_last & mask) && swimcoll_var5[i] != 2) {
-      if (swimcoll_var1[i] || swimcoll_var7[i] >= 240 && swimcoll_var7[i] >= swimcoll_var9[i]) {
-        swimcoll_var5[i] = 0;
-        if (swimcoll_var7[i] >= 240) {
-          swimcoll_var1[i] = 1;
-          swimcoll_var5[i] = 1;
-        } else {
-          swimcoll_var9[i] = 240;
-          swimcoll_var1[i] = 0;
-        }
-      }
-    } else {
-      swimcoll_var9[i] = 240;
-      swimcoll_var1[i] = 0;
-    }
-  }
-}
-
-void LinkState_Zapped() {  // 87996c
-  CacheCameraPropertiesIfOutdoors();
-  LinkZap_HandleMosaic();
-  if (!sign8(--link_delay_timer_spin_attack))
-    return;
-  link_delay_timer_spin_attack = 2;
-  player_handler_timer++;
-  if (player_handler_timer & 1)
-    Palette_ElectroThemedGear();
-  else
-    LoadActualGearPalettes();
-  if (player_handler_timer == 8) {
-    player_handler_timer = 0;
-    link_player_handler_state = kPlayerState_Ground;
-    link_disable_sprite_damage = 0;
-    link_electrocute_on_touch = 0;
-    link_auxiliary_state = 0;
-    Player_SetCustomMosaicLevel(0);
-  }
-}
-
-void PlayerHandler_15_HoldItem() {  // 8799ac
-  // empty by design
-}
-
-void Link_ReceiveItem(uint8 item, int chest_position) {  // 8799ad
-  if (link_auxiliary_state) {
-    link_auxiliary_state = 0;
-    link_incapacitated_timer = 0;
-    countdown_for_blink = 0;
-    link_state_bits = 0;
-  }
-  link_receiveitem_index = item;
-  if (item == 0x3e)
-    Ancilla_Sfx3_Near(0x2e);
-  link_receiveitem_var1 = 0x60;
-  if (item_receipt_method == 0 || item_receipt_method == 3) {
-    link_state_bits = 0;
-    button_mask_b_y = 0;
-    bitfield_for_a_button = 0;
-    button_b_frames = 0;
-    link_speed_setting = 0;
-    link_cant_change_direction = 0;
-    link_item_in_hand = 0;
-    link_position_mode = 0;
-    player_handler_timer = 0;
-    link_player_handler_state = kPlayerState_HoldUpItem;
-    link_pose_for_item = 1;
-    link_disable_sprite_damage = 1;
-    if (item == 0x20)
-      link_pose_for_item = 2;
-  }
-  AncillaAdd_ItemReceipt(0x22, 4, chest_position);
-  if (item != 0x20 && item != 0x37 && item != 0x38 && item != 0x39)
-    Hud_RefreshIcon();
-  Link_CancelDash();
-}
-
-void Link_TuckIntoBed() {  // 879a2c
-  link_y_coord = 0x215a;
-  link_x_coord = 0x940;
-  link_player_handler_state = kPlayerState_AsleepInBed;
-  player_sleep_in_bed_state = 0;
-  link_pose_during_opening = 0;
-  link_countdown_for_dash = 3;
-  AncillaAdd_Blanket(0x20);
-}
-
-void LinkState_Sleeping() {  // 879a5a
-  switch (player_sleep_in_bed_state) {
-  case 0:
-    if (!(frame_counter & 0x1f))
-      AncillaAdd_Snoring(0x21, 1);
-    break;
-  case 1:
-    if (submodule_index == 0 && sign8(--link_countdown_for_dash)) {
-      link_countdown_for_dash = 0;
-      if (((filtered_joypad_H & 0xe0) | (filtered_joypad_H << 4) | filtered_joypad_L) & 0xf0) {
-        link_pose_during_opening++;
-        link_direction_facing = 6;
-        player_sleep_in_bed_state++;
-        link_countdown_for_dash = 4;
-      }
-    }
-    break;
-  case 2:
-    if (sign8(--link_countdown_for_dash)) {
-      link_actual_vel_y = 4;
-      link_actual_vel_x = 21;
-      link_actual_vel_z = 24;
-      link_actual_vel_z_copy = 24;
-      link_incapacitated_timer = 16;
-      link_auxiliary_state = 2;
-      link_player_handler_state = kPlayerState_RecoilOther;
-    }
-    break;
-  }
-}
-
-void Link_HandleSwordCooldown() {  // 879ac2
-  if (!sign8(--link_sword_delay_timer))
-    return;
-
-  link_sword_delay_timer = 0;
-  if (link_item_in_hand | link_position_mode)
-    return;
-
-  if (button_b_frames < 9) {
-    if (!link_is_running)
-      Link_CheckForSwordSwing();
-  } else {
-    HandleSwordControls();
-  }
-
-}
-
-void Link_HandleYItem() {  // 879b0e
-  if (button_b_frames && button_b_frames < 9)
-    return;
-
-  uint8 item = current_item_y;
-
-  if (link_is_bunny_mirror && (item != 11 && item != 20))
-    return;
-
-  if (is_archer_or_shovel_game && !link_is_bunny_mirror) {
-    if (is_archer_or_shovel_game == 2)
-      LinkItem_Bow();
-    else
-      LinkItem_Shovel();
-    return;
-  }
-
-  uint8 old_down = joypad1H_last, old_pressed = filtered_joypad_H, old_bottle = link_item_bottle_index;
-  if ((link_item_in_hand | link_position_mode) == 0 && !(old_down & kJoypadH_Y)) {
-    // Is any special key held down?
-    int btn_index = GetCurrentItemButtonIndex();
-    if (btn_index != 0) {
-      uint8 *cur_item_ptr = GetCurrentItemButtonPtr(btn_index);
-      if (*cur_item_ptr) {
-        if (*cur_item_ptr >= kHudItem_Bottle1)
-          link_item_bottle_index = *cur_item_ptr - kHudItem_Bottle1 + 1;
-        item = Hud_LookupInventoryItem(*cur_item_ptr);
-        // Pretend it's actually Y that's down
-        joypad1H_last = old_down | kJoypadH_Y;
-        static const uint8 kButtonIndexKeys[4] = { 0, kJoypadL_X, kJoypadL_L, kJoypadL_R };
-        filtered_joypad_H = old_pressed | ((filtered_joypad_L & kButtonIndexKeys[btn_index]) ? kJoypadH_Y : 0);
-      }
-    }
-  }
-
-  if (item != current_item_active) {
-    if (current_item_active == 8 && (link_item_flute & 2))
-      button_mask_b_y &= ~0x40;
-    if (current_item_active == 19 && link_cape_mode)
-      Link_ForceUnequipCape();
-  }
-
-
-  if ((link_item_in_hand | link_position_mode) == 0)
-    current_item_active = item;
-
-  if (current_item_active == 5 || current_item_active == 6)
-    eq_selected_rod = current_item_active - 5 + 1;
-
-  switch (current_item_active) {
-  case 0:
-    break;
-  case 1: LinkItem_Bombs(); break;
-  case 2: LinkItem_Boomerang(); break;
-  case 3: LinkItem_Bow(); break;
-  case 4: LinkItem_Hammer(); break;
-  case 5: LinkItem_Rod(); break;
-  case 6: LinkItem_Rod(); break;
-  case 7: LinkItem_Net(); break;
-  case 8: LinkItem_ShovelAndFlute(); break;
-  case 9: LinkItem_Lamp(); break;
-  case 10: LinkItem_Powder(); break;
-  case 11: LinkItem_Bottle(); break;
-  case 12: LinkItem_Book(); break;
-  case 13: LinkItem_CaneOfByrna(); break;
-  case 14: LinkItem_Hookshot(); break;
-  case 15: LinkItem_Bombos(); break;
-  case 16: LinkItem_Ether(); break;
-  case 17: LinkItem_Quake(); break;
-  case 18: LinkItem_CaneOfSomaria(); break;
-  case 19: LinkItem_Cape(); break;
-  case 20: LinkItem_Mirror(); break;
-  case 21: LinkItem_Shovel(); break;
-  default:
-    assert(0);
-  }
-
-  joypad1H_last = old_down;
-  filtered_joypad_H = old_pressed;
-  link_item_bottle_index = old_bottle;
-}
-
-void Link_HandleAPress() {  // 879baa
-  flag_is_sprite_to_pick_up_cached = 0;
-  if (link_item_in_hand || (link_position_mode & 0x1f) || byte_7E0379)
-    return;
-
-  if (button_b_frames < 9 && (button_mask_b_y & 0x80))
-    return;
-
-  uint8 action = tile_action_index;
-
-  if ((link_state_bits | link_grabbing_wall) == 0) {
-    if (!Link_CheckNewAPress()) {
-      bitfield_for_a_button = 0;
-      return;
-    }
-
-    if (link_need_for_pullforrupees_sprite && !link_direction_facing) {
-      action = 7;
-    } else if (link_is_near_moveable_statue) {
-      action = 6;
-    } else {
-      if (!flag_is_ancilla_to_pick_up) {
-        if (!flag_is_sprite_to_pick_up) {
-          action = Link_HandleLiftables();
-          goto attempt_action;
-        }
-        flag_is_sprite_to_pick_up_cached = flag_is_sprite_to_pick_up;
-      }
-
-      if (button_b_frames)
-        Link_ResetSwordAndItemUsage();
-
-      if (link_item_in_hand | link_position_mode) {
-        link_item_in_hand = 0;
-        link_position_mode = 0;
-        Link_ResetBoomerangYStuff();
-        flag_for_boomerang_in_place = 0;
-        if (ancilla_type[0] == 5)
-          ancilla_type[0] = 0;
-      }
-      action = 1;
-    }
-    static const uint8 kAbilityBitmasks[] = { 0xE0, 0x40, 4, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0 };
-attempt_action:
-    if (!(kAbilityBitmasks[action] & link_ability_flags)) {
-      bitfield_for_a_button = 0;
-      return;
-    }
-
-    tile_action_index = action;
-    Link_APress_PerformBasic(action * 2);
-  }
-
-  // actionInProgress
-  unused_2 = tile_action_index;
-  switch (tile_action_index) {
-  case 1: Link_APress_LiftCarryThrow(); break;
-  case 3: Link_APress_PullObject(); break;
-  case 6: Link_APress_StatueDrag(); break;
-  }
-}
-
-void Link_APress_PerformBasic(uint8 action_x2) {  // 879c5f
-  switch (action_x2 >> 1) {
-  case 0: Link_PerformDesertPrayer(); break;
-  case 1: Link_PerformThrow(); break;
-  case 2: Link_PerformDash(); break;
-  case 3: Link_PerformGrab(); break;
-  case 4: Link_PerformRead(); break;
-  case 5: Link_PerformOpenChest(); break;
-  case 6: Link_PerformStatueDrag(); break;
-  case 7: Link_PerformRupeePull(); break;
-  default:
-    assert(0);
-  }
-}
-
-void HandleSwordSfxAndBeam() {  // 879c66
-  link_direction &= ~0xf;
-  button_b_frames = 0;
-  link_spin_attack_step_counter = 0;
-
-  uint8 health = link_health_capacity - 4;
-  if (health < link_health_current && ((link_sword_type + 1) & 0xfe) && link_sword_type >= 2) {
-    int i = 4;
-    while (ancilla_type[i] != 0x31) {
-      if (--i < 0) {
-        AddSwordBeam(0);
-        break;
-      }
-    }
-  }
-  uint8 sword = link_sword_type - 1;
-  if (sword != 0xfe && sword != 0xff)
-    sound_effect_1 = kFireBeamSounds[sword] | Link_CalculateSfxPan();
-  link_delay_timer_spin_attack = 1;
-}
-
-void Link_CheckForSwordSwing() {  // 879cd9
-  if (bitfield_for_a_button & 0x10)
-    return;
-
-  if (!(button_mask_b_y & 0x80)) {
-    if (!(filtered_joypad_H & 0x80))
-      return;
-    if (is_standing_in_doorway) {
-      TileDetect_SwordSwingDeepInDoor(is_standing_in_doorway);
-      if ((R14 & 0x30) == 0x30)
-        return;
-    }
-    button_mask_b_y |= 0x80;
-    HandleSwordSfxAndBeam();
-    link_cant_change_direction |= 1;
-    link_animation_steps = 0;
-  }
-
-  if (!(joypad1H_last & kJoypadH_B))
-    button_mask_b_y |= 1;
-  HaltLinkWhenUsingItems();
-  link_direction &= ~0xf;
-  if (sign8(--link_delay_timer_spin_attack)) {
-    if (++button_b_frames >= 9) {
-      HandleSwordControls();
-      return;
-    }
-    link_delay_timer_spin_attack = kSpinAttackDelays[button_b_frames];
-    if (button_b_frames == 5) {
-      if (link_sword_type != 0 && link_sword_type != 1 && link_sword_type != 0xff)
-        AncillaAdd_SwordSwingSparkle(0x26, 4);
-      if (link_sword_type != 0 && link_sword_type != 0xff)
-        TileDetect_MainHandler(link_sword_type == 1 ? 1 : 6);
-    } else if (button_b_frames >= 4 && (button_mask_b_y & 1) && (joypad1H_last & kJoypadH_B)) {
-      button_mask_b_y &= ~1;
-      HandleSwordSfxAndBeam();
-      return;
-    }
-  }
-  CalculateSwordHitBox();
-}
-
-void HandleSwordControls() {  // 879d72
-  if (joypad1H_last & kJoypadH_B) {
-    Player_Sword_SpinAttackJerks_HoldDown();
-  } else {
-    if (link_spin_attack_step_counter < 48) {
-      Link_ResetSwordAndItemUsage();
-    } else {
-      Link_ResetSwordAndItemUsage();
-      link_spin_attack_step_counter = 0;
-      Link_ActivateSpinAttack();
-    }
-  }
-}
-
-void Link_ResetSwordAndItemUsage() {  // 879d84
-  link_speed_setting = 0;
-  bitmask_of_dragstate &= ~9;
-  link_delay_timer_spin_attack = 0;
-  button_b_frames = 0;
-  button_mask_b_y &= ~0x81;
-  link_cant_change_direction &= ~1;
-}
-
-void Player_Sword_SpinAttackJerks_HoldDown() {  // 879d9f
-  if ((bitmask_of_dragstate & 0x80) || (bitmask_of_dragstate & 9) == 0) {
-    if (set_when_damaging_enemies == 0) {
-      button_b_frames = 9;
-      link_cant_change_direction |= 1;
-      link_delay_timer_spin_attack = 0;
-      if (link_speed_setting != 4 && link_speed_setting != 16) {
-        link_speed_setting = 12;
-        if (!((uint8)(link_sword_type + 1) & ~1))
-          return;
-        int i = 4;
-        do {
-          if (ancilla_type[i] == 0x30 || ancilla_type[i] == 0x31)
-            return;
-        } while (--i >= 0);
-
-        if (link_spin_attack_step_counter >= 6 && (frame_counter & 3) == 0)
-          AncillaSpawn_SwordChargeSparkle();
-
-        if (link_spin_attack_step_counter < 64 && ++link_spin_attack_step_counter == 48) {
-          Ancilla_Sfx2_Near(55);
-          AncillaAdd_ChargedSpinAttackSparkle();
-        }
-      } else {
-        CalculateSwordHitBox();
-      }
-      return;
-    } else if (set_when_damaging_enemies == 1) {
-      Link_ResetSwordAndItemUsage();
-      return;
-    }
-  }
-  // endif_2
-  if (button_b_frames == 9) {
-    button_b_frames = 10;
-    link_delay_timer_spin_attack = kSpinAttackDelays[button_b_frames];
-  }
-
-  if (sign8(--link_delay_timer_spin_attack)) {
-    uint8 frames = button_b_frames + 1;
-    if (frames == 13) {
-      if ((uint8)(link_sword_type + 1) & ~1 && (bitmask_of_dragstate & 9)) {
-        AncillaAdd_WallTapSpark(27, 1);
-        Ancilla_Sfx2_Near((bitmask_of_dragstate & 8) ? 6 : 5);
-        TileDetect_MainHandler(1);
-      }
-      frames = 10;
-    }
-    button_b_frames = frames;
-    link_delay_timer_spin_attack = kSpinAttackDelays[button_b_frames];
-  }
-  CalculateSwordHitBox();
-}
-
-void LinkItem_Rod() {  // 879eef
-  static const uint8 kRodAnimDelays[] = { 3, 3, 5 };
-  if (!(button_mask_b_y & 0x40)) {
-    if (is_standing_in_doorway || !CheckYButtonPress())
-      return;
-    if (!LinkCheckMagicCost(0))
-      goto out;
-    link_debug_value_2 = 1;
-    if (eq_selected_rod == 1)
-      AncillaAdd_FireRodShot(2, 1);
-    else
-      AncillaAdd_IceRodShot(11, 1);
-    link_delay_timer_spin_attack = kRodAnimDelays[0];
-    link_animation_steps = 0;
-    player_handler_timer = 0;
-    link_item_in_hand = 1;
-  }
-  HaltLinkWhenUsingItems();
-  link_direction &= ~0xf;
-  if (!sign8(--link_delay_timer_spin_attack))
-    return;
-  player_handler_timer++;
-
-  link_delay_timer_spin_attack = kRodAnimDelays[player_handler_timer];
-  if (player_handler_timer != 3)
-    return;
-  link_debug_value_2 = 0;
-  link_speed_setting = 0;
-  player_handler_timer = 0;
-  link_delay_timer_spin_attack = 0;
-  link_item_in_hand &= ~1;
-out:
-  button_mask_b_y &= ~0x40;
-}
-
-void LinkItem_Hammer() {  // 879f7b
-  static const uint8 kHammerAnimDelays[] = { 3, 3, 16 };
-  if (link_item_in_hand & 0x10)
-    return;
-  if (!(button_mask_b_y & 0x40)) {
-    if (is_standing_in_doorway || !(filtered_joypad_H & kJoypadH_Y))
-      return;
-    button_mask_b_y |= 0x40;
-    link_delay_timer_spin_attack = kHammerAnimDelays[0];
-    link_cant_change_direction |= 1;
-    link_animation_steps = 0;
-    player_handler_timer = 0;
-    link_item_in_hand = 2;
-  }
-
-  HaltLinkWhenUsingItems();
-  link_direction &= ~0xf;
-  if (!sign8(--link_delay_timer_spin_attack))
-    return;
-  player_handler_timer++;
-
-  link_delay_timer_spin_attack = kHammerAnimDelays[player_handler_timer];
-  if (player_handler_timer == 1) {
-    TileDetect_MainHandler(3);
-    Ancilla_AddHitStars(22, 0);
-    if (sound_effect_1 == 0) {
-      Ancilla_Sfx2_Near(16);
-      SpawnHammerWaterSplash();
-    }
-  } else if (player_handler_timer == 3) {
-    player_handler_timer = 0;
-    link_delay_timer_spin_attack = 0;
-    button_mask_b_y &= ~0x40;
-    link_cant_change_direction &= ~1;
-    link_item_in_hand &= ~2;
-  }
-}
-
-void LinkItem_Bow() {  // 87a006
-  static const uint8 kBowDelays[] = { 3, 3, 8 };
-
-  if (!(button_mask_b_y & 0x40)) {
-    if (is_standing_in_doorway || !CheckYButtonPress())
-      return;
-    link_cant_change_direction |= 1;
-    link_delay_timer_spin_attack = kBowDelays[0];
-    link_animation_steps = 0;
-    player_handler_timer = 0;
-    link_item_in_hand = 16;
-  }
-  HaltLinkWhenUsingItems();
-  link_direction &= ~0xf;
-  if (!sign8(--link_delay_timer_spin_attack))
-    return;
-  player_handler_timer++;
-
-  link_delay_timer_spin_attack = kBowDelays[player_handler_timer];
-  if (player_handler_timer != 3)
-    return;
-
-  int obj = AncillaAdd_Arrow(9, link_direction_facing, 2, link_x_coord, link_y_coord);
-  if (obj >= 0) {
-    if (archery_game_arrows_left) {
-      archery_game_arrows_left--;
-      link_num_arrows += 2;
-    }
-    if (!archery_game_out_of_arrows && link_num_arrows) {
-      if (--link_num_arrows == 0)
-        Hud_RefreshIcon();
-    } else {
-      ancilla_type[obj] = 0;
-      Ancilla_Sfx2_Near(60);
-    }
-  }
-
-  player_handler_timer = 0;
-  link_delay_timer_spin_attack = 0;
-  button_mask_b_y &= ~0x40;
-  link_cant_change_direction &= ~1;
-  link_item_in_hand &= ~0x10;
-  if (button_b_frames >= 9)
-    button_b_frames = 9;
-}
-
-void LinkItem_Boomerang() {  // 87a0bb
-  if (!(button_mask_b_y & 0x40)) {
-    if (is_standing_in_doorway || !CheckYButtonPress() || flag_for_boomerang_in_place)
-      return;
-    link_animation_steps = 0;
-    link_item_in_hand = 0x80;
-    player_handler_timer = 0;
-    link_delay_timer_spin_attack = 7;
-
-    int s0 = AncillaAdd_Boomerang(5, 0);
-
-    if (button_b_frames >= 9) {
-      Link_ResetBoomerangYStuff();
-      return;
-    }
-
-    if (!s0) {
-      link_direction_last = joypad1H_last & kJoypadH_AnyDir;
-    } else {
-      link_cant_change_direction |= 1;
-    }
-  } else {
-    link_cant_change_direction |= 1;
-  }
-
-  if (link_item_in_hand) {
-    HaltLinkWhenUsingItems();
-    link_direction &= ~0xf;
-    if (!sign8(--link_delay_timer_spin_attack))
-      return;
-    link_delay_timer_spin_attack = 5;
-    if (++player_handler_timer != 2)
-      return;
-  }
-  Link_ResetBoomerangYStuff();
-}
-
-void Link_ResetBoomerangYStuff() {  // 87a11f
-  link_item_in_hand = 0;
-  player_handler_timer = 0;
-  link_delay_timer_spin_attack = 0;
-  button_mask_b_y &= ~0x40;
-  if (!(button_mask_b_y & 0x80))
-    link_cant_change_direction &= ~1;
-}
-
-void LinkItem_Bombs() {  // 87a138
-  if (is_standing_in_doorway || follower_indicator == 13 || !CheckYButtonPress())
-    return;
-  button_mask_b_y &= ~0x40;
-  AncillaAdd_Bomb(7, enhanced_features0 & kFeatures0_MoreActiveBombs ? 3 : 1);
-  link_item_in_hand = 0;
-}
-
-void LinkItem_Bottle() {  // 87a15b
-  if (!CheckYButtonPress())
-    return;
-  button_mask_b_y &= ~0x40;
-  int btidx = link_item_bottle_index - 1;
-  uint8 b = link_bottle_info[btidx];
-  if (b == 0)
-    return;
-  if (b < 3) {
-fail:
-    Ancilla_Sfx2_Near(60);
-  } else if (b == 3) {  // red potion
-    if (link_health_capacity == link_health_current)
-      goto fail;
-    link_bottle_info[btidx] = 2;
-    link_item_in_hand = 0;
-    submodule_index = 4;
-    saved_module_for_menu = main_module_index;
-    main_module_index = 14;
-    animate_heart_refill_countdown = 7;
-    Hud_Rebuild();
-  } else if (b == 4) { // green potion
-    if (link_magic_power == 128)
-      goto fail;
-    link_bottle_info[btidx] = 2;
-    link_item_in_hand = 0;
-    submodule_index = 8;
-    saved_module_for_menu = main_module_index;
-    main_module_index = 14;
-    animate_heart_refill_countdown = 7;
-    Hud_Rebuild();
-  } else if (b == 5) { // blue potion
-    if (link_health_capacity == link_health_current && link_magic_power == 128)
-      goto fail;
-    link_bottle_info[btidx] = 2;
-    link_item_in_hand = 0;
-    submodule_index = 9;
-    saved_module_for_menu = main_module_index;
-    main_module_index = 14;
-    animate_heart_refill_countdown = 7;
-    Hud_Rebuild();
-  } else if (b == 6) { // fairy
-    link_item_in_hand = 0;
-    if (ReleaseFairy() < 0)
-      goto fail;
-    link_bottle_info[btidx] = 2;
-    Hud_Rebuild();
-  } else if (b == 7 || b == 8) {  // bad/good bee
-    if (!ReleaseBeeFromBottle(btidx))
-      goto fail;
-    link_bottle_info[btidx] = 2;
-    Hud_Rebuild();
-  }
-}
-
-void LinkItem_Lamp() {  // 87a24d
-  if (is_standing_in_doorway || !CheckYButtonPress())
-    return;
-  if (link_item_torch && LinkCheckMagicCost(6)) {
-    AncillaAdd_MagicPowder(0x1a, 0);
-    Dungeon_LightTorch();
-    AncillaAdd_LampFlame(0x2f, 2);
-  }
-  link_item_in_hand = 0;
-  button_mask_b_y = 0;
-  button_b_frames = 0;
-  link_cant_change_direction = 0;
-  if (button_b_frames == 9)
-    link_speed_setting = 0;
-}
-
-void LinkItem_Powder() {  // 87a293
-  static const uint8 kMushroomTimer[] = { 2, 1, 1, 3, 2, 2, 2, 2, 6, 0 };
-
-  if (!(button_mask_b_y & 0x40)) {
-    if (is_standing_in_doorway || !CheckYButtonPress())
-      return;
-    if (link_item_mushroom != 2) {
-      Ancilla_Sfx2_Near(60);
-      goto out;
-    }
-    if (!LinkCheckMagicCost(2))
-      goto out;
-    link_delay_timer_spin_attack = kMushroomTimer[0];
-    player_handler_timer = 0;
-    link_animation_steps = 0;
-    link_direction &= ~0xf;
-    link_item_in_hand = 0x40;
-  }
-  link_x_vel = link_y_vel = 0;
-  link_direction = 0;
-  link_subpixel_x = link_subpixel_y = 0;
-  link_moving_against_diag_tile = 0;
-  if (!sign8(--link_delay_timer_spin_attack))
-    return;
-  player_handler_timer++;
-  link_delay_timer_spin_attack = kMushroomTimer[player_handler_timer];
-  if (player_handler_timer == 4)
-    AncillaAdd_MagicPowder(26, 0);
-  if (player_handler_timer != 9)
-    return;
-  if (submodule_index == 0)
-    TileDetect_MainHandler(1);
-out:
-  link_item_in_hand = 0;
-  player_handler_timer = 0;
-  button_mask_b_y &= ~0x40;
-}
-
-void LinkItem_ShovelAndFlute() {  // 87a313
-  if (link_item_flute == 1)
-    LinkItem_Shovel();
-  else if (link_item_flute != 0)
-    LinkItem_Flute();
-}
-
-void LinkItem_Shovel() {  // 87a32c
-  static const uint8 kShovelAnimDelay[] = { 7, 18, 16, 7, 18, 16 };
-  static const uint8 kShovelAnimDelay2[] = { 0, 1, 2, 0, 1, 2 };
-  if (!(button_mask_b_y & 0x40)) {
-    if (is_standing_in_doorway || !CheckYButtonPress())
-      return;
-
-    link_delay_timer_spin_attack = kShovelAnimDelay[0];
-    link_var30d = 0;
-    player_handler_timer = 0;
-    link_position_mode = 1;
-    link_cant_change_direction |= 1;
-    link_animation_steps = 0;
-  }
-  HaltLinkWhenUsingItems();
-  link_direction &= ~0xf;
-  if (!sign8(--link_delay_timer_spin_attack))
-    return;
-  link_var30d++;
-  link_delay_timer_spin_attack = kShovelAnimDelay[link_var30d];
-  player_handler_timer = kShovelAnimDelay2[link_var30d];
-
-  if (player_handler_timer == 1) {
-    TileDetect_MainHandler(2);
-    if (BYTE(word_7E04B2)) {
-      Ancilla_Sfx3_Near(27);
-      AncillaAdd_DugUpFlute(54, 0);
-    }
-
-    if (!((tiledetect_thick_grass | tiledetect_destruction_aftermath) & 1)) {
-      Ancilla_AddHitStars(22, 0); // hit stars
-      Ancilla_Sfx2_Near(5);
-    } else {
-      AncillaAdd_ShovelDirt(23, 0); // shovel dirt
-      if (is_archer_or_shovel_game)
-        DiggingGameGuy_AttemptPrizeSpawn();
-      Ancilla_Sfx2_Near(18);
-    }
-  }
-
-  if (link_var30d == 3) {
-    link_var30d = 0;
-    player_handler_timer = 0;
-    button_mask_b_y &= 0x80;
-    link_position_mode = 0;
-    link_cant_change_direction &= ~1;
-  }
-}
-
-void LinkItem_Flute() {  // 87a3db
-  if (button_mask_b_y & 0x40) {
-    if (--flute_countdown)
-      return;
-    button_mask_b_y &= ~0x40;
-  }
-  if (!CheckYButtonPress())
-    return;
-  flute_countdown = 128;
-  Ancilla_Sfx2_Near(19);
-  if (player_is_indoors || overworld_screen_index & 0x40 || main_module_index == 11)
-    return;
-  int i = 4;
-  do {
-    if (ancilla_type[i] == 0x27)
-      return;
-  } while (--i >= 0);
-  if (link_item_flute == 2) {
-    if (overworld_screen_index == 0x18 && link_y_coord >= 0x760 && link_y_coord < 0x7e0 && link_x_coord >= 0x1cf && link_x_coord < 0x230) {
-      submodule_index = 45;
-      AncillaAdd_ExplodingWeatherVane(55, 0);
-    }
-  } else {
-    AncillaAdd_Duck_take_off(39, 4);
-    link_need_for_pullforrupees_sprite = 0;
-  }
-}
-
-void LinkItem_Book() {  // 87a471
-  if (button_mask_b_y & 0x40 || is_standing_in_doorway || !CheckYButtonPress())
-    return;
-  button_mask_b_y &= ~0x40;
-  if (byte_7E02ED) {
-    Link_PerformDesertPrayer();
-  } else {
-    Ancilla_Sfx2_Near(60);
-  }
-}
-
-void LinkItem_Ether() {  // 87a494
-  if (!CheckYButtonPress())
-    return;
-  button_mask_b_y &= ~0x40;
-
-  if (is_standing_in_doorway || flag_block_link_menu || dung_savegame_state_bits & 0x8000 || !((uint8)(link_sword_type + 1) & ~1) ||
-      follower_dropped && follower_indicator == 13) {
-    Ancilla_Sfx2_Near(60);
-    return;
-  }
-
-  if (ancilla_type[0] | ancilla_type[1] | ancilla_type[2])
-    return;
-
-  if (!LinkCheckMagicCost(1))
-    return;
-  link_player_handler_state = kPlayerState_Ether;
-  link_cant_change_direction |= 1;
-  link_delay_timer_spin_attack = kEtherAnimDelays[0];
-  state_for_spin_attack = 0;
-  step_counter_for_spin_attack = 0;
-  byte_7E0324 = 0;
-  Ancilla_Sfx3_Near(35);
-}
-
-void LinkState_UsingEther() {  // 87a50f
-  flag_unk1++;
-  if (!sign8(--link_delay_timer_spin_attack))
-    return;
-
-  step_counter_for_spin_attack++;
-  if (step_counter_for_spin_attack == 4) {
-    Ancilla_Sfx3_Near(35);
-  } else if (step_counter_for_spin_attack == 9) {
-    Ancilla_Sfx2_Near(44);
-  } else if (step_counter_for_spin_attack == 12) {
-    step_counter_for_spin_attack = 10;
-  }
-  const uint8 *table = (enhanced_features0 & kFeatures0_DimFlashes) ? kEtherAnimDelaysNoFlash : kEtherAnimDelays;
-  link_delay_timer_spin_attack = table[step_counter_for_spin_attack];
-  state_for_spin_attack = kEtherAnimStates[step_counter_for_spin_attack];
-  if (!byte_7E0324 && step_counter_for_spin_attack == 10) {
-    byte_7E0324 = 1;
-    AncillaAdd_EtherSpell(24, 0);
-    link_auxiliary_state = 0;
-    link_incapacitated_timer = 0;
-  }
-}
-
-void LinkItem_Bombos() {  // 87a569
-  if (!CheckYButtonPress())
-    return;
-  button_mask_b_y &= ~0x40;
-
-  if (is_standing_in_doorway || flag_block_link_menu || dung_savegame_state_bits & 0x8000 || !((uint8)(link_sword_type + 1) & ~1) ||
-      follower_dropped && follower_indicator == 13) {
-    Ancilla_Sfx2_Near(60);
-    return;
-  }
-
-  if (ancilla_type[0] | ancilla_type[1] | ancilla_type[2])
-    return;
-
-  if (!LinkCheckMagicCost(1))
-    return;
-  link_player_handler_state = kPlayerState_Bombos;
-  link_cant_change_direction |= 1;
-  link_delay_timer_spin_attack = kBombosAnimDelays[0];
-  state_for_spin_attack = kBombosAnimStates[0];
-  step_counter_for_spin_attack = 0;
-  byte_7E0324 = 0;
-  Ancilla_Sfx3_Near(35);
-}
-
-void LinkState_UsingBombos() {  // 87a5f7
-  flag_unk1++;
-  if (!sign8(--link_delay_timer_spin_attack))
-    return;
-
-  step_counter_for_spin_attack++;
-  if (step_counter_for_spin_attack == 4) {
-    Ancilla_Sfx3_Near(35);
-  } else if (step_counter_for_spin_attack == 10) {
-    Ancilla_Sfx2_Near(44);
-  } else if (step_counter_for_spin_attack == 20) {
-    step_counter_for_spin_attack = 19;
-  }
-  link_delay_timer_spin_attack = kBombosAnimDelays[step_counter_for_spin_attack];
-  state_for_spin_attack = kBombosAnimStates[step_counter_for_spin_attack];
-  if (!byte_7E0324 && step_counter_for_spin_attack == 19) {
-    byte_7E0324 = 1;
-    AncillaAdd_BombosSpell(25, 0);
-    link_auxiliary_state = 0;
-    link_incapacitated_timer = 0;
-  }
-}
-
-void LinkItem_Quake() {  // 87a64b
-  if (!CheckYButtonPress())
-    return;
-  button_mask_b_y &= ~0x40;
-
-  if (is_standing_in_doorway || flag_block_link_menu || dung_savegame_state_bits & 0x8000 || !((uint8)(link_sword_type + 1) & ~1) ||
-      follower_dropped && follower_indicator == 13) {
-    Ancilla_Sfx2_Near(60);
-    return;
-  }
-
-  if (ancilla_type[0] | ancilla_type[1] | ancilla_type[2])
-    return;
-
-  if (!LinkCheckMagicCost(1))
-    return;
-  link_player_handler_state = kPlayerState_Quake;
-  link_cant_change_direction |= 1;
-  link_delay_timer_spin_attack = kQuakeAnimDelays[0];
-  state_for_spin_attack = kQuakeAnimStates[0];
-  step_counter_for_spin_attack = 0;
-  byte_7E0324 = 0;
-  link_actual_vel_z_mirror = 40;
-  link_actual_vel_z_copy_mirror = 40;
-  BYTE(link_z_coord_mirror) = 0;
-  Ancilla_Sfx3_Near(35);
-}
-
-void LinkState_UsingQuake() {  // 87a6d6
-  flag_unk1++;
-  link_actual_vel_x = link_actual_vel_y = 0;
-
-  if (step_counter_for_spin_attack == 10) {
-    link_actual_vel_z = link_actual_vel_z_mirror;
-    link_actual_vel_z_copy = link_actual_vel_z_copy_mirror;
-    BYTE(link_z_coord) = link_z_coord_mirror;
-    link_auxiliary_state = 2;
-    Player_ChangeZ(2);
-    Link_MovePosition();
-    link_actual_vel_z_mirror = link_actual_vel_z;
-    link_actual_vel_z_copy_mirror = link_actual_vel_z_copy;
-    BYTE(link_z_coord_mirror) = link_z_coord;
-    if (!sign8(link_z_coord)) {
-      state_for_spin_attack = sign8(link_actual_vel_z) ? 21 : 20;
-      return;
-    }
-  } else {
-    if (!sign8(--link_delay_timer_spin_attack))
-      return;
-  }
-
-  step_counter_for_spin_attack++;
-  if (step_counter_for_spin_attack == 4) {
-    Ancilla_Sfx3_Near(35);
-  } else if (step_counter_for_spin_attack == 10) {
-    Ancilla_Sfx2_Near(44);
-  } else if (step_counter_for_spin_attack == 11) {
-    Ancilla_Sfx2_Near(12);
-  } else if (step_counter_for_spin_attack == 12) {
-    step_counter_for_spin_attack = 11;
-  }
-  link_delay_timer_spin_attack = kQuakeAnimDelays[step_counter_for_spin_attack];
-  state_for_spin_attack = kQuakeAnimStates[step_counter_for_spin_attack];
-  if (!byte_7E0324 && step_counter_for_spin_attack == 11) {
-    byte_7E0324 = 1;
-    AncillaAdd_QuakeSpell(28, 0);
-    link_auxiliary_state = 0;
-    link_incapacitated_timer = 0;
-  }
-}
-
-void Link_ActivateSpinAttack() {  // 87a77a
-  AncillaAdd_SpinAttackInitSpark(42, 0, 0);
-  Link_AnimateVictorySpin();
-}
-
-void Link_AnimateVictorySpin() {  // 87a783
-  link_player_handler_state = 3;
-  link_spin_offsets = (link_direction_facing >> 1) * 12;
-  link_delay_timer_spin_attack = 3;
-  state_for_spin_attack = kLinkSpinGraphicsByDir[link_spin_offsets];
-  step_counter_for_spin_attack = 0;
-  button_b_frames = 144;
-  link_cant_change_direction |= 1;
-  button_mask_b_y = 0x80;
-  LinkState_SpinAttack();
-}
-
-void LinkState_SpinAttack() {  // 87a804
-  CacheCameraPropertiesIfOutdoors();
-
-  if (link_auxiliary_state) {
-    int i = 4;
-    do {
-      if (ancilla_type[i] == 0x2a || ancilla_type[i] == 0x2b)
-        ancilla_type[i] = 0;
-    } while (--i >= 0);
-    link_z_coord &= 0xff;
-    link_cant_change_direction &= ~1;
-    link_delay_timer_spin_attack = 0;
-    button_b_frames = 0;
-    button_mask_b_y = 0;
-    bitfield_for_a_button = 0;
-    state_for_spin_attack = 0;
-    step_counter_for_spin_attack = 0;
-    link_speed_setting = 0;
-    if (link_electrocute_on_touch) {
-      if (link_cape_mode)
-        Link_ForceUnequipCape_quietly();
-      Link_ResetSwordAndItemUsage();
-      link_disable_sprite_damage = 1;
-      player_handler_timer = 0;
-      link_delay_timer_spin_attack = 2;
-      link_animation_steps = 0;
-      link_direction &= ~0xf;
-      Ancilla_Sfx3_Near(43);
-      link_player_handler_state = kPlayerState_Electrocution;
-      LinkState_Zapped();
-    } else {
-      link_player_handler_state = kPlayerState_RecoilWall;
-      LinkState_Recoil();
-    }
-    return;
-  }
-
-  if (link_incapacitated_timer) {
-    Link_HandleRecoilAndTimer(false);
-  } else {
-    link_direction = 0;
-    Link_HandleVelocity();
-    Link_HandleCardinalCollision();
-    link_player_handler_state = kPlayerState_SpinAttacking;
-    fallhole_var1 = 0;
-    HandleIndoorCameraAndDoors();
-  }
-
-  if (!sign8(--link_delay_timer_spin_attack))
-    return;
-
-  step_counter_for_spin_attack++;
-
-  if (step_counter_for_spin_attack == 2)
-    Ancilla_Sfx3_Near(35);
-
-  if (step_counter_for_spin_attack == 12) {
-    link_cant_change_direction &= ~1;
-    link_delay_timer_spin_attack = 0;
-    button_b_frames = 0;
-    state_for_spin_attack = 0;
-    step_counter_for_spin_attack = 0;
-    if (link_player_handler_state != kPlayerState_SpinAttackMotion) {
-      button_mask_b_y = (button_b_frames) ? (joypad1H_last & kJoypadH_B) : 0; // wtf, it's zero,
-    }
-    link_player_handler_state = kPlayerState_Ground;
-  } else {
-    state_for_spin_attack = kLinkSpinGraphicsByDir[step_counter_for_spin_attack + link_spin_offsets];
-    link_delay_timer_spin_attack = kLinkSpinDelays[step_counter_for_spin_attack];
-    TileDetect_MainHandler(8);
-  }
-}
-
-void LinkItem_Mirror() {  // 87a91a
-  if (!(button_mask_b_y & 0x40)) {
-    if (!CheckYButtonPress())
-      return;
-
-    if (follower_indicator == 10) {
-      dialogue_message_index = 289;
-      Main_ShowTextMessage();
-      return;
-    }
-  }
-  button_mask_b_y &= ~0x40;
-
-  if (is_standing_in_doorway || 
-      !cheatWalkThroughWalls && !(enhanced_features0 & kFeatures0_MirrorToDarkworld) && 
-      !player_is_indoors && !(overworld_screen_index & 0x40)) {
-    Ancilla_Sfx2_Near(60);
-    return;
-  }
-
-  DoSwordInteractionWithTiles_Mirror();
-}
-
-void DoSwordInteractionWithTiles_Mirror() {  // 87a95c
-  if (player_is_indoors) {
-    if (flag_block_link_menu)
-      return;
-    Mirror_SaveRoomData();
-    if (sound_effect_1 != 60) {
-      index_of_changable_dungeon_objs[0] = 0;
-      index_of_changable_dungeon_objs[1] = 0;
-    }
-  } else if (main_module_index != 11) {
-    last_light_vs_dark_world = overworld_screen_index & 0x40;
-    if (last_light_vs_dark_world) {
-      bird_travel_y_lo[15] = link_y_coord;
-      bird_travel_y_hi[15] = link_y_coord >> 8;
-      bird_travel_x_lo[15] = link_x_coord;
-      bird_travel_x_hi[15] = link_x_coord >> 8;
-    }
-    submodule_index = 35;
-    link_need_for_pullforrupees_sprite = 0;
-    link_triggered_by_whirlpool_sprite = 1;
-    subsubmodule_index = 0;
-    link_actual_vel_x = link_actual_vel_y = 0;
-    link_player_handler_state = kPlayerState_Mirror;
-  }
-}
-
-void LinkState_CrossingWorlds() {  // 87a9b1
-  uint8 t;
-
-  Link_ResetProperties_B();
-  TileCheckForMirrorBonk();
-
-  if ((overworld_screen_index & 0x40) != last_light_vs_dark_world && ((t = R12 | R14) & 0xc) != 0 && BitSum4(t) >= 2)
-    goto do_mirror;
-
-  if (BitSum4(tiledetect_deepwater) >= 2) {
-    if (link_item_flippers) {
-      link_is_in_deep_water = 1;
-      link_some_direction_bits = link_direction_last;
-      Link_ResetSwimmingState();
-      link_player_handler_state = kPlayerState_Swimming;
-      Link_ForceUnequipCape_quietly();
-      link_speed_setting = 0;
-      return;
-    }
-    if ((overworld_screen_index & 0x40) != last_light_vs_dark_world) {
-do_mirror:
-      submodule_index = 44;
-      link_need_for_pullforrupees_sprite = 0;
-      link_triggered_by_whirlpool_sprite = 1;
-      subsubmodule_index = 0;
-      link_actual_vel_x = link_actual_vel_y = 0;
-      link_player_handler_state = kPlayerState_Mirror;
-      return;
-    }
-    CheckAbilityToSwim();
-  }
-
-  if (link_is_in_deep_water) {
-    link_is_in_deep_water = 0;
-    link_direction_last = link_some_direction_bits;
-  }
-
-  link_countdown_for_dash = 0;
-  link_is_running = 0;
-  link_speed_setting = 0;
-  button_mask_b_y = 0;
-  button_b_frames = 0;
-  link_cant_change_direction = 0;
-  swimcoll_var5[0] &= ~0xff;
-  link_actual_vel_y = 0;
-
-  if ((overworld_screen_index & 0x40) != last_light_vs_dark_world)
-    num_memorized_tiles = 0;
-
-  link_player_handler_state = (link_item_moon_pearl || !(overworld_screen_index & 0x40)) ? kPlayerState_Ground : kPlayerState_PermaBunny;
-}
-
-void Link_PerformDesertPrayer() {  // 87aa6c
-  submodule_index = 5;
-  saved_module_for_menu = main_module_index;
-  main_module_index = 14;
-  flag_unk1 = 1;
-  some_animation_timer = 22;
-  some_animation_timer_steps = 0;
-  link_state_bits = 2;
-  link_cant_change_direction |= 1;
-  link_animation_steps = 0;
-  link_direction &= ~0xf;
-  sound_effect_ambient = 17;
-  music_control = 242;
-}
-
-void HandleFollowersAfterMirroring() {  // 87aaa2
-  TileDetect_MainHandler(0);
-  link_animation_steps = 0;
-  if (follower_indicator == 12 || follower_indicator == 13) {
-    if (follower_indicator == 13) {
-      super_bomb_indicator_unk2 = 0xfe;
-      super_bomb_indicator_unk1 = 0;
-    }
-    if (follower_dropped) {
-      follower_dropped = 0;
-      follower_indicator = 0;
-    }
-  } else if (follower_indicator == 9 || follower_indicator == 10) {
-    follower_indicator = 0;
-  } else if (follower_indicator == 7 || follower_indicator == 8) {
-    follower_indicator ^= (7 ^ 8);
-    LoadFollowerGraphics();
-    AncillaAdd_DwarfPoof(0x40, 4);
-  }
-
-  if (!link_item_moon_pearl) {
-    AncillaAdd_BunnyPoof(0x23, 4);
-    Link_ForceUnequipCape_quietly();
-    link_bunny_transform_timer = 0;
-  } else if (link_cape_mode) {
-    Link_ForceUnequipCape();
-    link_bunny_transform_timer = 0;
-  }
-}
-
-void LinkItem_Hookshot() {  // 87ab25
-  if (button_mask_b_y & 0x40 || is_standing_in_doorway || bitmask_of_dragstate & 2 || !CheckYButtonPress())
-    return;
-
-  ResetAllAcceleration();
-  player_handler_timer = 0;
-  link_cant_change_direction |= 1;
-  link_delay_timer_spin_attack = 7;
-  link_animation_steps = 0;
-  link_direction &= ~0xf;
-  link_position_mode = 4;
-  link_player_handler_state = kPlayerState_Hookshot;
-  link_disable_sprite_damage = 1;
-  AncillaAdd_Hookshot(31, 3);
-}
-
-void LinkState_Hookshotting() {  // 87ab7c
-  static const int8 kHookshotArrA[4] = { -8, -16, 0, 0 };
-  static const int8 kHookshotArrB[4] = { 0, 0, 4, -12 };
-  static const int8 kHookshotArrC[4] = { -64, 64, 0, 0 };
-  static const int8 kHookshotArrD[4] = { 0, 0, -64, 64 };
-
-  link_give_damage = 0;
-  link_auxiliary_state = 0;
-  link_incapacitated_timer = 0;
-  int i = 4;
-  while (ancilla_type[i] != 0x1f) {
-    if (--i < 0) {
-      if (!sign8(--link_delay_timer_spin_attack))
-        return;
-      player_handler_timer = 0;
-      link_disable_sprite_damage = 0;
-      button_mask_b_y &= ~0x40;
-      link_cant_change_direction &= ~1;
-      link_position_mode &= ~4;
-      link_player_handler_state = kPlayerState_Ground;
-      if (button_b_frames >= 9)
-        button_b_frames = 9;
-      return;
-    }
-  }
-
-  if (sign8(--link_delay_timer_spin_attack))
-    link_delay_timer_spin_attack = 0;
-
-  if (!related_to_hookshot) {
-    link_y_coord_safe_return_lo = link_y_coord;
-    link_x_coord_safe_return_lo = link_x_coord;
-    link_y_vel = link_x_vel = 0;
-    Link_HandleCardinalCollision();
-    return;
-  }
-
-  player_on_somaria_platform = 0;
-
-  uint8 hei = hookshot_effect_index;
-  if (sign8(--ancilla_item_to_link[hei])) {
-    ancilla_item_to_link[hei] = 0;
-  } else {
-    uint16 x = ancilla_x_lo[hei] | (ancilla_x_hi[hei] << 8);
-    uint16 y = ancilla_y_lo[hei] | (ancilla_y_hi[hei] << 8);
-    int8 r4 = kHookshotArrA[ancilla_dir[hei]];
-    int8 r6 = kHookshotArrB[ancilla_dir[hei]];
-    link_actual_vel_x = link_actual_vel_y = 0;
-    int8 r8 = kHookshotArrC[ancilla_dir[hei]];
-    int8 r10 = kHookshotArrD[ancilla_dir[hei]];
-
-    uint16 yd = (int16)(y + r4 - link_y_coord);
-    if ((int16)yd < 0)
-      yd = -yd;
-    if (yd >= 2)
-      link_actual_vel_y = r8;
-
-    uint16 xd = (int16)(x + r6 - link_x_coord);
-    if ((int16)xd < 0)
-      xd = -xd;
-    if (xd >= 2)
-      link_actual_vel_x = r10;
-
-    if (link_actual_vel_x | link_actual_vel_y)
-      goto loc_87AD49;
-  }
-
-  ancilla_type[hei] = 0;
-  tagalong_var7 = tagalong_var1;
-  link_player_handler_state = kPlayerState_Ground;
-  player_handler_timer = 0;
-  link_delay_timer_spin_attack = 0;
-  related_to_hookshot = 0;
-  button_mask_b_y &= ~0x40;
-  link_cant_change_direction &= ~1;
-  link_position_mode &= ~4;
-  link_disable_sprite_damage = 0;
-
-  if (ancilla_arr1[hei]) {
-    link_is_on_lower_level_mirror ^= 1;
-    dung_cur_floor--;
-    if (kind_of_in_room_staircase == 0) {
-      BYTE(dungeon_room_index2) = dungeon_room_index;
-      BYTE(dungeon_room_index) += 0x10;
-    }
-    if (kind_of_in_room_staircase != 2) {
-      link_is_on_lower_level ^= 1;
-    }
-    Dungeon_FlagRoomData_Quadrants();
-  }
-  Player_TileDetectNearby();
-  if (tiledetect_deepwater & 0xf && !link_is_in_deep_water) {
-    link_is_in_deep_water = 1;
-    link_some_direction_bits = link_direction_last;
-    Link_ResetSwimmingState();
-    AncillaAdd_Splash(21, 0);
-    link_player_handler_state = kPlayerState_Swimming;
-    Link_ForceUnequipCape_quietly();
-    link_state_bits = 0;
-    link_picking_throw_state = 0;
-    link_grabbing_wall = 0;
-    link_speed_setting = 0;
-    if (player_is_indoors)
-      link_is_on_lower_level = 1;
-    if (button_b_frames >= 9)
-      button_b_frames = 9;
-  } else if (tiledetect_pit_tile & 0xf) {
-    byte_7E005C = 9;
-    link_this_controls_sprite_oam = 0;
-    player_near_pit_state = 1;
-    link_player_handler_state = kPlayerState_FallingIntoHole;
-    if (button_b_frames >= 9)
-      button_b_frames = 9;
-  } else {
-    link_y_coord_safe_return_lo = link_y_coord;
-    link_y_coord_safe_return_hi = link_y_coord >> 8;
-    link_x_coord_safe_return_lo = link_x_coord;
-    link_x_coord_safe_return_hi = link_x_coord >> 8;
-    Link_HandleCardinalCollision();
-    HandleIndoorCameraAndDoors();
-  }
-  return;
-loc_87AD49:
-  Link_MovePosition();
-  TileDetect_MainHandler(5);
-  if (player_is_indoors) {
-    uint8 x = tiledetect_vertical_ledge >> 4 | tiledetect_vertical_ledge | detection_of_ledge_tiles_horiz_uphoriz;
-    if (x & 1 && sign8(--hookshot_var1)) {
-      hookshot_var1 = 3;
-      related_to_hookshot ^= 2;
-    }
-  }
-  draw_water_ripples_or_grass = 0;
-  if (!(related_to_hookshot & 2)) {
-    if (tiledetect_thick_grass & 1) {
-      draw_water_ripples_or_grass = 2;
-      if (!Link_PermissionForSloshSounds())
-        Ancilla_Sfx2_Near(26);
-    } else if ((tiledetect_shallow_water | tiledetect_deepwater) & 1) {
-      draw_water_ripples_or_grass++;
-      Ancilla_Sfx2_Near((uint8)overworld_screen_index == 0x70 ? 27 : 28);
-    }
-  }
-
-  HandleIndoorCameraAndDoors();
-}
-
-void LinkItem_Cape() {  // 87adc1
-  if (!link_cape_mode) {
-    if (!sign8(--link_bunny_transform_timer)) {
-      link_direction &= ~0xf;
-      HaltLinkWhenUsingItems();
-      return;
-    }
-    link_bunny_transform_timer = 0;
-    if (is_standing_in_doorway || !CheckYButtonPress())
-      return;
-    button_mask_b_y &= ~0x40;
-    if (!link_magic_power) {
-      Ancilla_Sfx2_Near(60);
-      dialogue_message_index = 123;
-      Main_ShowTextMessage();
-      return;
-    }
-    player_handler_timer = 0;
-    link_cape_mode = 1;
-    cape_decrement_counter = kCapeDepletionTimers[link_magic_consumption];
-    link_bunny_transform_timer = 20;
-    AncillaAdd_CapePoof(35, 4);
-    Ancilla_Sfx2_Near(20);
-  } else {
-    link_disable_sprite_damage = 1;
-    HaltLinkWhenUsingItems();
-    link_direction &= ~0xf;
-    if (!--cape_decrement_counter) {
-      cape_decrement_counter = kCapeDepletionTimers[link_magic_consumption];
-      // Avoid magic underflow if an anti-fairy consumes magic.
-      if (link_magic_power == 0 && (enhanced_features0 & kFeatures0_MiscBugFixes) ||
-          !--link_magic_power) {
-        Link_ForceUnequipCape();
-        return;
-      }
-    }
-    if (sign8(--link_bunny_transform_timer)) {
-      link_bunny_transform_timer = 0;
-      if (filtered_joypad_H & kJoypadH_Y)
-        Link_ForceUnequipCape();
-    }
-  }
-}
-
-void Link_ForceUnequipCape() {  // 87ae47
-  AncillaAdd_CapePoof(35, 4);
-  Ancilla_Sfx2_Near(21);
-  Link_ForceUnequipCape_quietly();
-}
-
-void Link_ForceUnequipCape_quietly() {  // 87ae54
-  link_bunny_transform_timer = 32;
-  link_disable_sprite_damage = 0;
-  link_cape_mode = 0;
-  link_electrocute_on_touch = 0;
-}
-
-void HaltLinkWhenUsingItems() {  // 87ae65
-  if (dung_hdr_collision_2 == 2 && (byte_7E0322 & 3) == 3) {
-    link_y_vel = 0;
-    link_x_vel = 0;
-    link_direction = 0;
-    link_subpixel_y = 0;
-    link_subpixel_x = 0;
-    link_moving_against_diag_tile = 0;
-  }
-  if (player_on_somaria_platform)
-    link_direction = 0;
-}
-
-void Link_HandleCape_passive_LiftCheck() {  // 87ae88
-  //bugfix: grabbing or pulling while wearing cape didn't drain magic
-  if (link_state_bits & 0x80 || (enhanced_features0 & kFeatures0_MiscBugFixes && link_grabbing_wall))
-    Player_CheckHandleCapeStuff();
-}
-
-void Player_CheckHandleCapeStuff() {  // 87ae8f
-  if (link_cape_mode && current_item_active == 19) {
-    if (current_item_active == current_item_y) {
-      if (--cape_decrement_counter)
-        return;
-      cape_decrement_counter = kCapeDepletionTimers[link_magic_consumption];
-      if (!link_magic_power || --link_magic_power)
-        return;
-    }
-    Link_ForceUnequipCape();
-  }
-}
-
-void LinkItem_CaneOfSomaria() {  // 87aec0
-  static const uint8 kRodAnimDelays[] = { 3, 3, 5 };
-  if (!(button_mask_b_y & 0x40)) {
-    if (player_on_somaria_platform || is_standing_in_doorway || !CheckYButtonPress())
-      return;
-    int i = 4;
-    bool did_charge_magic = false;
-
-    while (ancilla_type[i] != 0x2c) {
-      if (--i < 0) {
-        if (!LinkCheckMagicCost(4)) {
-          // If you use the Cane of Somaria with an empty magic meter,
-          // then quickly switch to the mushroom or magic powder after
-          // the "no magic" prompt, you will automatically sprinkle magic powder
-          // despite pressing no button and having no magic.
-          if (enhanced_features0 & kFeatures0_MiscBugFixes)
-            goto out;
-          return;
-        }
-        did_charge_magic = true;
-        break;
-      }
-    }
-    link_debug_value_2 = 1;
-    if (AncillaAdd_SomariaBlock(0x2c, 1) < 0) {
-      // If you use the Cane of Somaria while two bombs and the boomerang are active,
-      // magic will be refunded instead of used.
-      if (did_charge_magic || !(enhanced_features0 & kFeatures0_MiscBugFixes))
-        Refund_Magic(4);
-    }
-    link_delay_timer_spin_attack = kRodAnimDelays[0];
-    link_animation_steps = 0;
-    player_handler_timer = 0;
-    link_item_in_hand = 0;
-    link_position_mode |= 8;
-  }
-
-  HaltLinkWhenUsingItems();
-  link_direction &= ~0xf;
-  if (!sign8(--link_delay_timer_spin_attack))
-    return;
-  player_handler_timer++;
-
-  link_delay_timer_spin_attack = kRodAnimDelays[player_handler_timer];
-  if (player_handler_timer != 3)
-    return;
-  link_speed_setting = 0;
-  player_handler_timer = 0;
-  link_delay_timer_spin_attack = 0;
-  link_debug_value_2 = 0;
-  link_position_mode &= ~8;
-out:
-  button_mask_b_y &= ~0x40;
-}
-
-void LinkItem_CaneOfByrna() {  // 87af3e
-  static const uint8 kByrnaDelays[] = { 19, 7, 13, 32 };
-  if (SearchForByrnaSpark())
-    return;
-  if (!(button_mask_b_y & 0x40)) {
-    if (is_standing_in_doorway || !CheckYButtonPress())
-      return;
-    if (!LinkCheckMagicCost(8))
-      goto out;
-    AncillaAdd_CaneOfByrnaInitSpark(48, 0);
-    link_spin_attack_step_counter = 0;
-    link_delay_timer_spin_attack = kByrnaDelays[0];
-    link_var30d = 0;
-    player_handler_timer = 0;
-    link_position_mode = 8;
-    link_cant_change_direction |= 1;
-    link_animation_steps = 0;
-  }
-  HaltLinkWhenUsingItems();
-  link_direction &= ~0xf;
-  if (!sign8(--link_delay_timer_spin_attack))
-    return;
-  player_handler_timer++;
-  link_delay_timer_spin_attack = kByrnaDelays[player_handler_timer];
-  if (player_handler_timer == 1) {
-    Ancilla_Sfx3_Near(42);
-  } else if (player_handler_timer == 3) {
-out:
-    link_var30d = 0;
-    player_handler_timer = 0;
-    button_mask_b_y &= 0x80;
-    link_position_mode = 0;
-    link_cant_change_direction &= ~1;
-  }
-}
-
-bool SearchForByrnaSpark() {  // 87afb5
-  if (link_position_mode & 8)
-    return false;
-  int i = 4;
-  do {
-    if (ancilla_type[i] == 0x31)
-      return true;
-  } while (--i >= 0);
-  return false;
-}
-
-void LinkItem_Net() {  // 87aff8
-  static const uint8 kBugNetTimers[] = { 11, 6, 7, 8, 1, 2, 3, 4, 5, 6, 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 9, 4, 5, 6, 7, 8, 1, 2, 3, 4, 10, 8, 1, 2, 3, 4, 5, 6, 7, 8 };
-  if (!(button_mask_b_y & 0x40)) {
-    if (is_standing_in_doorway || !CheckYButtonPress())
-      return;
-
-    player_handler_timer = kBugNetTimers[(link_direction_facing >> 1) * 10];
-    link_delay_timer_spin_attack = 3;
-    link_var30d = 0;
-    link_position_mode = 16;
-    link_cant_change_direction |= 1;
-    link_animation_steps = 0;
-    Ancilla_Sfx2_Near(50);
-  }
-
-  HaltLinkWhenUsingItems();
-  link_direction &= ~0xf;
-  if (!sign8(--link_delay_timer_spin_attack))
-    return;
-
-  link_var30d++;
-  link_delay_timer_spin_attack = 3;
-  player_handler_timer = kBugNetTimers[(link_direction_facing >> 1) * 10 + link_var30d];
-
-  if (link_var30d == 10) {
-    link_var30d = 0;
-    player_handler_timer = 0;
-    button_mask_b_y &= 0x80;
-    link_position_mode = 0;
-    link_cant_change_direction &= ~1;
-    player_oam_x_offset = 0x80;
-    player_oam_y_offset = 0x80;
-  }
-}
-
-bool CheckYButtonPress() {  // 87b073
-  if (button_mask_b_y & 0x40 || link_incapacitated_timer || !(filtered_joypad_H & kJoypadH_Y))
-    return false;
-  button_mask_b_y |= 0x40;
-  return true;
-}
-
-bool LinkCheckMagicCost(uint8 x) {  // 87b0ab
-  uint8 cost = kLinkItem_MagicCosts[x * 3 + link_magic_consumption];
-  uint8 a = link_magic_power;
-  if (a && (a -= cost) < 0x80) {
-    link_magic_power = a;
-    return true;
-  }
-  if (x != 3) {
-    Ancilla_Sfx2_Near(60);
-    dialogue_message_index = 123;
-    Main_ShowTextMessage();
-  }
-  return false;
-}
-
-void Refund_Magic(uint8 x) {  // 87b0e9
-  uint8 cost = kLinkItem_MagicCosts[x * 3 + link_magic_consumption];
-
-  int new_magic = link_magic_power + cost;
-  // Ensure magic can't overflow (for example the cane of somaria bug)
-  if (enhanced_features0 & kFeatures0_MiscBugFixes && new_magic >= 128)
-    new_magic = 128;
-  link_magic_power = new_magic;
-}
-
-void Link_ItemReset_FromOverworldThings() {  // 87b107
-  some_animation_timer_steps = 0;
-  bitfield_for_a_button = 0;
-  link_state_bits = 0;
-  link_picking_throw_state = 0;
-  link_grabbing_wall = 0;
-  link_cant_change_direction &= ~1;
-}
-
-void Link_PerformThrow() {  // 87b11c
-
-  if (!(flag_is_sprite_to_pick_up | flag_is_ancilla_to_pick_up)) {
-    Link_ResetSwordAndItemUsage();
-    bitfield_for_a_button = 0;
-    int i = 15;
-    while (sprite_state[i] != 0) {
-      if (--i < 0)
-        return;
-    }
-
-    if (interacting_with_liftable_tile_x1 == 5 || interacting_with_liftable_tile_x1 == 6) {
-      player_handler_timer = 1;
-    } else {
-      Point16U pt;
-      uint8 attr = player_is_indoors ? Dungeon_LiftAndReplaceLiftable(&pt) : Overworld_HandleLiftableTiles(&pt);
-
-      i = 8;
-      while (kLink_Lift_tab[i] != attr) {
-        if (--i < 0)
-          return;
-      }
-
-      flag_is_sprite_to_pick_up = 1;
-      Sprite_SpawnThrowableTerrain(i, pt.x, pt.y);
-      filtered_joypad_L &= ~kJoypadL_A;
-      player_handler_timer = 0;
-    }
-  } else {
-    player_handler_timer = 0;
-  }
-
-  button_mask_b_y = 0;
-  some_animation_timer = 6;
-  link_picking_throw_state = 1;
-  link_state_bits = 0x80;
-  some_animation_timer_steps = 0;
-  link_speed_setting = 12;
-  link_animation_steps = 0;
-  link_direction &= 0xf0;
-  link_cant_change_direction |= 1;
-}
-
-void Link_APress_LiftCarryThrow() {  // 87b1ca
-  if (!link_state_bits)
-    return;
-
-  // throwing?
-  if ((link_picking_throw_state & 2) && some_animation_timer >= 5)
-    some_animation_timer = 5;
-
-  // picking up?
-  if (link_picking_throw_state)
-    HaltLinkWhenUsingItems();
-
-  if (link_picking_throw_state & 1) {
-    link_animation_steps = 0;
-    link_counter_var1 = 0;
-    link_direction &= ~0xf;
-  }
-
-  if (--some_animation_timer)
-    return;
-
-  if (link_picking_throw_state & 2) {
-    link_state_bits = 0;
-    bitmask_of_dragstate = 0;
-    link_speed_setting = 0;
-    if (link_player_handler_state == 24)
-      link_player_handler_state = 0;
-  } else {
-    static const uint8 kLiftTab0[10] = { 8, 24, 8, 24, 8, 32, 6, 8, 13, 13 };
-    static const uint8 kLiftTab1[10] = { 0, 1, 0, 1, 0, 1, 0, 1, 2, 3 };
-    static const uint8 kLiftTab2[29] = { 6, 7, 7, 5, 10, 0, 23, 0, 18, 0, 18, 0, 8, 0, 8, 0, 254, 255, 17, 0, 
-        0x54, 0x52, 0x50, 0xFF, 0x51, 0x53, 0x55, 0x56, 0x57 };
-
-    if (player_handler_timer != 0) {
-      if (player_handler_timer + 1 != 9) {
-        player_handler_timer++;
-        some_animation_timer = kLiftTab0[player_handler_timer];
-        some_animation_timer_steps = kLiftTab1[player_handler_timer];
-        if (player_handler_timer == 6) {
-          BYTE(dung_secrets_unk1) = 0;
-          Point16U pt;
-          uint8 what = (player_is_indoors) ? Dungeon_LiftAndReplaceLiftable(&pt) : Overworld_HandleLiftableTiles(&pt);
-          link_player_handler_state = 24;
-          flag_is_sprite_to_pick_up = 1;
-          Sprite_SpawnThrowableTerrain((what & 0xf) + 1, pt.x, pt.y);
-          filtered_joypad_L &= ~kJoypadL_A;
-        }
-        return;
-      }
-    } else {
-      // fix OOB read triggered when lifting for too long
-      if (some_animation_timer_steps >= sizeof(kLiftTab2) - 1)
-        return;
-      some_animation_timer = kLiftTab2[++some_animation_timer_steps];
-      assert(some_animation_timer_steps < arraysize(kLiftTab2));
-      if (some_animation_timer_steps != 3)
-        return;
-    }
-  }
-
-  // stop animation
-  link_picking_throw_state = 0;
-  link_cant_change_direction &= ~1;
-}
-
-void Link_PerformDash() {  // 87b281
-  if (player_on_somaria_platform)
-    return;
-  if (flag_is_sprite_to_pick_up | flag_is_ancilla_to_pick_up)
-    return;
-  if (link_state_bits & 0x80)
-    return;
-  bitfield_for_a_button = 0;
-  link_countdown_for_dash = 29;
-  link_dash_ctr = 64;
-  link_player_handler_state = kPlayerState_StartDash;
-  link_is_running = 1;
-  button_mask_b_y &= 0x80;
-  link_state_bits = 0;
-  link_item_in_hand = 0;
-  bitmask_of_dragstate = 0;
-  link_moving_against_diag_tile = 0;
-
-  if (follower_indicator == kTagalongArr1[follower_indicator]) {
-    printf("Warning: Write to CART!\n");
-    link_speed_setting = 0;
-    timer_tagalong_reacquire = 64;
-  }
-}
-
-void Link_PerformGrab() {  // 87b2ee
-  if ((button_mask_b_y & 0x80) && button_b_frames >= 9)
-    return;
-
-  link_grabbing_wall = 1;
-  link_cant_change_direction |= 1;
-  link_animation_steps = 0;
-  some_animation_timer_steps = 0;
-  some_animation_timer = 0;
-  link_var30d = 0;
-}
-
-void Link_APress_PullObject() {  // 87b322
-  link_direction &= ~0xf;
-
-  if (!(kGrabWallDirs[link_direction_facing >> 1] & joypad1H_last)) {
-    link_var30d = 0;
-    goto set;
-  } else if (sign8(--some_animation_timer)) {
-    link_var30d = (link_var30d + 1 == 7) ? 1 : link_var30d + 1;
-set:
-    some_animation_timer_steps = kGrabWall_AnimSteps[link_var30d];
-    some_animation_timer = kGrabWall_AnimTimer[link_var30d];
-  }
-
-  if (!(joypad1L_last & kJoypadL_A)) {
-    link_var30d = 0;
-    some_animation_timer_steps = 0;
-    link_grabbing_wall = 0;
-    bitfield_for_a_button = 0;
-    link_cant_change_direction &= ~1;
-  }
-}
-
-void Link_PerformStatueDrag() {  // 87b371
-  link_grabbing_wall = 2;
-  link_cant_change_direction |= 1;
-  link_animation_steps = 0;
-  some_animation_timer_steps = 0;
-  some_animation_timer = kGrabWall_AnimTimer[0];
-  link_var30d = 0;
-}
-
-void Link_APress_StatueDrag() {  // 87b389
-  link_speed_setting = 20;
-  int j;
-  if (!(j = joypad1H_last & kGrabWallDirs[link_direction_facing >> 1])) {
-    link_direction = 0;
-    link_x_vel = link_y_vel = 0;
-    link_animation_steps = 0;
-    link_var30d = 0;
-  } else {
-    link_direction = j;
-    if (!sign8(--some_animation_timer))
-      goto skip_set;
-    link_var30d = (link_var30d + 1 == 7) ? 1 : link_var30d + 1;
-  }
-  some_animation_timer_steps = kGrabWall_AnimSteps[link_var30d];
-  some_animation_timer = kGrabWall_AnimTimer[link_var30d];
-skip_set:
-  if (!(joypad1L_last & kJoypadL_A)) {
-    link_speed_setting = 0;
-    link_is_near_moveable_statue = 0;
-    link_var30d = 0;
-    some_animation_timer_steps = 0;
-    link_grabbing_wall = 0;
-    bitfield_for_a_button = 0;
-    link_cant_change_direction &= ~1;
-  }
-}
-
-void Link_PerformRupeePull() {  // 87b3e5
-  if (link_direction_facing != 0)
-    return;
-  Link_ResetProperties_A();
-  link_grabbing_wall = 2;
-  link_cant_change_direction |= 2;
-
-  link_animation_steps = 0;
-  some_animation_timer_steps = 0;
-  some_animation_timer = kGrabWall_AnimTimer[0];
-  link_var30d = 0;
-  link_player_handler_state = kPlayerState_PullForRupees;
-  link_actual_vel_y = 0;
-  link_actual_vel_x = 0;
-  button_mask_b_y = 0;
-}
-
-void LinkState_TreePull() {  // 87b416
-  CacheCameraPropertiesIfOutdoors();
-  if (link_auxiliary_state) {
-    HandleLink_From1D();
-    return;
-  }
-
-  if (link_grabbing_wall) {
-    if (!button_mask_b_y) {
-      if (!(joypad1L_last & kJoypadL_A)) {
-        link_grabbing_wall = 0;
-        link_var30d = 0;
-        some_animation_timer = 2;
-        some_animation_timer_steps = 0;
-        link_cant_change_direction = 0;
-        link_player_handler_state = 0;
-        LinkState_Default();
-        return;
-      }
-      if (!(joypad1H_last & kJoypadH_Down))
-        goto out;
-      button_mask_b_y = 4;
-      Ancilla_Sfx2_Near(0x22);
-    }
-
-    if (!sign8(--some_animation_timer))
-      goto out;
-    int j = ++link_var30d;
-    some_animation_timer_steps = kGrabWall_AnimSteps[j];
-    some_animation_timer = kGrabWall_AnimTimer[j];
-    if (j != 7)
-      goto out;
-
-    link_grabbing_wall = 0;
-    link_var30d = 0;
-    some_animation_timer = 2;
-    some_animation_timer_steps = 0;
-    link_state_bits = 1;
-    link_picking_throw_state = 0;
-  }
-
-  if (bitmask_of_dragstate & 9) {
-reset_to_normal:
-    link_direction_facing = 0;
-    link_state_bits = 0;
-    link_cant_change_direction = 0;
-    link_player_handler_state = kPlayerState_Ground;
-    return;
-  }
-  if (link_var30d == 9) {
-    if (!(filtered_joypad_H & kJoypadH_AnyDir))
-      goto out2;
-    link_player_handler_state = kPlayerState_Ground;
-    LinkState_Default();
-    return;
-  }
-  AncillaAdd_DashDust_charging(0x1e, 0);
-  if (sign8(--some_animation_timer)) {
-    static const uint8 kGrabWall_AnimSteps2[10] = { 0, 1, 2, 3, 4, 0, 1, 2, 3, 0x20 };  // oob read
-    int j = ++link_var30d;
-    some_animation_timer_steps = kGrabWall_AnimSteps2[j];
-    some_animation_timer = 2;
-    link_actual_vel_y = 48;
-    if (j == 9)
-      goto reset_to_normal;
-  }
-  Flag67WithDirections();
-  if (!(link_direction & 3))
-    link_actual_vel_x = 0;
-  if (!(link_direction & 0xc))
-    link_actual_vel_y = 0;
-out:
-  Link_MovePosition();
-out2:
-  Link_HandleCardinalCollision();
-  HandleIndoorCameraAndDoors();
-}
-
-void Link_PerformRead() {  // 87b4f2
-  if (player_is_indoors) {
-    dialogue_message_index = Dungeon_GetTeleMsg(dungeon_room_index);
-  } else {
-    dialogue_message_index = (sram_progress_indicator < 2) ? 0x3A : Overworld_GetSignText(overworld_screen_index);
-  }
-  Main_ShowTextMessage();
-  bitfield_for_a_button = 0;
-}
-
-void Link_PerformOpenChest() {  // 87b574
-  static const uint8 kReceiveItemAlternates[] = { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 68, 255, 255, 255, 255, 255, 53, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 70, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 };
-  if (link_direction_facing || item_receipt_method || link_auxiliary_state)
-    return;
-  bitfield_for_a_button = 0;
-  int chest_position = -1;
-  uint8 item = OpenChestForItem(index_of_interacting_tile, &chest_position);
-  if (sign8(item)) {
-    item_receipt_method = 0;
-    return;
-  }
-  assert(chest_position != -1);
-  item_receipt_method = 1;
-  uint8 alt = kReceiveItemAlternates[item];
-  if (alt != 0xff) {
-    uint16 ram_addr = kMemoryLocationToGiveItemTo[item];
-    if (g_ram[ram_addr])
-      item = alt;
-  }
-
-  Link_ReceiveItem(item, chest_position);
-}
-
-bool Link_CheckNewAPress() {  // 87b5c0
-  if (bitfield_for_a_button & 0x80 || link_incapacitated_timer || !(filtered_joypad_L & kJoypadL_A))
-    return false;
-  bitfield_for_a_button |= 0x80;
-  return true;
-}
-
-bool Link_HandleToss() {  // 87b5d6
-  if (!(bitfield_for_a_button & 0x80) || !(filtered_joypad_L & kJoypadL_A) || (link_picking_throw_state & 1))
-    return false;
-  link_var30d = 0;
-  link_var30e = 0;
-  some_animation_timer_steps = 0;
-  bitfield_for_a_button = 0;
-  link_cant_change_direction &= ~1;
-  // debug stuff here
-  return true;
-}
-
-void Link_HandleDiagonalCollision() {  // 87b64f
-  if (CheckIfRoomNeedsDoubleLayerCheck()) {
-    Player_LimitDirections_Inner();
-    CreateVelocityFromMovingBackground();
-  }
-  link_direction &= 0xf;
-  Player_LimitDirections_Inner();
-}
-
-void Player_LimitDirections_Inner() {  // 87b660
-  link_direction_mask_a = 0xf;
-  link_direction_mask_b = 0xf;
-  link_num_orthogonal_directions = 0;
-
-  static const uint8 kMasks[4] = { 7, 0xB, 0xD, 0xE };
-
-  if (link_direction & 0xC) {
-    link_num_orthogonal_directions++;
-
-    link_last_direction_moved_towards = link_direction & 8 ? 0 : 1;
-    TileDetect_Movement_VerticalSlopes(link_last_direction_moved_towards);
-
-    if ((R14 & 0x30) && !(tiledetect_var1 & 2) && !(((R14 & 0x30) >> 4) & link_direction) && (link_direction & 3)) {
-      link_direction_mask_a = kMasks[(link_direction & 2) ? 2 : 3];
-    } else {
-      if (dung_hdr_collision == 0) {
-        if (link_auxiliary_state != 0 && (R12 & 3))
-          goto set_thingy;
-      }
-
-      if (R14 & 3) {
-        link_moving_against_diag_tile = 0;
-        if (link_flag_moving && (bitfield_spike_cactus_tiles & 3) == 0 && (link_direction & 3)) {
-          swimcoll_var1[0] = 0;
-          swimcoll_var5[0] = 0;
-          swimcoll_var7[0] = 0;
-          swimcoll_var9[0] = 0;
-        }
-set_thingy:
-        fallhole_var1 = 1;
-        link_direction_mask_a = kMasks[link_last_direction_moved_towards];
-      }
-    }
-
-    if (link_direction & 3) {
-      link_num_orthogonal_directions++;
-
-      link_last_direction_moved_towards = link_direction & 2 ? 2 : 3;
-      TileDetect_Movement_HorizontalSlopes(link_last_direction_moved_towards);
-
-      if ((R14 & 0x30) && (tiledetect_var1 & 2) && !(((R14 & 0x30) >> 2) & link_direction) && (link_direction & 0xC)) {
-        link_direction_mask_b = kMasks[(link_direction & 8) ? 0 : 1];
-      } else {
-        if (dung_hdr_collision == 0) {
-          if (link_auxiliary_state != 0 && (R12 & 3))
-            goto set_thingy_b;
-        }
-
-        if (R14 & 3) {
-          link_moving_against_diag_tile = 0;
-          if (link_flag_moving && (bitfield_spike_cactus_tiles & 3) == 0 && (link_direction & 0xC)) {
-            swimcoll_var1[1] = 0;
-            swimcoll_var5[1] = 0;
-            swimcoll_var7[1] = 0;
-            swimcoll_var9[1] = 0;
-          }
-set_thingy_b:
-          fallhole_var1 = 1;
-          link_direction_mask_b = kMasks[link_last_direction_moved_towards];
-        }
-      }
-
-      link_direction &= link_direction_mask_a & link_direction_mask_b;
-    }
-  }
-
-  // ending
-  if ((link_direction & 0xf) && (link_moving_against_diag_tile & 0xf))
-    link_direction = link_moving_against_diag_tile & 0xf;
-
-  if (link_num_orthogonal_directions == 2) {
-    link_num_orthogonal_directions = (link_direction_facing & 4) ? 2 : 1;
-  } else {
-    link_num_orthogonal_directions = 0;
-  }
-}
-
-void Link_HandleCardinalCollision() {  // 87b7c7
-  tiledetect_diag_state = 0;
-  tiledetect_diagonal_tile = 0;
-
-  if (((link_moving_against_diag_tile & 0x30) != 0 || (Link_HandleDiagonalKickback(), moving_against_diag_deadlocked == 0)) &&
-      CheckIfRoomNeedsDoubleLayerCheck()) {
-
-    if (dung_hdr_collision < 2 || dung_hdr_collision == 3)
-      goto yx;
-    tile_coll_flag = 2;
-    Player_TileDetectNearby();
-    byte_7E0316 = R14;
-    if (byte_7E0316 == 0)
-      goto yx;
-    link_y_vel += dung_floor_y_vel;
-    link_x_vel += dung_floor_x_vel;
-
-    uint8 a;
-    a = R14;
-    if (a == 12 || a == 3)
-      goto yx;
-    if (a == 10 || a == 5)
-      goto xy;
-    if ((a & 0xc) == 0 && (a & 3) == 0)
-      goto yx;
-
-    if (link_y_vel)
-      goto xy;
-    if (!link_x_vel)
-      goto yx;
-
-    if (sign8(dung_floor_y_vel)) {
-yx:   RunSlopeCollisionChecks_VerticalFirst();
-    } else {
-xy:   RunSlopeCollisionChecks_HorizontalFirst();
-    }
-    CreateVelocityFromMovingBackground();
-  } // endif_1
-
-  if (dung_hdr_collision == 2) {
-    Player_TileDetectNearby();
-    if ((R14 | byte_7E0316) == 0xf) {
-      if (!countdown_for_blink)
-        countdown_for_blink = 58;
-      if (link_direction == 0) {
-        if (BYTE(dung_floor_y_vel))
-          link_y_vel = -link_y_vel;
-        if (BYTE(dung_floor_x_vel))
-          link_x_vel = -link_x_vel;
-      }
-    }
-    tile_coll_flag = 1;
-    RunSlopeCollisionChecks_VerticalFirst();
-  } else if (dung_hdr_collision == 3) {
-    tile_coll_flag = 1;
-    RunSlopeCollisionChecks_HorizontalFirst();
-  } else if (dung_hdr_collision == 4 || (link_x_vel | link_y_vel) != 0) {
-    tile_coll_flag = 1;
-    RunSlopeCollisionChecks_VerticalFirst();
-  } else {
-    uint8 st = link_player_handler_state;
-    if (st != 19 && st != 8 && st != 9 && st != 10 && st != 3) {
-      Player_TileDetectNearby();
-      if (tiledetect_pit_tile & 0xf) {
-        link_player_handler_state = kPlayerState_FallingIntoHole;
-        if (!link_is_running)
-          link_speed_setting = 4;
-      }
-    }
-  }
-
-  TileDetect_MainHandler(0);
-  if (link_num_orthogonal_directions != 0)
-    link_moving_against_diag_tile = 0;
-
-  if (link_player_handler_state != 11) {
-    link_y_vel = link_y_coord - link_y_coord_safe_return_lo;
-    if (link_y_vel)
-      link_direction = (link_direction & 3) | (sign8(link_y_vel) ? 8 : 4);
-  }
-
-  link_x_vel = link_x_coord - link_x_coord_safe_return_lo;
-  if (link_x_vel)
-    link_direction = (link_direction & 0xC) | (sign8(link_x_vel) ? 2 : 1);
-
-  if (!player_is_indoors || dung_hdr_collision != 4 || link_player_handler_state != kPlayerState_Swimming)
-    return;
-
-  if (dung_floor_y_vel && (uint8)(link_y_vel - dung_floor_y_vel) == 0)
-    link_direction &= sign8(dung_floor_y_vel) ? ~8 : ~4;
-
-  if (dung_floor_x_vel && (uint8)(link_x_vel - dung_floor_x_vel) == 0)
-    link_direction &= sign8(dung_floor_x_vel) ? ~2 : ~1;
-}
-
-void RunSlopeCollisionChecks_VerticalFirst() {  // 87b956
-  if (!(link_moving_against_diag_tile & 0x20))
-    StartMovementCollisionChecks_Y();
-  if (!(link_moving_against_diag_tile & 0x10))
-    StartMovementCollisionChecks_X();
-}
-
-void RunSlopeCollisionChecks_HorizontalFirst() {  // 87b969
-  if (!(link_moving_against_diag_tile & 0x10))
-    StartMovementCollisionChecks_X();
-  if (!(link_moving_against_diag_tile & 0x20))
-    StartMovementCollisionChecks_Y();
-}
-
-bool CheckIfRoomNeedsDoubleLayerCheck() {  // 87b97c
-  if (dung_hdr_collision == 0 || dung_hdr_collision == 4)
-    return false;
-
-  if (dung_hdr_collision >= 2) {
-    link_y_coord += BG1VOFS_copy2 - BG2VOFS_copy2;
-    related_to_moving_floor_y = link_y_coord;
-    link_x_coord += BG1HOFS_copy2 - BG2HOFS_copy2;
-    related_to_moving_floor_x = link_x_coord;
-  }
-  link_is_on_lower_level = 1;
-  return true;
-}
-
-void CreateVelocityFromMovingBackground() {  // 87b9b3
-  if (dung_hdr_collision != 1) {
-    uint16 x = link_x_coord - related_to_moving_floor_x;
-    uint16 y = link_y_coord - related_to_moving_floor_y;
-    link_y_coord += BG2VOFS_copy2 - BG1VOFS_copy2;
-    link_x_coord += BG2HOFS_copy2 - BG1HOFS_copy2;
-    if (link_direction) {
-      link_x_vel += x;
-      link_y_vel += y;
-    }
-  }
-  link_is_on_lower_level = 0;
-}
-
-void StartMovementCollisionChecks_Y() {  // 87ba0a
-  if (!link_y_vel)
-    return;
-
-  if (is_standing_in_doorway == 1)
-    link_last_direction_moved_towards = (uint8)link_y_coord < 0x80 ? 0 : 1;
-  else
-    link_last_direction_moved_towards = sign8(link_y_vel) ? 0 : 1;
-  TileDetect_Movement_Y(link_last_direction_moved_towards);
-  if (player_is_indoors)
-    StartMovementCollisionChecks_Y_HandleIndoors();
-  else
-    StartMovementCollisionChecks_Y_HandleOutdoors();
-}
-
-void StartMovementCollisionChecks_Y_HandleIndoors() {  // 87ba35
-  if (sign8(link_state_bits) || link_incapacitated_timer != 0) {
-    R14 |= R14 >> 4;
-  } else {
-    if (is_standing_in_doorway == 2) {
-      if (link_num_orthogonal_directions == 0) {
-        if (dung_hdr_collision != 3 || link_is_on_lower_level == 0) {
-          Link_AddInVelocityY();
-          ChangeAxisOfPerpendicularDoorMovement_Y();
-          return;
-        }
-        goto label_3;
-      } else if (tiledetect_var1) {
-        Link_AddInVelocityY();
-        goto endif_1b;
-      }
-    } // else_3
-    if (R14 & 0x70) {
-      if ((R14 >> 8) & 7) {
-        force_move_any_direction = (sign8(link_y_vel)) ? 8 : 4;
-      } // endif_6
-
-      is_standing_in_doorway = 1;
-      link_on_conveyor_belt = 0;
-      if ((R14 & 0x70) != 0x70) {
-        if (R14 & 5) { // if_7
-          link_moving_against_diag_tile = 0;
-          Link_AddInVelocityYFalling();
-          CalculateSnapScratch_Y();
-          is_standing_in_doorway = 0;
-
-          if (R14 & 0x20 && (R14 & 1) == 0 && (link_x_coord & 7) == 1)
-            link_x_coord &= ~7;
-          goto else_7;
-        }
-        if (R14 & 0x20)
-          goto else_7;
-      } else { // else_7
-else_7:
-        if (!(tile_coll_flag & 2))
-          link_cant_change_direction &= ~2;
-        return;
-      }
-    }
-  } // endif_1
-
-  if (!(tile_coll_flag & 2)) {
-    is_standing_in_doorway = 0;
-  }
-
-endif_1b:
-  if (!(tile_coll_flag & 2)) {
-    link_cant_change_direction &= ~2;
-    room_transitioning_flags = 0;
-    force_move_any_direction = 0;
-  } // label_3
-
-label_3:
-
-  if ((R14 & 7) == 0 && (R12 & 5) != 0) {
-    link_on_conveyor_belt = 0;
-    FlagMovingIntoSlopes_Y();
-    if ((link_moving_against_diag_tile & 0xf) != 0)
-      return;
-  } // endif_9
-
-  link_moving_against_diag_tile = 0;
-  if (tiledetect_key_lock_gravestones & 0x20) {
-    uint16 bak = R14;
-    int dummy;
-    OpenChestForItem(tiledetect_tile_type, &dummy);
-    tiledetect_tile_type = 0;
-    R14 = bak;
-  }
-  if (!link_is_on_lower_level) {
-    if (tiledetect_water_staircase & 7) {
-      byte_7E0322 |= 1;
-    } else if ((bitfield_spike_cactus_tiles & 7) == 0 && (R14 & 2) == 0) { // else_11
-      byte_7E0322 &= ~1;
-    } // endif_11
-  } else { // else_10
-    if ((tiledetect_moving_floor_tiles & 7) != 0) {
-      byte_7E0322 |= 2;
-    } else {
-      byte_7E0322 &= ~2;
-    }
-  } // endif_11
-
-  if (tiledetect_misc_tiles & 0x2200) {
-    uint16 dy = tiledetect_misc_tiles & 0x2000 ? 8 : 0;
-
-    static const uint8 kLink_DoMoveXCoord_Indoors_dx[] = { 8, 8, 0, 15 };
-    static const uint8 kLink_DoMoveXCoord_Indoors_dy[] = { 8, 24, 16, 16 };
-
-    link_rupees_goal += 5;
-    uint16 y = link_y_coord + kLink_DoMoveXCoord_Indoors_dy[link_last_direction_moved_towards] - dy;
-    uint16 x = link_x_coord + kLink_DoMoveXCoord_Indoors_dx[link_last_direction_moved_towards];
-
-    Dungeon_DeleteRupeeTile(x, y);
-    Ancilla_Sfx3_Near(10);
-  }  // endif_12_norupee
-
-  if (tiledetect_var4 & 0x22) {
-    link_on_conveyor_belt = tiledetect_var4 & 0x20 ? 2 : 1;
-  } else if (tiledetect_var4 & 0x2200) {
-    link_on_conveyor_belt = tiledetect_var4 & 0x2000 ? 4 : 3;
-  } else {
-    if (!(bitfield_spike_cactus_tiles & 7) && !(R14 & 2))
-      link_on_conveyor_belt = 0;
-  } // endif_15
-
-  if ((tiledetect_vertical_ledge & 7) == 7 && RunLedgeHopTimer()) {
-    Link_CancelDash();
-    about_to_jump_off_ledge++;
-    link_disable_sprite_damage = 1;
-    link_auxiliary_state = 2;
-    Ancilla_Sfx2_Near(0x20);
-
-    goto endif_19;
-  } else if ((tiledetect_deepwater & 7) == 7 && link_is_in_deep_water == 0) {
-    // if_20
-    Link_CancelDash();
-    if (TS_copy == 0) {
-      Dungeon_HandleLayerChange();
-    } else {
-      link_is_in_deep_water = 1;
-      link_some_direction_bits = link_direction_last;
-      link_state_bits = 0;
-      link_picking_throw_state = 0;
-      link_grabbing_wall = 0;
-      link_speed_setting = 0;
-      Link_ResetSwimmingState();
-      Ancilla_Sfx2_Near(0x20);
-    }
-endif_19:
-    link_disable_sprite_damage = 1;
-    Link_HopInOrOutOfWater_Y();
-  } else {
-    // else_20
-    if ((tiledetect_normal_tiles & 2) && link_is_in_deep_water != 0) {
-      if (link_auxiliary_state != 0) {
-        R14 = 7;
-      } else {
-        Link_CancelDash();
-        link_direction_last = link_some_direction_bits;
-        link_is_in_deep_water = 0;
-        if (AncillaAdd_Splash(0x15, 0)) {
-          link_is_in_deep_water = 1;
-          R14 = 7;
-        } else {
-          link_disable_sprite_damage = 1;
-          Link_HopInOrOutOfWater_Y();
-        }
-      }
-    }
-  } // endif_21
-
-  if ((tiledetect_stair_tile & 7) == 7) {
-    if (link_incapacitated_timer) {
-      R14 &= ~0xff;
-      R14 |= tiledetect_stair_tile & 7;
-      HandlePushingBonkingSnaps_Y();
-      return;
-    }
-    if (tiledetect_inroom_staircase & 0x77) {
-      submodule_index = tiledetect_inroom_staircase & 0x70 ? 16 : 8;
-      main_module_index = 7;
-      Link_CancelDash();
-    } else if (enhanced_features0 & kFeatures0_TurnWhileDashing) {
-      // avoid weirdness in stairs
-      Link_CancelDash();
-    }
-
-    if ((link_last_direction_moved_towards & 2) == 0) {
-      link_speed_setting = 2;
-      link_speed_modifier = 1;
-      return;
-    }
-  }
-
-  if (link_speed_setting == 2)
-    link_speed_setting = link_is_running ? 16 : 0;
-
-  if (link_speed_modifier == 1)
-    link_speed_modifier = 2;
-
-  if (tiledetect_pit_tile & 5 && (R14 & 2) == 0) {
-    if (link_player_handler_state == 5 || link_player_handler_state == 2)
-      return;
-    byte_7E005C = 9;
-    link_this_controls_sprite_oam = 0;
-    player_near_pit_state = 1;
-    link_player_handler_state = kPlayerState_FallingIntoHole;
-    return;
-  } // endif_23
-
-  link_this_controls_sprite_oam = 0;
-
-  if (bitfield_spike_cactus_tiles & 7) {
-    if ((link_incapacitated_timer | countdown_for_blink | link_cape_mode) == 0) {
-      if (((link_last_direction_moved_towards == 0) ? (link_y_coord & 4) == 0 : ((link_y_coord & 4) != 0)) && (countdown_for_blink == 0)) {
-        link_give_damage = 8;
-        Link_CancelDash();
-        Link_ForceUnequipCape_quietly();
-        LinkApplyTileRebound();
-        return;
-      }
-    } else {
-      R14 &= ~0xFF;
-      R14 |= bitfield_spike_cactus_tiles & 7;
-    } // endif_24
-  } // endif_24
-  if (dung_hdr_collision == 0 || dung_hdr_collision == 4 || !link_is_on_lower_level) {
-    if (tiledetect_var2 && link_num_orthogonal_directions == 0) {
-      byte_7E02C2 = tiledetect_var2;
-      if (!sign8(--gravestone_push_timeout))
-        goto endif_26;
-      uint16 bits = tiledetect_var2;
-      int i = 15;
-      do {
-        if (bits & 0x8000) {
-          uint8 idx = FindFreeMovingBlockSlot(i);
-          if (idx == 0xff)
-            continue;
-          R14 = idx;
-          if (InitializePushBlock(idx, i * 2))
-            continue;
-          Sprite_Dungeon_DrawSinglePushBlock(idx * 2);
-          R14 = 4;  // Unwanted side effect
-          pushedblock_facing[idx] = link_last_direction_moved_towards * 2;
-          push_block_direction = link_last_direction_moved_towards * 2;
-          pushedblocks_target[idx] = (pushedblocks_y_lo[idx] - (link_last_direction_moved_towards == 1)) & 0xf;
-        }
-      } while (bits <<= 1, --i >= 0);
-    }
-    // endif_27
-    gravestone_push_timeout = 21;
-  }
-  // endif_26
-endif_26:
-  HandlePushingBonkingSnaps_Y();
-}
-
-void HandlePushingBonkingSnaps_Y() {  // 87bdb1
-  if (R14 & 7) {
-    if (link_player_handler_state == kPlayerState_Swimming) {
-      if ((uint8)dung_floor_y_vel == 0)
-        ResetAllAcceleration();
-
-      if (link_num_orthogonal_directions != 0) {
-        Link_AddInVelocityYFalling();
-        goto label_a;
-      }
-    }  // endif_2
-
-    if (R14 & 2 || (R14 & 5) == 5) {
-      uint16 bak = R14;
-      Link_BonkAndSmash();
-      RepelDash();
-      R14 = bak;
-    }
-
-    fallhole_var1 = 1;
-
-    if ((R14 & 2) == 2) {
-      Link_AddInVelocityYFalling();
-    } else {
-      if (link_num_orthogonal_directions == 1)
-        goto returnb;
-      Link_AddInVelocityYFalling();
-      if (link_num_orthogonal_directions == 2)
-        goto returnb;
-    } // endif_4
-
-label_a:
-
-    if ((R14 & 5) == 5) {
-      Link_BonkAndSmash();
-      RepelDash();
-    } else if (R14 & 4) {
-      uint8 tt = sign8(link_y_vel) ? link_y_vel : -link_y_vel;
-      uint8 r0 = sign8(tt) ? 0xff : 1;
-      if ((R14 & 2) == 0) {
-        if (link_x_coord & 7) {
-          link_x_coord += (int8)r0;
-          HandleNudging(r0);
-          return;
-        }
-        Link_BonkAndSmash();
-        RepelDash();
-      }
-    } else { // else_7
-      uint8 tt = sign8(link_y_vel) ? -link_y_vel : link_y_vel;
-      uint8 r0 = sign8(tt) ? 0xff : 1;
-      if ((R14 & 2) == 0) {
-        if (link_x_coord & 7) {
-          link_x_coord += (int8)r0;
-          HandleNudging(r0);
-          return;
-        }
-        Link_BonkAndSmash();
-        RepelDash();
-      }
-    }
-    // endif_10
-    if (link_last_direction_moved_towards * 2 == link_direction_facing) {
-      bitmask_of_dragstate |= (tile_coll_flag & 1) << 1;
-      if (button_b_frames == 0 && !sign8(--link_timer_push_get_tired))
-        return;
-
-      bitmask_of_dragstate |= (tiledetect_misc_tiles & 0x20) ? tile_coll_flag << 3 : tile_coll_flag;
-    }
-  } else {// else_1
-    if (link_is_on_lower_level)
-      return;
-    bitmask_of_dragstate &= ~9;
-  } // endif_1
-
-returnb:
-  link_timer_push_get_tired = 32;
-  bitmask_of_dragstate &= ~2;
-}
-
-void StartMovementCollisionChecks_Y_HandleOutdoors() {  // 87beaf
-  if (link_speed_setting == 2)
-    link_speed_setting = link_is_running ? 16 : 0;
-
-  if ((tiledetect_pit_tile & 5) != 0 && (R14 & 2) == 0) {
-    if (link_player_handler_state != 5 && link_player_handler_state != 2) {
-      // start fall into hole
-      byte_7E005C = 9;
-      link_this_controls_sprite_oam = 0;
-      player_near_pit_state = 1;
-      link_player_handler_state = kPlayerState_FallingIntoHole;
-    }
-    return;
-  }
-
-  if (tiledetect_read_something & 2) {
-    interacting_with_liftable_tile_x1 = interacting_with_liftable_tile_x2 >> 1;
-  } else {
-    interacting_with_liftable_tile_x1 = 0;
-  }  // endif_2
-
-  if ((tiledetect_deepwater & 2) && !link_is_in_deep_water && !link_auxiliary_state) {
-    Link_ResetSwordAndItemUsage();
-    Link_CancelDash();
-    link_is_in_deep_water = 1;
-    link_some_direction_bits = link_direction_last;
-    link_grabbing_wall = 0;
-    link_speed_setting = 0;
-    Link_ResetSwimmingState();
-    if ((draw_water_ripples_or_grass == 1) && (Link_ForceUnequipCape_quietly(), link_item_flippers != 0)) {
-      if (!link_is_bunny_mirror)
-        link_player_handler_state = kPlayerState_Swimming;
-    } else {
-      Ancilla_Sfx2_Near(0x20);
-      link_y_coord = (link_y_coord_safe_return_hi << 8) | link_y_coord_safe_return_lo;
-      link_x_coord = (link_x_coord_safe_return_hi << 8) | link_x_coord_safe_return_lo;
-      link_disable_sprite_damage = 1;
-      Link_HopInOrOutOfWater_Y();
-    }
-  }  // endif_afterSwimCheck
-
-  if (link_is_in_deep_water) {
-    if (tiledetect_vertical_ledge & 7) {
-      R14 = tiledetect_vertical_ledge & 7;
-      HandlePushingBonkingSnaps_Y();
-      return;
-    }
-    if ((tiledetect_stair_tile & 7) == 7 || (tiledetect_normal_tiles & 7) == 7) {
-      Link_CancelDash();
-      link_is_in_deep_water = 0;
-      if (link_auxiliary_state == 0) {
-        link_direction_last = link_some_direction_bits;
-        link_disable_sprite_damage = 1;
-        AncillaAdd_Splash(0x15, 0);
-        Link_HopInOrOutOfWater_Y();
-        return;
-      }
-    }
-  }
-
-  if (detection_of_ledge_tiles_horiz_uphoriz & 2 || detection_of_unknown_tile_types & 0x22) {
-    R14 = 7;
-    HandlePushingBonkingSnaps_Y();
-    return;
-  }
-
-  if (tiledetect_vertical_ledge & 0x70 && RunLedgeHopTimer()) {
-    Link_CancelDash();
-    link_disable_sprite_damage = 1;
-    allow_scroll_z = 1;
-    link_player_handler_state = 11;
-    link_incapacitated_timer = 0;
-    link_z_coord_mirror = -1;
-    bitmask_of_dragstate = 0;
-    link_speed_setting = 0;
-    link_actual_vel_z_copy_mirror = link_actual_vel_z_mirror = link_is_in_deep_water ? 14 : 20;
-    link_auxiliary_state = link_is_in_deep_water ? 4 : 2;
-    return;
-  }
-
-  if (tiledetect_vertical_ledge & 7 && RunLedgeHopTimer()) {
-    Ancilla_Sfx2_Near(0x20);
-    link_disable_sprite_damage = 1;
-    Link_CancelDash();
-    bitmask_of_dragstate = 0;
-    link_speed_setting = 0;
-    Link_FindValidLandingTile_North();
-    return;
-  }
-
-  if (!link_is_in_deep_water) {
-    if (tiledetect_ledges_down_leftright & 7 && !(tiledetect_vertical_ledge & 0x77)) {
-      uint8 xand = index_of_interacting_tile == 0x2f ? 4 : 1;
-      if ((tiledetect_ledges_down_leftright & xand) && RunLedgeHopTimer()) {
-        Link_CancelDash();
-        link_actual_vel_x = tiledetect_ledges_down_leftright & 4 ? 16 : -16;
-        link_disable_sprite_damage = 1;
-        bitmask_of_dragstate = 0;
-        link_speed_setting = 0;
-        allow_scroll_z = 1;
-        link_auxiliary_state = 2;
-        link_actual_vel_z_copy_mirror = link_actual_vel_z_mirror = 20;
-        link_z_coord_mirror |= 0xff;
-        link_incapacitated_timer = 0;
-        link_player_handler_state = 14;
-        return;
-      }
-    } // endif_6
-
-    if (detection_of_ledge_tiles_horiz_uphoriz & 0x70 && !(tiledetect_vertical_ledge & 0x77) && RunLedgeHopTimer()) {
-      Link_CancelDash();
-      Ancilla_Sfx2_Near(0x20);
-      link_last_direction_moved_towards = detection_of_ledge_tiles_horiz_uphoriz & 0x40 ? 3 : 2;
-      link_disable_sprite_damage = 1;
-      bitmask_of_dragstate = 0;
-      link_speed_setting = 0;
-      Link_FindValidLandingTile_DiagonalNorth();
-      return;
-    }
-  } // endif_7
-
-  if ((tiledetect_stair_tile & 7) == 7) {
-    if (link_incapacitated_timer != 0) {
-      R14 = tiledetect_stair_tile & 7;
-      HandlePushingBonkingSnaps_Y();
-      return;
-    } else if (!(link_last_direction_moved_towards & 2)) {
-      link_speed_setting = 2;
-      link_speed_modifier = 1;
-      return;
-    }
-  }  // endif_8
-
-  if (link_speed_setting == 2)
-    link_speed_setting = link_is_running ? 16 : 0;
-
-  if (link_speed_modifier == 1)
-    link_speed_modifier = 2;
-
-  if ((R14 & 7) == 0 && (R12 & 5) != 0) {
-    FlagMovingIntoSlopes_Y();
-    if ((link_moving_against_diag_tile & 0xf) != 0)
-      return;
-  }  // endif_11
-
-  link_moving_against_diag_tile = 0;
-  if (tiledetect_key_lock_gravestones & 2 && link_last_direction_moved_towards == 0) {
-    if (link_is_running || sign8(--gravestone_push_timeout)) {
-      uint16 bak = R14;
-      AncillaAdd_GraveStone(0x24, 4);
-      R14 = bak;
-      gravestone_push_timeout = 52;
-    }
-  } else {
-    gravestone_push_timeout = 52;
-  } // endif_12
-
-  if ((bitfield_spike_cactus_tiles & 7) != 0) {
-    if ((link_incapacitated_timer | countdown_for_blink | link_cape_mode) == 0) {
-      if (link_last_direction_moved_towards == 0 ? ((link_y_coord & 4) == 0) : ((link_y_coord & 4) != 0)) {
-        link_give_damage = 8;
-        Link_CancelDash();
-        Link_ForceUnequipCape_quietly();
-        LinkApplyTileRebound();
-        return;
-      }
-    } else {
-      R14 = bitfield_spike_cactus_tiles & 7;
-    }
-  }  // endif_13
-  HandlePushingBonkingSnaps_Y();
-}
-
-bool RunLedgeHopTimer() { // carry  // 87c16d
-  bool rv = false;
-  if (link_auxiliary_state != 1) {
-    if (!link_is_running) {
-      if (sign8(--link_timer_jump_ledge)) {
-        link_timer_jump_ledge = 19;
-        return true;
-      }
-    } else {
-      rv = true;
-    }
-  }
-  link_y_coord = link_y_coord_prev;
-  link_x_coord = link_x_coord_prev;
-  link_subpixel_y = link_subpixel_x = 0;
-  return rv;
-}
-
-void Link_BonkAndSmash() {  // 87c1a1
-  if (!link_is_running || (link_dash_ctr == 64) || !(bitmask_for_dashable_tiles & 0x70))
-    return;
-  for (int i = 0; i < 2; i++) {
-    Point16U pt;
-    int j = Overworld_SmashRockPile(i != 0, &pt);
-    if (j >= 0) {
-      int k = FindInByteArray(kLink_Lift_tab, (uint8)j, 9);
-      if (k >= 0) {
-        if (k == 2 || k == 4)
-          Ancilla_Sfx3_Near(0x32);
-        Sprite_SpawnImmediatelySmashedTerrain(k, pt.x, pt.y);
-      }
-    }
-  }
-}
-
-void Link_AddInVelocityYFalling() {  // 87c1e4
-  link_y_coord -= (tiledetect_which_y_pos[0] & 7) - (sign8(link_y_vel) ? 8 : 0);
-}
-
-// Adjust X coord to fit through door
-void CalculateSnapScratch_Y() {  // 87c1ff
-  uint8 yv = link_y_vel;
-  if (R14 & 4) {
-    if (!sign8(yv)) yv = -yv;
-  } else {
-    if (sign8(yv)) yv = -yv;
-  }
-  link_x_coord += !sign8(yv) ? 1 : -1;
-}
-
-void ChangeAxisOfPerpendicularDoorMovement_Y() {  // 87c23d
-  link_cant_change_direction |= 2;
-  uint8 t = (R14 | (R14 >> 4)) & 0xf;
-  if (!(t & 7)) {
-    is_standing_in_doorway = 0;
-    return;
-  }
-  int8 vel;
-  uint8 dir;
-
-  if ((uint8)link_x_coord >= 0x80) {
-    uint8 t = link_y_vel;
-    if (!sign8(t)) t = -t;
-    vel = sign8(t) ? -1 : 1;
-    dir = 4;
-  } else {
-    uint8 t = link_y_vel;
-    if (sign8(t)) t = -t;
-    vel = sign8(t) ? -1 : 1;
-    dir = 6;
-  }
-  if (!(link_cant_change_direction & 1))
-    link_direction_facing = dir;
-  link_x_coord += vel;
-}
-
-void Link_AddInVelocityY() {  // 87c29f
-  link_y_coord -= (int8)link_y_vel;
-}
-
-void Link_HopInOrOutOfWater_Y() {  // 87c2c3
-  static const uint8 kRecoilVelY[] = { 24, 16, 16 };
-  static const uint8 kRecoilVelZ[] = { 36, 24, 24 };
-
-  uint8 ts = !player_is_indoors ? 2 :
-    about_to_jump_off_ledge ? 0 : TS_copy;
-
-  int8 vel = kRecoilVelY[ts];
-  if (!link_last_direction_moved_towards)
-    vel = -vel;
-
-  link_actual_vel_y = vel;
-  link_actual_vel_x = 0;
-  link_actual_vel_z_copy = link_actual_vel_z = kRecoilVelZ[ts];
-  link_z_coord = 0;
-  link_incapacitated_timer = 16;
-  if (link_auxiliary_state != 2) {
-    link_auxiliary_state = 1;
-    link_electrocute_on_touch = 0;
-  }
-  link_player_handler_state = 6;
-}
-
-void Link_FindValidLandingTile_North() {  // 87c36c
-  uint16 y_coord_bak = link_y_coord;
-  link_y_coord_original = link_y_coord;
-
-  for (;;) {
-    link_y_coord -= 16;
-    TileDetect_Movement_Y(link_last_direction_moved_towards);
-    uint8 k = tiledetect_normal_tiles | tiledetect_destruction_aftermath | tiledetect_thick_grass | tiledetect_deepwater;
-    if ((k & 7) == 7)
-      break;
-  }
-
-  if (tiledetect_deepwater & 7) {
-    link_auxiliary_state = 1;
-    link_electrocute_on_touch = 0;
-    link_is_in_deep_water = 1;
-    link_some_direction_bits = link_direction_last;
-    Link_ResetSwimmingState();
-    link_grabbing_wall = 0;
-    link_speed_setting = 0;
-  }
-
-  link_y_coord -= 16;
-  link_y_coord_original -= link_y_coord;
-  link_y_coord = y_coord_bak;
-
-  uint8 o = (uint8)link_y_coord_original >> 3;
-
-  static const uint8 kLink_MoveY_RecoilOther_dy[32] = { 16, 16, 20, 20, 24, 24, 28, 28, 32, 32, 36, 36, 40, 40, 44, 44, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48 };
-  static const uint8 kLink_MoveY_RecoilOther_dz[32] = { 24, 24, 24, 24, 28, 28, 28, 28, 32, 32, 32, 32, 36, 36, 36, 36, 40, 40, 40, 40, 44, 44, 44, 44, 48, 48, 48, 48, 52, 52, 52, 52 };
-  static const uint8 kLink_MoveY_RecoilOther_timer[32] = { 16, 16, 20, 20, 24, 24, 28, 28, 32, 32, 36, 36, 40, 40, 44, 44, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48 };
-
-  int8 dy = kLink_MoveY_RecoilOther_dy[o];
-  link_actual_vel_y = (link_last_direction_moved_towards != 0) ? dy : -dy;
-  link_actual_vel_x = 0;
-  link_actual_vel_z_copy = link_actual_vel_z = kLink_MoveY_RecoilOther_dz[o];
-  link_z_coord = 0;
-  link_incapacitated_timer = kLink_MoveY_RecoilOther_timer[o];
-  link_auxiliary_state = 2;
-  link_electrocute_on_touch = 0;
-  link_player_handler_state = 6;
-}
-
-void Link_FindValidLandingTile_DiagonalNorth() {  // 87c46d
-  uint8 b0 = link_y_coord_safe_return_lo;
-  uint16 b1 = link_x_coord;
-  uint8 dir = link_last_direction_moved_towards;
-
-  link_actual_vel_x = (link_last_direction_moved_towards != 2 ? 1 : -1);
-  link_last_direction_moved_towards = 0;
-  LinkHop_FindLandingSpotDiagonallyDown();
-
-  link_x_coord = b1;
-  link_y_coord_safe_return_lo = b0;
-
-  uint16 o = (uint16)(link_y_coord_original - link_y_coord) >> 3;
-  link_y_coord = link_y_coord_original;
-
-  static const uint8 kLink_JumpOffLedgeUpDown_dx[32] = { 8, 8, 8, 8, 16, 16, 16, 16, 24, 24, 24, 24, 16, 16, 16, 16, 8, 20, 20, 20, 24, 24, 24, 24, 28, 28, 28, 28, 32, 32, 32, 32 };
-  static const uint8 kLink_JumpOffLedgeUpDown_dy[32] = { 8, 8, 8, 8, 16, 16, 20, 20, 24, 24, 24, 24, 32, 32, 32, 32, 8, 20, 20, 20, 24, 24, 24, 24, 28, 28, 28, 28, 32, 32, 32, 32 };
-  static const uint8 kLink_JumpOffLedgeUpDown_dz[32] = { 32, 32, 32, 32, 32, 32, 32, 32, 36, 36, 36, 36, 40, 40, 40, 40, 32, 40, 40, 40, 44, 44, 44, 44, 48, 48, 48, 48, 52, 52, 52, 52 };
-
-  link_actual_vel_y = -kLink_JumpOffLedgeUpDown_dy[o];
-  uint8 dx = kLink_JumpOffLedgeUpDown_dx[o];
-  link_actual_vel_x = (dir != 2) ? dx : -dx;
-  link_actual_vel_z_copy = link_actual_vel_z = kLink_JumpOffLedgeUpDown_dz[o];
-  link_z_coord = 0;
-  link_z_coord_mirror &= ~0xff;
-  link_auxiliary_state = 2;
-  link_electrocute_on_touch = 0;
-  link_player_handler_state = 13;
-}
-
-void StartMovementCollisionChecks_X() {  // 87c4d4
-  if (!link_x_vel)
-    return;
-
-  if (is_standing_in_doorway == 2)
-    link_last_direction_moved_towards = (uint8)link_x_coord < 0x80 ? 2 : 3;
-  else
-    link_last_direction_moved_towards = sign8(link_x_vel) ? 2 : 3;
-  TileDetect_Movement_X(link_last_direction_moved_towards);
-  if (player_is_indoors)
-    StartMovementCollisionChecks_X_HandleIndoors();
-  else
-    StartMovementCollisionChecks_X_HandleOutdoors();
-}
-
-void StartMovementCollisionChecks_X_HandleIndoors() {  // 87c4ff
-  if (sign8(link_state_bits) || link_incapacitated_timer != 0) {
-    R14 |= R14 >> 4;
-  } else {
-    if (link_num_orthogonal_directions == 0)
-      link_speed_modifier = 0;
-    if (is_standing_in_doorway == 1 && link_num_orthogonal_directions == 0) {
-      if (dung_hdr_collision != 3 || link_is_on_lower_level == 0) {
-        SnapOnX();
-        int8 spd = ChangeAxisOfPerpendicularDoorMovement_X();
-        HandleNudgingInADoor(spd);
-        return;
-      }
-      goto label_3;
-    } // else_3
-
-    if (R14 & 0x70) {
-      if ((R14 >> 8) & 7) {
-        force_move_any_direction = (sign8(link_x_vel)) ? 2 : 1;
-      } // endif_6
-
-      is_standing_in_doorway = 2;
-      link_on_conveyor_belt = 0;
-      if ((R14 & 0x70) != 0x70) {
-        if (R14 & 7) { // if_7
-          link_moving_against_diag_tile = 0;
-          is_standing_in_doorway = 0;
-          SnapOnX();
-          CalculateSnapScratch_X();
-          return;
-        }
-        if (R14 & 0x70)
-          goto else_7;
-      } else { // else_7
-else_7:
-        if (!(tile_coll_flag & 2))
-          link_cant_change_direction &= ~2;
-        return;
-      }
-    }
-  } // endif_1
-
-  if (!(tile_coll_flag & 2)) {
-    link_cant_change_direction &= ~2;
-    is_standing_in_doorway = 0;
-    room_transitioning_flags = 0;
-    force_move_any_direction = 0;
-  }  // label_3
-
-label_3:
-
-  if ((R14 & 2) == 0 && (R12 & 5) != 0) {
-    link_on_conveyor_belt = 0;
-    FlagMovingIntoSlopes_X();
-    if ((link_moving_against_diag_tile & 0xf) != 0)
-      return;
-  } // endif_9
-
-  link_moving_against_diag_tile = 0;
-  if (!link_is_on_lower_level) {
-    if (tiledetect_water_staircase & 7) {
-      byte_7E0322 |= 1;
-    } else if ((bitfield_spike_cactus_tiles & 7) == 0 && (R14 & 2) == 0) { // else_11
-      byte_7E0322 &= ~1;
-    } // endif_11
-  } else { // else_10
-    if ((tiledetect_moving_floor_tiles & 7) != 0) {
-      byte_7E0322 |= 2;
-    } else {
-      byte_7E0322 &= ~2;
-    }
-  } // endif_11
-
-  if (tiledetect_misc_tiles & 0x2200) {
-    uint16 dy = tiledetect_misc_tiles & 0x2000 ? 8 : 0;
-
-    static const uint8 kLink_DoMoveXCoord_Indoors_dx[] = { 8, 8, 0, 15 };
-    static const uint8 kLink_DoMoveXCoord_Indoors_dy[] = { 8, 24, 16, 16 };
-
-    link_rupees_goal += 5;
-    uint16 y = link_y_coord + kLink_DoMoveXCoord_Indoors_dy[link_last_direction_moved_towards] - dy;
-    uint16 x = link_x_coord + kLink_DoMoveXCoord_Indoors_dx[link_last_direction_moved_towards];
-
-    Dungeon_DeleteRupeeTile(x, y);
-    Ancilla_Sfx3_Near(10);
-  }  // endif_12_norupee
-
-  if (tiledetect_var4 & 0x22) {
-    link_on_conveyor_belt = tiledetect_var4 & 0x20 ? 2 : 1;
-  } else if (tiledetect_var4 & 0x2200) {
-    link_on_conveyor_belt = tiledetect_var4 & 0x2000 ? 4 : 3;
-  } else {
-    if (!(bitfield_spike_cactus_tiles & 7) && !(R14 & 2))
-      link_on_conveyor_belt = 0;
-  } // endif_15
-
-  if ((detection_of_ledge_tiles_horiz_uphoriz & 7) == 7 && RunLedgeHopTimer()) {
-    Link_CancelDash();
-    about_to_jump_off_ledge++;
-    link_auxiliary_state = 2;
-    goto endif_19;
-  } else if ((tiledetect_deepwater & 7) == 7 && link_is_in_deep_water == 0 && link_player_handler_state != 6) {
-    // if_20
-    link_y_coord = link_y_coord_safe_return_lo | link_y_coord_safe_return_hi << 8;
-    link_x_coord = link_x_coord_safe_return_lo | link_x_coord_safe_return_hi << 8;
-    Link_CancelDash();
-    if (TS_copy == 0) {
-      Dungeon_HandleLayerChange();
-    } else {
-      link_is_in_deep_water = 1;
-      link_some_direction_bits = link_direction_last;
-      link_state_bits = 0;
-      link_picking_throw_state = 0;
-      link_grabbing_wall = 0;
-      link_speed_setting = 0;
-      Link_ResetSwimmingState();
-    }
-endif_19:
-    link_disable_sprite_damage = 1;
-    Link_HopInOrOutOfWater_X();
-    Ancilla_Sfx2_Near(0x20);
-  } else {
-    // else_20
-    if ((tiledetect_normal_tiles & 7) == 7 && link_is_in_deep_water != 0) {
-      if (link_auxiliary_state != 0) {
-        R14 = 7;
-      } else {
-        Link_CancelDash();
-        if (link_auxiliary_state == 0) {
-          link_direction_last = link_some_direction_bits;
-          link_is_in_deep_water = 0;
-          AncillaAdd_Splash(0x15, 0);
-          link_disable_sprite_damage = 1;
-          Link_HopInOrOutOfWater_X();
-        }
-      }
-    }
-  } // endif_21
-
-  if (tiledetect_pit_tile & 5 && (R14 & 2) == 0) {
-    if (link_player_handler_state == 5 || link_player_handler_state == 2)
-      return;
-    byte_7E005C = 9;
-    link_this_controls_sprite_oam = 0;
-    player_near_pit_state = 1;
-    link_player_handler_state = kPlayerState_FallingIntoHole;
-    return;
-  } // endif_23
-
-  player_near_pit_state = 0;
-
-  if (bitfield_spike_cactus_tiles & 7) {
-    if ((link_incapacitated_timer | countdown_for_blink | link_cape_mode) == 0) {
-      if (((link_last_direction_moved_towards == 2) ? (link_x_coord & 4) == 0 : ((link_x_coord & 4) != 0)) && (countdown_for_blink == 0)) {
-        link_give_damage = 8;
-        Link_CancelDash();
-        Link_ForceUnequipCape_quietly();
-        LinkApplyTileRebound();
-        return;
-      }
-    } else {
-      R14 &= ~0xFF;
-      R14 |= bitfield_spike_cactus_tiles & 7;
-    } // endif_24
-  } // endif_24
-  if (dung_hdr_collision == 0 || dung_hdr_collision == 4 || !link_is_on_lower_level) {
-    if (tiledetect_var2 && link_num_orthogonal_directions == 0) {
-      byte_7E02C2 = tiledetect_var2;
-      if (!sign8(--gravestone_push_timeout))
-        goto endif_26;
-      uint16 bits = tiledetect_var2;
-      int i = 15;
-      do {
-        if (bits & 0x8000) {
-          uint8 idx = FindFreeMovingBlockSlot(i);
-          if (idx == 0xff)
-            continue;
-          R14 = idx;  // This seems like it's overwriting the tiledetector's stuff
-          if (InitializePushBlock(idx, i * 2))
-            continue;
-          Sprite_Dungeon_DrawSinglePushBlock(idx * 2);
-          R14 = 4;
-          pushedblock_facing[idx] = link_last_direction_moved_towards * 2;
-          push_block_direction = link_last_direction_moved_towards * 2;
-          pushedblocks_target[idx] = (pushedblocks_x_lo[idx] - (link_last_direction_moved_towards != 2)) & 0xf;
-        }
-      } while (bits <<= 1, --i >= 0);
-    }
-    // endif_27
-    gravestone_push_timeout = 21;
-  }
-  // endif_26
-endif_26:
-  if (link_num_orthogonal_directions == 0) {
-    link_speed_modifier = 0;
-    if (link_speed_setting == 2)
-      link_speed_setting = 0;
-  }
-  HandlePushingBonkingSnaps_X();
-}
-
-void HandlePushingBonkingSnaps_X() {  // 87c7fc
-  if (R14 & 7) {
-    if (link_player_handler_state == kPlayerState_Swimming && (uint8)dung_floor_x_vel == 0)
-      ResetAllAcceleration();
-
-    if (R14 & 2) {
-      uint16 bak = R14;
-      Link_BonkAndSmash();
-      RepelDash();
-      R14 = bak;
-    }
-
-    fallhole_var1 = 1;
-
-    if ((R14 & 7) == 7) {
-      SnapOnX();
-    } else {
-      if (link_num_orthogonal_directions == 2)
-        goto returnb;
-      SnapOnX();
-      if (link_num_orthogonal_directions == 1)
-        goto returnb;
-    } // endif_4
-
-    if ((R14 & 5) == 5) {
-      Link_BonkAndSmash();
-      RepelDash();
-    } else if (R14 & 4) {
-      uint8 tt = sign8(link_x_vel) ? link_x_vel : -link_x_vel;
-      uint8 r0 = sign8(tt) ? 0xff : 1;
-      if ((R14 & 2) == 0) {
-        if (link_y_coord & 7) {
-          link_y_coord += (int8)r0;
-          HandleNudging(r0);
-          return;
-        }
-        Link_BonkAndSmash();
-        RepelDash();
-      }
-    } else { // else_7
-      uint8 tt = sign8(link_x_vel) ? -link_x_vel : link_x_vel;
-      uint8 r0 = sign8(tt) ? 0xff : 1;
-      if ((R14 & 2) == 0) {
-        if (link_y_coord & 7) {
-          link_y_coord += (int8)r0;
-          HandleNudging(r0);
-          return;
-        }
-        Link_BonkAndSmash();
-        RepelDash();
-      }
-    }
-    // endif_10
-    if (link_last_direction_moved_towards * 2 == link_direction_facing) {
-      bitmask_of_dragstate |= (tile_coll_flag & 1) << 1;
-      if (button_b_frames == 0 && !sign8(--link_timer_push_get_tired))
-        return;
-
-      bitmask_of_dragstate |= (tiledetect_misc_tiles & 0x20) ? tile_coll_flag << 3 : tile_coll_flag;
-    }
-  } else {// else_1
-    if (link_is_on_lower_level)
-      return;
-    bitmask_of_dragstate &= ~9;
-  } // endif_1
-
-returnb:
-  link_timer_push_get_tired = 32;
-  bitmask_of_dragstate &= ~2;
-}
-
-void StartMovementCollisionChecks_X_HandleOutdoors() {  // 87c8e9
-  if (link_num_orthogonal_directions == 0) {
-    link_speed_modifier = 0;
-    if (link_speed_setting == 2)
-      link_speed_setting = 0;
-  }
-
-  if ((tiledetect_pit_tile & 5) != 0 && (R14 & 2) == 0) {
-    if (link_player_handler_state != 5 && link_player_handler_state != 2) {
-      // start fall into hole
-      byte_7E005C = 9;
-      link_this_controls_sprite_oam = 0;
-      player_near_pit_state = 1;
-      link_player_handler_state = kPlayerState_FallingIntoHole;
-    }
-    return;
-  }
-
-  if (tiledetect_read_something & 2) {
-    interacting_with_liftable_tile_x1b = interacting_with_liftable_tile_x2 >> 1;
-  } else {
-    interacting_with_liftable_tile_x1b = 0;
-  }  // endif_2
-
-  if ((tiledetect_deepwater & 4) && !link_is_in_deep_water && !link_auxiliary_state) {
-    Link_CancelDash();
-    Link_ResetSwordAndItemUsage();
-    link_is_in_deep_water = 1;
-    link_some_direction_bits = link_direction_last;
-    Link_ResetSwimmingState();
-    link_grabbing_wall = 0;
-    link_speed_setting = 0;
-    if ((draw_water_ripples_or_grass == 1) && (Link_ForceUnequipCape_quietly(), link_item_flippers != 0)) {
-      if (!link_is_bunny_mirror)
-        link_player_handler_state = kPlayerState_Swimming;
-    } else {
-      link_y_coord = (link_y_coord_safe_return_hi << 8) | link_y_coord_safe_return_lo;
-      link_x_coord = (link_x_coord_safe_return_hi << 8) | link_x_coord_safe_return_lo;
-      link_disable_sprite_damage = 1;
-      Link_HopInOrOutOfWater_X();
-      Ancilla_Sfx2_Near(0x20);
-    }
-  }  // endif_afterSwimCheck
-
-  if (link_is_in_deep_water ? ((detection_of_ledge_tiles_horiz_uphoriz & 7) == 7) : (tiledetect_vertical_ledge & 0x42)) {
-    // not implemented, jumps to another routine
-    R14 = 7;
-    HandlePushingBonkingSnaps_X();
-    return;
-  } // endif_3
-
-  if ((tiledetect_normal_tiles & 7) == 7 && link_is_in_deep_water) {
-    Link_CancelDash();
-    if (!link_auxiliary_state) {
-      link_direction_last = link_some_direction_bits;
-      link_is_in_deep_water = 0;
-      AncillaAdd_Splash(0x15, 0);
-      link_disable_sprite_damage = 1;
-      Link_HopInOrOutOfWater_X();
-      return;
-    }
-  }  // endif_4
-
-  if ((detection_of_ledge_tiles_horiz_uphoriz & 7) != 0 && RunLedgeHopTimer()) {
-    Ancilla_Sfx2_Near(0x20);
-    link_actual_vel_x = (link_last_direction_moved_towards & 1) ? 0x10 : -0x10;
-    Link_CancelDash();
-    link_auxiliary_state = 2;
-    link_actual_vel_z_mirror = link_actual_vel_z_copy_mirror = 20;
-    link_z_coord_mirror |= 0xff;
-    link_player_handler_state = kPlayerState_FallOfLeftRightLedge;
-    link_disable_sprite_damage = 1;
-    allow_scroll_z = 1;
-    bitmask_of_dragstate = 0;
-    link_speed_setting = 0;
-    if (!player_is_indoors)
-      link_is_on_lower_level = 2;
-
-    uint16 xbak = link_x_coord;
-    uint8 rv = Link_HoppingHorizontally_FindTile_X((link_last_direction_moved_towards & ~2) * 2);
-    link_last_direction_moved_towards = 1;
-    if (rv != 0xff) {
-      Link_HoppingHorizontally_FindTile_Y();
-    } else {
-      LinkHop_FindTileToLandOnSouth();
-    }
-    link_x_coord = xbak;
-    return;
-  }  // endif_5
-
-  if ((detection_of_unknown_tile_types & 0x77) != 0 && RunLedgeHopTimer()) {
-    uint8 sfx = Ancilla_Sfx2_Near(0x20);
-    link_player_handler_state = (sfx & 7) == 0 ? 16 : 15;
-    link_actual_vel_x = (link_last_direction_moved_towards & 1) ? 0x10 : -0x10;
-    Link_CancelDash();
-    link_auxiliary_state = 2;
-    link_actual_vel_z_mirror = link_actual_vel_z_copy_mirror = 20;
-    link_z_coord_mirror |= 0xff;
-    link_incapacitated_timer = 0;
-    link_disable_sprite_damage = 1;
-    allow_scroll_z = 1;
-    bitmask_of_dragstate = 0;
-    link_speed_setting = 0;
-    return;
-  }  // endif_6
-
-  if ((detection_of_ledge_tiles_horiz_uphoriz & 0x70) != 0 &&
-      (detection_of_ledge_tiles_horiz_uphoriz & 0x7) == 0 &&
-      (detection_of_unknown_tile_types & 0x77) == 0 &&
-      link_player_handler_state != 13 && RunLedgeHopTimer()) {
-    Ancilla_Sfx2_Near(0x20);
-    Link_CancelDash();
-    link_disable_sprite_damage = 1;
-    bitmask_of_dragstate = 0;
-    link_speed_setting = 0;
-    Link_FindValidLandingTile_DiagonalNorth();
-    return;
-  }  // endif_7
-
-  if ((tiledetect_ledges_down_leftright & 7) != 0 && (detection_of_ledge_tiles_horiz_uphoriz & 7) == 0 &&
-      (detection_of_unknown_tile_types & 0x77) == 0 && RunLedgeHopTimer()) {
-    link_actual_vel_x = (link_last_direction_moved_towards & 1) ? 0x10 : -0x10;
-    Link_CancelDash();
-    link_auxiliary_state = 2;
-    link_actual_vel_z_mirror = link_actual_vel_z_copy_mirror = 20;
-    link_z_coord_mirror |= 0xff;
-    link_player_handler_state = 14;
-    link_incapacitated_timer = 0;
-    link_disable_sprite_damage = 1;
-    allow_scroll_z = 1;
-    bitmask_of_dragstate = 0;
-    link_speed_setting = 0;
-    return;
-  } // endif_8
-
-  // If force facing down (hold B button), while turboing on the Run key, we'll never
-  // reach FlagMovingIntoSlopes_X causing a Dash Buffering glitch.
-  // Fix by always calling it, not sure why you wouldn't always want to call it.
-  if ((R14 & 2) == 0 && (R12 & 5) != 0) {
-    bool skip_check = link_is_running && !(link_direction_facing & 4);
-    if (!skip_check || (enhanced_features0 & kFeatures0_MiscBugFixes)) {
-      FlagMovingIntoSlopes_X();
-      if ((link_moving_against_diag_tile & 0xf) != 0)
-        return;
-    }  // endif_9
-  }
-
-  link_moving_against_diag_tile = 0;
-
-  if ((bitfield_spike_cactus_tiles & 7) != 0) {
-    if ((link_incapacitated_timer | countdown_for_blink | link_cape_mode) == 0) {
-      if (link_last_direction_moved_towards == 2 ? ((link_x_coord & 4) == 0) : ((link_x_coord & 4) != 0)) {
-        link_give_damage = 8;
-        Link_CancelDash();
-        LinkApplyTileRebound();
-        return;
-      }
-    } else {
-      R14 = bitfield_spike_cactus_tiles & 7;
-    }
-  }  // endif_10
-  HandlePushingBonkingSnaps_X();
-}
-
-void SnapOnX() {  // 87cb84
-  link_x_coord -= (link_x_coord & 7) - (sign8(link_x_vel) ? 8 : 0);
-}
-
-void CalculateSnapScratch_X() {  // 87cb9f
-  if (R14 & 4) {
-    int8 x = link_x_vel;
-    if (x >= 0) x = -x; // wtf
-    link_y_coord += x < 0 ? -1 : 1;
-  } else {
-    int8 x = link_x_vel;
-    if (x < 0) x = -x;
-    link_y_coord += x < 0 ? -1 : 1;
-  }
-}
-
-int8 ChangeAxisOfPerpendicularDoorMovement_X() {  // 87cbdd
-  link_cant_change_direction |= 2;
-  uint8 r0 = (R14 | (R14 >> 4)) & 0xf;
-  if ((r0 & 7) == 0) {
-    is_standing_in_doorway = 0;
-    return r0; // wtf?
-  }
-
-  int8 x_vel = link_x_vel;
-  uint8 dir;
-  if ((uint8)link_y_coord >= 0x80) {
-    if (x_vel >= 0) x_vel = -x_vel;
-    dir = 0;
-  } else {
-    if (x_vel < 0) x_vel = -x_vel;
-    dir = 2;
-  }
-  if (!(link_cant_change_direction & 1))
-    link_direction_facing = dir;
-  link_y_coord += x_vel;
-  return x_vel;
-}
-
-void Link_HopInOrOutOfWater_X() {  // 87cc3c
-  static const uint8 kRecoilVelX[] = { 28, 24, 16 };
-  static const uint8 kRecoilVelZ[] = { 32, 24, 24 };
-
-  uint8 ts = !player_is_indoors ? 2 :
-    about_to_jump_off_ledge ? 0 : TS_copy;
-
-  int8 vel = kRecoilVelX[ts];
-  if (!(link_last_direction_moved_towards & 1))
-    vel = -vel;
-  link_actual_vel_x = vel;
-  link_actual_vel_y = 0;
-  link_actual_vel_z_copy = link_actual_vel_z = kRecoilVelZ[ts];
-  link_incapacitated_timer = 16;
-  if (link_auxiliary_state != 2) {
-    link_auxiliary_state = 1;
-    link_electrocute_on_touch = 0;
-  }
-  link_player_handler_state = 6;
-}
-
-void Link_HandleDiagonalKickback() {  // 87ccab
-  if (link_x_vel && link_y_vel) {
-    link_y_coord_copy = link_y_coord;
-    link_x_coord_copy = link_x_coord;
-
-    TileDetect_Movement_X(sign8(link_x_vel) ? 2 : 3);
-    if ((R12 & 5) == 0)
-      goto noHorizOrNoVertical;
-    FlagMovingIntoSlopes_X();
-    if (!(link_moving_against_diag_tile & 0xf))
-      goto noHorizOrNoVertical;
-
-    int8 xd = link_x_coord - link_x_coord_copy;
-    link_x_coord = link_x_coord_copy;
-    link_x_vel = xd;
-
-    TileDetect_Movement_Y(sign8(link_y_vel) ? 0 : 1);
-    if ((R12 & 5) == 0)
-      goto noHorizOrNoVertical;
-    FlagMovingIntoSlopes_Y();
-    if (!(link_moving_against_diag_tile & 0xf))
-      goto noHorizOrNoVertical;
-
-    moving_against_diag_deadlocked = link_moving_against_diag_tile;
-
-    int8 yd = link_y_coord - link_y_coord_copy;
-    link_y_vel = yd;
-
-    static const int8 x0[] = { 0, 1, 1, 1, 2, 2, 2, 3, 3, 3 };
-    static const int8 x1[] = { 0, -1, -1, -1, -2, -2, -2, -3, -3, -3 };
-    link_x_coord += sign8(link_x_vel) ? x1[-(int8)link_x_vel] : x0[link_x_vel];
-
-    static const int8 y0[10] = { 0, 0, 0, 1, 1, 1, 2, 2, 2, 3 };
-    // Bug in zelda, might read index 15
-    static const int8 y1[16] = { 0, 1, 1, 2, 2, 2, 3, 3, 3, 3, 0xa5, 0x30, 0xf0, 0x04, 0xa5, 0x31 };
-    link_y_coord += sign8(link_y_vel) ? y1[-(int8)link_y_vel] : y0[link_y_vel];
-  } else {
-noHorizOrNoVertical:
-    moving_against_diag_deadlocked = 0;
-  }
-  link_moving_against_diag_tile = 0;
-}
-
-void TileDetect_MainHandler(uint8 item) {  // 87d077
-  tiledetect_pit_tile = 0;
-  TileDetect_ResetState();
-  uint16 o;
-
-  if (item == 8) {
-    int16 a = state_for_spin_attack - 2;
-    if (a < 0 || a >= 8)
-      return;
-    static const uint8 kDoSwordInteractionWithTiles_o[] = { 10, 6, 14, 2, 12, 4, 8, 0 };
-    o = kDoSwordInteractionWithTiles_o[a] + 0x40;
-  } else {
-    o = item * 8 + link_direction_facing;
-  }
-  o >>= 1;
-
-  static const int8 kDoSwordInteractionWithTiles_x[] = { 8, 8, 8, 8, 6, 8, -1, 22, 19, 19, 0, 19, 6, 8, -1, 22, 8, 8, 8, 8, 8, 8, 0, 15, 6, 8, -10, 29, 6, 8, -6, 22, 6, 8, -4, 22, -4, 22, -4, 22 };
-  static const int8 kDoSwordInteractionWithTiles_y[] = { 20, 20, 20, 20, 4, 28, 16, 16, 22, 22, 22, 22, 4, 24, 16, 16, 16, 16, 16, 16, 20, 20, 23, 23, -4, 36, 16, 16, 4, 28, 16, 16, 4, 28, 16, 16, 4, 4, 28, 28 };
-  uint16 x = ((link_x_coord + kDoSwordInteractionWithTiles_x[o]) & tilemap_location_calc_mask) >> 3;
-  uint16 y = ((link_y_coord + kDoSwordInteractionWithTiles_y[o]) & tilemap_location_calc_mask);
-
-  if (item == 1 || item == 2 || item == 3 || item == 6 || item == 7 || item == 8) {
-    TileBehavior_HandleItemAndExecute(x, y);
-    return;
-  }
-
-  TileDetection_Execute(x, y, 1);
-
-  if (item == 5)
-    return;
-
-  if (tiledetect_thick_grass & 0x10) {
-    uint8 tx = (link_x_coord + 0) & 0xf;
-    uint8 ty = (link_y_coord + 8) & 0xf;
-
-    if ((ty < 4 || ty >= 11) && (tx < 4 || tx >= 12) && countdown_for_blink == 0 && link_auxiliary_state == 0) {
-      if (player_is_indoors) {
-        Dungeon_FlagRoomData_Quadrants();
-        Ancilla_Sfx2_Near(0x33);
-        link_speed_setting = 0;
-        submodule_index = 21;
-        BYTE(dungeon_room_index_prev) = dungeon_room_index;
-        BYTE(dungeon_room_index) = dung_hdr_travel_destinations[0];
-        HandleLayerOfDestination();
-      } else if (!link_triggered_by_whirlpool_sprite) {
-        DoSwordInteractionWithTiles_Mirror();
-      }
-    }
-  } else {  // else_3
-    link_triggered_by_whirlpool_sprite = 0;
-    if (tiledetect_thick_grass & 1) {
-      draw_water_ripples_or_grass = 2;
-      if (!Link_PermissionForSloshSounds() && link_auxiliary_state == 0)
-        Ancilla_Sfx2_Near(26);
-      return;
-    }
-
-    if (tiledetect_shallow_water & 1) {
-      draw_water_ripples_or_grass = 1;
-
-      if (!player_is_indoors && link_is_in_deep_water && !link_is_bunny_mirror) {
-        if (link_item_flippers) {
-          link_is_in_deep_water = 0;
-          link_direction_last = link_some_direction_bits;
-          link_player_handler_state = 0;
-        }
-      } else if (!Link_PermissionForSloshSounds()) {
-        if ((uint8)overworld_screen_index == 0x70) {
-          Ancilla_Sfx2_Near(27);
-        } else if (link_auxiliary_state == 0) {
-          Ancilla_Sfx2_Near(28);
-        }
-      }
-      return;
-    }
-
-    if (!player_is_indoors && !link_is_in_deep_water && (tiledetect_deepwater & 1)) {
-      draw_water_ripples_or_grass = 1;
-      if (!Link_PermissionForSloshSounds()) {
-        if ((uint8)overworld_screen_index == 0x70) {
-          Ancilla_Sfx2_Near(27);
-        } else if (link_auxiliary_state == 0) {
-          Ancilla_Sfx2_Near(28);
-        }
-      }
-      return;
-    }
-  }
-  // else_6
-  draw_water_ripples_or_grass = 0;
-
-  if (tiledetect_spike_floor_and_tile_triggers & 1) {
-    byte_7E02ED = 1;
-    return;
-  }
-
-  byte_7E02ED = 0;
-
-  if (tiledetect_spike_floor_and_tile_triggers & 0x10) {
-    link_give_damage = 0;
-    if (!link_cape_mode && !SearchForByrnaSpark() && !countdown_for_blink) {
-      link_need_for_poof_for_transform = 0;
-      link_timer_tempbunny = 0;
-      if (link_item_moon_pearl) {
-        link_is_bunny = 0;
-        link_is_bunny_mirror = 0;
-      }
-      link_give_damage = 8;
-      Link_CancelDash();
-      return;
-    }
-  }
-
-  if (tiledetect_icy_floor & 0x11) {
-    if (link_flag_moving) {
-      if (link_num_orthogonal_directions)
-        link_direction_last = link_some_direction_bits;
-    } else { // else_11
-      if (link_direction & 0xC)
-        swimcoll_var7[0] = 0x180;
-      if (link_direction & 3)
-        swimcoll_var7[0] = 0x180;
-
-      link_flag_moving = (tiledetect_icy_floor & 1) ? 1 : 2;
-      link_some_direction_bits = link_direction_last;
-      Link_ResetSwimmingState();
-    }
-  } else {
-    if (link_player_handler_state != 4) {
-      if (link_flag_moving)
-        link_direction_last = link_some_direction_bits;
-      Link_ResetSwimmingState();
-    }
-    link_flag_moving = 0;
-  }
-
-  if ((bitfield_spike_cactus_tiles & 0x10) && countdown_for_blink == 0)
-    countdown_for_blink = 58;
-}
-
-bool Link_PermissionForSloshSounds() {  // 87d2c6
-  if (!(link_direction & 0xf))
-    return true;
-  if (link_player_handler_state != 17) {
-    return (frame_counter & 0xf) != 0;
-  } else {
-    return (frame_counter & 0x7) != 0;
-  }
-}
-
-bool PushBlock_AttemptToPushTheBlock(uint8 what, uint16 x, uint16 y) {  // 87d304
-  static const int8 kChangableDungeonObj_Func1B_y0[4] = { -4, 20, 4, 4 };
-  static const int8 kChangableDungeonObj_Func1B_y1[4] = { -4, 20, 12, 12 };
-  static const int8 kChangableDungeonObj_Func1B_x0[4] = { 4, 4, -4, 20 };
-  static const int8 kChangableDungeonObj_Func1B_x1[4] = { 12, 12, -4, 20 };
-  static const uint8 T[256] = {
-    0, 1, 2, 3, 2, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0,
-    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1,
-    0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1,
-    0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1,
-    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-    0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
-
-  };
-
-  uint8 idx = what * 4 + link_last_direction_moved_towards, xt;
-  uint16 new_x, new_y;
-
-  new_x = ((x + kChangableDungeonObj_Func1B_x0[idx]) & tilemap_location_calc_mask) >> 3;
-  new_y = ((y + kChangableDungeonObj_Func1B_y0[idx]) & tilemap_location_calc_mask);
-  xt = PushBlock_GetTargetTileFlag(new_x, new_y);
-  if (T[xt] != 0 && xt != 9)
-    return true;
-
-  new_x = ((x + kChangableDungeonObj_Func1B_x1[idx]) & tilemap_location_calc_mask) >> 3;
-  new_y = ((y + kChangableDungeonObj_Func1B_y1[idx]) & tilemap_location_calc_mask);
-  xt = PushBlock_GetTargetTileFlag(new_x, new_y);
-  if (T[xt] != 0 && xt != 9)
-    return true;
-
-  return false;
-}
-
-uint8 Link_HandleLiftables() {  // 87d383
-  static const uint8 kGetBestActionToPerformOnTile_a[7] = { 0, 1, 0, 0, 2, 1, 2 };
-  static const uint8 kGetBestActionToPerformOnTile_b[7] = { 2, 3, 1, 4, 0, 5, 6 };
-
-  tiledetect_pit_tile = 0;
-  TileDetect_ResetState();
-
-  uint16 y0 = (link_y_coord + kGetBestActionToPerformOnTile_y[link_direction_facing >> 1]) & tilemap_location_calc_mask;
-  uint16 y1 = (link_y_coord + 20) & tilemap_location_calc_mask;
-
-  uint16 x0 = ((link_x_coord + kGetBestActionToPerformOnTile_x[link_direction_facing >> 1]) & tilemap_location_calc_mask) >> 3;
-  uint16 x1 = ((link_x_coord + 8) & tilemap_location_calc_mask) >> 3;
-
-  TileDetection_Execute(x0, y0, 1);
-  TileDetection_Execute(x1, y1, 2);
-
-  uint8 action = ((R14 | tiledetect_vertical_ledge) & 1) ? 3 : 2;
-
-  if (player_is_indoors) {
-    uint8 a = Dungeon_CheckForAndIDLiftableTile();
-    if (a != 0xff) {
-      interacting_with_liftable_tile_x1 = kGetBestActionToPerformOnTile_b[a & 0xf];
-    } else {
-      if ((tiledetect_read_something & 1) && link_direction_facing == 0 && interacting_with_liftable_tile_x2 == 0)
-        action = 4;
-      goto getout;
-    }
-  } else {
-    if (!(tiledetect_read_something & 1))
-      goto getout;
-    if (link_direction_facing == 0 && interacting_with_liftable_tile_x2 == 0) {
-      action = 4;
-      goto getout;
-    }
-    interacting_with_liftable_tile_x1 = interacting_with_liftable_tile_x2 >> 1;
-  }
-  if (kGetBestActionToPerformOnTile_a[interacting_with_liftable_tile_x1] - link_item_gloves <= 0)
-    action = 1;
-getout:
-  if (tiledetect_chest & 1)
-    action = 5;
-  return action;
-}
-
-void HandleNudging(int8 arg_r0) {  // 87d485
-  uint8 p, o;
-
-  if ((link_last_direction_moved_towards & 2) == 0) {
-    p = (link_last_direction_moved_towards & 1) ? 4 : 0;
-    o = (R14 & 4) ? 0 : 2;
-  } else {
-    p = (link_last_direction_moved_towards & 1) ? 12 : 8;
-    o = (R14 & 4) ? 0 : 2;
-  }
-  o = (o + p) >> 1;
-
-  tiledetect_pit_tile = 0;
-  TileDetect_ResetState();
-
-  uint16 y0 = (link_y_coord + kLink_Move_Helper6_tab0[o]) & tilemap_location_calc_mask;
-  uint16 x0 = ((link_x_coord + kLink_Move_Helper6_tab1[o]) & tilemap_location_calc_mask) >> 3;
-
-  uint16 y1 = (link_y_coord + kLink_Move_Helper6_tab2[o]) & tilemap_location_calc_mask;
-  uint16 x1 = ((link_x_coord + kLink_Move_Helper6_tab3[o]) & tilemap_location_calc_mask) >> 3;
-
-  TileDetection_Execute(x0, y0, 1);
-  TileDetection_Execute(x1, y1, 2);
-
-  if ((R14 | detection_of_ledge_tiles_horiz_uphoriz) & 3 ||
-      (tiledetect_vertical_ledge | detection_of_unknown_tile_types) & 0x33) {
-
-    if (link_last_direction_moved_towards & 2)
-      link_y_coord -= arg_r0;
-    else
-      link_x_coord -= arg_r0;
-  }
-}
-
-void TileBehavior_HandleItemAndExecute(uint16 x, uint16 y) {  // 87dc4a
-  uint8 tile = HandleItemTileAction_Overworld(x, y);
-  TileDetect_ExecuteInner(tile, 0, 1, false);
-}
-
-uint8 PushBlock_GetTargetTileFlag(uint16 x, uint16 y) {  // 87e026
-  return dung_bg2_attr_table[(y & ~7) * 8 + (x & 0x3f) + (link_is_on_lower_level ? 0x1000 : 0)];
-}
-
-void FlagMovingIntoSlopes_Y() {  // 87e076
-  int8 y = (tiledetect_which_y_pos[0] & 7);
-  uint8 o = (tiledetect_diag_state * 4) + ((link_x_coord - ((R12 & 4) != 0)) & 7);
-
-  if (tiledetect_diagonal_tile & 5) {
-    int8 ym = tiledetect_which_y_pos[0] & 7;
-
-    if (enhanced_features0 & kFeatures0_MiscBugFixes) {
-      if (tiledetect_diag_state & 2) {
-        ym = -ym;
-      } else {
-        ym = kAvoidJudder1[o] - (8 - ym);
-      }
-    } else {
-      // This code is bad because it could cause the player
-      // to move up to 15 pixels, causing an array out bounds read.
-      // Not sure how it works, but changed it to look more like the X version.
-      if (!(tiledetect_diag_state & 2)) {
-        ym = 8 - ym; // 0 to 8
-      } else {
-        ym += 8; // 8 to 15
-      }
-      // -15 to 7
-      ym = kAvoidJudder1[o] - ym;
-    }
-
-    if (link_y_vel == 0)
-      return;
-    if (sign8(link_y_vel))
-      ym = -ym;
-    y = ym;
-  } else {  // else_1
-    y = kAvoidJudder1[o] - y;
-  } // endif_1
-
-  if (sign8(link_y_vel)) {
-    if (y <= 0)
-      return;
-    link_y_coord += y;
-    link_moving_against_diag_tile = 8;
-  } else {
-    if (y >= 0)
-      return;
-    link_y_coord += y;
-    link_moving_against_diag_tile = 4;
-  }
-  link_moving_against_diag_tile |= (R12 & 4) ? 0x10 + 2 : 0x10 + 1;
-}
-
-void FlagMovingIntoSlopes_X() {  // 87e112
-  int8 x = (link_x_coord - (tiledetect_diag_state == 6)) & 7;
-  uint8 o = (tiledetect_diag_state * 4) + (tiledetect_which_y_pos[(R12 & 4) ? 1 : 0] & 7);
-
-  if (tiledetect_diagonal_tile & 5) {
-    int8 xm = link_x_coord & 7;
-
-    if (tiledetect_diag_state != 4 && tiledetect_diag_state != 6) {
-      xm = -xm;
-    } else {
-      xm = kAvoidJudder1[o] - (8 - xm);
-    } // endif_5
-    if (link_x_vel == 0)
-      return;
-    if (sign8(link_x_vel))
-      xm = -xm;
-    x = xm;
-  } else {  // else_1
-    x = kAvoidJudder1[o] - x;
-  } //  endif_1
-
-  if (sign8(link_x_vel)) {
-    if (x <= 0)
-      return;
-    link_x_coord += x;
-    link_moving_against_diag_tile = 2;
-  } else {
-    if (x >= 0)
-      return;
-    link_x_coord += x;
-    link_moving_against_diag_tile = 1;
-  }
-  link_moving_against_diag_tile |= (tiledetect_diag_state & 2) ? 0x20 + 8 : 0x20 + 4;
-}
-
-void Link_HandleRecoiling() {  // 87e1be
-  link_direction = 0;
-  if (link_actual_vel_y) {
-    link_direction_last = (link_direction |= sign8(link_actual_vel_y) ? 8 : 4);
-    Player_HandleIncapacitated_Inner2();
-  }
-  if (link_actual_vel_x)
-    link_direction_last = (link_direction |= sign8(link_actual_vel_x) ? 2 : 1);
-  Player_HandleIncapacitated_Inner2();
-}
-
-void Player_HandleIncapacitated_Inner2() {  // 87e1d7
-  if ((link_moving_against_diag_tile & 0xc) && (link_moving_against_diag_tile & 3) && link_player_handler_state == 2) {
-    link_actual_vel_x = -link_actual_vel_x;
-    link_actual_vel_y = -link_actual_vel_y;
-  }
-  if (is_standing_in_doorway == 1) {
-    link_direction_last &= 0xc;
-    link_direction &= 0xc;
-    link_actual_vel_x = 0;
-  } else if (is_standing_in_doorway == 2) {
-    link_direction_last &= 3;
-    link_direction &= 3;
-    link_actual_vel_y = 0;
-  }
-}
-
-void Link_HandleVelocity() {  // 87e245
-  if (submodule_index == 2 && main_module_index == 14 || link_prevent_from_moving) {
-    link_y_coord_safe_return_lo = link_y_coord;
-    link_y_coord_safe_return_hi = link_y_coord >> 8;
-    link_x_coord_safe_return_lo = link_x_coord;
-    link_x_coord_safe_return_hi = link_x_coord >> 8;
-    Link_HandleVelocityAndSandDrag(link_x_coord, link_y_coord);
-    return;
-  }
-
-  if (link_player_handler_state == kPlayerState_Swimming) {
-    HandleSwimStrokeAndSubpixels();
-    return;
-  }
-  uint8 r0;
-
-  if (link_flag_moving) {
-    if (!link_is_running) {
-      HandleSwimStrokeAndSubpixels();
-      return;
-    }
-    r0 = 24;
-  } else {
-    if (link_is_running) {
-      link_speed_modifier = 0;
-      assert(link_dash_ctr >= 32);
-    }
-
-    if ((byte_7E0316 | byte_7E0317) == 0xf)
-      return;
-
-    r0 = link_speed_setting;
-    if (draw_water_ripples_or_grass) {
-      r0 = (link_speed_setting == 16) ? 22 :
-        (link_speed_setting == 12) ? 14 : 12;
-    }
-  }  // endif_4
-
-  link_actual_vel_x = link_actual_vel_y = 0;
-  link_y_page_movement_delta = link_x_page_movement_delta = 0;
-
-  r0 += ((link_direction & 0xC) != 0 && (link_direction & 3) != 0);
-
-  if (player_near_pit_state) {
-    if (player_near_pit_state == 3)
-      link_speed_modifier = (link_speed_modifier < 48) ? link_speed_modifier + 8 : 32;
-  } else {
-    if (link_speed_modifier) {
-      r0 = (submodule_index == 8 || submodule_index == 16) ? 10 : 2;
-      if (link_speed_modifier != 1) {
-        if (link_speed_modifier < 16) {
-          link_speed_modifier += 1;
-          r0 = 26; // kSpeedMod[26] is 0
-        } else {
-          link_speed_modifier = 0;
-          link_speed_setting = 0;
-        }
-      }
-    }
-  } // endif_7
-
-  static const uint8 kSpeedMod[27] = { 24, 16, 10, 24, 16, 8, 8, 4, 12, 16, 9, 25, 20, 13, 16, 8, 64, 42, 16, 8, 4, 2, 48, 24, 32, 21, 0 };
-
-  uint8 vel = link_speed_modifier + kSpeedMod[r0];
-  if (link_direction & 3)
-    link_actual_vel_x = (link_direction & 2) ? -vel : vel;
-  if (link_direction & 0xC)
-    link_actual_vel_y = (link_direction & 8) ? -vel : vel;
-
-  link_actual_vel_z = 0xff;
-  link_z_coord = 0xffff;
-  link_subpixel_z = 0;
-  Link_MovePosition();
-}
-
-void Link_MovePosition() {  // 87e370
-  uint16 x = link_x_coord, y = link_y_coord;
-  link_y_coord_safe_return_lo = link_y_coord;
-  link_y_coord_safe_return_hi = link_y_coord >> 8;
-  link_x_coord_safe_return_lo = link_x_coord;
-  link_x_coord_safe_return_hi = link_x_coord >> 8;
-
-  if (link_player_handler_state != 10 && player_on_somaria_platform == 2) {
-    Link_HandleVelocityAndSandDrag(x, y);
-    return;
-  }
-
-  uint32 tmp;
-  tmp = link_subpixel_x + (int8)link_actual_vel_x * 16 + link_x_coord * 256;
-  link_subpixel_x = (uint8)tmp, link_x_coord = (tmp >> 8);
-  tmp = link_subpixel_y + (int8)link_actual_vel_y * 16 + link_y_coord * 256;
-  link_subpixel_y = (uint8)tmp, link_y_coord = (tmp >> 8);
-  if (link_auxiliary_state) {
-    tmp = link_subpixel_z + (int8)link_actual_vel_z * 16 + link_z_coord * 256;
-    link_subpixel_z = (uint8)tmp, link_z_coord = (tmp >> 8);
-  }
-
-  Link_HandleMovingFloor();
-  Link_ApplyConveyor();
-  Link_HandleVelocityAndSandDrag(x, y);
-}
-
-void Link_HandleVelocityAndSandDrag(uint16 x, uint16 y) {  // 87e3e0
-  link_y_coord += drag_player_y;
-  link_x_coord += drag_player_x;
-  link_y_vel = link_y_coord - y;
-  link_x_vel = link_x_coord - x;
-}
-
-void HandleSwimStrokeAndSubpixels() {  // 87e42a
-  link_actual_vel_x = link_actual_vel_y = 0;
-
-  static const int8 kSwimmingTab4[] = { 8, -12, -8, -16, 4, -6, -12, -6, 10, -16, -12, -6 };
-  static const uint8 kSwimmingTab5[] = { ~0xc & 0xff, ~3 & 0xff };
-  static const uint8 kSwimmingTab6[] = { 8, 4, 2, 1 };
-  uint16 S[2];
-  for (int i = 1; i >= 0; i--) {
-    if ((int16)--swimcoll_var3[i] < 0) {
-      swimcoll_var3[i] = 0;
-      swimcoll_var5[i] = 1;
-    }
-    uint16 t = swimcoll_var5[i];
-    if (link_flag_moving)
-      t += link_flag_moving * 4;
-
-    uint16 sum = swimcoll_var7[i] + kSwimmingTab4[t];
-    if ((int16)sum <= 0) {
-      link_direction &= kSwimmingTab5[i];
-      link_direction_last = link_direction;
-      //link_actual_vel_y = link_y_page_movement_delta; // WTF bug?!
-      if (swimcoll_var5[i] == 2) {
-        swimcoll_var5[i] = 0;
-        swimcoll_var9[i] = 240;
-        swimcoll_var7[i] = 2;
-      } else {
-        swimcoll_var5[i] = 0;
-        swimcoll_var9[i] = 0;
-        swimcoll_var7[i] = 0;
-      }
-    } else {
-      link_direction |= kSwimmingTab6[swimcoll_var11[i] + i * 2];
-      if (sum >= swimcoll_var9[i])
-        sum = swimcoll_var9[i];
-      swimcoll_var7[i] = sum;
-    }
-    S[i] = swimcoll_var7[i];
-    if (link_num_orthogonal_directions | link_moving_against_diag_tile)
-      S[i] -= S[i] >> 2;
-    if (!swimcoll_var11[i])
-      S[i] = -S[i];
-  }
-
-  Player_SomethingWithVelocity_TiredOrSwim(S[1], S[0]);
-
-}
-
-void Player_SomethingWithVelocity_TiredOrSwim(uint16 xvel, uint16 yvel) {  // 87e4d3
-  uint16 org_x = link_x_coord, org_y = link_y_coord;
-  link_y_coord_safe_return_lo = link_y_coord;
-  link_y_coord_safe_return_hi = link_y_coord >> 8;
-  link_x_coord_safe_return_lo = link_x_coord;
-  link_x_coord_safe_return_hi = link_x_coord >> 8;
-
-  uint8 u;
-
-  uint32 tmp;
-  tmp = link_subpixel_x + (int16)xvel + link_x_coord * 256;
-  link_subpixel_x = (uint8)tmp, link_x_coord = (tmp >> 8);
-
-  u = xvel >> 8;
-  link_actual_vel_x = ((sign8(u) ? -u : u) << 4) | ((uint8)xvel >> 4);
-
-  tmp = link_subpixel_y + (int16)yvel + link_y_coord * 256;
-  link_subpixel_y = (uint8)tmp, link_y_coord = (tmp >> 8);
-  u = yvel >> 8;
-  link_actual_vel_y = ((sign8(u) ? -u : u) << 4) | ((uint8)yvel >> 4);
-
-  if (dung_hdr_collision == 4)
-    Link_ApplyMovingFloorVelocity();
-  link_x_page_movement_delta = 0;
-  link_y_page_movement_delta = 0;
-  Link_HandleVelocityAndSandDrag(org_x, org_y);
-}
-
-void Link_HandleMovingFloor() {  // 87e595
-  if (!dung_hdr_collision)
-    return;
-  if (BYTE(link_z_coord) != 0 && BYTE(link_z_coord) != 255)
-    return;
-  if (((byte_7E0322) & 3) != 3)
-    return;
-  if (link_player_handler_state == 19) // hookshot
-    return;
-
-  if (dung_floor_y_vel)
-    link_direction |= sign8(dung_floor_y_vel) ? 8 : 4;
-
-  if (dung_floor_x_vel)
-    link_direction |= sign8(dung_floor_x_vel) ? 2 : 1;
-
-  Link_ApplyMovingFloorVelocity();
-}
-
-void Link_ApplyMovingFloorVelocity() {  // 87e5cd
-  link_num_orthogonal_directions = 0;
-  link_y_coord += dung_floor_y_vel;
-  link_x_coord += dung_floor_x_vel;
-}
-
-void Link_ApplyConveyor() {  // 87e5f0
-  static const uint8 kMovePosDirFlag[4] = { 8, 4, 2, 1 };
-  static const int8 kMovingBeltY[4] = { -8, 8, 0, 0 };
-  static const int8 kMovingBeltX[4] = { 0, 0, -8, 8 };
-
-  if (!link_on_conveyor_belt)
-    return;
-  if (BYTE(link_z_coord) != 0 && BYTE(link_z_coord) != 0xff)
-    return;
-  if (link_grabbing_wall & 1 || link_player_handler_state == kPlayerState_Hookshot || link_auxiliary_state)
-    return;
-
-  int j = link_on_conveyor_belt - 1;
-  if (link_is_running && link_dash_ctr == 32 && (link_direction & kMovePosDirFlag[j]))
-    return;
-
-  link_num_orthogonal_directions = 0;
-  link_direction |= kMovePosDirFlag[j];
-
-  uint32 t = link_y_coord << 8 | dung_some_subpixel[0];
-  t += kMovingBeltY[j] << 4;
-  dung_some_subpixel[0] = t;
-  link_y_coord = t >> 8;
-
-  t = link_x_coord << 8 | dung_some_subpixel[1];
-  t += kMovingBeltX[j] << 4;
-  dung_some_subpixel[1] = t;
-  link_x_coord = t >> 8;
-}
-
-void Link_HandleMovingAnimation_FullLongEntry() {  // 87e6a6
-  if (link_player_handler_state == 4) {
-    Link_HandleMovingAnimationSwimming();
-    return;
-  }
-
-  static const uint8 kTab[4] = { 8, 4, 2, 1 };
-
-  uint8 r0 = link_direction_last;
-  uint8 y;
-  if (r0 == 0)
-    return;
-  if (link_flag_moving)
-    r0 = link_some_direction_bits;
-  if (link_cant_change_direction)
-    goto bail;
-  if (link_num_orthogonal_directions == 0)
-    goto not_diag;
-  if (is_standing_in_doorway) {
-    y = (is_standing_in_doorway * 2) & ~3;
-  } else {
-    if (r0 & kTab[link_direction_facing >> 1])
-      goto bail;
-not_diag:
-    y = (r0 & 0xc) ? 0 : 4;
-  }
-
-  if (y != 4) {
-    y += (r0 & 4) ? 2 : 0;
-  } else {
-    y += (r0 & 1) ? 2 : 0;
-  }
-  link_direction_facing = y;
-bail:
-  Link_HandleMovingAnimation_StartWithDash();
-}
-
-void Link_HandleMovingAnimation_StartWithDash() {  // 87e704
-  if (link_is_running) {
-    Link_HandleMovingAnimation_Dash();
-    return;
-  }
-
-  uint8 x = link_direction_facing >> 1;
-  if (link_speed_setting == 6) {
-    x += 4;
-  } else if (link_flag_moving) {
-    if (!(joypad1H_last & kJoypadH_AnyDir)) {
-      link_animation_steps = 0;
-      return;
-    }
-    x += 4;
-  }
-
-  static const uint8 tab2[16] = { 4, 4, 4, 4, 1, 1, 1, 1, 2, 2, 2, 2, 8, 8, 8, 8 };
-  static const uint8 tab3[24] = { 1, 2, 3, 2, 2, 2, 3, 2, 1, 1, 2, 1, 1, 1, 2, 1, 2, 2, 3, 2, 2, 2, 3, 2 };
-
-//bugfix: tempbunny animation steps are wrong due to missing check
-  if (link_player_handler_state == 23 || (enhanced_features0 & kFeatures0_MiscBugFixes && link_player_handler_state == 28)) {  // bunny states
-    if (link_animation_steps < 4 && player_on_somaria_platform != 2) {
-      if (++link_counter_var1 >= tab2[x]) {
-        link_counter_var1 = 0;
-        if (++link_animation_steps == 4)
-          link_animation_steps = 0;
-      }
-    } else {
-      link_animation_steps = 0;
-    }
-    return;
-  }
-
-  if (submodule_index == 18 || submodule_index == 19) {
-    x = 12;
-  } else if (submodule_index != kPlayerState_JumpOffLedgeDiag && (link_state_bits & 0x80) == 0) {
-    if (bitmask_of_dragstate & 0x8d) {
-      x = 12;
-    } else if (!draw_water_ripples_or_grass && !button_b_frames) {
-      // else_6
-      x = link_animation_steps;
-      if (link_speed_setting == 6)
-        x += 8;
-      if (link_flag_moving)
-        x += 8;
-      if (player_on_somaria_platform == 2)
-        return;
-      if (++link_counter_var1 >= tab3[x]) {
-        link_counter_var1 = 0;
-        if (++link_animation_steps == 9)
-          link_animation_steps = 1;
-      }
-      return;
-    }
-  }
-  // endif_4
-
-  if (link_animation_steps < 6 && player_on_somaria_platform != 2) {
-    if (++link_counter_var1 >= tab2[x]) {
-      link_counter_var1 = 0;
-      if (++link_animation_steps == 6)
-        link_animation_steps = 0;
-    }
-  } else {
-    link_animation_steps = 0;
-  }
-}
-
-void Link_HandleMovingAnimationSwimming() {  // 87e7fa
-  static const uint8 kTab[4] = { 8, 4, 2, 1 };
-  if (!link_some_direction_bits || link_cant_change_direction)
-    return;
-  uint8 y;
-
-  if (link_num_orthogonal_directions) {
-    if (is_standing_in_doorway) {
-      y = (is_standing_in_doorway * 2) & ~3;
-    } else {
-      if (link_some_direction_bits & kTab[link_direction_facing >> 1])
-        return;
-      y = link_some_direction_bits & 0xC ? 0 : 4;
-    }
-  } else {
-    y = link_some_direction_bits & 0xC ? 0 : 4;
-  }
-  if (y != 4) {
-    y += (link_some_direction_bits & 4) ? 2 : 0;
-  } else {
-    y += (link_some_direction_bits & 1) ? 2 : 0;
-  }
-  link_direction_facing = y;
-}
-
-void Link_HandleMovingAnimation_Dash() {  // 87e88f
-  static const uint8 kDashTab3[] = { 48, 36, 24, 16, 12, 8, 4 };
-  static const uint8 kDashTab4[] = { 3, 3, 5, 3, 3, 3, 5, 3, 2, 2, 4, 2, 2, 2, 4, 2, 2, 2, 3, 2, 2, 2, 3, 2, 1, 1, 2, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
-  static const uint8 kDashTab5[] = { 1, 2, 2, 2, 2, 2, 2 };
-
-  uint8 t = 6;
-  while (link_countdown_for_dash >= kDashTab3[t] && t)
-    t--;
-
-  if (button_b_frames < 9 && !draw_water_ripples_or_grass) {
-    if (++link_counter_var1 >= kDashTab4[t * 8]) {
-      link_counter_var1 = 0;
-      link_animation_steps++;
-      if (link_animation_steps == 9)
-        link_animation_steps = 1;
-    }
-  } else {
-    if (++link_counter_var1 >= kDashTab5[t]) {
-      link_counter_var1 = 0;
-      link_animation_steps++;
-      if (link_animation_steps >= 6)
-        link_animation_steps = 0;
-    }
-  }
-}
-
-void HandleIndoorCameraAndDoors() {  // 87e8f0
-  if (player_is_indoors) {
-    if (is_standing_in_doorway)
-      HandleDoorTransitions();
-    else
-      ApplyLinksMovementToCamera();
-  }
-}
-
-void HandleDoorTransitions() {  // 87e901
-  uint16 t;
-
-  link_x_page_movement_delta = 0;
-  link_y_page_movement_delta = 0;
-
-  // Using a potion might have changed us into a different module, and the routines
-  // below just increment the submodule value, causing all kinds of havoc.
-  // There's an added return to catch the same behavior a bit up, but this one catches more cases,
-  // at the expense of link already having done his movement, so by returning here we might
-  // miss handling the door causing other kinds of issues.
-  if ((enhanced_features0 & kFeatures0_MiscBugFixes) && !(main_module_index == 7 && submodule_index == 0))
-    return;
-
-  if (link_direction_last & 0xC && is_standing_in_doorway == 1) {
-    if (link_direction_last & 4) {
-      if (((t = link_y_coord + 28) & 0xfc) == 0)
-        link_y_page_movement_delta = (t >> 8) - link_y_coord_safe_return_hi;
-    } else {
-      t = link_y_coord - 18;
-      link_y_page_movement_delta = (t >> 8) - link_y_coord_safe_return_hi;
-    }
-  }
-
-  if (link_direction_last & 3 && is_standing_in_doorway == 2) {
-    if (link_direction_last & 1) {
-      if (((t = link_x_coord + 21) & 0xfc) == 0)
-        link_x_page_movement_delta = (t >> 8) - link_x_coord_safe_return_hi;
-    } else {
-      t = link_x_coord - 8;
-      link_x_page_movement_delta = (t >> 8) - link_x_coord_safe_return_hi;
-    }
-  }
-
-  if (link_x_page_movement_delta) {
-    some_animation_timer = 0;
-    link_state_bits = 0;
-    link_picking_throw_state = 0;
-    link_grabbing_wall = 0;
-    if (sign8(link_x_page_movement_delta))
-      Dung_StartInterRoomTrans_Left_Plus();
-    else
-      HandleEdgeTransitionMovementEast_RightBy8();
-  } else if (link_y_page_movement_delta) {
-    some_animation_timer = 0;
-    link_state_bits = 0;
-    link_picking_throw_state = 0;
-    link_grabbing_wall = 0;
-    if (sign8(link_y_page_movement_delta))
-      Dungeon_StartInterRoomTrans_Up();
-    else
-      HandleEdgeTransitionMovementSouth_DownBy16();
-  }
-}
-
-void ApplyLinksMovementToCamera() {  // 87e9d3
-  // Sometimes, when using spin attack, this routine will end up getting
-  // called twice in the same frame, which messes up things.
-  g_ApplyLinksMovementToCamera_called = true;
-
-  link_y_page_movement_delta = (link_y_coord >> 8) - link_y_coord_safe_return_hi;
-  link_x_page_movement_delta = (link_x_coord >> 8) - link_x_coord_safe_return_hi;
-
-  if (link_x_page_movement_delta) {
-    if (sign8(link_x_page_movement_delta))
-      AdjustQuadrantAndCamera_left();
-    else
-      AdjustQuadrantAndCamera_right();
-  }
-
-  if (link_y_page_movement_delta) {
-    if (sign8(link_y_page_movement_delta))
-      AdjustQuadrantAndCamera_up();
-    else
-      AdjustQuadrantAndCamera_down();
-  }
-}
-
-uint8 FindFreeMovingBlockSlot(uint8 x) {  // 87ed2c
-  if (index_of_changable_dungeon_objs[1] == 0) {
-    index_of_changable_dungeon_objs[1] = x + 1;
-    return 1;
-  }
-  if (index_of_changable_dungeon_objs[0] == 0) {
-    index_of_changable_dungeon_objs[0] = x + 1;
-    return 0;
-  }
-  return 0xff;
-}
-
-bool InitializePushBlock(uint8 r14, uint8 idx) {  // 87ed3f
-  uint16 pos = dung_object_tilemap_pos[idx >> 1];
-  uint16 x = (pos & 0x007e) << 2;
-  uint16 y = (pos & 0x1f80) >> 4;
-
-  x += (dung_loade_bgoffs_h_copy & 0xff00);
-  y += (dung_loade_bgoffs_v_copy & 0xff00);
-
-  pushedblocks_x_lo[r14] = (uint8)x;
-  pushedblocks_x_hi[r14] = (uint8)(x >> 8);
-  pushedblocks_y_lo[r14] = (uint8)y;
-  pushedblocks_y_hi[r14] = (uint8)(y >> 8);
-  pushedblocks_target[r14] = 0;
-  pushedblocks_subpixel[r14] = 0;
-
-  if (dung_hdr_tag[0] != 38 && dung_replacement_tile_state[idx >> 1] == 0) {
-    if (!PushBlock_AttemptToPushTheBlock(0, x, y)) {
-      Ancilla_Sfx2_Near(0x22);
-      dung_replacement_tile_state[idx >> 1] = 1;
-      return false;
-    }
-  }
-
-  index_of_changable_dungeon_objs[r14] = 0;
-  return true;
-}
-
-void Sprite_Dungeon_DrawSinglePushBlock(int j) {  // 87f0d9
-  static const uint8 kPushedBlock_Tab1[9] = { 0, 1, 2, 3, 4, 0, 0, 0, 0 };
-  static const uint8 kPushedblock_Char[4] = { 0xc, 0xc, 0xc, 0xff };
-  j >>= 1;
-  Oam_AllocateFromRegionB(4);
-  OamEnt *oam = GetOamCurPtr();
-  int y = (uint8)pushedblocks_y_lo[j] | (uint8)pushedblocks_y_hi[j] << 8;
-  int x = (uint8)pushedblocks_x_lo[j] | (uint8)pushedblocks_x_hi[j] << 8;
-  y -= BG2VOFS_copy2 + 1;
-  x -= BG2HOFS_copy2;
-  uint8 ch = kPushedblock_Char[kPushedBlock_Tab1[pushedblocks_some_index]];
-  if (ch != 0xff)
-    SetOamPlain(oam, x, y, ch, 0x20, 2);
-}
-
-void Link_Initialize() {  // 87f13c
-  link_direction_facing = 2;
-  link_direction_last = 0;
-  link_item_in_hand = 0;
-  link_position_mode = 0;
-  link_debug_value_1 = 0;
-  link_debug_value_2 = 0;
-  link_var30d = 0;
-  link_var30e = 0;
-  some_animation_timer_steps = 0;
-  link_is_transforming = 0;
-  bitfield_for_a_button = 0;
-  button_mask_b_y &= ~0x40;
-  link_state_bits = 0;
-  link_picking_throw_state = 0;
-  link_grabbing_wall = 0;
-  Link_ResetSwimmingState();
-  link_cant_change_direction &= ~1;
-  link_z_coord &= 0xff;
-  link_auxiliary_state = 0;
-  link_incapacitated_timer = 0;
-  countdown_for_blink = 0;
-  link_electrocute_on_touch = 0;
-  link_pose_for_item = 0;
-  link_cape_mode = 0;
-  Link_ForceUnequipCape_quietly();
-  Link_ResetSwordAndItemUsage();
-  link_disable_sprite_damage = 0;
-  player_handler_timer = 0;
-  link_direction &= ~0xf;
-  player_on_somaria_platform = 0;
-  link_spin_attack_step_counter = 0;
-
-  if (enhanced_features0 & kFeatures0_MiscBugFixes) {
-    // If you quit while jumping from a ledge and get hit on a platform you can go under solid layers
-    about_to_jump_off_ledge = 0;
- 
-    // If you use the mirror near a moveable statue you can pull thin air and glitch the camera
-    link_is_near_moveable_statue = 0;
-
-    // If you use the mirror on a conveyor belt you will retain momentum and clip into the entrance wall
-    link_on_conveyor_belt = 0;
-    
-    // bugfix: you use the mirror on ice, you retain momentum
-    link_flag_moving = 0;
-
-    // If you quit in the middle of red armos knight stomp the lumberjack tree will fall on its own
-    bg1_y_offset = bg1_x_offset = 0;
-      //bugfix: if you die in a dungeon as a permabunny and continue, you revert back to link
-      if (!link_item_moon_pearl && savegame_is_darkworld) {
-        link_player_handler_state = kPlayerState_PermaBunny;
-        link_is_bunny = 1;
-        link_is_bunny_mirror = 1;
-        LoadGearPalettes_bunny();
-      }
-  }
-}
-
-void Link_ResetProperties_A() {  // 87f1a3
-  link_direction_last = 0;
-  link_direction = 0;
-  link_flag_moving = 0;
-  Link_ResetSwimmingState();
-  link_is_transforming = 0;
-  countdown_for_blink = 0;
-  ancilla_arr24[0] = 0;
-  link_is_bunny = 0;
-  link_is_bunny_mirror = 0;
-  BYTE(link_timer_tempbunny) = 0;
-  link_need_for_poof_for_transform = 0;
-  is_archer_or_shovel_game = 0;
-  link_need_for_pullforrupees_sprite = 0;
-  BYTE(bit9_of_xcoord) = 0;
-  link_something_with_hookshot = 0;
-  link_give_damage = 0;
-  link_spin_offsets = 0;
-  tagalong_event_flags = 0;
-  link_want_make_noise_when_dashed = 0;
-  BYTE(tiledetect_tile_type) = 0;
-  item_receipt_method = 0;
-  link_triggered_by_whirlpool_sprite = 0;
-  Link_ResetProperties_B();
-}
-
-void Link_ResetProperties_B() {  // 87f1e6
-  player_on_somaria_platform = 0;
-  link_spin_attack_step_counter = 0;
-  fallhole_var1 = 0;
-  flag_is_sprite_to_pick_up_cached = 0;
-  bitmask_of_dragstate = 0;
-  link_this_controls_sprite_oam = 0;
-  player_near_pit_state = 0;
-  Link_ResetProperties_C();
-}
-
-void Link_ResetProperties_C() {  // 87f1fa
-  if (enhanced_features0 & kFeatures0_MiscBugFixes) {
-    // Fix save menu lockout when dying after medallion cast (#126)
-    flag_custom_spell_anim_active = 0;
-  }
-
-  tile_action_index = 0;
-  state_for_spin_attack = 0;
-  step_counter_for_spin_attack = 0;
-  tile_coll_flag = 0;
-  link_force_hold_sword_up = 0;
-  link_sword_delay_timer = 0;
-  tiledetect_misc_tiles = 0;
-  link_item_in_hand = 0;
-  link_position_mode = 0;
-  link_debug_value_1 = 0;
-  link_debug_value_2 = 0;
-  link_var30d = 0;
-  link_var30e = 0;
-  some_animation_timer_steps = 0;
-  bitfield_for_a_button = 0;
-  button_mask_b_y = 0;
-  button_b_frames = 0;
-  link_state_bits = 0;
-  link_picking_throw_state = 0;
-  link_grabbing_wall = 0;
-  link_cant_change_direction = 0;
-  link_auxiliary_state = 0;
-  link_incapacitated_timer = 0;
-  link_electrocute_on_touch = 0;
-  link_pose_for_item = 0;
-  link_cape_mode = 0;
-  Link_ResetSwordAndItemUsage();
-  link_disable_sprite_damage = 0;
-  player_handler_timer = 0;
-  related_to_hookshot = 0;
-  flag_is_ancilla_to_pick_up = 0;
-  flag_is_sprite_to_pick_up = 0;
-  link_need_for_pullforrupees_sprite = 0;
-  link_is_near_moveable_statue = 0;
-}
-
-bool Link_CheckForEdgeScreenTransition() {  // 87f439
-  uint8 st = link_player_handler_state;
-  if (st == 3 || st == 8 || st == 9 || st == 10 || !link_incapacitated_timer)
-    return false;
-  link_actual_vel_x = link_actual_vel_y = 0;
-  link_recoilmode_timer = 3;
-  link_x_coord = link_x_coord_prev;
-  link_y_coord = link_y_coord_prev;
-  return true;
-}
-
-void CacheCameraPropertiesIfOutdoors() {  // 87f514
-  if (!player_is_indoors)
-    CacheCameraProperties();
-}
-
-void SomariaBlock_HandlePlayerInteraction(int k) {  // 88e7e6
-  cur_object_index = k;
-  if (ancilla_G[k])
-    return;
-
-  if (!ancilla_H[k]) {
-    if (link_auxiliary_state || (link_state_bits & 1) || ancilla_z[k] != 0 && ancilla_z[k] != 0xff || ancilla_K[k] || ancilla_L[k])
-      return;
-    if (!(joypad1H_last & kJoypadH_AnyDir)) {
-      ancilla_arr3[k] = 0;
-      bitmask_of_dragstate = 0;
-      ancilla_A[k] = 255;
-      if (!link_is_running) {
-        link_speed_setting = 0;
-        return;
-      }
-    } else if ((joypad1H_last & kJoypadH_AnyDir) == ancilla_arr3[k]) {
-      if (link_speed_setting == 18)
-        bitmask_of_dragstate |= 0x81;
-    } else {
-      ancilla_arr3[k] = (joypad1H_last & kJoypadH_AnyDir);
-      link_speed_setting = 0;
-    }
-
-    CheckPlayerCollOut coll_out;
-    if (!Ancilla_CheckLinkCollision(k, 4, &coll_out) || ancilla_floor[k] != link_is_on_lower_level)
-      return;
-
-    if (!link_is_running || link_dash_ctr == 64) {
-      uint8 t;
-      ancilla_x_vel[k] = 0;
-      ancilla_y_vel[k] = 0;
-      ancilla_arr3[k] = t = joypad1H_last & kJoypadH_AnyDir;
-      if (t & 3) {
-        ancilla_x_vel[k] = t & 1 ? 16 : -16;
-        ancilla_dir[k] = t & 1 ? 3 : 2;
-      } else {
-        ancilla_y_vel[k] = t & 8 ? -16 : 16;
-        ancilla_dir[k] = t & 8 ? 0 : 1;
-      }
-      if (link_actual_vel_y == 0 || link_actual_vel_x == 0) {
-        if (!Ancilla_CheckTileCollision_Class2(k)) {
-          Ancilla_MoveY(k);
-          Ancilla_MoveX(k);
-          if (!(link_state_bits & 0x80) && !(++ancilla_A[k] & 7))
-            Ancilla_Sfx2_Pan(k, 0x22);
-        }
-        bitmask_of_dragstate = 0x81;
-        link_speed_setting = 0x12;
-      }
-      Sprite_NullifyHookshotDrag();
-      return;
-    }
-    static const int8 kSomarianBlock_Yvel[4] = { -40, 40, 0, 0 };
-    static const int8 kSomarianBlock_Xvel[4] = { 0, 0, -40, 40 };
-    if (flag_is_ancilla_to_pick_up == k + 1)
-      flag_is_ancilla_to_pick_up = 0;
-    Link_CancelDash();
-    Ancilla_Sfx3_Pan(k, 0x32);
-    int j = link_direction_facing >> 1;
-    ancilla_dir[k] = j;
-    ancilla_y_vel[k] = kSomarianBlock_Yvel[j];
-    ancilla_x_vel[k] = kSomarianBlock_Xvel[j];
-    ancilla_z_vel[k] = 48;
-    ancilla_H[k] = 1;
-    ancilla_z[k] = 0;
-  }
-
-  ancilla_z_vel[k] -= 2;
-  Ancilla_MoveY(k);
-  Ancilla_MoveX(k);
-  Ancilla_MoveZ(k);
-  if (ancilla_z[k] && ancilla_z[k] < 252)
-    return;
-
-  Ancilla_Sfx2_Pan(k, 0x21);
-  ancilla_z[k] = 0;
-  int j = ancilla_H[k]++;
-  if (j == 3) {
-    ancilla_arr4[k] = 0;
-    ancilla_H[k] = 0;
-  } else {
-    static const int8 kSomarianBlock_Zvel[4] = { 48, 24, 16, 8 };
-    ancilla_z_vel[k] = kSomarianBlock_Zvel[j - 1];
-    ancilla_y_vel[k] = (int8)ancilla_y_vel[k] / 2;
-    ancilla_x_vel[k] = (int8)ancilla_x_vel[k] / 2;
-  }
-}
-
-void Gravestone_Move(int k) {  // 88ed89
-  if (submodule_index)
-    return;
-  ancilla_y_vel[k] = -8;
-  Ancilla_MoveY(k);
-
-  Gravestone_ActAsBarrier(k);
-  uint16 y_target = ancilla_B[k] << 8 | ancilla_A[k];
-  uint16 y_cur = Ancilla_GetY(k);
-
-  if (y_cur >= y_target)
-    return;
-
-  ancilla_type[k] = 0;
-  link_something_with_hookshot = 0;
-  bitmask_of_dragstate &= ~4;
-  BYTE(scratch_0) = ((uint8 *)door_debris_y)[k];
-  HIBYTE(scratch_0) = ((uint8 *)door_debris_x)[k];
-  big_rock_starting_address = scratch_0;
-
-  door_open_closed_counter = big_rock_starting_address == 0x532 ? 0x48 :
-    big_rock_starting_address == 0x488 ? 0x60 : 0x40;
-  Overworld_DoMapUpdate32x32_B();
-}
-
-void Gravestone_ActAsBarrier(int k) {  // 88ee57
-  uint16 x = Ancilla_GetX(k);
-  uint16 y = Ancilla_GetY(k);
-  uint16 r4 = y + 0x18;
-  uint16 r6 = x + 0x20;
-  uint16 lx = link_x_coord + 8;
-  uint16 ly = link_y_coord + 8;
-  if (ly >= y && ly < r4 &&
-      lx >= x && lx < r6) {
-    uint16 r10 = abs16(ly - r4);
-    link_y_coord += r10;
-    link_y_vel += r10;
-    bitmask_of_dragstate |= 4;
-  }
-  if (link_direction_facing)
-    link_direction_facing &= ~4;
-}
-
-void AncillaAdd_DugUpFlute(uint8 a, uint8 y) {  // 898c73
-  int k = Ancilla_AddAncilla(a, y);
-  if (k < 0)
-    return;
-  ancilla_step[k] = 0;
-  ancilla_z[k] = 0;
-  ancilla_z_vel[k] = 24;
-  ancilla_x_vel[k] = link_direction_facing == 4 ? -8 : 8;
-  DecodeAnimatedSpriteTile_variable(12);
-  Ancilla_SetXY(k, 0x490, 0xa8a);
-}
-
-void AncillaAdd_CaneOfByrnaInitSpark(uint8 a, uint8 y) {  // 898ee0
-  for (int k = 4; k >= 0; k--) {
-    if (ancilla_type[k] == 0x31)
-      ancilla_type[k] = 0;
-  }
-  int k = Ancilla_AddAncilla(a, y);
-  if (k >= 0) {
-    ancilla_item_to_link[k] = 0;
-    ancilla_aux_timer[k] = 9;
-    link_disable_sprite_damage = 1;
-    ancilla_arr3[k] = 2;
-  }
-}
-
-void AncillaAdd_ShovelDirt(uint8 a, uint8 y) {  // 898f5b
-  int k = Ancilla_AddAncilla(a, y);
-  if (k >= 0) {
-    ancilla_item_to_link[k] = 0;
-    ancilla_timer[k] = 20;
-    Ancilla_SetXY(k, link_x_coord, link_y_coord);
-  }
-}
-
-void AncillaAdd_Hookshot(uint8 a, uint8 y) {  // 899b10
-  static const int8 kHookshot_Yvel[4] = { -64, 64, 0, 0 };
-  static const int8 kHookshot_Xvel[4] = { 0, 0, -64, 64 };
-  static const int8 kHookshot_Yd[4] = { 4, 20, 8, 8 };
-  static const int8 kHookshot_Xd[4] = { 0, 0, -4, 11 };
-
-  int k = Ancilla_AddAncilla(a, y);
-  if (k >= 0) {
-    ancilla_aux_timer[k] = 3;
-    ancilla_item_to_link[k] = 0;
-    ancilla_step[k] = 0;
-    ancilla_L[k] = 0;
-    related_to_hookshot = 0;
-    hookshot_effect_index = k;
-    ancilla_K[k] = 0;
-    ancilla_G[k] = 255;
-    ancilla_arr1[k] = 0;
-    ancilla_timer[k] = 0;
-    int j = link_direction_facing >> 1;
-    ancilla_dir[k] = j;
-    ancilla_x_vel[k] = kHookshot_Xvel[j];
-    ancilla_y_vel[k] = kHookshot_Yvel[j];
-    Ancilla_SetXY(k, link_x_coord + kHookshot_Xd[j], link_y_coord + kHookshot_Yd[j]);
-  }
-}
-
-void ResetSomeThingsAfterDeath(uint8 a) {  // 8bffbf
-  link_is_in_deep_water = 0;
-  link_speed_setting = a;
-  link_on_conveyor_belt = 0;
-  byte_7E0322 = 0;
-  flag_is_link_immobilized = 0;
-  palette_swap_flag = 0;
-  player_unk1 = 0;
-  link_give_damage = 0;
-  link_actual_vel_y = 0;
-  link_actual_vel_x = 0;
-  link_actual_vel_z = 0;
-  BYTE(link_z_coord) = 0;
-  draw_water_ripples_or_grass = 0;
-  byte_7E0316 = 0;
-  countdown_for_blink = 0;
-  link_player_handler_state = 0;
-  link_visibility_status = 0;
-  Ancilla_TerminateSelectInteractives(0);
-  Link_ResetProperties_A();
-}
-
-void SpawnHammerWaterSplash() {  // 9aff3c
-  static const int8 kItem_Hammer_SpawnWater_X[4] = { 0, 12, -8, 24 };
-  static const int8 kItem_Hammer_SpawnWater_Y[4] = { 8, 32, 24, 24 };
-  if (submodule_index | flag_is_link_immobilized | flag_unk1)
-    return;
-  int i = link_direction_facing >> 1;
-  uint16 x = link_x_coord + kItem_Hammer_SpawnWater_X[i];
-  uint16 y = link_y_coord + kItem_Hammer_SpawnWater_Y[i];
-  uint8 tiletype;
-  if (player_is_indoors) {
-    int t = (link_is_on_lower_level >= 1) ? 0x1000 : 0;
-    t += (x & 0x1f8) >> 3;
-    t += (y & 0x1f8) << 3;
-    tiletype = dung_bg2_attr_table[t];
-  } else {
-    tiletype = Overworld_ReadTileAttribute(x >> 3, y);
-  }
-
-  if (tiletype == 8 || tiletype == 9) {
-    int j = Sprite_SpawnSmallSplash(0);
-    if (j >= 0) {
-      Sprite_SetX(j, x - 8);
-      Sprite_SetY(j, y - 16);
-      sprite_floor[j] = link_is_on_lower_level;
-      sprite_z[j] = 0;
-    }
-  }
-}
-
-void DiggingGameGuy_AttemptPrizeSpawn() {  // 9dfd5c
-  static const int8 kDiggingGameGuy_Xvel[2] = { -16, 16 };
-  static const int8 kDiggingGameGuy_X[2] = { 0, 19 };
-  static const uint8 kDiggingGameGuy_Items[4] = { 0xdb, 0xda, 0xd9, 0xdf };
-
-  beamos_x_hi[1]++;
-  if (link_y_coord >= 0xb18)
-    return;
-  int j = GetRandomNumber() & 7;
-  uint8 item_to_spawn;
-  switch (j) {
-  case 0: case 1: case 2: case 3:
-    item_to_spawn = kDiggingGameGuy_Items[j];
-    break;
-  case 4:
-    if (beamos_x_hi[1] < 25 || beamos_x_hi[0] || GetRandomNumber() & 3)
-      return;
-    item_to_spawn = beamos_x_hi[0] = 0xeb;
-    break;
-  default:
-    return;
-  }
-  SpriteSpawnInfo info;
-  j = Sprite_SpawnDynamically(4, item_to_spawn, &info); // zelda bug: 4 wtf...
-  if (j >= 0) {
-    int i = link_direction_facing != 4;
-    sprite_x_vel[j] = kDiggingGameGuy_Xvel[i];
-    sprite_y_vel[j] = 0;
-    sprite_z_vel[j] = 24;
-    sprite_stunned[j] = 255;
-    sprite_delay_aux4[j] = 48;
-    Sprite_SetX(j, (link_x_coord + kDiggingGameGuy_X[i]) & ~0xf);
-    Sprite_SetY(j, (link_y_coord + 22) & ~0xf);
-    sprite_floor[j] = 0;
-    SpriteSfx_QueueSfx3WithPan(j, 0x30);
-  }
-}
-
--- a/player.h
+++ /dev/null
@@ -1,242 +1,0 @@
-#pragma once
-#include "types.h"
-
-extern const uint8 kSwimmingTab1[4];
-extern const uint8 kSwimmingTab2[2];
-
-enum {
-  kPlayerState_Ground = 0,
-  kPlayerState_FallingIntoHole = 1,
-  kPlayerState_RecoilWall = 2,
-  kPlayerState_SpinAttacking = 3,
-  kPlayerState_Swimming = 4,
-  kPlayerState_TurtleRock = 5,
-  kPlayerState_RecoilOther = 6,
-  kPlayerState_Electrocution = 7,
-  kPlayerState_Ether = 8,
-  kPlayerState_Bombos = 9,
-  kPlayerState_Quake = 10,
-  kPlayerState_FallOfLeftRightLedge = 12,
-  kPlayerState_JumpOffLedgeDiag = 14,
-  kPlayerState_StartDash = 17,
-  kPlayerState_StopDash = 18,
-  kPlayerState_Hookshot = 19,
-  kPlayerState_Mirror = 20,
-  kPlayerState_HoldUpItem = 21,
-  kPlayerState_AsleepInBed = 22,
-  kPlayerState_PermaBunny = 23,
-  kPlayerState_ReceivingEther = 25,
-  kPlayerState_ReceivingBombos = 26,
-  kPlayerState_OpeningDesertPalace = 27,
-  kPlayerState_TempBunny = 28,
-  kPlayerState_PullForRupees = 29,
-  kPlayerState_SpinAttackMotion = 30,
-};
-
-
-
-
-
-
-void Dungeon_HandleLayerChange();
-void CacheCameraProperties();
-void CheckAbilityToSwim();
-void Link_Main();
-void Link_ControlHandler();
-void LinkState_Default();
-void HandleLink_From1D();
-void PlayerHandler_00_Ground_3();
-bool Link_HandleBunnyTransformation();
-void LinkState_TemporaryBunny();
-void PlayerHandler_17_Bunny();
-void LinkState_Bunny_recache();
-void Link_TempBunny_Func2();
-void LinkState_HoldingBigRock();
-void EtherTablet_StartCutscene();
-void LinkState_ReceivingEther();
-void BombosTablet_StartCutscene();
-void LinkState_ReceivingBombos();
-void LinkState_ReadingDesertTablet();
-void HandleSomariaAndGraves();
-void LinkState_Recoil();
-void Link_HandleRecoilAndTimer(bool jump_into_middle);
-void LinkState_OnIce();
-void Link_HandleChangeInZVelocity();
-void Player_ChangeZ(uint8 zd);
-void LinkHop_HoppingSouthOW();
-void LinkState_HandlingJump();
-void LinkHop_FindTileToLandOnSouth();
-void LinkState_HoppingHorizontallyOW();
-void Link_HoppingHorizontally_FindTile_Y();
-void Link_SetToDeepWater();
-void LinkState_0F();
-uint8 Link_HoppingHorizontally_FindTile_X(uint8 o);
-void LinkState_HoppingDiagonallyUpOW();
-void LinkState_HoppingDiagonallyDownOW();
-void LinkHop_FindLandingSpotDiagonallyDown();
-void Link_SplashUponLanding();
-void LinkState_Dashing();
-void LinkState_ExitingDash();
-void Link_CancelDash();
-void RepelDash();
-void LinkApplyTileRebound();
-void Sprite_RepelDash();
-void Flag67WithDirections();
-void LinkState_Pits();
-void HandleLayerOfDestination();
-void DungeonPitDoDamage();
-void HandleDungeonLandingFromPit();
-void PlayerHandler_04_Swimming();
-void Link_HandleSwimMovements();
-void Link_FlagMaxAccels();
-void Link_SetIceMaxAccel();
-void Link_SetMomentum();
-void Link_ResetSwimmingState();
-void Link_ResetStateAfterDamagingPit();
-void ResetAllAcceleration();
-void Link_HandleSwimAccels();
-void Link_SetTheMaxAccel();
-void LinkState_Zapped();
-void PlayerHandler_15_HoldItem();
-void Link_ReceiveItem(uint8 item, int chest_position);
-void Link_TuckIntoBed();
-void LinkState_Sleeping();
-void Link_HandleSwordCooldown();
-void Link_HandleYItem();
-void Link_HandleAPress();
-void Link_APress_PerformBasic(uint8 action_x2);
-void HandleSwordSfxAndBeam();
-void Link_CheckForSwordSwing();
-void HandleSwordControls();
-void Link_ResetSwordAndItemUsage();
-void Player_Sword_SpinAttackJerks_HoldDown();
-void LinkItem_Rod();
-void LinkItem_Hammer();
-void LinkItem_Bow();
-void LinkItem_Boomerang();
-void Link_ResetBoomerangYStuff();
-void LinkItem_Bombs();
-void LinkItem_Bottle();
-void LinkItem_Lamp();
-void LinkItem_Powder();
-void LinkItem_ShovelAndFlute();
-void LinkItem_Shovel();
-void LinkItem_Flute();
-void LinkItem_Book();
-void LinkItem_Ether();
-void LinkState_UsingEther();
-void LinkItem_Bombos();
-void LinkState_UsingBombos();
-void LinkItem_Quake();
-void LinkState_UsingQuake();
-void Link_ActivateSpinAttack();
-void Link_AnimateVictorySpin();
-void LinkState_SpinAttack();
-void LinkItem_Mirror();
-void DoSwordInteractionWithTiles_Mirror();
-void LinkState_CrossingWorlds();
-void Link_PerformDesertPrayer();
-void HandleFollowersAfterMirroring();
-void LinkItem_Hookshot();
-void LinkState_Hookshotting();
-void LinkItem_Cape();
-void Link_ForceUnequipCape();
-void Link_ForceUnequipCape_quietly();
-void HaltLinkWhenUsingItems();
-void Link_HandleCape_passive_LiftCheck();
-void Player_CheckHandleCapeStuff();
-void LinkItem_CaneOfSomaria();
-void LinkItem_CaneOfByrna();
-bool SearchForByrnaSpark();
-void LinkItem_Net();
-bool CheckYButtonPress();
-bool LinkCheckMagicCost(uint8 x);
-void Refund_Magic(uint8 x);
-void Link_ItemReset_FromOverworldThings();
-void Link_PerformThrow();
-void Link_APress_LiftCarryThrow();
-void Link_PerformDash();
-void Link_PerformGrab();
-void Link_APress_PullObject();
-void Link_PerformStatueDrag();
-void Link_APress_StatueDrag();
-void Link_PerformRupeePull();
-void LinkState_TreePull();
-void Link_PerformRead();
-void Link_PerformOpenChest();
-bool Link_CheckNewAPress();
-bool Link_HandleToss();
-void Link_HandleDiagonalCollision();
-void Player_LimitDirections_Inner();
-void Link_HandleCardinalCollision();
-void RunSlopeCollisionChecks_VerticalFirst();
-void RunSlopeCollisionChecks_HorizontalFirst();
-bool CheckIfRoomNeedsDoubleLayerCheck();
-void CreateVelocityFromMovingBackground();
-void StartMovementCollisionChecks_Y();
-void StartMovementCollisionChecks_Y_HandleIndoors();
-void HandlePushingBonkingSnaps_Y();
-void StartMovementCollisionChecks_Y_HandleOutdoors();
-bool RunLedgeHopTimer(); // carry
-void Link_BonkAndSmash();
-void Link_AddInVelocityYFalling();
-void CalculateSnapScratch_Y();
-void ChangeAxisOfPerpendicularDoorMovement_Y();
-void Link_AddInVelocityY();
-void Link_HopInOrOutOfWater_Y();
-void Link_FindValidLandingTile_North();
-void Link_FindValidLandingTile_DiagonalNorth();
-void StartMovementCollisionChecks_X();
-void StartMovementCollisionChecks_X_HandleIndoors();
-void HandlePushingBonkingSnaps_X();
-void StartMovementCollisionChecks_X_HandleOutdoors();
-void SnapOnX();
-void CalculateSnapScratch_X();
-int8 ChangeAxisOfPerpendicularDoorMovement_X();
-void Link_HopInOrOutOfWater_X();
-void Link_HandleDiagonalKickback();
-void TileDetect_MainHandler(uint8 item);
-bool Link_PermissionForSloshSounds();
-bool PushBlock_AttemptToPushTheBlock(uint8 what, uint16 x, uint16 y);
-uint8 Link_HandleLiftables();
-void HandleNudging(int8 arg_r0);
-void TileBehavior_HandleItemAndExecute(uint16 x, uint16 y);
-uint8 PushBlock_GetTargetTileFlag(uint16 x, uint16 y);
-void FlagMovingIntoSlopes_Y();
-void FlagMovingIntoSlopes_X();
-void Link_HandleRecoiling();
-void Player_HandleIncapacitated_Inner2();
-void Link_HandleVelocity();
-void Link_MovePosition();
-void Link_HandleVelocityAndSandDrag(uint16 x, uint16 y);
-void HandleSwimStrokeAndSubpixels();
-void Player_SomethingWithVelocity_TiredOrSwim(uint16 xvel, uint16 yvel);
-void Link_HandleMovingFloor();
-void Link_ApplyMovingFloorVelocity();
-void Link_ApplyConveyor();
-void Link_HandleMovingAnimation_FullLongEntry();
-void Link_HandleMovingAnimation_StartWithDash();
-void Link_HandleMovingAnimationSwimming();
-void Link_HandleMovingAnimation_Dash();
-void HandleIndoorCameraAndDoors();
-void HandleDoorTransitions();
-void ApplyLinksMovementToCamera();
-uint8 FindFreeMovingBlockSlot(uint8 x);
-bool InitializePushBlock(uint8 r14, uint8 idx);
-void Sprite_Dungeon_DrawSinglePushBlock(int j);
-void Link_Initialize();
-void Link_ResetProperties_A();
-void Link_ResetProperties_B();
-void Link_ResetProperties_C();
-bool Link_CheckForEdgeScreenTransition();
-void CacheCameraPropertiesIfOutdoors();
-void SomariaBlock_HandlePlayerInteraction(int k);
-void Gravestone_Move(int k);
-void Gravestone_ActAsBarrier(int k);
-void AncillaAdd_DugUpFlute(uint8 a, uint8 y);
-void AncillaAdd_CaneOfByrnaInitSpark(uint8 a, uint8 y);
-void AncillaAdd_ShovelDirt(uint8 a, uint8 y);
-void AncillaAdd_Hookshot(uint8 a, uint8 y);
-void ResetSomeThingsAfterDeath(uint8 a);
-void SpawnHammerWaterSplash();
-void DiggingGameGuy_AttemptPrizeSpawn();
--- a/player_oam.c
+++ /dev/null
@@ -1,1289 +1,0 @@
-#include "player_oam.h"
-#include "zelda_rtl.h"
-#include "variables.h"
-#include "snes/snes_regs.h"
-#include "player.h"
-#include "misc.h"
-
-static const int8 kPlayerOam_StairsOffsY[] = {
-  0, -2, -3, 0, -2, -3, 0, 0, 0, 0, 0, 0, 0, -2, -3, 0,
-  -2, -3, 0, 0, 0, 0, 0, 0,
-};
-static const uint16 kPlayerOam_FloorOamPrio[] = {0x2000, 0x1000, 0x3000, 0x2000};
-static const uint16 kPlayerOam_SortSpritesOffs[] = {0x190, 0xe0};
-static const int8 kPlayerOam_Tab1[9] = {0, 1, 2, 0, 1, 2, 0, 1, 2};
-static const int8 kPlayerOam_Tab2[8] = {6, 6, 6, 6, 7, 7, 8, 9};
-static const int8 kPlayerOam_Tab3[6] = {12, 11, 32, 34, 35, 37};
-static const int8 kPlayerOam_Tab4[8] = {38, 11, 11, 12, 11, 11, 11, 13};
-static const uint8 kPlayerOam_Tab5[7] = {4, 16, 18, 21, 23, 24, 39};
-static const uint16 kSwordTipSomething[] = { 0xFFFF, 0xFFFF, 0x6A3E, 0x6A2F, 0x6A2F, 0x2A05, 0x2A2F, 0x2A3E, 0xFFFF, 0xFFFF, 0xFFFF, 0xAA3E, 0xAA2F, 0xAA2F, 0xAA05, 0xEA2F, 0xEA3E, 0xFFFF, 0xFFFF, 0xFFFF, 0x2A3E, 0x2A3F, 0x2A3F, 0x2A05, 0xAA3F, 0xAA3E, 0xFFFF, 0xFFFF, 0xFFFF, 0x6A3E, 0x6A3F, 0x6A3F, 0x6A05, 0xEA3F, 0xEA3E, 0xFFFF };
-static const int8 kSwordOamYOffs_Good[] = {-1, -1, -5, -13, -15, -21, -13, -5, -1, -1, -1, 22, 27, 29, 35, 27, 24, -1, -1, -1, -1, 2, 5, 12, 20, 26, -1, -1, -1, -1, 2, 5, 12, 20, 26, -1};
-static const int8 kSwordOamXOffs_Good[] = {-1, -1, 15, 13, 8, -1, -10, -14, -1, -1, -1, -6, -3, 1, 8, 16, 21, -1, -1, -1, -11, -15, -18, -24, -17, -12, -1, -1, -1, 19, 23, 26, 32, 25, 20, -1};
-static const uint16 kPlayerOamOtherOffs[] = { 0, 36, 72, 96, 108, 118, 122, 134, 36, 146, 154, 178, 185, 188, 212, 236, 252, 264, 272, 288, 300, 316, 339, 363, 374, 390, 396, 402, 408, 420, 421, 422, 424, 428, 444, 456, 468, 469, 470, 475, 9, 45, 78, 99, 108, 119, 125, 137, 45, 148, 160, 178, 185, 194, 218, 236, 255, 266, 276, 291, 304, 316, 345, 363, 378, 393, 399, 402, 411, 420, 421, 422, 425, 432, 447, 456, 468, 469, 470, 484, 18, 54, 84, 102, 108, 120, 128, 140, 54, 150, 166, 178, 182, 200, 224, 236, 258, 268, 280, 294, 308, 316, 351, 363, 382, 390, 396, 402, 414, 420, 421, 422, 426, 436, 450, 456, 468, 469, 470, 493, 27, 63, 90, 105, 108, 121, 131, 143, 63, 152, 172, 178, 185, 206, 230, 236, 261, 270, 284, 297, 312, 316, 357, 363, 386, 393, 399, 402, 417, 420, 421, 422, 427, 440, 453, 456, 468, 469, 470, 502 };
-static const int8 kSwordOamYOffs[511] = {
-  -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128,
-  -128, -128, -128, -128, 9, 5, -2, -6, -8, -5, -3, 7, 9, 11, 15, 21, 25, 27, 25, 23, 13, 11, -2, 2, 3, 12, 12, 15, 22, 27, 27, -2,
-  2, 3, 12, 12, 15, 22, 27, 27, -5, -4, -3, -5, -4, -3, 24, 25, 26, 24, 25, 26, 13, 14, 15, 13, 14, 15, 13, 14, 15, 13, 14, 15,
-  -3, -7, 2, 20, 26, 24, 10, 13, 15, 10, 13, 15, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -7, -1, -2, -3, 10, 26,
-  -2, 3, 14, -2, 3, 14, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128,
-  -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128,
-  -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128,
-  -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -4, -8, 6, 15, 26, 26, 14, 6, -7, -7, 22, 26, 16, 8, 5, 12, -128, -128, -128, -128,
-  -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128,
-  -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, 24, 16, -5, 16,
-  13, -4, -5, -5, -1, -5, -5, -5, -5, 11, 15, 21, 25, 27, 13, -3, -7, 26, 18, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128,
-  -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128,
-  -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128,
-  -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128,
-  -128, -128, -128, -128, -128, -128, -128, -128, -4, -5, 4, 14, 20, 15, 8, -3, -8, 14, -3, 15, -128, -128, -128, -128, -128, -128, -128, 9, 5, -3, -9, -11,
-  -15, -9, -4, 8, 11, 14, 20, 25, 27, 31, 25, 23, 13, -2, -1, 0, 8, 9, 12, 16, 24, 30, -2, -1, 0, 8, 9, 12, 16, 24, 30,
-};
-static const int8 kSwordOamXOffs[511] = {
-  -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128,
-  -128, -128, -128, -128, 19, 18, 14, 10, 0, -4, -10, -13, -15, -8, -6, -5, 5, 8, 12, 18, 22, 23, 3, -2, -7, -11, -14, -11, -9, 1, 3, 5,
-  10, 15, 19, 22, 19, 17, 7, 5, 0, 0, 0, 0, 0, 0, 7, 7, 7, 7, 7, 7, -10, -10, -10, -10, -10, -10, 18, 18, 18, 18, 18, 18,
-  -3, 2, -3, 10, 7, 10, -16, -24, -20, 16, 24, 20, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -2, -2, -2, 10, 10, 10,
-  1, -10, -11, 7, 18, 19, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128,
-  -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128,
-  -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128,
-  -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, 13, 6, 22, 22, 8, -1, -14, -14, -1, 9, -5, 3, 18, 21, -11, -12, -128, -128, -128, -128,
-  -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128,
-  -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, 7, -9, 0, 17,
-  22, 14, 10, 10, 14, 11, 8, 8, 8, 23, 22, 20, 12, 8, 23, 14, 10, 12, 12, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128,
-  -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128,
-  -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128,
-  -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128,
-  -128, -128, -128, -128, -128, -128, -128, -128, 13, 13, 16, 11, 2, -11, -16, -9, 0, 11, -9, -11, -128, -128, -128, -128, -128, -128, -128, 19, 17, 15, 14, 3,
-  -1, -5, -11, -14, -8, -7, -6, 3, 5, 8, 12, 18, 22, 3, -2, -8, -13, -16, -20, -15, -12, 1, 5, 10, 16, 21, 24, 28, 23, 20, 7,
-};
-static const int8 kPlayerOam_Main_SwordStuff_array1[511] = {
-  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-  -1, -1, -1, -1, 1, 5, 14, 26, 6, 8, 16, 20, 0, 0, 2, 13,
-  25, 7, 11, 19, 23, 1, 6, 8, 16, 20, 0, 2, 13, 25, 7, 6,
-  10, 18, 22, 1, 4, 15, 27, 7, 10, 10, 10, 10, 10, 10, 9, 9,
-  9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1,
-  6, 10, 6, 7, 9, 7, 0, 0, 0, 1, 1, 1, -1, -1, -1, -1,
-  -1, -1, -1, -1, -1, -1, 8, 10, 10, 8, 32, 29, 33, 29, 34, 30,
-  31, 37, 38, 31, 35, 36, 42, 39, 39, 41, 40, 40, 44, 42, 42, 45,
-  41, 41, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-  -1, -1, -1, -1, -1, -1, 49, 49, 50, 47, 47, 48, -1, -1, -1, -1,
-  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 10, 8, 5, 4,
-  11, 9, 2, 3, 8, 10, 9, 11, 4, 5, 3, 2, -1, -1, -1, -1,
-  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 3, 3,
-  -1, 1, 5, 5, -1, 0, 3, 3, -1, 1, 5, 5, 9, 2, 6, 4,
-  4, 10, 6, 6, 10, 6, 8, 8, 8, 1, 4, 15, 11, 7, 4, 10,
-  6, 7, 28, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-  -1, -1, -1, -1, -1, -1, -1, -1, 51, 52, 53, 54, -1, -1, -1, -1,
-  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 68, 68, 70, 68,
-  68, 67, 71, 68, 74, 73, 69, 72, 55, 55, 56, 57, 58, 59, 60, 61,
-  62, 63, 64, 65, 6, 75, -1, -1, -1, -1, -1, 1, 5, 14, 26, 10,
-  6, 8, 16, 20, 0, 2, 13, 25, 9, 7, 11, 19, 23, 6, 8, 16,
-  20, 3, 0, 2, 13, 25, 6, 10, 18, 22, 5, 1, 4, 15, 27,
-};
-static const uint8 kPlayerOam_Main_SwordStuff_array2[76] = {
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2,
-  2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0,
-  0, 0, 0, 2, 0, 2, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2,
-  0, 2, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-  2, 2, 2, 0, 0, 0, 0, 2, 0, 2, 0, 2,
-};
-static const uint8 kPlayerOam_Main_SwordStuff_array3[76] = {
-  6, 6, 4, 4, 4, 4, 0, 0, 8, 8, 8, 8, 2, 2, 2, 2,
-  10, 10, 10, 10, 12, 12, 12, 12, 14, 14, 14, 14, 0, 9, 12, 9,
-  12, 14, 10, 8, 13, 8, 13, 18, 18, 17, 17, 16, 16, 16, 16, 64,
-  65, 64, 65, 24, 24, 25, 25, 36, 33, 37, 35, 34, 32, 38, 35, 37,
-  38, 34, 40, 42, 41, 41, 44, 40, 43, 40, 43, 48,
-};
-static const uint8 kPlayerOam_Main_SwordStuff_array4[10] = {1, 4, 1, 4, 6, 2, 0, 5, 0, 5};
-static const int8 kPlayerOam_ShieldStuff_array1[511] = {
-  1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0,
-  0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2,
-  2, 2, 2, 2, 0, 0, 0, 0, 2, 2, 2, 2, 2, 1, 1, 1,
-  1, 3, 3, 3, 3, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-  1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3,
-  3, 3, 3, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-  2, 2, 2, 3, 3, 3, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1,
-  -1, -1, -1, -1, -1, -1, 1, 0, 1, 1, 2, 2, 2, 3, 3, 3,
-  1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-  -1, -1, 1, 2, 0, 3, 3, 1, 2, 1, 1, 1, 1, 1, 1, 1,
-  0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2,
-  2, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 3, 1, 2,
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 0, 0,
-  3, 0, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-  -1, -1, -1, -1, 3, -1, -1, -1, 2, 3, -1, -1, -1, -1, -1, -1,
-  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 2, 2, 2, 2, 2,
-  2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, -1, -1, -1,
-  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-};
-static const uint8 kPlayerOam_ShieldStuff_array2[18] = {
-  0, 2, 4, 4, 4, 4, 4, 4, 9, 12, 9, 12, 14, 10, 8, 13,
-  8, 13,
-};
-static const uint8 kPlayerOam_ShieldStuff_array3[10] = {1, 4, 1, 4, 6, 2, 0, 5, 0, 5};
-static const uint8 kPlayerOamSpriteLocs[511] = {
-  2, 2, 2, 2, 2, 2, 2, 2, 2, 10, 10, 10, 10, 10, 10, 10, 10, 10, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-  2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 1, 0, 0, 0, 0, 11, 11, 11, 11, 11, 2, 2, 2, 2, 2, 2, 0, 0, 0, 2,
-  2, 2, 2, 2, 2, 0, 0, 0, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-  3, 3, 3, 6, 6, 6, 5, 5, 5, 5, 5, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 0, 0, 0, 3, 3, 6, 6, 6,
-  0, 0, 0, 0, 0, 0, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 2, 0, 2, 0, 2, 2, 2, 2, 2, 2,
-  10, 10, 10, 10, 10, 10, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 1, 1, 2, 1, 1, 2, 4, 4, 4, 4,
-  4, 4, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3,
-  2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 5, 5, 5, 5, 5, 2, 2, 5, 5, 5, 5, 2, 5, 0, 0, 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 7, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9,
-  0, 0, 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 1,
-  1, 1, 1, 1, 1, 3, 3, 10, 10, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-  2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-  2, 2, 2, 2, 1, 1, 2, 2, 3, 6, 5, 5, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 2, 2,
-  0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 2, 2, 0, 2, 0, 5, 2, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3,
-  3, 3, 3, 3, 0, 11, 11, 11, 11, 11, 11, 11, 11, 2, 2, 2, 2, 2, 0, 0, 0, 0, 2, 2, 2, 2, 2, 0, 0, 0, 0,
-};
-static const uint16 kPlayerOam_Tab6[28] = {0, 10, 22, 38, 61, 72, 88, 0, 13, 26, 38, 61, 76, 97, 0, 16, 30, 38, 61, 80, 106, 0, 19, 34, 38, 61, 84, 115};
-static const int8 kPlayerOam_Spr1Bank[124] = {
-  0, -1, -1, 2, 3, 4, -1, -1, -1, -1, -1, 21, 23, -1, 21, 23, -1, 22, 24, -1, 21, 23, 19, 11, 15, -1, 17, 9, 13, -1, 9, 18,
-  13, -1, 10, 17, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 4, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 23, 23,
-  -1, -1, -1, -1, -1, -1, -1, -1, -1, 23, 23, -1, -1, 21, 21, -1, -1, 24, 24, -1, -1, 23, 23, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 26, 26, 26, -1, -1, -1, -1, -1, -1, 25, 25, 25, -1, -1,
-};
-static const int8 kPlayerOam_Spr2Bank[124] = {
-  1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 22, 24, -1, 22, 24, -1, -1, -1, -1, -1, -1, 20, 12, 16, -1, 18, 10, 14, -1, -1, -1,
-  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 24, 24,
-  -1, -1, -1, -1, -1, -1, -1, -1, -1, 24, 24, -1, -1, 22, 22, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-};
-static const uint8 kPlayerOam_Tab19B[12] = {20, 28, 8, 16, 16, 20, 28, 16, 8, 8, 8, 20};
-static const uint8 kPlayerOam_Tab19A[12] = {0, 8, 0, 8, 8, 12, 20, 8, 8, 0, 0, 0};
-static const int8 kPlayerOam_Spr1X[124] = {
-  8, -1, -1, 4, 4, 4, -1, -1, -1, -1, -1, -7, -9, -1, -8, -10, -1, 13, 16, -1, -5, -8, -2, -6, -5, -1, -1, -5, -6, -1, -3, 4,
-  9, -1, 11, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 4, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -5, -8,
-  -1, -1, -1, -1, -1, -1, -1, -1, -1, -5, -8, -1, -1, -5, -8, -1, -1, 15, 17, -1, -1, -7, -9, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -3, -7, -3, -1, -1, -1, -1, -1, -1, 11, 15, 11, -1, -1,
-};
-static const int8 kPlayerOam_Spr1Y[124] = {
-  0, -1, -1, 8, 8, 8, -1, -1, -1, -1, -1, 7, 10, -1, 5, 8, -1, 8, 12, -1, 8, 12, 2, 7, 13, -1, 20, 14, 7, -1, 20, 21,
-  20, -1, 20, 21, 20, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -8, -8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 5, 11,
-  -1, -1, -1, -1, -1, -1, -1, -1, -1, 5, 11, -1, -1, 6, 1, -1, -1, 13, 15, -1, -1, 13, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 12, 12, 12, -1, -1, -1, -1, -1, -1, 12, 12, 12, -1, -1,
-};
-static const int8 kPlayerOam_Spr2X[124] = {
-  -8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 15, 17, -1, 16, 18, -1, -1, -1, -1, -1, -1, 10, 14, 13, -1, 9, 14, 14, -1, -1, -1,
-  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 13, 16,
-  -1, -1, -1, -1, -1, -1, -1, -1, -1, 13, 16, -1, -1, 13, 16, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-};
-static const int8 kPlayerOam_Spr2Y[124] = {
-  16, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 7, 10, -1, 5, 8, -1, -1, -1, -1, -1, -1, 2, 7, 13, -1, 20, 14, 7, -1, -1, -1,
-  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 5, 11,
-  -1, -1, -1, -1, -1, -1, -1, -1, -1, 5, 11, -1, -1, 6, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-};
-static const uint8 kPlayerOam_Tab20A[12] = {4, 12, 4, 12, 12, 16, 24, 12, 12, 12, 4, 4};
-static const uint8 kPlayerOam_Tab20B[12] = {24, 32, 12, 20, 20, 24, 32, 20, 12, 20, 12, 24};
-static const uint8 kPlayerOam_Prio[15] = {0x0, 0x0, 0x0, 0x0, 0x40, 0x40, 0x48, 0xc0, 0x48, 0xc0, 0x48, 0xc0, 0x48, 0xc0, 0x40};
-static const int8 kDrawSword_y[511] = {
-  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-  -1, -1, -1, -1, 9, 5, -2, -6, -8, -5, -3, -1, 9, 11, 15, 13, 17, 19, 17, 15, 13, 11, -2, 2, 3, 4, 12, 15, 14, 19, 19, -2,
-  2, 3, 4, 12, 15, 14, 19, 19, -5, -4, -3, -5, -4, -3, 16, 17, 18, 16, 17, 18, 13, 14, 15, 13, 14, 15, 13, 14, 15, 13, 14, 15,
-  -3, -7, 2, 12, 18, 16, 15, 13, 10, 15, 13, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 2, 3, 6, 6, -8, -3, -3, -3, 10, 18,
-  -2, 2, 14, -2, 2, 14, 5, 9, 9, 9, 13, 13, 10, 7, 7, 10, 7, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 10, 11, -4, 10, 11, -4, -1, -1, -1, -1,
-  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -4, -8, 6, 15, 18, 18, 14, 6, -7, -7, 14, 17, 16, 8, 5, 12, -1, -1, -1, -1,
-  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 8, 6, 10, -1, 8, 6, 10, -1, 8, 6, 10, -1, 8, 6, 10, 16, 16, -5, 16,
-  13, -4, -5, -5, -1, -5, -5, -5, -5, 11, 15, 13, 17, 19, 13, -3, -7, 18, 18, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-  -1, -1, -1, -1, -1, -1, -1, -1, 2, 17, 12, 12, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 5, -2, -9, -7,
-  -2, 16, 2, -2, 12, 2, -2, 12, -4, -5, 4, 14, 20, 15, 8, -3, -8, 14, -3, 15, -5, 0, -1, -1, -1, -1, -1, 9, 5, -3, -9, -11,
-  -15, -9, -4, 0, 11, 14, 12, 17, 19, 23, 17, 15, 13, -2, -1, 0, 0, 9, 12, 16, 16, 19, -2, -1, 0, 0, 9, 12, 16, 16, 19,
-};
-static const int8 kDrawSword_x[511] = {
-  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-  -1, -1, -1, -1, 11, 10, 6, 2, 0, -4, -10, -13, -15, -8, -6, -5, -3, 8, 12, 10, 14, 15, 3, -2, -7, -11, -14, -11, -9, -7, 3, 5,
-  10, 7, 11, 14, 11, 9, 7, 5, 0, 0, 0, 0, 0, 0, 7, 7, 7, 7, 7, 7, -10, -10, -10, -10, -10, -10, 10, 10, 10, 10, 10, 10,
-  -3, 2, -3, 10, 7, 10, -12, -16, -8, 12, 16, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -4, 12, 8, 0, -2, -2, -2, 10, 10, 9,
-  1, -10, -11, 7, 10, 11, -2, -5, -5, 9, 2, 2, -2, -3, -3, 2, 11, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -3, -7, 8, 3, 7, 0, -1, -1, -1, -1,
-  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 13, 6, 14, 14, 8, -1, -14, -14, -1, 9, -5, 3, 10, 13, -11, -12, -1, -1, -1, -1,
-  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -14, -13, -12, -1, 14, 13, 12, -1, -14, -13, -12, -1, 14, 13, 12, 7, -9, 0, 9,
-  14, 14, 10, 10, 14, 11, 8, 8, 8, 15, 14, 12, 12, 8, 15, 14, 10, 4, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-  -1, -1, -1, -1, -1, -1, -1, -1, 4, 4, -7, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -3, -3, 9,
-  12, 8, 10, 3, -13, -10, 5, 13, 13, 13, 16, 11, 2, -11, -16, -9, 0, 8, -9, -11, 12, -7, -1, -1, -1, -1, -1, 11, 9, 7, 6, 3,
-  -1, -5, -11, -14, -8, -7, -6, -5, 5, 8, 12, 10, 14, 3, -2, -8, -13, -16, -20, -15, -12, -7, 5, 10, 8, 13, 16, 20, 15, 12, 7,
-};
-static const int8 kPlayerOam_Rod[3] = {0x2, 0x4, 0x4};
-static const uint16 kSwordTiledata[228] = {
-  0x2a05, 0x2a06, 0xffff,
-  0x6a06, 0x6a05, 0xffff,
-  0xaa05, 0xaa06, 0xffff,
-  0x2a05, 0x2a06, 0xffff,
-  0xea06, 0xea05, 0xffff,
-  0x6a06, 0x6a05, 0xffff,
-  0x2a05, 0xffff, 0x2a15,
-  0xaa15, 0xffff, 0xaa05,
-  0x2a05, 0xffff, 0x2a15,
-  0xaa15, 0xffff, 0xaa05,
-  0x6a05, 0xffff, 0x6a15,
-  0xea15, 0xffff, 0xea05,
-  0x2a05, 0xffff, 0xffff,
-  0xaa05, 0xffff, 0xffff,
-  0x6a05, 0xffff, 0xffff,
-  0xea05, 0xffff, 0xffff,
-  0x2a05, 0xffff, 0xffff,
-  0xaa05, 0xffff, 0xffff,
-  0x6a05, 0xffff, 0xffff,
-  0xea05, 0xffff, 0xffff,
-  0x2a05, 0xffff, 0xffff,
-  0xaa05, 0xffff, 0xffff,
-  0x6a05, 0xffff, 0xffff,
-  0xea05, 0xffff, 0xffff,
-  0x2a05, 0xffff, 0xffff,
-  0xaa05, 0xffff, 0xffff,
-  0x6a05, 0xffff, 0xffff,
-  0xea05, 0xffff, 0xffff,
-  0xaa15, 0xffff, 0xffff,
-  0x2209, 0xffff, 0x2219,
-  0x2209, 0xffff, 0x2219,
-  0x221a, 0xffff, 0x2219,
-  0xa219, 0xffff, 0xa209,
-  0x2209, 0xffff, 0x2219,
-  0x2209, 0xffff, 0xffff,
-  0x2209, 0xffff, 0xffff,
-  0x2219, 0x2209, 0xffff,
-  0x6209, 0xffff, 0xffff,
-  0x6209, 0x6219, 0xffff,
-  0xa209, 0xe209, 0xffff,
-  0x2209, 0x6209, 0xffff,
-  0x6209, 0xffff, 0xe209,
-  0x2209, 0xffff, 0xa209,
-  0xa209, 0xffff, 0xffff,
-  0x6209, 0xffff, 0xffff,
-  0x2209, 0xffff, 0xffff,
-  0xe209, 0xffff, 0xffff,
-  0x2209, 0xffff, 0xffff,
-  0x2209, 0xffff, 0xffff,
-  0x6209, 0xffff, 0xffff,
-  0x6209, 0xffff, 0xffff,
-  0x221a, 0xffff, 0xffff,
-  0x221a, 0xffff, 0xffff,
-  0x221a, 0xffff, 0xffff,
-  0x221a, 0xffff, 0xffff,
-  0x2209, 0xffff, 0xffff,
-  0x2209, 0xffff, 0xffff,
-  0x2209, 0xffff, 0xffff,
-  0xe209, 0xffff, 0xffff,
-  0x2209, 0xffff, 0xffff,
-  0x2209, 0xffff, 0xffff,
-  0x2209, 0xffff, 0xffff,
-  0x2209, 0xffff, 0xffff,
-  0x2209, 0xffff, 0xffff,
-  0x2209, 0xffff, 0xffff,
-  0x2209, 0xffff, 0xffff,
-  0x2209, 0xffff, 0x2219,
-  0x2209, 0xffff, 0x2219,
-  0x2209, 0xffff, 0x2219,
-  0x6209, 0xffff, 0x6219,
-  0x2209, 0xffff, 0x2219,
-  0x2209, 0xffff, 0xffff,
-  0xa219, 0xa209, 0xffff,
-  0x6209, 0xffff, 0xffff,
-  0xe209, 0xe219, 0xffff,
-  0x2809, 0xffff, 0xffff,
-};
-static const int8 kShieldStuff_x[511] = {
-  5, 5, 5, 5, 5, 5, 5, 5, 5, -4, -4, -4, -4, -4, -4, -4, -4, -4, -8, -8, -8, -8, -8, -8, -8, -8, -8, 8, 8, 8, 8, 8,
-  8, 8, 8, 8, 6, 6, 8, 8, 10, 10, 10, 10, 10, -5, -5, -7, -7, -10, -10, -10, -10, -10, 1, 1, 1, 1, 0, 0, 0, 0, 0, -1,
-  -1, -1, -1, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, -9, -9, -9, -9, -9, -9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-  10, 10, 10, -10, -10, -10, 0, -1, 0, 0, 1, 0, -4, -1, -1, -1, -1, -1, -1, -1, -1, -1, 8, -4, 2, -3, 9, 9, 9, -10, -10, -10,
-  0, 0, 0, 0, 0, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 5, 9, -4, -10, 0, 0, 8, 0, 5, 5, 5, 5, 5, 5,
-  -4, -4, -4, -4, -4, -4, -8, -8, -8, -8, -8, -8, 8, 8, 8, 8, 8, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -4, -8, 5, 8,
-  -4, -4, -4, -4, -5, -5, -5, -5, -5, -10, -10, -10, -10, -10, -5, -5, -7, -4, -4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 9, 9, 9, -10, -10, -10, -1, -1,
-  -1, -1, -1, -1, -6, -1, -1, -1, 10, -10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 10, 10, 10, 10, 10,
-  10, 10, 10, 10, -9, -9, -9, -9, -10, -10, -10, -10, -10, 1, 1, 1, 2, 2, 2, 1, 2, 2, -1, -1, -1, -2, -2, -2, -1, -2, -2,
-};
-static const int8 kShieldStuff_y[511] = {
-  5, 5, 4, 3, 5, 5, 4, 3, 5, 9, 10, 9, 7, 8, 10, 9, 7, 8, 5, 5, 4, 3, 4, 5, 4, 3, 4, 5, 5, 4, 3, 4,
-  5, 4, 3, 4, 12, 12, 8, 8, 6, 6, 6, 6, 6, 1, 1, 3, 3, 7, 7, 7, 7, 7, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
-  5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 7, 5, 6, 7, 6, 7, 8, 6, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-  7, 5, 7, 7, 8, 7, 5, 5, 5, 5, 5, 5, 16, -1, -1, -1, -1, -1, -1, -1, -1, -1, 5, 8, 7, 7, 6, 5, 5, 7, 7, 7,
-  5, 5, 5, 5, 5, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 6, 6, 11, 7, 4, 8, 4, 8, 4, 5, 6, 4, 5, 6,
-  10, 11, 12, 10, 11, 12, 5, 6, 7, 5, 6, 7, 5, 6, 7, 5, 6, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 10, 5, 4, 5,
-  10, 10, 10, 10, 10, 10, 10, 10, 10, 7, 7, 7, 7, 7, 10, 10, 1, 10, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 5, 5, 5, 7, 7, 7, -1, -1,
-  -1, -1, -1, -1, 9, -1, -1, -1, 5, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 8, 8, 6, 6, 4,
-  2, 5, 6, 6, 1, 1, 4, 4, 6, 8, 6, 6, 6, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
-};
-static const uint8 kShieldStuff_oam_index_ptrs_1[12] = {36, 20, 36, 8, 32, 36, 20, 36, 36, 36, 16, 28};
-static const uint8 kShieldStuff_oam_index_ptrs_0[12] = {28, 0, 28, 0, 24, 28, 12, 28, 36, 28, 8, 8};
-static const uint16 kShieldStuff_OamData[54] = {
-  0x2a07, 0xffff, 0xffff,
-  0x2a07, 0xffff, 0xffff,
-  0x2a07, 0xffff, 0xffff,
-  0x6a07, 0xffff, 0xffff,
-  0x2a07, 0xffff, 0xffff,
-  0x6a07, 0xffff, 0xffff,
-  0x2a07, 0xffff, 0xffff,
-  0x6a07, 0xffff, 0xffff,
-  0x2809, 0xffff, 0x2819,
-  0x2809, 0xffff, 0x2819,
-  0x281a, 0xffff, 0x2819,
-  0xa819, 0xffff, 0xa809,
-  0x2809, 0xffff, 0x2819,
-  0x2809, 0xffff, 0xffff,
-  0x2809, 0xffff, 0xffff,
-  0x2819, 0x2809, 0xffff,
-  0x6809, 0xffff, 0xffff,
-  0x6809, 0x6819, 0xffff,
-};
-static const uint8 kLinkBody_oam_index_0[12] = {20, 28, 8, 16, 0, 20, 24, 0, 16, 4, 16, 28};
-static const uint8 kLinkBody_oam_index_1[12] = {28, 36, 16, 24, 8, 28, 36, 8, 16, 12, 24, 36};
-static const uint16 kLinkDmaGraphicsIndices[511] = {
-  0, 174, 175, 176, 177, 178, 179, 180, 181, 5, 182, 183, 184, 185, 182, 186, 187, 188, 10, 10, 189, 190, 191, 192, 193, 194, 195, 13, 13, 196, 197, 198,
-  199, 200, 201, 202, 16, 16, 17, 17, 18, 18, 19, 19, 19, 20, 20, 21, 21, 22, 22, 23, 23, 23, 24, 24, 25, 25, 26, 26, 27, 27, 27, 28,
-  28, 29, 29, 30, 30, 31, 31, 31, 32, 33, 34, 32, 35, 36, 37, 38, 39, 37, 40, 41, 42, 43, 44, 42, 43, 44, 45, 46, 47, 45, 46, 47,
-  49, 48, 50, 52, 51, 52, 54, 53, 55, 57, 56, 58, 59, 60, 61, 62, 62, 62, 0, 13, 5, 10, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72,
-  73, 74, 75, 76, 77, 78, 0, 33, 116, 5, 117, 118, 42, 26, 119, 45, 30, 120, 163, 164, 165, 166, 167, 26, 168, 30, 0, 206, 207, 0, 162, 36,
-  5, 208, 209, 5, 210, 211, 10, 212, 213, 10, 212, 213, 13, 214, 215, 13, 214, 215, 125, 126, 127, 128, 83, 84, 85, 86, 87, 88, 89, 90, 91, 89,
-  92, 93, 94, 95, 96, 94, 97, 98, 99, 100, 101, 99, 100, 101, 102, 103, 104, 102, 103, 104, 32, 33, 34, 32, 35, 36, 37, 38, 39, 37, 40, 41,
-  42, 43, 44, 42, 43, 44, 45, 46, 47, 45, 46, 47, 105, 106, 107, 107, 108, 108, 109, 109, 13, 13, 110, 111, 112, 113, 114, 115, 216, 217, 217, 218,
-  219, 219, 220, 221, 221, 222, 223, 223, 142, 143, 144, 145, 146, 147, 148, 149, 152, 150, 151, 150, 155, 153, 154, 153, 158, 156, 157, 156, 161, 159, 160, 159,
-  150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 171, 171, 172, 172, 169, 169, 170, 170, 171, 171, 172, 172, 169, 169, 170, 170, 37, 42, 32, 45,
-  107, 173, 173, 173, 107, 203, 203, 203, 203, 204, 204, 204, 166, 166, 107, 203, 94, 205, 205, 224, 225, 226, 224, 227, 228, 229, 230, 231, 229, 232, 233, 234,
-  235, 236, 234, 235, 236, 237, 238, 239, 237, 238, 239, 257, 279, 279, 279, 279, 240, 241, 255, 94, 219, 255, 257, 279, 279, 279, 260, 280, 280, 280, 263, 281,
-  281, 281, 266, 282, 282, 282, 245, 246, 247, 242, 243, 244, 251, 252, 253, 248, 249, 250, 5, 10, 0, 13, 272, 273, 0, 33, 116, 5, 117, 118, 42, 26,
-  119, 45, 30, 120, 274, 275, 276, 277, 18, 22, 26, 30, 283, 284, 283, 285, 286, 287, 286, 288, 289, 290, 289, 290, 291, 292, 291, 292, 111, 293, 294, 106,
-  203, 72, 113, 99, 26, 295, 102, 30, 105, 203, 107, 10, 10, 109, 109, 13, 13, 112, 114, 110, 203, 297, 299, 300, 301, 302, 63, 16, 16, 79, 79, 294,
-  80, 294, 19, 19, 20, 20, 21, 21, 81, 82, 81, 23, 23, 24, 24, 25, 130, 131, 132, 133, 134, 134, 28, 28, 29, 121, 122, 123, 124, 129, 129,
-};
-typedef struct LinkSpriteBody {
-  int8 y, x;
-  uint8 tile;
-} LinkSpriteBody;
-static const LinkSpriteBody kLinkSpriteBodys[303] = {
-  { 0,  0, 0x00},
-  { 1,  0, 0x00},
-  { 2,  0, 0x00},
-  { 1,  0, 0x04},
-  { 2,  0, 0x04},
-  { 0,  0, 0x00},
-  { 1,  0, 0x00},
-  { 2,  0, 0x00},
-  { 1,  0, 0x04},
-  { 2,  0, 0x04},
-  { 0,  1, 0x44},
-  { 1,  1, 0x44},
-  { 2,  2, 0x44},
-  { 0, -1, 0x00},
-  { 1, -1, 0x00},
-  { 2, -2, 0x00},
-  { 0,  0, 0x00},
-  { 0,  0, 0x00},
-  {-1,  0, 0x00},
-  { 0,  0, 0x00},
-  { 0,  0, 0x00},
-  { 1,  0, 0x00},
-  { 1,  0, 0x00},
-  { 1,  0, 0x00},
-  { 1,  1, 0x44},
-  { 1,  1, 0x44},
-  { 1,  0, 0x44},
-  { 1,  1, 0x44},
-  { 1, -1, 0x00},
-  { 1, -1, 0x00},
-  { 1,  0, 0x00},
-  { 1, -1, 0x00},
-  { 0,  0, 0x00},
-  { 1,  0, 0x00},
-  { 2,  0, 0x00},
-  { 1,  0, 0x04},
-  { 2,  0, 0x04},
-  { 0,  0, 0x00},
-  { 1,  0, 0x00},
-  { 2,  0, 0x00},
-  { 1,  0, 0x00},
-  { 2,  0, 0x00},
-  { 0,  1, 0x44},
-  { 1,  1, 0x44},
-  { 2,  1, 0x44},
-  { 0, -1, 0x00},
-  { 1, -1, 0x00},
-  { 2, -1, 0x00},
-  {-1,  0, 0x00},
-  { 0,  0, 0x00},
-  { 0,  0, 0x00},
-  { 2,  0, 0x00},
-  { 1,  0, 0x00},
-  { 2, -1, 0x44},
-  { 1,  1, 0x44},
-  { 1,  1, 0x44},
-  { 2,  1, 0x00},
-  { 1, -1, 0x00},
-  { 1, -1, 0x00},
-  { 0, -8, 0x00},
-  { 4,  0, 0x0f},
-  { 4,  0, 0x0f},
-  { 0,  0, 0xff},
-  { 0,  0, 0x00},
-  { 0,  0, 0x00},
-  { 0,  0, 0x44},
-  { 0,  0, 0x00},
-  { 0,  0, 0x00},
-  {-1,  0, 0x00},
-  {-1,  0, 0x00},
-  { 0,  0, 0x00},
-  { 1,  0, 0x00},
-  { 2,  0, 0x00},
-  { 0,  0, 0x44},
-  { 1,  0, 0x44},
-  { 1,  0, 0x44},
-  { 0,  0, 0x00},
-  { 1,  0, 0x00},
-  { 1,  0, 0x00},
-  {-1,  0, 0x00},
-  {-5,  0, 0x00},
-  { 2,  0, 0x00},
-  { 5,  0, 0x00},
-  {-1,  0, 0x44},
-  { 0,  0, 0x44},
-  { 0,  1, 0x44},
-  {-1,  0, 0x00},
-  { 0,  0, 0x00},
-  { 0, -1, 0x00},
-  { 0,  0, 0x00},
-  { 1,  0, 0x00},
-  { 2,  0, 0x00},
-  { 1,  0, 0x04},
-  { 2,  0, 0x04},
-  { 0,  0, 0x00},
-  { 1,  0, 0x00},
-  { 2,  0, 0x00},
-  { 1,  0, 0x04},
-  { 2,  0, 0x04},
-  { 0,  1, 0x44},
-  { 1,  1, 0x44},
-  { 2,  1, 0x44},
-  { 0, -1, 0x00},
-  { 1, -1, 0x00},
-  { 2, -1, 0x00},
-  { 1,  0, 0x04},
-  { 0,  0, 0x44},
-  { 0,  0, 0x00},
-  { 0,  1, 0x44},
-  { 0,  0, 0x00},
-  { 0,  0, 0x04},
-  { 0,  0, 0x44},
-  { 0,  1, 0x40},
-  { 0,  2, 0x40},
-  { 0, -1, 0x00},
-  { 0, -2, 0x00},
-  { 0,  0, 0x00},
-  { 1,  0, 0x00},
-  { 0,  0, 0x00},
-  { 0,  1, 0x44},
-  { 0, -1, 0x00},
-  { 1,  1, 0x00},
-  { 2,  1, 0x00},
-  { 2,  4, 0x00},
-  { 2,  1, 0x00},
-  { 0,  0, 0x00},
-  { 1,  0, 0x00},
-  { 1,  0, 0x00},
-  { 0,  0, 0x00},
-  { 1,  0, 0x00},
-  { 1, -1, 0x44},
-  { 2, -1, 0x44},
-  { 2, -4, 0x44},
-  { 2, -1, 0x44},
-  { 1,  0, 0x44},
-  { 0,  0, 0x00},
-  { 0,  0, 0x40},
-  { 0,  0, 0x04},
-  { 0,  0, 0x04},
-  { 0,  0, 0x00},
-  { 0,  0, 0x00},
-  { 0,  0, 0x00},
-  { 1,  0, 0x00},
-  { 2,  0, 0x04},
-  { 1,  0, 0x00},
-  { 2,  0, 0x04},
-  { 5,  1, 0x40},
-  { 6,  1, 0x44},
-  { 5, -1, 0x04},
-  { 6, -1, 0x00},
-  { 0,  0, 0x00},
-  { 0,  0, 0x04},
-  { 0,  0, 0x00},
-  { 0,  0, 0x00},
-  { 0,  0, 0x44},
-  { 0,  0, 0x00},
-  {13,  3, 0x44},
-  {12,  5, 0x44},
-  {12,  5, 0x44},
-  {13, -3, 0x00},
-  {12, -5, 0x00},
-  {12, -5, 0x00},
-  { 1,  0, 0x00},
-  { 0,  0, 0x00},
-  { 0,  0, 0x00},
-  { 1,  0, 0x00},
-  { 2,  0, 0x00},
-  { 0,  0, 0x44},
-  { 0,  0, 0x00},
-  { 0,  0, 0x00},
-  { 0,  0, 0x00},
-  { 0,  0, 0x44},
-  { 0,  0, 0x44},
-  {-1,  0, 0x04},
-  { 0,  0, 0x00},
-  {-1,  0, 0x00},
-  {-2,  0, 0x00},
-  { 0,  0, 0x00},
-  { 0,  0, 0x00},
-  {-1,  0, 0x00},
-  {-2,  0, 0x00},
-  { 0,  0, 0x00},
-  { 0,  0, 0x04},
-  {-1,  0, 0x00},
-  {-2,  0, 0x00},
-  { 0,  0, 0x00},
-  {-1,  0, 0x04},
-  {-2,  0, 0x04},
-  { 0,  0, 0x04},
-  {-1,  1, 0x44},
-  {-1,  0, 0x44},
-  { 0,  1, 0x44},
-  { 0,  1, 0x44},
-  {-1,  1, 0x44},
-  {-1,  0, 0x44},
-  { 0,  0, 0x44},
-  {-1, -1, 0x00},
-  {-1,  0, 0x00},
-  { 0, -1, 0x00},
-  { 0, -1, 0x00},
-  {-1, -1, 0x00},
-  {-1,  0, 0x00},
-  { 0,  0, 0x00},
-  { 0,  0, 0x04},
-  { 1,  0, 0x00},
-  { 2,  0, 0x00},
-  { 1,  0, 0x00},
-  { 2,  0, 0x00},
-  { 1,  0, 0x00},
-  { 2,  0, 0x00},
-  { 1,  0, 0x04},
-  { 2,  0, 0x04},
-  { 1,  1, 0x44},
-  { 2,  1, 0x44},
-  { 1, -1, 0x00},
-  { 2, -1, 0x00},
-  { 2,  0, 0x00},
-  { 2,  0, 0x00},
-  { 3,  0, 0x00},
-  { 3,  0, 0x00},
-  { 2, -2, 0x44},
-  { 2,  1, 0x44},
-  { 2,  2, 0x00},
-  { 2, -1, 0x00},
-  { 0,  0, 0x00},
-  { 1,  0, 0x00},
-  { 2,  0, 0x00},
-  { 1,  0, 0x04},
-  { 2,  0, 0x04},
-  { 2,  0, 0x00},
-  { 3,  0, 0x00},
-  { 4,  0, 0x00},
-  { 3,  0, 0x04},
-  { 4,  0, 0x04},
-  { 0,  0, 0x44},
-  { 1,  0, 0x44},
-  { 2,  0, 0x44},
-  { 0,  0, 0x00},
-  { 1,  0, 0x00},
-  { 2,  0, 0x00},
-  { 3,  0, 0x00},
-  { 2,  0, 0x00},
-  {-1,  0, 0x00},
-  { 0,  0, 0x00},
-  { 1,  0, 0x00},
-  {-1,  0, 0x00},
-  { 0,  0, 0x00},
-  { 1,  0, 0x00},
-  {-1,  0, 0x44},
-  { 0,  0, 0x44},
-  { 1,  0, 0x44},
-  {-1,  0, 0x44},
-  { 0,  0, 0x44},
-  { 1,  0, 0x44},
-  { 0,  0, 0x00},
-  { 1,  0, 0x00},
-  { 2,  0, 0x00},
-  { 1,  0, 0x00},
-  { 2,  0, 0x00},
-  { 0,  0, 0x00},
-  { 3,  0, 0x00},
-  { 4,  0, 0x00},
-  { 2,  0, 0x00},
-  { 0, -1, 0x44},
-  { 1,  1, 0x44},
-  { 0,  1, 0x44},
-  { 0,  1, 0x00},
-  { 1,  1, 0x00},
-  { 0, -1, 0x00},
-  { 3,  0, 0x00},
-  { 2,  0, 0x04},
-  { 3,  0, 0x04},
-  { 0,  2, 0x00},
-  { 8,  8, 0x00},
-  { 0,  0, 0x00},
-  { 0,  0, 0x00},
-  {-1,  0, 0x0f},
-  { 1,  0, 0x00},
-  { 0,  0, 0x04},
-  { 0,  0, 0x00},
-  { 2,  0, 0x00},
-  { 1,  4, 0x44},
-  { 1, -4, 0x00},
-  { 0,  0, 0x00},
-  { 1,  0, 0x00},
-  { 1,  0, 0x04},
-  { 0,  0, 0x00},
-  { 1,  0, 0x00},
-  { 1,  0, 0x04},
-  { 0,  1, 0x44},
-  { 1,  1, 0x44},
-  { 0, -1, 0x00},
-  { 1, -1, 0x00},
-  { 0,  0, 0x44},
-  {-2,  0, 0x00},
-  { 0, -2, 0x04},
-  { 0,  0, 0x00},
-  { 0,  1, 0x00},
-  { 0,  0, 0x04},
-  {12,  0, 0x08},
-  {14,  0, 0x80},
-  {12,  0, 0x00},
-  {11,  0, 0x00},
-};
-static const uint8 kSwordStuff_oam_index_ptrs_1[12] = {0, 0, 24, 32, 24, 0, 0, 24, 24, 24, 32, 0};
-static const uint8 kSwordStuff_oam_index_ptrs_0[12] = {8, 16, 16, 24, 16, 0, 0, 16, 24, 16, 24, 16};
-static const int8 kPlayerOam_DrawOam_Throwing_State[16] = {-1, -1, -1, -1, 0, -1, -1, -1, 0, 0, -1, -1, 0, 0, 0, -1};
-static const int8 kPlayerOam_DrawOam_Throwing_X[16] = {-1, -1, -1, -1, 8, -1, -1, -1, 8, 5, -1, -1, 8, 5, 2, -1};
-static const int8 kPlayerOam_DrawOam_Throwing_Y[16] = {-1, -1, -1, -1, 14, -1, -1, -1, 14, 22, -1, -1, 14, 22, 30, -1};
-static const uint8 kShieldTypeToOffs[4] = {4, 4, 8, 8};
-static const int8 kOffsToShadowGivenDir_X[12] = {0, 0, -1, 1, 0, 0, 0, 0, 0, 0, 0, 0};
-static const int8 kOffsToShadowGivenDir_Y[12] = {16, 16, 17, 17, 16, 16, 16, 16, 18, 18, 18, 18};
-static const uint8 kShadow_oam_indexes_1[12] = {12, 12, 0, 0, 0, 12, 12, 0, 0, 0, 0, 12};
-static const uint8 kShadow_oam_indexes_0[12] = {40, 40, 40, 40, 40, 40, 40, 40, 0, 40, 40, 40};
-static const uint16 kLinkShadows_Chardata[22] = {0x286c, 0x686c, 0x2828, 0x6828, 0x2838, 0xffff, 0x286e, 0x686e, 0x287e, 0x687e, 0x24d8, 0x64d8, 0x24d9, 0x64d9, 0x24da, 0x64da, 0x22c8, 0x62c8, 0x22c9, 0x62c9, 0x22ca, 0x62ca};
-static const uint8 kPlayerOam_DrawOam_2X[3] = {0, 0, 4};
-bool PlayerOam_WantInvokeSword() {
-  if (link_player_handler_state != kPlayerState_Ether &&
-      link_player_handler_state != kPlayerState_Bombos &&
-      link_player_handler_state != kPlayerState_Quake &&
-      link_player_handler_state != kPlayerState_SpinAttacking &&
-      link_player_handler_state != kPlayerState_SpinAttackMotion &&
-      !link_state_bits && !link_force_hold_sword_up && !link_electrocute_on_touch) {
-    if (link_item_in_hand & 0x40)
-      return false;
-    if (link_position_mode & 0x3d || link_item_in_hand & 0x93)
-      return true;
-    if (!(button_mask_b_y & 0x80))
-      return false;
-  }
-  return ((link_sword_type + 1) & 0xfe) != 0;
-}
-
-void CalculateSwordHitBox() {  // 879e63
-  if (link_sword_type == 0 || link_sword_type == 0xff)
-    return;
-  if (link_sword_type >= 2 && button_b_frames < 9) {
-    int i = button_b_frames + ((link_direction_facing>>1) * 9);
-    if ((uint8)kSwordTipSomething[i] != 0xff) {
-      player_oam_y_offset = kSwordOamYOffs_Good[i];
-      player_oam_x_offset = kSwordOamXOffs_Good[i];
-      return;
-    }
-  }
-  uint8 offs = button_b_frames;
-  if (offs == 9)
-    return;
-  uint8 y = 39;
-  if (offs >= 10) {
-    offs -= 10;
-    y = 3;
-  }
-  int i = kPlayerOamOtherOffs[(link_direction_facing >> 1) * 40 + y] + offs;
-  player_oam_y_offset = kSwordOamYOffs[i];
-  player_oam_x_offset = kSwordOamXOffs[i];
-}
-
-void LinkOam_Main() {  // 8da18e
-  uint16 y_coord_backup = link_y_coord;
-
-  if (submodule_index == 18 || submodule_index == 19) {
-    int t = submodule_index == 18 ? 0 : 12;
-    t += which_staircase_index & 4 ? 6 : 0;
-    t += (link_animation_steps < 6) ? link_animation_steps : 0;
-    link_y_coord += kPlayerOam_StairsOffsY[t];
-  }
-
-  uint8 xcoord = link_x_coord - BG2HOFS_copy2;
-  uint8 ycoord = link_y_coord - BG2VOFS_copy2;
-  player_oam_x_offset = player_oam_y_offset = 0x80;
-  uint8 scratch_0_var = (draw_water_ripples_or_grass != 0);
-  oam_priority_value = kPlayerOam_FloorOamPrio[link_is_on_lower_level];
-  sort_sprites_offset_into_oam_buffer = kPlayerOam_SortSpritesOffs[(uint8)sort_sprites_setting];
-
-  uint8 yt, rt;
-
-  if (link_player_handler_state == kPlayerState_AsleepInBed && link_pose_during_opening != 2) {
-    yt = 0x1f, rt = link_pose_during_opening;
-    goto continue_after_set;
-  }
-  if (link_force_hold_sword_up) {
-    yt = 0x24, rt = 0;
-    link_direction_facing_mirror = link_direction_facing;
-    goto continue_after_set;
-  }
-  if (link_is_bunny_mirror) {
-    yt = 0x21, rt = link_animation_steps & 3;
-    link_direction_facing_mirror = link_direction_facing;
-    goto continue_after_set;
-  }
-  yt = draw_water_ripples_or_grass ? 10 : 0;
-
-  if (submodule_index == 14 && main_module_index != 18 && ((yt = 10), link_actual_vel_x)) {
-    if (link_direction_facing != 4 && link_direction_facing != 6) {
-      rt = kPlayerOam_Tab1[link_animation_steps];
-      yt = which_staircase_index & 4 ? 0x1a : 0x19;
-    } else {
-      rt = link_animation_steps;
-    }
-  } else {
-    if (link_grabbing_wall & 3) {
-      yt = 0x18, rt = some_animation_timer_steps;
-    } else {
-      if (bitmask_of_dragstate & 0xd) {
-        yt = 0x16;
-        if (link_animation_steps >= 5)
-          link_animation_steps = 0;
-      }
-      rt = link_animation_steps;
-    }
-  }
-  link_direction_facing_mirror = link_direction_facing;
-  if (link_is_in_deep_water)
-    oam_priority_value = 0x2000;
-
-  if (link_player_handler_state == kPlayerState_Swimming) {
-    yt = 0x11, rt &= 1;
-    if (submodule_index == 0 && (joypad1H_last & 0xf) != 0 || (swimcoll_var7[0] | swimcoll_var7[1]))
-      yt = 0x13, rt = byte_7E02CC;
-    if (link_maybe_swim_faster)
-      yt = 0x12, rt = link_maybe_swim_faster - 1;
-    goto continue_after_set;
-  }
-  if (link_pose_for_item) {
-    rt = 0, yt = (link_pose_for_item != 2) ? 0x1d : 0x1e;
-    goto continue_after_set;
-  }
-  if (player_unk1 & 1) {
-    yt = 0x1b, rt = some_animation_timer_steps;
-    goto continue_after_set;
-  }
-
-  if (link_auxiliary_state != 0) {
-    if (link_auxiliary_state == 4) {
-      yt = 0x13, rt = kSwimmingTab1[(frame_counter & 0x18) >> 3];
-      goto continue_after_set;
-    } else if (link_auxiliary_state == 1) {
-      if (link_player_handler_state == kPlayerState_TurtleRock) {
-        if (!byte_7E034E)
-          oam_priority_value = 0x3000;
-        goto link_state_is_empty;
-      } else if (link_player_handler_state != kPlayerState_Hookshot && !link_cape_mode) {
-        if (link_electrocute_on_touch)
-          yt = 0x14, rt = player_handler_timer & 3;
-        else
-          yt = 5, rt = 0;
-        goto continue_after_set;
-      }
-    }
-  }
-
-  if (player_near_pit_state != 0 && player_near_pit_state != 1) {
-    if (player_near_pit_state == 3)
-      sort_sprites_offset_into_oam_buffer = 0;
-    yt = 4, rt = link_this_controls_sprite_oam;
-    if (rt >= 6)
-      oam_priority_value |= 0x3000;
-    goto continue_after_set;
-  }
-
-  if (link_state_bits != 0) {
-    uint8 bit = FindMostSignificantBit(link_state_bits);
-    if (bit < 6)
-      link_direction_facing_mirror = 2;
-    yt = kPlayerOam_Tab4[bit];
-    if (yt >= 0xd) {
-      if (link_picking_throw_state & 2)
-        yt += 1;
-
-      if (link_picking_throw_state & 1)
-        yt = 0x10;
-      else if (link_state_bits & 0x80)
-        goto continue_after_set;
-    }
-    rt = some_animation_timer_steps;
-    goto continue_after_set;
-  }
-link_state_is_empty:
-  if (link_unk_master_sword != 0) {
-    yt = 0x17, rt = link_unk_master_sword - 1;
-    goto continue_after_set;
-  }
-
-  if (link_item_in_hand != 0) {
-    yt = kPlayerOam_Tab2[FindMostSignificantBit(link_item_in_hand)];
-    rt = player_handler_timer;
-    goto continue_after_set;
-  } else if (link_position_mode != 0) {
-    yt = kPlayerOam_Tab3[FindMostSignificantBit(link_position_mode)];
-    rt = player_handler_timer;
-    goto continue_after_set;
-  }
-
-  if (link_player_handler_state == kPlayerState_Quake || link_player_handler_state == kPlayerState_Ether || link_player_handler_state == kPlayerState_Bombos) {
-    yt = 0x15, rt = state_for_spin_attack;
-    goto continue_after_set;
-  } else if (link_player_handler_state == kPlayerState_SpinAttackMotion || link_player_handler_state == kPlayerState_SpinAttacking) {
-    yt = 0xf, rt = state_for_spin_attack;
-    goto continue_after_set;
-  }
-
-  if (button_mask_b_y & 0x80) {
-    if (button_b_frames == 9) {
-      yt = 2;
-    } else {
-      yt = 0x27, rt = button_b_frames;
-      if (rt >= 9) {
-        yt = 3;
-        rt -= 10;
-      }
-    }
-  }
-continue_after_set:
-  value_computed_for_player_oam = yt;
-  if (yt != 5)
-    oam_priority_value_2 = oam_priority_value;
-
-  BYTE(index_of_interacting_tile) = rt;
-
-  int dir = link_direction_facing >> 1;
-
-  int r2 = kPlayerOamOtherOffs[dir * 40 + yt] + rt;
-  int r4loc = kPlayerOamSpriteLocs[r2];
-
-  link_palette_bits_of_oam = palette_swap_flag ? 0 : 0xe00;
-  link_dma_var1 = link_dma_var2 = 0;
-
-  int xt = FindInByteArray(kPlayerOam_Tab5, yt, 7);
-  if (xt >= 0) {
-    int j = kPlayerOam_Tab6[xt + dir * 7] + rt;
-    scratch_1 = j;
-    {
-      uint8 bank1 = kPlayerOam_Spr1Bank[j];
-      if (bank1 != 0xff) {
-        link_dma_var1 = bank1 * 2;
-        int oam_pos = ((scratch_0_var ? kPlayerOam_Tab19B : kPlayerOam_Tab19A)[r4loc] + sort_sprites_offset_into_oam_buffer) >> 2;
-        uint8 zt = ((int16)link_z_coord >= 0 || BYTE(link_z_coord) < 0xf0) ? BYTE(link_z_coord) : 0;
-        oam_buf[oam_pos].y = kPlayerOam_Spr1Y[j] + ycoord - zt;
-        oam_buf[oam_pos].x = kPlayerOam_Spr1X[j] + xcoord;
-        uint16 q = WORD(kPlayerOam_Prio[bank1 >> 1]);
-        q = (bank1 & 1) ? q << 4 : q;
-        WORD(oam_buf[oam_pos].charnum) = (q & 0xc000) | oam_priority_value | link_palette_bits_of_oam | 4;
-        bytewise_extended_oam[oam_pos] = 0;
-      }
-    }
-
-    uint8 bank2 = kPlayerOam_Spr2Bank[j];
-    if (bank2 != 0xff) {
-      link_dma_var2 = bank2 * 2;
-      int oam_pos = ((scratch_0_var ? kPlayerOam_Tab20B : kPlayerOam_Tab20A)[r4loc] + sort_sprites_offset_into_oam_buffer) >> 2;
-      uint8 zt = ((int16)link_z_coord >= 0 || BYTE(link_z_coord) < 0xf0) ? BYTE(link_z_coord) : 0;
-      oam_buf[oam_pos].y = kPlayerOam_Spr2Y[j] + ycoord - zt;
-      oam_buf[oam_pos].x = kPlayerOam_Spr2X[j] + xcoord;
-      uint16 q = WORD(kPlayerOam_Prio[bank2 >> 1]);
-      q = (bank2 & 1) ? q << 4 : q;
-      WORD(oam_buf[oam_pos].charnum) = (q & 0xc000) | oam_priority_value | link_palette_bits_of_oam | 0x14;
-      bytewise_extended_oam[oam_pos] = 0;
-    }
-  }
-  SwordResult sr;
-
-  if (link_picking_throw_state & 4) {
-    LinkOam_UnusedWeaponSettings(r4loc, xcoord, ycoord);
-  } else if (PlayerOam_WantInvokeSword() && !LinkOam_SetWeaponVRAMOffsets(r2, &sr)) {
-    uint8 zcoord = ((int16)link_z_coord >= 0 || BYTE(link_z_coord) < 0xf0) ? BYTE(link_z_coord) : 0;
-    uint8 oam_y = kDrawSword_y[r2] + ycoord - zcoord;
-    uint8 oam_x = kDrawSword_x[r2] + xcoord;
-
-    if ((link_item_in_hand & 2) ? (player_handler_timer == 2 && link_delay_timer_spin_attack == 15) : ((link_item_in_hand & 5) == 0)) {
-      player_oam_y_offset = kSwordOamYOffs[r2];
-      player_oam_x_offset = kSwordOamXOffs[r2];
-    }
-    uint16 oam_pal = 0;
-    if (link_item_in_hand & 5) {
-      assert(link_state_bits == 0);
-      oam_pal = kPlayerOam_Rod[eq_selected_rod - 1] << 8;
-    }
-    if ((link_position_mode & 8) && current_item_y == 13)
-      oam_pal = 0x400;  // cane of byrna
-
-    int oam_pos = ((scratch_0_var ? kSwordStuff_oam_index_ptrs_1 : kSwordStuff_oam_index_ptrs_0)[r4loc] + sort_sprites_offset_into_oam_buffer)>>2;
-    oam_pos = LinkOam_CalculateSwordSparklePosition(oam_pos, xcoord, ycoord);
-
-    int j = sr.r6 * 3;
-    for (int i = 0; i != 3; i++, j++) {
-      uint16 td = kSwordTiledata[j];
-      if (td != 0xffff) {
-        td = (td & ~0x3000) | oam_priority_value;
-        if ((td & 0xe00) != 0x200 && !link_palette_bits_of_oam)
-          td = (td & ~0xe00) | 0x600;
-        if (oam_pal)
-          td = (td & ~0xe00) | oam_pal;
-        WORD(oam_buf[oam_pos].charnum) = td;
-        oam_buf[oam_pos].x = oam_x;
-        oam_buf[oam_pos].y = oam_y;
-        uint16 xt = (uint8)xcoord - oam_x;
-        if ((int16)xt < 0) xt = -xt;
-        bytewise_extended_oam[oam_pos] = sr.r12 | (xt >= 0x80);
-        oam_pos++;
-      }
-      oam_x += 8;
-      if (i == 1)
-        oam_x -= 16, oam_y += 8;
-    }
-  }
-
-  //SwordStuff_fail
-  if (link_shield_type && sram_progress_indicator && !LinkOam_SetEquipmentVRAMOffsets(r2, &sr)) {
-    uint8 zcoord = ((int16)link_z_coord >= 0 || BYTE(link_z_coord) < 0xf0) ? BYTE(link_z_coord) : 0;
-    uint8 oam_y = kShieldStuff_y[r2] + ycoord - 1 - zcoord;
-    uint8 oam_x = kShieldStuff_x[r2] + xcoord;
-
-    LinkOam_CalculateXOffsetRelativeLink(kShieldStuff_x[r2]);
-
-    uint16 oam_pal = (link_palette_bits_of_oam >> 8) ? 0xa00 : 0x600;
-
-    int oam_pos = ((scratch_0_var ? kShieldStuff_oam_index_ptrs_1 : kShieldStuff_oam_index_ptrs_0)[r4loc] + sort_sprites_offset_into_oam_buffer)>>2;
-
-    int j = sr.r6 * 3;
-    for (int i = 0; i != 3; i++, j++) {
-      uint16 td = kShieldStuff_OamData[j];
-      if (td == 0xffff)
-        continue;
-      td = (td & 0xc1ff) | oam_pal | oam_priority_value;
-      WORD(oam_buf[oam_pos].charnum) = td;
-      WORD(oam_buf[oam_pos].x) = oam_x | oam_y << 8;
-      bytewise_extended_oam[oam_pos] = sr.r12 | bit9_of_xcoord;
-      oam_x += 8;
-      if (i == 1)
-        oam_x -= 16, oam_y += 8;
-    }
-  }
-
-  if (link_visibility_status != 12 && link_player_handler_state != kPlayerState_AsleepInBed) {
-    if (value_computed_for_player_oam != 5 && draw_water_ripples_or_grass) {
-      LinkOam_DrawFootObject(r4loc, xcoord, ycoord);
-    } else if (link_auxiliary_state != 4 && link_player_handler_state != kPlayerState_Swimming) {
-      if (player_near_pit_state != 0 && player_near_pit_state != 1) {
-        if (link_this_controls_sprite_oam >= 6) {
-          LinkOam_DrawDungeonFallShadow(r4loc, xcoord);
-          r4loc = 2; // wtf
-        }
-      } else {
-        // draw shadow
-        int shadow_idx = (link_auxiliary_state != 0) && (link_auxiliary_state != 1 || !link_cape_mode);
-        uint16 oam_y = link_y_coord - BG2VOFS_copy2 + kOffsToShadowGivenDir_Y[link_direction_facing_mirror >> 1];
-        if (oam_y < 256) {
-          uint8 oam_x = xcoord + kOffsToShadowGivenDir_X[link_direction_facing_mirror >> 1];
-          int oam_pos = ((scratch_0_var ? kShadow_oam_indexes_1 : kShadow_oam_indexes_0)[r4loc] + sort_sprites_offset_into_oam_buffer)>>2;
-
-          uint16 td = kLinkShadows_Chardata[shadow_idx*2] & ~0x3000 | oam_priority_value_2;
-          if (!link_palette_bits_of_oam)
-            td = td & ~0xe00 | 0x600;
-          WORD(oam_buf[oam_pos+0].charnum) = td;
-          WORD(oam_buf[oam_pos+1].charnum) = td & ~0xC000 | 0x4000;
-          WORD(oam_buf[oam_pos+0].x) = (uint8)oam_x | oam_y << 8;
-          WORD(oam_buf[oam_pos+1].x) = (uint8)(oam_x + 8) | oam_y << 8;
-          bytewise_extended_oam[oam_pos+0] = 0;
-          bytewise_extended_oam[oam_pos+1] = 0;
-        }
-      }
-    }
-  }
-
-  {
-    int oam_pos = ((scratch_0_var ? kLinkBody_oam_index_1 : kLinkBody_oam_index_0)[r4loc] + sort_sprites_offset_into_oam_buffer)>>2;
-
-    int j = kLinkDmaGraphicsIndices[r2];
-    link_dma_graphics_index = j * 2;
-
-    if (link_visibility_status != 12) {
-      uint8 zcoord = ((int16)link_z_coord >= 0 || BYTE(link_z_coord) < 0xf0) ? BYTE(link_z_coord) : 0;
-
-      const LinkSpriteBody *sp = &kLinkSpriteBodys[j];
-
-      uint8 oam_y = ycoord + sp->y - zcoord;
-      uint8 oam_x = xcoord + sp->x;
-      uint16 td = sp->tile << 8;
-
-      if ((td & 0xf000) != 0xf000) {
-        WORD(oam_buf[oam_pos].charnum) = td & 0xf000 | oam_priority_value | link_palette_bits_of_oam;
-        WORD(oam_buf[oam_pos].x) = oam_x | oam_y << 8;
-        bytewise_extended_oam[oam_pos] = 2 + (oam_x >= 0xf8);
-      }
-
-      if ((td << 4 & 0xf000) != 0xf000) {
-        WORD(oam_buf[oam_pos+1].charnum) = td << 4 & 0xf000 | oam_priority_value | link_palette_bits_of_oam | 2;
-        WORD(oam_buf[oam_pos+1].x) = (uint8)(xcoord) | (ycoord - zcoord + 8) << 8;
-        bytewise_extended_oam[oam_pos+1] = 2;
-      }
-    }
-  }
-
-  uint16 t;
-  bool hide_shadow = true;
-  if (is_standing_in_doorway && ((t = link_x_coord - BG2HOFS_copy2) < 4 || t >= 252 || (t = link_y_coord - BG2VOFS_copy2) < 4 || t >= 224) ||
-      (hide_shadow = false,
-      submodule_index == 0 && countdown_for_blink && --countdown_for_blink >= 4 && (countdown_for_blink & 1) == 0 ||
-      link_visibility_status == 12 ||
-      link_cape_mode != 0)) {
-    int shadow_oam_pos = (!hide_shadow && link_visibility_status != 12) ?
-        (scratch_0_var ? kShadow_oam_indexes_1 : kShadow_oam_indexes_0)[r4loc] >> 2 : -10;
-
-    // This appears to hide link by setting the extended bits of the oam to hide them from the screen.
-    // It doesn't really play well with the widescreen modes, so change how it's done.
-    if (enhanced_features0 & kFeatures0_WidescreenVisualFixes) {
-      OamEnt *oam = &oam_buf[sort_sprites_offset_into_oam_buffer >> 2];
-      for (int i = 0; i < 12; i++) {
-        if (i < shadow_oam_pos || i > shadow_oam_pos + 1)
-          oam[i].y = 0xf0;
-      }
-    } else {
-      uint8 *p = &bytewise_extended_oam[sort_sprites_offset_into_oam_buffer >> 2];
-      WORD(p[0]) = 0x101;
-      WORD(p[2]) = 0x101;
-      WORD(p[4]) = 0x101;
-      WORD(p[6]) = 0x101;
-      WORD(p[8]) = 0x101;
-      WORD(p[10]) = 0x101;
-      // Clear the bit again for the shadow oam so it's not hidden?
-      if (shadow_oam_pos >= 0)
-        WORD(p[shadow_oam_pos]) = 0;
-    }
-  }
-
-  if (submodule_index == 18 || submodule_index == 19)
-    link_y_coord = y_coord_backup;
-}
-
-uint8 FindMostSignificantBit(uint8 v) {  // 8daac3
-  int i = 7;
-  while (!(v & 0x80) && --i >= 0)
-    v <<= 1;
-  return (uint8)i;
-}
-
-bool LinkOam_SetWeaponVRAMOffsets(int r2, SwordResult *sr) {  // 8dab6e
-  uint8 j = kPlayerOam_Main_SwordStuff_array1[r2];
-  if ((sr->r6 = j) == 0xff)
-    return true;
-  sr->r12 = kPlayerOam_Main_SwordStuff_array2[j];
-  uint8 y = kPlayerOam_Main_SwordStuff_array3[j];
-  if (j < 29) {
-    link_dma_var3 = y;
-  } else {
-    if (link_item_in_hand & 5)
-      y = kPlayerOam_Main_SwordStuff_array4[j - 29];
-    link_dma_var5 = y;
-  }
-  return false;
-}
-
-bool LinkOam_SetEquipmentVRAMOffsets(int r2, SwordResult *sr) {  // 8dabe6
-  uint8 j = kPlayerOam_ShieldStuff_array1[r2];
-  if ((sr->r6 = j) == 0xff)
-    return true;
-
-  uint8 y = kPlayerOam_ShieldStuff_array2[j];
-  if (j >= 8) {
-    if (link_item_in_hand & 5)
-      y = kPlayerOam_ShieldStuff_array3[j - 8];
-    link_dma_var5 = y;
-    sr->r12 = (y & 7) ? 0 : 2;
-  } else {
-    link_dma_var4 = y;
-    sr->r12 = 2;
-  }
-  return false;
-}
-
-int LinkOam_CalculateSwordSparklePosition(int oam_pos, uint8 oam_x, uint8 oam_y) {  // 8dacd5
-  if (link_player_handler_state | link_speed_setting)
-    return oam_pos;
-  if (link_sword_type == 0 || link_sword_type == 1 || link_sword_type == 0xff || !(button_mask_b_y & 0x80) || button_b_frames >= 9)
-    return oam_pos;
-
-  int i = (link_direction_facing >> 1) * 9 + button_b_frames;
-  uint16 td = kSwordTipSomething[i];
-  if (td == 0xffff)
-    return oam_pos;
-  td = td & ~0x3000 | oam_priority_value;
-  if (!link_palette_bits_of_oam)
-    td = td & ~0xe00 | 0x600;
-  WORD(oam_buf[oam_pos].charnum) = td;
-  player_oam_x_offset = kSwordOamXOffs_Good[i];
-  player_oam_y_offset = kSwordOamYOffs_Good[i];
-  oam_x += player_oam_x_offset;
-  oam_y += player_oam_y_offset;
-  oam_buf[oam_pos].x = oam_x;
-  oam_buf[oam_pos].y = oam_y;
-  LinkOam_CalculateXOffsetRelativeLink(player_oam_x_offset);
-  bytewise_extended_oam[oam_pos] = bit9_of_xcoord;
-  return oam_pos + 1;
-}
-
-void LinkOam_UnusedWeaponSettings(int r4loc, uint8 oam_x, uint8 oam_y) {  // 8dadb6
-  int j = link_var30e * 4;
-  int oam_pos = ((draw_water_ripples_or_grass != 0 ? kSwordStuff_oam_index_ptrs_1 : kSwordStuff_oam_index_ptrs_0)[r4loc] + sort_sprites_offset_into_oam_buffer)>>2;
-  OamEnt *oam = &oam_buf[oam_pos];
-  for (int i = 0; i != 4; i++, j++) {
-    uint8 st = kPlayerOam_DrawOam_Throwing_State[j];
-    if (st != 0xff) {
-      WORD(oam->charnum) = 0x2609 & ~0x3000 | oam_priority_value;
-      oam->x = oam_x + kPlayerOam_DrawOam_Throwing_X[j];
-      oam->y = oam_y + kPlayerOam_DrawOam_Throwing_Y[j];
-      bytewise_extended_oam[oam_pos] = 0;
-      oam++, oam_pos++;
-    }
-  }
-}
-
-void LinkOam_DrawDungeonFallShadow(int r4loc, uint8 xcoord) {  // 8dae3b
-  uint8 yd = tiledetect_which_y_pos[0] - 12 - link_y_coord;
-  int yv = yd >= 240 ? 0 :
-           yd >= 96 ? 2 :
-           yd >= 48 ? 1 : 0;
-
-  xcoord += kPlayerOam_DrawOam_2X[yv];
-  uint8 ycoord = tiledetect_which_y_pos[0] - 12 - BG2VOFS_copy2 + 29;
-  int oam_pos = ((draw_water_ripples_or_grass ? kShadow_oam_indexes_1 : kShadow_oam_indexes_0)[r4loc] + sort_sprites_offset_into_oam_buffer)>>2;
-
-  yv *= 2;
-  for (int i = 0; i != 2; i++, oam_pos++, yv++) {
-    uint16 td = kLinkShadows_Chardata[yv];
-    if (td != 0xffff) {
-      WORD(oam_buf[oam_pos].charnum) = td & ~0x3000 | oam_priority_value_2;
-      WORD(oam_buf[oam_pos].x) = xcoord | ycoord << 8;
-    }
-    bytewise_extended_oam[oam_pos] = 0;
-    xcoord += 8;
-  }
-}
-
-void LinkOam_DrawFootObject(int r4loc, uint8 oam_x, uint8 oam_y) {  // 8daed1
-  primary_water_grass_timer = (primary_water_grass_timer + 1) & 0xf;
-  if (primary_water_grass_timer >= 9) {
-    primary_water_grass_timer = 0;
-    secondary_water_grass_timer = (secondary_water_grass_timer + 1) & 3;
-    if (secondary_water_grass_timer == 3)
-      secondary_water_grass_timer = 0;
-  }
-
-  int i = (link_direction_facing_mirror >> 1) + kShieldTypeToOffs[link_shield_type];
-
-  oam_x += kOffsToShadowGivenDir_X[i];
-  oam_y += kOffsToShadowGivenDir_Y[i];
-
-  int oam_pos = (kShadow_oam_indexes_1[r4loc] + sort_sprites_offset_into_oam_buffer)>>2;
-
-  uint8 yv;
-  if (draw_water_ripples_or_grass == 2) {
-    yv = (link_animation_steps >= 3 ? link_animation_steps - 3 : link_animation_steps);
-    ((uint8 *)&overlay_index)[1] = yv * 4;
-    yv = (8 + yv);
-  } else {
-    ((uint8 *)&overlay_index)[1] = secondary_water_grass_timer * 4;
-    yv = (5 + secondary_water_grass_timer);
-  }
-
-  OamEnt *oam = &oam_buf[oam_pos];
-
-  if (yv >= 11) {
-    // OOB read
-    WORD(oam[0].charnum) = 0x00 & ~0x3000 | oam_priority_value_2;
-    WORD(oam[1].charnum) = 0xAE | oam_priority_value_2;
-  } else {
-    WORD(oam[0].charnum) = kLinkShadows_Chardata[yv * 2 + 0] & ~0x3000 | oam_priority_value_2;
-    WORD(oam[1].charnum) = kLinkShadows_Chardata[yv * 2 + 1] | oam_priority_value_2;
-
-  }
-
-
-  oam[0].x = oam_x;
-  oam[1].x = oam_x + 8;
-
-  oam[0].y = oam_y;
-  oam[1].y = oam_y;
-
-  WORD(bytewise_extended_oam[oam_pos]) = 0;
-}
-
-void LinkOam_CalculateXOffsetRelativeLink(uint8 x) {  // 8dafc0
-  bit9_of_xcoord = (link_x_coord + (int8)x - BG2HOFS_copy2) >> 8 & 1;
-}
-
--- a/player_oam.h
+++ /dev/null
@@ -1,19 +1,0 @@
-#pragma once
-#include "types.h"
-
-typedef struct SwordResult {
-  uint8 r6;
-  uint8 r12;
-} SwordResult;
-
-bool PlayerOam_WantInvokeSword();
-void CalculateSwordHitBox();
-void LinkOam_Main();
-uint8 FindMostSignificantBit(uint8 v);
-bool LinkOam_SetWeaponVRAMOffsets(int r2, SwordResult *sr);
-bool LinkOam_SetEquipmentVRAMOffsets(int r2, SwordResult *sr);
-int LinkOam_CalculateSwordSparklePosition(int oam_pos, uint8 oam_x, uint8 oam_y);
-void LinkOam_UnusedWeaponSettings(int r4loc, uint8 oam_x, uint8 oam_y);
-void LinkOam_DrawDungeonFallShadow(int r4loc, uint8 xcoord);
-void LinkOam_DrawFootObject(int r4loc, uint8 oam_x, uint8 oam_y);
-void LinkOam_CalculateXOffsetRelativeLink(uint8 x);
--- a/poly.c
+++ /dev/null
@@ -1,323 +1,0 @@
-#include "poly.h"
-#include "zelda_rtl.h"
-#include "variables.h"
-
-static const int8 kPolySinCos[320] = {
-  0,   2,   3,   5,   6,   8,   9,  11,  12,  14,  16,  17,  19,  20,  22,  23,
-  24,  26,  27,  29,  30,  32,  33,  34,  36,  37,  38,  39,  41,  42,  43,  44,
-  45,  46,  47,  48,  49,  50,  51,  52,  53,  54,  55,  56,  56,  57,  58,  59,
-  59,  60,  60,  61,  61,  62,  62,  62,  63,  63,  63,  64,  64,  64,  64,  64,
-  64,  64,  64,  64,  64,  64,  63,  63,  63,  62,  62,  62,  61,  61,  60,  60,
-  59,  59,  58,  57,  56,  56,  55,  54,  53,  52,  51,  50,  49,  48,  47,  46,
-  45,  44,  43,  42,  41,  39,  38,  37,  36,  34,  33,  32,  30,  29,  27,  26,
-  24,  23,  22,  20,  19,  17,  16,  14,  12,  11,   9,   8,   6,   5,   3,   2,
-  0,  -2,  -3,  -5,  -6,  -8,  -9, -11, -12, -14, -16, -17, -19, -20, -22, -23,
-  -24, -26, -27, -29, -30, -32, -33, -34, -36, -37, -38, -39, -41, -42, -43, -44,
-  -45, -46, -47, -48, -49, -50, -51, -52, -53, -54, -55, -56, -56, -57, -58, -59,
-  -59, -60, -60, -61, -61, -62, -62, -62, -63, -63, -63, -64, -64, -64, -64, -64,
-  -64, -64, -64, -64, -64, -64, -63, -63, -63, -62, -62, -62, -61, -61, -60, -60,
-  -59, -59, -58, -57, -56, -56, -55, -54, -53, -52, -51, -50, -49, -48, -47, -46,
-  -45, -44, -43, -42, -41, -39, -38, -37, -36, -34, -33, -32, -30, -29, -27, -26,
-  -24, -23, -22, -20, -19, -17, -16, -14, -12, -11,  -9,  -8,  -6,  -5,  -3,  -2,
-  0,   2,   3,   5,   6,   8,   9,  11,  12,  14,  16,  17,  19,  20,  22,  23,
-  24,  26,  27,  29,  30,  32,  33,  34,  36,  37,  38,  39,  41,  42,  43,  44,
-  45,  46,  47,  48,  49,  50,  51,  52,  53,  54,  55,  56,  56,  57,  58,  59,
-  59,  60,  60,  61,  61,  62,  62,  62,  63,  63,  63,  64,  64,  64,  64,  64,
-};
-typedef struct Vertex3 {
-  int8 x, y, z;
-} Vertex3;
-static const Vertex3 kPoly0_Vtx[6] = {
-  {  0,  65,   0},
-  {  0, -65,   0},
-  {  0,   0, -40},
-  {-40,   0,   0},
-  {  0,   0,  40},
-  { 40,   0,   0},
-};
-static const uint8 kPoly0_Polys[40] = {
-  3, 0, 5, 2, 4,
-  3, 0, 2, 3, 1,
-  3, 0, 3, 4, 2,
-  3, 0, 4, 5, 3,
-  3, 1, 2, 5, 4,
-  3, 1, 3, 2, 1,
-  3, 1, 4, 3, 2,
-  3, 1, 5, 4, 3,
-};
-static const Vertex3 kPoly1_Vtx[6] = {
-  {  0,  40,  10},
-  { 40, -40,  10},
-  {-40, -40,  10},
-  {  0,  40, -10},
-  {-40, -40, -10},
-  { 40, -40, -10},
-};
-static const uint8 kPoly1_Polys[28] = {
-  3, 0, 1, 2, 7,
-  3, 3, 4, 5, 6,
-  4, 0, 3, 5, 1, 5,
-  4, 1, 5, 4, 2, 4,
-  4, 3, 0, 2, 4, 3,
-};
-typedef struct PolyConfig {
-  uint8 num_vtx, num_poly;
-  uint16 vtx_val, polys_val;
-  const Vertex3 *vertex;
-  const uint8 *poly;
-} PolyConfig;
-static const PolyConfig kPolyConfigs[2] = {
-  {6, 8, 0xff98, 0xffaa, kPoly0_Vtx, kPoly0_Polys},
-  {6, 5, 0xffd2, 0xffe4, kPoly1_Vtx, kPoly1_Polys},
-};
-static const uint32 kPoly_RasterColors[16] = {
-  0x00, 0xff, 0xff00, 0xffff,
-  0xff0000, 0xff00ff, 0xffff00, 0xffffff,
-  0xff000000, 0xff0000ff, 0xff00ff00, 0xff00ffff,
-  0xffff0000, 0xffff00ff, 0xffffff00, 0xffffffff,
-};
-static const uint16 kPoly_LeftSideMask[8] = {0xffff, 0x7f7f, 0x3f3f, 0x1f1f, 0xf0f, 0x707, 0x303, 0x101};
-static const uint16 kPoly_RightSideMask[8] = {0x8080, 0xc0c0, 0xe0e0, 0xf0f0, 0xf8f8, 0xfcfc, 0xfefe, 0xffff};
-uint16 Poly_Divide(uint16 a, uint16 b) {
-  poly_tmp1 = sign16(a) ? -a : a;
-  poly_tmp0 = b;
-  while (poly_tmp0 >= 256)
-    poly_tmp0 >>= 1, poly_tmp1 >>= 1;
-  int q = poly_tmp1 / poly_tmp0;
-  return sign16(a) ? -q : q;
-}
-
-void Poly_RunFrame() {
-  Polyhedral_EmptyBitMapBuffer();
-  Polyhedral_SetShapePointer();
-  Polyhedral_SetRotationMatrix();
-  Polyhedral_OperateRotation();
-  Polyhedral_DrawPolyhedron();
-}
-
-void Polyhedral_SetShapePointer() {  // 89f83d
-  poly_var1 = poly_config1 * 2 + 0x80;
-  poly_tmp0 = poly_which_model * 2;
-
-  const PolyConfig *poly_config = &kPolyConfigs[poly_which_model];
-  poly_config_num_vertex = poly_config->num_vtx;
-  poly_config_num_polys = poly_config->num_poly;
-  poly_fromlut_ptr2 = poly_config->vtx_val;
-  poly_fromlut_ptr4 = poly_config->polys_val;
-}
-
-void Polyhedral_SetRotationMatrix() {  // 89f864
-  poly_sin_a = kPolySinCos[poly_a];
-  poly_cos_a = kPolySinCos[poly_a + 64];
-  poly_sin_b = kPolySinCos[poly_b];
-  poly_cos_b = kPolySinCos[poly_b + 64];
-  poly_e0 = (int16)poly_sin_b * (int8)poly_sin_a >> 8 << 2;
-  poly_e1 = (int16)poly_cos_b * (int8)poly_cos_a >> 8 << 2;
-  poly_e2 = (int16)poly_cos_b * (int8)poly_sin_a >> 8 << 2;
-  poly_e3 = (int16)poly_sin_b * (int8)poly_cos_a >> 8 << 2;
-}
-
-void Polyhedral_OperateRotation() {  // 89f8fb
-  const PolyConfig *poly_config = &kPolyConfigs[poly_which_model];
-  const int8 *src = &poly_config->vertex[0].x;
-  int i = poly_config_num_vertex;
-  src += i * 3;
-  do {
-    src -= 3, i -= 1;
-    poly_fromlut_x = src[2];
-    poly_fromlut_y = src[1];
-    poly_fromlut_z = src[0];
-    Polyhedral_RotatePoint();
-    Polyhedral_ProjectPoint();
-    poly_arr_x[i] = poly_base_x + poly_f0;
-    poly_arr_y[i] = poly_base_y - poly_f1;
-  } while (i);
-}
-
-void Polyhedral_RotatePoint() {  // 89f931
-  int x = (int8)poly_fromlut_x;
-  int y = (int8)poly_fromlut_y;
-  int z = (int8)poly_fromlut_z;
-
-  poly_f0 =   (int16)poly_cos_b * z                         - (int16)poly_sin_b * x;
-  poly_f1 =   (int16)poly_e0    * z + (int16)poly_cos_a * y + (int16)poly_e2    * x;
-  poly_f2 = ((int16)poly_e3 * z >> 8) - ((int16)poly_sin_a * y >> 8) + ((int16)poly_e1 * x >> 8) + poly_var1;
-}
-
-void Polyhedral_ProjectPoint() {  // 89f9d6
-  poly_f0 = Poly_Divide(poly_f0, poly_f2);
-  poly_f1 = Poly_Divide(poly_f1, poly_f2);
-}
-
-void Polyhedral_DrawPolyhedron() {  // 89fa4f
-  const PolyConfig *poly_config = &kPolyConfigs[poly_which_model];
-  const uint8 *src = poly_config->poly;
-  do {
-    poly_num_vertex_in_poly = *src++;
-    BYTE(poly_tmp0) = poly_num_vertex_in_poly;
-    poly_xy_coords[0] = poly_num_vertex_in_poly * 2;
-
-    int i = 1;
-    do {
-      int j = *src++;
-      poly_xy_coords[i + 0] = poly_arr_x[j];
-      poly_xy_coords[i + 1] = poly_arr_y[j];
-      i += 2;
-    } while (--BYTE(poly_tmp0));
-
-    poly_raster_color_config = *src++;
-    int order = Polyhedral_CalculateCrossProduct();
-    if (order > 0) {
-      Polyhedral_SetForegroundColor();
-      Polyhedral_DrawFace();
-    }
-  } while (--poly_config_num_polys);
-}
-
-void Polyhedral_SetForegroundColor() {  // 89faca
-  uint8 t = poly_which_model ? (poly_config1 >> 5) : 0;
-  uint8 a = (poly_tmp0 << (t + 1)) >> 8;
-  Polyhedral_SetColorMask(a <= 1 ? 1 : a >= 7 ? 7 : a);
-}
-
-int16 Polyhedral_CalculateCrossProduct() {  // 89fb24
-  int16 a = poly_xy_coords[3] - poly_xy_coords[1];
-  poly_tmp0 = a * (int8)(poly_xy_coords[6] - poly_xy_coords[4]);
-  a = poly_xy_coords[5] - poly_xy_coords[3];
-  poly_tmp0 -= a * (int8)(poly_xy_coords[4] - poly_xy_coords[2]);
-  return poly_tmp0;
-}
-
-void Polyhedral_SetColorMask(int c) {  // 89fcae
-  uint32 v = kPoly_RasterColors[c];
-  poly_raster_color0 = v;
-  poly_raster_color1 = v >> 16;
-}
-
-void Polyhedral_EmptyBitMapBuffer() {  // 89fd04
-  memset(polyhedral_buffer, 0, 0x800);
-}
-
-void Polyhedral_DrawFace() {  // 89fd1e
-  int n = poly_xy_coords[0];
-  uint8 min_y = poly_xy_coords[n];
-  int min_idx = n;
-  while (n -= 2) {
-    if (poly_xy_coords[n] < min_y)
-      min_y = poly_xy_coords[n], min_idx = n;
-  }
-  poly_raster_dst_ptr = 0xe800 + (((min_y & 0x38) ^ (min_y & 0x20 ? 0x24 : 0)) << 6) + (min_y & 7) * 2;
-  poly_cur_vertex_idx0 = poly_cur_vertex_idx1 = min_idx;
-  poly_total_num_steps = poly_xy_coords[0] >> 1;
-  poly_y0_cur = poly_y1_cur = poly_xy_coords[min_idx];
-  poly_x0_cur = poly_x1_cur = poly_xy_coords[min_idx - 1];
-  if (Polyhedral_SetLeft() || Polyhedral_SetRight())
-    return;
-  for (;;) {
-    Polyhedral_FillLine();
-    if (BYTE(poly_raster_dst_ptr) != 0xe) {
-      poly_raster_dst_ptr += 2;
-    } else {
-      uint8 a = HIBYTE(poly_raster_dst_ptr) + 2;
-      poly_raster_dst_ptr = (a ^ ((a & 8) ? 0 : 0x19)) << 8;
-    }
-    if (poly_y0_cur == poly_y0_trig) {
-      poly_x0_cur = poly_x0_target;
-      if (Polyhedral_SetLeft())
-        return;
-    }
-    poly_y0_cur++;
-    if (poly_y1_cur == poly_y1_trig) {
-      poly_x1_cur = poly_x1_target;
-      if (Polyhedral_SetRight())
-        return;
-    }
-    poly_y1_cur++;
-    poly_x0_frac += poly_x0_step;
-    poly_x1_frac += poly_x1_step;
-  }
-}
-
-void Polyhedral_FillLine() {  // 89fdcf
-  uint16 left = kPoly_LeftSideMask[(poly_x0_frac >> 8) & 7];
-  uint16 right = kPoly_RightSideMask[(poly_x1_frac >> 8) & 7];
-  poly_tmp2 = (poly_x0_frac >> 8) & 0x38;
-  int d0 = ((poly_x1_frac >> 8) & 0x38);
-  uint16 *ptr = (uint16*)&g_ram[poly_raster_dst_ptr + d0 * 4];
-  if ((d0 -= poly_tmp2) == 0) {
-    poly_tmp1 = left & right;
-    ptr[0] ^= (ptr[0] ^ poly_raster_color0) & poly_tmp1;
-    ptr[8] ^= (ptr[8] ^ poly_raster_color1) & poly_tmp1;
-    return;
-  }
-  if (d0 < 0)
-    return;
-  int n = d0 >> 3;
-  ptr[0] ^= (ptr[0] ^ poly_raster_color0) & right;
-  ptr[8] ^= (ptr[8] ^ poly_raster_color1) & right;
-  ptr -= 0x10;
-  while (--n) {
-    ptr[0] = poly_raster_color0;
-    ptr[8] = poly_raster_color1;
-    ptr -= 0x10;
-  }
-  ptr[0] ^= (ptr[0] ^ poly_raster_color0) & left;
-  ptr[8] ^= (ptr[8] ^ poly_raster_color1) & left;
-  poly_tmp1 = left, poly_raster_numfull = 0;
-}
-
-bool Polyhedral_SetLeft() {  // 89feb4
-  int i;
-  for (;;) {
-    if (sign8(--poly_total_num_steps))
-      return true;
-    i = poly_cur_vertex_idx0 - 2;
-    if (i == 0)
-      i = poly_xy_coords[0];
-    if (poly_xy_coords[i] < poly_y0_cur)
-      return true;
-    if (poly_xy_coords[i] != poly_y0_cur)
-      break;
-    poly_x0_cur = poly_xy_coords[i - 1];
-    poly_cur_vertex_idx0 = i;
-  }
-  poly_y0_trig = poly_xy_coords[i];
-  poly_x0_target = poly_xy_coords[i - 1];
-  poly_cur_vertex_idx0 = i;
-  int t = poly_x0_target - poly_x0_cur, u = t;
-  if (t < 0)
-    t = -t;
-  t = ((t & 0xff) << 8) / (uint8)(poly_y0_trig - poly_y0_cur);
-  poly_x0_frac = (poly_x0_cur << 8) | 0x80;
-  poly_x0_step = (u < 0) ? -t : t;
-  return false;
-}
-
-bool Polyhedral_SetRight() {  // 89ff1e
-  int i;
-  for (;;) {
-    if (sign8(--poly_total_num_steps))
-      return true;
-    i = poly_cur_vertex_idx1;
-    if (i == poly_xy_coords[0])
-      i = 0;
-    i += 2;
-    if (poly_xy_coords[i] < poly_y1_cur)
-      return true;
-    if (poly_xy_coords[i] != poly_y1_cur)
-      break;
-    poly_x1_cur = poly_xy_coords[i - 1];
-    poly_cur_vertex_idx1 = i;
-  }
-  poly_y1_trig = poly_xy_coords[i];
-  poly_x1_target = poly_xy_coords[i - 1];
-  poly_cur_vertex_idx1 = i;
-  int t = poly_x1_target - poly_x1_cur, u = t;
-  if (t < 0)
-    t = -t;
-  t = ((t & 0xff) << 8) / (uint8)(poly_y1_trig - poly_y1_cur);
-  poly_x1_frac = (poly_x1_cur << 8) | 0x80;
-  poly_x1_step = (u < 0) ? -t : t;
-  return false;
-}
-
--- a/poly.h
+++ /dev/null
@@ -1,19 +1,0 @@
-#pragma once
-#include "types.h"
-
-uint16 Poly_Divide(uint16 a, uint16 b);
-void Poly_RunFrame();
-void Polyhedral_SetShapePointer();
-void Polyhedral_SetRotationMatrix();
-void Polyhedral_OperateRotation();
-void Polyhedral_RotatePoint();
-void Polyhedral_ProjectPoint();
-void Polyhedral_DrawPolyhedron();
-void Polyhedral_SetForegroundColor();
-int16 Polyhedral_CalculateCrossProduct();
-void Polyhedral_SetColorMask(int c);
-void Polyhedral_EmptyBitMapBuffer();
-void Polyhedral_DrawFace();
-void Polyhedral_FillLine();
-bool Polyhedral_SetLeft();
-bool Polyhedral_SetRight();
--- a/run_with_tcc.bat
+++ b/run_with_tcc.bat
@@ -25,9 +25,9 @@
   REM
 )
 
-IF NOT EXIST "tables\zelda3_assets.dat" (
+IF NOT EXIST "zelda3_assets.dat" (
   ECHO:
-  ECHO ERROR: tables\zelda3_assets.dat was not found.
+  ECHO ERROR: zelda3_assets.dat was not found.
   ECHO You need to extract assets from the ROM first, or get this file from a friend. Please see README.md
   ECHO:
   PAUSE
@@ -38,7 +38,7 @@
 
 
 echo Building with TCC...
-third_party\tcc\tcc.exe -ozelda3.exe -DCOMPILER_TCC=1 -DSTBI_NO_SIMD=1 -DHAVE_STDINT_H=1 -D_HAVE_STDINT_H=1 -DSYSTEM_VOLUME_MIXER_AVAILABLE=0 -I%SDL2%/include -L%SDL2%/lib/x64 -lSDL2 *.c snes/*.c third_party/gl_core/gl_core_3_1.c third_party/opus-1.3.1-stripped/opus_decoder_amalgam.c
+third_party\tcc\tcc.exe -ozelda3.exe -DCOMPILER_TCC=1 -DSTBI_NO_SIMD=1 -DHAVE_STDINT_H=1 -D_HAVE_STDINT_H=1 -DSYSTEM_VOLUME_MIXER_AVAILABLE=0 -I%SDL2%/include -L%SDL2%/lib/x64 -lSDL2 -I. src/*.c snes/*.c third_party/gl_core/gl_core_3_1.c third_party/opus-1.3.1-stripped/opus_decoder_amalgam.c
 IF ERRORLEVEL 1 goto GETOUT
 
 copy %SDL2%\lib\x64\SDL2.dll .
--- a/select_file.c
+++ /dev/null
@@ -1,929 +1,0 @@
-#include "zelda_rtl.h"
-#include "variables.h"
-#include "load_gfx.h"
-#include "select_file.h"
-#include "snes/snes_regs.h"
-#include "overworld.h"
-#include "messaging.h"
-#include "sprite.h"
-
-#define selectfile_R16 g_ram[0xc8]
-#define selectfile_R17 g_ram[0xc9]
-#define selectfile_R18 WORD(g_ram[0xca])
-#define selectfile_R20 WORD(g_ram[0xcc])
-static const uint8 kSelectFile_Draw_Y[3] = {0x43, 0x63, 0x83};
-bool Intro_CheckCksum(const uint8 *s) {
-  const uint16 *src = (const uint16 *)s;
-  uint16 sum = 0;
-  for (int i = 0; i < 0x280; i++)
-    sum += src[i];
-  return sum == 0x5a5a;
-
-}
-
-uint16 *SelectFile_Func1() {
-  static const uint16 kSelectFile_Func1_Tab[4] = {0x3581, 0x3582, 0x3591, 0x3592};
-  uint16 *dst = (uint16 *)&g_ram[0x1002];
-  *dst++ = 0x10;
-  *dst++ = 0xff07;
-  for (int i = 0; i < 1024; i++)
-    *dst++ = kSelectFile_Func1_Tab[((i & 0x20) >> 4) + (i & 1)];
-  return dst;
-}
-
-void SelectFile_Func5_DrawOams(int k) {
-  static const uint8 kSelectFile_Draw_OamIdx[3] = {0x28, 0x3c, 0x50};
-  static const uint8 kSelectFile_Draw_SwordChar[4] = {0x85, 0xa1, 0xa1, 0xa1};
-  static const uint8 kSelectFile_Draw_ShieldChar[3] = {0xc4, 0xca, 0xe0};
-  static const uint8 kSelectFile_Draw_Flags[3] = {0x72, 0x76, 0x7a};
-  static const uint8 kSelectFile_Draw_Flags2[3] = {0x32, 0x36, 0x3a};
-  static const uint8 kSelectFile_Draw_Flags3[3] = {0x30, 0x34, 0x38};
-
-  link_dma_graphics_index = 0x116 * 2;
-  uint8 *sram = g_zenv.sram + 0x500 * k;
-
-  OamEnt *oam = oam_buf + kSelectFile_Draw_OamIdx[k] / 4;
-  uint8 x = 0x34;
-  uint8 y = kSelectFile_Draw_Y[k];
-
-  uint8 sword = sram[kSrmOffs_Sword] - 1;
-  uint8 swordchar = kSelectFile_Draw_SwordChar[sign8(sword) ? 0 : sword];
-  SetOamPlain(oam + 0, x + 0xc, y - 5, swordchar, kSelectFile_Draw_Flags[k], 0);
-  SetOamPlain(oam + 1, x + 0xc, y + 3, swordchar + 16, kSelectFile_Draw_Flags[k], 0);
-  if (sign8(sword))
-    oam[1].y = oam[0].y = 0xf0;
-  uint8 shield = sram[kSrmOffs_Shield] - 1;
-  SetOamPlain(oam + 2, x - 5, y + 10, kSelectFile_Draw_ShieldChar[sign8(shield) ? 0 : shield], kSelectFile_Draw_Flags2[k], 2);
-  if (sign8(shield))
-    oam[2].y = 0xf0;
-  SetOamPlain(oam + 3, x, y + 0, 0, kSelectFile_Draw_Flags3[k], 2);
-  SetOamPlain(oam + 4, x, y + 8, 2, kSelectFile_Draw_Flags3[k] | 0x40, 2);
-}
-
-void SelectFile_Func6_DrawOams2(int k) {
-  static const uint8 kSelectFile_DrawDigit_Char[10] = {0xd0, 0xac, 0xad, 0xbc, 0xbd, 0xae, 0xaf, 0xbe, 0xbf, 0xc0};
-  static const int8 kSelectFile_DrawDigit_OamIdx[3] = {4, 16, 28};
-  static const int8 kSelectFile_DrawDigit_X[3] = {12, 4, -4};
-
-  uint8 *sram = g_zenv.sram + 0x500 * k;
-  uint8 x = 0x34;
-  uint8 y = kSelectFile_Draw_Y[k];
-
-  int died_ctr = WORD(sram[kSrmOffs_DiedCounter]);
-  if (died_ctr == 0xffff)
-    return;
-
-  if (died_ctr > 999)
-    died_ctr = 999;
-
-  uint8 digits[3];
-  digits[2] = died_ctr / 100;
-  died_ctr %= 100;
-  digits[1] = died_ctr / 10;
-  digits[0] = died_ctr % 10;
-
-  int i = (digits[2] != 0) ? 2 : (digits[1] != 0) ? 1 : 0;
-  OamEnt *oam = oam_buf + kSelectFile_DrawDigit_OamIdx[k] / 4;
-  do {
-    SetOamPlain(oam, x + kSelectFile_DrawDigit_X[i], y + 0x10, kSelectFile_DrawDigit_Char[digits[i]], 0x3c, 0);
-  } while (oam++, --i >= 0);
-}
-
-void SelectFile_Func17(int k) {
-  static const uint16 kSelectFile_DrawName_VramOffs[3] = {8, 0x5c, 0xb0};
-  static const uint16 kSelectFile_DrawName_HealthVramOffs[3] = {0x16, 0x6a, 0xbe};
-  uint8 *sram = g_zenv.sram + 0x500 * k;
-  uint16 *name = (uint16 *)(sram + kSrmOffs_Name);
-  uint16 *dst = vram_upload_data + kSelectFile_DrawName_VramOffs[k] / 2;
-  for (int i = 5; i >= 0; i--) {
-    uint16 t = *name++ + 0x1800;
-    dst[0] = t;
-    dst[21] = t + 0x10;
-    dst++;
-  }
-  int health = sram[kSrmOffs_Health] >> 3;
-  dst = vram_upload_data + kSelectFile_DrawName_HealthVramOffs[k] / 2;
-  uint16 *dst_org = dst;
-  int row = 10;
-  do {
-    *dst++ = 0x520;
-    if (--row == 0)
-      dst = dst_org + 21;
-  } while (--health);
-}
-
-void SelectFile_Func16() {
-  static const uint8 kSelectFile_Func16_FaerieY[2] = {175, 191};
-  FileSelect_DrawFairy(0x1c, kSelectFile_Func16_FaerieY[selectfile_R16]);
-
-  int k = selectfile_R16;
-  if (filtered_joypad_H & 0x2c) {
-    k += (filtered_joypad_H & 0x24) ? 1 : -1;
-    selectfile_R16 = k & 1;
-    sound_effect_2 = 0x20;
-  }
-
-  uint8 a = (filtered_joypad_L & 0xc0 | filtered_joypad_H) & 0xd0;
-  if (a != 0) {
-    sound_effect_1 = 0x2c;
-    if (selectfile_R16 == 0) {
-      sound_effect_2 = 0x22;
-      sound_effect_1 = 0x0;
-      int k = subsubmodule_index;
-      selectfile_arr1[k] = 0;
-      memset(g_zenv.sram + k * 0x500, 0, 0x500);
-      memset(g_zenv.sram + k * 0x500 + 0xf00, 0, 0x500);
-      ZeldaWriteSram();
-    }
-    ReturnToFileSelect();
-    subsubmodule_index = 0;
-  }
-}
-
-void Module_NamePlayer_1() {
-  uint16 *dst = SelectFile_Func1();
-  dst[0] = 0xffff;
-  nmi_load_bg_from_vram = 1;
-  submodule_index++;
-}
-
-void Module_NamePlayer_2() {
-  nmi_load_bg_from_vram = 5;
-  submodule_index++;
-  INIDISP_copy = 15;
-  nmi_disable_core_updates = 0;
-}
-
-void Intro_FixCksum(uint8 *s) {
-  uint16 *src = (uint16 *)s;
-  uint16 sum = 0;
-  for (int i = 0; i < 0x27f; i++)
-    sum += src[i];
-  src[0x27f] = 0x5a5a - sum;
-}
-
-void LoadFileSelectGraphics() {  // 80e4e9
-  Decomp_spr(&g_ram[0x14000], 0x5e);
-  Do3To4High(&g_zenv.vram[0x5000], &g_ram[0x14000]);
-
-  Decomp_spr(&g_ram[0x14000], 0x5f);
-  Do3To4High(&g_zenv.vram[0x5400], &g_ram[0x14000]);
-
-  TransferFontToVRAM();
-
-  Decomp_spr(&g_ram[0x14000], 0x6b);
-  memcpy(&g_zenv.vram[0x7800], &g_ram[0x14000], 0x300 * sizeof(uint16));
-}
-
-void Intro_ValidateSram() {  // 828054
-  uint8 *cart = g_zenv.sram;
-  for (int i = 0; i < 3; i++) {
-    uint8 *c = cart + i * 0x500;
-    if (!Intro_CheckCksum(c)) {
-      if (Intro_CheckCksum(c + 0xf00)) {
-        memcpy(c, c + 0xf00, 0x500);
-      } else {
-        memset(c, 0, 0x500);
-        memset(c + 0xf00, 0, 0x500);
-      }
-    }
-  }
-  memset(&g_ram[0xd00], 0, 256 * 3);
-}
-
-void Module01_FileSelect() {  // 8ccd7d
-  BG3HOFS_copy2 = 0;
-  BG3VOFS_copy2 = 0;
-  switch (submodule_index) {
-  case 0: Module_SelectFile_0(); break;
-  case 1: FileSelect_ReInitSaveFlagsAndEraseTriforce(); break;
-  case 2: Module_EraseFile_1(); break;
-  case 3: FileSelect_TriggerStripesAndAdvance(); break;
-  case 4: FileSelect_TriggerNameStripesAndAdvance(); break;
-  case 5: FileSelect_Main(); break;
-  }
-}
-
-void Module_SelectFile_0() {  // 8ccd9d
-  EnableForceBlank();
-  is_nmi_thread_active = 0;
-  nmi_flag_update_polyhedral = 0;
-  music_control = 11;
-  submodule_index++;
-  overworld_palette_aux_or_main = 0x200;
-  palette_main_indoors = 6;
-  nmi_disable_core_updates = 6;
-  Palette_Load_DungeonSet();
-  Palette_Load_OWBG3();
-  hud_palette = 0;
-  Palette_Load_HUD();
-  hud_cur_item = 0;
-  misc_sprites_graphics_index = 1;
-  main_tile_theme_index = 35;
-  aux_tile_theme_index = 81;
-  LoadDefaultGraphics();
-  InitializeTilesets();
-  LoadFileSelectGraphics();
-  Intro_ValidateSram();
-  DecompressEnemyDamageSubclasses();
-}
-
-void FileSelect_ReInitSaveFlagsAndEraseTriforce() {  // 8ccdf2
-  memset(selectfile_arr1, 0, 6);
-  FileSelect_EraseTriforce();
-}
-
-void FileSelect_EraseTriforce() {  // 8ccdf9
-  nmi_disable_core_updates = 128;
-  EnableForceBlank();
-  EraseTileMaps_triforce();
-  Palette_LoadForFileSelect();
-  flag_update_cgram_in_nmi++;
-  submodule_index++;
-}
-
-void Module_EraseFile_1() {  // 8cce53
-  static const uint8 kSelectFile_Gfx0[224] = {
-    0x10, 0x42,    0, 0x27, 0x89, 0x35, 0x8a, 0x35, 0x8b, 0x35, 0x8c, 0x35, 0x8b, 0x35, 0x8c, 0x35,
-    0x8b, 0x35, 0x8c, 0x35, 0x8b, 0x35, 0x8c, 0x35, 0x8b, 0x35, 0x8c, 0x35, 0x8b, 0x35, 0x8c, 0x35,
-    0x8b, 0x35, 0x8c, 0x35, 0x8b, 0x35, 0x8c, 0x35, 0x8a, 0x75, 0x89, 0x75, 0x10, 0x62,    0,    3,
-    0x99, 0x35, 0x9a, 0x35, 0x10, 0x64, 0x40, 0x1e, 0x7f, 0x34, 0x10, 0x74,    0,    3, 0x9a, 0x75,
-    0x99, 0x75, 0x10, 0x82,    0,    3, 0xa9, 0x35, 0xaa, 0x35, 0x10, 0x84, 0x40, 0x1e, 0x7f, 0x34,
-    0x10, 0x94,    0,    3, 0xaa, 0x75, 0xa9, 0x75, 0x10, 0xa2,    0, 0x27, 0x9d, 0x35, 0xad, 0x35,
-    0x9b, 0x35, 0x9c, 0x35, 0x9b, 0x35, 0x9c, 0x35, 0x9b, 0x35, 0x9c, 0x35, 0x9b, 0x35, 0x9c, 0x35,
-    0x9b, 0x35, 0x9c, 0x35, 0x9b, 0x35, 0x9c, 0x35, 0x9b, 0x35, 0x9c, 0x35, 0x9b, 0x35, 0x9c, 0x35,
-    0xad, 0x75, 0x9d, 0x75, 0x10, 0xc2,    0, 0x27, 0xab, 0x35, 0xac, 0x35, 0xab, 0x35, 0xac, 0x35,
-    0xab, 0x35, 0xac, 0x35, 0xab, 0x35, 0xac, 0x35, 0xab, 0x35, 0xac, 0x35, 0xab, 0x35, 0xac, 0x35,
-    0xab, 0x35, 0xac, 0x35, 0xab, 0x35, 0xac, 0x35, 0xab, 0x35, 0xac, 0x35, 0xab, 0x75, 0xac, 0x75,
-    0x10, 0xe2,    0,    1, 0x83, 0x35, 0x10, 0xe3, 0x40, 0x32, 0x85, 0x35, 0x10, 0xfd,    0,    1,
-    0x84, 0x35, 0x11,    2, 0xc0, 0x22, 0x86, 0x35, 0x11, 0x1d, 0xc0, 0x22, 0x96, 0x35, 0x13, 0x42,
-       0,    1, 0x93, 0x35, 0x13, 0x43, 0x40, 0x32, 0x95, 0x35, 0x13, 0x5d,    0,    1, 0x94, 0x35,
-  };
-  uint16 *dst = SelectFile_Func1();
-  memcpy(dst, kSelectFile_Gfx0, 224);
-  dst += 224 / 2;
-  uint16 t = 0x1103;
-  for (int i = 17; i >= 0; i--) {
-    *dst++ = swap16(t);
-    t += 0x20;
-    *dst++ = 0x3240;
-    *dst++ = 0x347f;
-  }
-  *(uint8 *)dst = 0xff;
-  submodule_index++;
-  nmi_load_bg_from_vram = 1;
-}
-
-void FileSelect_TriggerStripesAndAdvance() {  // 8ccea5
-  selectfile_R16 = selectfile_var2;
-  submodule_index++;
-  nmi_load_bg_from_vram = 6;
-}
-
-void FileSelect_TriggerNameStripesAndAdvance() {  // 8cceb1
-  static const uint8 kSelectFile_Func3_Data[253] = {
-    0x61, 0x29,    0, 0x25, 0xe7, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18,
-    0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18,
-    0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0x61, 0x49,    0, 0x25, 0xf7, 0x18,
-    0x91, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18,
-    0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18,
-    0xa9, 0x18, 0xa9, 0x18, 0x61, 0xa9,    0, 0x25, 0xe8, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18,
-    0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18,
-    0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0x61, 0xc9,
-       0, 0x25, 0xf8, 0x18, 0x91, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18,
-    0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18,
-    0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0x62, 0x29,    0, 0x25, 0xe9, 0x18, 0xa9, 0x18,
-    0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18,
-    0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18,
-    0xa9, 0x18, 0x62, 0x49,    0, 0x25, 0xf9, 0x18, 0x91, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18,
-    0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18,
-    0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xff,
-  };
-  memcpy(vram_upload_data, kSelectFile_Func3_Data, 253);
-  INIDISP_copy = 0xf;
-  nmi_disable_core_updates = 0;
-  submodule_index++;
-  nmi_load_bg_from_vram = 6;
-}
-
-void FileSelect_Main() {  // 8ccebd
-  static const uint8 kSelectFile_Faerie_Y[5] = {0x4a, 0x6a, 0x8a, 0xaf, 0xbf};
-
-  const uint8 *cart = g_zenv.sram;
-
-  if (selectfile_R16 < 3)
-    selectfile_var2 = selectfile_R16;
-
-  for (int k = 0; k < 3; k++) {
-    if (*(uint16 *)(cart + k * 0x500 + 0x3E5) == 0x55AA) {
-      selectfile_arr1[k] = 1;
-      SelectFile_Func5_DrawOams(k);
-      SelectFile_Func6_DrawOams2(k);
-      SelectFile_Func17(k);
-    }
-  }
-
-  FileSelect_DrawFairy(0x1c, kSelectFile_Faerie_Y[selectfile_R16]);
-  nmi_load_bg_from_vram = 1;
-
-  uint8 a = (filtered_joypad_L & 0xc0 | filtered_joypad_H) & 0xfc;
-  if (a & 0x2c) {
-    if (a & 8) {
-      sound_effect_2 = 0x20;
-      if (sign8(--selectfile_R16))
-        selectfile_R16 = 4;
-    } else {
-      sound_effect_2 = 0x20;
-      if (++selectfile_R16 == 5)
-        selectfile_R16 = 0;
-    }
-  } else if (a != 0) {
-    sound_effect_1 = 0x2c;
-    if (selectfile_R16 < 3) {
-      selectfile_R17 = 0;
-      if (!selectfile_arr1[selectfile_R16]) {
-        main_module_index = 4;
-        submodule_index = 0;
-        subsubmodule_index = 0;
-      } else {
-        music_control = 0xf1;
-        srm_var1 = selectfile_R16 * 2 + 2;
-        WORD(g_ram[0]) = selectfile_R16 * 0x500;
-        CopySaveToWRAM();
-      }
-    } else if (selectfile_arr1[0] | selectfile_arr1[1] | selectfile_arr1[2]) {
-      main_module_index = (selectfile_R16 == 3) ? 2 : 3;
-      selectfile_R16 = 0;
-      submodule_index = 0;
-      subsubmodule_index = 0;
-    } else {
-      sound_effect_1 = 0x3c;
-    }
-  }
-}
-
-void Module02_CopyFile() {  // 8cd053
-  selectfile_var2 = 0;
-  switch (submodule_index) {
-  case 0: FileSelect_EraseTriforce(); break;
-  case 1: Module_EraseFile_1(); break;
-  case 2: Module_CopyFile_2(); break;
-  case 3: CopyFile_ChooseSelection(); break;
-  case 4: CopyFile_ChooseTarget(); break;
-  case 5: CopyFile_ConfirmSelection(); break;
-  }
-}
-
-void Module_CopyFile_2() {  // 8cd06e
-  nmi_load_bg_from_vram = 7;
-  submodule_index++;
-  INIDISP_copy = 0xf;
-  nmi_disable_core_updates = 0;
-  int i = 0;
-  for (; selectfile_arr1[i] == 0; i++) {}
-  selectfile_R16 = i;
-}
-
-void CopyFile_ChooseSelection() {  // 8cd087
-  CopyFile_SelectionAndBlinker();
-  if (submodule_index == 3 && !(frame_counter & 0x30))
-    FilePicker_DeleteHeaderStripe();
-  nmi_load_bg_from_vram = 1;
-}
-
-void CopyFile_ChooseTarget() {  // 8cd0a2
-  CopyFile_TargetSelectionAndBlink();
-  if (submodule_index == 4 && !(frame_counter & 0x30))
-    FilePicker_DeleteHeaderStripe();
-  nmi_load_bg_from_vram = 1;
-}
-
-void CopyFile_ConfirmSelection() {  // 8cd0b9
-  CopyFile_HandleConfirmation();
-  nmi_load_bg_from_vram = 1;
-}
-
-void FilePicker_DeleteHeaderStripe() {  // 8cd0c6
-  static const uint16 kFilePicker_DeleteHeaderStripe_Dst[2] = {4, 0x1e};
-  for (int j = 1; j >= 0; j--) {
-    uint16 *dst = vram_upload_data + kFilePicker_DeleteHeaderStripe_Dst[j] / 2;
-    for (int i = 0; i != 11; i++)
-      dst[i] = 0xa9;
-  }
-}
-
-void CopyFile_SelectionAndBlinker() {  // 8cd13f
-  static const uint8 kCopyFile_SelectionAndBlinker_Tab[173] = {
-    0x61,    4,    0, 0x15, 0x85, 0x18, 0x26, 0x18,    7, 0x18, 0xaf, 0x18,    2, 0x18,    7, 0x18,
-    0x6f, 0x18, 0x86, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0x61, 0x24,    0, 0x15, 0x95, 0x18,
-    0x36, 0x18, 0x17, 0x18, 0xbf, 0x18, 0x12, 0x18, 0x17, 0x18, 0x7f, 0x18, 0x96, 0x18, 0xa9, 0x18,
-    0xa9, 0x18, 0xa9, 0x18, 0x61, 0x67,    0,  0xf, 0xe7, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18,
-    0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0x61, 0x87,    0,  0xf, 0xf7, 0x18, 0x91, 0x18,
-    0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0x61, 0xc7,    0,  0xf,
-    0xe8, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18,
-    0x61, 0xe7,    0,  0xf, 0xf8, 0x18, 0x91, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18,
-    0xa9, 0x18, 0xa9, 0x18, 0x62, 0x27,    0,  0xf, 0xe9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18,
-    0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0x62, 0x47,    0,  0xf, 0xf9, 0x18, 0x91, 0x18,
-    0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xff,
-  };
-  static const uint8 kCopyFile_SelectionAndBlinker_Tab1[73] = {
-    0x61, 0x67, 0x40,  0xe, 0xa9,    0, 0x61, 0x87, 0x40,  0xe, 0xa9,    0, 0x61, 0xc7, 0x40,  0xe,
-    0xa9,    0, 0x61, 0xe7, 0x40,  0xe, 0xa9,    0, 0x11, 0x30,    0,    1, 0x83, 0x35, 0x11, 0x31,
-    0x40, 0x14, 0x85, 0x35, 0x11, 0x3c,    0,    1, 0x84, 0x35, 0x11, 0x50, 0xc0,  0xe, 0x86, 0x35,
-    0x11, 0x5c, 0xc0,  0xe, 0x96, 0x35, 0x12, 0x50,    0,    1, 0x93, 0x35, 0x12, 0x51, 0x40, 0x14,
-    0x95, 0x35, 0x12, 0x5c,    0,    1, 0x94, 0x35, 0xff,
-  };
-  static const uint16 kCopyFile_SelectionAndBlinker_Dst[3] = {0x3c, 0x64, 0x8c};
-  static const uint8 kCopyFile_SelectionAndBlinker_FaerieX[4] = {36, 36, 36, 28};
-  static const uint8 kCopyFile_SelectionAndBlinker_FaerieY[4] = {87, 111, 135, 191};
-
-  vram_upload_offset = 0xac;
-  memcpy(vram_upload_data, kCopyFile_SelectionAndBlinker_Tab, 173);
-
-  for (int k = 0; k != 3; k++) {
-    if (selectfile_arr1[k] & 1) {
-      const uint16 *name = (uint16 *)(g_zenv.sram + 0x500 * k + kSrmOffs_Name);
-      uint16 *dst = vram_upload_data + kCopyFile_SelectionAndBlinker_Dst[k] / 2;
-      for (int i = 0; i != 6; i++) {
-        uint16 t = *name++ + 0x1800;
-        dst[0] = t;
-        dst[10] = t + 0x10;
-        dst++;
-      }
-    }
-  }
-  FileSelect_DrawFairy(kCopyFile_SelectionAndBlinker_FaerieX[selectfile_R16], kCopyFile_SelectionAndBlinker_FaerieY[selectfile_R16]);
-
-  uint8 a = (filtered_joypad_L & 0xc0 | filtered_joypad_H) & 0xfc;
-  if (a & 0x2c) {
-    uint8 k = selectfile_R16;
-    if (a & 8) {
-      do {
-        if (--k < 0) {
-          k = 3;
-          break;
-        }
-      } while (!selectfile_arr1[k]);
-    } else {
-      do {
-        k++;
-        if (k >= 4)
-          k = 0;
-      } while (k != 3 && !selectfile_arr1[k]);
-    }
-    selectfile_R16 = k;
-    sound_effect_2 = 0x20;
-  } else if (a != 0) {
-    sound_effect_1 = 0x2c;
-    if (selectfile_R16 == 3) {
-      ReturnToFileSelect();
-      return;
-    }
-    selectfile_R20 = selectfile_R16 * 2;
-    memcpy(vram_upload_data + 26, kCopyFile_SelectionAndBlinker_Tab1, 73);
-    if (selectfile_R16 != 2) {
-      uint16 *dst = vram_upload_data + selectfile_R16 * 6;
-      dst[26] = 0x2762;
-      dst[29] = 0x4762;
-    }
-    submodule_index++;
-    selectfile_R16 = 0;
-  }
-}
-
-void ReturnToFileSelect() {  // 8cd22d
-  main_module_index = 1;
-  submodule_index = 1;
-  subsubmodule_index = 0;
-  selectfile_R16 = 0;
-}
-
-void CopyFile_TargetSelectionAndBlink() {  // 8cd27b
-  {
-    int k = 1, t = 4;
-    do {
-      if (t != selectfile_R20)
-        selectfile_arr2[k--] = t;
-    } while ((t -= 2) >= 0);
-  }
-
-  static const uint8 kCopyFile_TargetSelectionAndBlink_Tab0[133] = {
-    0x61, 0x51,    0, 0x15, 0x85, 0x18, 0x23, 0x18,  0xe, 0x18, 0xa9, 0x18, 0x26, 0x18,    7, 0x18,
-    0xaf, 0x18,    2, 0x18,    7, 0x18, 0x6f, 0x18, 0x86, 0x18, 0x61, 0x71,    0, 0x15, 0x95, 0x18,
-    0x33, 0x18, 0x1e, 0x18, 0xb9, 0x18, 0x36, 0x18, 0x17, 0x18, 0xbf, 0x18, 0x12, 0x18, 0x17, 0x18,
-    0x7f, 0x18, 0x96, 0x18, 0x61, 0xb4,    0,  0xf, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18,
-    0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0x61, 0xd4,    0,  0xf, 0xa9, 0x18, 0x91, 0x18,
-    0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0x62, 0x14,    0,  0xf,
-    0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18,
-    0x62, 0x34,    0,  0xf, 0xa9, 0x18, 0x91, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18,
-    0xa9, 0x18, 0xa9, 0x18, 0xff,
-  };
-  static const uint8 kCopyFile_TargetSelectionAndBlink_Tab2[49] = {
-    0x61, 0xb4, 0x40,  0xe, 0xa9,    0, 0x61, 0xd4, 0x40,  0xe, 0xa9,    0, 0x62, 0xc6,    0,  0xd,
-       2, 0x18,  0xe, 0x18,  0xf, 0x18, 0x28, 0x18, 0xa9, 0x18,  0xe, 0x18,  0xa, 0x18, 0x62, 0xe6,
-       0,  0xd, 0x12, 0x18, 0x1e, 0x18, 0x1f, 0x18, 0x38, 0x18, 0xa9, 0x18, 0x1e, 0x18, 0x1a, 0x18,
-    0xff,
-  };
-  static const uint8 kCopyFile_TargetSelectionAndBlink_FaerieX[3] = {0x8c, 0x8c, 0x1c};
-  static const uint8 kCopyFile_TargetSelectionAndBlink_FaerieY[3] = {0x67, 0x7f, 0xbf};
-  static const uint16 kCopyFile_TargetSelectionAndBlink_Dst[2] = {0x38, 0x60};
-  static const uint16 kCopyFile_TargetSelectionAndBlink_Tab1[3] = {0x18e7, 0x18e8, 0x18e9};
-  memcpy(vram_upload_data, kCopyFile_TargetSelectionAndBlink_Tab0, 133);
-
-  for (int k = 0, j = 0; k != 3; k++) {
-    if (k * 2 == selectfile_R20)
-      continue;
-
-    uint16 *dst = vram_upload_data + kCopyFile_TargetSelectionAndBlink_Dst[j++] / 2;
-    uint16 t = kCopyFile_TargetSelectionAndBlink_Tab1[k];
-    dst[0] = t;
-    dst[10] = t + 0x10;
-    dst += 2;
-    if (selectfile_arr1[k]) {
-      const uint16 *name = (uint16 *)(g_zenv.sram + 0x500 * k + kSrmOffs_Name);
-      for (int i = 0; i != 6; i++) {
-        uint16 t = *name++ + 0x1800;
-        dst[0] = t;
-        dst[10] = t + 0x10;
-        dst++;
-      }
-    }
-  }
-
-  vram_upload_offset = 132;
-
-  FileSelect_DrawFairy(kCopyFile_TargetSelectionAndBlink_FaerieX[selectfile_R16], kCopyFile_TargetSelectionAndBlink_FaerieY[selectfile_R16]);
-
-  uint8 a = (filtered_joypad_L & 0xc0 | filtered_joypad_H) & 0xfc;
-  if (a & 0x2c) {
-    uint8 k = selectfile_R16;
-    if (a & 8) {
-      if (sign8(--k))
-        k = 2;
-    } else {
-      if (++k >= 3)
-        k = 0;
-    }
-    selectfile_R16 = k;
-    sound_effect_2 = 0x20;
-  } else if (a) {
-    sound_effect_1 = 0x2c;
-    if (selectfile_R16 == 2) {
-      ReturnToFileSelect();
-      selectfile_R16 = 0;
-      return;
-    }
-    selectfile_R18 = selectfile_arr2[selectfile_R16];
-    memcpy(vram_upload_data + 26, kCopyFile_TargetSelectionAndBlink_Tab2, 49);
-    if (selectfile_R16 == 0) {
-      uint16 *dst = vram_upload_data;
-      dst[26] = 0x1462;
-      dst[29] = 0x3462;
-    }
-    submodule_index++;
-    selectfile_R16 = 0;
-  }
-}
-
-void CopyFile_HandleConfirmation() {  // 8cd371
-  static const uint8 kCopyFile_HandleConfirmation_FaerieY[2] = {0xaf, 0xbf};
-  FileSelect_DrawFairy(0x1c, kCopyFile_HandleConfirmation_FaerieY[selectfile_R16]);
-
-  uint8 a = (filtered_joypad_L & 0xc0 | filtered_joypad_H) & 0xfc;
-  if (a & 0x2c) {
-    sound_effect_2 = 0x20;
-    if (a & 0x24) {
-      if (++selectfile_R16 >= 2)
-        selectfile_R16 = 0;
-    } else {
-      if (sign8(--selectfile_R16))
-        selectfile_R16 = 1;
-    }
-  } else if (a != 0) {
-    sound_effect_1 = 0x2c;
-    if (selectfile_R16 == 0) {
-      memcpy(g_zenv.sram + (selectfile_R18 >> 1) * 0x500, g_zenv.sram + (selectfile_R20 >> 1) * 0x500, 0x500);
-      selectfile_arr1[(selectfile_R18 >> 1)] = 1;
-      ZeldaWriteSram();
-    }
-    ReturnToFileSelect();
-    selectfile_R16 = 0;
-  }
-}
-
-void Module03_KILLFile() {  // 8cd485
-  switch (submodule_index) {
-  case 0: FileSelect_EraseTriforce(); break;
-  case 1: Module_EraseFile_1(); break;
-  case 2: KILLFile_SetUp(); break;
-  case 3: KILLFile_HandleSelection(); break;
-  case 4: KILLFile_HandleConfirmation(); break;
-  }
-}
-
-void KILLFile_SetUp() {  // 8cd49a
-  nmi_load_bg_from_vram = 8;
-  submodule_index++;
-  INIDISP_copy = 0xf;
-  nmi_disable_core_updates = 0;
-  int i = 0;
-  for (; selectfile_arr1[i] == 0; i++) {}
-  selectfile_R16 = i;
-}
-
-void KILLFile_HandleSelection() {  // 8cd49f
-  if (selectfile_R16 < 3)
-    selectfile_var2 = selectfile_R16;
-  KILLFile_ChooseTarget();
-  nmi_load_bg_from_vram = 1;
-}
-
-void KILLFile_HandleConfirmation() {  // 8cd4b1
-  SelectFile_Func16();
-  nmi_load_bg_from_vram = 1;
-}
-
-void KILLFile_ChooseTarget() {  // 8cd4ba
-  static const uint8 kKILLFile_ChooseTarget_Tab[253] = {
-    0x61, 0xa7,    0, 0x25, 0xe7, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18,
-    0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18,
-    0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0x61, 0xc7,    0, 0x25, 0xf7, 0x18,
-    0x91, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18,
-    0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18,
-    0xa9, 0x18, 0xa9, 0x18, 0x62,    7,    0, 0x25, 0xe8, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18,
-    0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18,
-    0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0x62, 0x27,
-       0, 0x25, 0xf8, 0x18, 0x91, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18,
-    0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18,
-    0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0x62, 0x67,    0, 0x25, 0xe9, 0x18, 0xa9, 0x18,
-    0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18,
-    0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18,
-    0xa9, 0x18, 0x62, 0x87,    0, 0x25, 0xf9, 0x18, 0x91, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18,
-    0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18,
-    0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xff,
-  };
-  static const uint8 kKILLFile_ChooseTarget_Tab2[101] = {
-    0x61, 0xa7, 0x40, 0x24, 0xa9,    0, 0x61, 0xc7, 0x40, 0x24, 0xa9,    0, 0x62,    7, 0x40, 0x24,
-    0xa9,    0, 0x62, 0x27, 0x40, 0x24, 0xa9,    0, 0x62, 0xc6,    0, 0x21,    4, 0x18, 0x21, 0x18,
-       0, 0x18, 0x22, 0x18,    4, 0x18, 0xa9, 0x18, 0x23, 0x18,    7, 0x18, 0xaf, 0x18, 0x22, 0x18,
-    0xa9, 0x18,  0xf, 0x18,  0xb, 0x18,    0, 0x18, 0x28, 0x18,    4, 0x18, 0x21, 0x18, 0x62, 0xe6,
-       0, 0x21, 0x14, 0x18, 0x31, 0x18, 0x10, 0x18, 0x32, 0x18, 0x14, 0x18, 0xa9, 0x18, 0x33, 0x18,
-    0x17, 0x18, 0xbf, 0x18, 0x32, 0x18, 0xa9, 0x18, 0x1f, 0x18, 0x1b, 0x18, 0x10, 0x18, 0x38, 0x18,
-    0x14, 0x18, 0x31, 0x18, 0xff,
-  };
-  static const uint8 kKILLFile_ChooseTarget_FaerieX[4] = {36, 36, 36, 28};
-  static const uint8 kKILLFile_ChooseTarget_FaerieY[4] = {103, 127, 151, 191};
-  memcpy(vram_upload_data, kKILLFile_ChooseTarget_Tab, 253);
-  for (int k = 0; k < 3; k++) {
-    if (selectfile_arr1[k])
-      SelectFile_Func17(k);
-  }
-
-  FileSelect_DrawFairy(kKILLFile_ChooseTarget_FaerieX[selectfile_R16], kKILLFile_ChooseTarget_FaerieY[selectfile_R16]);
-
-  int k = selectfile_R16;
-  if (filtered_joypad_H & 0x2c) {
-    if (!(filtered_joypad_H & 0x24)) {
-      do {
-        if (--k < 0) {
-          k = 3;
-          break;
-        }
-      } while (!selectfile_arr1[k]);
-    } else {
-      do {
-        k++;
-        if (k >= 4)
-          k = 0;
-      } while (k != 3 && !selectfile_arr1[k]);
-    }
-    sound_effect_2 = 0x20;
-  }
-  selectfile_R16 = k;
-
-  uint8 a = (filtered_joypad_L & 0xc0 | filtered_joypad_H) & 0xd0;
-  if (a) {
-    sound_effect_1 = 0x2c;
-    if (k == 3) {
-      ReturnToFileSelect();
-      return;
-    }
-
-    memcpy(vram_upload_data, kKILLFile_ChooseTarget_Tab2, 101);
-    submodule_index++;
-    if (selectfile_R16 != 2) {
-      uint16 *dst = vram_upload_data + selectfile_R16 * 6;
-      dst[0] = 0x6762;
-      dst[3] = 0x8762;
-    }
-    subsubmodule_index = selectfile_R16;
-    selectfile_R16 = 0;
-  }
-}
-
-void FileSelect_DrawFairy(uint8 x, uint8 y) {  // 8cd7a5
-  SetOamPlain(&oam_buf[0], x, y, frame_counter & 8 ? 0xaa : 0xa8, 0x7e, 2);
-}
-
-void Module04_NameFile() {  // 8cd88a
-  switch (submodule_index) {
-  case 0: NameFile_EraseSave(); break;
-  case 1: Module_NamePlayer_1(); break;
-  case 2: Module_NamePlayer_2(); break;
-  case 3: NameFile_DoTheNaming(); break;
-  }
-}
-
-void NameFile_EraseSave() {  // 8cd89c
-  FileSelect_EraseTriforce();
-  irq_flag = 1;
-  selectfile_var3 = 0;
-  selectfile_var4 = 0;
-  selectfile_var5 = 0;
-  selectfile_arr2[0] = 0;
-  selectfile_var6 = 0;
-  selectfile_var7 = 0x83;
-  selectfile_var8 = 0x1f0;
-  BG3HOFS_copy2 = 0;
-  int offs = selectfile_R16 * 0x500;
-  attract_legend_ctr = offs;
-  memset(g_zenv.sram + offs, 0, 0x500);
-  uint16 *name = (uint16 *)(g_zenv.sram + offs + kSrmOffs_Name);
-  name[0] = name[1] = name[2] = name[3] = name[4] = name[5] = 0xa9;
-}
-
-void NameFile_DoTheNaming() {  // 8cda4d
-  static const int16 kNamePlayer_Tab1[26] = {
-    -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1,
-    -2, 2, -2, 2, -2, 2, -2, 2, -4, 4,
-  };
-  static const uint8 kNamePlayer_Tab2[4] = {131, 147, 163, 179};
-  static const int8 kNamePlayer_X[6] = {31, 47, 63, 79, 95, 111};
-  static const int16 kNamePlayer_Tab0[32] = {
-    0x1f0,     0,  0x10,  0x20,  0x30,  0x40,  0x50,  0x60,  0x70,  0x80,  0x90,  0xa0,  0xb0,  0xc0,  0xd0,  0xe0,
-     0xf0, 0x100, 0x110, 0x120, 0x130, 0x140, 0x150, 0x160, 0x170, 0x180, 0x190, 0x1a0, 0x1b0, 0x1c0, 0x1d0, 0x1e0,
-  };
-  static const int8 kNamePlayer_Tab3[128] = {
-       6,    7, 0x5f,    9, 0x59, 0x59, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x60, 0x23,
-    0x59, 0x59, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x59, 0x59, 0x59,    0,    1,    2,    3,    4,    5,
-    0x10, 0x11, 0x12, 0x13, 0x59, 0x59, 0x24, 0x5f, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d,
-    0x59, 0x59, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x59, 0x59, 0x59,  0xa,  0xb,  0xc,  0xd,  0xe,  0xf,
-    0x40, 0x41, 0x42, 0x59, 0x59, 0x59, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x40, 0x41, 0x42, 0x59,
-    0x59, 0x59, 0x61, 0x3f, 0x45, 0x46, 0x59, 0x59, 0x59, 0x59, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19,
-    0x44, 0x59, 0x6f, 0x6f, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x5a, 0x44, 0x59, 0x6f, 0x6f,
-    0x59, 0x59, 0x5a, 0x44, 0x59, 0x6f, 0x6f, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x5a,
-  };
-  for (;;) {
-    int j = selectfile_var9;
-    if (j == 0) {
-      NameFile_CheckForScrollInputX();
-      break;
-    }
-    if (j != 0x31)
-      selectfile_var9 += 4;
-    j--;
-    if (kNamePlayer_Tab0[selectfile_var3] == selectfile_var8) {
-      selectfile_var9 = (joypad1H_last & 3) ? 0x30 : 0;
-      NameFile_CheckForScrollInputX();
-      continue;
-    }
-    if (!selectfile_var10)
-      j += 2;
-    selectfile_var8 = (selectfile_var8 + WORD(((uint8*)&kNamePlayer_Tab1)[j])) & 0x1ff;
-    break;
-  }
-
-  for (;;) {
-    if (selectfile_var11 == 0) {
-      NameFile_CheckForScrollInputY();
-      break;
-    }
-    uint8 diff = selectfile_var7 - kNamePlayer_Tab2[selectfile_var5];
-    if (diff != 0) {
-      selectfile_var7 += sign8(diff) ? 2 : -2;
-      break;
-    }
-    selectfile_var11 = 0;
-    NameFile_CheckForScrollInputY();
-  }
-
-  OamEnt *oam = oam_buf;
-  for (int i = 0; i != 26; i++) {
-    SetOamPlain(oam, 0x18 + i * 8, selectfile_var7, 0x2e, 0x3c, 0);
-    oam++;
-  }
-  SetOamPlain(oam, kNamePlayer_X[selectfile_var4], 0x58, 0x29, 0xc, 0);
-
-  if (selectfile_var9 | selectfile_var11)
-    return;
-
-  if (!(filtered_joypad_H & 0x10)) {
-    if (!(filtered_joypad_H & 0xc0 || filtered_joypad_L & 0xc0))
-      return;
-
-    sound_effect_1 = 0x2b;
-    uint8 t = kNamePlayer_Tab3[selectfile_var3 + selectfile_var5 * 0x20];
-    if (t == 0x5a) {
-      if (!selectfile_var4)
-        selectfile_var4 = 5;
-      else
-        selectfile_var4--;
-      return;
-    } else if (t == 0x44) {
-      if (++selectfile_var4 == 6)
-        selectfile_var4 = 0;
-      return;
-    } else if (t != 0x6f) {
-      int p = selectfile_var4 * 2 + attract_legend_ctr;
-      uint16 chr = (t & 0xfff0) * 2 + (t & 0xf);
-      WORD(g_zenv.sram[p + kSrmOffs_Name]) = chr;
-      NameFile_DrawSelectedCharacter(selectfile_var4, chr);
-      if (++selectfile_var4 == 6)
-        selectfile_var4 = 0;
-      return;
-    }
-  }
-  int i = 0;
-  for(;;) {
-    uint16 a = WORD(g_zenv.sram[i * 2 + attract_legend_ctr + kSrmOffs_Name]);
-    if (a != 0xa9)
-      break;
-    if (++i == 6) {
-      sound_effect_1 = 0x3c;
-      return;
-    }
-  }
-  srm_var1 = selectfile_R16 * 2 + 2;
-  uint8 *sram = &g_zenv.sram[selectfile_R16 * 0x500];
-  WORD(sram[0x3e5]) = 0x55aa;
-  WORD(sram[0x20c]) = 0xf000;
-  WORD(sram[0x20e]) = 0xf000;
-  WORD(sram[kSrmOffs_DiedCounter]) = 0xffff;
-  static const uint8 kSramInit_Normal[60] = {
-    0, 0, 0, 0, 0, 0, 0, 0, 0,    0, 0, 0,    0,    0, 0, 0,
-    0, 0, 0, 0, 0, 0, 0, 0, 0,    0, 0, 0,    0,    0, 0, 0,
-    0, 0, 0, 0, 0, 0, 0, 0, 0,    0, 0, 0, 0x18, 0x18, 0, 0,
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0xf8, 0, 0,
-  };
-  memcpy(sram + 0x340, kSramInit_Normal, 60);
-  Intro_FixCksum(sram);
-  ZeldaWriteSram();
-  ReturnToFileSelect();
-  irq_flag = 0xff;
-  sound_effect_1 = 0x2c;
-}
-
-void NameFile_CheckForScrollInputX() {  // 8cdc8c
-  static const uint16 kNameFile_CheckForScrollInputX_Add[2] = {1, 0xff};
-  static const int16 kNameFile_CheckForScrollInputX_Cmp[2] = {0x20, 0xff};
-  static const int16 kNameFile_CheckForScrollInputX_Set[2] = {0, 0x1f};
-  if (joypad1H_last & 3) {
-    int k = (joypad1H_last & 3) - 1;
-    selectfile_var10 = k;
-    selectfile_var9++;
-    uint8 t = selectfile_var3 + kNameFile_CheckForScrollInputX_Add[k];
-    if (t == kNameFile_CheckForScrollInputX_Cmp[k])
-      t = kNameFile_CheckForScrollInputX_Set[k];
-    selectfile_var3 = t;
-  }
-}
-
-void NameFile_CheckForScrollInputY() {  // 8cdcbf
-  static const int8 kNameFile_CheckForScrollInputY_Add[2] = {1, -1};
-  static const int8 kNameFile_CheckForScrollInputY_Cmp[2] = {4, -1};
-  static const int8 kNameFile_CheckForScrollInputY_Set[2] = {0, 3};
-
-  uint8 a = joypad1H_last & 0xc;
-  if (a) {
-    if ((a * 2 | selectfile_var5) == 0x10 || (a * 4 | selectfile_var5) == 0x13) {
-      selectfile_arr2[1] = a;
-      return;
-    }
-     a >>= 2;
-    int t = selectfile_var5 + kNameFile_CheckForScrollInputY_Add[a-1];
-    if (t == kNameFile_CheckForScrollInputY_Cmp[a-1])
-      t = kNameFile_CheckForScrollInputY_Set[a-1];
-    selectfile_var5 = t;
-
-    selectfile_var11++;
-    selectfile_arr2[1] = a;
-
-  } else {
-    selectfile_arr2[0] = 0;
-  }
-}
-
-void NameFile_DrawSelectedCharacter(int k, uint16 chr) {  // 8cdd30
-  static const uint16 kNameFile_DrawSelectedCharacter_Tab[6] = {0x84, 0x86, 0x88, 0x8a, 0x8c, 0x8e};
-  uint16 *dst = vram_upload_data;
-  uint16 a = kNameFile_DrawSelectedCharacter_Tab[k] | 0x6100;
-  dst[0] = swap16(a);
-  dst[1] = 0x100;
-  dst[2] = 0x1800 | chr;
-  dst[3] = swap16(a + 0x20);
-  dst[4] = 0x100;
-  dst[5] = (0x1800 | chr) + 0x10;
-  BYTE(dst[6]) = 0xff;
-  nmi_load_bg_from_vram = 1;
-}
-
--- a/select_file.h
+++ /dev/null
@@ -1,44 +1,0 @@
-#pragma once
-
-
-bool Intro_CheckCksum(const uint8 *s);
-uint16 *SelectFile_Func1();
-void SelectFile_Func5_DrawOams(int k);
-void SelectFile_Func6_DrawOams2(int k);
-void SelectFile_Func17(int k);
-void SelectFile_Func16();
-void Module_NamePlayer_1();
-void Module_NamePlayer_2();
-void Intro_FixCksum(uint8 *s);
-void LoadFileSelectGraphics();
-void Intro_ValidateSram();
-void Module01_FileSelect();
-void Module_SelectFile_0();
-void FileSelect_ReInitSaveFlagsAndEraseTriforce();
-void FileSelect_EraseTriforce();
-void Module_EraseFile_1();
-void FileSelect_TriggerStripesAndAdvance();
-void FileSelect_TriggerNameStripesAndAdvance();
-void FileSelect_Main();
-void Module02_CopyFile();
-void Module_CopyFile_2();
-void CopyFile_ChooseSelection();
-void CopyFile_ChooseTarget();
-void CopyFile_ConfirmSelection();
-void FilePicker_DeleteHeaderStripe();
-void CopyFile_SelectionAndBlinker();
-void ReturnToFileSelect();
-void CopyFile_TargetSelectionAndBlink();
-void CopyFile_HandleConfirmation();
-void Module03_KILLFile();
-void KILLFile_SetUp();
-void KILLFile_HandleSelection();
-void KILLFile_HandleConfirmation();
-void KILLFile_ChooseTarget();
-void FileSelect_DrawFairy(uint8 x, uint8 y);
-void Module04_NameFile();
-void NameFile_EraseSave();
-void NameFile_DoTheNaming();
-void NameFile_CheckForScrollInputX();
-void NameFile_CheckForScrollInputY();
-void NameFile_DrawSelectedCharacter(int k, uint16 chr);
--- a/snes/ppu.c
+++ b/snes/ppu.c
@@ -6,7 +6,7 @@
 #include <stddef.h>
 #include <assert.h>
 #include "ppu.h"
-#include "../types.h"
+#include "src/types.h"
 
 static const uint8 kSpriteSizes[8][2] = {
   {8, 16}, {8, 32}, {8, 64}, {16, 32},
--- a/snes/ppu.h
+++ b/snes/ppu.h
@@ -7,10 +7,10 @@
 #include <string.h>
 #include <stdint.h>
 #include <stdbool.h>
-#include "saveload.h"
+#include "snes/saveload.h"
 typedef struct Ppu Ppu;
 
-#include "../types.h"
+#include "src/types.h"
 
 typedef struct BgLayer {
   uint16_t hScroll;
--- a/spc_player.c
+++ /dev/null
@@ -1,1447 +1,0 @@
-#include <stdint.h>
-#include <string.h>
-#include <stdlib.h>
-#include <assert.h>
-#include "types.h"
-
-#include "snes/spc.h"
-#include "snes/dsp_regs.h"
-
-#include "spc_player.h"
-
-typedef struct MemMap {
-  uint16 off, org_off;
-} MemMap;
-
-typedef struct MemMapSized {
-  uint16 off, org_off, size;
-} MemMapSized;
-
-static const MemMap kChannel_Maps[] = {
-  {offsetof(Channel, pattern_order_ptr_for_chan), 0x8030},
-  {offsetof(Channel, note_ticks_left), 0x70},
-  {offsetof(Channel, note_keyoff_ticks_left), 0x71},
-  {offsetof(Channel, subroutine_num_loops), 0x80},
-  {offsetof(Channel, volume_fade_ticks), 0x90},
-  {offsetof(Channel, pan_num_ticks), 0x91},
-  {offsetof(Channel, pitch_slide_length), 0xa0},
-  {offsetof(Channel, pitch_slide_delay_left), 0xa1},
-  {offsetof(Channel, vibrato_hold_count), 0xb0},
-  {offsetof(Channel, vib_depth), 0xb1},
-  {offsetof(Channel, tremolo_hold_count), 0xc0},
-  {offsetof(Channel, tremolo_depth), 0xc1},
-  {offsetof(Channel, vibrato_change_count), 0x100},
-  {offsetof(Channel, note_length), 0x200},
-  {offsetof(Channel, note_gate_off_fixedpt), 0x201},
-  {offsetof(Channel, channel_volume_master), 0x210},
-  {offsetof(Channel, instrument_id), 0x211},
-  {offsetof(Channel, instrument_pitch_base), 0x8220},
-  {offsetof(Channel, saved_pattern_ptr), 0x8230},
-  {offsetof(Channel, pattern_start_ptr), 0x8240},
-  {offsetof(Channel, pitch_envelope_num_ticks), 0x280},
-  {offsetof(Channel, pitch_envelope_delay), 0x281},
-  {offsetof(Channel, pitch_envelope_direction), 0x290},
-  {offsetof(Channel, pitch_envelope_slide_value), 0x291},
-  {offsetof(Channel, vibrato_count), 0x2a0},
-  {offsetof(Channel, vibrato_rate), 0x2a1},
-  {offsetof(Channel, vibrato_delay_ticks), 0x2b0},
-  {offsetof(Channel, vibrato_fade_num_ticks), 0x2b1},
-  {offsetof(Channel, vibrato_fade_add_per_tick), 0x2c0},
-  {offsetof(Channel, vibrato_depth_target), 0x2c1},
-  {offsetof(Channel, tremolo_count), 0x2d0},
-  {offsetof(Channel, tremolo_rate), 0x2d1},
-  {offsetof(Channel, tremolo_delay_ticks), 0x2e0},
-  {offsetof(Channel, channel_transposition), 0x2f0},
-  {offsetof(Channel, channel_volume), 0x8300},
-  {offsetof(Channel, volume_fade_addpertick), 0x8310},
-  {offsetof(Channel, volume_fade_target), 0x320},
-  {offsetof(Channel, final_volume), 0x321},
-  {offsetof(Channel, pan_value), 0x8330},
-  {offsetof(Channel, pan_add_per_tick), 0x8340},
-  {offsetof(Channel, pan_target_value), 0x350},
-  {offsetof(Channel, pan_flag_with_phase_invert), 0x351},
-  {offsetof(Channel, pitch), 0x8360},
-  {offsetof(Channel, pitch_add_per_tick), 0x8370},
-  {offsetof(Channel, pitch_target), 0x380},
-  {offsetof(Channel, fine_tune), 0x381},
-  {offsetof(Channel, sfx_sound_ptr), 0x8390},
-  {offsetof(Channel, sfx_which_sound), 0x3a0},
-  {offsetof(Channel, sfx_arr_countdown), 0x3a1},
-  {offsetof(Channel, sfx_note_length_left), 0x3b0},
-  {offsetof(Channel, sfx_note_length), 0x3b1},
-  {offsetof(Channel, sfx_pan), 0x3d0},
-};
-
-static const MemMapSized kSpcPlayer_Maps[] = {
-  {offsetof(SpcPlayer, new_value_from_snes), 0x0, 4},
-  {offsetof(SpcPlayer, port_to_snes), 0x4, 4},
-  {offsetof(SpcPlayer, last_value_from_snes), 0x8, 4},
-  {offsetof(SpcPlayer, counter_sf0c), 0xc, 1},
-  {offsetof(SpcPlayer, _always_zero), 0xe, 2},
-  {offsetof(SpcPlayer, temp_accum), 0x10, 2},
-  {offsetof(SpcPlayer, ttt), 0x12, 1},
-  {offsetof(SpcPlayer, did_affect_volumepitch_flag), 0x13, 1},
-  {offsetof(SpcPlayer, addr0), 0x14, 2},
-  {offsetof(SpcPlayer, addr1), 0x16, 2},
-  {offsetof(SpcPlayer, lfsr_value), 0x18, 2},
-  {offsetof(SpcPlayer, is_chan_on), 0x1a, 1},
-  {offsetof(SpcPlayer, fast_forward), 0x1b, 1},
-  {offsetof(SpcPlayer, sfx_start_arg_pan), 0x20, 1},
-  {offsetof(SpcPlayer, sfx_sound_ptr_cur), 0x2c, 2},
-  {offsetof(SpcPlayer, music_ptr_toplevel), 0x40, 2},
-  {offsetof(SpcPlayer, block_count), 0x42, 1},
-  {offsetof(SpcPlayer, sfx_timer_accum), 0x43, 1},
-  {offsetof(SpcPlayer, chn), 0x44, 1},
-  {offsetof(SpcPlayer, key_ON), 0x45, 1},
-  {offsetof(SpcPlayer, key_OFF), 0x46, 1},
-  {offsetof(SpcPlayer, cur_chan_bit), 0x47, 1},
-  {offsetof(SpcPlayer, reg_FLG), 0x48, 1},
-  {offsetof(SpcPlayer, reg_NON), 0x49, 1},
-  {offsetof(SpcPlayer, reg_EON), 0x4a, 1},
-  {offsetof(SpcPlayer, reg_PMON), 0x4b, 1},
-  {offsetof(SpcPlayer, echo_stored_time), 0x4c, 1},
-  {offsetof(SpcPlayer, echo_parameter_EDL), 0x4d, 1},
-  {offsetof(SpcPlayer, reg_EFB), 0x4e, 1},
-  {offsetof(SpcPlayer, global_transposition), 0x50, 1},
-  {offsetof(SpcPlayer, main_tempo_accum), 0x51, 1},
-  {offsetof(SpcPlayer, tempo), 0x52, 2},
-  {offsetof(SpcPlayer, tempo_fade_num_ticks), 0x54, 1},
-  {offsetof(SpcPlayer, tempo_fade_final), 0x55, 1},
-  {offsetof(SpcPlayer, tempo_fade_add), 0x56, 2},
-  {offsetof(SpcPlayer, master_volume), 0x58, 2},
-  {offsetof(SpcPlayer, master_volume_fade_ticks), 0x5a, 1},
-  {offsetof(SpcPlayer, master_volume_fade_target), 0x5b, 1},
-  {offsetof(SpcPlayer, master_volume_fade_add_per_tick), 0x5c, 2},
-  {offsetof(SpcPlayer, vol_dirty), 0x5e, 1},
-  {offsetof(SpcPlayer, percussion_base_id), 0x5f, 1},
-  {offsetof(SpcPlayer, echo_volume_left), 0x60, 2},
-  {offsetof(SpcPlayer, echo_volume_right), 0x62, 2},
-  {offsetof(SpcPlayer, echo_volume_fade_add_left), 0x64, 2},
-  {offsetof(SpcPlayer, echo_volume_fade_add_right), 0x66, 2},
-  {offsetof(SpcPlayer, echo_volume_fade_ticks), 0x68, 1},
-  {offsetof(SpcPlayer, echo_volume_fade_target_left), 0x69, 1},
-  {offsetof(SpcPlayer, echo_volume_fade_target_right), 0x6a, 1},
-  {offsetof(SpcPlayer, sfx_channel_index), 0x3c0, 1},
-  {offsetof(SpcPlayer, current_bit), 0x3c1, 1},
-  {offsetof(SpcPlayer, dsp_register_index), 0x3c2, 1},
-  {offsetof(SpcPlayer, echo_channels), 0x3c3, 1},
-  {offsetof(SpcPlayer, byte_3C4), 0x3c4, 1},
-  {offsetof(SpcPlayer, byte_3C5), 0x3c5, 1},
-  {offsetof(SpcPlayer, echo_fract_incr), 0x3c7, 1},
-  {offsetof(SpcPlayer, sfx_channel_index2), 0x3c8, 1},
-  {offsetof(SpcPlayer, sfx_channel_bit), 0x3c9, 1},
-  {offsetof(SpcPlayer, pause_music_ctr), 0x3ca, 1},
-  {offsetof(SpcPlayer, port2_active), 0x3cb, 1},
-  {offsetof(SpcPlayer, port2_current_bit), 0x3cc, 1},
-  {offsetof(SpcPlayer, port3_active), 0x3cd, 1},
-  {offsetof(SpcPlayer, port3_current_bit), 0x3ce, 1},
-  {offsetof(SpcPlayer, port1_active), 0x3cf, 1},
-  {offsetof(SpcPlayer, port1_current_bit), 0x3e0, 1},
-  {offsetof(SpcPlayer, byte_3E1), 0x3e1, 1},
-  {offsetof(SpcPlayer, sfx_play_echo_flag), 0x3e2, 1},
-  {offsetof(SpcPlayer, sfx_channels_echo_mask2), 0x3e3, 1},
-  {offsetof(SpcPlayer, port1_counter), 0x3e4, 1},
-  {offsetof(SpcPlayer, channel_67_volume), 0x3e5, 1},
-  {offsetof(SpcPlayer, cutk_always_zero), 0x3ff, 1},
-};
-
-static void PlayNote(SpcPlayer *p, Channel *c, uint8 note);
-
-static void Dsp_Write(SpcPlayer *p, uint8_t reg, uint8 value) {
-  DspRegWriteHistory *hist = p->reg_write_history;
-  if (hist) {
-    if (hist->count < 256) {
-      hist->addr[hist->count] = reg;
-      hist->val[hist->count] = value;
-      hist->count++;
-    }
-  }
-  if (p->dsp)
-    dsp_write(p->dsp, reg, value);
-}
-
-static void Not_Implemented() {
-  assert(0);
-  printf("Not Implemented\n");
-}
-
-static uint16 SpcDivHelper(int a, uint8 b) {
-  int org_a = a;
-  if (a & 0x100)
-    a = -a;
-  int q = b ? (a & 0xff) / b : 0xff;
-  int r = b ? (a & 0xff) % b : (a & 0xff);
-  int t = (q << 8) + (b ? ((r << 8) / b & 0xff) : 0xff);
-  return (org_a & 0x100) ? -t : t;
-}
-
-static inline void Chan_DoAnyFade(uint16 *p, uint16 add, uint8 target, uint8 cont) {
-  if (!cont)
-    *p = target << 8;
-  else
-    *p += add;
-}
-
-static void SetupEchoParameter_EDL(SpcPlayer *p, uint8 a) {
-  p->echo_parameter_EDL = a;
-  if (a != p->last_written_edl) {
-    a = (p->last_written_edl & 0xf) ^ 0xff;
-    if (p->echo_stored_time & 0x80)
-      a += p->echo_stored_time;
-    p->echo_stored_time = a;
-
-    Dsp_Write(p, EON, 0);
-    Dsp_Write(p, EFB, 0);
-    Dsp_Write(p, EVOLR, 0);
-    Dsp_Write(p, EVOLL, 0);
-    Dsp_Write(p, FLG, p->reg_FLG | 0x20);
-
-    p->last_written_edl = p->echo_parameter_EDL;
-    Dsp_Write(p, EDL, p->echo_parameter_EDL);
-  }
-  Dsp_Write(p, ESA, (p->echo_parameter_EDL * 8 ^ 0xff) + 0xd1);
-}
-
-static void WriteVolumeToDsp(SpcPlayer *p, Channel *c, uint16 volume) {
-  static const uint8 kVolumeTable[22] = {0, 1, 3, 7, 13, 21, 30, 41, 52, 66, 81, 94, 103, 110, 115, 119, 122, 124, 125, 126, 127, 127};
-  if (p->is_chan_on & p->cur_chan_bit)
-    return;
-  for (int i = 0; i < 2; i++) {
-    int j = volume >> 8;
-    uint8 t;
-    if (j >= 21) {
-      t = p->ram[j + 0x1178] + ((p->ram[j + 0x1179] - p->ram[j + 0x1178]) * (uint8)volume >> 8);
-    } else {
-      t = kVolumeTable[j] + ((kVolumeTable[j + 1] - kVolumeTable[j]) * (uint8)volume >> 8);
-    }
-    
-     
-    t = t * c->final_volume >> 8;
-    if ((c->pan_flag_with_phase_invert << i) & 0x80)
-      t = -t;
-    Dsp_Write(p, V0VOLL + i + c->index * 16, t);
-    volume = 0x1400 - volume;
-  }
-}
-
-static void WritePitch(SpcPlayer *p, Channel *c, uint16 pitch) {
-  static const uint16 kBaseNoteFreqs[13] = {2143, 2270, 2405, 2548, 2700, 2860, 3030, 3211, 3402, 3604, 3818, 4045, 4286};
-  if ((pitch >> 8) >= 0x34) {
-    pitch += (pitch >> 8) - 0x34;
-  } else if ((pitch >> 8) < 0x13) {
-    pitch += (uint8)(((pitch >> 8) - 0x13) * 2) - 256;
-  }
-
-  uint8 pp = (pitch >> 8) & 0x7f;
-  uint8 q = pp / 12, r = pp % 12;
-  uint16 t = kBaseNoteFreqs[r] + ((uint8)(kBaseNoteFreqs[r + 1] - kBaseNoteFreqs[r]) * (uint8)pitch >> 8);
-  t *= 2;
-  while (q != 6)
-    t >>= 1, q++;
-
-  t = c->instrument_pitch_base * t >> 8;
-  if (!(p->cur_chan_bit & p->is_chan_on)) {
-    uint8 reg = c->index * 16;
-    Dsp_Write(p, reg + V0PITCHL, t & 0xff);
-    Dsp_Write(p, reg + V0PITCHH, t >> 8);
-  }
-}
-
-static void Music_ResetChan(SpcPlayer *p) {
-  Channel *c = &p->channel[7];
-  p->cur_chan_bit = 0x80;
-  do {
-    HIBYTE(c->channel_volume) = 0xff;
-    c->pan_flag_with_phase_invert = 10;
-    c->pan_value = 10 << 8;
-    c->instrument_id = 0;
-    c->fine_tune = 0;
-    c->channel_transposition = 0;
-    c->pitch_envelope_num_ticks = 0;
-    c->vib_depth = 0;
-    c->tremolo_depth = 0;
-  } while (c--, p->cur_chan_bit >>= 1);
-  p->master_volume_fade_ticks = 0;
-  p->echo_volume_fade_ticks = 0;
-  p->tempo_fade_num_ticks = 0;
-  p->global_transposition = 0;
-  p->block_count = 0;
-  p->percussion_base_id = 0;
-  HIBYTE(p->master_volume) = 0xc0;
-  HIBYTE(p->tempo) = 0x20;
-}
-
-static void Channel_SetInstrument(SpcPlayer *p, Channel *c, uint8 instrument) {
-  c->instrument_id = instrument;
-  if (instrument & 0x80)
-    instrument = instrument + 54 + p->percussion_base_id;
-  const uint8 *ip = p->ram + instrument * 6 + 0x3d00;
-  if (p->is_chan_on & p->cur_chan_bit)
-    return;
-  uint8 reg = c->index * 16;
-  if (ip[0] & 0x80) {
-    // noise
-    p->reg_FLG = (p->reg_FLG & 0x20) | ip[0] & 0x1f;
-    p->reg_NON |= p->cur_chan_bit;
-    Dsp_Write(p, reg + V0SRCN, 0);
-  } else {
-    Dsp_Write(p, reg + V0SRCN, ip[0]);
-  }
-  Dsp_Write(p, reg + V0ADSR1, ip[1]);
-  Dsp_Write(p, reg + V0ADSR2, ip[2]);
-  Dsp_Write(p, reg + V0GAIN, ip[3]);
-  c->instrument_pitch_base = ip[4] << 8 | ip[5];
-}
-
-static void ComputePitchAdd(Channel *c, uint8 pitch) {
-  c->pitch_target = pitch & 0x7f;
-  c->pitch_add_per_tick = SpcDivHelper(c->pitch_target - (c->pitch >> 8), c->pitch_slide_length);
-}
-
-static void PitchSlideToNote_Check(SpcPlayer *p, Channel *c) {
-  if (c->pitch_slide_length || p->ram[c->pattern_order_ptr_for_chan] != 0xf9)
-    return;
-
-  if (p->cur_chan_bit & p->is_chan_on) {
-    c->pattern_order_ptr_for_chan += 4;
-    return;
-  }
-  c->pattern_order_ptr_for_chan++;
-  c->pitch_slide_delay_left = p->ram[c->pattern_order_ptr_for_chan++];
-  c->pitch_slide_length = p->ram[c->pattern_order_ptr_for_chan++];
-  ComputePitchAdd(c, p->ram[c->pattern_order_ptr_for_chan++] + p->global_transposition + c->channel_transposition);
-}
-
-static const uint8 kEffectByteLength[27] = {1, 1, 2, 3, 0, 1, 2, 1, 2, 1, 1, 3, 0, 1, 2, 3, 1, 3, 3, 0, 1, 3, 0, 3, 3, 3, 1};
-
-static void HandleEffect(SpcPlayer *p, Channel *c, uint8 effect) {
-  uint8 arg = kEffectByteLength[effect - 0xe0] ? p->ram[c->pattern_order_ptr_for_chan++] : 0;
-
-  switch (effect) {
-  case 0xe0:
-    Channel_SetInstrument(p, c, arg);
-    break;
-  case 0xe1:
-    c->pan_flag_with_phase_invert = arg;
-    c->pan_value = (arg & 0x1f) << 8;
-    break;
-  case 0xe2:
-    c->pan_num_ticks = arg;
-    c->pan_target_value = p->ram[c->pattern_order_ptr_for_chan++];
-    c->pan_add_per_tick = SpcDivHelper(c->pan_target_value - (c->pan_value >> 8), arg);
-    break;
-  case 0xe3: // vibrato on
-    c->vibrato_delay_ticks = arg;
-    c->vibrato_rate = p->ram[c->pattern_order_ptr_for_chan++];
-    c->vibrato_depth_target = c->vib_depth = p->ram[c->pattern_order_ptr_for_chan++];
-    c->vibrato_fade_num_ticks = 0;
-    break;
-  case 0xe4: // vibrato off
-    c->vibrato_depth_target = c->vib_depth = 0;
-    c->vibrato_fade_num_ticks = 0;
-    break;
-  case 0xe5:
-    if (!p->pause_music_ctr && !p->byte_3E1)
-      p->master_volume = arg << 8;
-    break;
-  case 0xe6:
-    p->master_volume_fade_ticks = arg;
-    p->master_volume_fade_target = p->ram[c->pattern_order_ptr_for_chan++];
-    p->master_volume_fade_add_per_tick = SpcDivHelper(p->master_volume_fade_target - (p->master_volume >> 8), arg);
-    break;
-  case 0xe7:
-    p->tempo = arg << 8;
-    break;
-  case 0xe8:
-    p->tempo_fade_num_ticks = arg;
-    p->tempo_fade_final = p->ram[c->pattern_order_ptr_for_chan++];
-    p->tempo_fade_add = SpcDivHelper(p->tempo_fade_final - (p->tempo >> 8), arg);
-    break;
-  case 0xe9:
-    p->global_transposition = arg;
-    break;
-  case 0xea:
-    c->channel_transposition = arg;
-    break;
-  case 0xeb:
-    c->tremolo_delay_ticks = arg;
-    c->tremolo_rate = p->ram[c->pattern_order_ptr_for_chan++];
-    c->tremolo_depth = p->ram[c->pattern_order_ptr_for_chan++];
-    break;
-  case 0xec:
-    c->tremolo_depth = 0;
-    break;
-  case 0xed:
-    c->channel_volume = arg << 8;
-    break;
-  case 0xee:
-    c->volume_fade_ticks = arg;
-    c->volume_fade_target = p->ram[c->pattern_order_ptr_for_chan++];
-    c->volume_fade_addpertick = SpcDivHelper(c->volume_fade_target - (c->channel_volume >> 8), arg);
-    break;
-  case 0xef:
-    c->pattern_start_ptr = p->ram[c->pattern_order_ptr_for_chan++] << 8 | arg;
-    c->subroutine_num_loops = p->ram[c->pattern_order_ptr_for_chan++];
-    c->saved_pattern_ptr = c->pattern_order_ptr_for_chan;
-    c->pattern_order_ptr_for_chan = c->pattern_start_ptr;
-    break;
-  case 0xf0:
-    c->vibrato_fade_num_ticks = arg;
-    c->vibrato_fade_add_per_tick = arg ? c->vib_depth / arg : 0xff;
-    break;
-  case 0xf4:
-    c->fine_tune = arg;
-    break;
-  case 0xf5:
-    p->reg_EON = p->echo_channels = arg;
-    p->echo_volume_left = p->ram[c->pattern_order_ptr_for_chan++] << 8;
-    p->echo_volume_right = p->ram[c->pattern_order_ptr_for_chan++] << 8;
-    p->reg_FLG &= ~0x20;
-    break;
-  case 0xf6:  // echo off
-    p->echo_volume_left = 0;
-    p->echo_volume_right = 0;
-    p->reg_FLG |= 0x20;
-    break;
-  case 0xf7: {
-    static const int8_t kEchoFirParameters[] = {
-      127, 0, 0, 0, 0, 0, 0, 0,
-      88, -65, -37, -16, -2, 7, 12, 12,
-      12, 33, 43, 43, 19, -2, -13, -7,
-      52, 51, 0, -39, -27, 1, -4, -21,
-    };
-    SetupEchoParameter_EDL(p, arg);
-    p->reg_EFB = p->ram[c->pattern_order_ptr_for_chan++];
-    const int8_t *ep = kEchoFirParameters + p->ram[c->pattern_order_ptr_for_chan++] * 8;
-    for (int i = 0; i < 8; i++)
-      Dsp_Write(p, FIR0 + i * 16, *ep++);
-    break;
-  }
-  case 0xf8:
-    p->echo_volume_fade_ticks = arg;
-    p->echo_volume_fade_target_left = p->ram[c->pattern_order_ptr_for_chan++];
-    p->echo_volume_fade_target_right = p->ram[c->pattern_order_ptr_for_chan++];
-    p->echo_volume_fade_add_left = SpcDivHelper(p->echo_volume_fade_target_left - (p->echo_volume_left >> 8), arg);
-    p->echo_volume_fade_add_right = SpcDivHelper(p->echo_volume_fade_target_right - (p->echo_volume_right >> 8), arg);
-    break;
-  case 0xf9:
-    c->pitch_slide_delay_left = arg;
-    c->pitch_slide_length = p->ram[c->pattern_order_ptr_for_chan++];
-    ComputePitchAdd(c, p->ram[c->pattern_order_ptr_for_chan++] + p->global_transposition + c->channel_transposition);
-    break;
-  case 0xfa:
-    p->percussion_base_id = arg;
-    break;
-  default:
-    Not_Implemented();
-  }
-}
-
-static bool WantWriteKof(SpcPlayer *p, Channel *c) {
-  int loops = c->subroutine_num_loops;
-  int ptr = c->pattern_order_ptr_for_chan;
-
-  for (;;) {
-    uint8 cmd = p->ram[ptr++];
-    if (cmd == 0) {
-      if (loops == 0)
-        return true;
-      ptr = (--loops == 0) ? c->saved_pattern_ptr : c->pattern_start_ptr;
-    } else {
-      while (!(cmd & 0x80))
-        cmd = p->ram[ptr++];
-      if (cmd == 0xc8)
-        return false;
-      if (cmd == 0xef) {
-        ptr = p->ram[ptr + 0] | p->ram[ptr + 1] << 8;
-      } else if (cmd >= 0xe0) {
-        ptr += kEffectByteLength[cmd - 0xe0];
-      } else {
-        return true;
-      }
-    }
-  }
-}
-
-static void HandleTremolo(SpcPlayer *p, Channel *c) {
-  Not_Implemented();
-}
-
-static void CalcVibratoAddPitch(SpcPlayer *p, Channel *c, uint16 pitch, uint8 value) {
-  int t = value << 2;
-  t ^= (t & 0x100) ? 0xff : 0;
-  int r = (c->vib_depth >= 0xf1) ?
-      (uint8)t * (c->vib_depth & 0xf) :
-      (uint8)t * c->vib_depth >> 8;
-  WritePitch(p, c, pitch + (value & 0x80 ? -r : r));
-}
-
-static void HandlePanAndSweep(SpcPlayer *p, Channel *c) {
-  p->did_affect_volumepitch_flag = 0;
-  if (c->tremolo_depth) {
-    c->tremolo_hold_count = c->tremolo_delay_ticks;
-    HandleTremolo(p, c);
-  }
-
-  uint16 volume = c->pan_value;
-
-  if (c->pan_num_ticks) {
-    p->did_affect_volumepitch_flag = 0x80;
-    volume += p->main_tempo_accum * (int16_t)c->pan_add_per_tick / 256;
-  }
-
-  if (p->did_affect_volumepitch_flag)
-    WriteVolumeToDsp(p, c, volume);
-
-  p->did_affect_volumepitch_flag = 0;
-  uint16 pitch = c->pitch;
-  if (c->pitch_slide_length && !c->pitch_slide_delay_left) {
-    p->did_affect_volumepitch_flag |= 0x80;
-    pitch += p->main_tempo_accum * (int16_t)c->pitch_add_per_tick / 256;
-  }
-
-  if (c->vib_depth && c->vibrato_delay_ticks == c->vibrato_hold_count) {
-    CalcVibratoAddPitch(p, c, pitch, (p->main_tempo_accum * c->vibrato_rate >> 8) + c->vibrato_count);
-    return;
-  }
-
-  if (p->did_affect_volumepitch_flag)
-    WritePitch(p, c, pitch);
-}
-
-static void HandleNoteTick(SpcPlayer *p, Channel *c) {
-  if (c->note_keyoff_ticks_left != 0 && (--c->note_keyoff_ticks_left == 0 || c->note_ticks_left == 2)) {
-    if (WantWriteKof(p, c) && !(p->cur_chan_bit & p->is_chan_on))
-      Dsp_Write(p, KOF, p->cur_chan_bit);
-  }
-
-  p->did_affect_volumepitch_flag = 0;
-  if (c->pitch_slide_length) {
-    if (c->pitch_slide_delay_left) {
-      c->pitch_slide_delay_left--;
-    } else if (!(p->is_chan_on & p->cur_chan_bit)) {
-      p->did_affect_volumepitch_flag = 0x80;
-      Chan_DoAnyFade(&c->pitch, c->pitch_add_per_tick, c->pitch_target, --c->pitch_slide_length);
-    }
-  }
-
-  uint16 pitch = c->pitch;
-
-  if (c->vib_depth) {
-    if (c->vibrato_delay_ticks == c->vibrato_hold_count) {
-      if (c->vibrato_change_count == c->vibrato_fade_num_ticks) {
-        c->vib_depth = c->vibrato_depth_target;
-      } else {
-        c->vib_depth = (c->vibrato_change_count++ == 0 ? 0 : c->vib_depth) + c->vibrato_fade_add_per_tick;
-      }
-      c->vibrato_count += c->vibrato_rate;
-      CalcVibratoAddPitch(p, c, pitch, c->vibrato_count);
-      return;
-    }
-    c->vibrato_hold_count++;
-  }
-  
-  if (p->did_affect_volumepitch_flag)
-    WritePitch(p, c, pitch);
-}
-
-void CalcFinalVolume(SpcPlayer *p, Channel *c, uint8 vol) {
-  int t = (p->master_volume >> 8) * vol >> 8;
-  t = t * c->channel_volume_master >> 8;
-  t = t * (c->channel_volume >> 8) >> 8;
-  c->final_volume = t * t >> 8;
-}
-
-void CalcTremolo(SpcPlayer *p, Channel *c) {
-  Not_Implemented();
-}
-
-static void Chan_HandleTick(SpcPlayer *p, Channel *c) {
-  if (c->volume_fade_ticks) {
-    c->volume_fade_ticks--;
-    p->vol_dirty |= p->cur_chan_bit;
-    Chan_DoAnyFade(&c->channel_volume, c->volume_fade_addpertick, c->volume_fade_target, true);
-  }
-  if (c->tremolo_depth) {
-    if (c->tremolo_delay_ticks == c->tremolo_hold_count) {
-      p->vol_dirty |= p->cur_chan_bit;
-      if (c->tremolo_count & 0x80 && c->tremolo_depth == 0xff) {
-        c->tremolo_count = 0x80;
-      } else {
-        c->tremolo_count += c->tremolo_rate;
-      }
-      CalcTremolo(p, c);
-    } else {
-      c->tremolo_hold_count++;
-      CalcFinalVolume(p, c, 0xff);
-    }
-  } else {
-    CalcFinalVolume(p, c, 0xff);
-  }
-
-  if (c->pan_num_ticks) {
-    c->pan_num_ticks--;
-    p->vol_dirty |= p->cur_chan_bit;
-    Chan_DoAnyFade(&c->pan_value, c->pan_add_per_tick, c->pan_target_value, true);
-  }
-
-  if (p->vol_dirty & p->cur_chan_bit)
-    WriteVolumeToDsp(p, c, c->pan_value);
-}
-
-static void Port0_HandleMusic(SpcPlayer *p) {
-  Channel *c;
-  uint8 a = p->new_value_from_snes[0];
-  int t;
-
-  if (a == 0) {
-handle_cmd_00:
-    if (p->port_to_snes[0] == 0)
-      return;
-    if (p->pause_music_ctr != 0 && --p->pause_music_ctr == 0)
-      goto HandleCmd_0xf0_PauseMusic;
-    if (p->counter_sf0c == 0)
-      goto label_a;
-    if (--p->counter_sf0c != 0) {
-      Music_ResetChan(p);
-      return;
-    }
-next_phrase:
-    for (;;) {
-      t = WORD(p->ram[p->music_ptr_toplevel]);
-      p->music_ptr_toplevel += 2;
-      if ((t >> 8) != 0)
-        break;
-      if (t == 0)
-        goto HandleCmd_0xf0_PauseMusic;
-      if (t == 0x80) {
-        p->fast_forward = 0x80;
-      } else if (t == 0x81) {
-        p->fast_forward = 0;
-      } else {
-        if (sign8(--p->block_count))
-          p->block_count = t;
-        t = WORD(p->ram[p->music_ptr_toplevel]);
-        p->music_ptr_toplevel += 2;
-        if (p->block_count != 0)
-          p->music_ptr_toplevel = t;
-      }
-    }
-    for (int i = 0; i < 8; i++)
-      p->channel[i].pattern_order_ptr_for_chan = WORD(p->ram[t]), t += 2;
-
-    c = p->channel, p->cur_chan_bit = 1;
-    do {
-      if (HIBYTE(c->pattern_order_ptr_for_chan) && c->instrument_id == 0)
-        Channel_SetInstrument(p, c, 0);
-      c->subroutine_num_loops = 0;
-      c->volume_fade_ticks = 0;
-      c->pan_num_ticks = 0;
-      c->note_ticks_left = 1;
-    } while (c++, p->cur_chan_bit <<= 1);
-label_a:
-    p->vol_dirty = 0;
-    c = p->channel, p->cur_chan_bit = 1;
-    do {
-      if (!HIBYTE(c->pattern_order_ptr_for_chan))
-        continue;
-      if (!--c->note_ticks_left) {
-        for (;;) {
-          uint8 cmd = p->ram[c->pattern_order_ptr_for_chan++];
-          if (cmd == 0) {
-            if (!c->subroutine_num_loops)
-              goto next_phrase;
-            c->pattern_order_ptr_for_chan = (--c->subroutine_num_loops == 0) ? c->saved_pattern_ptr : c->pattern_start_ptr;
-            continue;
-          }
-          if (!(cmd & 0x80)) {
-            static const uint8 kNoteVol[16] = { 25, 50, 76, 101, 114, 127, 140, 152, 165, 178, 191, 203, 216, 229, 242, 252 };
-            static const uint8 kNoteGateOffPct[8] = { 50, 101, 127, 152, 178, 203, 229, 252 };
-            c->note_length = cmd;
-            cmd = p->ram[c->pattern_order_ptr_for_chan++];
-            if (!(cmd & 0x80)) {
-              c->note_gate_off_fixedpt = kNoteGateOffPct[cmd >> 4 & 7];
-              c->channel_volume_master = kNoteVol[cmd & 0xf];
-              cmd = p->ram[c->pattern_order_ptr_for_chan++];
-            }
-          }
-          if (cmd >= 0xe0) {
-            HandleEffect(p, c, cmd); 
-            continue;
-          }
-          if (!p->fast_forward && !(p->is_chan_on & p->cur_chan_bit))
-            PlayNote(p, c, cmd);
-          c->note_ticks_left = c->note_length;
-          t = c->note_ticks_left * c->note_gate_off_fixedpt >> 8;
-          c->note_keyoff_ticks_left = (t != 0) ? t : 1;
-          PitchSlideToNote_Check(p, c);
-          break;
-        }
-      } else if (!p->fast_forward) {
-        HandleNoteTick(p, c);
-        PitchSlideToNote_Check(p, c);
-      }
-    } while (c++, p->cur_chan_bit <<= 1);
-    if (p->tempo_fade_num_ticks)
-      p->tempo = (--p->tempo_fade_num_ticks == 0) ? p->tempo_fade_final << 8 : p->tempo + p->tempo_fade_add;
-    if (p->echo_volume_fade_ticks) {
-      p->echo_volume_left += p->echo_volume_fade_add_left;
-      p->echo_volume_right += p->echo_volume_fade_add_right;
-      if (--p->echo_volume_fade_ticks == 0) {
-        p->echo_volume_left = p->echo_volume_fade_target_left << 8;
-        p->echo_volume_right = p->echo_volume_fade_target_right << 8;
-      }
-    }
-    if (p->master_volume_fade_ticks) {
-      p->master_volume = (--p->master_volume_fade_ticks == 0) ? p->master_volume_fade_target << 8 : p->master_volume + p->master_volume_fade_add_per_tick;
-      p->vol_dirty = 0xff;
-    }
-    c = p->channel, p->cur_chan_bit = 1;
-    do {
-      if (HIBYTE(c->pattern_order_ptr_for_chan))
-        Chan_HandleTick(p, c);
-    } while (c++, p->cur_chan_bit <<= 1);
-  } else if (a == 0xff) {
-    // Load new music
-    Not_Implemented();
-  } else if (a == 0xf1) { // continue music
-    p->master_volume_fade_ticks = 0x80;
-    p->pause_music_ctr = 0x80;
-    p->master_volume_fade_target = 0;
-    p->master_volume_fade_add_per_tick = SpcDivHelper(0 - (p->master_volume >> 8), 0x80);
-
-    goto handle_cmd_00;
-  } else if (a == 0xf2) {
-    if (p->byte_3E1 != 0)
-      return;
-    p->byte_3E1 = HIBYTE(p->master_volume);
-    HIBYTE(p->master_volume) = 0x70;
-    goto handle_cmd_00;
-  } else if (a == 0xf3) {
-    if (p->byte_3E1 == 0)
-      return;
-    HIBYTE(p->master_volume) = p->byte_3E1;
-    p->byte_3E1 = 0;
-    goto handle_cmd_00;
-  } else if (a == 0xf0) HandleCmd_0xf0_PauseMusic: {
-    p->key_OFF = p->is_chan_on ^ 0xff;
-    p->port_to_snes[0] = 0;
-    p->cur_chan_bit = 0;
-  } else {
-    p->pause_music_ctr = 0;
-    p->byte_3E1 = 0;
-    p->port_to_snes[0] = a;
-    p->music_ptr_toplevel = WORD(p->ram[0xD000 + (a - 1) * 2]);
-    p->counter_sf0c = 2;
-    p->key_OFF |= p->is_chan_on ^ 0xff;
-  }
-
-}
-
-static inline uint8 Asl(uint8 *p) {
-  uint8 old = *p;
-  *p <<= 1;
-  return old >> 7;
-}
-
-static void Sfx_TurnOffChannel(SpcPlayer *p, Channel *c) {
-  c->sfx_which_sound = 0;
-  p->is_chan_on &= ~p->current_bit;
-  p->port1_active &= ~p->current_bit;
-  p->port2_active &= ~p->current_bit;
-  p->port3_active &= ~p->current_bit;
-  Channel_SetInstrument(p, c, c->instrument_id);
-  if (p->echo_channels & p->current_bit && !(p->reg_EON & p->current_bit)) {
-    p->reg_EON |= p->current_bit;
-    Dsp_Write(p, EON, p->reg_EON);
-    p->sfx_channels_echo_mask2 &= ~p->current_bit;
-  }
-}
-
-static void Write_KeyOn(SpcPlayer *p, uint8 bit) {
-  Dsp_Write(p, KOF, 0);
-  Dsp_Write(p, KON, bit);
-}
-
-static void PlayNote(SpcPlayer *p, Channel *c, uint8 note) {
-  if (note >= 0xca) {
-    Channel_SetInstrument(p, c, note);
-    note = 0xa4;
-  }
-
-//  if (c->index == 0) {
-//    if (note == 0xc8) {
-//      printf("-+-\n");
-//    } else if (note == 0xc9) {
-//      printf("---\n");
-//    }
-//  }
-
-  if (note >= 0xc8 || p->is_chan_on & p->cur_chan_bit)
-    return;
-
-  //static const char *const kNoteNames[] = { "C-", "C#", "D-", "D#", "E-", "F-", "F#", "G-", "G#", "A-", "A#", "B-" };
-  //if (c->index==0)
-  //  printf("%s%d\n", kNoteNames[(note & 0x7f) % 12], (note & 0x7f) / 12 + 1);
-
-  c->pitch = ((note & 0x7f) + p->global_transposition + c->channel_transposition) << 8 | c->fine_tune;
-  c->vibrato_count = c->vibrato_fade_num_ticks << 7;
-  c->vibrato_hold_count = 0;
-  c->vibrato_change_count = 0;
-  c->tremolo_count = 0;
-  c->tremolo_hold_count = 0;
-  p->vol_dirty |= p->cur_chan_bit;
-  p->key_ON |= p->cur_chan_bit;
-  c->pitch_slide_length = c->pitch_envelope_num_ticks;
-  if (c->pitch_slide_length) {
-    c->pitch_slide_delay_left = c->pitch_envelope_delay;
-    if (!c->pitch_envelope_direction)
-      c->pitch -= c->pitch_envelope_slide_value << 8;
-    ComputePitchAdd(c, (c->pitch >> 8) + c->pitch_envelope_slide_value);
-  }
-  WritePitch(p, c, c->pitch);
-}
-
-static void Sfx_MaybeDisableEcho(SpcPlayer *p) {
-  if (!(p->port_to_snes[0] & 0x10) || p->current_bit & p->sfx_channels_echo_mask2) {
-    if (p->current_bit & p->reg_EON) {
-      p->reg_EON ^= p->current_bit;
-      Dsp_Write(p, EON, p->reg_EON);
-    }
-  }
-}
-
-static void Sfx_ChannelTick(SpcPlayer *p, Channel *c, bool is_continue) {
-  uint8 cmd;
-
-  if (is_continue) {
-    Sfx_MaybeDisableEcho(p);
-    p->sfx_channel_index = c->index * 2;
-    p->sfx_sound_ptr_cur = c->sfx_sound_ptr;
-    if (--c->sfx_note_length_left)
-      goto note_continue;
-    p->sfx_sound_ptr_cur++;
-  }
-
-  for (;;) {
-    p->dsp_register_index = p->sfx_channel_index * 8;
-
-    cmd = p->ram[p->sfx_sound_ptr_cur];
-    if (cmd == 0) {
-      Sfx_TurnOffChannel(p, c);
-      return;
-    }
-
-    if (!(cmd & 0x80)) {
-      c->sfx_note_length = cmd;
-      cmd = p->ram[++p->sfx_sound_ptr_cur];
-      if (!(cmd & 0x80)) {
-        if (p->port1_active & p->current_bit) {
-          if (cmd == 0 || !p->channel_67_volume) {
-            uint8 volume = cmd;
-            Dsp_Write(p, p->dsp_register_index + V0VOLL, cmd);
-            cmd = p->ram[++p->sfx_sound_ptr_cur];
-            if (cmd & 0x80) {
-              Dsp_Write(p, p->dsp_register_index + V0VOLR, volume);
-            } else {
-              Dsp_Write(p, p->dsp_register_index + V0VOLR, cmd);
-              cmd = p->ram[++p->sfx_sound_ptr_cur];
-            }
-          } else {
-            cmd = p->ram[++p->sfx_sound_ptr_cur];
-          }
-        } else {
-          c->final_volume = cmd * 2;
-          c->pan_flag_with_phase_invert = 10;
-          WriteVolumeToDsp(p, c, (p->sfx_start_arg_pan & 0x80 ? 16 : p->sfx_start_arg_pan & 0x40 ? 4 : 10) << 8);
-          cmd = p->ram[++p->sfx_sound_ptr_cur];
-        }
-      }
-    }
-    // cmd_parsed
-    if (cmd == 0xe0) {
-      const uint8 *ip = p->ram + 0x3E00 + (p->ram[++p->sfx_sound_ptr_cur] * 9);
-      uint8 reg = c->index * 16;
-      Dsp_Write(p, reg + V0VOLL, ip[0]);
-      Dsp_Write(p, reg + V0VOLR, ip[1]);
-      Dsp_Write(p, reg + V0PITCHL, ip[2]);
-      Dsp_Write(p, reg + V0PITCHH, ip[3]);
-      Dsp_Write(p, reg + V0SRCN, ip[4]);
-      Dsp_Write(p, reg + V0ADSR1, ip[5]);
-      Dsp_Write(p, reg + V0ADSR2, ip[6]);
-      Dsp_Write(p, reg + V0GAIN, ip[7]);
-      c->instrument_pitch_base = ip[8] << 8;
-      p->sfx_sound_ptr_cur++;
-    } else if (cmd == 0xf9 || cmd == 0xf1) {
-      if (cmd == 0xf9) {
-        PlayNote(p, c, p->ram[++p->sfx_sound_ptr_cur]);
-        Write_KeyOn(p, p->current_bit);
-      }
-      c->pitch_slide_delay_left = p->ram[++p->sfx_sound_ptr_cur];
-      c->pitch_slide_length = p->ram[++p->sfx_sound_ptr_cur];
-      ComputePitchAdd(c, p->ram[++p->sfx_sound_ptr_cur]);
-      c->sfx_note_length_left = c->sfx_note_length;
-      goto note_continue;
-    } else if (cmd == 0xff) {
-      p->sfx_sound_ptr_cur = c->sfx_sound_ptr = WORD(p->ram[0x17C0 + (c->sfx_which_sound - 1) * 2]);
-    } else {
-      PlayNote(p, c, cmd);
-      Write_KeyOn(p, p->current_bit);
-      c->sfx_note_length_left = c->sfx_note_length;
-note_continue:
-      p->did_affect_volumepitch_flag = 0;
-      if (c->pitch_slide_length) {
-        p->did_affect_volumepitch_flag = 0x80;
-        Chan_DoAnyFade(&c->pitch, c->pitch_add_per_tick, c->pitch_target, --c->pitch_slide_length);
-        p->cur_chan_bit = 0;  // force change through
-        WritePitch(p, c, c->pitch);
-      } else if (c->sfx_note_length_left == 2) {
-        Dsp_Write(p, KOF, p->current_bit);
-      }
-      break;
-    }
-  }
-  c->sfx_sound_ptr = p->sfx_sound_ptr_cur;
-}
-
-static void Port1_Play_Inner(SpcPlayer *p) {
-  p->port1_counter = 0;
-  Channel *c = &p->channel[7];
-  c->sfx_which_sound = p->new_value_from_snes[1];
-  c->sfx_arr_countdown = 3;
-  c->pitch_envelope_num_ticks = 0;
-  p->port1_active = 0x80;
-  p->is_chan_on |= 0x80;
-  Dsp_Write(p, KOF, 0x80);
-  p->new_value_from_snes[1] = p->ram[0x1800 + p->new_value_from_snes[1] - 1];
-  if (!p->new_value_from_snes[1])
-    return;
-  c--;
-  c->sfx_which_sound = p->new_value_from_snes[1];
-  c->sfx_arr_countdown = 3;
-  c->pitch_envelope_num_ticks = 0;
-  p->port1_active = 0x40;
-  p->is_chan_on |= 0x40;
-  Dsp_Write(p, KOF, 0x40);
-  p->port1_active = 0xc0;
-  p->sfx_channels_echo_mask2 |= 0xc0;
-  p->port2_active &= 0x3f;
-  p->port3_active &= 0x3f;
-}
-
-static void Port1_StartNewSound(SpcPlayer *p) {
-  if (p->port1_counter != 0) {
-    if (--p->port1_counter == 0) {
-      p->new_value_from_snes[1] = 5;
-      Port1_Play_Inner(p);
-      p->new_value_from_snes[1] = 0;
-      return;
-    }
-    p->channel_67_volume = p->port1_counter >> 1;
-    Dsp_Write(p, V7VOLL, p->channel_67_volume);
-    Dsp_Write(p, V7VOLR, p->channel_67_volume);
-    Dsp_Write(p, V6VOLL, p->channel_67_volume);
-    Dsp_Write(p, V6VOLR, p->channel_67_volume);
-  }
-  p->port1_current_bit = p->port1_active;
-  if (!p->port1_current_bit)
-    return;
-  Channel *c = &p->channel[7];
-  p->current_bit = 0x80;
-  do {
-    if (Asl(&p->port1_current_bit)) {
-      p->sfx_channel_index = c->index * 2;
-      p->dsp_register_index = c->index * 16;
-      p->sfx_start_arg_pan = c->sfx_pan;
-      if (!c->sfx_arr_countdown) {
-        if (c->sfx_which_sound)
-          Sfx_ChannelTick(p, c, true);
-      } else {
-        p->sfx_channel_index = c->index * 2;
-        if (!--c->sfx_arr_countdown) {
-          p->sfx_sound_ptr_cur = c->sfx_sound_ptr = WORD(p->ram[0x17C0 + (c->sfx_which_sound - 1) * 2]);
-          Sfx_ChannelTick(p, c, false);
-        }
-      }
-    }
-  } while (c--, (p->current_bit >>= 1) != 0x10);
-}
-
-static void Port1_HandleCmd(SpcPlayer *p) {
-  uint8 a = p->new_value_from_snes[1];
-  if (!(a & 0x80)) {
-    if (a != 0) {
-      p->port_to_snes[1] = a;
-      if (a != 5 || p->port1_active)
-        Port1_Play_Inner(p);
-    }
-  } else {  
-    p->port_to_snes[1] = a;
-    if (p->port1_active)
-      p->port1_counter = 0x78;
-  }
-}
-
-static void Port2_StartNewSound(SpcPlayer *p) {
-  p->port2_current_bit = p->port2_active;
-  if (!p->port2_current_bit)
-    return;
-  Channel *c = &p->channel[7];
-  p->current_bit = 0x80;
-  do {
-    if (Asl(&p->port2_current_bit)) {
-      p->sfx_channel_index = c->index * 2;
-      p->dsp_register_index = c->index * 16;
-      p->sfx_start_arg_pan = c->sfx_pan;
-      if (!c->sfx_arr_countdown) {
-        if (c->sfx_which_sound)
-          Sfx_ChannelTick(p, c, true);
-      } else {
-        p->sfx_channel_index = c->index * 2;
-        if (!--c->sfx_arr_countdown) {
-          p->sfx_sound_ptr_cur = c->sfx_sound_ptr = WORD(p->ram[0x1820 + (c->sfx_which_sound - 1) * 2]);
-          Sfx_ChannelTick(p, c, false);
-        }
-      }
-    }
-  } while (c--, p->current_bit >>= 1);
-}
-
-static Channel *Port2_AllocateChan(SpcPlayer *p) {
-  p->sfx_play_echo_flag = p->ram[0x18dd + (p->new_value_from_snes[2] & 0x3f) - 1];
-  Channel *c = &p->channel[7];
-  p->current_bit = 0x80;
-  do {
-    if (p->port2_active & p->current_bit && c->sfx_which_sound + c->sfx_pan == p->new_value_from_snes[2])
-      goto found_channel;
-  } while (c--, p->current_bit >>= 1);
-  c = &p->channel[7];
-  p->current_bit = 0x80;
-  do {
-    if (!(p->is_chan_on & p->current_bit))
-      goto found_channel;
-  } while (c--, p->current_bit >>= 1);
-  assert(0);  // unreachable
-found_channel:
-  p->sfx_channel_index2 = p->sfx_channel_index = c->index * 2;
-  p->sfx_channel_bit = p->current_bit;
-  p->is_chan_on |= p->current_bit;
-  if (p->sfx_play_echo_flag)
-    p->sfx_channels_echo_mask2 |= p->current_bit;
-  Sfx_MaybeDisableEcho(p);
-  return c;
-}
-
-static void Port2_HandleCmd(SpcPlayer *p) {
-  while (p->new_value_from_snes[2] != 0 && p->is_chan_on != 0xff) {
-    Channel *c = Port2_AllocateChan(p);
-    c->sfx_pan = p->new_value_from_snes[2] & 0xc0;
-    c->sfx_which_sound = p->new_value_from_snes[2] & 0x3f;
-    c->sfx_arr_countdown = 3;
-    c->pitch_envelope_num_ticks = 0;
-    p->port2_active |= p->current_bit;
-    Dsp_Write(p, KOF, p->current_bit);
-    p->new_value_from_snes[2] = p->ram[0x189e + c->sfx_which_sound - 1];
-  }
-}
-
-
-static void Port3_StartNewSound(SpcPlayer *p) {
-  p->port3_current_bit = p->port3_active;
-  if (!p->port3_current_bit)
-    return;
-  Channel *c = &p->channel[7];
-  p->current_bit = 0x80;
-  do {
-    if (Asl(&p->port3_current_bit)) {
-      p->sfx_channel_index = c->index * 2;
-      p->dsp_register_index = c->index * 16;
-      p->sfx_start_arg_pan = c->sfx_pan;
-      if (!c->sfx_arr_countdown) {
-        if (c->sfx_which_sound)
-          Sfx_ChannelTick(p, c, true);
-      } else {
-        p->sfx_channel_index = c->index * 2;
-        if (!--c->sfx_arr_countdown) {
-          p->sfx_sound_ptr_cur = c->sfx_sound_ptr = WORD(p->ram[0x191C + (c->sfx_which_sound - 1) * 2]);
-          Sfx_ChannelTick(p, c, false);
-        }
-      }
-    }
-  } while (c--, p->current_bit >>= 1);
-}
-
-static Channel *Port3_AllocateChan(SpcPlayer *p) {
-  p->sfx_play_echo_flag = p->ram[0x19d8 + (p->new_value_from_snes[3] & 0x3f)];
-  Channel *c = &p->channel[7];
-  p->current_bit = 0x80;
-  do {
-    if (p->port3_active & p->current_bit && c->sfx_which_sound + c->sfx_pan == p->new_value_from_snes[3])
-      goto found_channel;
-  } while (c--, p->current_bit >>= 1);
-  c = &p->channel[7];
-  p->current_bit = 0x80;
-  do {
-    if (!(p->is_chan_on & p->current_bit))
-      goto found_channel;
-  } while (c--, p->current_bit >>= 1);
-  assert(0);  // unreachable
-found_channel:
-  p->sfx_channel_index2 = p->sfx_channel_index = c->index * 2;
-  p->sfx_channel_bit = p->current_bit;
-  p->is_chan_on |= p->current_bit;
-  if (p->sfx_play_echo_flag)
-    p->sfx_channels_echo_mask2 |= p->current_bit;
-  Sfx_MaybeDisableEcho(p);
-  return c;
-}
-
-static void Port3_HandleCmd(SpcPlayer *p) {
-  while (p->new_value_from_snes[3] != 0 && p->is_chan_on != 0xff) {
-    Channel *c = Port3_AllocateChan(p);
-    c->sfx_pan = p->new_value_from_snes[3] & 0xc0;
-    c->sfx_which_sound = p->new_value_from_snes[3] & 0x3f;
-    c->sfx_arr_countdown = 3;
-    c->pitch_envelope_num_ticks = 0;
-    p->port3_active |= p->current_bit;
-    Dsp_Write(p, KOF, p->current_bit);
-    p->new_value_from_snes[3] = p->ram[0x199a + c->sfx_which_sound - 1];
-  }
-}
-
-static void ReadPortFromSnes(SpcPlayer *p, int port) {
-  uint8 old = p->last_value_from_snes[port];
-  p->last_value_from_snes[port] = p->input_ports[port];
-  if (p->input_ports[port] != old)
-    p->new_value_from_snes[port] = p->input_ports[port];
-  else
-    p->new_value_from_snes[port] = 0;
-}
-
-static void Spc_Loop_Part1(SpcPlayer *p) {
-  Dsp_Write(p, KOF, p->key_OFF);
-  Dsp_Write(p, PMON, p->reg_PMON);
-  Dsp_Write(p, NON, p->reg_NON);
-  Dsp_Write(p, KOF, 0);
-  Dsp_Write(p, KON, p->key_ON);
-  if (!(p->echo_stored_time & 0x80)) {
-    Dsp_Write(p, FLG, p->reg_FLG);
-    if (p->echo_stored_time == p->echo_parameter_EDL) {
-      Dsp_Write(p, EON, p->reg_EON);
-      Dsp_Write(p, EFB, p->reg_EFB);
-      Dsp_Write(p, EVOLR, p->echo_volume_right >> 8);
-      Dsp_Write(p, EVOLL, p->echo_volume_left >> 8);
-    }
-  }
-  p->key_OFF = p->key_ON = 0;
-}
-
-static void Spc_Loop_Part2(SpcPlayer *p, uint8 ticks) {
-  int t = p->sfx_timer_accum + (uint8)(ticks * 0x38);
-  p->sfx_timer_accum = t;
-  if (t >= 256) {
-    Port1_StartNewSound(p);
-    Port1_HandleCmd(p);
-    ReadPortFromSnes(p, 1);
-
-    Port2_StartNewSound(p);
-    Port2_HandleCmd(p);
-    ReadPortFromSnes(p, 2);
-
-    Port3_StartNewSound(p);
-    Port3_HandleCmd(p);
-    ReadPortFromSnes(p, 3);
-
-    if (p->echo_stored_time != p->echo_parameter_EDL && !(++p->echo_fract_incr & 1))
-      p->echo_stored_time++;
-  }
-
-  t = p->main_tempo_accum + (uint8)(ticks * HIBYTE(p->tempo));
-  p->main_tempo_accum = t;
-  if (t >= 256) {
-    Port0_HandleMusic(p);
-    ReadPortFromSnes(p, 0);
-  } else if (p->port_to_snes[0]) {
-    Channel *c = p->channel;
-    for (p->cur_chan_bit = 1; p->cur_chan_bit != 0; p->cur_chan_bit <<= 1, c++) {
-      if (HIBYTE(c->pattern_order_ptr_for_chan))
-        HandlePanAndSweep(p, c);
-    }
-  }
-}
-
-static void Interrupt_Reset(SpcPlayer *p) {
-  dsp_reset(p->dsp);
-
-  memset(&p->new_value_from_snes, 0, sizeof(SpcPlayer) - offsetof(SpcPlayer, new_value_from_snes));
-  for (int i = 0; i < 8; i++)
-    p->channel[i].index = i;
-  SetupEchoParameter_EDL(p, 1);
-  p->reg_FLG |= 0x20;
-  Dsp_Write(p, MVOLL, 0x60);
-  Dsp_Write(p, MVOLR, 0x60);
-  Dsp_Write(p, DIR, 0x3c);
-  HIBYTE(p->tempo) = 16;
-  p->timer_cycles = 0;
-}
-
-SpcPlayer *SpcPlayer_Create() {
-  SpcPlayer *p = (SpcPlayer *)malloc(sizeof(SpcPlayer));
-  p->dsp = dsp_init(p->ram);
-  p->reg_write_history = 0;
-  return p;
-}
-
-void SpcPlayer_Initialize(SpcPlayer *p) {
-  Interrupt_Reset(p);
-  Spc_Loop_Part1(p);
-}
-
-void SpcPlayer_CopyVariablesToRam(SpcPlayer *p) {
-  Channel *c = p->channel;
-  for (int i = 0; i < 8; i++, c++) {
-    for (const MemMap *m = &kChannel_Maps[0]; m != &kChannel_Maps[countof(kChannel_Maps)]; m++)
-      memcpy(&p->ram[(m->org_off & 0x7fff) + i * 2], (uint8 *)c + m->off, m->org_off & 0x8000 ? 2 : 1);
-  }
-  for (const MemMapSized *m = &kSpcPlayer_Maps[0]; m != &kSpcPlayer_Maps[countof(kSpcPlayer_Maps)]; m++)
-    memcpy(&p->ram[m->org_off], (uint8 *)p + m->off, m->size);
-}
-
-void SpcPlayer_CopyVariablesFromRam(SpcPlayer *p) {
-  Channel *c = p->channel;
-  for (int i = 0; i < 8; i++, c++) {
-    for (const MemMap *m = &kChannel_Maps[0]; m != &kChannel_Maps[countof(kChannel_Maps)]; m++)
-      memcpy((uint8 *)c + m->off, &p->ram[(m->org_off & 0x7fff) + i * 2], m->org_off & 0x8000 ? 2 : 1);
-  }
-  for (const MemMapSized *m = &kSpcPlayer_Maps[0]; m != &kSpcPlayer_Maps[countof(kSpcPlayer_Maps)]; m++)
-    memcpy((uint8 *)p + m->off, &p->ram[m->org_off], m->size);
-}
-
-
-void SpcPlayer_GenerateSamples(SpcPlayer *p) {
-  assert(p->timer_cycles <= 64);
-
-  assert(p->dsp->sampleOffset <= 534);
-
-  for (;;) {
-    if (p->timer_cycles >= 64) {
-      Spc_Loop_Part2(p, p->timer_cycles >> 6);
-      Spc_Loop_Part1(p);
-      p->timer_cycles &= 63;
-    }
-
-    // sample rate 32000
-    int n = 534 - p->dsp->sampleOffset;
-    if (n > (64 - p->timer_cycles))
-      n = (64 - p->timer_cycles);
-
-    p->timer_cycles += n;
-
-    for (int i = 0; i < n; i++)
-      dsp_cycle(p->dsp);
-
-    if (p->dsp->sampleOffset == 534)
-      break;
-  }
-}
-
-void SpcPlayer_Upload(SpcPlayer *p, const uint8_t *data) {
-  Dsp_Write(p, EVOLL, 0);
-  Dsp_Write(p, EVOLR, 0);
-  Dsp_Write(p, KOF, 0xff);
-
-  for (;;) {
-    int numbytes = *(uint16 *)(data);
-    if (numbytes == 0)
-      break;
-    int target = *(uint16 *)(data + 2);
-    data += 4;
-    do {
-      p->ram[target++ & 0xffff] = *data++;
-    } while (--numbytes);
-  }
-  p->pause_music_ctr = 0;
-  p->port_to_snes[0] = 0;
-  p->port1_active = 0;
-  p->port2_active = 0;
-  p->port3_active = 0;
-  p->is_chan_on = 0;
-  p->input_ports[0] = p->input_ports[1] = p->input_ports[2] = p->input_ports[3] = 0;
-}
-
-// =======================================
-#define WITH_SPC_PLAYER_DEBUGGING 0
-
-#if WITH_SPC_PLAYER_DEBUGGING
-
-#include <SDL.h>
-
-static DspRegWriteHistory my_write_hist;
-static SpcPlayer my_spc, my_spc_snapshot;
-static int loop_ctr;
-
-bool CompareSpcImpls(SpcPlayer *p, SpcPlayer *p_org, Apu *apu) {
-  SpcPlayer_CopyVariablesToRam(p);
-  memcpy(p->ram + 0x18, apu->ram + 0x18, 2); //lfsr_value
-  memcpy(p->ram + 0x110, apu->ram + 0x110, 256-16);  // stack
-  memcpy(p->ram + 0xf1, apu->ram + 0xf1, 15);  // dsp regs
-  memcpy(p->ram + 0x10, apu->ram + 0x10, 8);  // temp regs
-  p->ram[0x44] = apu->ram[0x44]; // chn
-  int errs = 0;
-  for (int i = 0; i != 0xc000; i++) {  // skip compare echo etc
-    if (p->ram[i] != apu->ram[i]) {
-      if (errs < 16) {
-        if (errs == 0)
-          printf("@%d\n", loop_ctr);
-        printf("%.4X: %.2X != %.2X (mine, theirs) orig %.2X\n", i, p->ram[i], apu->ram[i], p_org->ram[i]);
-        errs++;
-      }
-    }
-  }
-
-  int n = my_write_hist.count < apu->hist.count ? apu->hist.count : my_write_hist.count;
-  for (int i = 0; i != n; i++) {
-    if (i >= my_write_hist.count || i >= apu->hist.count || my_write_hist.addr[i] != apu->hist.addr[i] || my_write_hist.val[i] != apu->hist.val[i]) {
-      if (errs == 0)
-        printf("@%d\n", loop_ctr);
-      printf("%d: ", i);
-      if (i >= my_write_hist.count) printf("[??: ??]"); else printf("[%.2x: %.2x]", my_write_hist.addr[i], my_write_hist.val[i]);
-      printf(" != ");
-      if (i >= apu->hist.count) printf("[??: ??]"); else printf("[%.2x: %.2x]", apu->hist.addr[i], apu->hist.val[i]);
-      printf("\n");
-      errs++;
-    }
-  }
-
-  if (errs) {
-    printf("Total %d errors\n", errs);
-    return false;
-  }
-
-  apu->hist.count = 0;
-  my_write_hist.count = 0;
-  loop_ctr++;
-  return true;
-}
-
-void RunAudioPlayer() {
-  if(SDL_Init(SDL_INIT_AUDIO) != 0) {
-    printf("Failed to init SDL: %s\n", SDL_GetError());
-    return;
-  }
-  
-  SDL_AudioSpec want, have;
-  SDL_AudioDeviceID device;
-  SDL_memset(&want, 0, sizeof(want));
-  want.freq = 44100;
-  want.format = AUDIO_S16;
-  want.channels = 2;
-  want.samples = 2048;
-  want.callback = NULL; // use queue
-  device = SDL_OpenAudioDevice(NULL, 0, &want, &have, 0);
-  if(device == 0) {
-    printf("Failed to open audio device: %s\n", SDL_GetError());
-    return;
-  }
-  int16_t* audioBuffer = (int16_t*)malloc(735 * 4); // *2 for stereo, *2 for sizeof(int16)
-  SDL_PauseAudioDevice(device, 0);
-
-  memset(&my_spc, 0, sizeof(my_spc));
-  FILE *f = fopen("lightworld.spc", "rb");
-  fread(my_spc.ram, 1, 65536, f);
-  fclose(f);
-
-  my_spc.reg_write_history = &my_write_hist;
-
-  bool run_both = 0;// false;// false;
-
-  if (!run_both) {
-    SpcPlayer *p = &my_spc;
-    Dsp *dsp = dsp_init(p->ram);
-    dsp_reset(dsp);
-    p->dsp = dsp;
-    SpcPlayer_Initialize(p);
-
-    p->input_ports[0] = 4;
-
-    for (;;) {
-      SpcPlayer_GenerateSamples(p);
-
-      int16_t audioBuffer[736 * 2];
-      dsp_getSamples(p->dsp, audioBuffer, 736, have.channels);
-      SDL_QueueAudio(device, audioBuffer, 736 * 2 * have.channels);
-      while (SDL_GetQueuedAudioSize(device) >= 736 * 4 * 3/* 44100 * 4 * 300*/)
-        SDL_Delay(1);
-
-    }
-
-  } else {
-    SpcPlayer *p = &my_spc;
-    Dsp *dsp = dsp_init(p->ram);
-    dsp_reset(dsp);
-    p->dsp = dsp;
-
-    Apu *apu = apu_init();
-    apu_reset(apu);
-    apu->spc->pc = 0x800;
-
-    memcpy(apu->ram, my_spc.ram, 65536);
-
-    CompareSpcImpls(&my_spc, &my_spc_snapshot, apu);
-
-    uint64_t cycle_counter = 0;
-    int tgt = 0x878;
-    uint8 ticks_next = 0;
-    bool apu_debug = false;
-    bool is_initialize = true;
-    for (;;) {
-      if (apu_debug && apu->cpuCyclesLeft == 0) {
-        char line[80];
-        getProcessorStateSpc(apu, line);
-        puts(line);
-      }
-
-      apu_cycle(apu);
-
-      if (((apu->cycles - 1) & 0x1f) == 0)
-        dsp_cycle(p->dsp);
-
-
-      if (apu->spc->pc == tgt) {
-        tgt ^= 0x878 ^ 0x879;
-        if (tgt == 0x878) {
-          uint8 ticks = ticks_next;
-          ticks_next = apu->spc->y;
-          my_spc_snapshot = my_spc;
-          for (;;) {
-            my_write_hist.count = 0;
-            if (is_initialize)
-              SpcPlayer_Initialize(&my_spc);
-            else {
-              Spc_Loop_Part2(&my_spc, ticks);
-              Spc_Loop_Part1(&my_spc);
-            }
-            is_initialize = false;
-            if (CompareSpcImpls(&my_spc, &my_spc_snapshot,apu))
-              break;
-            my_spc = my_spc_snapshot;
-          }
-
-          if (cycle_counter == 0)
-            apu->inPorts[0] = my_spc.input_ports[0] = 2;// 2 + cycle_counter / 1000;
-          cycle_counter++;
-        }
-      }
-
-      if (p->dsp->sampleOffset == 534) {
-        int16_t audioBuffer[736 * 2];
-        dsp_getSamples(p->dsp, audioBuffer, 736, have.channels);
-        SDL_QueueAudio(device, audioBuffer, 736 * 2 * have.channels);
-        while (SDL_GetQueuedAudioSize(device) >= 736 * 4 * 3/* 44100 * 4 * 300*/) {
-          SDL_Delay(1);
-        }
-      }
-    }
-  }
-}
-#endif  // WITH_SPC_PLAYER_DEBUGGING
\ No newline at end of file
--- a/spc_player.h
+++ /dev/null
@@ -1,145 +1,0 @@
-#include <stddef.h>
-#include "snes/dsp.h"
-
-typedef struct Channel {
-  uint16 pattern_order_ptr_for_chan;
-  uint8 note_ticks_left;
-  uint8 note_keyoff_ticks_left;
-  uint8 subroutine_num_loops;
-  uint8 volume_fade_ticks;
-  uint8 pan_num_ticks;
-  uint8 pitch_slide_length;
-  uint8 pitch_slide_delay_left;
-  uint8 vibrato_hold_count;
-  uint8 vib_depth;
-  uint8 tremolo_hold_count;
-  uint8 tremolo_depth;
-  uint8 vibrato_change_count;
-  uint8 note_length;
-  uint8 note_gate_off_fixedpt;
-  uint8 channel_volume_master;
-  uint8 instrument_id;
-  uint16 instrument_pitch_base;
-  uint16 saved_pattern_ptr;
-  uint16 pattern_start_ptr;
-  uint8 pitch_envelope_num_ticks;
-  uint8 pitch_envelope_delay;
-  uint8 pitch_envelope_direction;
-  uint8 pitch_envelope_slide_value;
-  uint8 vibrato_count;
-  uint8 vibrato_rate;
-  uint8 vibrato_delay_ticks;
-  uint8 vibrato_fade_num_ticks;
-  uint8 vibrato_fade_add_per_tick;
-  uint8 vibrato_depth_target;
-  uint8 tremolo_count;
-  uint8 tremolo_rate;
-  uint8 tremolo_delay_ticks;
-  uint8 channel_transposition;
-  uint16 channel_volume;
-  uint16 volume_fade_addpertick;
-  uint8 volume_fade_target;
-  uint8 final_volume;
-  uint16 pan_value;
-  uint16 pan_add_per_tick;
-  uint8 pan_target_value;
-  uint8 pan_flag_with_phase_invert;
-  uint16 pitch;
-  uint16 pitch_add_per_tick;
-  uint8 pitch_target;
-  uint8 fine_tune;
-  uint16 sfx_sound_ptr;
-  uint8 sfx_which_sound;
-  uint8 sfx_arr_countdown;
-  uint8 sfx_note_length_left;
-  uint8 sfx_note_length;
-  uint8 sfx_pan;
-  uint8 index;
-} Channel;
-
-typedef struct SpcPlayer {
-  DspRegWriteHistory *reg_write_history;
-  uint8 timer_cycles;
-  Dsp *dsp;
-  uint8 new_value_from_snes[4];
-  uint8 port_to_snes[4];
-  uint8 last_value_from_snes[4];
-  uint8 counter_sf0c;
-  uint16 _always_zero;
-  uint16 temp_accum;
-  uint8 ttt;
-  uint8 did_affect_volumepitch_flag;
-  uint16 addr0;
-  uint16 addr1;
-  uint16 lfsr_value;
-  uint8 is_chan_on;
-  uint8 fast_forward;
-  uint8 sfx_start_arg_pan;
-  uint16 sfx_sound_ptr_cur;
-  uint16 music_ptr_toplevel;
-  uint8 block_count;
-  uint8 sfx_timer_accum;
-  uint8 chn;
-  uint8 key_ON;
-  uint8 key_OFF;
-  uint8 cur_chan_bit;
-  uint8 reg_FLG;
-  uint8 reg_NON;
-  uint8 reg_EON;
-  uint8 reg_PMON;
-  uint8 echo_stored_time;
-  uint8 echo_parameter_EDL;
-  uint8 reg_EFB;
-  uint8 global_transposition;
-  uint8 main_tempo_accum;
-  uint16 tempo;
-  uint8 tempo_fade_num_ticks;
-  uint8 tempo_fade_final;
-  uint16 tempo_fade_add;
-  uint16 master_volume;
-  uint8 master_volume_fade_ticks;
-  uint8 master_volume_fade_target;
-  uint16 master_volume_fade_add_per_tick;
-  uint8 vol_dirty;
-  uint8 percussion_base_id;
-  uint16 echo_volume_left;
-  uint16 echo_volume_right;
-  uint16 echo_volume_fade_add_left;
-  uint16 echo_volume_fade_add_right;
-  uint8 echo_volume_fade_ticks;
-  uint8 echo_volume_fade_target_left;
-  uint8 echo_volume_fade_target_right;
-  uint8 sfx_channel_index;
-  uint8 current_bit;
-  uint8 dsp_register_index;
-  uint8 echo_channels;
-  uint8 byte_3C4;
-  uint8 byte_3C5;
-  uint8 echo_fract_incr;
-  uint8 sfx_channel_index2; 
-  uint8 sfx_channel_bit;
-  uint8 pause_music_ctr;
-  uint8 port2_active;
-  uint8 port2_current_bit;
-  uint8 port3_active;
-  uint8 port3_current_bit;
-  uint8 port1_active;
-  uint8 port1_current_bit;
-  uint8 byte_3E1;
-  uint8 sfx_play_echo_flag;
-  uint8 sfx_channels_echo_mask2;
-  uint8 port1_counter;
-  uint8 channel_67_volume;
-  uint8 cutk_always_zero;
-  uint8 last_written_edl;
-  uint8 input_ports[4];
-  Channel channel[8];
-  uint8 ram[65536]; // rest of ram
-} SpcPlayer;
-
-SpcPlayer *SpcPlayer_Create();
-void SpcPlayer_GenerateSamples(SpcPlayer *p);
-void SpcPlayer_Initialize(SpcPlayer *p);
-void SpcPlayer_Upload(SpcPlayer *p, const uint8_t *data);
-void SpcPlayer_CopyVariablesFromRam(SpcPlayer *p);
-void SpcPlayer_CopyVariablesToRam(SpcPlayer *p);
--- a/sprite.c
+++ /dev/null
@@ -1,4328 +1,0 @@
-#include "sprite.h"
-#include "dungeon.h"
-#include "hud.h"
-#include "load_gfx.h"
-#include "overworld.h"
-#include "variables.h"
-#include "tagalong.h"
-#include "overlord.h"
-#include "ancilla.h"
-#include "player.h"
-#include "misc.h"
-#include "overlord.h"
-#include "tile_detect.h"
-#include "sprite_main.h"
-#include "assets.h"
-static const uint16 kOamGetBufferPos_Tab0[6] = {0x171, 0x201, 0x31, 0xc1, 0x141, 0x1d1};
-static const uint16 kOamGetBufferPos_Tab1[48] = {
-   0x30,  0x50,  0x80,  0xb0,  0xe0, 0x110, 0x140, 0x170, 0x1d0, 0x1d4, 0x1dc, 0x1e0, 0x1e4, 0x1ec, 0x1f0, 0x1f8,
-      0,     4,     8,   0xc,  0x10,  0x14,  0x18,  0x1c,  0x30,  0x38,  0x50,  0x68,  0x80,  0x98,  0xb0,  0xc8,
-  0x120, 0x124, 0x128, 0x12c, 0x130, 0x134, 0x138, 0x13c, 0x140, 0x150, 0x160, 0x170, 0x180, 0x190, 0x1a0, 0x1b8,
-};
-static const uint8 kSprite2_ReturnIfRecoiling_Masks[6] = {3, 1, 0, 0, 0xc, 3};
-static const int8 kSpriteHitbox_XLo[32] = {
-  2, 3, 0, -3, -6, 0, 2, -8, 0, -4, -8, 0, -8, -16, 2, 2,
-  2, 2, 2, -8, 2, 2, -16, -8, -12, 4, -4, -12, 5, -32, -2, 4,
-};
-static const int8 kSpriteHitbox_XHi[32] = {
-  0, 0, 0, -1, -1, 0, 0, -1, 0, -1, -1, 0, -1, -1, 0, 0,
-  0, 0, 0, -1, 0, 0, -1, -1, -1, 0, -1, -1, 0, -1, -1, 0,
-};
-static const uint8 kSpriteHitbox_XSize[32] = {
-  12, 1, 16, 20, 20, 8, 4, 32, 48, 24, 32, 32, 32, 48, 12, 12,
-  60, 124, 12, 32, 4, 12, 48, 32, 40, 8, 24, 24, 5, 80, 4, 8,
-};
-static const int8 kSpriteHitbox_YLo[32] = {
-  0, 3, 4, -4, -8, 2, 0, -16, 12, -4, -8, 0, -10, -16, 2, 2,
-  2, 2, -3, -12, 2, 10, 0, -12, 16, 4, -4, -12, 3, -16, -8, 10,
-};
-static const int8 kSpriteHitbox_YHi[32] = {
-  0, 0, 0, -1, -1, 0, 0, -1, 0, -1, -1, 0, -1, -1, 0, 0,
-  0, 0, -1, -1, 0, 0, 0, -1, 0, 0, -1, -1, 0, -1, -1, 0,
-};
-static const uint8 kSpriteHitbox_YSize[32] = {
-  14, 1, 16, 21, 24, 4, 8, 40, 20, 24, 40, 29, 36, 48, 60, 124,
-  12, 12, 17, 28, 4, 2, 28, 20, 10, 4, 24, 16, 5, 48, 8, 12,
-};
-static const uint8 kSpriteDamage_Tab2[4] = {6, 4, 0, 0};
-static const uint8 kSpriteDamage_Tab3[4] = {4, 6, 0, 2};
-static const uint8 kSprite_Func21_Sfx[9] = {0x1f, 0x1f, 0x1e, 0x1e, 0x1e, 0x1f, 0x1f, 0x1f, 0x1f};
-static const int8 kSparkleGarnish_XY[4] = {-4, 12, 3, 8};
-static const uint8 kSpriteStunned_Main_Func1_Masks[7] = {0x7f, 0xf, 3, 1, 0, 0, 0};
-static const uint8 kSprite_Func7_Tab[4] = {8, 4, 2, 1};
-static const int8 kSprite_Func5_X[54] = {
-  8, 8, 2, 14, 8, 8, -2, 10, 8, 8, 1, 14, 4, 4, 4, 4,
-  4, 4, -2, 10, 8, 8, -25, 40, 8, 8, 2, 14, 8, 8, -8, 23,
-  8, 8, -20, 36, 8, 8, -1, 16, 8, 8, -1, 16, 8, 8, -8, 24,
-  8, 8, -8, 24, 8, 3,
-};
-static const int8 kSprite_Func5_Y[54] = {
-  6, 20, 13, 13, 0, 8, 4, 4, 1, 14, 8, 8, 4, 4, 4, 4,
-  -2, 10, 4, 4, -25, 40, 8, 8, 3, 16, 10, 10, -8, 25, 8, 8,
-  -20, 36, 8, 8, -1, 16, 8, 8, 14, 3, 8, 8, -8, 24, 8, 8,
-  -8, 32, 8, 8, 12, 4,
-};
-static const uint8 kSprite_SimplifiedTileAttr[256] = {
-  0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0,
-  1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 3, 3, 3,
-  0, 0, 0, 0, 0, 0, 1, 1, 4, 4, 4, 4, 4, 4, 4, 4,
-  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1,
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4,
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1,
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-};
-static const int8 kSprite_Func5_Tab3[256] = {
-  0, 1, 2, 3, 2, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0,
-  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1,
-  1, 1, 1, 0, 0, 0, 1, 2, -1, -1, -1, -1, -1, -1, -1, -1,
-  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1,
-  0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, -1, -1, -1, -1,
-  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-  0, 0, 0, 0, 0, 1, 0, 2, 0, 0, 0, 0, 1, 1, 1, 1,
-  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-};
-static const int8 kSlopedTile[32] = {
-  7, 6, 5, 4, 3, 2, 1, 0,
-  0, 1, 2, 3, 4, 5, 6, 7,
-  0, 1, 2, 3, 4, 5, 6, 7,
-  7, 6, 5, 4, 3, 2, 1, 0,
-};
-static const uint8 kSprite_Func1_Tab[8] = {15, 15, 24, 15, 15, 19, 15, 15};
-static const uint8 kSprite_Func1_Tab2[8] = {6, 6, 6, 12, 6, 6, 6, 15};
-static const uint8 kSprite_Func14_Damage[12] = {1, 2, 3, 4, 2, 3, 4, 5, 1, 1, 2, 3};
-static const uint8 kEnemyDamages[128] = {
-  0, 1, 32, 255, 252, 251, 0, 0, 0, 2, 64, 4, 0, 0, 0, 0,
-  0, 4, 64, 2, 3, 0, 0, 0, 0, 8, 64, 4, 0, 0, 0, 0,
-  0, 16, 64, 8, 0, 0, 0, 0, 0, 16, 64, 8, 0, 0, 0, 0,
-  0, 4, 64, 16, 0, 0, 0, 0, 0, 255, 64, 255, 252, 251, 0, 0,
-  0, 4, 64, 255, 252, 251, 32, 0, 0, 100, 24, 100, 0, 0, 0, 0,
-  0, 249, 250, 255, 100, 0, 0, 0, 0, 8, 64, 253, 4, 16, 0, 0,
-  0, 8, 64, 254, 4, 0, 0, 0, 0, 16, 64, 253, 0, 0, 0, 0,
-  0, 254, 64, 16, 0, 0, 0, 0, 0, 32, 64, 255, 0, 0, 0, 250,
-};
-static const uint8 kSpriteInit_Flags2[243] = {
-     1,    2,    1, 0x82, 0x81, 0x84, 0x84, 0x84,    2,  0xf,    2,    1, 0x20,    3,    4, 0x84,
-     1,    5,    4,    1, 0x80,    4, 0xa2, 0x83,    4,    2, 0x82, 0x62, 0x82, 0x80, 0x80, 0x85,
-     1, 0xa5,    3,    4,    4, 0x83,    2,    1, 0x82, 0xa2, 0xa2, 0xa3, 0xaa, 0xa3, 0xa4, 0x82,
-  0x82, 0x83, 0x82, 0x80, 0x82, 0x82, 0xa5, 0x80, 0xa4, 0x82, 0x81, 0x82, 0x82, 0x82, 0x81,    6,
-     8,    8,    8,    8,    6,    8,    8,    8,    6,    7,    7,    2,    2, 0x22,    1,    1,
-  0x20, 0x82,    7, 0x85,  0xf, 0x21,    5, 0x83,    2,    1,    1,    1,    1,    7,    7,    7,
-     7,    0, 0x85, 0x83,    3, 0xa4,    0,    0,    0,    0,    9,    4, 0xa0,    0,    1,    0,
-     0,    3, 0x8b, 0x86, 0xc2, 0x82, 0x81,    4, 0x82, 0x21,    6,    3,    1,    3,    3,    3,
-     0,    0,    4,    5,    5,    3,    1,    2,    0,    0,    0,    2,    7,    0,    1,    1,
-  0x87,    6,    0, 0x83,    2, 0x22, 0x22, 0x22, 0x22,    4,    3,    5,    1,    1,    4,    1,
-     2,    8,    8, 0x80, 0x21,    3,    3,    3,    2,    2,    8, 0x8f, 0xa1, 0x81, 0x80, 0x80,
-  0x80, 0x80, 0xa1, 0x80, 0x81, 0x81, 0x86, 0x81, 0x82, 0x82, 0x80, 0x80, 0x83,    6,    0,    0,
-     5,    4,    6,    5,    2,    0,    0,    5,    4,    4,    7,  0xb,  0xc,  0xc,    6,    6,
-     3, 0xa4,    4, 0x82, 0x81, 0x83, 0x10, 0x10, 0x81, 0x82, 0x82, 0x82, 0x83, 0x83, 0x83, 0x81,
-  0x82, 0x83, 0x83, 0x81, 0x82, 0x81, 0x82, 0xa0, 0xa1, 0xa3, 0xa1, 0xa1, 0xa1, 0x83, 0x85, 0x83,
-  0x83, 0x83, 0x83,
-};
-static const uint8 kSpriteInit_Health[243] = {
-   12,   6, 255,   3,  3,   3,   3,   3,   2,  12,  4, 255,   0,   3,  12,   2,
-    0,  20,   4,   4,  0, 255,   0,   2,   3,   8,  0,   0,   0,   0,   0,   0,
-    8,   3,   8,   2,  2,   0,   3, 255,   0,   3,  3,   3,   3,   3,   3,   3,
-    3,   0,   3,   0,  3,   3,   3,   0,   3,   0,  0,   0,   0,   3,   2, 255,
-    2,   6,   4,   8,  6,   8,   6,   4,   8,   8,  8,   4,   4,   2,   2,   2,
-  255,   8, 255,  48, 16,   8,   8, 255,   2,   0,  0, 255, 255, 255, 255, 255,
-  255, 255, 255, 255,  4,   4, 255, 255, 255, 255, 16,   3,   0,   2,   4,   1,
-  255,   4, 255,   0,  0,   0,   0, 255,   0,   0, 96, 255,  24, 255, 255, 255,
-    3,   4, 255,  16,  8,   8,   0, 255,  32,  32, 32,  32,  32,   8,   8,   4,
-    8,  64,  48, 255,  2, 255, 255, 255, 255,  16,  4,   2,   4,   4,   8,   8,
-    8,  16,  64,  64,  8,   4,   8,   4,   4,   8, 12,  16,   0,   0,   0,   0,
-    0,   0,   0,   0,  0,   0,   0,   0,   0,   0,  0,   0,   0, 128,  48, 255,
-  255, 255, 255,   8,  0,   0,   0,  32,   0,   8,  5,  40,  40,  40,  90,  16,
-   24,  64,   0,   4,  0,   0, 255, 255,   0,   0,  0,   0,   0,   0,   0,   0,
-    0,   0,   0,   0,  0,   0,   0,   0,   0,   0,  0,   0,   0,   0,   0,   0,
-    0,   0,   0,
-};
-const uint8 kSpriteInit_BumpDamage[243] = {
-  0x83, 0x83, 0x81,    2,    2,    2,    2,    2,    1, 0x13,    1,    1,    1,    1,    8,    1,
-     1,    8,    5,    3, 0x40,    4,    0,    2,    3, 0x85,    0,    1,    0, 0x40,    0,    0,
-     6,    0,    5,    3,    1,    0,    0,    3,    0,    0,    0,    0,    0,    0,    0,    0,
-     0,    0,    0,    0,    0,    0,    0, 0x40,    0,    0,    0,    0,    0,    0,    2,    2,
-     0,    1,    1,    3,    1,    3,    1,    1,    3,    3,    3,    1,    3,    1,    1,    1,
-     1,    1,    1, 0x11, 0x14,    1,    1,    2,    5,    0,    0,    4,    4,    8,    8,    8,
-     8,    4,    0,    4,    3,    2,    2,    2,    2,    2,    3,    1,    0,    0,    1, 0x80,
-     5,    1,    0,    0,    0, 0x40,    0,    4,    0,    0, 0x14,    4,    6,    4,    4,    4,
-     4,    3,    4,    4,    4,    1,    4,    4, 0x15,    5,    4,    5, 0x15, 0x15,    3,    5,
-     0,    5, 0x15,    5,    5,    6,    6,    6,    6,    5,    3,    6,    5,    5,    3,    3,
-     3,    6, 0x17, 0x15, 0x15,    5,    5,    1, 0x85, 0x83,    5,    4,    0,    0,    0,    0,
-     0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0, 0x17, 0x17,    5,
-     5,    5,    4,    3,    2, 0x10,    0,    6,    0,    5,    7, 0x17, 0x17, 0x17, 0x15,    7,
-     6, 0x10,    0,    3,    3,    0, 0x19, 0x19,    0,    0,    0,    0,    0,    0,    0,    0,
-     0,    0,    0, 0x10,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
-     0,    0,    0,
-};
-static const uint8 kSpriteInit_Flags3[243] = {
-  0x19,  0xb, 0x1b, 0x4b, 0x41, 0x41, 0x41, 0x4d, 0x1d,    1, 0x1d, 0x19, 0x8d, 0x1b,    9, 0x9d,
-  0x3d,    1,    9, 0x11, 0x40,    1, 0x4d, 0x19,    7, 0x1d, 0x59, 0x80, 0x4d, 0x40,    1, 0x49,
-  0x1b, 0x41,    3, 0x13, 0x15, 0x41, 0x18, 0x1b, 0x41, 0x47,  0xf, 0x49, 0x4b, 0x4d, 0x41, 0x47,
-  0x49, 0x4d, 0x49, 0x40, 0x4d, 0x47, 0x49, 0x41, 0x74, 0x47, 0x5b, 0x58, 0x51, 0x49, 0x1d, 0x5d,
-     3, 0x19, 0x1b, 0x17, 0x19, 0x17, 0x19, 0x1b, 0x17, 0x17, 0x17, 0x1b,  0xd,    9, 0x19, 0x19,
-  0x49, 0x5d, 0x5b, 0x49,  0xd,    3, 0x13, 0x41, 0x1b, 0x5b, 0x5d, 0x43, 0x43, 0x4d, 0x4d, 0x4d,
-  0x4d, 0x4d, 0x49,    1,    0, 0x41, 0x4d, 0x4d, 0x4d, 0x4d, 0x1d,    9, 0xc4,  0xd,  0xd,    9,
-     3,    3, 0x4b, 0x47, 0x47, 0x49, 0x49, 0x41, 0x47, 0x36, 0x8b, 0x49, 0x1d, 0x49, 0x43, 0x43,
-  0x43,  0xb, 0x41,  0xd,    7,  0xb, 0x1d, 0x43,  0xd, 0x43,  0xd, 0x1d, 0x4d, 0x4d, 0x1b, 0x1b,
-   0xa,  0xb,    0,    5,  0xd,    1,    1,    1,    1,  0xb,    5,    1,    1,    1,    7, 0x17,
-  0x19,  0xd,  0xd, 0x80, 0x4d, 0x19, 0x17, 0x19,  0xb,    9,  0xd, 0x4a, 0x12, 0x49, 0xc3, 0xc3,
-  0xc3, 0xc3, 0x76, 0x40, 0x59, 0x41, 0x58, 0x4f, 0x73, 0x5b, 0x44, 0x41, 0x51,  0xa,  0xb,  0xb,
-  0x4b,    0, 0x40, 0x5b,  0xd,    0,    0,  0xd, 0x4b,  0xb, 0x59, 0x41,  0xb,  0xd,    1,  0xd,
-   0xd,    0, 0x50, 0x4c, 0x44, 0x51,    1,    1, 0xf2, 0xf8, 0xf4, 0xf2, 0xd4, 0xd4, 0xd4, 0xf8,
-  0xf8, 0xf4, 0xf4, 0xd8, 0xf8, 0xd8, 0xdf, 0xc8, 0x69, 0xc1, 0xd2, 0xd2, 0xdc, 0xc7, 0xc1, 0xc7,
-  0xc7, 0xc7, 0xc1,
-};
-static const uint8 kSpriteInit_Flags4[243] = {
-     0,    0,    0, 0x43, 0x43, 0x43, 0x43, 0x43,    0,    0,    0,    0, 0x1c,    0,    0,    2,
-     1,    3,    0,    0,    3, 0xc0,    7,    0,    0,    0,    7, 0x45, 0x43,    0, 0x40,  0xd,
-     0,    0,    0,    0,    0,    0,    0,    0,    7,    7,    7,    7,    7,    7,  0xd,    7,
-     7,    7,    7,    3,    7,    7,    7, 0x40,    3,    7,  0xd,    0,    7,    7,    0,    0,
-     9, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12,    0,    0,    0,    0,
-  0x80, 0x12,    9,    9,    0, 0x40,    0,  0xc,    0,    0,    0, 0x40, 0x40, 0x10, 0x10, 0x2e,
-  0x2e, 0x40, 0x1e, 0x53,    0,  0xa,    0,    0,    0,    0, 0x12, 0x12, 0x40,    0,    0, 0x40,
-  0x19,    0,    0,  0xa,  0xd,  0xa,  0xa, 0x80,  0xa, 0x41,    0, 0x40,    0, 0x49,    0,    0,
-  0xc0,    0, 0x40,    0,    0, 0x40,    0,    0,    9, 0x80, 0xc0,    0, 0x40,    0,    0, 0x80,
-     0,    0, 0x18, 0x5a,    0, 0xd4, 0xd4, 0xd4, 0xd4,    0, 0x40,    0, 0x80, 0x80, 0x40, 0x40,
-  0x40,    0,    9, 0x1d,    0,    0,    0,    0,    0,    0,    0,    0,    0,  0xa, 0x1b, 0x1b,
-  0x1b, 0x1b, 0x41,    0,    3,    7,    7,    3,  0xa,    0,    1,  0xa,  0xa,    9,    0,    0,
-     0,    0,    9,    0,    0, 0x40, 0x40,    0,    0,    0,    0, 0x89, 0x80, 0x80,    0, 0x1c,
-     0, 0x40,    0,    0, 0x1c,    7,    3,    3, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44,
-  0x44, 0x44, 0x44, 0x43, 0x44, 0x43, 0x40, 0xc0, 0xc0, 0xc7, 0xc3, 0xc3, 0xc0, 0x1b,    8, 0x1b,
-  0x1b, 0x1b,    3,
-};
-static const uint8 kSpriteInit_Flags[243] = {
-     0,    0,    0,    0,    0,    0,    0,    0,    0,  0xa,    0,    1, 0x30,    0, 0, 0x20,
-  0x10,    0,    0,    1,    0,    0,    0,    0,    0,    0,    0,    8, 0x20,    0, 4,    0,
-     0,    0,    0,    0,    0,    0,    1,    4,    0,    0,    0,    0,    0,    0, 0,    0,
-     0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0, 0, 0x68,
-  0x60, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61,    0,    0, 0,    0,
-     0,    0,    2,    2,    2,    0,    0, 0x70,    0,    0,    0, 0x90, 0x90,    0, 0,    0,
-     0,    0,    0,    0,    0,    0,    0,    0,    0,    0, 0x60, 0x60,    0,    0, 0,    0,
-     0,    0,    0,    0,    0,    0,    0, 0x80,    0,    0,    2,    0,    0, 0x70, 0,    0,
-     0,    0,    0,    0,    0,    0, 0xb0,    0, 0xc2,    0, 0x20,    0,    2,    0, 0,    0,
-     0,    0,    2,    0, 0xb0,    0,    0,    0,    0,    0,    0,    0, 0xa0, 0xa0, 0,    0,
-     0,    4,    2,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0, 0,    0,
-     0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0, 0xc2, 0,    0,
-     0,    0,    0,    0,    4,    0,    0,    0,    0,    0,    0,    2,    2,    2, 2,    0,
-     0,    0,    0,    0,    0,    0,  0xa,  0xa, 0x10, 0x10, 0x10, 0x10,    0,    0, 0, 0x10,
-  0x10, 0x10, 0x10,    0, 0x10,    0,    0,    0,    0,    0,    0,    0,    0,    0, 0,    0,
-     0,    0,    0,
-};
-static const uint8 kSpriteInit_Flags5[243] = {
-  0x83, 0x96, 0x84, 0x80, 0x80, 0x80, 0x80, 0x80,    2,    0,    2, 0x80, 0xa0, 0x83, 0x97, 0x80,
-  0x80, 0x94, 0x91,    7,    0, 0x80,    0, 0x80, 0x92, 0x96, 0x80, 0xa0,    0,    0,    0, 0x80,
-     4, 0x80, 0x82,    6,    6,    0,    0, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
-  0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,    0,    0, 0x80, 0x80, 0x90,
-  0x80, 0x91, 0x91, 0x91, 0x97, 0x91, 0x95, 0x95, 0x93, 0x97, 0x14, 0x91, 0x92, 0x81, 0x82, 0x82,
-  0x80, 0x85, 0x80, 0x80, 0x80,    4,    4, 0x80, 0x91, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
-  0x80,    0, 0x80, 0x80, 0x82, 0x8a, 0x80, 0x80, 0x80, 0x80, 0x92, 0x91, 0x80, 0x82, 0x81, 0x81,
-  0x80, 0x81, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x97, 0x80, 0x80, 0x80,
-  0x80, 0xc2, 0x80, 0x15, 0x15, 0x17,    6,    0, 0x80,    0, 0xc0, 0x13, 0x40,    0,    2,    6,
-  0x10, 0x14,    0,    0, 0x40,    0,    0,    0,    0, 0x13, 0x46, 0x11, 0x80, 0x80,    0,    0,
-     0, 0x10,    0,    0,    0, 0x16, 0x16, 0x16, 0x81, 0x87, 0x82,    0, 0x80, 0x80,    0,    0,
-     0,    0, 0x80, 0x80,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
-     0,    0,    0, 0x80,    0,    0,    0, 0x17,    0, 0x12,    0,    0,    0,    0,    0, 0x10,
-  0x17,    0, 0x40,    1,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
-     0,    0,    0, 0x40,    0,    0,    0,    0,    0,    0,    0,    0, 0x80,    0,    0,    0,
-     0,    0,    0,
-};
-static const uint8 kSpriteInit_DeflBits[243] = {
-     0,    0, 0x44, 0x20, 0x20, 0x20, 0x20, 0x20,    0, 0x81,    0,    0, 0x48,    0,    0,    0,
-     0,    0,    0,    0,    0,    0,    4,    0,    0,    0,    0, 0x48, 0x24, 0x80,    0,    0,
-     0, 0x20,    0,    0,    0, 0x80,    0,    0,    0,    0,    0,    0,    0,    0,    0, 0x80,
-  0x80,    0,    0,    0,    0,    0,    0, 0x80,    0, 0x80,    0,    2,    0,    0,    0,    4,
-  0x80,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
-  0x84,    0, 0x81,    5,    1, 0x40,    8, 0xa0,    0,    0,    0,    0,    0, 0x84, 0x84, 0x84,
-  0x84,    8, 0x80, 0x80, 0x80,    0, 0x80, 0x80, 0x80, 0x80,    0,    8, 0x80,    0,    0,    0,
-  0x40,    0,    0,    0,    0,    0,    0,    0,    0,    2,    1,    0,    0,    4,    0,    0,
-     0,    0, 0x80,    4,    4,    0,    0, 0x48,    0,    0,    4,    0,    1,    1,    0,    0,
-  0x80,    0,    0,    0, 0x40,    8,    8,    8,    8,    0,    0,    0, 0x80, 0x80,    0,    0,
-     0,    4,    1,    5,    0,    0,    0,    0,    0,    0,    0,    4,    2,    0, 0x80, 0x80,
-  0x80, 0x80, 0x82, 0x80,    0,    0, 0x80,    0,    0, 0x80, 0x80,    0,    0,    1,    1, 0x40,
-     0,    0,    4,    0,    0,    0,    0,    0,    0,    0,    4,    5,    5,    5, 0x80, 0x80,
-     0,    0,    0,    0,    0,    0,    0,    0,    2,    2,    2,    2,    2,    2,    2,    2,
-     2,    2,    2,    2,    2,    2,    2,    2,    2,    0, 0x82, 0x82,    8, 0x80, 0x20, 0x80,
-  0x80, 0x80, 0x20,
-};
-static const int8 kPlayerDamages[30] = {
-  2, 1, 1, 4, 4, 4, 0, 0, 0, 8, 4, 2, 8, 8, 8, 16,
-  8, 4, 32, 16, 8, 32, 24, 16, 24, 16, 8, 64, 48, 24,
-};
-static const uint8 kPlayerActionBoxRun_YHi[4] = {0xff, 0, 0, 0};
-static const uint8 kPlayerActionBoxRun_YLo[4] = {(uint8)-8, 16, 8, 8};
-static const uint8 kPlayerActionBoxRun_XHi[4] = {0, 0, 0xff, 0};
-static const uint8 kPlayerActionBoxRun_XLo[4] = {0, 0, (uint8)-8, 8};
-static const int8 kPlayer_SetupActionHitBox_X[65] = {
-  0, 2, 0, 0, -8, 0, 2, 0, 2, 2, 1, 1, 0, 0, 0, 0,
-  0, 2, 4, 4, 0, 0, -4, -4, -6, 2, 1, 1, 0, 0, 0, 0,
-  0, 0, 0, 0, 2, 2, 4, 4, 2, 2, 2, 2, 0, 0, 0, 0,
-  0, 0, 0, 0, -4, -4, -10, 0, 2, 2, 0, 0, 0, 0, 0, 0,
-  0,
-};
-static const int8 kPlayer_SetupActionHitBox_W[65] = {
-  15, 4, 8, 8, 8, 8, 12, 8, 4, 4, 6, 6, 0, 0, 0, 0,
-  0, 4, 16, 12, 8, 8, 12, 11, 12, 4, 6, 6, 0, 0, 0, 0,
-  0, 8, 8, 8, 10, 14, 15, 4, 4, 4, 6, 6, 0, 0, 0, 0,
-  0, 8, 8, 8, 10, 14, 15, 4, 4, 4, 6, 6, 0, 0, 0, 0,
-  0,
-};
-static const int8 kPlayer_SetupActionHitBox_Y[65] = {
-  0, 2, 0, 2, 4, 4, 4, 7, 2, 2, 1, 1, 0, 0, 0, 0,
-  0, 2, 0, 2, -4, -3, -8, 0, 0, 2, 1, 1, 0, 0, 0, 0,
-  0, 0, 0, 0, -2, 0, -4, 1, 2, 2, 1, 1, 0, 0, 0, 0,
-  0, 0, 0, 0, -2, 0, -4, 1, 2, 2, 1, 1, 0, 0, 0, 0,
-  0,
-};
-static const int8 kPlayer_SetupActionHitBox_H[65] = {
-  15, 4, 8, 2, 12, 8, 12, 8, 4, 4, 6, 6, 0, 0, 0, 0,
-  0, 4, 8, 4, 12, 12, 12, 4, 8, 4, 6, 4, 0, 0, 0, 0,
-  0, 8, 8, 8, 8, 8, 12, 4, 4, 4, 6, 6, 0, 0, 0, 0,
-  0, 8, 8, 8, 8, 8, 12, 4, 4, 4, 6, 6, 0, 0, 0, 0,
-  0,
-};
-static const int8 kPlayer_SetupActionHitBox_Tab4[13] = {
-  1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1
-};
-static const uint8 kSprite_PrepAndDrawSingleLarge_Tab1[236] = {
-  200, 0, 107, 0, 0, 0, 0, 0, 0, 203, 0, 8, 10, 11, 0, 0,
-  13, 0, 0, 86, 0, 0, 15, 17, 0, 19, 0, 0, 0, 0, 20, 0,
-  21, 27, 0, 42, 42, 248, 0, 182, 0, 0, 0, 170, 0, 0, 28, 0,
-  0, 0, 0, 0, 0, 0, 0, 243, 243, 0, 187, 39, 0, 0, 66, 0,
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 63, 0, 0, 0, 64, 64,
-  68, 0, 0, 0, 0, 71, 70, 0, 0, 72, 74, 101, 101, 0, 0, 0,
-  0, 0, 143, 0, 0, 76, 78, 78, 78, 78, 0, 48, 36, 50, 56, 60,
-  129, 0, 82, 0, 0, 0, 0, 0, 0, 92, 0, 98, 94, 0, 0, 0,
-  101, 102, 0, 0, 0, 0, 110, 14, 0, 59, 66, 0, 0, 117, 120, 123,
-  0, 0, 207, 0, 132, 141, 141, 141, 141, 0, 148, 117, 160, 0, 0, 162,
-  166, 0, 0, 0, 177, 0, 181, 0, 189, 0, 0, 0, 105, 0, 0, 0,
-  0, 0, 92, 0, 214, 230, 0, 0, 0, 219, 218, 233, 0, 0, 190, 192,
-  106, 0, 249, 215, 0, 0, 0, 216, 0, 0, 222, 227, 0, 0, 0, 235,
-  0, 0, 0, 0, 0, 0, 244, 244, 29, 31, 31, 31, 32, 32, 32, 33,
-  34, 35, 35, 37, 40, 106, 246, 41, 0, 0, 205, 206,
-};
-static const uint8 kSprite_PrepAndDrawSingleLarge_Tab2[251] = {
-  0xa0, 0xa2, 0xa0, 0xa2, 0x80, 0x82, 0x80, 0x82, 0xea, 0xec, 0x84, 0x4e, 0x61, 0xbd, 0x8c, 0x20,
-  0x22, 0xc0, 0xc2, 0xe6, 0xe4, 0x82, 0xaa, 0x84, 0xac, 0x80, 0xa0, 0xca, 0xaf, 0x29, 0x39, 0xb,
-  0x6e, 0x60, 0x62, 0x63, 0x4c, 0xea, 0xec, 0x24, 0x6b, 0x24, 0x22, 0x24, 0x26, 0x20, 0x30, 0x21,
-  0x2a, 0x24, 0x86, 0x88, 0x8a, 0x8c, 0x8e, 0xa2, 0xa4, 0xa6, 0xa8, 0xaa, 0x84, 0x80, 0x82, 0x6e,
-  0x40, 0x42, 0xe6, 0xe8, 0x80, 0x82, 0xc8, 0x8d, 0xe3, 0xe5, 0xc5, 0xe1, 4, 0x24, 0xe, 0x2e,
-  0xc, 0xa, 0x9c, 0xc7, 0xb6, 0xb7, 0x60, 0x62, 0x64, 0x66, 0x68, 0x6a, 0xe4, 0xf4, 2, 2,
-  0, 4, 0xc6, 0xcc, 0xce, 0x28, 0x84, 0x82, 0x80, 0xe5, 0x24, 0, 2, 4, 0xa0, 0xaa,
-  0xa4, 0xa6, 0xac, 0xa2, 0xa8, 0xa6, 0x88, 0x86, 0x8e, 0xae, 0x8a, 0x42, 0x44, 0x42, 0x44, 0x64,
-  0x66, 0xcc, 0xcc, 0xca, 0x87, 0x97, 0x8e, 0xae, 0xac, 0x8c, 0x8e, 0xaa, 0xac, 0xd2, 0xf3, 0x84,
-  0xa2, 0x84, 0xa4, 0xe7, 0x8a, 0xa8, 0x8a, 0xa8, 0x88, 0xa0, 0xa4, 0xa2, 0xa6, 0xa6, 0xa6, 0xa6,
-  0x7e, 0x7f, 0x8a, 0x88, 0x8c, 0xa6, 0x86, 0x8e, 0xac, 0x86, 0xbb, 0xac, 0xa9, 0xb9, 0xaa, 0xba,
-  0xbc, 0x8a, 0x8e, 0x8a, 0x86, 0xa, 0xc2, 0xc4, 0xe2, 0xe4, 0xc6, 0xea, 0xec, 0xff, 0xe6, 0xc6,
-  0xcc, 0xec, 0xce, 0xee, 0x4c, 0x6c, 0x4e, 0x6e, 0xc8, 0xc4, 0xc6, 0x88, 0x8c, 0x24, 0xe0, 0xae,
-  0xc0, 0xc8, 0xc4, 0xc6, 0xe2, 0xe0, 0xee, 0xae, 0xa0, 0x80, 0xee, 0xc0, 0xc2, 0xbf, 0x8c, 0xaa,
-  0x86, 0xa8, 0xa6, 0x2c, 0x28, 6, 0xdf, 0xcf, 0xa9, 0x46, 0x46, 0xea, 0xc0, 0xc2, 0xe0, 0xe8,
-  0xe2, 0xe6, 0xe4, 0xb, 0x8e, 0xa0, 0xec, 0xea, 0xe9, 0x48, 0x58,
-};
-static const uint8 kOverworldAreaSprcollSizes[192] = {
-  4, 4, 2, 4, 4, 4, 4, 2, 4, 4, 4, 4, 4, 4, 4, 4,
-  2, 2, 2, 2, 2, 2, 2, 2, 4, 4, 2, 4, 4, 2, 4, 4,
-  4, 4, 2, 4, 4, 2, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2,
-  4, 4, 2, 2, 2, 4, 4, 2, 4, 4, 2, 2, 2, 4, 4, 2,
-  4, 4, 2, 4, 4, 4, 4, 2, 4, 4, 4, 4, 4, 4, 4, 4,
-  2, 2, 2, 2, 2, 2, 2, 2, 4, 4, 2, 4, 4, 2, 4, 4,
-  4, 4, 2, 4, 4, 2, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2,
-  4, 4, 2, 2, 2, 4, 4, 2, 4, 4, 2, 2, 2, 4, 4, 2,
-  4, 4, 2, 4, 4, 4, 4, 2, 4, 4, 4, 4, 4, 4, 4, 4,
-  2, 2, 2, 2, 2, 2, 2, 2, 4, 4, 2, 4, 4, 2, 4, 4,
-  4, 4, 2, 4, 4, 2, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2,
-  4, 4, 2, 2, 2, 4, 4, 2, 4, 4, 2, 2, 2, 4, 4, 2,
-};
-static const uint16 kOam_ResetRegionBases[6] = {0x30, 0x1d0, 0, 0x30, 0x120, 0x140};
-static const uint8 kGarnish_OamMemSize[23] = {
-  0, 4, 4, 4, 4, 4,  4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
-  8, 4, 4, 4, 8, 16,
-};
-static HandlerFuncK *const kGarnish_Funcs[22] = {
-  &Garnish01_FireSnakeTail,
-  &Garnish02_MothulaBeamTrail,
-  &Garnish03_FallingTile,
-  &Garnish04_LaserTrail,
-  &Garnish_SimpleSparkle,
-  &Garnish06_ZoroTrail,
-  &Garnish07_BabasuFlash,
-  &Garnish08_KholdstareTrail,
-  &Garnish09_LightningTrail,
-  &Garnish0A_CannonSmoke,
-  &Garnish_WaterTrail,
-  &Garnish0C_TrinexxIceBreath,
-  NULL,
-  &Garnish0E_TrinexxFireBreath,
-  &Garnish0F_BlindLaserTrail,
-  &Garnish10_GanonBatFlame,
-  &Garnish11_WitheringGanonBatFlame,
-  &Garnish12_Sparkle,
-  &Garnish13_PyramidDebris,
-  &Garnish14_KakKidDashDust,
-  &Garnish15_ArrghusSplash,
-  &Garnish16_ThrownItemDebris,
-};
-static const uint8 kSpriteFall_Tab1[32] = {
-  13, 13, 13, 13, 13, 13, 13, 12, 12, 12, 12, 12, 3, 3, 3, 3,
-  3, 2, 2, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0,
-};
-static const uint8 kSpriteFall_Tab2[32] = {
-  5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 3, 3, 3, 3,
-  3, 2, 2, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0,
-};
-static const uint8 kSpriteFall_Tab3[16] = {0xff, 0x3f, 0x1f, 0xf, 0xf, 7, 3, 1, 0xff, 0x3f, 0x1f, 0xf, 7, 3, 1, 0};
-static const int8 kSpriteFall_Tab4[4] = {0, 4, 8, 0};
-static const DrawMultipleData kSpriteDrawFall0Data[12] = {
-  {0, 0, 0x0146, 2},
-  {0, 0, 0x0148, 2},
-  {0, 0, 0x014a, 2},
-  {4, 4, 0x014c, 0},
-  {4, 4, 0x00b7, 0},
-  {4, 4, 0x0080, 0},
-  {0, 0, 0x016c, 2},
-  {0, 0, 0x016e, 2},
-  {0, 0, 0x014e, 2},
-  {4, 4, 0x015c, 0},
-  {4, 4, 0x00b7, 0},
-  {4, 4, 0x0080, 0},
-};
-static const int8 kSpriteDrawFall1_X[56] = {
-  -4, 4, -4, 12, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0,
-  -4, 12, -4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0,
-  -4, 12, -4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0,
-  4, 0, 0, 0, 4, 0, 0, 0,
-};
-static const int8 kSpriteDrawFall1_Y[56] = {
-  -4, -4, 4, 12, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0,
-  -4, -4, 12, 4, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0,
-  -4, -4, 12, 4, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0,
-  4, 0, 0, 0, 4, 0, 0, 0,
-};
-static const uint8 kSpriteDrawFall1_Char[56] = {
-  0xae, 0xa8, 0xa6, 0xaf, 0xaa, 0, 0, 0, 0xac, 0, 0, 0, 0xbe, 0, 0, 0,
-  0xa8, 0xae, 0xaf, 0xa6, 0xaa, 0, 0, 0, 0xac, 0, 0, 0, 0xbe, 0, 0, 0,
-  0xa6, 0xaf, 0xae, 0xa8, 0xaa, 0, 0, 0, 0xac, 0, 0, 0, 0xbe, 0, 0, 0,
-  0xb6, 0, 0, 0, 0x80, 0, 0, 0,
-};
-static const uint8 kSpriteDrawFall1_Flags[56] = {
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-  0x40, 0x40, 0x40, 0x40, 0x40, 0, 0, 0, 0x40, 0, 0, 0, 0x40, 0, 0, 0,
-  0x80, 0x80, 0x80, 0x80, 0x80, 0, 0, 0, 0x80, 0, 0, 0, 0x80, 0, 0, 0,
-  1, 0, 0, 0, 1, 0, 0, 0,
-};
-static const uint8 kSpriteDrawFall1_Ext[56] = {
-  0, 2, 2, 0, 2, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0,
-  2, 0, 0, 2, 2, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0,
-  2, 0, 0, 2, 2, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0,
-};
-static const int8 kSpriteDistress_X[4] = {-3, 2, 7, 11};
-static const int8 kSpriteDistress_Y[4] = {-5, -7, -7, -5};
-static const uint8 kPikitDropItems[4] = {0xdc, 0xe1, 0xd9, 0xe6};
-static const uint8 kPrizeMasks[7] = { 1, 1, 1, 0, 1, 1, 1 };
-static const uint8 kPrizeItems[56] = {
-  0xd8, 0xd8, 0xd8, 0xd8, 0xd9, 0xd8, 0xd8, 0xd9, 0xda, 0xd9, 0xda, 0xdb, 0xda, 0xd9, 0xda, 0xda,
-  0xe0, 0xdf, 0xdf, 0xda, 0xe0, 0xdf, 0xd8, 0xdf, 0xdc, 0xdc, 0xdc, 0xdd, 0xdc, 0xdc, 0xde, 0xdc,
-  0xe1, 0xd8, 0xe1, 0xe2, 0xe1, 0xd8, 0xe1, 0xe2, 0xdf, 0xd9, 0xd8, 0xe1, 0xdf, 0xdc, 0xd9, 0xd8,
-  0xd8, 0xe3, 0xe0, 0xdb, 0xde, 0xd8, 0xdb, 0xe2,
-};
-static const uint8 kPrizeZ[15] = {0, 0x24, 0x24, 0x24, 0x20, 0x20, 0x20, 0x24, 0x24, 0x24, 0x24, 0, 0x24, 0x20, 0x20};
-static const int8 kPerishOverlay_X[32] = {
-  0, 0, 0, 8, 0, 8, 0, 8, 8, 8, 0, 8, 0, 8, 0, 8,
-  0, 8, 0, 8, 0, 8, 0, 8, -3, 11, -3, 11, -6, 14, -6, 14,
-};
-static const int8 kPerishOverlay_Y[32] = {
-  0, 0, 8, 8, 0, 0, 8, 8, 0, 0, 8, 8, 0, 0, 8, 8,
-  0, 0, 8, 8, 0, 0, 8, 8, -3, -3, 11, 11, -6, -6, 14, 14,
-};
-static const uint8 kPerishOverlay_Char[32] = {
-  0, 0xb9, 0, 0, 0xb4, 0xb5, 0xb5, 0xb4, 0xb9, 0, 0, 0, 0xb5, 0xb4, 0xb4, 0xb5,
-  0xa8, 0xa8, 0xb8, 0xb8, 0xa8, 0xa8, 0xb8, 0xb8, 0xa9, 0xa9, 0xa9, 0xa9, 0x9b, 0x9b, 0x9b, 0x9b,
-};
-static const uint8 kPerishOverlay_Flags[32] = {
-  4, 4, 4, 4, 4, 4, 0xc4, 0xc4, 0x44, 4, 4, 4, 0x44, 0x44, 0x84, 0x84,
-  4, 0x44, 4, 0x44, 4, 0x44, 4, 0x44, 0x44, 4, 0xc4, 0x84, 4, 0x44, 0x84, 0xc4,
-};
-static HandlerFuncK *const kSprite_ExecuteSingle[12] = {
-  &Sprite_inactiveSprite,
-  &SpriteModule_Fall1,
-  &SpriteModule_Poof,
-  &SpriteModule_Drown,
-  &SpriteModule_Explode,
-  &SpriteModule_Fall2,
-  &SpriteModule_Die,
-  &SpriteModule_Burn,
-  &SpriteModule_Initialize,
-  &SpriteActive_Main,
-  &SpriteModule_Carried,
-  &SpriteModule_Stunned,
-};
-// it's not my job to tell you what to think, my job is to think about what you tell me'
-#define R0 WORD(g_ram[0])
-#define R2 WORD(g_ram[2])
-static const uint8 kSpawnSecretItems[22] = {
-  0xd9, 0x3e, 0x79, 0xd9, 0xdc, 0xd8, 0xda, 0xe4, 0xe1, 0xdc, 0xd8, 0xdf, 0xe0, 0xb, 0x42, 0xd3,
-  0x41, 0xd4, 0xd9, 0xe3, 0xd8, 0,
-};
-static const uint8 kSpawnSecretItem_SpawnFlag[22] = {
-  0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 0, 0,
-  0, 0, 0, 0, 0, 0,
-};
-static const uint8 kSpawnSecretItem_XLo[22] = {
-  4, 0, 4, 4, 0, 4, 4, 4, 4, 0, 4, 4, 4, 0, 0, 0,
-  0, 0, 4, 0, 4, 4,
-};
-static const uint8 kSpawnSecretItem_IgnoreProj[22] = {
-  1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0,
-  0, 0, 1, 1, 1, 1,
-};
-static const uint8 kSpawnSecretItem_ZVel[22] = {
-  16, 0, 0, 16, 0, 0, 16, 16, 16, 16, 0, 16, 10, 16, 0, 0,
-  0, 0, 16, 0, 0, 0,
-};
-static const uint8 kSprite_ReturnIfLifted_Dirs[4] = {4, 6, 0, 2};
-static const uint8 kAbsorbable_Tab1[15] = {0, 1, 1, 1, 2, 2, 2, 0, 1, 1, 2, 2, 1, 2, 2};
-static const uint8 kAbsorbable_Tab2[19] = {0, 0, 0, 0, 1, 2, 3, 0, 0, 4, 5, 0, 0, 0, 0, 2, 4, 6, 2};
-static const int16 kNumberedAbsorbable_X[18] = { 0, 0, 8, 0, 0, 8, 0, 0, 8, 0, 0, 2, 0, 0, 2, 0, 0, 0, };
-static const int16 kNumberedAbsorbable_Y[18] = { 0, 0, 8, 0, 0, 8, 0, 0, 8, 0, 8, 8, 0, 8, 8, 0, 8, 8, };
-static const uint8 kNumberedAbsorbable_Char[18] = { 0x6e, 0x6e, 0x68, 0x6e, 0x6e, 0x78, 0x6e, 0x6e, 0x79, 0x63, 0x73, 0x69, 0x63, 0x73, 0x6a, 0x63, 0x73, 0x73, };
-static const uint8 kNumberedAbsorbable_Ext[18] = { 2, 2, 0, 2, 2, 0, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, };
-static const uint8 kRupeesAbsorption[3] = {1, 5, 20};
-const uint8 kAbsorptionSfx[15] = {0xb, 0xa, 0xa, 0xa, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0x2f, 0x2f, 0xb};
-static const uint8 kBombsAbsorption[3] = {1, 4, 8};
-const uint8 kAbsorbBigKey[2] = {0x40, 0x20};
-static int AllocOverlord();
-static int Overworld_AllocSprite(uint8 type);
-uint16 Sprite_GetX(int k) {
-  return sprite_x_lo[k] | sprite_x_hi[k] << 8;
-}
-
-uint16 Sprite_GetY(int k) {
-  return sprite_y_lo[k] | sprite_y_hi[k] << 8;
-}
-
-void Sprite_SetX(int k, uint16 x) {
-  sprite_x_lo[k] = x;
-  sprite_x_hi[k] = x >> 8;
-}
-
-void Sprite_SetY(int k, uint16 y) {
-  sprite_y_lo[k] = y;
-  sprite_y_hi[k] = y >> 8;
-}
-
-void Sprite_ApproachTargetSpeed(int k, uint8 x, uint8 y) {
-  if (sprite_x_vel[k] - x)
-    sprite_x_vel[k] += sign8(sprite_x_vel[k] - x) ? 1 : -1;
-  if (sprite_y_vel[k] - y)
-    sprite_y_vel[k] += sign8(sprite_y_vel[k] - y) ? 1 : -1;
-}
-
-void SpriteAddXY(int k, int xv, int yv) {
-  Sprite_SetX(k, Sprite_GetX(k) + xv);
-  Sprite_SetY(k, Sprite_GetY(k) + yv);
-}
-
-void Sprite_MoveXYZ(int k) {
-  Sprite_MoveZ(k);
-  Sprite_MoveX(k);
-  Sprite_MoveY(k);
-}
-
-void Sprite_Invert_XY_Speeds(int k) {
-  sprite_x_vel[k] = -sprite_x_vel[k];
-  sprite_y_vel[k] = -sprite_y_vel[k];
-}
-
-int Sprite_SpawnSimpleSparkleGarnishEx(int k, uint16 x, uint16 y, int limit) {
-  int j = GarnishAllocLimit(limit);
-  if (j >= 0) {
-    garnish_type[j] = 5;
-    garnish_active = 5;
-    Garnish_SetX(j, Sprite_GetX(k) + x);
-    Garnish_SetY(j, Sprite_GetY(k) + y - sprite_z[k] + 16);
-    garnish_countdown[j] = 31;
-    garnish_sprite[j] = k;
-    garnish_floor[j] = sprite_floor[k];
-  }
-  g_ram[15] = j;
-  return j;
-}
-
-static int AllocOverlord() {
-  int i = 7;
-  while (i >= 0 && overlord_type[i] != 0)
-    i--;
-  return i;
-}
-
-static int Overworld_AllocSprite(uint8 type) {
-  int i = (type == 0x58) ? 4 :
-          (type == 0xd0) ? 5 :
-          (type == 0xeb || type == 0x53 || type  == 0xf3) ? 14 : 13;
-  for (; i >= 0; i--) {
-    if (sprite_state[i] == 0 || sprite_type[i] == 0x41 && sprite_C[i] != 0)
-      break;
-  }
-  return i;
-}
-
-uint16 Garnish_GetX(int k) {
-  return garnish_x_lo[k] | garnish_x_hi[k] << 8;
-}
-
-uint16 Garnish_GetY(int k) {
-  return garnish_y_lo[k] | garnish_y_hi[k] << 8;
-}
-
-void Garnish_SparkleCommon(int k, uint8 shift) {
-  static const uint8 kGarnishSparkle_Char[4] = {0x83, 0xc7, 0x80, 0xb7};
-  uint8 t = garnish_countdown[k] >> shift;
-  Point16U pt;
-  if (Garnish_ReturnIfPrepFails(k, &pt))
-    return;
-  OamEnt *oam = GetOamCurPtr();
-  int j = garnish_sprite[k];
-  SetOamPlain(oam, pt.x, pt.y, kGarnishSparkle_Char[t],
-               (sprite_oam_flags[j] | sprite_obj_prio[j]) & 0xf0 | 4, 0);
-}
-
-void Garnish_DustCommon(int k, uint8 shift) {
-  static const uint8 kRunningManDust_Char[3] = {0xdf, 0xcf, 0xa9};
-  tmp_counter = garnish_countdown[k] >> shift;
-  Point16U pt;
-  if (Garnish_ReturnIfPrepFails(k, &pt))
-    return;
-  OamEnt *oam = GetOamCurPtr();
-  SetOamPlain(oam, pt.x, pt.y, kRunningManDust_Char[tmp_counter], 0x24, 0);
-}
-
-void SpriteModule_Explode(int k) {
-  static const DrawMultipleData kSpriteExplode_Dmd[32] = {
-    { 0,  0, 0x0060, 2},
-    { 0,  0, 0x0060, 2},
-    { 0,  0, 0x0060, 2},
-    { 0,  0, 0x0060, 2},
-    {-5, -5, 0x0062, 2},
-    { 5, -5, 0x4062, 2},
-    {-5,  5, 0x8062, 2},
-    { 5,  5, 0xc062, 2},
-    {-8, -8, 0x0062, 2},
-    { 8, -8, 0x4062, 2},
-    {-8,  8, 0x8062, 2},
-    { 8,  8, 0xc062, 2},
-    {-8, -8, 0x0064, 2},
-    { 8, -8, 0x4064, 2},
-    {-8,  8, 0x8064, 2},
-    { 8,  8, 0xc064, 2},
-    {-8, -8, 0x0066, 2},
-    { 8, -8, 0x4066, 2},
-    {-8,  8, 0x8066, 2},
-    { 8,  8, 0xc066, 2},
-    {-8, -8, 0x0068, 2},
-    { 8, -8, 0x0068, 2},
-    {-8,  8, 0x0068, 2},
-    { 8,  8, 0x0068, 2},
-    {-8, -8, 0x006a, 2},
-    { 8, -8, 0x406a, 2},
-    {-8,  8, 0x806a, 2},
-    { 8,  8, 0xc06a, 2},
-    {-8, -8, 0x004e, 2},
-    { 8, -8, 0x404e, 2},
-    {-8,  8, 0x804e, 2},
-    { 8,  8, 0xc04e, 2},
-  };
-
-  if (sprite_A[k]) {
-    if (!sprite_delay_main[k]) {
-      sprite_state[k] = 0;
-      for (int j = 15; j >= 0; j--) {
-        if (sprite_state[j] == 4)
-          return;
-      }
-      load_chr_halfslot_even_odd = 1;
-      if (!Sprite_CheckIfScreenIsClear())
-        flag_block_link_menu = 0;
-    } else {
-      Sprite_DrawMultiple(k, &kSpriteExplode_Dmd[((sprite_delay_main[k] >> 2) ^ 7) * 4], 4, NULL);
-    }
-    return;
-  }
-  sprite_floor[k] = 2;
-
-  if (sprite_delay_main[k] == 32) {
-    sprite_state[k] = 0;
-    flag_is_link_immobilized = 0;
-    if (player_near_pit_state != 2 && Sprite_CheckIfScreenIsClear()) {
-      if (sprite_type[k] >= 0xd6) {
-        music_control = 0x13;
-      } else if (sprite_type[k] == 0x7a) {
-        PrepareDungeonExitFromBossFight();
-      } else {
-        SpriteExplode_SpawnEA(k);
-        return;
-      }
-    }
-  }
-
-  if (sprite_delay_main[k] >= 64 && (sprite_delay_main[k] >= 0x70 || !(sprite_delay_main[k] & 1)))
-    SpriteActive_Main(k);
-
-  uint8 type = sprite_type[k];
-  if (sprite_delay_main[k] >= 0xc0)
-    return;
-  if ((sprite_delay_main[k] & 3) == 0)
-    SpriteSfx_QueueSfx2WithPan(k, 0xc);
-  if (sprite_delay_main[k] & ((type == 0x92) ? 3 : 7))
-    return;
-
-  SpriteSpawnInfo info;
-  int j = Sprite_SpawnDynamically(k, 0x1c, &info);
-  if (j >= 0) {
-    static const int8 kSpriteExplode_RandomXY[16] = {0, 4, 8, 12, -4, -8, -12, 0, 0, 8, 16, 24, -24, -16, -8, 0};
-    load_chr_halfslot_even_odd = 11;
-    sprite_state[j] = 4;
-    sprite_flags2[j] = 3;
-    sprite_oam_flags[j] = 0xc;
-    int xoff = kSpriteExplode_RandomXY[(GetRandomNumber() & 7) | ((type == 0x92) ? 8 : 0)];
-    int yoff = kSpriteExplode_RandomXY[(GetRandomNumber() & 7) | ((type == 0x92) ? 8 : 0)];
-    Sprite_SetX(j, info.r0_x + xoff);
-    Sprite_SetY(j, info.r2_y + yoff - info.r4_z);
-    sprite_delay_main[j] = 31;
-    sprite_A[j] = 31;
-  }
-  // endif_1
-}
-
-void SpriteDeath_MainEx(int k, bool second_entry) {
-  if (!second_entry) {
-    uint8 type = sprite_type[k];
-    if (type == 0xec) {
-      ThrowableScenery_ScatterIntoDebris(k);
-      return;
-    }
-    if (type == 0x53 || type == 0x54 || type == 0x92 || type == 0x4a && sprite_C[k] >= 2) {
-      SpriteActive_Main(k);
-      return;
-    }
-    if (sprite_delay_main[k] == 0) {
-      Sprite_DoTheDeath(k);
-      return;
-    }
-  }
-  if (sign8(sprite_flags3[k])) {
-    SpriteActive_Main(k);
-    return;
-  }
-  if (!((frame_counter & 3) | submodule_index | flag_unk1))
-    sprite_delay_main[k]++;
-  SpriteDeath_DrawPoof(k);
-
-  if (sprite_type[k] != 0x40 && sprite_delay_main[k] < 10)
-    return;
-  oam_cur_ptr += 16;
-  oam_ext_cur_ptr += 4;
-  uint8 bak = sprite_flags2[k];
-  sprite_flags2[k] -= 4;
-  SpriteActive_Main(k);
-  sprite_flags2[k] = bak;
-}
-
-void SpriteModule_Burn(int k) {
-  static const uint8 kFlame_Gfx[32] = {
-    5, 4, 3, 1, 2, 0, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0,
-    1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0,
-  };
-  sprite_hit_timer[k] = 0;
-  int j = sprite_delay_main[k] - 1;
-  if (j == 0) {
-    Sprite_DoTheDeath(k);
-    return;
-  }
-  uint8 bak = sprite_graphics[k];
-  uint8 bak1 = sprite_oam_flags[k];
-  sprite_graphics[k] = kFlame_Gfx[j >> 3];
-  sprite_oam_flags[k] = 3;
-  Flame_Draw(k);
-  sprite_oam_flags[k] = bak1;
-  sprite_graphics[k] = bak;
-
-  oam_cur_ptr += 8;
-  oam_ext_cur_ptr += 2;
-  if (sprite_delay_main[k] >= 0x10) {
-    uint8 bak = sprite_flags2[k];
-    sprite_flags2[k] -= 2;
-    SpriteActive_Main(k);
-    sprite_flags2[k] = bak;
-  }
-}
-
-void Sprite_HitTimer31(int k) {
-  if (sprite_type[k] != 0x7a || is_in_dark_world)
-    return;
-  if (sprite_health[k] <= sprite_give_damage[k]) {
-    dialogue_message_index = 0x140;
-    Sprite_ShowMessageMinimal();
-  }
-}
-
-void SpriteStunned_MainEx(int k, bool second_entry) {
-  if (second_entry)
-    goto ThrownSprite_TileAndSpriteInteraction;
-  Sprite_DrawRippleIfInWater(k);
-  SpriteStunned_Main_Func1(k);
-  if (Sprite_ReturnIfPaused(k))
-    return;
-  if (sprite_F[k]) {
-    if (sign8(sprite_F[k]))
-      sprite_F[k] = 0;
-    sprite_x_vel[k] = sprite_y_vel[k] = 0;
-  }
-  if (sprite_delay_main[k] < 0x20)
-    Sprite_CheckDamageFromLink(k);
-  if (Sprite_ReturnIfRecoiling(k))
-    return;
-  Sprite_MoveXY(k);
-  if (!sprite_E[k]) {
-    Sprite_CheckTileCollision(k);
-    if (!sprite_state[k])
-      return;
-  ThrownSprite_TileAndSpriteInteraction:
-    if (sprite_wallcoll[k] & 0xf) {
-      Sprite_ApplyRicochet(k);
-      if (sprite_state[k] == 11)
-        SpriteSfx_QueueSfx2WithPan(k, 5);
-    }
-  }
-  Sprite_CheckTileProperty(k, 0x68);
-
-  if (kSpriteInit_Flags3[sprite_type[k]] & 0x10) {
-    sprite_flags3[k] |= 0x10;
-    if (sprite_tiletype == 32)
-      sprite_flags3[k] &= ~0x10;
-  }
-  Sprite_MoveZ(k);
-  sprite_z_vel[k] -= 2;
-  uint8 z = sprite_z[k] - 1;
-  if (z >= 0xf0) {
-    sprite_z[k] = 0;
-    if (sprite_type[k] == 0xe8 && sign8(sprite_z_vel[k] - 0xe8)) {
-      sprite_state[k] = 6;
-      sprite_delay_main[k] = 8;
-      sprite_flags2[k] = 3;
-      return;
-    }
-    ThrowableScenery_TransmuteIfValid(k);
-    uint8 a = sprite_tiletype;
-    if (sprite_tiletype == 32 && !(a = sprite_flags[k] >> 1, sprite_flags[k] & 1)) {  // wtf
-      Sprite_Func8(k);
-      return;
-    }
-    if (a == 9) {
-      z = sprite_z_vel[k];
-      sprite_z_vel[k] = 0;
-      int j;
-      SpriteSpawnInfo info;
-
-      if (sign8(z - 0xf0) && (j = Sprite_SpawnDynamically(k, 0xec, &info)) >= 0) {
-        Sprite_SetSpawnedCoordinates(j, &info);
-        Sprite_Func22(j);
-      }
-    } else if (a == 8) {
-      if (sprite_type[k] == 0xd2 || (GetRandomNumber() & 1))
-        Sprite_SpawnLeapingFish(k);
-      Sprite_Func22(k);
-      return;
-    }
-    z = sprite_z_vel[k];
-    if (sign8(z)) {
-      z = (uint8)(-z) >> 1;
-      sprite_z_vel[k] = z < 9 ? 0 : z;
-    }
-    sprite_x_vel[k] = (int8)sprite_x_vel[k] >> 1;
-    if (sprite_x_vel[k] == 255)
-      sprite_x_vel[k] = 0;
-    sprite_y_vel[k] = (int8)sprite_y_vel[k] >> 1;
-    if (sprite_y_vel[k] == 255)
-      sprite_y_vel[k] = 0;
-  }
-  if (sprite_state[k] != 11 || sprite_unk5[k] != 0) {
-    if (Sprite_ReturnIfLifted(k))
-      return;
-    if (sprite_type[k] != 0x4a)
-      ThrownSprite_CheckDamageToSprites(k);
-  }
-}
-
-int Ancilla_SpawnFallingPrize(uint8 item) {  // 85a51d
-  return AncillaAdd_FallingPrize(0x29, item, 4);
-}
-
-bool Sprite_CheckDamageToAndFromLink(int k) {  // 85ab93
-  Sprite_CheckDamageFromLink(k);
-  return Sprite_CheckDamageToLink(k);
-}
-
-uint8 Sprite_CheckTileCollision(int k) {  // 85b88d
-  Sprite_CheckTileCollision2(k);
-  return sprite_wallcoll[k];
-}
-
-bool Sprite_TrackBodyToHead(int k) {  // 85dca2
-  if (sprite_head_dir[k] != sprite_D[k]) {
-    if (frame_counter & 0x1f)
-      return false;
-    if (!((sprite_head_dir[k] ^ sprite_D[k]) & 2)) {
-      sprite_D[k] = (((k ^ frame_counter) >> 5 | 2) & 3) ^ (sprite_head_dir[k] & 2);
-      return false;
-    }
-  }
-  sprite_D[k] = sprite_head_dir[k];
-  return true;
-}
-
-void Sprite_DrawMultiple(int k, const DrawMultipleData *src, int n, PrepOamCoordsRet *info) {  // 85df6c
-  PrepOamCoordsRet info_buf;
-  if (!info)
-    info = &info_buf;
-  if (Sprite_PrepOamCoordOrDoubleRet(k, info))
-    return;
-  word_7E0CFE = 0;
-  uint8 a = sprite_state[k];
-  if (a == 10)
-    a = sprite_unk4[k];
-  if (a == 11)
-    BYTE(word_7E0CFE) = sprite_unk5[k];
-  OamEnt *oam = GetOamCurPtr();
-  do {
-    uint16 d = src->char_flags ^ WORD(info->r4);
-    if (word_7E0CFE >= 1)
-      d = d & ~0xE00 | 0x400;
-    SetOamHelper0(oam, src->x + info->x, src->y + info->y, d, d >> 8, src->ext);
-
-  } while (src++, oam++, --n);
-}
-
-void Sprite_DrawMultiplePlayerDeferred(int k, const DrawMultipleData *src, int n, PrepOamCoordsRet *info) {  // 85df75
-  Oam_AllocateDeferToPlayer(k);
-  Sprite_DrawMultiple(k, src, n, info);
-}
-
-int Sprite_ShowSolicitedMessage(int k, uint16 msg) {  // 85e1a7
-  static const uint8 kShowMessageFacing_Tab0[4] = {4, 6, 0, 2};
-  dialogue_message_index = msg;
-  if (!Sprite_CheckDamageToLink_same_layer(k) ||
-      Sprite_CheckIfLinkIsBusy() ||
-      !(filtered_joypad_L & 0x80) ||
-      sprite_delay_aux4[k] || link_auxiliary_state == 2)
-    return sprite_D[k];
-  uint8 dir = Sprite_DirectionToFaceLink(k, NULL);
-  if (link_direction_facing != kShowMessageFacing_Tab0[dir])
-    return sprite_D[k];
-  Sprite_ShowMessageUnconditional(dialogue_message_index);
-  sprite_delay_aux4[k] = 64;
-  return dir ^ 0x103;
-}
-
-int Sprite_ShowMessageOnContact(int k, uint16 msg) {  // 85e1f0
-  dialogue_message_index = msg;
-  if (!Sprite_CheckDamageToLink_same_layer(k) || link_auxiliary_state == 2)
-    return sprite_D[k];
-  Sprite_ShowMessageUnconditional(dialogue_message_index);
-  return Sprite_DirectionToFaceLink(k, NULL) ^ 0x103;
-}
-
-void Sprite_ShowMessageUnconditional(uint16 msg) {  // 85e219
-  dialogue_message_index = msg;
-  byte_7E0223 = 0;
-  messaging_module = 0;
-  submodule_index = 2;
-  saved_module_for_menu = main_module_index;
-  main_module_index = 14;
-  Sprite_NullifyHookshotDrag();
-  link_speed_setting = 0;
-  Link_CancelDash();
-  link_auxiliary_state = 0;
-  link_incapacitated_timer = 0;
-  if (link_player_handler_state == kPlayerState_RecoilWall)
-    link_player_handler_state = kPlayerState_Ground;
-}
-
-bool Sprite_TutorialGuard_ShowMessageOnContact(int k, uint16 msg) {  // 85fa59
-  dialogue_message_index = msg;
-  uint8 bak2 = sprite_flags2[k];
-  uint8 bak4 = sprite_flags4[k];
-  sprite_flags2[k] = 0x80;
-  sprite_flags4[k] = 0x07;
-  bool rv = Sprite_CheckDamageToLink_same_layer(k);
-  sprite_flags2[k] = bak2;
-  sprite_flags4[k] = bak4;
-  if (!rv)
-    return rv;
-  Sprite_NullifyHookshotDrag();
-  link_is_running = 0;
-  link_speed_setting = 0;
-  if (!link_auxiliary_state)
-    Sprite_ShowMessageMinimal();
-  return rv;
-}
-
-void Sprite_ShowMessageMinimal() {  // 85fa8e
-  byte_7E0223 = 0;
-  messaging_module = 0;
-  submodule_index = 2;
-  saved_module_for_menu = main_module_index;
-  main_module_index = 14;
-}
-
-void Prepare_ApplyRumbleToSprites() {  // 8680fa
-  static const int8 kApplyRumble_X[4] = { -32, -32, -32, 16 };
-  static const int8 kApplyRumble_Y[4] = { -32, 32, -24, -24 };
-  static const uint8 kApplyRumble_WH[6] = { 0x50, 0x50, 0x20, 0x20, 0x50, 0x50 };
-  int j = link_direction_facing >> 1;
-  SpriteHitBox hb;
-  uint16 x = link_x_coord + kApplyRumble_X[j];
-  uint16 y = link_y_coord + kApplyRumble_Y[j];
-  hb.r0_xlo = x;
-  hb.r8_xhi = x >> 8;
-  hb.r1_ylo = y;
-  hb.r9_yhi = y >> 8;
-  hb.r2 = kApplyRumble_WH[j];
-  hb.r3 = kApplyRumble_WH[j + 2];
-  Entity_ApplyRumbleToSprites(&hb);
-}
-
-void Sprite_SpawnImmediatelySmashedTerrain(uint8 what, uint16 x, uint16 y) {  // 86812d
-  uint8 bak1 = flag_is_sprite_to_pick_up;
-  uint8 bak2 = byte_7E0FB2;
-  int k = Sprite_SpawnThrowableTerrain_silently(what, x, y);
-  if (k >= 0)
-    ThrowableScenery_TransmuteToDebris(k);
-  byte_7E0FB2 = bak2;
-  flag_is_sprite_to_pick_up = bak1;
-}
-
-void Sprite_SpawnThrowableTerrain(uint8 what, uint16 x, uint16 y) {  // 86814b
-  sound_effect_1 = Link_CalculateSfxPan() | 29;
-  Sprite_SpawnThrowableTerrain_silently(what, x, y);
-}
-
-int Sprite_SpawnThrowableTerrain_silently(uint8 what, uint16 x, uint16 y) {  // 868156
-  int k = 15;
-  for (; k >= 0 && sprite_state[k] != 0; k--);
-  if (k < 0)
-    return k;
-  sprite_state[k] = 10;
-  sprite_type[k] = 0xEC;
-  Sprite_SetX(k, x);
-  Sprite_SetY(k, y);
-  SpritePrep_LoadProperties(k);
-  sprite_floor[k] = link_is_on_lower_level;
-  sprite_C[k] = what;
-  if (what >= 6)
-    sprite_flags2[k] = 0xa6;
-  // oob read, this array has only 6 elements.
-  uint8 flags = kThrowableScenery_Flags[what];
-  if (what == 2) {
-    if (player_is_indoors)
-      sprite_oam_flags[k] = 0x80, flags = 0x50;  // wtf
-  }
-  sprite_oam_flags[k] = flags;
-  sprite_unk4[k] = 9;
-  flag_is_sprite_to_pick_up = 2;
-  byte_7E0FB2 = 2;
-  sprite_delay_main[k] = 16;
-  sprite_floor[k] = link_is_on_lower_level;
-  sprite_graphics[k] = 0;
-  if (BYTE(dung_secrets_unk1) != 255) {
-    if (!(BYTE(dung_secrets_unk1) | player_is_indoors) && (uint8)(sprite_C[k] - 2) < 2)
-      Overworld_SubstituteAlternateSecret();
-    if (dung_secrets_unk1 & 0x80) {
-      sprite_graphics[k] = dung_secrets_unk1 & 0x7f;
-      BYTE(dung_secrets_unk1) = 0;
-    }
-    Sprite_SpawnSecret(k);
-  }
-  return k;
-}
-
-void Sprite_SpawnSecret(int k) {  // 868264
-  if (!player_is_indoors && (GetRandomNumber() & 8))
-    return;
-  int b = BYTE(dung_secrets_unk1);
-  if (b == 0)
-    return;
-  if (b == 4)
-    b = 19 + (GetRandomNumber() & 3);
-  if (!kSpawnSecretItems[b - 1])
-    return;
-  SpriteSpawnInfo info;
-  int j = Sprite_SpawnDynamically(k, kSpawnSecretItems[b - 1], &info);
-  if (j < 0)
-    return;
-  sprite_ai_state[j] = kSpawnSecretItem_SpawnFlag[b - 1];
-  sprite_ignore_projectile[j] = kSpawnSecretItem_IgnoreProj[b - 1];
-  sprite_z_vel[j] = kSpawnSecretItem_ZVel[b - 1];
-  Sprite_SetX(j, info.r0_x + kSpawnSecretItem_XLo[b - 1]);
-  Sprite_SetY(j, info.r2_y);
-  sprite_z[j] = info.r4_z;
-  sprite_graphics[j] = 0;
-  sprite_delay_aux4[j] = 32;
-  sprite_delay_aux2[j] = 48;
-  uint8 type = sprite_type[j];
-  if (type == 0xe4) {
-    SpritePrep_SmallKey(j);
-    sprite_stunned[j] = 255;
-  } else if (type == 0xb) {
-    sound_effect_1 = 0x30;
-    if (BYTE(dungeon_room_index2) == 1)
-      sprite_subtype[j] = 1;
-    sprite_stunned[j] = 255;
-  } else if (type == 0x41 || type == 0x42) {
-    sound_effect_2 = 4;
-    sprite_give_damage[j] = 0;
-    sprite_hit_timer[j] = 160;
-  } else if (type == 0x3e) {
-    sprite_oam_flags[j] = 9;
-  } else {
-    sprite_stunned[j] = 255;
-    if (type == 0x79)
-      sprite_A[j] = 32;
-  }
-}
-
-void Sprite_Main() {  // 868328
-  if (!player_is_indoors) {
-    ancilla_floor[0] = 0;
-    ancilla_floor[1] = 0;
-    ancilla_floor[2] = 0;
-    ancilla_floor[3] = 0;
-    ancilla_floor[4] = 0;
-    Sprite_ProximityActivation();
-  }
-  is_in_dark_world = (savegame_is_darkworld != 0);
-  if (submodule_index == 0)
-    drag_player_x = drag_player_y = 0;
-  Oam_ResetRegionBases();
-  Garnish_ExecuteUpperSlots();
-  Follower_Main();
-  byte_7E0FB2 = flag_is_sprite_to_pick_up;
-  flag_is_sprite_to_pick_up = 0;
-  HIBYTE(dungmap_var8) = 0x80;
-
-  if (set_when_damaging_enemies & 0x7f)
-    set_when_damaging_enemies--;
-  else
-    set_when_damaging_enemies = 0;
-  byte_7E0379 = 0;
-  link_unk_master_sword = 0;
-  link_prevent_from_moving = 0;
-  if (sprite_alert_flag)
-    sprite_alert_flag--;
-  Ancilla_Main();
-  Overlord_Main();
-  archery_game_out_of_arrows = 0;
-  for (int i = 15; i >= 0; i--) {
-    cur_object_index = i;
-    Sprite_ExecuteSingle(i);
-  }
-  Garnish_ExecuteLowerSlots();
-  byte_7E069E[0] = byte_7E069E[1] = 0;
-  ExecuteCachedSprites();
-  if (load_chr_halfslot_even_odd)
-    byte_7E0FC6 = load_chr_halfslot_even_odd;
-}
-
-void Oam_ResetRegionBases() {  // 8683d3
-  memcpy(oam_region_base, kOam_ResetRegionBases, 12);
-}
-
-void Sprite_TimersAndOam(int k) {  // 8683f2
-  Sprite_Get16BitCoords(k);
-
-  uint8 num = ((sprite_flags2[k] & 0x1f) + 1) * 4;
-
-  if (sort_sprites_setting) {
-    if (sprite_floor[k])
-      Oam_AllocateFromRegionF(num);
-    else
-      Oam_AllocateFromRegionD(num);
-  } else {
-    Oam_AllocateFromRegionA(num);
-  }
-
-  if (!(submodule_index | flag_unk1)) {
-    if (sprite_delay_main[k])
-      sprite_delay_main[k]--;
-    if (sprite_delay_aux1[k])
-      sprite_delay_aux1[k]--;
-    if (sprite_delay_aux2[k])
-      sprite_delay_aux2[k]--;
-    if (sprite_delay_aux3[k])
-      sprite_delay_aux3[k]--;
-
-    uint8 timer = sprite_hit_timer[k] & 0x7f;
-    if (timer) {
-      if (sprite_state[k] >= 9) {
-        if (timer == 31) {
-          Sprite_HitTimer31(k);
-        } else if (timer == 24) {
-          Sprite_MiniMoldorm_Recoil(k);
-        }
-      }
-      if (sprite_give_damage[k] < 251)
-        sprite_obj_prio[k] = sprite_hit_timer[k] * 2 & 0xe;
-      sprite_hit_timer[k]--;
-    } else {
-      sprite_hit_timer[k] = 0;
-      sprite_obj_prio[k] = 0;
-    }
-    if (sprite_delay_aux4[k])
-      sprite_delay_aux4[k]--;
-  }
-
-  static const uint8 kSpritePrios[4] = {0x20, 0x10, 0x30, 0x30};
-  int floor = link_is_on_lower_level;
-  if (floor != 3)
-    floor = sprite_floor[k];
-  sprite_obj_prio[k] = sprite_obj_prio[k] & 0xcf | kSpritePrios[floor];
-}
-
-void Sprite_Get16BitCoords(int k) {  // 8684c1
-  cur_sprite_x = sprite_x_lo[k] | sprite_x_hi[k] << 8;
-  cur_sprite_y = sprite_y_lo[k] | sprite_y_hi[k] << 8;
-}
-
-void Sprite_ExecuteSingle(int k) {  // 8684e2
-  uint8 st = sprite_state[k];
-  if (st != 0)
-    Sprite_TimersAndOam(k);
-  kSprite_ExecuteSingle[st](k);
-}
-
-void Sprite_inactiveSprite(int k) {  // 868510
-  if (!player_is_indoors) {
-    sprite_N_word[k] = 0xffff;
-  } else {
-    sprite_N[k] = 0xff;
-  }
-}
-
-void SpriteModule_Fall1(int k) {  // 86852e
-  if (!sprite_delay_main[k]) {
-    sprite_state[k] = 0;
-    Sprite_ManuallySetDeathFlagUW(k);
-  } else {
-    PrepOamCoordsRet info;
-    if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
-      return;
-    SpriteFall_Draw(k, &info);
-  }
-}
-
-void SpriteModule_Drown(int k) {  // 86859c
-  static const DrawMultipleData kSpriteDrown_Dmd[8] = {
-    {-7, -7, 0x0480, 0},
-    {14, -6, 0x0483, 0},
-    {-6, -6, 0x04cf, 0},
-    {13, -5, 0x04df, 0},
-    {-4, -4, 0x04ae, 0},
-    {12, -4, 0x44af, 0},
-    { 0,  0, 0x04e7, 2},
-    { 0,  0, 0x04e7, 2},
-  };
-  static const uint8 kSpriteDrown_Oam_Flags[4] = {0, 0x40, 0xc0, 0x80};
-  static const uint8 kSpriteDrown_Oam_Char[11] = {0xc0, 0xc0, 0xc0, 0xc0, 0xcd, 0xcd, 0xcd, 0xcb, 0xcb, 0xcb, 0xcb};
-
-  if (sprite_ai_state[k]) {
-    if (sprite_A[k] == 6)
-      Oam_AllocateFromRegionC(8);
-    sprite_flags3[k] ^= 16;
-    SpriteDraw_SingleLarge(k);
-    OamEnt *oam = GetOamCurPtr();
-    int j = sprite_delay_main[k];
-    if (j == 1)
-      sprite_state[k] = 0;
-    if (j != 0) {
-      assert((j >> 1) < 11);
-      oam->charnum = kSpriteDrown_Oam_Char[j >> 1];
-      oam->flags = 0x24;
-      return;
-    }
-    oam->charnum = 0x8a;
-    oam->flags = kSpriteDrown_Oam_Flags[sprite_subtype2[k] >> 2 & 3] | 0x24;
-
-    if (Sprite_ReturnIfPaused(k))
-      return;
-    sprite_subtype2[k]++;
-    Sprite_MoveXY(k);
-    Sprite_MoveZ(k);
-    sprite_z_vel[k] -= 2;
-    if (sign8(sprite_z[k])) {
-      sprite_z[k] = 0;
-      sprite_delay_main[k] = 18;
-      sprite_flags3[k] &= ~0x10;
-    }
-  } else {
-    if (Sprite_ReturnIfPaused(k))
-      return;
-    if (!(frame_counter & 1))
-      sprite_delay_main[k]++;
-    sprite_oam_flags[k] = 0;
-    sprite_hit_timer[k] = 0;
-    if (!sprite_delay_main[k])
-      sprite_state[k] = 0;
-    Sprite_DrawMultiple(k, &kSpriteDrown_Dmd[(sprite_delay_main[k] << 1 & 0xf8) >> 2], 2, NULL);
-  }
-}
-
-void Sprite_DrawDistress_custom(uint16 xin, uint16 yin, uint8 time) {  // 86a733
-  Oam_AllocateFromRegionA(0x10);
-  if (!(time & 0x18))
-    return;
-  int i = 3;
-  OamEnt *oam = GetOamCurPtr();
-  do {
-    SetOamHelper0(oam, xin + kSpriteDistress_X[i], yin + kSpriteDistress_Y[i],
-                  0x83, 0x22, 0);
-  } while (oam++, --i >= 0);
-}
-
-void Sprite_CheckIfLifted_permissive(int k) {  // 86aa0c
-  Sprite_ReturnIfLiftedPermissive(k);
-}
-
-void Entity_ApplyRumbleToSprites(SpriteHitBox *hb) {  // 86ad03
-  for (int j = 15; j >= 0; j--) {
-    if (!(sprite_defl_bits[j] & 2) || sprite_E[j] == 0)
-      continue;
-    if (byte_7E0FC6 != 0xe) {
-      Sprite_SetupHitBox(j, hb);
-      if (!CheckIfHitBoxesOverlap(hb))
-        continue;
-    }
-    sprite_E[j] = 0;
-    sound_effect_2 = 0x30;
-    sprite_z_vel[j] = 0x30;
-    sprite_x_vel[j] = 0x10;
-    sprite_delay_aux3[j] = 0x30;
-    sprite_stunned[j] = 255;
-    if (sprite_type[j] == 0xd8)
-      Sprite_TransmuteToBomb(j);
-  }
-}
-
-void Sprite_ZeroVelocity_XY(int k) {  // 86cf5d
-  sprite_x_vel[k] = sprite_y_vel[k] = 0;
-}
-
-bool Sprite_HandleDraggingByAncilla(int k) {  // 86cf64
-  int j = sprite_B[k];
-  if (j-- == 0)
-    return false;
-  if (ancilla_type[j] == 0) {
-    Sprite_HandleAbsorptionByPlayer(k);
-  } else {
-    sprite_x_lo[k] = ancilla_x_lo[j];
-    sprite_x_hi[k] = ancilla_x_hi[j];
-    sprite_y_lo[k] = ancilla_y_lo[j];
-    sprite_y_hi[k] = ancilla_y_hi[j];
-    sprite_z[k] = 0;
-  }
-  return true;
-}
-
-bool Sprite_ReturnIfPhasingOut(int k) {  // 86d0ed
-  if (!sprite_stunned[k] || (submodule_index | flag_unk1))
-    return false;
-  if (!(frame_counter & 1))
-    sprite_stunned[k]--;
-  uint8 a = sprite_stunned[k];
-  if (a == 0)
-    sprite_state[k] = 0;
-  else if (a >= 0x28 || (a & 1) != 0)
-    return false;
-  PrepOamCoordsRet info;
-  Sprite_PrepOamCoordOrDoubleRet(k, &info);
-  return true;
-}
-
-void Sprite_CheckAbsorptionByPlayer(int k) {  // 86d116
-  if (!sprite_delay_aux4[k] && Sprite_CheckDamageToPlayer_1(k))
-    Sprite_HandleAbsorptionByPlayer(k);
-}
-
-void Sprite_HandleAbsorptionByPlayer(int k) {  // 86d13c
-  sprite_state[k] = 0;
-  int t = sprite_type[k] - 0xd8;
-  SpriteSfx_QueueSfx3WithPan(k, kAbsorptionSfx[t]);
-  switch(t) {
-  case 0:
-    link_hearts_filler += 8;
-    break;
-  case 1: case 2: case 3:
-    link_rupees_goal += kRupeesAbsorption[t - 1];
-    break;
-  case 4: case 5: case 6:
-    link_bomb_filler += kBombsAbsorption[t - 4];
-    break;
-  case 7:
-    link_magic_filler += 0x10;
-    break;
-  case 8:
-    link_magic_filler = 0x80;
-    break;
-  case 9:
-    link_arrow_filler += (sprite_head_dir[k] == 0) ? 5 : sprite_head_dir[k];
-    break;
-  case 10:
-    link_arrow_filler += 10;
-    break;
-  case 11:
-    SpriteSfx_QueueSfx2WithPan(k, 0x31);
-    link_hearts_filler += 56;
-    break;
-  case 12:
-    link_num_keys += 1;
-    goto after_getkey;
-  case 13:
-    item_receipt_method = 0;
-    Link_ReceiveItem(0x32, 0);
-  after_getkey:
-    sprite_N[k] = sprite_subtype[k];
-    dung_savegame_state_bits |= kAbsorbBigKey[sprite_die_action[k]] << 8;
-    Sprite_ManuallySetDeathFlagUW(k);
-    break;
-  case 14:
-    link_shield_type = sprite_subtype[k];
-    // Shield needs to have the right palette after pikit
-    if (enhanced_features0 & kFeatures0_MiscBugFixes)
-      Palette_Load_Shield();
-    break;
-  }
-}
-
-bool SpriteDraw_AbsorbableTransient(int k, bool transient) {  // 86d22f
-  if (transient && Sprite_ReturnIfPhasingOut(k))
-    return false;
-  if (sort_sprites_setting == 0 && player_is_indoors != 0)
-    sprite_obj_prio[k] = 0x30;
-  if (byte_7E0FC6 >= 3)
-    return false;
-  if (sprite_delay_aux2[k] != 0)
-    Oam_AllocateFromRegionC(12);
-  if (sprite_E[k] != 0) {
-    // This code runs when an absorbable is hidden under say a rock.
-    // sprite_B holds the sprite that grabbed us with a hookshot.
-    // Cancel the grab if we're hidden.
-    if (enhanced_features0 & kFeatures0_MiscBugFixes)
-      sprite_B[k] = 0;
-    return true;
-  }
-  uint8 j = sprite_type[k];
-  assert(j >= 0xd8 && j < 0xd8 + 19);
-  uint8 a = kAbsorbable_Tab2[j - 0xd8];
-  if (a != 0) {
-    Sprite_DrawNumberedAbsorbable(k, a);
-    return false;
-  }
-  uint8 t = kAbsorbable_Tab1[j - 0xd8];
-  if (t == 0) {
-    SpriteDraw_SingleSmall(k);
-    return false;
-  }
-  if (t == 2) {
-    if (sprite_type[k] == 0xe6) {
-      if (sprite_subtype[k] == 1)
-        goto draw_key;
-      sprite_graphics[k] = 1;
-    }
-    SpriteDraw_SingleLarge(k);
-    return false;
-  }
-draw_key:
-  Sprite_DrawThinAndTall(k);
-  return false;
-}
-
-void Sprite_DrawNumberedAbsorbable(int k, int a) {  // 86d2fa
-  a = (a - 1) * 3;
-  PrepOamCoordsRet info;
-  if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
-    return;
-  OamEnt *oam = GetOamCurPtr();
-  int n = (sprite_head_dir[k] < 1) ? 2 : 1;
-  do {
-    int j = n + a;
-    SetOamHelper0(oam,
-                  info.x + kNumberedAbsorbable_X[j], info.y + kNumberedAbsorbable_Y[j],
-                  kNumberedAbsorbable_Char[j], info.flags,
-                  kNumberedAbsorbable_Ext[j]);
-  } while (oam++, --n >= 0);
-  SpriteDraw_Shadow(k, &info);
-}
-
-void Sprite_BounceOffWall(int k) {  // 86d9c0
-  if (sprite_wallcoll[k] & 3)
-    sprite_x_vel[k] = -sprite_x_vel[k];
-  if (sprite_wallcoll[k] & 12)
-    sprite_y_vel[k] = -sprite_y_vel[k];
-}
-
-void Sprite_InvertSpeed_XY(int k) {  // 86d9d5
-  sprite_x_vel[k] = -sprite_x_vel[k];
-  sprite_y_vel[k] = -sprite_y_vel[k];
-}
-
-bool Sprite_ReturnIfInactive(int k) {  // 86d9ec
-  return (sprite_state[k] != 9 || flag_unk1 || submodule_index || !(sprite_defl_bits[k] & 0x80) && sprite_pause[k]);
-}
-
-bool Sprite_ReturnIfPaused(int k) {  // 86d9f3
-  return (flag_unk1 || submodule_index || !(sprite_defl_bits[k] & 0x80) && sprite_pause[k]);
-}
-
-void SpriteDraw_SingleLarge(int k) {  // 86dc10
-  PrepOamCoordsRet info;
-  if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
-    return;
-  Sprite_PrepAndDrawSingleLargeNoPrep(k, &info);
-}
-
-void Sprite_PrepAndDrawSingleLargeNoPrep(int k, PrepOamCoordsRet *info) {  // 86dc13
-  OamEnt *oam = GetOamCurPtr();
-  oam->x = info->x;
-  if ((uint16)(info->y + 0x10) < 0x100) {
-    oam->y = info->y;
-    oam->charnum = kSprite_PrepAndDrawSingleLarge_Tab2[kSprite_PrepAndDrawSingleLarge_Tab1[sprite_type[k]] + sprite_graphics[k]];
-    oam->flags = info->flags;
-  }
-  bytewise_extended_oam[oam - oam_buf] = 2 | ((info->x >= 256) ? 1: 0);
-  if (sprite_flags3[k] & 0x10)
-    SpriteDraw_Shadow(k, info);
-}
-
-void SpriteDraw_Shadow_custom(int k, PrepOamCoordsRet *info, uint8 a) {  // 86dc5c
-  uint16 y = Sprite_GetY(k) + a;
-  info->y = y;
-  if (sprite_pause[k] || sprite_state[k] == 10 && sprite_unk3[k] == 3)
-    return;
-  y -= BG2VOFS_copy2;
-  info->y = y;
-  if ((uint16)(y + 0x10) >= 0x100)
-    return;
-  OamEnt *oam = GetOamCurPtr() + (sprite_flags2[k] & 0x1f);
-  if (sprite_flags3[k] & 0x20) {
-    SetOamHelper1(oam, info->x, y + 1, 0x38, (info->flags & 0x30) | 8, 0);
-  } else {
-    SetOamHelper1(oam, info->x, y, 0x6c, (info->flags & 0x30) | 8, 2);
-  }
-}
-
-void SpriteDraw_Shadow(int k, PrepOamCoordsRet *oam) {  // 86dc64
-  SpriteDraw_Shadow_custom(k, oam, 10);
-}
-
-void SpriteDraw_SingleSmall(int k) {  // 86dcef
-  PrepOamCoordsRet info;
-  if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
-    return;
-  OamEnt *oam = GetOamCurPtr();
-  oam->x = info.x;
-  if ((uint16)(info.y + 0x10) < 0x100) {
-    oam->y = info.y;
-    oam->charnum = kSprite_PrepAndDrawSingleLarge_Tab2[kSprite_PrepAndDrawSingleLarge_Tab1[sprite_type[k]] + sprite_graphics[k]];
-    oam->flags = info.flags;
-  }
-  bytewise_extended_oam[oam - oam_buf] = 0 | (info.x >= 256);
-  if (sprite_flags3[k] & 0x10)
-    SpriteDraw_Shadow_custom(k, &info, 2);
-}
-
-void Sprite_DrawThinAndTall(int k) {  // 86dd40
-  PrepOamCoordsRet info;
-  if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
-    return;
-  OamEnt *oam = GetOamCurPtr();
-  uint8 a = kSprite_PrepAndDrawSingleLarge_Tab2[kSprite_PrepAndDrawSingleLarge_Tab1[sprite_type[k]] + sprite_graphics[k]];
-  SetOamHelper0(oam + 0, info.x, info.y + 0, a + 0x00, info.flags, 0);
-  SetOamHelper0(oam + 1, info.x, info.y + 8, a + 0x10, info.flags, 0);
-  if (sprite_flags3[k] & 0x10)
-    SpriteDraw_Shadow(k, &info);
-}
-
-void SpriteModule_Carried(int k) {  // 86de83
-
-
-  static const uint8 kSpriteHeld_ZForFrame[6] = {3, 2, 1, 3, 2, 1};
-  static const int8 kSpriteHeld_X[16] = {0, 0, 0, 0, 0, 0, 0, 0, -13, -10, -5, 0, 13, 10, 5, 0};
-  static const uint8 kSpriteHeld_Z[16] = {13, 14, 15, 16, 0, 10, 22, 16, 8, 11, 14, 16, 8, 11, 14, 16};
-  sprite_room[k] = overworld_area_index;
-  if (sprite_unk3[k] != 3) {
-    if (sprite_delay_main[k] == 0) {
-      sprite_delay_main[k] = (sprite_C[k] == 6) ? 8 : 4;
-      sprite_unk3[k]++;
-    }
-  } else {
-    sprite_flags3[k] &= ~0x10;
-  }
-
-  uint8 t = sprite_delay_aux4[k] - 1;
-  uint8 r0 = t < 63 && (t & 2);
-  int j = link_direction_facing * 2 + sprite_unk3[k];
-
-  int t0 = (uint8)link_x_coord + (uint8)kSpriteHeld_X[j];
-  int t1 = (uint8)t0 + (t0 >> 8 & 1) + r0;
-  int t2 = HIBYTE(link_x_coord) + (t1 >> 8 & 1) + (t0 >> 8 & 1) + (uint8)(kSpriteHeld_X[j]>>8);
-  sprite_x_lo[k] = t1;
-  sprite_x_hi[k] = t2;
-
- // Sprite_SetX(k, link_x_coord + kSpriteHeld_X[j] + r0);
-  sprite_z[k] = kSpriteHeld_Z[j];
-  int an = link_animation_steps < 6 ? link_animation_steps : 0;
-  uint16 z = link_z_coord + 1 + kSpriteHeld_ZForFrame[an];
-  Sprite_SetY(k, link_y_coord + 8 - z);
-  sprite_floor[k] = link_is_on_lower_level & 1;
-  CarriedSprite_CheckForThrow(k);
-  Sprite_Get16BitCoords(k);
-  if (sprite_unk4[k] != 11) {
-    SpriteActive_Main(k);
-    if (sprite_delay_aux4[k] == 1) {
-      sprite_state[k] = 9;
-      sprite_B[k] = 0;
-      sprite_delay_aux4[k] = 96;
-      sprite_z_vel[k] = 32;
-      sprite_flags3[k] |= 0x10;
-      link_picking_throw_state = 2;
-    }
-  } else {
-    SpriteStunned_Main_Func1(k);
-  }
-}
-
-void CarriedSprite_CheckForThrow(int k) {  // 86df6d
-  static const int8 kSpriteHeld_Throw_Xvel[4] = {0, 0, -62, 63};
-  static const int8 kSpriteHeld_Throw_Yvel[4] = {-62, 63, 0, 0};
-  static const uint8 kSpriteHeld_Throw_Zvel[4] = {4, 4, 4, 4};
-
-  if (main_module_index == 14)
-    return;
-
-  if (player_near_pit_state != 2) {
-    uint8 t = (link_auxiliary_state & 1) | link_is_in_deep_water | link_is_bunny_mirror |
-              link_pose_for_item | (link_disable_sprite_damage ? 0 : link_incapacitated_timer);
-    if (!t) {
-      if (sprite_unk3[k] != 3 || !((filtered_joypad_H | filtered_joypad_L) & 0x80))
-        return;
-      filtered_joypad_L &= 0x7f;
-    }
-  }
-
-  SpriteSfx_QueueSfx3WithPan(k, 0x13);
-  link_picking_throw_state = 2;
-  sprite_state[k] = sprite_unk4[k];
-  sprite_z_vel[k] = 0;
-  sprite_unk3[k] = 0;
-  sprite_flags3[k] = sprite_flags3[k] & ~0x10 | kSpriteInit_Flags3[sprite_type[k]] & 0x10;
-  int j = link_direction_facing >> 1;
-  sprite_x_vel[k] = kSpriteHeld_Throw_Xvel[j];
-  sprite_y_vel[k] = kSpriteHeld_Throw_Yvel[j];
-  sprite_z_vel[k] = kSpriteHeld_Throw_Zvel[j];
-  sprite_delay_aux4[k] = 0;
-}
-
-void SpriteModule_Stunned(int k) {  // 86dffa
-  SpriteStunned_MainEx(k, false);
-}
-
-void ThrownSprite_TileAndSpriteInteraction(int k) {  // 86e02a
-  SpriteStunned_MainEx(k, true);
-}
-
-void Sprite_Func8(int k) {  // 86e0ab
-  sprite_state[k] = 1;
-  sprite_delay_main[k] = 0x1f;
-  sound_effect_1 = 0;
-  SpriteSfx_QueueSfx2WithPan(k, 0x20);
-}
-
-void Sprite_Func22(int k) {  // 86e0f6
-  sound_effect_1 = Sprite_CalculateSfxPan(k) | 0x28;
-  sprite_state[k] = 3;
-  sprite_delay_main[k] = 15;
-  sprite_ai_state[k] = 0;
-  GetRandomNumber(); // wtf
-  sprite_flags2[k] = 3;
-}
-
-void ThrowableScenery_InteractWithSpritesAndTiles(int k) {  // 86e164
-  Sprite_MoveXY(k);
-  if (!sprite_E[k])
-    Sprite_CheckTileCollision(k);
-  ThrownSprite_TileAndSpriteInteraction(k);
-}
-
-void ThrownSprite_CheckDamageToSprites(int k) {  // 86e172
-  if (sprite_delay_aux4[k] || !(sprite_x_vel[k] | sprite_y_vel[k]))
-    return;
-  for (int i = 15; i >= 0; i--) {
-    if (i != cur_object_index && sprite_type[k] != 0xd2 && sprite_state[i] >= 9 &&
-      ((i ^ frame_counter) & 3 | sprite_ignore_projectile[i] | sprite_hit_timer[i]) == 0 && sprite_floor[k] == sprite_floor[i])
-      ThrownSprite_CheckDamageToSingleSprite(k, i);
-  }
-}
-
-void ThrownSprite_CheckDamageToSingleSprite(int k, int j) {  // 86e1b2
-  SpriteHitBox hb;
-  hb.r0_xlo = sprite_x_lo[k];
-  hb.r8_xhi = sprite_x_hi[k];
-  hb.r2 = 15;
-  int t = sprite_y_lo[k] - sprite_z[k];
-  int u = (t & 0xff) + 8;
-  hb.r1_ylo = u;
-  hb.r9_yhi = sprite_y_hi[k] + (u >> 8) - (t < 0);
-  hb.r3 = 8;
-  Sprite_SetupHitBox(j, &hb);
-  if (!CheckIfHitBoxesOverlap(&hb))
-    return;
-  if (sprite_type[j] == 0x3f) {
-    Sprite_PlaceWeaponTink(k);
-  } else {
-    uint8 a = (sprite_type[k] == 0xec && sprite_C[k] == 2 && !player_is_indoors) ? 1 : 3;
-    Ancilla_CheckDamageToSprite_preset(j, a);
-
-    sprite_x_recoil[j] = sprite_x_vel[k] * 2;
-    sprite_y_recoil[j] = sprite_y_vel[k] * 2;
-    sprite_delay_aux4[k] = 16;
-  }
-  Sprite_ApplyRicochet(k);
-}
-
-void Sprite_ApplyRicochet(int k) {  // 86e229
-  Sprite_InvertSpeed_XY(k);
-  Sprite_HalveSpeed_XY(k);
-  ThrowableScenery_TransmuteIfValid(k);
-}
-
-void ThrowableScenery_TransmuteIfValid(int k) {  // 86e22f
-  if (sprite_type[k] != 0xec)
-    return;
-  repulsespark_timer = 0;
-  ThrowableScenery_TransmuteToDebris(k);
-}
-
-void ThrowableScenery_TransmuteToDebris(int k) {  // 86e239
-  uint8 a = sprite_graphics[k];
-  if (a != 0) {
-    BYTE(dung_secrets_unk1) = a;
-    Sprite_SpawnSecret(k);
-    BYTE(dung_secrets_unk1) = 0;
-  }
-  a = player_is_indoors ? 0 : sprite_C[k];
-  sound_effect_1 = 0;
-  SpriteSfx_QueueSfx2WithPan(k, kSprite_Func21_Sfx[a]);
-  Sprite_ScheduleForBreakage(k);
-}
-
-void Sprite_ScheduleForBreakage(int k) {  // 86e25a
-  sprite_delay_main[k] = 31;
-  sprite_state[k] = 6;
-  sprite_flags2[k] += 4;
-}
-
-void Sprite_HalveSpeed_XY(int k) {  // 86e26e
-  sprite_x_vel[k] = (int8)sprite_x_vel[k] >> 1;
-  sprite_y_vel[k] = (int8)sprite_y_vel[k] >> 1;
-}
-
-void Sprite_SpawnLeapingFish(int k) {  // 86e286
-  SpriteSpawnInfo info;
-  int j = Sprite_SpawnDynamically(k, 0xd2, &info);
-  if (j < 0)
-    return;
-  Sprite_SetSpawnedCoordinates(j, &info);
-  sprite_ai_state[j] = 2;
-  sprite_delay_main[j] = 48;
-  if (sprite_type[k] == 0xd2)
-    sprite_A[j] = 0xd2;
-}
-
-void SpriteStunned_Main_Func1(int k) {  // 86e2ba
-  SpriteActive_Main(k);
-  if (sprite_unk5[k]) {
-    if (sprite_delay_main[k] < 32)
-      sprite_oam_flags[k] = sprite_oam_flags[k] & 0xf1 | 4;
-    uint8 t = ((k << 4) ^ frame_counter) | submodule_index;
-    if (t & kSpriteStunned_Main_Func1_Masks[sprite_delay_main[k] >> 4])
-      return;
-    uint16 x = kSparkleGarnish_XY[GetRandomNumber() & 3];
-    uint16 y = kSparkleGarnish_XY[GetRandomNumber() & 3];
-    Sprite_GarnishSpawn_Sparkle(k, x, y);
-  } else {
-    if ((frame_counter & 1) | submodule_index | flag_unk1)
-      return;
-    uint8 t = sprite_stunned[k];
-    if (t) {
-      sprite_stunned[k]--;
-      if (t < 0x38) {
-        sprite_x_vel[k] = (t & 1) ? -8 : 8;
-        Sprite_MoveX(k);
-      }
-      return;
-    }
-    sprite_state[k] = 9;
-    sprite_x_recoil[k] = 0;
-    sprite_y_recoil[k] = 0;
-  }
-}
-
-void SpriteModule_Poof(int k) {  // 86e393
-  static const int8 kSpritePoof_X[16] = {-6, 10, 1, 13, -6, 10, 1, 13, -7, 4, -5, 6, -1, 1, -2, 0};
-  static const int8 kSpritePoof_Y[16] = {-6, -4, 10, 9, -6, -4, 10, 9, -8, -10, 4, 3, -1, -2, 0, 1};
-  static const uint8 kSpritePoof_Char[16] = {0x9b, 0x9b, 0x9b, 0x9b, 0xb3, 0xb3, 0xb3, 0xb3, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a};
-  static const uint8 kSpritePoof_Flags[16] = {0x24, 0xa4, 0x24, 0xa4, 0xe4, 0x64, 0xa4, 0x24, 0x24, 0xe4, 0xe4, 0xe4, 0x24, 0xe4, 0xe4, 0xe4};
-  static const uint8 kSpritePoof_Ext[16] = {0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2};
-  // Frozen sprite pulverized by hammer
-  if (sprite_delay_main[k] == 0) {
-    if (sprite_type[k] == 0xd && sprite_head_dir[k] != 0) {
-      // buzz blob?
-      int bakx = Sprite_GetX(k);
-      PrepareEnemyDrop(k, 0xd);
-      Sprite_SetX(k, bakx);
-      sprite_z_vel[k] = 0;
-      sprite_ignore_projectile[k] = 0;
-    } else {
-      if (sprite_die_action[k] == 0) {
-        ForcePrizeDrop(k, 2, 2);
-      } else {
-        Sprite_DoTheDeath(k);
-      }
-    }
-  } else {
-    PrepOamCoordsRet info;
-    if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
-      return;
-    OamEnt *oam = GetOamCurPtr();
-    int j = ((sprite_delay_main[k] >> 1) & ~3) + 3;
-    for (int i = 3; i >= 0; i--, j--, oam++) {
-      SetOamPlain(oam, kSpritePoof_X[j] + BYTE(dungmap_var7), kSpritePoof_Y[j] + HIBYTE(dungmap_var7),
-                   kSpritePoof_Char[j], kSpritePoof_Flags[j], kSpritePoof_Ext[j]);
-    }
-    Sprite_CorrectOamEntries(k, 3, 0xff);
-  }
-}
-
-void Sprite_PrepOamCoord(int k, PrepOamCoordsRet *ret) {  // 86e416
-  Sprite_PrepOamCoordOrDoubleRet(k, ret);
-}
-
-bool Sprite_PrepOamCoordOrDoubleRet(int k, PrepOamCoordsRet *ret) {  // 86e41e
-  sprite_pause[k] = 0;
-  uint16 x = cur_sprite_x - BG2HOFS_copy2;
-  uint16 y = cur_sprite_y - BG2VOFS_copy2;
-  bool out_of_bounds = false;
-  R0 = x;
-  R2 = y - sprite_z[k];
-  ret->flags = sprite_oam_flags[k] ^ sprite_obj_prio[k];
-  ret->r4 = 0;
-  int xt = (enhanced_features0 & kFeatures0_ExtendScreen64) ? 0x40 : 0;
-
-  if ((uint16)(x + 0x40 + xt) >= (0x170 + xt * 2) ||
-      (uint16)(y + 0x40) >= 0x170 && !(sprite_flags4[k] & 0x20)) {
-    sprite_pause[k]++;
-    if (!(sprite_defl_bits[k] & 0x80))
-      Sprite_KillSelf(k);
-    out_of_bounds = true;
-  }
-  ret->x = R0;
-  ret->y = R2;
-  BYTE(dungmap_var7) = ret->x;
-  HIBYTE(dungmap_var7) = ret->y;
-  return out_of_bounds;
-}
-
-void Sprite_CheckTileCollision2(int k) {  // 86e4ab
-  sprite_wallcoll[k] = 0;
-  if (sign8(sprite_flags4[k]) || !dung_hdr_collision) {
-    Sprite_CheckTileCollisionSingleLayer(k);
-    return;
-  }
-  byte_7E0FB6 = sprite_floor[k];
-  sprite_floor[k] = 1;
-  Sprite_CheckTileCollisionSingleLayer(k);
-  if (dung_hdr_collision == 4) {
-    sprite_floor[k] = byte_7E0FB6;
-    return;
-  }
-  sprite_floor[k] = 0;
-  Sprite_CheckTileCollisionSingleLayer(k);
-  byte_7FFABC[k] = sprite_tiletype;
-}
-
-void Sprite_CheckTileCollisionSingleLayer(int k) {  // 86e4db
-  if (sprite_flags2[k] & 0x20) {
-    if (Sprite_CheckTileProperty(k, 0x6a))
-      sprite_wallcoll[k]++;
-    return;
-  }
-
-  if (sign8(sprite_flags4[k]) || dung_hdr_collision == 0) {
-    if (sprite_y_vel[k])
-      Sprite_CheckForTileInDirection_vertical(k, sign8(sprite_y_vel[k]) ? 0 : 1);
-    if (sprite_x_vel[k])
-      Sprite_CheckForTileInDirection_horizontal(k, sign8(sprite_x_vel[k]) ? 2 : 3);
-  } else {
-    Sprite_CheckForTileInDirection_vertical(k, 1);
-    Sprite_CheckForTileInDirection_vertical(k, 0);
-    Sprite_CheckForTileInDirection_horizontal(k, 3);
-    Sprite_CheckForTileInDirection_horizontal(k, 2);
-  }
-
-  if (sign8(sprite_flags5[k]) || sprite_z[k])
-    return;
-
-  Sprite_CheckTileProperty(k, 0x68);
-  sprite_I[k] = sprite_tiletype;
-  if (sprite_tiletype == 0x1c) {
-    if (sort_sprites_setting && sprite_state[k] == 11)
-      sprite_floor[k] = 1;
-  } else if (sprite_tiletype == 0x20) {
-    if (sprite_flags[k] & 1) {
-      if (!player_is_indoors) {
-        Sprite_Func8(k);
-      } else {
-        sprite_state[k] = 5;
-        if (sprite_type[k] == 0x13 || sprite_type[k] == 0x26) {
-          sprite_oam_flags[k] &= ~1;
-          sprite_delay_main[k] = 63;
-        } else {
-          sprite_delay_main[k] = 95;
-        }
-      }
-    }
-  } else if (sprite_tiletype == 0xc) {
-    if (byte_7FFABC[k] == 0x1c) {
-      SpriteFall_AdjustPosition(k);
-      sprite_wallcoll[k] |= 0x20;
-    }
-  } else if (sprite_tiletype >= 0x68 && sprite_tiletype < 0x6c) {
-    Sprite_ApplyConveyor(k, sprite_tiletype);
-  } else if (sprite_tiletype == 8) {
-    if (dung_hdr_collision == 4)
-      Sprite_ApplyConveyor(k, 0x6a);
-  }
-}
-
-void Sprite_CheckForTileInDirection_horizontal(int k, int yy) {  // 86e5b8
-  if (!Sprite_CheckTileInDirection(k, yy))
-    return;
-  sprite_wallcoll[k] |= kSprite_Func7_Tab[yy];
-  if ((sprite_subtype[k] & 7) < 5) {
-    int8 n = sprite_F[k] ? 3 : 1;
-    SpriteAddXY(k, (yy & 1) ? -n : n, 0);
-  }
-}
-
-void Sprite_CheckForTileInDirection_vertical(int k, int yy) {  // 86e5ee
-  if (!Sprite_CheckTileInDirection(k, yy))
-    return;
-  sprite_wallcoll[k] |= kSprite_Func7_Tab[yy];
-  if ((sprite_subtype[k] & 7) < 5) {
-    int8 n = sprite_F[k] ? 3 : 1;
-    SpriteAddXY(k, 0, (yy & 1) ? -n : n);
-  }
-}
-
-void SpriteFall_AdjustPosition(int k) {  // 86e624
-  SpriteAddXY(k, dung_floor_x_vel, dung_floor_y_vel);
-}
-
-bool Sprite_CheckTileInDirection(int k, int yy) {  // 86e72f
-  uint8 t = (sprite_flags[k] & 0xf0);
-  yy = 2 * ((t >> 2) + yy);
-  return Sprite_CheckTileProperty(k, yy);
-}
-
-bool Sprite_CheckTileProperty(int k, int j) {  // 86e73c
-  uint16 x, y;
-  bool in_bounds;
-  j >>= 1;
-
-  if (player_is_indoors) {
-    x = (cur_sprite_x + 8 & 0x1ff) + kSprite_Func5_X[j] - 8;
-    y = (cur_sprite_y + 8 & 0x1ff) + kSprite_Func5_Y[j] - 8;
-    in_bounds = (x < 0x200) && (y < 0x200);
-  } else {
-    x = cur_sprite_x + kSprite_Func5_X[j];
-    y = cur_sprite_y + kSprite_Func5_Y[j];
-    in_bounds = (uint16)(x - sprcoll_x_base) < sprcoll_x_size &&
-                (uint16)(y - sprcoll_y_base) < sprcoll_y_size;
-  }
-  if (!in_bounds) {
-    if (sprite_flags2[k] & 0x40) {
-      sprite_state[k] = 0;
-      return false;
-    } else {
-      return true;
-    }
-  }
-
-  int b = Sprite_GetTileAttribute(k, &x, y);
-
-  if (sprite_defl_bits[k] & 8) {
-    uint8 a = kSprite_SimplifiedTileAttr[b];
-    if (a == 4) {
-      if (!player_is_indoors)
-        sprite_E[k] = 4;
-    } else if (a >= 1) {
-      return (sprite_tiletype >= 0x10 && sprite_tiletype < 0x14) ? Entity_CheckSlopedTileCollision(x, y) : true;
-    }
-    return false;
-  }
-
-  if (sprite_flags5[k] & 0x40) {
-    uint8 type = sprite_type[k];
-    if ((type == 0xd2 || type == 0x8a) && b == 9)
-      return false;
-    if (type == 0x94 && !sprite_E[k] || type == 0xe3 || type == 0x8c || type == 0x9a || type == 0x81)
-      return (b != 8) && (b != 9);
-  }
-
-  if (kSprite_Func5_Tab3[b] == 0)
-    return false;
-
-  if (sprite_tiletype >= 0x10 && sprite_tiletype < 0x14)
-    return Entity_CheckSlopedTileCollision(x, y);
-
-  if (sprite_tiletype == 0x44) {
-    if (sprite_F[k] && !sign8(sprite_give_damage[k])) {
-
-      // Some mothula bug fix because we changed damage class 4.
-      if (sprite_type[k] == 0x88 && (enhanced_features0 & kFeatures0_MiscBugFixes)) {
-        if (sprite_hit_timer[k] == 0)
-          Ancilla_CheckDamageToSprite_preset(k, 6);
-      } else {
-        Ancilla_CheckDamageToSprite_preset(k, 4);
-      }
-      if (sprite_hit_timer[k]) {
-        sprite_hit_timer[k] = 153;
-        sprite_F[k] = 0;
-      }
-    }
-  } else if (sprite_tiletype == 0x20) {
-    return !(sprite_flags[k] & 1) || !sprite_F[k];
-  }
-  return true;
-}
-
-uint8 GetTileAttribute(uint8 floor, uint16 *x, uint16 y) {  // 86e87b
-  uint8 tiletype;
-  if (player_is_indoors) {
-    int t = (floor >= 1) ? 0x1000 : 0;
-    t += (*x & 0x1f8) >> 3;
-    t += (y & 0x1f8) << 3;
-    tiletype = dung_bg2_attr_table[t];
-  } else {
-    tiletype = Overworld_GetTileAttributeAtLocation(*x >>= 3, y);
-  }
-  sprite_tiletype = tiletype;
-  return tiletype;
-}
-
-uint8 Sprite_GetTileAttribute(int k, uint16 *x, uint16 y) {  // 86e883
-  return GetTileAttribute(sprite_floor[k], x, y);
-}
-
-bool Entity_CheckSlopedTileCollision(uint16 x, uint16 y) {  // 86e8fe
-  uint8 a = y & 7;
-  uint8 r6 = sprite_tiletype - 0x10;
-  uint8 b = kSlopedTile[r6 * 8 + (x & 7)];
-  return (r6 < 2) ? (b >= a) : (a >= b);
-}
-
-void Sprite_MoveXY(int k) {  // 86e92c
-  Sprite_MoveX(k);
-  Sprite_MoveY(k);
-}
-
-void Sprite_MoveX(int k) {  // 86e932
-  if (sprite_x_vel[k] != 0) {
-    uint32 t = sprite_x_subpixel[k] + (sprite_x_lo[k] << 8) + (sprite_x_hi[k] << 16) + ((int8)sprite_x_vel[k] << 4);
-    sprite_x_subpixel[k] = t, sprite_x_lo[k] = t >> 8, sprite_x_hi[k] = t >> 16;
-  }
-}
-
-void Sprite_MoveY(int k) {  // 86e93e
-  if (sprite_y_vel[k] != 0) {
-    uint32 t = sprite_y_subpixel[k] + (sprite_y_lo[k] << 8) + (sprite_y_hi[k] << 16) + ((int8)sprite_y_vel[k] << 4);
-    sprite_y_subpixel[k] = t, sprite_y_lo[k] = t >> 8, sprite_y_hi[k] = t >> 16;
-  }
-}
-
-void Sprite_MoveZ(int k) {  // 86e96c
-  uint16 z = (sprite_z[k] << 8 | sprite_z_subpos[k]) + ((int8)sprite_z_vel[k] << 4);
-  sprite_z_subpos[k] = z;
-  sprite_z[k] = z >> 8;
-}
-
-ProjectSpeedRet Sprite_ProjectSpeedTowardsLink(int k, uint8 vel) {  // 86e991
-  if (vel == 0) {
-    ProjectSpeedRet rv = { 0, 0, 0, 0 };
-    return rv;
-  }
-  PairU8 below = Sprite_IsBelowLink(k);
-  uint8 r12 = sign8(below.b) ? -below.b : below.b;
-
-  PairU8 right = Sprite_IsRightOfLink(k);
-  uint8 r13 = sign8(right.b) ? -right.b : right.b;
-  uint8 t;
-  bool swapped = false;
-  if (r13 < r12) {
-    swapped = true;
-    t = r12, r12 = r13, r13 = t;
-  }
-  uint8 xvel = vel, yvel = 0;
-  t = 0;
-  do {
-    t += r12;
-    if (t >= r13)
-      t -= r13, yvel++;
-  } while (--vel);
-  if (swapped)
-    t = xvel, xvel = yvel, yvel = t;
-  ProjectSpeedRet rv = {
-    (uint8)(right.a ? -xvel : xvel),
-    (uint8)(below.a ? -yvel : yvel),
-    right.b,
-    below.b
-
-  };
-  return rv;
-}
-
-void Sprite_ApplySpeedTowardsLink(int k, uint8 vel) {  // 86ea04
-  ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLink(k, vel);
-  sprite_x_vel[k] = pt.x;
-  sprite_y_vel[k] = pt.y;
-}
-
-ProjectSpeedRet Sprite_ProjectSpeedTowardsLocation(int k, uint16 x, uint16 y, uint8 vel) {  // 86ea2d
-  if (vel == 0) {
-    ProjectSpeedRet rv = { 0, 0, 0, 0 };
-    return rv;
-  }
-  PairU8 below = Sprite_IsBelowLocation(k, y);
-  uint8 r12 = sign8(below.b) ? -below.b : below.b;
-
-  PairU8 right = Sprite_IsRightOfLocation(k, x);
-  uint8 r13 = sign8(right.b) ? -right.b : right.b;
-  uint8 t;
-  bool swapped = false;
-  if (r13 < r12) {
-    swapped = true;
-    t = r12, r12 = r13, r13 = t;
-  }
-  uint8 xvel = vel, yvel = 0;
-  t = 0;
-  do {
-    t += r12;
-    if (t >= r13)
-      t -= r13, yvel++;
-  } while (--vel);
-  if (swapped)
-    t = xvel, xvel = yvel, yvel = t;
-  ProjectSpeedRet rv = {
-    (uint8)(right.a ? -xvel : xvel),
-    (uint8)(below.a ? -yvel : yvel),
-    right.b,
-    below.b
-  };
-  return rv;
-}
-
-uint8 Sprite_DirectionToFaceLink(int k, PointU8 *coords_out) {  // 86eaa4
-  PairU8 below = Sprite_IsBelowLink(k);
-  PairU8 right = Sprite_IsRightOfLink(k);
-  uint8 ym = sign8(below.b) ? -below.b : below.b;
-  tmp_counter = ym;
-  uint8 xm = sign8(right.b) ? -right.b : right.b;
-  if (coords_out)
-    coords_out->x = right.b, coords_out->y = below.b;
-  return (xm >= ym) ? right.a : below.a + 2;
-}
-
-PairU8 Sprite_IsRightOfLink(int k) {  // 86ead1
-  uint16 x = link_x_coord - Sprite_GetX(k);
-  PairU8 rv = { (uint8)(sign16(x) ? 1 : 0), (uint8)x };
-  return rv;
-}
-
-PairU8 Sprite_IsBelowLink(int k) {  // 86eae8
-  int t = BYTE(link_y_coord) + 8;
-  int u = (t & 0xff) + sprite_z[k];
-  int v = (u & 0xff) - sprite_y_lo[k];
-  int w = HIBYTE(link_y_coord) - sprite_y_hi[k] - (v < 0);
-  uint8 y = (w & 0xff) + (t >> 8) + (u >> 8);
-  PairU8 rv = { (uint8)(sign8(y) ? 1 : 0), (uint8)v };
-  return rv;
-}
-
-PairU8 Sprite_IsRightOfLocation(int k, uint16 x) {  // 86eb0a
-  uint16 xv = x - Sprite_GetX(k);
-  PairU8 rv = { (uint8)(sign16(xv) ? 1 : 0), (uint8)xv };
-  return rv;
-}
-
-PairU8 Sprite_IsBelowLocation(int k, uint16 y) {  // 86eb1d
-  uint16 yv = y - Sprite_GetY(k);
-  PairU8 rv = { (uint8)(sign16(yv) ? 1 : 0), (uint8)yv };
-  return rv;
-}
-
-uint8 Sprite_DirectionToFaceLocation(int k, uint16 x, uint16 y) {  // 86eb30
-  PairU8 below = Sprite_IsBelowLocation(k, y);
-  PairU8 right = Sprite_IsRightOfLocation(k, x);
-  uint8 ym = sign8(below.b) ? -below.b : below.b;
-  tmp_counter = ym;
-  uint8 xm = sign8(right.b) ? -right.b : right.b;
-  return (xm >= ym) ? right.a : below.a + 2;
-}
-
-void Guard_ParrySwordAttacks(int k) {  // 86eb5e
-  if (link_is_on_lower_level != sprite_floor[k] || link_incapacitated_timer | link_auxiliary_state || sign8(sprite_hit_timer[k]))
-    return;
-  SpriteHitBox hb;
-  Sprite_DoHitBoxesFast(k, &hb);
-  if (link_position_mode & 0x10 || player_oam_y_offset == 0x80) {
-    Sprite_AttemptDamageToLinkWithCollisionCheck(k);
-    return;
-  }
-  Player_SetupActionHitBox(&hb);
-  if (sign8(button_b_frames) || !CheckIfHitBoxesOverlap(&hb)) {
-    Sprite_SetupHitBox(k, &hb);
-    if (!CheckIfHitBoxesOverlap(&hb))
-      Sprite_AttemptDamageToLinkWithCollisionCheck(k);
-    else
-      Sprite_AttemptZapDamage(k);
-    return;
-  }
-  if (sprite_type[k] != 0x6a)
-    sprite_F[k] = kSprite_Func1_Tab[GetRandomNumber() & 7];
-  link_incapacitated_timer = kSprite_Func1_Tab2[GetRandomNumber() & 7];
-  ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLink(k, sign8(button_b_frames - 9) ? 32 : 24);
-  sprite_x_recoil[k] = -pt.x;
-  sprite_y_recoil[k] = -pt.y;
-  Sprite_ApplyRecoilToLink(k, sign8(button_b_frames - 9) ? 8 : 16);
-  Link_PlaceWeaponTink();
-  set_when_damaging_enemies = 0x90;
-}
-
-void Sprite_AttemptZapDamage(int k) {  // 86ec02
-  uint8 a = sprite_type[k];
-  if ((a == 0x7a || a == 0xd && (a = link_sword_type) < 4 || (a == 0x24 || a == 0x23) && sprite_delay_main[k] != 0) && sprite_state[k] == 9) {
-    if (!countdown_for_blink) {
-      sprite_delay_aux1[k] = 64;
-      link_electrocute_on_touch = 64;
-      Sprite_AttemptDamageToLinkPlusRecoil(k);
-    }
-  } else {
-    ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLink(k, sign8(button_b_frames - 9) ? 0x50 : 0x40);
-    sprite_x_recoil[k] = -pt.x;
-    sprite_y_recoil[k] = -pt.y;
-    Sprite_CalculateSwordDamage(k);
-  }
-}
-
-void Ancilla_CheckDamageToSprite_preset(int k, int a) {  // 86ece0
-  if (a == 15 && sprite_z[k] != 0)
-    return;
-
-  if (a != 0 && a != 7) {
-    Sprite_Func15(k, a);
-    return;
-  }
-  Sprite_Func15(k, a);
-  if (sprite_give_damage[k] || repulsespark_timer)
-    return;
-  // Called when hitting enemy which is frozen
-  repulsespark_timer = 5;
-  int j = byte_7E0FB6;
-  repulsespark_x_lo = ancilla_x_lo[j] + 4;
-  repulsespark_y_lo = ancilla_y_lo[j];
-  repulsespark_floor_status = link_is_on_lower_level;
-  sound_effect_1 = 0;
-  SpriteSfx_QueueSfx2WithPan(k, 5);
-}
-
-void Sprite_Func15(int k, int a) {  // 86ed25
-  damage_type_determiner = a;
-  Sprite_ApplyCalculatedDamage(k, a == 8 ? 0x35 : 0x20);
-}
-
-void Sprite_CalculateSwordDamage(int k) {  // 86ed3f
-  if (sprite_flags3[k] & 0x40)
-    return;
-  sprite_unk1[k] = link_is_running;
-  uint8 a = link_sword_type - 1;
-  if (!link_is_running)
-    a |= sign8(button_b_frames) ? 4 : sign8(button_b_frames - 9) ? 0 : 8;
-  damage_type_determiner = kSprite_Func14_Damage[a];
-  if (link_item_in_hand & 10)
-    damage_type_determiner = 3;
-  link_sword_delay_timer = 4;
-  set_when_damaging_enemies = 16;
-  Sprite_ApplyCalculatedDamage(k, 0x9d);
-}
-
-void Sprite_ApplyCalculatedDamage(int k, int a) {  // 86ed89
-  if ((sprite_flags3[k] & 0x40) || sprite_type[k] >= 0xD8)
-    return;
-  uint8 dmg = kEnemyDamages[damage_type_determiner * 8 | enemy_damage_data[sprite_type[k] * 16 | damage_type_determiner]];
-  Sprite_GiveDamage(k, dmg, a);
-}
-
-void Sprite_GiveDamage(int k, uint8 dmg, uint8 r0_hit_timer) {  // 86edc5
-  if (dmg == 249) {
-    Sprite_Func18(k, 0xe3);
-    return;
-  }
-  if (dmg == 250) {
-    Sprite_Func18(k, 0x8f);
-    sprite_ai_state[k] = 2;
-    sprite_z_vel[k] = 32;
-    sprite_oam_flags[k] = 8;
-    sprite_F[k] = 0;
-    sprite_hit_timer[k] = 0;
-    sprite_health[k] = 0;
-    sprite_bump_damage[k] = 1;
-    sprite_flags5[k] = 1;
-    return;
-  }
-  if (dmg >= sprite_give_damage[k])
-    sprite_give_damage[k] = dmg;
-  if (dmg == 0) {
-    if (damage_type_determiner != 10) {
-      if (sprite_flags[k] & 4)
-        goto flag4;
-      link_sword_delay_timer = 0;
-    }
-    sprite_hit_timer[k] = 0;
-    sprite_give_damage[k] = 0;
-    return;
-  }
-  if (dmg >= 254 && sprite_state[k] == 11) {
-    sprite_hit_timer[k] = 0;
-    sprite_give_damage[k] = 0;
-    return;
-  }
-  if (sprite_type[k] == 0x9a && sprite_give_damage[k] < 0xf0) {
-    sprite_state[k] = 9;
-    sprite_ai_state[k] = 4;
-    sprite_delay_main[k] = 15;
-    SpriteSfx_QueueSfx2WithPan(k, 0x28);
-    return;
-  }
-  if (sprite_type[k] == 0x1b) {
-    SpriteSfx_QueueSfx2WithPan(k, 5);
-    Sprite_ScheduleForBreakage(k);
-    Sprite_PlaceWeaponTink(k);
-    return;
-  }
-  sprite_hit_timer[k] = r0_hit_timer;
-  if (sprite_type[k] != 0x92 || sprite_C[k] >= 3) {
-    uint8 sfx = sprite_flags[k] & 2 ? 0x21 :
-                sprite_flags5[k] & 0x10 ? 0x1c : 8;
-    sound_effect_2 = sfx | Sprite_CalculateSfxPan(k);
-  }
-  uint8 type;
-flag4:
-  type = sprite_type[k];
-  sprite_F[k] = (damage_type_determiner >= 13) ? 0 :
-                (type == 9) ? 20 :
-                (type == 0x53 || type == 0x18) ? 11 : 15;
-}
-
-void Sprite_Func18(int k, uint8 new_type) {  // 86edcb
-  sprite_type[k] = new_type;
-  SpritePrep_LoadProperties(k);
-  Sprite_SpawnPoofGarnish(k);
-  sound_effect_2 = 0;
-  SpriteSfx_QueueSfx3WithPan(k, 0x32);
-  sprite_hit_timer[k] = 0;
-  sprite_give_damage[k] = 0;
-}
-
-void Sprite_MiniMoldorm_Recoil(int k) {  // 86eec8
-  if (sprite_state[k] < 9)
-    return;
-  tmp_counter = sprite_state[k];
-
-  uint8 dmg = sprite_give_damage[k];
-  if (dmg == 253) {
-    sprite_give_damage[k] = 0;
-    SpriteSfx_QueueSfx3WithPan(k, 9);
-    sprite_state[k] = 7;
-    sprite_delay_main[k] = 0x70;
-    sprite_flags2[k] += 2;
-    sprite_give_damage[k] = 0;
-    return;
-  }
-
-  if (dmg >= 251) {
-    sprite_give_damage[k] = 0;
-    if (sprite_state[k] == 11)
-      return;
-    sprite_unk5[k] = (dmg == 254);
-    if (sprite_unk5[k]) {
-      sprite_defl_bits[k] |= 8;
-      sprite_flags5[k] &= ~0x80;
-      SpriteSfx_QueueSfx2WithPan(k, 15);
-      sprite_z_vel[k] = 24;
-      sprite_bump_damage[k] &= ~0x80;
-      Sprite_ZeroVelocity_XY(k);
-    }
-    sprite_state[k] = 11;
-    sprite_delay_main[k] = 64;
-    static const uint8 kHitTimer24StunValues[5] = {0x20, 0x80, 0, 0, 0xff};
-    sprite_stunned[k] = kHitTimer24StunValues[(uint8)(dmg + 5)];
-    if (sprite_type[k] == 0x23)
-      sprite_type[k] = 0x24;
-    return;
-  }
-
-  int t = sprite_health[k] - sprite_give_damage[k];
-  sprite_health[k] = t;
-  sprite_give_damage[k] = 0;
-  if (t > 0)
-    return;
-
-  if (sprite_die_action[k] == 0) {
-    if (sprite_state[k] == 11)
-      sprite_die_action[k] = 3;
-    if (sprite_unk1[k] != 0) {
-      sprite_unk1[k] = 0;
-      sprite_flags5[k] = 0;
-    }
-  }
-
-  uint8 type = sprite_type[k];
-  if (type != 0x1b)
-    SpriteSfx_QueueSfx3WithPan(k, 9);
-
-  if (type == 0x40)
-    save_ow_event_info[BYTE(overworld_screen_index)] |= 0x40;
-  else if (type == 0xec) {
-    if (sprite_C[k] == 2)
-      ThrowableScenery_TransmuteToDebris(k);
-    return;
-  }
-
-  if (sprite_state[k] == 10) {
-    link_state_bits = 0;
-    link_picking_throw_state = 0;
-  }
-  sprite_state[k] = 6;
-
-  if (type == 0xc) {
-    Sprite_Func3(k);
-  } else if (type == 0x92) {
-    Sprite_KillFriends();
-    sprite_delay_main[k] = 255;
-    goto out_common;
-  } else if (type == 0xcb) {
-    sprite_ai_state[k] = 128;
-    sprite_delay_main[k] = 128;
-    sprite_state[k] = 9;
-    goto out_common;
-  } else if (type == 0xcc || type == 0xcd) {
-    sprite_ai_state[k] = 128;
-    sprite_delay_main[k] = 96;
-    sprite_state[k] = 9;
-    goto out_common;
-  } else if (type == 0x53) {
-    sprite_delay_main[k] = 35;
-    sprite_hit_timer[k] = 0;
-    goto out_common2;
-  } else if (type == 0x54) {
-    sprite_ai_state[k] = 5;
-    sprite_delay_main[k] = 0xc0;
-    sprite_hit_timer[k] = 0xc0;
-    goto out_common;
-  } else if (type == 0x9) {
-    sprite_ai_state[k] = 3;
-    sprite_delay_aux4[k] = 160;
-    sprite_state[k] = 9;
-    goto out_common;
-  } else if (type == 0x7a) {
-    Sprite_KillFriends();
-    sprite_state[k] = 9;
-    sprite_ignore_projectile[k] = 9;
-    if (is_in_dark_world == 0) {
-      sprite_ai_state[k] = 10;
-      sprite_delay_main[k] = 255;
-      sprite_z_vel[k] = 32;
-    } else {
-      sprite_delay_main[k] = 255;
-      sprite_ai_state[k] = 8;
-      sprite_ai_state[1] = 9;
-      sprite_ai_state[2] = 9;
-      sprite_graphics[1] = 0;
-      sprite_graphics[2] = 0;
-    }
-    goto out_common;
-  } else if (type == 0x23 && sprite_C[k] == 0) {
-    sprite_ai_state[k] = 2;
-    sprite_delay_main[k] = 32;
-    sprite_state[k] = 9;
-    sprite_hit_timer[k] = 0;
-  } else if (type == 0xf) {
-    sprite_hit_timer[k] = 0;
-    sprite_delay_main[k] = 15;
-  } else if (!(sprite_flags[k] & 2)) {
-    sprite_delay_main[k] = sprite_hit_timer[k] & 0x80 ? 31 : 15;
-    sprite_flags2[k] += 4;
-    if (tmp_counter == 11)
-      sprite_flags5[k] = 1;
-  } else {
-    if (type != 0xa2)
-      Sprite_KillFriends();
-    sprite_state[k] = 4;
-    sprite_A[k] = 0;
-    sprite_delay_main[k] = 255;
-    sprite_hit_timer[k] = 255;
-  out_common:
-    flag_block_link_menu++;
-  out_common2:
-    sound_effect_2 = 0;
-    SpriteSfx_QueueSfx3WithPan(k, 0x22);
-  }
-}
-
-void Sprite_Func3(int k) {  // 86efda
-  sprite_state[k] = 6;
-  sprite_delay_main[k] = 31;
-  sprite_flags2[k] = 3;
-}
-
-bool Sprite_CheckDamageToLink(int k) {  // 86f145
-  if (link_disable_sprite_damage)
-    return false;
-  return Sprite_CheckDamageToPlayer_1(k);
-}
-
-bool Sprite_CheckDamageToPlayer_1(int k) {  // 86f14a
-  if ((k ^ frame_counter) & 3 | sprite_hit_timer[k])
-    return false;
-  return Sprite_CheckDamageToLink_same_layer(k);
-}
-
-bool Sprite_CheckDamageToLink_same_layer(int k) {  // 86f154
-  if (link_is_on_lower_level != sprite_floor[k])
-    return false;
-  return Sprite_CheckDamageToLink_ignore_layer(k);
-}
-
-bool Sprite_CheckDamageToLink_ignore_layer(int k) {  // 86f15c
-  uint8 carry, t;
-  if (sprite_flags4[k]) {
-    SpriteHitBox hitbox;
-    Link_SetupHitBox(&hitbox);
-
-    // Set hitbox to the sword hitbox if the item type is an absorbable
-    if (sprite_type[k] >= 0xd8 && sprite_type[k] <= 0xe6 && (enhanced_features0 & kFeatures0_CollectItemsWithSword))
-      Link_UpdateHitBoxWithSword(&hitbox);
-
-    Sprite_SetupHitBox(k, &hitbox);
-    carry = CheckIfHitBoxesOverlap(&hitbox);
-  } else {
-    carry = Sprite_SetupHitBox00(k);
-  }
-
-  if (sign8(sprite_flags2[k]))
-    return carry;
-
-  if (!carry || link_auxiliary_state)
-    return false;
-
-  if (link_is_bunny_mirror || sign8(link_state_bits) || !(sprite_flags5[k] & 0x20) || !link_shield_type)
-    goto if_3;
-  sprite_state[k] = 0;
-
-  t = button_b_frames ? kSpriteDamage_Tab2[link_direction_facing >> 1] : link_direction_facing;
-  if (t != kSpriteDamage_Tab3[sprite_D[k]]) {
-if_3:
-    Sprite_AttemptDamageToLinkPlusRecoil(k);
-    if (sprite_type[k] == 0xc)
-      Sprite_Func3(k);
-    return true;
-  }
-  SpriteSfx_QueueSfx2WithPan(k, 6);
-  Sprite_PlaceRupulseSpark_2(k);
-  if (sprite_type[k] == 0x95) {
-    SpriteSfx_QueueSfx3WithPan(k, 0x26);
-    return false;
-  } else if (sprite_type[k] == 0x9B) {
-    Sprite_Invert_XY_Speeds(k);
-    sprite_D[k] ^= 1;
-    sprite_ai_state[k]++;
-    sprite_state[k] = 9;
-    return false;
-  } else if (sprite_type[k] == 0x1B) { // arrow
-    Sprite_ScheduleForBreakage(k);
-    return false;  // unk ret val
-  } else if (sprite_type[k] == 0xc) {
-    Sprite_Func3(k);
-    return true;
-  } else {
-    return false;  // unk ret val
-  }
-}
-
-bool Sprite_SetupHitBox00(int k) {  // 86f1f6
-  return (uint16)(link_x_coord - cur_sprite_x + 11) < 23 &&
-         (uint16)(link_y_coord - cur_sprite_y + sprite_z[k] + 16) < 24;
-}
-
-bool Sprite_ReturnIfLifted(int k) {  // 86f228
-  if (submodule_index | button_b_frames | flag_unk1 || sprite_floor[k] != link_is_on_lower_level)
-    return false;
-  for (int j = 15; j >= 0; j--)
-    if (sprite_state[j] == 10)
-      return false;
-  if (sprite_type[k] != 0xb && sprite_type[k] != 0x4a && (sprite_x_vel[k] | sprite_y_vel[k]) != 0)
-    return false;
-  if (link_is_running)
-    return false;
-  return Sprite_ReturnIfLiftedPermissive(k);
-}
-
-bool Sprite_ReturnIfLiftedPermissive(int k) {  // 86f257
-  if (link_is_running)
-    return false;
-  if ((uint8)(flag_is_sprite_to_pick_up_cached - 1) != cur_object_index) {
-    SpriteHitBox hb;
-    Link_SetupHitBox_conditional(&hb);
-    Sprite_SetupHitBox(k, &hb);
-    if (CheckIfHitBoxesOverlap(&hb))
-      byte_7E0FB2 = flag_is_sprite_to_pick_up = k + 1;
-    return false;
-  } else {
-    BYTE(filtered_joypad_L) = 0;
-    sprite_E[k] = 0;
-    SpriteSfx_QueueSfx2WithPan(k, 0x1d);
-    sprite_unk4[k] = sprite_state[k];
-    sprite_state[k] = 10;
-    sprite_delay_main[k] = 16;
-    sprite_unk3[k] = 0;
-    sprite_I[k] = 0;
-    link_direction_facing = kSprite_ReturnIfLifted_Dirs[Sprite_DirectionToFaceLink(k, NULL)];
-    return true;
-  }
-}
-
-uint8 Sprite_CheckDamageFromLink(int k) {  // 86f2b4
-  if (sprite_hit_timer[k] & 0x80 || sprite_floor[k] != link_is_on_lower_level || player_oam_y_offset == 0x80)
-    return 0;
-
-  SpriteHitBox hb;
-  Player_SetupActionHitBox(&hb);
-  Sprite_SetupHitBox(k, &hb);
-  if (!CheckIfHitBoxesOverlap(&hb))
-    return 0;
-
-  set_when_damaging_enemies = 0;
-  if (link_position_mode & 0x10)
-    return kCheckDamageFromPlayer_Carry | kCheckDamageFromPlayer_Ne;
-
-  if (link_item_in_hand & 10) {
-    if (sprite_type[k] >= 0xd6)
-      return 0;
-    if (sprite_state[k] == 11 && sprite_unk5[k] != 0) {
-      sprite_state[k] = 2;
-      sprite_delay_main[k] = 32;
-      sprite_flags2[k] = (sprite_flags2[k] & 0xe0) | 3;
-      SpriteSfx_QueueSfx2WithPan(k, 0x1f);
-      return kCheckDamageFromPlayer_Carry | kCheckDamageFromPlayer_Ne;
-    }
-  }
-  uint8 type = sprite_type[k];
-  if (type == 0x7b) {
-    if (!sign8(button_b_frames - 9))
-      return 0;
-  } else if (type == 9) {
-    if (!sprite_A[k]) {
-      Sprite_ApplyRecoilToLink(k, 48);
-      set_when_damaging_enemies = 144;
-      link_incapacitated_timer = 16;
-      SpriteSfx_QueueSfx2WithPan(k, 0x21);
-      sprite_delay_aux1[k] = 48;
-      sound_effect_2 = Sprite_CalculateSfxPan(k) | (enhanced_features0 & kFeatures0_MiscBugFixes ? 0x32 : 0);
-      Link_PlaceWeaponTink();
-      return kCheckDamageFromPlayer_Carry;
-    }
-  } else if (type == 0x92) {
-    if (sprite_C[k] >= 3)
-      goto is_many;
-    goto getting_out;
-  } else if (type == 0x26 || type == 0x13 || type == 2) {
-    bool cond = (type == 0x13 && kSpriteDamage_Tab3[sprite_D[k]] == link_direction_facing) || (type == 2);
-    Sprite_AttemptZapDamage(k);
-    Sprite_ApplyRecoilToLink(k, 32);
-    set_when_damaging_enemies = 16;
-    link_incapacitated_timer = 16;
-    if (cond) {
-      sprite_hit_timer[k] = 0;
-      Link_PlaceWeaponTink();
-    }
-    return 0; // what return value?
-  } else if (type == 0xcb || type == 0xcd || type == 0xcc || type == 0xd6 || type == 0xd7 || type == 0xce || type == 0x54) {
-is_many:
-    Sprite_ApplyRecoilToLink(k, 32);
-    set_when_damaging_enemies = 144;
-    link_incapacitated_timer = 16;
-  }
-  if (!(sprite_defl_bits[k] & 4)) {
-    Sprite_AttemptZapDamage(k);
-    return kCheckDamageFromPlayer_Carry;
-  }
-getting_out:
-  if (!set_when_damaging_enemies) {
-    Sprite_ApplyRecoilToLink(k, 4);
-    link_incapacitated_timer = 16;
-    set_when_damaging_enemies = 16;
-  }
-  Link_PlaceWeaponTink();
-  return kCheckDamageFromPlayer_Carry;
-}
-
-void Sprite_AttemptDamageToLinkWithCollisionCheck(int k) {  // 86f3ca
-  if ((k ^ frame_counter) & 1)
-    return;
-  SpriteHitBox hb;
-  Sprite_DoHitBoxesFast(k, &hb);
-  Link_SetupHitBox_conditional(&hb);
-  if (CheckIfHitBoxesOverlap(&hb))
-    Sprite_AttemptDamageToLinkPlusRecoil(k);
-}
-
-void Sprite_AttemptDamageToLinkPlusRecoil(int k) {  // 86f3db
-  if (countdown_for_blink | link_disable_sprite_damage)
-    return;
-  link_incapacitated_timer = 19;
-  Sprite_ApplyRecoilToLink(k, 24);
-  link_auxiliary_state = 1;
-  link_give_damage = kPlayerDamages[3 * (sprite_bump_damage[k] & 0xf) + link_armor];
-  if (sprite_type[k] == 0x61 && sprite_C[k]) {
-    link_actual_vel_x = sprite_x_vel[k] * 2;
-    link_actual_vel_y = sprite_y_vel[k] * 2;
-  }
-}
-
-void Player_SetupActionHitBox(SpriteHitBox *hb) {  // 86f5e0
-  if (link_is_running) {
-    int j = link_direction_facing >> 1;
-    int x = link_x_coord + (kPlayerActionBoxRun_XLo[j] | kPlayerActionBoxRun_XHi[j] << 8);
-    int y = link_y_coord + (kPlayerActionBoxRun_YLo[j] | kPlayerActionBoxRun_YHi[j] << 8);
-    hb->r0_xlo = x;
-    hb->r8_xhi = x >> 8;
-    hb->r1_ylo = y;
-    hb->r9_yhi = y >> 8;
-    hb->r2 = hb->r3 = 16;
-  } else {
-    int t = 0;
-    if (!(link_item_in_hand & 10) && !(link_position_mode & 0x10)) {
-      if (sign8(button_b_frames)) {
-        int x = link_x_coord - 14;
-        int y = link_y_coord - 10;
-        hb->r0_xlo = x;
-        hb->r8_xhi = x >> 8;
-        hb->r1_ylo = y;
-        hb->r9_yhi = y >> 8;
-        hb->r2 = 44;
-        hb->r3 = 45;
-        return;
-      } else if (kPlayer_SetupActionHitBox_Tab4[button_b_frames]) {
-        hb->r8_xhi = 0x80;
-        return;
-      }
-      t = link_direction_facing * 8 + button_b_frames + 1;
-    }
-    int x = link_x_coord + (int8)(kPlayer_SetupActionHitBox_X[t] + player_oam_x_offset);
-    int y = link_y_coord + (int8)(kPlayer_SetupActionHitBox_Y[t] + player_oam_y_offset);
-    hb->r0_xlo = x;
-    hb->r8_xhi = x >> 8;
-    hb->r1_ylo = y;
-    hb->r9_yhi = y >> 8;
-    hb->r2 = kPlayer_SetupActionHitBox_W[t];
-    hb->r3 = kPlayer_SetupActionHitBox_H[t];
-  }
-}
-
-void Link_UpdateHitBoxWithSword(SpriteHitBox *hb) {  // new
-  if (link_spin_attack_step_counter != 0 || sign8(button_b_frames) ||
-      kPlayer_SetupActionHitBox_Tab4[button_b_frames])
-    return;
-  int t = link_direction_facing * 8 + button_b_frames + 1, r;
-  int x = link_x_coord + (int8)(kPlayer_SetupActionHitBox_X[t] + player_oam_x_offset);
-  int y = link_y_coord + (int8)(kPlayer_SetupActionHitBox_Y[t] + player_oam_y_offset);
-  // Reduce size of hitbox if 'too' big.
-  hb->r2 = kPlayer_SetupActionHitBox_W[t];
-  if (hb->r2 - 2 >= 0)
-    r = IntMin(6, hb->r2 - 2), hb->r2 -= r, x += r >> 1;
-  hb->r3 = kPlayer_SetupActionHitBox_H[t];
-  if (hb->r3 - 2 >= 0)
-    r = IntMin(6, hb->r3 - 2), hb->r3 -= r, y += r >> 1;
-  hb->r0_xlo = x;
-  hb->r8_xhi = x >> 8;
-  hb->r1_ylo = y;
-  hb->r9_yhi = y >> 8;
-}
-
-void Sprite_DoHitBoxesFast(int k, SpriteHitBox *hb) {  // 86f645
-  if (HIBYTE(dungmap_var8) == 0x80) {
-    hb->r10_spr_xhi = 0x80;
-    return;
-  }
-  int t;
-  t = Sprite_GetX(k) + (int8)HIBYTE(dungmap_var8);
-  hb->r4_spr_xlo = t;
-  hb->r10_spr_xhi = t >> 8;
-  t = Sprite_GetY(k) + (int8)BYTE(dungmap_var8);
-  hb->r5_spr_ylo = t;
-  hb->r11_spr_yhi = t >> 8;
-  hb->r6_spr_xsize = hb->r7_spr_ysize = (sprite_type[k] == 0x6a) ? 16 : 3;
-}
-
-void Sprite_ApplyRecoilToLink(int k, uint8 vel) {  // 86f688
-  ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLink(k, vel);
-  link_actual_vel_x = pt.x;
-  link_actual_vel_y = pt.y;
-  g_ram[0xc7] = link_actual_vel_z = vel >> 1;
-  link_z_coord = 0;
-}
-
-void Link_PlaceWeaponTink() {  // 86f69f
-  if (repulsespark_timer)
-    return;
-  repulsespark_timer = 5;
-  int t = (uint8)link_x_coord + player_oam_x_offset;
-  repulsespark_x_lo = t;
-  t = (uint8)link_y_coord + player_oam_y_offset + (t >> 8);  // carry wtf
-  repulsespark_y_lo = t;
-  repulsespark_floor_status = link_is_on_lower_level;
-  sound_effect_1 = Link_CalculateSfxPan() | 5;
-}
-
-void Sprite_PlaceWeaponTink(int k) {  // 86f6ca
-  if (repulsespark_timer)
-    return;
-  SpriteSfx_QueueSfx2WithPan(k, 5);
-  Sprite_PlaceRupulseSpark_2(k);
-}
-
-void Sprite_PlaceRupulseSpark_2(int k) {  // 86f6d5
-  uint16 x = Sprite_GetX(k) - BG2HOFS_copy2;
-  uint16 y = Sprite_GetY(k) - BG2VOFS_copy2;
-  if (x & ~0xff || y & ~0xff)
-    return;
-  repulsespark_x_lo = sprite_x_lo[k];
-  repulsespark_y_lo = sprite_y_lo[k];
-  repulsespark_timer = 5;
-  repulsespark_floor_status = sprite_floor[k];
-}
-
-void Link_SetupHitBox_conditional(SpriteHitBox *hb) {  // 86f705
-  if (link_disable_sprite_damage)
-    hb->r9_yhi = 0x80;
-  else
-    Link_SetupHitBox(hb);
-}
-
-void Link_SetupHitBox(SpriteHitBox *hb) {  // 86f70a
-  hb->r3 = hb->r2 = 8;
-  uint16 x = link_x_coord + 4;
-  hb->r0_xlo = x;
-  hb->r8_xhi = x >> 8;
-  uint16 y = link_y_coord + 8;
-  hb->r1_ylo = y;
-  hb->r9_yhi = y >> 8;
-}
-
-void Sprite_SetupHitBox(int k, SpriteHitBox *hb) {  // 86f7ef
-  if (sign8(sprite_z[k])) {
-    hb->r10_spr_xhi = 0x80;
-    return;
-  }
-  int i = sprite_flags4[k] & 0x1f;
-  int t, u;
-
-  t = sprite_x_lo[k] + (uint8)kSpriteHitbox_XLo[i];
-  hb->r4_spr_xlo = t;
-  t = sprite_x_hi[k] + (uint8)kSpriteHitbox_XHi[i] + (t >> 8);
-  hb->r10_spr_xhi = t;
-
-  t = sprite_y_lo[k] + (uint8)kSpriteHitbox_YLo[i];
-  u = t >> 8;
-  t = (t & 0xff) - sprite_z[k];
-  hb->r5_spr_ylo = t;
-  t = sprite_y_hi[k] - (t < 0);
-  hb->r11_spr_yhi = t + u + (uint8)kSpriteHitbox_YHi[i];
-
-  hb->r6_spr_xsize = kSpriteHitbox_XSize[i];
-  hb->r7_spr_ysize = kSpriteHitbox_YSize[i];
-}
-
-// Returns the carry flag
-bool CheckIfHitBoxesOverlap(SpriteHitBox *hb) {  // 86f836
-  int t;
-  uint8 r15, r12;
-
-  if (hb->r8_xhi == 0x80 || hb->r10_spr_xhi == 0x80)
-    return false;
-
-  t = hb->r5_spr_ylo - hb->r1_ylo;
-  r15 = t + hb->r7_spr_ysize;
-  r12 = hb->r11_spr_yhi - hb->r9_yhi - (t < 0);
-  t = r12 + (((t & 0xff) + 0x80) >> 8);
-  if (t & 0xff)
-    return (t >= 0x100);
-  if ((uint8)(hb->r3 + hb->r7_spr_ysize) < r15)
-    return false;
-
-  t = hb->r4_spr_xlo - hb->r0_xlo;
-  r15 = t + hb->r6_spr_xsize;
-  r12 = hb->r10_spr_xhi - hb->r8_xhi - (t < 0);
-  t = r12 + (((t & 0xff) + 0x80) >> 8);
-  if (t & 0xff)
-    return (t >= 0x100);
-  if ((uint8)(hb->r2 + hb->r6_spr_xsize) < r15)
-    return false;
-
-  return true;
-}
-
-void Oam_AllocateDeferToPlayer(int k) {  // 86f86c
-  if (sprite_floor[k] != link_is_on_lower_level)
-    return;
-  PairU8 right = Sprite_IsRightOfLink(k);
-  if ((uint8)(right.b + 0x10) >= 0x20)
-    return;
-  PairU8 below = Sprite_IsBelowLink(k);
-  if ((uint8)(below.b + 0x20) >= 0x48)
-    return;
-  uint8 nslots = ((sprite_flags2[k] & 0x1f) + 1) << 2;
-  if (below.a)
-    Oam_AllocateFromRegionC(nslots);
-  else
-    Oam_AllocateFromRegionB(nslots);
-}
-
-void SpriteModule_Die(int k) {  // 86f8a2
-  SpriteDeath_MainEx(k, false);
-}
-
-void Sprite_DoTheDeath(int k) {  // 86f923
-  uint8 type = sprite_type[k];
-  // This is how Vitreous knows whether to come out of his slime pool
-  if (type == 0xBE)
-    sprite_G[0]--;
-
-  if (type == 0xaa && sprite_E[k] != 0) {
-    uint8 bak = sprite_subtype[k];
-    PrepareEnemyDrop(k, kPikitDropItems[sprite_E[k] - 1]);
-    sprite_subtype[k] = bak;
-    if (bak == 1) {
-      sprite_oam_flags[k] = 9;
-      sprite_flags3[k] = 0xf0;
-    }
-    sprite_head_dir[k]++;
-    return;
-  }
-
-  // Resets the music in the village when the crazy green guards are killed.
-  if (type == 0x45 && sram_progress_indicator == 2 && BYTE(overworld_area_index) == 0x18)
-    music_control = 7;
-
-  uint8 drop_item = sprite_die_action[k];
-  if (drop_item != 0) {
-    sprite_subtype[k] = sprite_N[k];
-    sprite_N[k] = 255;
-    uint8 arg = (drop_item == 1) ? 0xe4 : // small key, big key or rupee
-                (drop_item == 3) ? 0xd9 : 0xe5;
-    PrepareEnemyDrop(k, arg);
-    return;
-  }
-
-  uint8 prize = sprite_flags5[k] & 0xf;
-  if (prize-- != 0) {
-    uint8 luck = item_drop_luck;
-    if (luck != 0) {
-      if (++luck_kill_counter >= 10)
-        item_drop_luck = 0;
-      if (luck == 1) {
-        ForcePrizeDrop(k, prize, 1);
-        return;
-      }
-    } else {
-      if (!(GetRandomNumber() & kPrizeMasks[prize])) {
-        ForcePrizeDrop(k, prize, prize);
-        return;
-      }
-    }
-  }
-  sprite_state[k] = 0;
-  SpriteDeath_Func4(k);
-}
-
-void ForcePrizeDrop(int k, uint8 prize, uint8 slot) {  // 86f9bc
-  prize = prize * 8 | prizes_arr1[slot];
-  prizes_arr1[slot] = (prizes_arr1[slot] + 1) & 7;
-  PrepareEnemyDrop(k, kPrizeItems[prize]);
-}
-
-void PrepareEnemyDrop(int k, uint8 item) {  // 86f9d1
-  sprite_type[k] = item;
-  if (item == 0xe5)
-    SpritePrep_BigKey_load_graphics(k);
-  else if (item == 0xe4)
-    SpritePrep_KeySetItemDrop(k);
-
-  sprite_state[k] = 9;
-  uint8 zbak = sprite_z[k];
-  SpritePrep_LoadProperties(k);
-  sprite_ignore_projectile[k]++;
-
-  uint8 pz = kPrizeZ[sprite_type[k] - 0xd8];
-  sprite_z_vel[k] = pz & 0xf0;
-  Sprite_SetX(k, Sprite_GetX(k) + (pz & 0xf));
-  sprite_z[k] = zbak;
-  sprite_delay_aux4[k] = 21;
-  sprite_stunned[k] = 255;
-  SpriteDeath_Func4(k);
-}
-
-void SpriteDeath_Func4(int k) {  // 86fa25
-  if (sprite_type[k] == 0xa2 && Sprite_CheckIfScreenIsClear())
-    Ancilla_SpawnFallingPrize(4);
-  Sprite_ManuallySetDeathFlagUW(k);
-  num_sprites_killed++;
-  if (sprite_type[k] == 0x40) {
-    // evil barrier
-    sprite_state[k] = 9;
-    sprite_graphics[k] = 4;
-    SpriteDeath_MainEx(k, true);
-  }
-}
-
-void SpriteDeath_DrawPoof(int k) {  // 86fb2a
-  if (dung_hdr_collision == 4)
-    sprite_obj_prio[k] = 0x30;
-  PrepOamCoordsRet info;
-  if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
-    return;
-  OamEnt *oam = GetOamCurPtr();
-  uint8 r12 = (sprite_flags3[k] & 0x20) >> 3;
-  int i = ((sprite_delay_main[k] & 0x1c) ^ 0x1c) + 3, n = 3;
-  do {
-    if (kPerishOverlay_Char[i]) {
-      oam->charnum = kPerishOverlay_Char[i];
-      oam->y = HIBYTE(dungmap_var7) - r12 + kPerishOverlay_Y[i];
-      oam->x = BYTE(dungmap_var7) - r12 + kPerishOverlay_X[i];
-      oam->flags = (info.flags & 0x30) | kPerishOverlay_Flags[i];
-    }
-  } while (oam++, i--, --n >= 0);
-  Sprite_CorrectOamEntries(k, 3, 0);
-}
-
-void SpriteModule_Fall2(int k) {  // 86fbea
-  uint8 delay = sprite_delay_main[k];
-  if (!delay) {
-    sprite_state[k] = 0;
-    Sprite_ManuallySetDeathFlagUW(k);
-    return;
-  }
-
-  if (delay >= 0x40) {
-    if (sprite_oam_flags[k] != 5) {
-      if (!(delay & 7 | submodule_index | flag_unk1))
-        SpriteSfx_QueueSfx3WithPan(k, 0x31);
-      SpriteActive_Main(k);
-      PrepOamCoordsRet info;
-      if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
-        return;
-      Sprite_DrawDistress_custom(info.x, info.y - 8, delay + 20);
-      return;
-    }
-    sprite_delay_main[k] = delay = 63;
-  }
-
-  if (delay == 61)
-    SpriteSfx_QueueSfx2WithPan(k, 0x20);
-
-  int j = delay >> 1;
-
-  if (sprite_type[k] == 0x26 || sprite_type[k] == 0x13) {
-    sprite_graphics[k] = kSpriteFall_Tab2[j];
-    SpriteDraw_FallingHelmaBeetle(k);
-  } else {
-    uint8 t = kSpriteFall_Tab1[j];
-    if (t < 12)
-      t += kSpriteFall_Tab4[sprite_D[k]];
-    sprite_graphics[k] = t;
-    SpriteDraw_FallingHumanoid(k);
-  }
-  if (frame_counter & kSpriteFall_Tab3[sprite_delay_main[k] >> 3] | submodule_index)
-    return;
-  Sprite_CheckTileProperty(k, 0x68);
-  if (sprite_tiletype != 0x20) {
-    sprite_y_recoil[k] = 0;
-    sprite_x_recoil[k] = 0;
-  }
-  sprite_y_vel[k] = (int8)sprite_y_recoil[k] >> 2;
-  sprite_x_vel[k] = (int8)sprite_x_recoil[k] >> 2;
-  Sprite_MoveXY(k);
-}
-
-void SpriteDraw_FallingHelmaBeetle(int k) {  // 86fd17
-  PrepOamCoordsRet info;
-  const DrawMultipleData *src = kSpriteDrawFall0Data + sprite_graphics[k];
-  if (sprite_type[k] == 0x13)
-    src += 6;
-  Sprite_DrawMultiple(k, src, 1, &info);
-}
-
-void SpriteDraw_FallingHumanoid(int k) {  // 86fe5b
-  PrepOamCoordsRet info;
-  if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
-    return;
-
-  int q = sprite_graphics[k];
-  OamEnt *oam = GetOamCurPtr();
-  int n = (q < 12 && (q & 3) == 0) ? 3 : 0, nn = n;
-  do {
-    int i = q * 4 + n;
-    SetOamPlain(oam, info.x + kSpriteDrawFall1_X[i], info.y + kSpriteDrawFall1_Y[i],
-                 kSpriteDrawFall1_Char[i], info.flags ^ kSpriteDrawFall1_Flags[i], kSpriteDrawFall1_Ext[i]);
-  } while (oam++, --n >= 0);
-  Sprite_CorrectOamEntries(k, nn, 0xff);
-}
-
-void Sprite_CorrectOamEntries(int k, int n, uint8 islarge) {  // 86febc
-  OamEnt *oam = GetOamCurPtr();
-  uint8 *extp = &g_ram[oam_ext_cur_ptr];
-  uint16 spr_x = Sprite_GetX(k);
-  uint16 spr_y = Sprite_GetY(k);
-  uint8 scrollx = spr_x - BG2HOFS_copy2;
-  uint8 scrolly = spr_y - BG2VOFS_copy2;
-  do {
-    uint16 x = spr_x + (int8)(oam->x - scrollx);
-    uint16 y = spr_y + (int8)(oam->y - scrolly);
-    uint8 ext = sign8(islarge) ? (*extp & 2) : islarge;
-    *extp = ext + ((uint16)(x - BG2HOFS_copy2) >= 0x100);
-    if ((uint16)(y + 0x10 - BG2VOFS_copy2) >= 0x100)
-      oam->y = 0xf0;
-  } while (oam++, extp++, --n >= 0);
-}
-
-bool Sprite_ReturnIfRecoiling(int k) {  // 86ff78
-  if (!sprite_F[k])
-    return false;
-  if (!(sprite_F[k] & 0x7f)) {
-    sprite_F[k] = 0;
-    return false;
-  }
-  uint8 yvbak = sprite_y_vel[k];
-  uint8 xvbak = sprite_x_vel[k];
-  if (!--sprite_F[k] && ((uint8)(sprite_x_recoil[k] + 0x20) >= 0x40 || (uint8)(sprite_y_recoil[k] + 0x20) >= 0x40))
-    sprite_F[k] = 144;
-
-  int i = sprite_F[k];
-  uint8 t;
-  if (!sign8(i) && !(frame_counter & kSprite2_ReturnIfRecoiling_Masks[i>>2])) {
-    sprite_y_vel[k] = sprite_y_recoil[k];
-    sprite_x_vel[k] = sprite_x_recoil[k];
-    if (!sign8(sprite_bump_damage[k]) && (t = (Sprite_CheckTileCollision(k) & 0xf))) {
-      if (t < 4)
-        sprite_x_recoil[k] = sprite_x_vel[k] = 0;
-      else
-        sprite_y_recoil[k] = sprite_y_vel[k] = 0;
-    } else {
-      Sprite_MoveXY(k);
-    }
-  }
-  sprite_y_vel[k] = yvbak;
-  sprite_x_vel[k] = xvbak;
-  return sprite_type[k] != 0x7a;
-}
-
-bool Sprite_CheckIfLinkIsBusy() {  // 87f4d0
-  if (link_auxiliary_state | link_pose_for_item | (link_state_bits & 0x80))
-    return true;
-  for (int i = 4; i >= 0; i--) {
-    if (ancilla_type[i] == 0x27)
-      return true;
-  }
-  return false;
-}
-
-void Sprite_SetSpawnedCoordinates(int k, SpriteSpawnInfo *info) {  // 89ae64
-  sprite_x_lo[k] = info->r0_x;
-  sprite_x_hi[k] = info->r0_x >> 8;
-  sprite_y_lo[k] = info->r2_y;
-  sprite_y_hi[k] = info->r2_y >> 8;
-  sprite_z[k] = info->r4_z;
-}
-
-bool Sprite_CheckIfScreenIsClear() {  // 89af32
-  for (int i = 15; i >= 0; i--) {
-    if (sprite_state[i] && !(sprite_flags4[i] & 0x40)) {
-      uint16 x = Sprite_GetX(i) - BG2HOFS_copy2;
-      uint16 y = Sprite_GetY(i) - BG2VOFS_copy2;
-      if (x < 256 && y < 256)
-        return false;
-    }
-  }
-  return Sprite_CheckIfOverlordsClear();
-}
-
-bool Sprite_CheckIfRoomIsClear() {  // 89af61
-  for (int i = 15; i >= 0; i--) {
-    if (sprite_state[i] && !(sprite_flags4[i] & 0x40))
-      return false;
-  }
-  return Sprite_CheckIfOverlordsClear();
-}
-
-bool Sprite_CheckIfOverlordsClear() {  // 89af76
-  for (int i = 7; i >= 0; i--) {
-    if (overlord_type[i] == 0x14 || overlord_type[i] == 0x18)
-      return false;
-  }
-  return true;
-}
-
-void Sprite_InitializeMirrorPortal() {  // 89af89
-  for (int k = 15; k >= 0; k--) {
-    if (sprite_state[k] && sprite_type[k] == 0x6c)
-      sprite_state[k] = 0;
-  }
-
-  SpriteSpawnInfo info;
-  int j = Sprite_SpawnDynamically(0xff, 0x6c, &info);
-  if (j < 0)
-    j = 0;
-
-  Sprite_SetX(j, bird_travel_x_hi[15] << 8 | bird_travel_x_lo[15]);
-  Sprite_SetY(j, (bird_travel_y_hi[15] << 8 | bird_travel_y_lo[15]) + 8);
-
-  sprite_floor[j] = 0;
-  sprite_ignore_projectile[j] = 1;
-}
-
-void Sprite_InitializeSlots() {  // 89afd6
-  for (int k = 15; k >= 0; k--) {
-    uint8 st = sprite_state[k], ty = sprite_type[k];
-    if (st != 0) {
-      if (st == 10) {
-        if (ty != 0xec && ty != 0xd2) {
-          link_picking_throw_state = 0;
-          link_state_bits = 0;
-          sprite_state[k] = 0;
-        }
-      } else {
-        if (ty != 0x6c && sprite_room[k] != BYTE(overworld_area_index))
-          sprite_state[k] = 0;
-      }
-    }
-  }
-  for (int k = 7; k >= 0; k--) {
-    if (overlord_type[k] && overlord_spawned_in_area[k] != BYTE(overworld_area_index))
-      overlord_type[k] = 0;
-  }
-}
-
-void Garnish_ExecuteUpperSlots() {  // 89b08c
-  HandleScreenFlash();
-
-  if (garnish_active) {
-    for (int i = 29; i >= 15; i--)
-      Garnish_ExecuteSingle(i);
-  }
-}
-
-void Garnish_ExecuteLowerSlots() {  // 89b097
-  if (garnish_active) {
-    for (int i = 14; i >= 0; i--)
-      Garnish_ExecuteSingle(i);
-  }
-}
-
-void Garnish_ExecuteSingle(int k) {  // 89b0b6
-  cur_object_index = k;
-  uint8 type = garnish_type[k];
-  if (type == 0)
-    return;
-  if ((type == 5 || (submodule_index | flag_unk1) == 0) && garnish_countdown[k] != 0 && --garnish_countdown[k] == 0) {
-    garnish_type[k] = 0;
-    return;
-  }
-  uint8 sprsize = kGarnish_OamMemSize[garnish_type[k]];
-  if (sort_sprites_setting) {
-    if (garnish_floor[k])
-      Oam_AllocateFromRegionF(sprsize);
-    else
-      Oam_AllocateFromRegionD(sprsize);
-  } else {
-    Oam_AllocateFromRegionA(sprsize);
-  }
-  kGarnish_Funcs[garnish_type[k] - 1](k);
-}
-
-void Garnish15_ArrghusSplash(int k) {  // 89b178
-  static const int8 kArrghusSplash_X[8] = {-12, 20, -10, 10, -8, 8, -4, 4};
-  static const int8 kArrghusSplash_Y[8] = {-4, -4, -2, -2, 0, 0, 0, 0};
-  static const uint8 kArrghusSplash_Char[8] = {0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xac, 0xac};
-  static const uint8 kArrghusSplash_Flags[8] = {0x34, 0x74, 0x34, 0x74, 0x34, 0x74, 0x34, 0x74};
-  static const uint8 kArrghusSplash_Ext[8] = {0, 0, 2, 2, 2, 2, 2, 2};
-
-  Point16U pt;
-  if (Garnish_ReturnIfPrepFails(k, &pt))
-    return;
-  OamEnt *oam = GetOamCurPtr();
-  int g = (garnish_countdown[k] >> 1) & 6;
-  for (int i = 1; i >= 0; i--, oam++) {
-    int j = i + g;
-    SetOamPlain(oam, pt.x + kArrghusSplash_X[j], pt.y + kArrghusSplash_Y[j], kArrghusSplash_Char[j], kArrghusSplash_Flags[j], kArrghusSplash_Ext[j]);
-  }
-}
-
-void Garnish13_PyramidDebris(int k) {  // 89b216
-  OamEnt *oam = GetOamCurPtr();
-
-  int y = (garnish_y_lo[k] << 8) + garnish_y_subpixel[k] + ((int8)garnish_y_vel[k] << 4);
-  garnish_y_subpixel[k] = y;
-  garnish_y_lo[k] = y >> 8;
-
-  int x = (garnish_x_lo[k] << 8) + garnish_x_subpixel[k] + ((int8)garnish_x_vel[k] << 4);
-  garnish_x_subpixel[k] = x;
-  garnish_x_lo[k] = x >> 8;
-
-  garnish_y_vel[k] = garnish_y_vel[k] + 3;
-  uint8 t;
-  if ((t = garnish_x_lo[k] - BG2HOFS_copy2) >= 248) {
-    garnish_type[k] = 0;
-    return;
-  }
-  oam->x = t;
-  if ((t = garnish_y_lo[k] - BG2VOFS_copy2) >= 240) {
-    garnish_type[k] = 0;
-    return;
-  }
-  oam->y = t;
-  oam->charnum = 0x5c;
-  oam->flags = (frame_counter << 3) & 0xc0 | 0x34;
-  bytewise_extended_oam[oam - oam_buf] = 0;
-}
-
-void Garnish11_WitheringGanonBatFlame(int k) {  // 89b2b2
-  if ((submodule_index | flag_unk1) == 0) {
-    Garnish_SetY(k, Garnish_GetY(k) - 1);
-  }
-  Point16U pt;
-  if (Garnish_ReturnIfPrepFails(k, &pt))
-    return;
-  OamEnt *oam = GetOamCurPtr();
-  SetOamPlain(oam + 0, pt.x + 0, pt.y, 0xa4, 0x22, 0);
-  SetOamPlain(oam + 1, pt.x + 8, pt.y, 0xa5, 0x22, 0);
-}
-
-void Garnish10_GanonBatFlame(int k) {  // 89b306
-  static const uint8 kGanonBatFlame_Idx[32] = {
-    7, 6, 5, 4, 5, 4, 5, 4, 5, 4, 5, 4, 5, 4, 5, 4,
-    5, 4, 5, 4, 5, 4, 5, 4, 5, 4, 5, 4, 5, 4, 5, 4,
-  };
-  static const uint8 kGanonBatFlame_Char[7] = {0xac, 0xac, 0x66, 0x66, 0x8e, 0xa0, 0xa2};
-  static const uint8 kGanonBatFlame_Flags[7] = {1, 0x41, 1, 0x41, 0, 0, 0};
-
-  if (garnish_countdown[k] == 8)
-    garnish_type[k] = 0x11;
-  Point16U pt;
-  if (Garnish_ReturnIfPrepFails(k, &pt))
-    return;
-  int j = kGanonBatFlame_Idx[garnish_countdown[k] >> 3];
-  SetOamPlain(GetOamCurPtr(), pt.x, pt.y, kGanonBatFlame_Char[j], kGanonBatFlame_Flags[j] | 0x22, 2);
-  Garnish_CheckPlayerCollision(k, pt.x, pt.y);
-}
-
-void Garnish0C_TrinexxIceBreath(int k) {  // 89b34f
-  static const uint8 kTrinexxIce_Char[12] = {0xe8, 0xe8, 0xe6, 0xe6, 0xe4, 0xe4, 0xe4, 0xe4, 0xe4, 0xe4, 0xe4, 0xe4};
-  static const uint8 kTrinexxIce_Flags[4] = {0, 0x40, 0xc0, 0x80};
-
-  if (garnish_countdown[k] == 0x50 && (submodule_index | flag_unk1) == 0) {
-    Dungeon_UpdateTileMapWithCommonTile(Garnish_GetX(k), Garnish_GetY(k) - 16, 18);
-  }
-  Point16U pt;
-  if (Garnish_ReturnIfPrepFails(k, &pt))
-    return;
-  SetOamPlain(GetOamCurPtr(), pt.x, pt.y, kTrinexxIce_Char[garnish_countdown[k] >> 4],
-               kTrinexxIce_Flags[(garnish_countdown[k] >> 2) & 3] | 0x35, 2);
-}
-
-void Garnish14_KakKidDashDust(int k) {  // 89b3bc
-  Garnish_DustCommon(k, 2);
-}
-
-void Garnish_WaterTrail(int k) {  // 89b3c2
-  Garnish_DustCommon(k, 3);
-}
-
-void Garnish0A_CannonSmoke(int k) {  // 89b3ee
-  static const uint8 kGarnish_CannonPoof_Char[2] = { 0x8a, 0x86 };
-  static const uint8 kGarnish_CannonPoof_Flags[4] = { 0x20, 0x10, 0x30, 0x30 };
-  Point16U pt;
-  if (Garnish_ReturnIfPrepFails(k, &pt))
-    return;
-  int j = garnish_sprite[k];
-  SetOamPlain(GetOamCurPtr(), pt.x, pt.y, kGarnish_CannonPoof_Char[garnish_countdown[k] >> 3], kGarnish_CannonPoof_Flags[j] | 4, 2);
-}
-
-void Garnish09_LightningTrail(int k) {  // 89b429
-  static const uint8 kLightningTrail_Char[8] = {0xcc, 0xec, 0xce, 0xee, 0xcc, 0xec, 0xce, 0xee};
-  static const uint8 kLightningTrail_Flags[8] = {0x31, 0x31, 0x31, 0x31, 0x71, 0x71, 0x71, 0x71};
-  Point16U pt;
-  if (Garnish_ReturnIfPrepFails(k, &pt))
-    return;
-  int j = garnish_sprite[k];
-  SetOamPlain(GetOamCurPtr(), pt.x, pt.y,
-               kLightningTrail_Char[j] - (BYTE(dungeon_room_index2) == 0x20 ? 0x80 : 0),
-               (frame_counter << 1) & 0xe | kLightningTrail_Flags[j], 2);
-  Garnish_CheckPlayerCollision(k, pt.x, pt.y);
-}
-
-void Garnish_CheckPlayerCollision(int k, int x, int y) {  // 89b459
-  if ((k ^ frame_counter) & 7 | countdown_for_blink | link_disable_sprite_damage)
-    return;
-
-  if ((uint8)(link_x_coord - BG2HOFS_copy2 - x + 12) < 24 &&
-      (uint8)(link_y_coord - BG2VOFS_copy2 - y + 22) < 28) {
-    link_auxiliary_state = 1;
-    link_incapacitated_timer = 16;
-    link_give_damage = 16;
-    link_actual_vel_x ^= 255;
-    link_actual_vel_y ^= 255;
-  }
-}
-
-void Garnish07_BabasuFlash(int k) {  // 89b49e
-  static const uint8 kBabusuFlash_Char[4] = {0xa8, 0x8a, 0x86, 0x86};
-  static const uint8 kBabusuFlash_Flags[4] = {0x2d, 0x2c, 0x2c, 0x2c};
-  Point16U pt;
-  if (Garnish_ReturnIfPrepFails(k, &pt))
-    return;
-  int j = garnish_countdown[k] >> 3;
-  SetOamPlain(GetOamCurPtr(), pt.x, pt.y, kBabusuFlash_Char[j], kBabusuFlash_Flags[j], 2);
-}
-
-void Garnish08_KholdstareTrail(int k) {  // 89b4c6
-  static const int8 kGarnish_Nebule_XY[3] = { -1, -1, 0 };
-  static const uint8 kGarnish_Nebule_Char[3] = { 0x9c, 0x9d, 0x8d };
-
-  Point16U pt;
-  if (Garnish_ReturnIfPrepFails(k, &pt))
-    return;
-  int i = garnish_countdown[k] >> 2;
-  int j = garnish_sprite[k];
-  SetOamPlain(GetOamCurPtr(), pt.x + kGarnish_Nebule_XY[i], pt.y + kGarnish_Nebule_XY[i], kGarnish_Nebule_Char[i],
-               (sprite_oam_flags[j] | sprite_obj_prio[j]) & ~1, 0);
-}
-
-void Garnish06_ZoroTrail(int k) {  // 89b4fb
-  Point16U pt;
-  if (Garnish_ReturnIfPrepFails(k, &pt))
-    return;
-  int j = garnish_sprite[k];
-  SetOamPlain(GetOamCurPtr(), pt.x, pt.y, 0x75, sprite_oam_flags[j] | sprite_obj_prio[j], 0);
-}
-
-void Garnish12_Sparkle(int k) {  // 89b520
-  Garnish_SparkleCommon(k, 2);
-}
-
-void Garnish_SimpleSparkle(int k) {  // 89b526
-  Garnish_SparkleCommon(k, 3);
-}
-
-void Garnish0E_TrinexxFireBreath(int k) {  // 89b55d
-  static const uint8 kTrinexxLavaBubble_Char[4] = {0x83, 0xc7, 0x80, 0x9d};
-  Point16U pt;
-  if (Garnish_ReturnIfPrepFails(k, &pt))
-    return;
-  int j = garnish_sprite[k];
-  SetOamPlain(GetOamCurPtr(), pt.x, pt.y, kTrinexxLavaBubble_Char[garnish_countdown[k] >> 3],
-               (sprite_oam_flags[j] | sprite_obj_prio[j]) & 0xf0 | 0xe, 0);
-}
-
-void Garnish0F_BlindLaserTrail(int k) {  // 89b591
-  static const uint8 kBlindLaserTrail_Char[4] = {0x61, 0x71, 0x70, 0x60};
-  Point16U pt;
-  if (Garnish_ReturnIfPrepFails(k, &pt))
-    return;
-  int j = garnish_sprite[k];
-  SetOamPlain(GetOamCurPtr(), pt.x, pt.y, kBlindLaserTrail_Char[garnish_oam_flags[k] - 7], sprite_oam_flags[j] | sprite_obj_prio[j], 0);
-}
-
-void Garnish04_LaserTrail(int k) {  // 89b5bb
-  static const uint8 kLaserBeamTrail_Char[2] = {0xd2, 0xf3};
-  Point16U pt;
-  if (Garnish_ReturnIfPrepFails(k, &pt))
-    return;
-  SetOamPlain(GetOamCurPtr(), pt.x, pt.y, kLaserBeamTrail_Char[garnish_oam_flags[k]], 0x25, 0);
-}
-
-bool Garnish_ReturnIfPrepFails(int k, Point16U *pt) {  // 89b5de
-  uint16 x = Garnish_GetX(k) - BG2HOFS_copy2;
-  uint16 y = Garnish_GetY(k) - BG2VOFS_copy2;
-
-  if (x >= 256 || y >= 256) {
-    garnish_type[k] = 0;
-    return true;
-  }
-  pt->x = x;
-  pt->y = y - 16;
-  return false;
-}
-
-void Garnish03_FallingTile(int k) {  // 89b627
-  static const uint8 kCrumbleTile_XY[5] = {4, 0, 0, 0, 0};
-  static const uint8 kCrumbleTile_Char[5] = {0x80, 0xcc, 0xcc, 0xea, 0xca};
-  static const uint8 kCrumbleTile_Flags[5] = {0x30, 0x31, 0x31, 0x31, 0x31};
-  static const uint8 kCrumbleTile_Ext[5] = {0, 2, 2, 2, 2};
-
-  int j;
-  if ((j = garnish_countdown[k]) == 0x1e && (j = (submodule_index | flag_unk1)) == 0)
-    Dungeon_UpdateTileMapWithCommonTile(Garnish_GetX(k), Garnish_GetY(k) - 16, 4);
-  j >>= 3;
-  uint16 x = Garnish_GetX(k) + kCrumbleTile_XY[j] - BG2HOFS_copy2;
-  uint16 y = Garnish_GetY(k) + kCrumbleTile_XY[j] - BG2VOFS_copy2;
-  if (x < 256 && y < 256)
-    SetOamPlain(GetOamCurPtr(), x, y - 16, kCrumbleTile_Char[j], kCrumbleTile_Flags[j], kCrumbleTile_Ext[j]);
-}
-
-void Garnish01_FireSnakeTail(int k) {  // 89b6c0
-  Point16U pt;
-  if (Garnish_ReturnIfPrepFails(k, &pt))
-    return;
-  int j = garnish_sprite[k];
-  SetOamPlain(GetOamCurPtr(), pt.x, pt.y, 0x28, sprite_oam_flags[j] | sprite_obj_prio[j], 2);
-}
-
-void Garnish02_MothulaBeamTrail(int k) {  // 89b6e1
-  int j = garnish_sprite[k];
-  SetOamPlain(GetOamCurPtr(), garnish_x_lo[k] - BG2HOFS_copy2, garnish_y_lo[k] - BG2VOFS_copy2, 0xaa,
-               sprite_oam_flags[j] | sprite_obj_prio[j], 2);
-}
-
-void Dungeon_ResetSprites() {  // 89c114
-  Dungeon_CacheTransSprites();
-  link_picking_throw_state = 0;
-  link_state_bits = 0;
-  Sprite_DisableAll();
-  sprcoll_x_size = sprcoll_y_size = 0xffff;
-  int j = FindInWordArray(dungeon_room_history, dungeon_room_index2, 4);
-  if (j < 0) {
-    uint16 blk = dungeon_room_history[3];
-    dungeon_room_history[3] = dungeon_room_history[2];
-    dungeon_room_history[2] = dungeon_room_history[1];
-    dungeon_room_history[1] = dungeon_room_history[0];
-    dungeon_room_history[0] = dungeon_room_index2;
-    if (blk != 0xffff)
-      sprite_where_in_room[blk] = 0;
-  }
-  Dungeon_LoadSprites();
-}
-
-void Dungeon_CacheTransSprites() {  // 89c176
-  if (!player_is_indoors)
-    return;
-  alt_sprites_flag = player_is_indoors;
-  for (int k = 15; k >= 0; k--) {
-    alt_sprite_state[k] = 0;
-    alt_sprite_type[k] = sprite_type[k];
-    alt_sprite_x_lo[k] = sprite_x_lo[k];
-    alt_sprite_graphics[k] = sprite_graphics[k];
-    alt_sprite_x_hi[k] = sprite_x_hi[k];
-    alt_sprite_y_lo[k] = sprite_y_lo[k];
-    alt_sprite_y_hi[k] = sprite_y_hi[k];
-    if (sprite_pause[k] != 0 || sprite_state[k] == 4 || sprite_state[k] == 10)
-      continue;
-    alt_sprite_state[k] = sprite_state[k];
-    alt_sprite_A[k] = sprite_A[k];
-    alt_sprite_head_dir[k] = sprite_head_dir[k];
-    alt_sprite_oam_flags[k] = sprite_oam_flags[k];
-    alt_sprite_obj_prio[k] = sprite_obj_prio[k];
-    alt_sprite_D[k] = sprite_D[k];
-    alt_sprite_flags2[k] = sprite_flags2[k];
-    alt_sprite_floor[k] = sprite_floor[k];
-    alt_sprite_spawned_flag[k] = sprite_ai_state[k];
-    alt_sprite_flags3[k] = sprite_flags3[k];
-    alt_sprite_B[k] = sprite_B[k];
-    alt_sprite_C[k] = sprite_C[k];
-    alt_sprite_E[k] = sprite_E[k];
-    alt_sprite_subtype2[k] = sprite_subtype2[k];
-    alt_sprite_height_above_shadow[k] = sprite_z[k];
-    alt_sprite_delay_main[k] = sprite_delay_main[k];
-    alt_sprite_I[k] = sprite_I[k];
-    alt_sprite_maybe_ignore_projectile[k] = sprite_ignore_projectile[k];
-  }
-}
-
-void Sprite_DisableAll() {  // 89c22f
-  for (int k = 15; k >= 0; k--) {
-    if (sprite_state[k] && (player_is_indoors || sprite_type[k] != 0x6c))
-      sprite_state[k] = 0;
-  }
-  for (int k = 9; k >= 0; k--)
-    ancilla_type[k] = 0;
-  flag_is_ancilla_to_pick_up = 0;
-  sprite_limit_instance = 0;
-  byte_7E0B9B = 0;
-  byte_7E0B88 = 0;
-  archery_game_arrows_left = 0;
-  garnish_active = 0;
-  byte_7E0B9E = 0;
-  activate_bomb_trap_overlord = 0;
-  intro_times_pal_flash = 0;
-  byte_7E0FF8 = 0;
-  byte_7E0FFB = 0;
-  flag_block_link_menu = 0;
-  byte_7E0FFD = 0;
-  byte_7E0FC6 = 0;
-  is_archer_or_shovel_game = 0;
-  for (int k = 7; k >= 0; k--)
-    overlord_type[k] = 0;
-  for (int k = 29; k >= 0; k--)
-    garnish_type[k] = 0;
-}
-
-void Dungeon_LoadSprites() {  // 89c290
-  const uint8 *src = kDungeonSprites + kDungeonSpriteOffs[dungeon_room_index2];
-  byte_7E0FB1 = dungeon_room_index2 >> 3 & 0xfe;
-  byte_7E0FB0 = (dungeon_room_index2 & 0xf) << 1;
-  sort_sprites_setting = *src++;
-  for (int k = 0; *src != 0xff; src += 3)
-    k = Dungeon_LoadSingleSprite(k, src) + 1;
-}
-
-void Sprite_ManuallySetDeathFlagUW(int k) {  // 89c2f5
-  if (!player_is_indoors || sprite_defl_bits[k] & 1 || sign8(sprite_N[k]))
-    return;
-  sprite_where_in_room[dungeon_room_index2] |= 1 << sprite_N[k];
-}
-
-int Dungeon_LoadSingleSprite(int k, const uint8 *src) {  // 89c327
-  uint8 y = src[0], x = src[1], type = src[2];
-  if (type == 0xe4) {
-    if (y == 0xfe || y == 0xfd) {
-      sprite_die_action[k - 1] = (y == 0xfe) ? 1 : 2;
-      return k - 1;
-    }
-  } else if (x >= 0xe0) {
-    Dungeon_LoadSingleOverlord(src);
-    return k - 1;
-  }
-  if (!(kSpriteInit_DeflBits[type] & 1) && (sprite_where_in_room[dungeon_room_index2] & (1 << k)))
-    return k;
-  sprite_state[k] = 8;
-  tmp_counter = y;
-  sprite_floor[k] = (y >> 7);
-  Sprite_SetY(k, ((y << 4) & 0x1ff) + (byte_7E0FB1 << 8));
-  byte_7E0FB6 = x;
-  Sprite_SetX(k, ((x << 4) & 0x1ff) + (byte_7E0FB0 << 8));
-  sprite_type[k] = type;
-  tmp_counter = (tmp_counter & 0x60) >> 2;
-  sprite_subtype[k] = tmp_counter | byte_7E0FB6 >> 5;
-  sprite_N[k] = k;
-  sprite_die_action[k] = 0;
-  return k;
-}
-
-void Dungeon_LoadSingleOverlord(const uint8 *src) {  // 89c3e8
-  int k = AllocOverlord();
-  if (k < 0)
-    return;
-  uint8 y = src[0], x = src[1], type = src[2];
-  overlord_type[k] = type;
-  overlord_floor[k] = (y >> 7);
-  int t = ((y << 4) & 0x1ff) + (byte_7E0FB1 << 8);
-  overlord_y_lo[k] = t;
-  overlord_y_hi[k] = t >> 8;
-  t = ((x << 4) & 0x1ff) + (byte_7E0FB0 << 8);
-  overlord_x_lo[k] = t;
-  overlord_x_hi[k] = t >> 8;
-  overlord_spawned_in_area[k] = overworld_area_index;
-  overlord_gen2[k] = 0;
-  overlord_gen1[k] = 0;
-  overlord_gen3[k] = 0;
-  if (overlord_type[k] == 10 || overlord_type[k] == 11) {
-    overlord_gen2[k] = 160;
-  } else if (overlord_type[k] == 3) {
-    overlord_gen2[k] = 255;
-    overlord_x_lo[k] -= 8;
-  }
-}
-
-void Sprite_ResetAll() {  // 89c44e
-  Sprite_DisableAll();
-  Sprite_ResetAll_noDisable();
-}
-
-void Sprite_ResetAll_noDisable() {  // 89c452
-  byte_7E0FDD = 0;
-  sprite_alert_flag = 0;
-  byte_7E0FFD = 0;
-  byte_7E02F0 = 0;
-  byte_7E0FC6 = 0;
-  sprite_limit_instance = 0;
-  sort_sprites_setting = 0;
-  if (follower_indicator != 13)
-    super_bomb_indicator_unk2 = 0xfe;
-  memset(sprite_where_in_room, 0, 0x1000);
-  memset(overworld_sprite_was_loaded, 0, 0x200);
-  memset(dungeon_room_history, 0xff, 8);
-}
-
-void Sprite_ReloadAll_Overworld() {  // 89c499
-  Sprite_DisableAll();
-  Sprite_OverworldReloadAll_justLoad();
-}
-
-void Sprite_OverworldReloadAll_justLoad() {  // 89c49d
-  Sprite_ResetAll_noDisable();
-  Overworld_LoadSprites();
-  Sprite_ActivateAllProxima();
-}
-
-void Overworld_LoadSprites() {  // 89c4ac
-  sprcoll_x_base = (overworld_area_index & 7) << 9;
-  sprcoll_y_base = ((overworld_area_index & 0x3f) >> 2 & 0xe) << 8;
-  sprcoll_x_size = sprcoll_y_size = kOverworldAreaSprcollSizes[BYTE(overworld_area_index)] << 8;
-  const uint8 *src = GetOverworldSpritePtr(overworld_area_index);
-  uint8 b;
-
-  for (; (b = src[0]) != 0xff; src += 3) {
-    if (src[2] == 0xf4) {
-      byte_7E0FFD++;
-      continue;
-    }
-    uint8 r2 = (src[0] >> 4) << 2;
-    uint8 r6 = (src[1] >> 4) + r2;
-    uint8 r5 = src[1] & 0xf | src[0] << 4;
-    sprite_where_in_overworld[r5 | r6 << 8] = src[2] + 1;
-  }
-}
-
-void Sprite_ActivateAllProxima() {  // 89c55e
-  uint16 bak0 = BG2HOFS_copy2;
-  uint8 bak1 = byte_7E069E[1];
-  byte_7E069E[1] = 0xff;
-
-  int xt = (enhanced_features0 & kFeatures0_ExtendScreen64) ? 0x40 : 0;
-  BG2HOFS_copy2 -= xt;
-  for (int i = 21 + (xt >> 3); i >= 0; i--) {
-    Sprite_ActivateWhenProximal();
-    BG2HOFS_copy2 += 16;
-  }
-  byte_7E069E[1] = bak1;
-  BG2HOFS_copy2 = bak0;
-}
-
-void Sprite_ProximityActivation() {  // 89c58f
-  if (submodule_index != 0) {
-    Sprite_ActivateWhenProximal();
-    Sprite_ActivateWhenProximalBig();
-  } else {
-    if (!(spr_ranged_based_toggler & 1))
-      Sprite_ActivateWhenProximal();
-    if (spr_ranged_based_toggler & 1)
-      Sprite_ActivateWhenProximalBig();
-    spr_ranged_based_toggler++;
-  }
-}
-
-void Sprite_ActivateWhenProximal() {  // 89c5bb
-  if (byte_7E069E[1]) {
-    int xt = (enhanced_features0 & kFeatures0_ExtendScreen64) ? 0x40 : 0;
-    uint16 x = BG2HOFS_copy2 + (sign8(byte_7E069E[1]) ? -0x10 - xt : 0x110 + xt);
-    uint16 y = BG2VOFS_copy2 - 0x30;
-    for (int i = 21; i >= 0; i--, y += 16)
-      Sprite_Overworld_ProximityMotivatedLoad(x, y);
-  }
-}
-
-void Sprite_ActivateWhenProximalBig() {  // 89c5fa
-  if (byte_7E069E[0]) {
-    int xt = (enhanced_features0 & kFeatures0_ExtendScreen64) ? 0x40 : 0;
-    uint16 x = BG2HOFS_copy2 - 0x30 - xt;
-    uint16 y = BG2VOFS_copy2 + (sign8(byte_7E069E[0]) ? -0x10 : 0x110);
-    for (int i = 21 + (xt >> 3); i >= 0; i--, x += 16)
-      Sprite_Overworld_ProximityMotivatedLoad(x, y);
-  }
-}
-
-void Sprite_Overworld_ProximityMotivatedLoad(uint16 x, uint16 y) {  // 89c6f5
-  uint16 xt = (uint16)(x - sprcoll_x_base);
-  uint16 yt = (uint16)(y - sprcoll_y_base);
-  if (xt >= sprcoll_x_size || yt >= sprcoll_y_size)
-    return;
-
-  uint8 r1 = (yt >> 8) * 4 | (xt >> 8);
-  uint8 r0 = y & 0xf0 | x >> 4 & 0xf;
-  Overworld_LoadProximaSpriteIfAlive(r1 << 8 | r0);
-}
-
-void Overworld_LoadProximaSpriteIfAlive(uint16 blk) {  // 89c739
-  uint8 *p5 = sprite_where_in_overworld + blk;
-  uint8 sprite_to_spawn = *p5;
-  if (!sprite_to_spawn)
-    return;
-
-  uint8 loadedmask = (0x80 >> (blk & 7));
-  uint8 *loadedp = &overworld_sprite_was_loaded[blk >> 3];
-
-  if (*loadedp & loadedmask)
-    return;
-
-  if (sprite_to_spawn >= 0xf4) {
-    // load overlord
-    int k = AllocOverlord();
-    if (k < 0)
-      return;
-    *loadedp |= loadedmask;
-    overlord_offset_sprite_pos[k] = blk;
-    overlord_type[k] = sprite_to_spawn - 0xf3;
-    overlord_x_lo[k] = (blk << 4 & 0xf0) + (overlord_type[k] == 1 ? 8 : 0);
-    overlord_y_lo[k] = blk & 0xf0;
-    overlord_x_hi[k] = (blk >> 8 & 3) + HIBYTE(sprcoll_x_base);
-    overlord_y_hi[k] = (blk >> 10) + HIBYTE(sprcoll_y_base);
-    overlord_floor[k] = 0;
-    overlord_spawned_in_area[k] = overworld_area_index;
-    overlord_gen2[k] = 0;
-    overlord_gen1[k] = 0;
-    overlord_gen3[k] = 0;
-  } else {
-    // load regular sprite
-    int k = Overworld_AllocSprite(sprite_to_spawn);
-    if (k < 0)
-      return;
-    *loadedp |= loadedmask;
-
-    sprite_N_word[k] = blk;
-    sprite_type[k] = sprite_to_spawn - 1;
-    sprite_state[k] = 8;
-    sprite_x_lo[k] = blk << 4 & 0xf0;
-    sprite_y_lo[k] = blk & 0xf0;
-    sprite_x_hi[k] = (blk >> 8 & 3) + HIBYTE(sprcoll_x_base);
-    sprite_y_hi[k] = (blk >> 10) + HIBYTE(sprcoll_y_base);
-    sprite_floor[k] = 0;
-    sprite_subtype[k] = 0;
-    sprite_die_action[k] = 0;
-  }
-}
-
-void SpriteExplode_SpawnEA(int k) {  // 89ee4c
-  tmp_counter = sprite_type[k];
-  SpriteSpawnInfo info;
-  int j = Sprite_SpawnDynamicallyEx(k, 0xea, &info, 14);
-  Sprite_SetSpawnedCoordinates(j, &info);
-  sprite_z_vel[j] = 32;
-  sprite_floor[j] = link_is_on_lower_level;
-  sprite_A[j] = (j == 9) ? 2 : 6;
-  Sprite_SetY(j, info.r2_y + 3);
-  if (tmp_counter == 0xce) {
-    Sprite_SetY(j, info.r2_y + 16);
-    return;
-  }
-  if (tmp_counter == 0xcb) {
-    sprite_y_lo[j] = sprite_x_lo[j] = 0x78;
-    sprite_x_hi[j] = HIBYTE(link_x_coord);
-    sprite_y_hi[j] = HIBYTE(link_y_coord);
-  }
-}
-
-void Sprite_KillFriends() {  // 89ef56
-  for(int j = 15; j >= 0; j--) {
-    if (j != cur_object_index && sprite_state[j] && !(sprite_defl_bits[j] & 2) && sprite_type[j] != 0x7a) {
-      sprite_state[j] = 6;
-      sprite_delay_main[j] = 15;
-      sprite_flags3[j] = 0;
-      sprite_flags5[j] = 0;
-      sprite_flags2[j] = 3;
-    }
-  }
-}
-
-void Garnish16_ThrownItemDebris(int k) {  // 89f0cb
-  static const int16 kScatterDebris_Draw_X[64] = {
-     0,  8,  0,  8, -2,  9, -1,  9, -4,  9, -1, 10, -6,  9, -1, 12,
-    -7,  9, -2, 13, -9,  9, -3, 14, -4, -4,  9, 15, -3, -3, -3,  9,
-    -4,  4,  6, 10, -1,  4,  6,  7,  0,  2,  4,  7,  1,  1,  5,  7,
-     0, -2,  8,  9, -1, -6,  9, 10, -2, -7, 12, 11, -3, -9,  4,  6,
-  };
-  static const int8 kScatterDebris_Draw_Y[64] = {
-      0,  0,  8,  8,   0, -1, 10, 10,   0, -3, 11,  7,   1, -4, 12,  8,
-      1, -4, 13,  9,   2, -4, 16, 10,  14, 14, -4, 11,  16, 16, 16, -1,
-      2, -5,  5,  1,   3, -7,  8,  2,   4, -8,  4, 10,  -9,  4,  4, 12,
-    -10,  4,  8, 14, -12,  4,  8, 15, -15,  3,  8, 17, -17,  1, 18, 15,
-  };
-  static const int8 kScatterDebris_Draw_Char[64] = {
-    0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58,
-    0x48, 0x58, 0x58, 0x58, 0x48, 0x58, 0x58, 0x48, 0x48, 0x48, 0x58, 0x48, 0x48, 0x48, 0x48, 0x48,
-    0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59,
-    0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59,
-  };
-  static const uint8 kScatterDebris_Draw_Flags[64] = {
-    0x80,    0, 0x80, 0x40, 0x80, 0x40, 0x80,    0,    0, 0xc0,    0, 0x80, 0x80, 0x40, 0x80,    0,
-    0x80, 0xc0,    0, 0x80,    0,    0, 0x80,    0, 0x80, 0x80, 0x80, 0x80,    0,    0,    0,    0,
-    0x40, 0x40, 0x40,    0, 0x40, 0x40, 0x40,    0, 0x40, 0x40,    0,    0, 0x80,    0, 0x40, 0x40,
-    0x40,    0, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,    0,    0, 0x40,    0,    0,    0,
-  };
-  Point16U pt;
-  if (Garnish_ReturnIfPrepFails(k, &pt))
-    return;
-  uint8 r5 = garnish_oam_flags[k];
-  if (byte_7E0FC6 >= 3)
-    return;
-  if (garnish_sprite[k] == 3) {
-    ScatterDebris_Draw(k, pt);
-    return;
-  }
-  OamEnt *oam = GetOamCurPtr();
-  tmp_counter = garnish_sprite[k];
-  uint8 base = ((garnish_countdown[k] >> 2) ^ 7) << 2;
-  if (tmp_counter == 4 || tmp_counter == 2 && !player_is_indoors)
-    base += 0x20;
-  for (int i = 3; i >= 0; i--, oam++) {
-    int j = i + base;
-    SetOamHelper1(oam, pt.x + kScatterDebris_Draw_X[j], pt.y + kScatterDebris_Draw_Y[j],
-                  (tmp_counter == 0) ? 0x4E : (tmp_counter >= 0x80) ? 0xF2 : kScatterDebris_Draw_Char[j],
-                  kScatterDebris_Draw_Flags[j] | r5, 0);
-  }
-}
-
-void ScatterDebris_Draw(int k, Point16U pt) {  // 89f198
-  static const int8 kScatterDebris_Draw_X2[12] = {-8, 8, 16, -5, 8, 15, -1, 7, 11, 1, 3, 8};
-  static const int8 kScatterDebris_Draw_Y2[12] = {7, 2, 12, 9, 2, 10, 11, 2, 11, 7, 3, 8};
-  static const uint8 kScatterDebris_Draw_Char2[12] = {0xe2, 0xe2, 0xe2, 0xe2, 0xf2, 0xf2, 0xf2, 0xe2, 0xe2, 0xf2, 0xe2, 0xe2};
-  static const uint8 kScatterDebris_Draw_Flags2[12] = {0, 0, 0, 0, 0x80, 0x40, 0, 0x80, 0x40, 0, 0, 0};
-
-  if (garnish_countdown[k] == 16)
-    garnish_type[k] = 0;
-
-  OamEnt *oam = GetOamCurPtr();
-  int base = ((garnish_countdown[k] & 0xf) >> 2) * 3;
-
-  for (int i = 2; i >= 0; i--, oam++) {
-    int j = i + base;
-    SetOamHelper1(oam, pt.x + kScatterDebris_Draw_X2[j], pt.y + kScatterDebris_Draw_Y2[j],
-                  kScatterDebris_Draw_Char2[j], kScatterDebris_Draw_Flags2[j] | 0x22, 0);
-  }
-}
-
-void Sprite_KillSelf(int k) {  // 89f1f8
-  if (!(sprite_defl_bits[k] & 0x40) && player_is_indoors)
-    return;
-  sprite_state[k] = 0;
-  uint16 blk = sprite_N_word[k];
-  g_ram[0] = blk;  // Sprite_PrepOamCoordOrDoubleRet reads this!
-  WORD(g_ram[1]) = (blk >> 3) + 0xef80; // Sprite_PrepOamCoordOrDoubleRet reads this!
-  uint8 loadedmask = (0x80 >> (blk & 7));
-  uint16 addr = 0xEF80 + (blk >> 3);  // warning: blk may be bad, seen with cannon balls in 2nd dungeon
-
-  uint8 *loadedp = &g_ram[addr + 0x10000];
-
-  if (blk < 0xffff)
-    *loadedp &= ~loadedmask;
-  if (!player_is_indoors)
-    sprite_N_word[k] = 0xffff;
-  else
-    sprite_N[k] = 0xff;
-}
-
-void SpritePrep_LoadProperties(int k) {  // 8db818
-  SpritePrep_ResetProperties(k);
-  int j = sprite_type[k];
-  sprite_flags2[k] = kSpriteInit_Flags2[j];
-  sprite_health[k] = kSpriteInit_Health[j];
-  sprite_flags4[k] = kSpriteInit_Flags4[j];
-  sprite_flags5[k] = kSpriteInit_Flags5[j];
-  sprite_defl_bits[k] = kSpriteInit_DeflBits[j];
-  sprite_bump_damage[k] = kSpriteInit_BumpDamage[j];
-  sprite_flags[k] = kSpriteInit_Flags[j];
-  sprite_room[k] = player_is_indoors ? dungeon_room_index2 : overworld_area_index;
-  sprite_flags3[k] = kSpriteInit_Flags3[j];
-  sprite_oam_flags[k] = kSpriteInit_Flags3[j] & 0xf;
-}
-
-void SpritePrep_LoadPalette(int k) {  // 8db85c
-  int f = kSpriteInit_Flags3[sprite_type[k]];
-  sprite_flags3[k] = f;
-  sprite_oam_flags[k] = f & 15;
-}
-
-void SpritePrep_ResetProperties(int k) {  // 8db871
-  sprite_pause[k] = 0;
-  sprite_E[k] = 0;
-  sprite_x_vel[k] = 0;
-  sprite_y_vel[k] = 0;
-  sprite_z_vel[k] = 0;
-  sprite_x_subpixel[k] = 0;
-  sprite_y_subpixel[k] = 0;
-  sprite_z_subpos[k] = 0;
-  sprite_ai_state[k] = 0;
-  sprite_graphics[k] = 0;
-  sprite_D[k] = 0;
-  sprite_delay_main[k] = 0;
-  sprite_delay_aux1[k] = 0;
-  sprite_delay_aux2[k] = 0;
-  sprite_delay_aux4[k] = 0;
-  sprite_head_dir[k] = 0;
-  sprite_anim_clock[k] = 0;
-  sprite_G[k] = 0;
-  sprite_hit_timer[k] = 0;
-  sprite_wallcoll[k] = 0;
-  sprite_z[k] = 0;
-  sprite_health[k] = 0;
-  sprite_F[k] = 0;
-  sprite_x_recoil[k] = 0;
-  sprite_y_recoil[k] = 0;
-  sprite_A[k] = 0;
-  sprite_B[k] = 0;
-  sprite_C[k] = 0;
-  sprite_unk2[k] = 0;
-  sprite_subtype2[k] = 0;
-  sprite_ignore_projectile[k] = 0;
-  sprite_obj_prio[k] = 0;
-  sprite_oam_flags[k] = 0;
-  sprite_stunned[k] = 0;
-  sprite_give_damage[k] = 0;
-  sprite_unk3[k] = 0;
-  sprite_unk4[k] = 0;
-  sprite_unk5[k] = 0;
-  sprite_unk1[k] = 0;
-  sprite_I[k] = 0;
-}
-
-uint8 Oam_AllocateFromRegionA(uint8 num) {  // 8dba80
-  return Oam_GetBufferPosition(num, 0);
-}
-
-uint8 Oam_AllocateFromRegionB(uint8 num) {  // 8dba84
-  return Oam_GetBufferPosition(num, 2);
-}
-
-uint8 Oam_AllocateFromRegionC(uint8 num) {  // 8dba88
-  return Oam_GetBufferPosition(num, 4);
-}
-
-uint8 Oam_AllocateFromRegionD(uint8 num) {  // 8dba8c
-  return Oam_GetBufferPosition(num, 6);
-}
-
-uint8 Oam_AllocateFromRegionE(uint8 num) {  // 8dba90
-  return Oam_GetBufferPosition(num, 8);
-}
-
-uint8 Oam_AllocateFromRegionF(uint8 num) {  // 8dba94
-  return Oam_GetBufferPosition(num, 10);
-}
-
-uint8 Oam_GetBufferPosition(uint8 num, uint8 y) {  // 8dbb0a
-  y >>= 1;
-  uint16 p = oam_region_base[y], pstart = p;
-  p += num;
-  if (p >= kOamGetBufferPos_Tab0[y]) {
-    int j = oam_alloc_arr1[y]++ & 7;
-    pstart = kOamGetBufferPos_Tab1[y * 8 + j];
-  } else {
-    oam_region_base[y] = p;
-  }
-  oam_ext_cur_ptr = 0xa20 + (pstart >> 2);
-  oam_cur_ptr = 0x800 + pstart;
-  return oam_cur_ptr;
-}
-
-void Sprite_NullifyHookshotDrag() {  // 8ff540
-  for (int i = 4; i >= 0; i--) {
-    if (!(ancilla_type[i] & 0x1f) && related_to_hookshot) {
-      related_to_hookshot = 0;
-      break;
-    }
-  }
-  link_x_coord_safe_return_hi = link_x_coord >> 8;
-  link_y_coord_safe_return_hi = link_y_coord >> 8;
-  link_x_coord = link_x_coord_prev;
-  link_y_coord = link_y_coord_prev;
-  HandleIndoorCameraAndDoors();
-}
-
-void Overworld_SubstituteAlternateSecret() {  // 9afbdb
-  static const uint8 kSecretSubst_Tab0[64] = {
-    0,  0, 0, 0, 0, 0, 0, 4,  0,  0, 0, 0, 0, 0, 0, 0,
-    4,  4, 6, 4, 4, 6, 0, 0, 15, 15, 4, 5, 5, 4, 6, 6,
-    15, 15, 4, 5, 5, 7, 6, 6, 31, 31, 4, 7, 7, 4, 6, 6,
-    6,  7, 2, 0, 0, 0, 0, 0,  6,  6, 2, 0, 0, 0, 0, 0,
-  };
-  static const uint8 kSecretSubst_Tab2[16] = { 1, 1, 1, 1, 15, 1, 1, 18, 16, 1, 1, 1, 17, 1, 1, 3 };
-  static const uint8 kSecretSubst_Tab1[16] = { 0, 0, 0, 0, 2, 0, 0, 8, 16, 0, 0, 0, 1, 0, 0, 0 };
-  if (GetRandomNumber() & 1)
-    return;
-  int n = 0;
-  for (int j = 15; j >= 0; j--) {
-    if (sprite_state[j] && sprite_type[j] != 0x6c)
-      n++;
-  }
-  if (n >= 4 || sram_progress_indicator < 2)
-    return;
-  int j = (overworld_secret_subst_ctr++ & 7) + (is_in_dark_world ? 8 : 0);
-  if (!(kSecretSubst_Tab0[BYTE(overworld_area_index) & 0x3f] & kSecretSubst_Tab1[j]))
-    BYTE(dung_secrets_unk1) = kSecretSubst_Tab2[j];
-}
-
-void Sprite_ApplyConveyor(int k, int j) {  // 9d8010
-  if (!(frame_counter & 1))
-    return;
-  static const int8 kConveyorAdjustment_X[] = {0, 0, -1, 1};
-  static const int8 kConveyorAdjustment_Y[] = {-1, 1, 0, 0};
-  Sprite_SetX(k, Sprite_GetX(k) + kConveyorAdjustment_X[j - 0x68]);
-  Sprite_SetY(k, Sprite_GetY(k) + kConveyorAdjustment_Y[j - 0x68]);
-}
-
-uint8 Sprite_BounceFromTileCollision(int k) {  // 9dc751
-  int j = Sprite_CheckTileCollision(k);
-  if (j & 3) {
-    sprite_x_vel[k] = -sprite_x_vel[k];
-    sprite_G[k]++;
-  }
-  if (j & 12) {
-    sprite_y_vel[k] = -sprite_y_vel[k];
-    sprite_G[k]++;
-    return sprite_G[k]; // wtf
-  }
-  return 0;
-}
-
-void ExecuteCachedSprites() {  // 9de9da
-  if (!player_is_indoors || submodule_index == 0 || submodule_index == 14 || alt_sprites_flag == 0) {
-    alt_sprites_flag = 0;
-    return;
-  }
-  for (int i = 15; i >= 0; i--) {
-    cur_object_index = i;
-    if (alt_sprite_state[i])
-      UncacheAndExecuteSprite(i);
-  }
-}
-
-void UncacheAndExecuteSprite(int k) {  // 9dea00
-  uint8 bak0 = sprite_state[k];
-  uint8 bak1 = sprite_type[k];
-  uint8 bak2 = sprite_x_lo[k];
-  uint8 bak3 = sprite_x_hi[k];
-  uint8 bak4 = sprite_y_lo[k];
-  uint8 bak5 = sprite_y_hi[k];
-  uint8 bak6 = sprite_graphics[k];
-  uint8 bak7 = sprite_A[k];
-  uint8 bak8 = sprite_head_dir[k];
-  uint8 bak9 = sprite_oam_flags[k];
-  uint8 bak10 = sprite_obj_prio[k];
-  uint8 bak11 = sprite_D[k];
-  uint8 bak12 = sprite_flags2[k];
-  uint8 bak13 = sprite_floor[k];
-  uint8 bak14 = sprite_ai_state[k];
-  uint8 bak15 = sprite_flags3[k];
-  uint8 bak16 = sprite_B[k];
-  uint8 bak17 = sprite_C[k];
-  uint8 bak18 = sprite_E[k];
-  uint8 bak19 = sprite_subtype2[k];
-  uint8 bak20 = sprite_z[k];
-  uint8 bak21 = sprite_delay_main[k];
-  uint8 bak22 = sprite_I[k];
-  uint8 bak23 = sprite_ignore_projectile[k];
-  sprite_state[k] = alt_sprite_state[k];
-  sprite_type[k] = alt_sprite_type[k];
-  sprite_x_lo[k] = alt_sprite_x_lo[k];
-  sprite_x_hi[k] = alt_sprite_x_hi[k];
-  sprite_y_lo[k] = alt_sprite_y_lo[k];
-  sprite_y_hi[k] = alt_sprite_y_hi[k];
-  sprite_graphics[k] = alt_sprite_graphics[k];
-  sprite_A[k] = alt_sprite_A[k];
-  sprite_head_dir[k] = alt_sprite_head_dir[k];
-  sprite_oam_flags[k] = alt_sprite_oam_flags[k];
-  sprite_obj_prio[k] = alt_sprite_obj_prio[k];
-  sprite_D[k] = alt_sprite_D[k];
-  sprite_flags2[k] = alt_sprite_flags2[k];
-  sprite_floor[k] = alt_sprite_floor[k];
-  sprite_ai_state[k] = alt_sprite_spawned_flag[k];
-  sprite_flags3[k] = alt_sprite_flags3[k];
-  sprite_B[k] = alt_sprite_B[k];
-  sprite_C[k] = alt_sprite_C[k];
-  sprite_E[k] = alt_sprite_E[k];
-  sprite_subtype2[k] = alt_sprite_subtype2[k];
-  sprite_z[k] = alt_sprite_height_above_shadow[k];
-  sprite_delay_main[k] = alt_sprite_delay_main[k];
-  sprite_I[k] = alt_sprite_I[k];
-  sprite_ignore_projectile[k] = alt_sprite_maybe_ignore_projectile[k];
-  Sprite_ExecuteSingle(k);
-  if (sprite_pause[k] != 0)
-    alt_sprite_state[k] = 0;
-  sprite_ignore_projectile[k] = bak23;
-  sprite_I[k] = bak22;
-  sprite_delay_main[k] = bak21;
-  sprite_z[k] = bak20;
-  sprite_subtype2[k] = bak19;
-  sprite_E[k] = bak18;
-  sprite_C[k] = bak17;
-  sprite_B[k] = bak16;
-  sprite_flags3[k] = bak15;
-  sprite_ai_state[k] = bak14;
-  sprite_floor[k] = bak13;
-  sprite_flags2[k] = bak12;
-  sprite_D[k] = bak11;
-  sprite_obj_prio[k] = bak10;
-  sprite_oam_flags[k] = bak9;
-  sprite_head_dir[k] = bak8;
-  sprite_A[k] = bak7;
-  sprite_graphics[k] = bak6;
-  sprite_y_hi[k] = bak5;
-  sprite_y_lo[k] = bak4;
-  sprite_x_hi[k] = bak3;
-  sprite_x_lo[k] = bak2;
-  sprite_type[k] = bak1;
-  sprite_state[k] = bak0;
-
-}
-
-uint8 Sprite_ConvertVelocityToAngle(uint8 x, uint8 y) {  // 9df614
-  static const uint8 kConvertVelocityToAngle_Tab0[32] = {
-    0, 0, 1, 1, 1, 2, 2, 2, 0, 0, 15, 15, 15, 14, 14, 14,
-    8, 8, 7, 7, 7, 6, 6, 6, 8, 8,  9,  9,  9, 10, 10, 10,
-  };
-  static const uint8 kConvertVelocityToAngle_Tab1[32] = {
-    4, 4, 3, 3, 3, 2, 2, 2, 12, 12, 13, 13, 13, 14, 14, 14,
-    4, 4, 5, 5, 5, 6, 6, 6, 12, 12, 11, 11, 11, 10, 10, 10,
-  };
-  int s = ((y >> 7) + (x >> 7) * 2) * 8;
-  if (sign8(x)) x = -x;
-  if (sign8(y)) y = -y;
-  if (x >= y) {
-    return kConvertVelocityToAngle_Tab0[(y >> 2) + s];
-  } else {
-    return kConvertVelocityToAngle_Tab1[(x >> 2) + s];
-  }
-}
-
-int Sprite_SpawnDynamically(int k, uint8 what, SpriteSpawnInfo *info) {  // 9df65d
-  return Sprite_SpawnDynamicallyEx(k, what, info, 15);
-}
-
-int Sprite_SpawnDynamicallyEx(int k, uint8 what, SpriteSpawnInfo *info, int j) {  // 9df65f
-  do {
-    if (sprite_state[j] == 0) {
-      sprite_type[j] = what;
-      sprite_state[j] = 9;
-      info->r0_x = Sprite_GetX(k);
-      info->r2_y = Sprite_GetY(k);
-      info->r4_z = sprite_z[k];
-      info->r5_overlord_x = overlord_x_lo[k] | overlord_x_hi[k] << 8;
-      info->r7_overlord_y = overlord_y_lo[k] | overlord_y_hi[k] << 8;
-      SpritePrep_LoadProperties(j);
-      if (!player_is_indoors) {
-        sprite_N_word[j] = 0xffff;
-      } else {
-        sprite_N[j] = 0xff;
-      }
-      sprite_floor[j] = sprite_floor[k];
-      sprite_D[j] = sprite_D[k];
-      sprite_die_action[j] = 0;
-      sprite_subtype[j] = 0;
-      break;
-    }
-  } while (--j >= 0);
-  return j;
-}
-
-void SpriteFall_Draw(int k, PrepOamCoordsRet *info) {  // 9dffc5
-  static const uint8 kSpriteFall_Char[8] = {0x83, 0x83, 0x83, 0x80, 0x80, 0x80, 0xb7, 0xb7};
-  OamEnt *oam = GetOamCurPtr();
-  oam->x = info->x + 4;
-  oam->y = info->y + 4;
-  oam->charnum = kSpriteFall_Char[sprite_delay_main[k] >> 2];
-  oam->flags = info->flags & 0x30 | 0x04;
-  Sprite_CorrectOamEntries(k, 0, 0);
-}
-
-void Sprite_GarnishSpawn_Sparkle_limited(int k, uint16 x, uint16 y) {  // 9ea001
-  Sprite_SpawnSimpleSparkleGarnishEx(k, x, y, 14);
-}
-
-int Sprite_GarnishSpawn_Sparkle(int k, uint16 x, uint16 y) {  // 9ea007
-  return Sprite_SpawnSimpleSparkleGarnishEx(k, x, y, 29);
-}
-
-void Sprite_BehaveAsBarrier(int k) {  // 9ef4f3
-  uint8 bak = sprite_flags4[k];
-  sprite_flags4[k] = 0;
-  if (Sprite_CheckDamageToLink_same_layer(k))
-    Sprite_HaltAllMovement();
-  sprite_flags4[k] = bak;
-}
-
-void Sprite_HaltAllMovement() {  // 9ef508
-  Sprite_NullifyHookshotDrag();
-  link_speed_setting = 0;
-  Link_CancelDash();
-}
-
-int ReleaseFairy() {  // 9efe33
-  SpriteSpawnInfo info;
-  int j = Sprite_SpawnDynamically(0, 0xe3, &info);
-  if (j >= 0) {
-    sprite_floor[j] = link_is_on_lower_level;
-    Sprite_SetX(j, link_x_coord + 8);
-    Sprite_SetY(j, link_y_coord + 16);
-    sprite_D[j] = 0;
-    sprite_delay_aux4[j] = 96;
-  }
-  return j;
-}
-
-void Sprite_DrawRippleIfInWater(int k) {  // 9eff8d
-  if (sprite_I[k] != 8 && sprite_I[k] != 9)
-    return;
-
-  if (sprite_flags3[k] & 0x20) {
-    cur_sprite_x -= 4;
-    if (sprite_type[k] == 0xdf)
-      cur_sprite_y -= 7;
-  }
-  SpriteDraw_WaterRipple(k);
-  Sprite_Get16BitCoords(k);
-  Oam_AllocateFromRegionA(((sprite_flags2[k] & 0x1f) + 1) * 4);
-}
-
--- a/sprite.h
+++ /dev/null
@@ -1,309 +1,0 @@
-#pragma once
-#include "types.h"
-#include "variables.h"
-
-
-typedef struct PrepOamCoordsRet {
-  uint16 x, y;
-  uint8 r4;
-  uint8 flags;
-} PrepOamCoordsRet;
-
-typedef struct SpriteHitBox {
-  uint8 r0_xlo;
-  uint8 r8_xhi;
-  uint8 r1_ylo;
-  uint8 r9_yhi;
-  uint8 r2, r3;
-
-  uint8 r4_spr_xlo;
-  uint8 r10_spr_xhi;
-
-  uint8 r5_spr_ylo;
-  uint8 r11_spr_yhi;
-  uint8 r6_spr_xsize;
-  uint8 r7_spr_ysize;
-} SpriteHitBox;
-
-typedef struct SpriteSpawnInfo {
-  uint16 r0_x;
-  uint16 r2_y;
-  uint8 r4_z;
-  uint16 r5_overlord_x;
-  uint16 r7_overlord_y;
-} SpriteSpawnInfo;
-
-extern const uint8 kAbsorbBigKey[2];
-
-typedef struct DrawMultipleData {
-  int8 x, y;
-  uint16 char_flags;
-  uint8 ext;
-} DrawMultipleData;
-
-
-enum {
-  kCheckDamageFromPlayer_Carry = 1,
-  kCheckDamageFromPlayer_Ne = 2,
-};
-
-static inline void SetOamHelper0(OamEnt *oam, uint16 x, uint16 y, uint8 charnum, uint8 flags, uint8 big) {
-  oam->x = x;
-  oam->y = (uint16)(y + 0x10) < 0x100 ? y : 0xf0;
-  oam->charnum = charnum;
-  oam->flags = flags;
-  bytewise_extended_oam[oam - oam_buf] = big | (x >> 8 & 1);
-}
-
-static inline void SetOamHelper1(OamEnt *oam, uint16 x, uint8 y, uint8 charnum, uint8 flags, uint8 big) {
-  oam->x = x;
-  oam->y = y;
-  oam->charnum = charnum;
-  oam->flags = flags;
-  bytewise_extended_oam[oam - oam_buf] = big | (x >> 8 & 1);
-}
-
-static inline void SetOamPlain(OamEnt *oam, uint8 x, uint8 y, uint8 charnum, uint8 flags, uint8 big) {
-  oam->x = x;
-  oam->y = y;
-  oam->charnum = charnum;
-  oam->flags = flags;
-  bytewise_extended_oam[oam - oam_buf] = big;
-}
-
-
-
-extern const uint8 kAbsorptionSfx[15];
-extern const uint8 kSpriteInit_BumpDamage[243];
-extern const uint16 kSinusLookupTable[256];
-extern const uint8 kThrowableScenery_Flags[9];
-extern const uint8 kWishPond2_OamFlags[76];
-
-uint16 Sprite_GetX(int k);
-uint16 Sprite_GetY(int k);
-void Sprite_SetX(int k, uint16 x);
-void Sprite_SetY(int k, uint16 y);
-void Sprite_ApproachTargetSpeed(int k, uint8 x, uint8 y);
-void SpriteAddXY(int k, int xv, int yv);
-void Sprite_MoveXYZ(int k);
-void Sprite_Invert_XY_Speeds(int k);
-int Sprite_SpawnSimpleSparkleGarnishEx(int k, uint16 x, uint16 y, int limit);
-uint16 Garnish_GetX(int k);
-uint16 Garnish_GetY(int k);
-void Garnish_SparkleCommon(int k, uint8 shift);
-void Garnish_DustCommon(int k, uint8 shift);
-void SpriteModule_Explode(int k);
-void SpriteDeath_MainEx(int k, bool second_entry);
-void SpriteModule_Burn(int k);
-void Sprite_HitTimer31(int k);
-void SpriteStunned_MainEx(int k, bool second_entry);
-int Ancilla_SpawnFallingPrize(uint8 item);
-bool Sprite_CheckDamageToAndFromLink(int k);
-uint8 Sprite_CheckTileCollision(int k);
-bool Sprite_TrackBodyToHead(int k);
-void Sprite_DrawMultiple(int k, const DrawMultipleData *src, int n, PrepOamCoordsRet *info);
-void Sprite_DrawMultiplePlayerDeferred(int k, const DrawMultipleData *src, int n, PrepOamCoordsRet *info);
-int Sprite_ShowSolicitedMessage(int k, uint16 msg);
-int Sprite_ShowMessageOnContact(int k, uint16 msg);
-void Sprite_ShowMessageUnconditional(uint16 msg);
-bool Sprite_TutorialGuard_ShowMessageOnContact(int k, uint16 msg);
-void Sprite_ShowMessageMinimal();
-void Prepare_ApplyRumbleToSprites();
-void Sprite_SpawnImmediatelySmashedTerrain(uint8 what, uint16 x, uint16 y);
-void Sprite_SpawnThrowableTerrain(uint8 what, uint16 x, uint16 y);
-int Sprite_SpawnThrowableTerrain_silently(uint8 what, uint16 x, uint16 y);
-void Sprite_SpawnSecret(int k);
-void Sprite_Main();
-void Oam_ResetRegionBases();
-void Sprite_TimersAndOam(int k);
-void Sprite_Get16BitCoords(int k);
-void Sprite_ExecuteSingle(int k);
-void Sprite_inactiveSprite(int k);
-void SpriteModule_Fall1(int k);
-void SpriteModule_Drown(int k);
-void Sprite_DrawDistress_custom(uint16 xin, uint16 yin, uint8 time);
-void Sprite_CheckIfLifted_permissive(int k);
-void Entity_ApplyRumbleToSprites(SpriteHitBox *hb);
-void Sprite_ZeroVelocity_XY(int k);
-bool Sprite_HandleDraggingByAncilla(int k);
-bool Sprite_ReturnIfPhasingOut(int k);
-void Sprite_CheckAbsorptionByPlayer(int k);
-void Sprite_HandleAbsorptionByPlayer(int k);
-bool SpriteDraw_AbsorbableTransient(int k, bool transient);
-void Sprite_DrawNumberedAbsorbable(int k, int a);
-void Sprite_BounceOffWall(int k);
-void Sprite_InvertSpeed_XY(int k);
-bool Sprite_ReturnIfInactive(int k);
-bool Sprite_ReturnIfPaused(int k);
-void SpriteDraw_SingleLarge(int k);
-void Sprite_PrepAndDrawSingleLargeNoPrep(int k, PrepOamCoordsRet *info);
-void SpriteDraw_Shadow_custom(int k, PrepOamCoordsRet *info, uint8 a);
-void SpriteDraw_Shadow(int k, PrepOamCoordsRet *oam);
-void SpriteDraw_SingleSmall(int k);
-void Sprite_DrawThinAndTall(int k);
-void SpriteModule_Carried(int k);
-void CarriedSprite_CheckForThrow(int k);
-void SpriteModule_Stunned(int k);
-void ThrownSprite_TileAndSpriteInteraction(int k);
-void Sprite_Func8(int k);
-void Sprite_Func22(int k);
-void ThrowableScenery_InteractWithSpritesAndTiles(int k);
-void ThrownSprite_CheckDamageToSprites(int k);
-void ThrownSprite_CheckDamageToSingleSprite(int k, int j);
-void Sprite_ApplyRicochet(int k);
-void ThrowableScenery_TransmuteIfValid(int k);
-void ThrowableScenery_TransmuteToDebris(int k);
-void Sprite_ScheduleForBreakage(int k);
-void Sprite_HalveSpeed_XY(int k);
-void Sprite_SpawnLeapingFish(int k);
-void SpriteStunned_Main_Func1(int k);
-void SpriteModule_Poof(int k);
-void Sprite_PrepOamCoord(int k, PrepOamCoordsRet *ret);
-bool Sprite_PrepOamCoordOrDoubleRet(int k, PrepOamCoordsRet *ret);
-void Sprite_CheckTileCollision2(int k);
-void Sprite_CheckTileCollisionSingleLayer(int k);
-void Sprite_CheckForTileInDirection_horizontal(int k, int yy);
-void Sprite_CheckForTileInDirection_vertical(int k, int yy);
-void SpriteFall_AdjustPosition(int k);
-bool Sprite_CheckTileInDirection(int k, int yy);
-bool Sprite_CheckTileProperty(int k, int j);
-uint8 GetTileAttribute(uint8 floor, uint16 *x, uint16 y);
-uint8 Sprite_GetTileAttribute(int k, uint16 *x, uint16 y);
-bool Entity_CheckSlopedTileCollision(uint16 x, uint16 y);
-void Sprite_MoveXY(int k);
-void Sprite_MoveX(int k);
-void Sprite_MoveY(int k);
-void Sprite_MoveZ(int k);
-ProjectSpeedRet Sprite_ProjectSpeedTowardsLink(int k, uint8 vel);
-void Sprite_ApplySpeedTowardsLink(int k, uint8 vel);
-ProjectSpeedRet Sprite_ProjectSpeedTowardsLocation(int k, uint16 x, uint16 y, uint8 vel);
-uint8 Sprite_DirectionToFaceLink(int k, PointU8 *coords_out);
-PairU8 Sprite_IsRightOfLink(int k);
-PairU8 Sprite_IsBelowLink(int k);
-PairU8 Sprite_IsRightOfLocation(int k, uint16 x);
-PairU8 Sprite_IsBelowLocation(int k, uint16 y);
-uint8 Sprite_DirectionToFaceLocation(int k, uint16 x, uint16 y);
-void Guard_ParrySwordAttacks(int k);
-void Sprite_AttemptZapDamage(int k);
-void Ancilla_CheckDamageToSprite_preset(int k, int a);
-void Sprite_Func15(int k, int a);
-void Sprite_CalculateSwordDamage(int k);
-void Sprite_ApplyCalculatedDamage(int k, int a);
-void Sprite_GiveDamage(int k, uint8 dmg, uint8 r0_hit_timer);
-void Sprite_Func18(int k, uint8 new_type);
-void Sprite_MiniMoldorm_Recoil(int k);
-void Sprite_Func3(int k);
-bool Sprite_CheckDamageToLink(int k);
-bool Sprite_CheckDamageToPlayer_1(int k);
-bool Sprite_CheckDamageToLink_same_layer(int k);
-bool Sprite_CheckDamageToLink_ignore_layer(int k);
-bool Sprite_SetupHitBox00(int k);
-bool Sprite_ReturnIfLifted(int k);
-bool Sprite_ReturnIfLiftedPermissive(int k);
-uint8 Sprite_CheckDamageFromLink(int k);
-void Sprite_AttemptDamageToLinkWithCollisionCheck(int k);
-void Sprite_AttemptDamageToLinkPlusRecoil(int k);
-void Player_SetupActionHitBox(SpriteHitBox *hb);
-void Link_UpdateHitBoxWithSword(SpriteHitBox *hb);
-void Sprite_DoHitBoxesFast(int k, SpriteHitBox *hb);
-void Sprite_ApplyRecoilToLink(int k, uint8 vel);
-void Link_PlaceWeaponTink();
-void Sprite_PlaceWeaponTink(int k);
-void Sprite_PlaceRupulseSpark_2(int k);
-void Link_SetupHitBox_conditional(SpriteHitBox *hb);
-void Link_SetupHitBox(SpriteHitBox *hb);
-void Sprite_SetupHitBox(int k, SpriteHitBox *hb);
-bool CheckIfHitBoxesOverlap(SpriteHitBox *hb);
-void Oam_AllocateDeferToPlayer(int k);
-void SpriteModule_Die(int k);
-void Sprite_DoTheDeath(int k);
-void ForcePrizeDrop(int k, uint8 prize, uint8 slot);
-void PrepareEnemyDrop(int k, uint8 item);
-void SpriteDeath_Func4(int k);
-void SpriteDeath_DrawPoof(int k);
-void SpriteModule_Fall2(int k);
-void SpriteDraw_FallingHelmaBeetle(int k);
-void SpriteDraw_FallingHumanoid(int k);
-void Sprite_CorrectOamEntries(int k, int n, uint8 islarge);
-bool Sprite_ReturnIfRecoiling(int k);
-bool Sprite_CheckIfLinkIsBusy();
-void Sprite_SetSpawnedCoordinates(int k, SpriteSpawnInfo *info);
-bool Sprite_CheckIfScreenIsClear();
-bool Sprite_CheckIfRoomIsClear();
-bool Sprite_CheckIfOverlordsClear();
-void Sprite_InitializeMirrorPortal();
-void Sprite_InitializeSlots();
-void Garnish_ExecuteUpperSlots();
-void Garnish_ExecuteLowerSlots();
-void Garnish_ExecuteSingle(int k);
-void Garnish15_ArrghusSplash(int k);
-void Garnish13_PyramidDebris(int k);
-void Garnish11_WitheringGanonBatFlame(int k);
-void Garnish10_GanonBatFlame(int k);
-void Garnish0C_TrinexxIceBreath(int k);
-void Garnish14_KakKidDashDust(int k);
-void Garnish_WaterTrail(int k);
-void Garnish0A_CannonSmoke(int k);
-void Garnish09_LightningTrail(int k);
-void Garnish_CheckPlayerCollision(int k, int x, int y);
-void Garnish07_BabasuFlash(int k);
-void Garnish08_KholdstareTrail(int k);
-void Garnish06_ZoroTrail(int k);
-void Garnish12_Sparkle(int k);
-void Garnish_SimpleSparkle(int k);
-void Garnish0E_TrinexxFireBreath(int k);
-void Garnish0F_BlindLaserTrail(int k);
-void Garnish04_LaserTrail(int k);
-bool Garnish_ReturnIfPrepFails(int k, Point16U *pt);
-void Garnish03_FallingTile(int k);
-void Garnish01_FireSnakeTail(int k);
-void Garnish02_MothulaBeamTrail(int k);
-void Dungeon_ResetSprites();
-void Dungeon_CacheTransSprites();
-void Sprite_DisableAll();
-void Dungeon_LoadSprites();
-void Sprite_ManuallySetDeathFlagUW(int k);
-int Dungeon_LoadSingleSprite(int k, const uint8 *src);
-void Dungeon_LoadSingleOverlord(const uint8 *src);
-void Sprite_ResetAll();
-void Sprite_ResetAll_noDisable();
-void Sprite_ReloadAll_Overworld();
-void Sprite_OverworldReloadAll_justLoad();
-void Overworld_LoadSprites();
-void Sprite_ActivateAllProxima();
-void Sprite_ProximityActivation();
-void Sprite_ActivateWhenProximal();
-void Sprite_ActivateWhenProximalBig();
-void Sprite_Overworld_ProximityMotivatedLoad(uint16 x, uint16 y);
-void Overworld_LoadProximaSpriteIfAlive(uint16 blk);
-void SpriteExplode_SpawnEA(int k);
-void Sprite_KillFriends();
-void Garnish16_ThrownItemDebris(int k);
-void ScatterDebris_Draw(int k, Point16U pt);
-void Sprite_KillSelf(int k);
-void SpritePrep_LoadProperties(int k);
-void SpritePrep_LoadPalette(int k);
-void SpritePrep_ResetProperties(int k);
-uint8 Oam_AllocateFromRegionA(uint8 num);
-uint8 Oam_AllocateFromRegionB(uint8 num);
-uint8 Oam_AllocateFromRegionC(uint8 num);
-uint8 Oam_AllocateFromRegionD(uint8 num);
-uint8 Oam_AllocateFromRegionE(uint8 num);
-uint8 Oam_AllocateFromRegionF(uint8 num);
-uint8 Oam_GetBufferPosition(uint8 num, uint8 y);
-void Sprite_NullifyHookshotDrag();
-void Overworld_SubstituteAlternateSecret();
-void Sprite_ApplyConveyor(int k, int j);
-uint8 Sprite_BounceFromTileCollision(int k);
-void ExecuteCachedSprites();
-void UncacheAndExecuteSprite(int k);
-uint8 Sprite_ConvertVelocityToAngle(uint8 x, uint8 y);
-int Sprite_SpawnDynamically(int k, uint8 what, SpriteSpawnInfo *info);
-int Sprite_SpawnDynamicallyEx(int k, uint8 what, SpriteSpawnInfo *info, int j);
-void SpriteFall_Draw(int k, PrepOamCoordsRet *info);
-void Sprite_GarnishSpawn_Sparkle_limited(int k, uint16 x, uint16 y);
-int Sprite_GarnishSpawn_Sparkle(int k, uint16 x, uint16 y);
-void Sprite_BehaveAsBarrier(int k);
-void Sprite_HaltAllMovement();
-int ReleaseFairy();
-void Sprite_DrawRippleIfInWater(int k);
--- a/sprite_main.c
+++ /dev/null
@@ -1,25878 +1,0 @@
-#include "sprite_main.h"
-#include "sprite.h"
-#include "tagalong.h"
-#include "ancilla.h"
-#include "overworld.h"
-#include "load_gfx.h"
-#include "hud.h"
-#include "dungeon.h"
-#include "player.h"
-#include "misc.h"
-
-#define byte_7FFE01 (*(uint8*)(g_ram+0x1FE01))
-static const int8 kSpriteKeese_Tab2[16] = {0, 8, 11, 14, 16, 14, 11, 8, 0, -8, -11, -14, -16, -14, -11, -8};
-static const int8 kSpriteKeese_Tab3[16] = {-16, -14, -11, -8, 0, 8, 11, 14, 16, 14, 11, 8, 0, -9, -11, -14};
-static const int8 kZazak_Yvel[4] = {0, 0, 16, -16};
-static const int8 kFluteBoyAnimal_Xvel[4] = {16, -16, 0, 0};
-static const int8 kDesertBarrier_Xv[4] = {16, -16, 0, 0};
-static const int8 kDesertBarrier_Yv[4] = {0, 0, 16, -16};
-static const uint8 kCrystalSwitchPal[2] = {2, 4};
-static const uint8 kZazak_Dir2[8] = {2, 3, 2, 3, 0, 1, 0, 1};
-#define moldorm_x_lo ((uint8*)(g_ram+0x1FC00))
-#define moldorm_x_hi ((uint8*)(g_ram+0x1FC80))
-#define moldorm_y_lo ((uint8*)(g_ram+0x1FD00))
-#define moldorm_y_hi ((uint8*)(g_ram+0x1FD80))
-static const int8 kBadPullDownSwitch_X[5] = {-4, 12, 0, -4, 4};
-static const int8 kBadPullDownSwitch_Y[5] = {-3, -3, 0, 5, 5};
-static const uint8 kBadPullDownSwitch_Char[5] = {0xd2, 0xd2, 0xc4, 0xe4, 0xe4};
-static const uint8 kBadPullDownSwitch_Flags[5] = {0x40, 0, 0, 0x40, 0};
-static const uint8 kBadPullDownSwitch_Big[5] = {0, 0, 2, 2, 2};
-static const uint8 kBadPullSwitch_Tab5[6] = {0, 1, 2, 3, 4, 5};
-static const uint8 kBadPullSwitch_Tab4[12] = {0, 0, 1, 1, 2, 2, 3, 3, 4, 5, 5, 5};
-static const uint8 kThief_Gfx[12] = {11, 8, 2, 5, 9, 6, 0, 3, 10, 7, 1, 4};
-#define word_7FFE00 (*(uint16*)(g_ram+0x1FE00))
-#define word_7FFE02 (*(uint16*)(g_ram+0x1FE02))
-#define word_7FFE04 (*(uint16*)(g_ram+0x1FE04))
-#define word_7FFE06 (*(uint16*)(g_ram+0x1FE06))
-static const int16 kTutorialSoldier_X[20] = {
-  4, 0, -6, -6, 2, 0, 0, -7, -7, -7, 0, 0, 0xf, 0xf, 0xf, 6,
-  0xe, -4, 4, 0,
-};
-static const int16 kTutorialSoldier_Y[20] = {
-  0, -10, -4, 12, 12, 0, -9, -11, -3, 5, 0, -9, -11, -3, 5, -11,
-  5, 0, 0, -9,
-};
-static const uint8 kTutorialSoldier_Char[20] = {
-  0x46, 0x40, 0, 0x28, 0x29, 0x4e, 0x42, 0x39, 0x2a, 0x3a, 0x4e, 0x42, 0x39, 0x2a, 0x3a, 0x26,
-  0x38, 0x64, 0x64, 0x44,
-};
-static const uint8 kTutorialSoldier_Flags[20] = {
-  0x40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x40, 0x40, 0x40, 0x40, 0x40, 0,
-  0x40, 0, 0x40, 0,
-};
-static const uint8 kTutorialSoldier_Big[20] = {
-  2, 2, 2, 0, 0, 2, 2, 0, 0, 0, 2, 2, 0, 0, 0, 2,
-  0, 2, 2, 2,
-};
-static const uint8 kSprite_TutorialEntities_Tab[4] = {2, 1, 0, 3};
-static const uint8 kSoldier_DirectionLockSettings[4] = {3, 2, 0, 1};
-static const uint8 kWishPond_X[8] = {0, 4, 8, 12, 16, 20, 24, 0};
-static const uint8 kWishPond_Y[8] = {0, 8, 16, 24, 32, 40, 4, 36};
-const uint8 kWishPond2_OamFlags[76] = {
-  5, 0xff, 5, 5, 5, 5, 5, 1, 2, 1, 1, 1, 2, 2, 2, 4,
-  4,    4, 1, 1, 2, 1, 1, 1, 2, 1, 2, 1, 4, 4, 2, 1,
-  6,    1, 2, 1, 2, 2, 1, 2, 2, 4, 1, 1, 4, 2, 1, 4,
-  2,    2, 4, 4, 4, 2, 1, 4, 1, 2, 2, 1, 2, 2, 1, 1,
-  4,    4, 1, 2, 2, 4, 4, 4, 2, 5, 2, 1,
-};
-static const uint8 kWishPondItemOffs[32] = {
-  0, 4, 6, 7, 8, 10, 11, 12, 13, 14, 15, 16, 17, 20, 21, 22, 22, 23, 24, 25, 28, 30, 31, 32, 33, 33, 37, 40, 42, 42, 42, 42
-};
-static const uint8 kWishPondItemData[50] = {
-  0x3a, 0x3a, 0x3b, 0x3b, 0x0c, 0x2a, 0x0a, 0x27, 0x29, 0x0d, 0x07, 0x08, 0x0f, 0x10, 0x11, 0x12,
-  0x09, 0x13, 0x14, 0x4a, 0x21, 0x1d, 0x15, 0x18, 0x19, 0x31, 0x1a, 0x1a, 0x1b, 0x1c, 0x4b, 0x1e,
-  0x1f, 0x49, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x22, 0x23, 0x29, 0x16, 0x2b, 0x2c, 0x2d, 0x3d, 0x3c, 0x48
-};
-static const uint8 kUncle_LeaveHouse_Delay[2] = {64, 224};
-static const uint8 kUncle_LeaveHouse_Dir[2] = {2, 1};
-static const int8 kUncle_LeaveHouse_Xvel[4] = {0, 0, -12, 12};
-static const int8 kUncle_LeaveHouse_Yvel[4] = {-12, 12, 0, 0};
-static const DrawMultipleData kPriest_Dmd[20] = {
-  { 0, -8, 0x0e20, 2},
-  { 0,  0, 0x0e26, 2},
-  { 0, -8, 0x0e20, 2},
-  { 0,  0, 0x4e26, 2},
-  { 0, -8, 0x0e0e, 2},
-  { 0,  0, 0x0e24, 2},
-  { 0, -8, 0x0e0e, 2},
-  { 0,  0, 0x0e24, 2},
-  { 0, -8, 0x0e22, 2},
-  { 0,  0, 0x0e28, 2},
-  { 0, -8, 0x0e22, 2},
-  { 0,  0, 0x0e2a, 2},
-  { 0, -8, 0x4e22, 2},
-  { 0,  0, 0x4e28, 2},
-  { 0, -8, 0x4e22, 2},
-  { 0,  0, 0x4e2a, 2},
-  {-7,  1, 0x0e0a, 2},
-  { 3,  3, 0x0e0c, 2},
-  {-7,  1, 0x0e0a, 2},
-  { 3,  3, 0x0e0c, 2},
-};
-static const DrawMultipleData kSageMantle_Dmd[4] = {
-  {0, 0, 0x162c, 2},
-  {16, 0, 0x562c, 2},
-  {0, 16, 0x062e, 2},
-  {16, 16, 0x462e, 2},
-};
-static const uint8 kCrystalMaiden_Dma[16] = {0x20, 0xc0, 0x20, 0xc0, 0, 0xa0, 0, 0xa0, 0x40, 0x80, 0x40, 0x60, 0x40, 0x80, 0x40, 0x60};
-static const DrawMultipleData kCrystalMaiden_SpriteData[16] = {
-  {1, -7, 0x0120, 2},
-  {1,  3, 0x0122, 2},
-  {1, -7, 0x0120, 2},
-  {1,  3, 0x4122, 2},
-  {1, -7, 0x0120, 2},
-  {1,  3, 0x0122, 2},
-  {1, -7, 0x0120, 2},
-  {1,  3, 0x4122, 2},
-  {1, -7, 0x0120, 2},
-  {1,  3, 0x0122, 2},
-  {1, -7, 0x0120, 2},
-  {1,  3, 0x0122, 2},
-  {1, -7, 0x4120, 2},
-  {1,  3, 0x4122, 2},
-  {1, -7, 0x4120, 2},
-  {1,  3, 0x4122, 2},
-};
-static const int8 kZelda_Xvel[4] = {0, 0, -9, 9};
-static const int8 kZelda_Yvel[4] = {-9, 9, 0, 0};
-static const int8 kHeartRefill_AccelX[2] = {1, -1};
-static const int8 kHeartRefill_VelTarget[2] = {10, -10};
-static const DrawMultipleData kFakeSword_Dmd[2] = {
-  {4, 0, 0x00f4, 0},
-  {4, 8, 0x00f5, 0},
-};
-static const uint8 kThrowableScenery_Char[12] = {0x42, 0x44, 0x46, 0, 0x46, 0x44, 0x42, 0x44, 0x44, 0, 0x46, 0x44};
-const uint8 kThrowableScenery_Flags[9] = { 0xc, 0xc, 0xc, 0, 0, 0, 0xb0, 0x08, 0xb4 };
-static const int16 kThrowableScenery_DrawLarge_X[4] = {-8, 8, -8, 8};
-static const int16 kThrowableScenery_DrawLarge_Y[4] = {-14, -14, 2, 2};
-static const uint8 kThrowableScenery_DrawLarge_Flags[4] = {0, 0x40, 0x80, 0xc0};
-static const int16 kThrowableScenery_DrawLarge_X2[3] = {-6, 0, 6};
-static const uint8 kThrowableScenery_DrawLarge_OamFlags[2] = {0xc, 0};
-static const int8 kScatterDebris_X[4] = {-8, 8, -8, 8};
-static const int8 kScatterDebris_Y[4] = {-8, -8, 8, 8};
-static const uint8 kMovableMantle_X[6] = {0, 0x10, 0x20, 0, 0x10, 0x20};
-static const uint8 kMovableMantle_Y[6] = {0, 0, 0, 0x10, 0x10, 0x10};
-static const uint8 kMovableMantle_Char[6] = {0xc, 0xe, 0xc, 0x2c, 0x2e, 0x2c};
-static const uint8 kMovableMantle_Flags[6] = {0x31, 0x31, 0x71, 0x31, 0x31, 0x71};
-static const uint8 kSprite_SimplifiedTileAttr[256] = {
-  0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0,
-  1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 3, 3, 3,
-  0, 0, 0, 0, 0, 0, 1, 1, 4, 4, 4, 4, 4, 4, 4, 4,
-  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1,
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4,
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1,
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-};
-static const uint8 kSoldier_Gfx[4] = {8, 0, 12, 5};
-static const uint8 kSoldier_Delay[4] = {0x60, 0xc0, 0xff, 0x40};
-static const uint8 kSoldier_Draw1_Char[4] = {0x42, 0x42, 0x40, 0x44};
-static const uint8 kSoldier_Draw1_Flags[4] = {0x40, 0, 0, 0};
-static const int8 kSoldier_Draw1_Yd[26] = {
-  7, 8, 7, 8, 8, 7, 8, 7, 8, 7, 8, 8, 7, 8, 8, 8,
-  8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
-};
-static const int8 kSoldier_Draw2_Xd[104] = {
-  -4, 4, 10, 10, -4, 4, 10, 10, -4, 4, 10, 10, -4, 4, 10, 10,
-  -4, -4, 0, 0, -4, -4, 0, 0, -3, -3, 0, 0, -3, -3, -4, 4,
-  -3, -3, -4, 4, -3, -3, -4, 4, -3, -3, -4, 4, 12, 12, 0, 0,
-  12, 12, 0, 0, 11, 11, 0, 0, -4, 4, 0, 0, -4, 4, 0, 0,
-  -4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-  -4, 4, 0, 0, -4, 4, 0, 0, -4, 4, 0, 0, 0, 0, 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0,
-};
-static const int8 kSoldier_Draw2_Yd[104] = {
-  0, 0, 2, 10, 0, 0, 2, 10, 0, 0, 1, 9, 0, 0, 2, 10,
-  -2, 6, 1, 1, -2, 6, 2, 2, -2, 6, 1, 1, -5, 3, 0, 0,
-  -4, 4, 0, 0, -4, 4, 0, 0, -5, 3, 0, 0, -2, 6, 1, 1,
-  -2, 6, 2, 2, -2, 6, 1, 1, 0, 0, 8, 8, 0, 0, 8, 8,
-  0, 0, 8, 8, 0, 0, 8, 8, 0, 0, 8, 8, 0, 0, 8, 8,
-  0, 0, 8, 8, 0, 0, 8, 8, 0, 0, 8, 8, 0, 0, 8, 8,
-  0, 0, 8, 8, 0, 0, 8, 8,
-};
-static const uint8 kSoldier_Draw2_Char[104] = {
-  0x48, 0x49, 0x6d, 0x7d, 0x49, 0x48, 0x6d, 0x7d, 0x46, 0x46, 0x6d, 0x7d, 0x4b, 0x46, 0x6d, 0x7d,
-  0x4d, 0x5d, 0x4e, 0x4e, 0x4d, 0x5d, 0x60, 0x60, 0x4d, 0x5d, 0x62, 0x62, 0x6d, 0x7d, 0x64, 0x64,
-  0x6d, 0x7d, 0x66, 0x67, 0x6d, 0x7d, 0x67, 0x66, 0x6d, 0x7d, 0x64, 0x69, 0x4d, 0x5d, 0x4e, 0x4e,
-  0x4d, 0x5d, 0x60, 0x60, 0x4d, 0x5d, 0x62, 0x62, 2, 3, 0x20, 0x20, 2, 0xc, 0x20, 0x20,
-  2, 0xc, 0x20, 0x20, 8, 8, 0x20, 0x20, 0xe, 0xe, 0x20, 0x20, 0xe, 0xe, 0x20, 0x20,
-  5, 6, 0x20, 0x20, 0x22, 6, 0x20, 0x20, 0x22, 6, 0x20, 0x20, 8, 8, 0x20, 0x20,
-  0xe, 0xe, 0x20, 0x20, 0xe, 0xe, 0x20, 0x20,
-};
-static const uint8 kSoldier_Draw2_Flags[104] = {
-  0, 0, 0, 0, 0x40, 0x40, 0, 0, 0, 0x40, 0, 0, 0, 0x40, 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x40,
-  0, 0, 0, 0, 0, 0, 0x40, 0x40, 0, 0, 0, 0x40, 0x40, 0x40, 0x40, 0x40,
-  0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0, 0, 0, 0, 0, 0, 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x40, 0x40, 0x40, 0x40,
-  0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
-};
-static const uint8 kSoldier_Draw2_Big[104] = {
-  2, 2, 0, 0, 2, 2, 0, 0, 2, 2, 0, 0, 2, 2, 0, 0,
-  0, 0, 2, 2, 0, 0, 2, 2, 0, 0, 2, 2, 0, 0, 2, 2,
-  0, 0, 2, 2, 0, 0, 2, 2, 0, 0, 2, 2, 0, 0, 2, 2,
-  0, 0, 2, 2, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-  2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-  2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-  2, 2, 2, 2, 2, 2, 2, 2,
-};
-static const uint8 kSoldier_Draw2_OamIdx[4] = {12, 12, 12, 4};
-static const int8 kSoldier_Draw3_Xd[28] = {
-  -3, -3, -4, -4, -4, -4, -4, -4, -11, -3, -11, -3, -16, -8, 12, 12,
-  12, 12, 12, 12, 12, 12, 21, 13, 21, 13, 24, 16,
-};
-static const int8 kSoldier_Draw3_Yd[28] = {
-  11, 19, 11, 19, 10, 18, 14, 22, 8, 8, 8, 8, 6, 6, -10, -2,
-  -9, -1, -9, -1, -16, -8, 8, 8, 8, 8, 6, 6,
-};
-static const uint8 kSoldier_Draw3_Char[28] = {
-  0x7b, 0x6b, 0x7b, 0x6b, 0x7b, 0x6b, 0x7b, 0x6b, 0x6c, 0x7c, 0x6c, 0x7c, 0x6c, 0x7c, 0x6b, 0x7b,
-  0x6b, 0x7b, 0x6b, 0x7b, 0x6b, 0x7b, 0x6c, 0x7c, 0x6c, 0x7c, 0x6c, 0x7c,
-};
-static const uint8 kSoldier_Draw3_Flags[28] = {
-  0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0, 0, 0, 0, 0, 0, 0, 0,
-  0, 0, 0, 0, 0, 0, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
-};
-static const uint8 kSoldier_Draw3_OamIdx[4] = {4, 4, 4, 20};
-static const int8 kSoldier_Xvel[4] = {8, -8, 0, 0};
-static const int8 kSoldier_Yvel[4] = {0, 0, 8, -8};
-static const uint8 kSoldier_Gfx2[32] = {
-  11, 12, 13, 12, 4, 5, 6, 5, 0, 1, 2, 3, 7, 8, 9, 10,
-  17, 18, 17, 18, 7, 8, 7, 8, 3, 4, 3, 4, 13, 14, 13, 14,
-};
-static const int8 kSoldierB_Xvel[8] = {1, 1, -1, -1, -1, -1, 1, 1};
-static const int8 kSoldierB_Yvel[8] = {-1, 1, 1, -1, -1, 1, 1, -1};
-static const int8 kSoldierB_Xvel2[8] = {8, 0, -8, 0, -8, 0, 8, 0};
-static const int8 kSoldierB_Yvel2[8] = {0, 8, 0, -8, 0, 8, 0, -8};
-static const uint8 kSoldierB_Dir[8] = {0, 2, 1, 3, 1, 2, 0, 3};
-static const uint8 kSoldierB_Mask2[8] = {1, 4, 2, 8, 2, 4, 1, 8};
-static const uint8 kSoldierB_Mask[8] = {8, 1, 4, 2, 8, 2, 4, 1};
-static const uint8 kSoldierB_NextB2[8] = {1, 2, 3, 0, 5, 6, 7, 4};
-static const uint8 kSoldierB_NextB[8] = {3, 0, 1, 2, 7, 4, 5, 6};
-static const uint8 kSoldier_HeadDirs[32] = {
-  0, 2, 2, 2, 0, 3, 3, 3, 1, 3, 3, 3, 1, 2, 2, 2,
-  2, 0, 0, 0, 2, 1, 1, 1, 3, 1, 1, 1, 3, 0, 0, 0,
-};
-static const uint8 kSoldier_Tab1[4] = {13, 13, 12, 12};
-static const uint8 kSoldier_DrawShadow[4] = {0xc, 0xc, 0xa, 0xa};
-static const int8 kSoldier_SetTowardsVel[6] = {14, -14, 0, 0, 14, -14};
-static const uint8 kSprite_SpawnProbeStaggered_Tab[4] = {0x10, 0x30, 0, 0x20};
-static const int8 kSpawnProbe_Xvel[64] = {
-  -16, -16, -16, -16, -16, -16, -16, -16, -16, -14, -12, -10, -8, -6, -4, -2,
-  0, 2, 4, 6, 8, 10, 12, 14, 16, 16, 16, 16, 16, 16, 16, 16,
-  16, 16, 16, 16, 16, 16, 16, 16, 14, 12, 10, 8, 6, 4, 2, 0,
-  -2, -4, -6, -8, -10, -12, -14, -16, -16, -16, -16, -16, -16, -16, -16, -16,
-};
-static const int8 kSpawnProbe_Yvel[64] = {
-  0, 2, 4, 6, 8, 10, 12, 14, 16, 16, 16, 16, 16, 16, 16, 16,
-  16, 16, 16, 16, 16, 16, 16, 16, 14, 12, 10, 8, 6, 4, 2, 0,
-  -2, -4, -6, -8, -10, -12, -14, -16, -16, -16, -16, -16, -16, -16, -16, -16,
-  -16, -16, -16, -16, -16, -16, -16, -16, -14, -12, -10, -8, -6, -4, -2, 0,
-};
-int ctr;
-bool foo = false;
-static const uint8 kChainBallTrooper_Tab1[4] = {0x0d, 0x60, 0x22, 0x10};  // wtf
-static const uint8 kFlailTrooperGfx[32] = {
-  0x10, 0x11, 0x12, 0x13, 0x10, 0x11, 0x12, 0x13, 6, 7, 8, 9, 6, 7, 8, 9,
-  0, 1, 2, 3, 0, 1, 4, 5, 0xa, 0xb, 0xc, 0xd, 0xa, 0xb, 0xe, 0xf,
-};
-static const uint8 kJavelinTrooper_Tab2[64] = {
-  25, 25, 24, 24, 23, 23, 23, 23, 19, 19, 18, 18, 17, 17, 17, 17,
-  16, 16, 15, 15, 14, 14, 14, 14, 22, 22, 21, 21, 20, 20, 20, 20,
-  20, 20, 18, 18, 18, 16, 16, 16, 21, 21,  8,  8,  8,  6,  6,  6,
-  22, 22,  4,  4,  4,  3,  3,  3, 23, 23, 15, 15, 15, 11, 11, 11,
-};
-static const int8 kSprite_Recruit_Xvel[8] = {12, -12, 0, 0, 18, -18, 0, 0};
-static const int8 kSprite_Recruit_Yvel[8] = {0, 0, 0xc, -0xc, 0, 0, 0x12, -0x12};
-static const int8 kSprite_Recruit_Gfx[8] = {0, 2, 4, 6, 1, 3, 5, 7};
-static const uint8 kRecruit_Moving_HeadDir[8] = {2, 3, 2, 3, 0, 1, 0, 1};
-static const int16 kRecruit_Draw_X[8] = {2, 2, -2, -2, 0, 0, 0, 0};
-static const uint8 kRecruit_Draw_Char[8] = {0x8a, 0x8c, 0x8a, 0x8c, 0x86, 0x88, 0x8e, 0xa0};
-static const uint8 kRecruit_Draw_Flags[8] = {0x40, 0x40, 0, 0, 0, 0, 0, 0};
-static const uint8 kSprite_Zora_SurfacingGfx[16] = {4, 3, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 0, 0};
-static const uint8 kChainBallTrooperHead_Char[4] = {2, 2, 0, 4};
-static const uint8 kChainBallTrooperHead_Flags[4] = {0x40, 0, 0, 0};
-static const int8 kFlailTrooperBody_X[72] = {
-  -4, 4, 12, -4, 4, 13, -4, 4, 13, -4, 4, 13, -4, 4, 13, -4,
-  4, 13, 0, 0, 4, 0, 0, 5, 0, 0, 6, 0, 0, 4, -4, 4,
-  -6, -4, 4, -5, -4, 4, -5, -4, 4, -6, -4, 4, -5, -4, 4, -6,
-  0, 0, 4, 0, 0, 3, 0, 0, 2, 0, 0, 4, 0, 0, 0, 0,
-  0, 0, -4, 4, 4, -4, 4, 4,
-};
-static const int8 kFlailTrooperBody_Y[72] = {
-  0, 0, -4, 0, 0, -4, 0, 0, -3, 0, 0, -2, 0, 0, -3, 0,
-  0, -2, 0, 0, 1, 0, 0, 1, 0, 0, 2, 0, 0, 2, 0, 0,
-  -2, 0, 0, -2, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1,
-  0, 0, 1, 0, 0, 1, 0, 0, 2, 0, 0, 2, 0, 0, 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0,
-};
-static const uint8 kFlailTrooperBody_Char[72] = {
-  0x46, 6, 0x2f, 0x46, 6, 0x2f, 0x48, 0xd, 0x2f, 0x48, 0xd, 0x2f, 0x49, 0xc, 0x2f, 0x49,
-  0xc, 0x2f, 8, 8, 0x2f, 8, 8, 0x2f, 0x22, 0x22, 0x2f, 0x22, 0x22, 0x2f, 0xa, 0x64,
-  0x2f, 0xa, 0x64, 0x2f, 0x2c, 0x67, 0x2f, 0x2c, 0x67, 0x2f, 0x2d, 0x66, 0x2f, 0x2d, 0x66, 0x2f,
-  8, 8, 0x2f, 8, 8, 0x2f, 0x22, 0x22, 0x2f, 0x22, 0x22, 0x2f, 0x62, 0x62, 0x62, 0x62,
-  0x62, 0x62, 0x46, 0x4b, 0x4b, 0x69, 0x64, 0x64,
-};
-static const uint8 kFlailTrooperBody_Flags[72] = {
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x40, 0x40, 0, 0x40,
-  0x40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x40,
-  0x40, 0, 0x40, 0x40, 0, 0, 0x40, 0, 0, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
-  0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0,
-  0, 0, 0, 0x40, 0x40, 0, 0x40, 0x40,
-};
-static const uint8 kFlailTrooperBody_Big[72] = {
-  2, 2, 0, 2, 2, 0, 2, 2, 0, 2, 2, 0, 2, 2, 0, 2,
-  2, 0, 2, 2, 0, 2, 2, 0, 2, 2, 0, 2, 2, 0, 2, 2,
-  0, 2, 2, 0, 2, 2, 0, 2, 2, 0, 2, 2, 0, 2, 2, 0,
-  2, 2, 0, 2, 2, 0, 2, 2, 0, 2, 2, 0, 2, 2, 2, 2,
-  2, 2, 2, 2, 2, 2, 2, 2,
-};
-static const uint8 kFlailTrooperBody_Num[24] = {
-  2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-  2, 2, 2, 2, 1, 1, 1, 1,
-};
-static const uint8 kFlailTrooperBody_SprOffs[24] = {
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-  0, 0, 0, 0, 8, 8, 8, 8,
-};
-const uint16 kSinusLookupTable[256] = {
-  0, 3, 6, 9, 12, 15, 18, 21, 25, 28, 31, 34, 37, 40, 40, 46,
-  49, 53, 56, 59, 62, 65, 68, 71, 74, 77, 80, 83, 86, 89, 92, 95,
-  97, 100, 103, 106, 109, 112, 115, 117, 120, 123, 126, 128, 131, 134, 136, 139,
-  142, 144, 147, 149, 152, 155, 157, 159, 162, 164, 167, 169, 171, 174, 176, 178,
-  181, 183, 185, 187, 189, 191, 193, 195, 197, 199, 201, 203, 205, 207, 209, 211,
-  212, 214, 216, 217, 219, 221, 222, 224, 225, 227, 228, 230, 231, 232, 234, 235,
-  236, 237, 238, 239, 241, 242, 243, 244, 244, 245, 246, 247, 248, 249, 249, 250,
-  251, 251, 252, 252, 253, 253, 254, 254, 254, 255, 255, 255, 255, 255, 255, 255,
-  256, 255, 255, 255, 255, 255, 255, 255, 254, 254, 254, 253, 253, 252, 252, 251,
-  251, 250, 249, 249, 248, 247, 246, 245, 244, 244, 243, 242, 241, 239, 238, 237,
-  236, 235, 234, 232, 231, 230, 228, 227, 225, 224, 222, 221, 219, 217, 216, 214,
-  212, 211, 209, 207, 205, 203, 201, 199, 197, 195, 193, 191, 189, 187, 185, 183,
-  181, 178, 176, 174, 171, 169, 167, 164, 162, 159, 157, 155, 152, 149, 147, 144,
-  142, 139, 136, 134, 131, 128, 126, 123, 120, 117, 115, 112, 109, 106, 103, 100,
-  97, 95, 92, 89, 86, 83, 80, 77, 74, 71, 68, 65, 62, 59, 56, 53,
-  49, 46, 43, 40, 37, 34, 31, 28, 25, 21, 18, 15, 12, 9, 6, 3,
-};
-static const uint8 kFlailTrooperWeapon_Tab4[4] = {0x33, 0x66, 0x99, 0xcc};
-static const uint8 kFlailTrooperWeapon_Tab0[32] = {
-  0x10, 0x12, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e, 0x20, 0x22, 0x24, 0x26, 0x28, 0x2a, 0x2c, 0x2e,
-  0x30, 0x2e, 0x2c, 0x2a, 0x28, 0x26, 0x24, 0x22, 0x20, 0x1e, 0x1c, 0x1a, 0x18, 0x16, 0x14, 0x12,
-};
-static const int8 kFlailTrooperWeapon_Tab1[4] = {4, 4, 12, -5};
-static const int8 kFlailTrooperWeapon_Tab2[4] = {-2, -2, -6, -4};
-static const uint8 kFlailTrooperAttackDir[4] = {3, 1, 2, 0};
-static const uint8 kSprite_WarpVortex_Flags[4] = {0, 0x40, 0xc0, 0x80};
-static const int8 kSpriteRope_Gfx[8] = {0, 0, 2, 3, 2, 3, 1, 1};
-static const int8 kSpriteRope_Flags[8] = {0, 0x40, 0, 0, 0x40, 0x40, 0, 0x40};
-static const int8 kSpriteRope_Tab1[8] = {4, 5, 2, 3, 0, 1, 6, 7};
-static const int8 kSpriteRope_Xvel[8] = {8, -8, 0, 0, 16, -16, 0, 0};
-static const int8 kSpriteRope_Yvel[8] = {0, 0, 8, -8, 0, 0, 0x10, -0x10};
-static const int8 kSpriteRope_Tab0[4] = {2, 3, 1, 0};
-static const uint8 kSpawnBee_InitDelay[4] = {64, 64, 255, 255};
-static const int8 kSpawnBee_InitVel[8] = {15, 5, -5, -15, 20, 10, -10, -20};
-static const DrawMultipleData kLargeShadow_Dmd[15] = {
-  {-6, 19, 0x086c, 2},
-  { 0, 19, 0x086c, 2},
-  { 6, 19, 0x086c, 2},
-  {-5, 19, 0x086c, 2},
-  { 0, 19, 0x086c, 2},
-  { 5, 19, 0x086c, 2},
-  {-4, 19, 0x086c, 2},
-  { 0, 19, 0x086c, 2},
-  { 4, 19, 0x086c, 2},
-  {-3, 19, 0x086c, 2},
-  { 0, 19, 0x086c, 2},
-  { 3, 19, 0x086c, 2},
-  {-2, 19, 0x086c, 2},
-  { 0, 19, 0x086c, 2},
-  { 2, 19, 0x086c, 2},
-};
-static const uint8 kHelmasaur_Tab0[32] = {
-  0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 8, 8, 8, 8, 8, 8,
-  8, 8, 8, 8, 8, 8, 8, 8, 8, 7, 6, 5, 4, 3, 2, 1,
-};
-static const uint8 kFluteBoyAnimal_OamFlags[2] = {0x40, 0};
-static const uint8 kFluteBoyAnimal_Gfx[3] = {0, 1, 2};
-static const uint8 kGibo_OamFlags[4] = {0, 0x40, 0xc0, 0x80};
-static const uint8 kGibo_OamFlags2[2] = {11, 7};
-#define chainchomp_x_hist ((uint16*)(g_ram+0x1FC00))
-#define chainchomp_y_hist ((uint16*)(g_ram+0x1FD00))
-static const uint8 kBlindHead_Draw_Char[16] = {0x86, 0x86, 0x84, 0x82, 0x80, 0x82, 0x84, 0x86, 0x86, 0x86, 0x88, 0x8a, 0x8c, 0x8a, 0x88, 0x86};
-static const uint8 kBlindHead_Draw_Flags[16] = {0, 0, 0, 0, 0, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0, 0, 0, 0};
-static const uint8 kGanon_G_Func2[16] = { 8, 7, 6, 5, 4, 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, 1 };
-static const int8 kGanon_Draw_X[204] = {
-   18,  -8,   8, -8,   8, -18, -18, 18,  -8,   8,  -8,   8,  18,  -8,   8, -8,
-    8, -18, -18, 18,  -8,   8,  -8,  8,  16,  -8,   8,  -8,   8, -18, -18, 16,
-   -8,   8, -11, 11,  16,  -8,   8, -8,   8, -18, -18,  16,  -8,   8, -11, 11,
-   16,  -8,   8, -8,   8, -18, -18, 16,  -8,   8, -11,  11,  18,  -8,   8, -8,
-    8, -18, -18, 18,  -8,   8,  -8,  8,  18,  -8,   8,  -8,   8, -18, -18, 18,
-   -8,   8,  -8,  8,  18,  -8,   8, -8,   8, -18, -18,  18,  -8,   8, -11, 11,
-   -8,   8,  -8,  8,  -8,   8,  -8,  8, -18, -18,  18,  18,  -8,   8,  -8,  8,
-   -8,   8,  -8,  8, -18, -18,  18, 18,  -8,   8,  -8,   8,  -8,   8, -10, 10,
-  -18, -18,  18, 18,  -8,   8,  -8,  8,  -8,   8, -10,  10, -18, -18,  18, 18,
-   -8,   8,  -8,  8,  -8,   8, -10, 10, -18, -18,  18,  18,  -8,   8,  -8,  8,
-   -8,   8,  -8,  8, -18, -18,  18, 18,  -8,   8,  -8,   8,  -8,   8,  -8,  8,
-  -18, -18,  18, 18,  -7,  -8,   8, -8,   8,  -9,   8, -14, -14,  -8,   8,  8,
-   -8,   8,  -8,  8, -18, -18,  18, 18,  -8,   8, -11,  11,
-};
-static const int8 kGanon_Draw_Y[204] = {
-   -8, -16, -16, -13, -13,  -9,  -1, -16,   3,   3,   8,   8,  -8, -16, -16, -13,
-  -13,  -9,  -1, -16,   3,   3,   8,   8,   5, -10, -10, -13, -13,  -7,   1,  -3,
-    3,   3,   8,   8,   5, -10, -10, -13, -13,  -7,   1,  -3,   3,   3,   8,   8,
-    5, -10, -10, -13, -13,  -7,   1,  -3,   3,   3,   8,   8,  -1, -16, -16, -13,
-  -13,  -9,  -1,  -9,   3,   3,   8,   8, -10, -16, -16, -13, -13, -18, -10, -18,
-    3,   3,   8,   8,   1, -10, -10, -13, -13,  -7,   1,  -7,   3,   3,   8,   8,
-  -12, -12,   4,   4, -18, -18,  10,  10, -16,  -8,  -4,   4, -12, -12,   4,   4,
-  -18, -18,  10,  10, -16,  -8,  -4,   4, -12, -12,   4,   4, -12, -12,  10,  10,
-   -4,   4,  -4,   4, -12, -12,   4,   4, -12, -12,  10,  10,  -4,   4,  -4,   4,
-  -12, -12,   4,   4, -12, -12,  10,  10,  -4,   4,  -4,   4, -12, -12,   4,   4,
-  -18, -18,  10,  10,  -4,   4,  -4,   4, -12, -12,   4,   4, -18, -18,  10,  10,
-  -16,  -8, -16,  -8,  -7, -12, -12,   4,   4,   7,  13, -11,  -4, -16, -16, -16,
-  -10, -10, -13, -13,  -7,  -7,  -7,  -7,   3,   3,   8,   8,
-};
-static const uint8 kGanon_Draw_Char[204] = {
-  0x16,    0,    0,    2,    2,    8, 0x18,    6, 0x22, 0x22, 0x20, 0x20, 0x46,    0,    0,    2,
-     2,    8, 0x18, 0x36, 0x22, 0x22, 0x20, 0x20, 0x1a,    0,    0,    4,    4, 0x38, 0x48,  0xa,
-  0x24, 0x24, 0x20, 0x20, 0x1a, 0x40, 0x42,    4,    4, 0x38, 0x48,  0xa, 0x24, 0x24, 0x20, 0x20,
-  0x1a, 0x42, 0x40,    4,    4, 0x38, 0x48,  0xa, 0x24, 0x24, 0x20, 0x20, 0x18,    0,    0,    2,
-     2,    8, 0x18,    8, 0x22, 0x22, 0x20, 0x20, 0x16, 0x6a, 0x6a,  0xe,  0xe,    6, 0x16,    6,
-  0x22, 0x22, 0x20, 0x20, 0x48,    0,    0,    4,    4, 0x38, 0x48, 0x38, 0x24, 0x24, 0x20, 0x20,
-  0x4e, 0x4e, 0x6e, 0x6e, 0x6c, 0x6c, 0xa2, 0xa2,  0xc, 0x1c, 0x3c, 0x4c, 0x4e, 0x4e, 0x6e, 0x6e,
-  0x6c, 0x6c, 0xa2, 0xa2, 0x3a, 0x4a, 0x3c, 0x4c, 0x84, 0x84, 0xa4, 0xa4, 0xa0, 0xa0, 0xa2, 0xa2,
-  0x3c, 0x4c, 0x3c, 0x4c, 0x84, 0x84, 0xa4, 0xa4, 0x80, 0x82, 0xa2, 0xa2, 0x3c, 0x4c, 0x3c, 0x4c,
-  0x84, 0x84, 0xa4, 0xa4, 0x82, 0x80, 0xa2, 0xa2, 0x3c, 0x4c, 0x3c, 0x4c, 0x4e, 0x4e, 0x6e, 0x6e,
-  0x6c, 0x6c, 0xa2, 0xa2, 0x3c, 0x4c, 0x3c, 0x4c, 0x4e, 0x4e, 0x6e, 0x6e, 0x6c, 0x6c, 0xa2, 0xa2,
-   0xc, 0x1c,  0xc, 0x1c, 0xe0, 0xc6, 0xc8, 0xe6, 0xe8, 0x20, 0x20,    8, 0x18, 0xc0, 0xc2, 0xc2,
-     0,    0, 0xce, 0xce, 0xec, 0xec, 0xec, 0xec, 0xee, 0xee, 0xc4, 0xc4,
-};
-static const uint8 kGanon_Draw_Flags[204] = {
-  0x4c,  0xc, 0x4c,  0xa, 0x4a,  0xc,  0xc, 0x4c,  0xa, 0x4a,  0xc, 0x4c, 0x4c,  0xc, 0x4c,  0xa,
-  0x4a,  0xc,  0xc, 0x4c,  0xa, 0x4a,  0xc, 0x4c, 0x4c,  0xc, 0x4c,  0xa, 0x4a,  0xc,  0xc, 0x4c,
-   0xa, 0x4a,  0xc, 0x4c, 0x4c,  0xc,  0xc,  0xa, 0x4a,  0xc,  0xc, 0x4c,  0xa, 0x4a,  0xc, 0x4c,
-  0x4c, 0x4c, 0x4c,  0xa, 0x4a,  0xc,  0xc, 0x4c,  0xa, 0x4a,  0xc, 0x4c, 0x4c,  0xc, 0x4c,  0xa,
-  0x4a,  0xc,  0xc, 0x4c,  0xa, 0x4a,  0xc, 0x4c, 0x4c,  0xc, 0x4c,  0xa, 0x4a,  0xc,  0xc, 0x4c,
-   0xa, 0x4a,  0xc, 0x4c, 0x4c,  0xc, 0x4c,  0xa, 0x4a,  0xc,  0xc, 0x4c,  0xa, 0x4a,  0xc, 0x4c,
-   0xa, 0x4a,  0xa, 0x4a,  0xc, 0x4c,  0xc, 0x4c,  0xc,  0xc, 0x4c, 0x4c,  0xa, 0x4a,  0xa, 0x4a,
-   0xc, 0x4c,  0xc, 0x4c,  0xc,  0xc, 0x4c, 0x4c,  0xa, 0x4a,  0xa, 0x4a,  0xc, 0x4c,  0xc, 0x4c,
-   0xc,  0xc, 0x4c, 0x4c,  0xa, 0x4a,  0xa, 0x4a,  0xc,  0xc,  0xc, 0x4c,  0xc,  0xc, 0x4c, 0x4c,
-   0xa, 0x4a,  0xa, 0x4a, 0x4c, 0x4c,  0xc, 0x4c,  0xc,  0xc, 0x4c, 0x4c,  0xa, 0x4a,  0xa, 0x4a,
-   0xc, 0x4c,  0xc, 0x4c,  0xc,  0xc, 0x4c, 0x4c,  0xa, 0x4a,  0xa, 0x4a,  0xc, 0x4c,  0xc, 0x4c,
-   0xc,  0xc, 0x4c, 0x4c,  0xc,  0xa,  0xa,  0xa,  0xa,  0xc, 0x4c,  0xc,  0xc,  0xc,  0xc,  0xc,
-   0xc, 0x4c,  0xa, 0x4a,  0xc,  0xc, 0x4c, 0x4c,  0xa, 0x4a,  0xc, 0x4c,
-};
-static const uint8 kGanon_Draw_Char2[12] = { 0x40, 0x42, 0, 0, 0x42, 0x40, 0x82, 0x80, 0xa0, 0xa0, 0x80, 0x82 };
-static const uint8 kGanon_Draw_Flags2[12] = { 0, 0, 0, 0x40, 0x40, 0x40, 0x40, 0x40, 0, 0x40, 0, 0 };
-static HandlerFuncK *const kSpriteActiveRoutines[243] = {
-  &Sprite_Raven,
-  &Sprite_01_Vulture_bounce,
-  &Sprite_02_StalfosHead,
-  NULL,
-  &Sprite_PullSwitch_bounce,
-  &Sprite_PullSwitch_bounce,
-  &Sprite_PullSwitch_bounce,
-  &Sprite_PullSwitch_bounce,
-  &Sprite_08_Octorok,
-  &Sprite_09_GiantMoldorm,
-  &Sprite_08_Octorok,
-  &Sprite_0B_Cucco,
-  &Sprite_0C_OctorokStone,
-  &Sprite_0D_Buzzblob,
-  &Sprite_0E_Snapdragon,
-  &Sprite_0F_Octoballoon,
-  &Sprite_10_OctoballoonBaby,
-  &Sprite_11_Hinox,
-  &Sprite_12_Moblin,
-  &Sprite_13_MiniHelmasaur,
-  &Sprite_14_ThievesTownGrate,
-  &Sprite_15_Antifairy,
-  &Sprite_16_Elder_bounce,
-  &Sprite_17_Hoarder,
-  &Sprite_18_MiniMoldorm,
-  &Sprite_19_Poe,
-  &Sprite_1A_Smithy,
-  &Sprite_1B_Arrow,
-  &Sprite_1C_Statue,
-  &Sprite_1D_FluteQuest,
-  &Sprite_1E_CrystalSwitch,
-  &Sprite_1F_SickKid,
-  &Sprite_20_Sluggula,
-  &Sprite_21_WaterSwitch,
-  &Sprite_22_Ropa,
-  &Sprite_23_RedBari,
-  &Sprite_23_RedBari,
-  &Sprite_25_TalkingTree,
-  &Sprite_26_HardhatBeetle,
-  &Sprite_27_Deadrock,
-  &Sprite_28_DarkWorldHintNPC,
-  &Sprite_HumanMulti_1,
-  &Sprite_SweepingLady,
-  &Sprite_2B_Hobo,
-  &Sprite_Lumberjacks,
-  &Sprite_2D_TelepathicTile,
-  &Sprite_2E_FluteKid,
-  &Sprite_MazeGameLady,
-  &Sprite_MazeGameGuy,
-  &Sprite_FortuneTeller,
-  &Sprite_QuarrelBros,
-  &Sprite_33_RupeePull,
-  &Sprite_YoungSnitchLady,
-  &Sprite_InnKeeper,
-  &Sprite_Witch,
-  &Sprite_37_Waterfall,
-  &Sprite_38_EyeStatue,
-  &Sprite_39_Locksmith,
-  &Sprite_3A_MagicBat,
-  &Sprite_DashItem,
-  &Sprite_TroughBoy,
-  &Sprite_OldSnitchLady,
-  &Sprite_17_Hoarder,
-  &Sprite_TutorialGuardOrBarrier,
-  &Sprite_TutorialGuardOrBarrier,
-  // Trampoline 48 entries
-  &Sprite_41_BlueGuard,
-  &Sprite_41_BlueGuard,
-  &Sprite_41_BlueGuard,
-  &Sprite_44_BluesainBolt,
-  &Sprite_45_HogSpearMan,
-  &Sprite_46_BlueArcher,
-  &Sprite_47_GreenBushGuard,
-  &Sprite_48_RedJavelinGuard,
-  &Sprite_49_RedBushGuard,
-  &Sprite_4A_BombGuard,
-  &Sprite_4B_GreenKnifeGuard,
-  &Sprite_4C_Geldman,
-  &Sprite_4D_Toppo,
-  &Sprite_4E_Popo,
-  &Sprite_4E_Popo,
-  &Sprite_50_Cannonball,
-  &Sprite_51_ArmosStatue,
-  &Sprite_52_KingZora,
-  &Sprite_53_ArmosKnight,
-  &Sprite_54_Lanmolas,
-  &Sprite_55_Zora,
-  &Sprite_56_WalkingZora,
-  &Sprite_57_DesertStatue,
-  &Sprite_58_Crab,
-  &Sprite_59_LostWoodsBird,
-  &Sprite_5A_LostWoodsSquirrel,
-  &Sprite_5B_Spark_Clockwise,
-  &Sprite_5B_Spark_Clockwise,
-  &Sprite_5D_Roller_VerticalDownFirst,
-  &Sprite_5D_Roller_VerticalDownFirst,
-  &Sprite_5D_Roller_VerticalDownFirst,
-  &Sprite_5D_Roller_VerticalDownFirst,
-  &Sprite_61_Beamos,
-  &Sprite_62_MasterSword,
-  &Sprite_63_DebirandoPit,
-  &Sprite_64_Debirando,
-  &Sprite_65_ArcheryGame,
-  &Sprite_66_WallCannonVerticalLeft,
-  &Sprite_66_WallCannonVerticalLeft,
-  &Sprite_66_WallCannonVerticalLeft,
-  &Sprite_66_WallCannonVerticalLeft,
-  &Sprite_6A_BallNChain,
-  &Sprite_6B_CannonTrooper,
-  &Sprite_6C_MirrorPortal,
-  &Sprite_6D_Rat,
-  &Sprite_6E_Rope,
-  &Sprite_6F_Keese,
-  &Sprite_70_KingHelmasaurFireball,
-  &Sprite_71_Leever,
-  &Sprite_72_FairyPond,
-  &Sprite_73_UncleAndPriest,
-  &Sprite_RunningMan,
-  &Sprite_BottleVendor,
-  &Sprite_76_Zelda,
-  &Sprite_15_Antifairy,
-  &Sprite_78_MrsSahasrahla,
-  // Trampoline 68 entries
-  &Sprite_79_Bee,
-  &Sprite_7A_Agahnim,
-  &Sprite_7B_AgahnimBalls,
-  &Sprite_7C_GreenStalfos,
-  &Sprite_7D_BigSpike,
-  &Sprite_7E_Firebar_Clockwise,
-  &Sprite_7E_Firebar_Clockwise,
-  &Sprite_80_Firesnake,
-  &Sprite_81_Hover,
-  &Sprite_82_AntifairyCircle,
-  &Sprite_83_GreenEyegore,
-  &Sprite_83_GreenEyegore,
-  &Sprite_85_YellowStalfos,
-  &Sprite_86_Kodongo,
-  &Sprite_87_KodongoFire,
-  &Sprite_88_Mothula,
-  &Sprite_89_MothulaBeam,
-  &Sprite_8A_SpikeBlock,
-  &Sprite_8B_Gibdo,
-  &Sprite_8C_Arrghus,
-  &Sprite_8D_Arrghi,
-  &Sprite_8E_Terrorpin,
-  &Sprite_8F_Blob,
-  &Sprite_90_Wallmaster,
-  &Sprite_91_StalfosKnight,
-  &Sprite_92_HelmasaurKing,
-  &Sprite_93_Bumper,
-  &Sprite_94_Pirogusu,
-  &Sprite_95_LaserEyeLeft,
-  &Sprite_95_LaserEyeLeft,
-  &Sprite_95_LaserEyeLeft,
-  &Sprite_95_LaserEyeLeft,
-  &Sprite_99_Pengator,
-  &Sprite_9A_Kyameron,
-  &Sprite_9B_Wizzrobe,
-  &Sprite_9C_Zoro,
-  &Sprite_9C_Zoro,
-  &Sprite_9E_HauntedGroveOstritch,
-  &Sprite_9F_HauntedGroveRabbit,
-  &Sprite_A0_HauntedGroveBird,
-  &Sprite_A1_Freezor,
-  &Sprite_A2_Kholdstare,
-  &Sprite_A3_KholdstareShell,
-  &Sprite_A4_FallingIce,
-  &Sprite_Zazak_Main,
-  &Sprite_Zazak_Main,
-  &Sprite_A7_Stalfos,
-  &Sprite_A8_GreenZirro,
-  &Sprite_A8_GreenZirro,
-  &Sprite_AA_Pikit,
-  &Sprite_AB_CrystalMaiden,
-  &Sprite_AC_Apple,
-  &Sprite_AD_OldMan,
-  &Sprite_AE_Pipe_Down,
-  &Sprite_AE_Pipe_Down,
-  &Sprite_AE_Pipe_Down,
-  &Sprite_AE_Pipe_Down,
-  &Sprite_B2_PlayerBee,
-  &Sprite_B3_PedestalPlaque,
-  &Sprite_B4_PurpleChest,
-  &Sprite_B5_BombShop,
-  &Sprite_B6_Kiki,
-  &Sprite_B7_BlindMaiden,
-  &Sprite_B8_DialogueTester,
-  &Sprite_B9_BullyAndPinkBall,
-  &Sprite_BA_Whirlpool,
-  &Sprite_BB_Shopkeeper,
-  &Sprite_BC_Drunkard,
-  // Trampoline 4, starts at 187, 27 entries
-  &Sprite_BD_Vitreous,
-  &Sprite_BE_VitreousEye,
-  &Sprite_BF_Lightning,
-  &Sprite_C0_Catfish,
-  &Sprite_C1_CutsceneAgahnim,
-  &Sprite_C2_Boulder,
-  &Sprite_C3_Gibo,
-  &Sprite_C4_Thief,
-  &Sprite_C5_Medusa,
-  &Sprite_C6_4WayShooter,
-  &Sprite_C7_Pokey,
-  &Sprite_C8_BigFairy,
-  &Sprite_C9_Tektite,
-  &Sprite_CA_ChainChomp,
-  &Sprite_CB_TrinexxRockHead,
-  &Sprite_CC,
-  &Sprite_CD,
-  &Sprite_CE_Blind,
-  &Sprite_CF_Swamola,
-  &Sprite_D0_Lynel,
-  &Sprite_D1_BunnyBeam,
-  &Sprite_D2_FloppingFish,
-  &Sprite_D3_Stal,
-  &Sprite_D4_Landmine,
-  &Sprite_D5_DigGameGuy,
-  &Sprite_D6_Ganon,
-  &Sprite_D6_Ganon,
-  &Sprite_D8_Heart,
-  &Sprite_D9_GreenRupee,
-  &Sprite_D9_GreenRupee,
-  &Sprite_D9_GreenRupee,
-  &Sprite_D9_GreenRupee,
-  &Sprite_D9_GreenRupee,
-  &Sprite_D9_GreenRupee,
-  &Sprite_D9_GreenRupee,
-  &Sprite_D9_GreenRupee,
-  &Sprite_D9_GreenRupee,
-  &Sprite_D9_GreenRupee,
-  &Sprite_E3_Fairy,
-  &Sprite_E4_SmallKey,
-  &Sprite_E4_SmallKey,
-  &Sprite_D9_GreenRupee,
-  &Sprite_E7_Mushroom,
-  &Sprite_E8_FakeSword,
-  &Sprite_E9_PotionShop,
-  &Sprite_HeartContainer,
-  &Sprite_HeartPiece,
-  &Sprite_EC_ThrownItem,
-  &Sprite_ED_SomariaPlatform,
-  &Sprite_EE_MovableMantle,
-  &Sprite_ED_SomariaPlatform,
-  &Sprite_ED_SomariaPlatform,
-  &Sprite_ED_SomariaPlatform,
-  &Sprite_F2_MedallionTablet,
-};
-static HandlerFuncK *const kSpritePrep_Main[243] = {
-  &SpritePrep_Raven,
-  &SpritePrep_Vulture,
-  &SpritePrep_DoNothingA,
-  NULL,
-  &SpritePrep_Switch,
-  &SpritePrep_DoNothingA,
-  &SpritePrep_Switch,
-  &SpritePrep_SwitchFacingUp,
-  &SpritePrep_Octorok,
-  &SpritePrep_Moldorm,
-  &SpritePrep_Octorok,
-  &SpritePrep_DoNothingA,
-  &SpritePrep_DoNothingA,
-  &SpritePrep_DoNothingA,
-  &SpritePrep_DoNothingA,
-  &SpritePrep_Octoballoon,
-  &SpritePrep_DoNothingA,
-  &SpritePrep_DoNothingA,
-  &SpritePrep_DoNothingA,
-  &SpritePrep_MiniHelmasaur,
-  &SpritePrep_ThievesTownGrate,
-  &SpritePrep_Antifairy,
-  &SpritePrep_Sage,
-  &SpritePrep_DoNothingA,
-  &SpritePrep_MiniMoldorm_bounce,
-  &SpritePrep_Poe,
-  &SpritePrep_Smithy,
-  &SpritePrep_DoNothingA,
-  &SpritePrep_Statue,
-  &SpritePrep_IgnoreProjectiles,
-  &SpritePrep_CrystalSwitch,
-  &SpritePrep_SickKid,
-  &SpritePrep_DoNothingA,
-  &SpritePrep_WaterLever,
-  &SpritePrep_DoNothingA,
-  &SpritePrep_Bari,
-  &SpritePrep_Bari,
-  &SpritePrep_TalkingTree,
-  &SpritePrep_HardhatBeetle,
-  &SpritePrep_DoNothingA,
-  &SpritePrep_Storyteller,
-  &SpritePrep_Adults,
-  &SpritePrep_IgnoreProjectiles,
-  &SpritePrep_Hobo,
-  &SpritePrep_MagicBat,
-  &SpritePrep_IgnoreProjectiles,
-  &SpritePrep_FluteKid,
-  &SpritePrep_IgnoreProjectiles,
-  &SpritePrep_IgnoreProjectiles,
-  &SpritePrep_FortuneTeller,
-  &SpritePrep_IgnoreProjectiles,
-  &SpritePrep_RupeePull,
-  &SpritePrep_Snitch_bounce_2,
-  &SpritePrep_Snitch_bounce_3,
-  &SpritePrep_IgnoreProjectiles,
-  &SpritePrep_IgnoreProjectiles,
-  &SpritePrep_DoNothingA,
-  &SpritePrep_Locksmith,
-  &SpritePrep_MagicBat,
-  &SpritePrep_BonkItem,
-  &SpritePrep_IgnoreProjectiles,
-  &SpritePrep_Snitch_bounce_1,
-  &SpritePrep_DoNothingA,
-  &SpritePrep_DoNothingA,
-  &SpritePrep_AgahnimsBarrier,
-  &SpritePrep_StandardGuard,
-  &SpritePrep_StandardGuard,
-  &SpritePrep_StandardGuard,
-  &SpritePrep_TrooperAndArcherSoldier,
-  &SpritePrep_TrooperAndArcherSoldier,
-  &SpritePrep_TrooperAndArcherSoldier,
-  &SpritePrep_TrooperAndArcherSoldier,
-  &SpritePrep_TrooperAndArcherSoldier,
-  &SpritePrep_TrooperAndArcherSoldier,
-  &SpritePrep_TrooperAndArcherSoldier,
-  &SpritePrep_WeakGuard,
-  &SpritePrep_Geldman,
-  &SpritePrep_Kyameron,
-  &SpritePrep_Popo,
-  &SpritePrep_Popo2,
-  &SpritePrep_DoNothingA,
-  &SpritePrep_DoNothingD,
-  &SpritePrep_KingZora,
-  &SpritePrep_ArmosKnight,
-  &SpritePrep_Lanmolas,
-  &SpritePrep_SwimmingZora,
-  &SpritePrep_WalkingZora,
-  &SpritePrep_DesertStatue,
-  &SpritePrep_DoNothingA,
-  &SpritePrep_LostWoodsBird,
-  &SpritePrep_LostWoodsSquirrel,
-  &SpritePrep_Spark,
-  &SpritePrep_Spark,
-  &SpritePrep_Roller_VerticalDownFirst,
-  &SpritePrep_RollerUpDown,
-  &SpritePrep_Roller_HorizontalRightFirst,
-  &SpritePrep_RollerLeftRight,
-  &SpritePrep_DoNothingA,
-  &SpritePrep_MasterSword,
-  &SpritePrep_DebirandoPit,
-  &SpritePrep_FireDebirando,
-  &SpritePrep_ArrowGame_bounce,
-  &SpritePrep_WallCannon,
-  &SpritePrep_WallCannon,
-  &SpritePrep_WallCannon,
-  &SpritePrep_WallCannon,
-  &SpritePrep_DoNothingA,
-  &SpritePrep_DoNothingA,
-  &SpritePrep_DoNothingA,
-  &SpritePrep_Rat,
-  &SpritePrep_Rope,
-  &SpritePrep_Keese,
-  &SpritePrep_DoNothingG,
-  &SpritePrep_FairyPond,
-  &SpritePrep_IgnoreProjectiles,
-  &SpritePrep_UncleAndPriest_bounce,
-  &SpritePrep_RunningMan,
-  &SpritePrep_IgnoreProjectiles,
-  &SpritePrep_Zelda_bounce,
-  &SpritePrep_Antifairy,
-  &SpritePrep_MrsSahasrahla,
-  &SpritePrep_OverworldBonkItem,
-  &SpritePrep_Agahnim,
-  &SpritePrep_DoNothingG,
-  &SpritePrep_GreenStalfos,
-  &SpritePrep_BigSpike,
-  &SpritePrep_FireBar,
-  &SpritePrep_FireBar,
-  &SpritePrep_DoNothingG,
-  &SpritePrep_DoNothingG,
-  &SpritePrep_AntifairyCircle,
-  &SpritePrep_Eyegore,
-  &SpritePrep_Eyegore,
-  &SpritePrep_DoNothingG,
-  &SpritePrep_Kodongo,
-  &SpritePrep_DoNothingG,
-  &SpritePrep_Mothula,
-  &SpritePrep_DoNothingG,
-  &SpritePrep_Spike,
-  &SpritePrep_DoNothingG,
-  &SpritePrep_Arrghus,
-  &SpritePrep_Arrghi,
-  &SpritePrep_DoNothingG,
-  &SpritePrep_Blob,
-  &SpritePrep_DoNothingG,
-  &SpritePrep_DoNothingG,
-  &SpritePrep_HelmasaurKing,
-  &SpritePrep_Bumper,
-  &SpritePrep_DoNothingA,
-  &SpritePrep_LaserEye_bounce,
-  &SpritePrep_LaserEye_bounce,
-  &SpritePrep_LaserEye_bounce,
-  &SpritePrep_LaserEye_bounce,
-  &SpritePrep_DoNothingA,
-  &SpritePrep_Kyameron,
-  &SpritePrep_DoNothingA,
-  &SpritePrep_Zoro,
-  &SpritePrep_Babasu,
-  &SpritePrep_HauntedGroveOstritch,
-  &SpritePrep_HauntedGroveAnimal,
-  &SpritePrep_HauntedGroveAnimal,
-  &SpritePrep_MoveDown_8px,
-  &SpritePrep_Kholdstare,
-  &SpritePrep_KholdstareShell,
-  &SpritePrep_FallingIce,
-  &SpritePrep_Zazakku,
-  &SpritePrep_Zazakku,
-  &SpritePrep_Stalfos,
-  &SpritePrep_Bomber,
-  &SpritePrep_Bomber,
-  &SpritePrep_DoNothingC,
-  &SpritePrep_DoNothingH,
-  &SpritePrep_OverworldBonkItem,
-  &SpritePrep_OldMan_bounce,
-  &SpritePrep_DoNothingA,
-  &SpritePrep_DoNothingA,
-  &SpritePrep_DoNothingA,
-  &SpritePrep_DoNothingA,
-  &SpritePrep_NiceBee,
-  &SpritePrep_PedestalPlaque,
-  &SpritePrep_PurpleChest,
-  &SpritePrep_BombShoppe,
-  &SpritePrep_Kiki,
-  &SpritePrep_BlindMaiden,
-  &SpritePrep_DoNothingA,
-  &SpritePrep_BullyAndVictim,
-  &SpritePrep_Whirlpool,
-  &SpritePrep_Shopkeeper,
-  &SpritePrep_IgnoreProjectiles,
-  &SpritePrep_Vitreous,
-  &SpritePrep_MiniVitreous,
-  &SpritePrep_DoNothingA,
-  &SpritePrep_Catfish,
-  &SpritePrep_CutsceneAgahnim,
-  &SpritePrep_DoNothingA,
-  &SpritePrep_Gibo,
-  &SpritePrep_DoNothingA,
-  &SpritePrep_IgnoreProjectiles,
-  &SpritePrep_IgnoreProjectiles,
-  &SpritePrep_Pokey,
-  &SpritePrep_BigFairy,
-  &SpritePrep_Tektite,
-  &SpritePrep_Chainchomp_bounce,
-  &SpritePrep_Trinexx,
-  &SpritePrep_Trinexx,
-  &SpritePrep_Trinexx,
-  &SpritePrep_Blind,
-  &SpritePrep_Swamola,
-  &SpritePrep_DoNothingA,
-  &SpritePrep_DoNothingA,
-  &SpritePrep_IgnoreProjectiles,
-  &SpritePrep_RockStal,
-  &SpritePrep_IgnoreProjectiles,
-  &SpritePrep_DiggingGameGuy_bounce,
-  &SpritePrep_Ganon,
-  &SpritePrep_Ganon,
-  &SpritePrep_Absorbable,
-  &SpritePrep_Absorbable,
-  &SpritePrep_Absorbable,
-  &SpritePrep_Absorbable,
-  &SpritePrep_Absorbable,
-  &SpritePrep_Absorbable,
-  &SpritePrep_Absorbable,
-  &SpritePrep_Absorbable,
-  &SpritePrep_Absorbable,
-  &SpritePrep_Absorbable,
-  &SpritePrep_Absorbable,
-  &SpritePrep_Fairy,
-  &SpritePrep_SmallKey,
-  &SpritePrep_BigKey,
-  &SpritePrep_ShieldPickup,
-  &SpritePrep_Mushroom,
-  &SpritePrep_FakeSword,
-  &SpritePrep_PotionShop,
-  &SpritePrep_HeartContainer,
-  &SpritePrep_HeartPiece,
-  &SpritePrep_ThrowableScenery,
-  &SpritePrep_DoNothingA,
-  &SpritePrep_Mantle,
-  &SpritePrep_DoNothingA,
-  &SpritePrep_DoNothingA,
-  &SpritePrep_DoNothingA,
-  &SpritePrep_MedallionTable,
-};
-
-void Sprite_PullSwitch_bounce(int k) {
-  if (sprite_type[k] == 5 || sprite_type[k] == 7)
-    PullSwitch_FacingUp(k);
-  else
-    PullSwitch_FacingDown(k);
-}
-
-void GiantMoldorm_DrawSegment_AB(int k, int lookback) {
-  static const DrawMultipleData kGiantMoldorm_SegA_Dmd[8] = {
-    {-8, -8, 0x0084, 2},
-    { 8, -8, 0x0086, 2},
-    {-8,  8, 0x00a4, 2},
-    { 8,  8, 0x00a6, 2},
-    {-8, -8, 0x4086, 2},
-    { 8, -8, 0x4084, 2},
-    {-8,  8, 0x40a6, 2},
-    { 8,  8, 0x40a4, 2},
-  };
-  int j = sprite_subtype2[k] - lookback & 0x7f;
-  cur_sprite_x = moldorm_x_lo[j] | moldorm_x_hi[j] << 8;
-  cur_sprite_y = moldorm_y_lo[j] | moldorm_y_hi[j] << 8;
-  oam_cur_ptr += 0x10;
-  oam_ext_cur_ptr += 4;
-  Sprite_DrawMultiple(k, &kGiantMoldorm_SegA_Dmd[(sprite_subtype2[k] >> 1 & 1) * 4], 4, NULL);
-}
-
-void GiantMoldorm_DrawSegment_C_OrTail(int k, int lookback) {
-  static const uint8 kGiantMoldorm_OamFlags[4] = {0, 0x40, 0xc0, 0x80};
-  int j = sprite_subtype2[k] - lookback & 0x7f;
-  cur_sprite_x = moldorm_x_lo[j] | moldorm_x_hi[j] << 8;
-  cur_sprite_y = moldorm_y_lo[j] | moldorm_y_hi[j] << 8;
-  uint8 bak = sprite_oam_flags[k];
-  sprite_oam_flags[k] = (bak & 0x3f) | kGiantMoldorm_OamFlags[sprite_subtype2[k] >> 1 & 3];
-  SpriteDraw_SingleLarge(k);
-  sprite_oam_flags[k] = bak;
-}
-
-void Chicken_IncrSubtype2(int k, int j) {
-  sprite_subtype2[k] += j;
-  sprite_graphics[k] = (sprite_subtype2[k] >> 4) & 1;
-  Sprite_ReturnIfLifted(k);
-}
-
-bool Octoballoon_Find() {
-  for (int i = 15; i >= 0; i--) {
-    if (sprite_state[i] && sprite_type[i] == 0x10)
-      return true;
-  }
-  return false;
-}
-
-bool FluteBoy_CheckIfPlayerClose(int k) {
-  int xx = Sprite_GetX(k);
-  int yy = Sprite_GetY(k) - 16;
-  int x = link_x_coord - xx - (yy < 0); // zelda bug: carry
-  int y = link_y_coord - yy - (x < 0);
-  if (sign16(x)) x = ~x;
-  if (sign16(y)) y = ~y;
-  return (uint16)x < 48 && (uint16)y < 48;
-}
-
-void FortuneTeller_LightOrDarkWorld(int k, bool dark_world) {
-  int j;
-  static const uint8 kFortuneTeller_Prices[4] = {10, 15, 20, 30};
-
-  switch (sprite_ai_state[k]) {
-  case 0:  // WaitForInquiry
-    sprite_graphics[k] = 0;
-    sprite_A[k] = (j = (GetRandomNumber() & 3)) << 1;
-    if (link_rupees_goal < kFortuneTeller_Prices[j])
-      sprite_ai_state[k] = 1;
-    else
-      sprite_ai_state[k] = 2;
-    break;
-  case 1: // NotEnoughRupees
-    Sprite_ShowSolicitedMessage(k, 0xf2);
-    break;
-  case 2:  // AskIfPlayerWantsReading
-    if (Sprite_ShowSolicitedMessage(k, 0xf3) & 0x100) {
-      sprite_delay_main[k] = 255;
-      flag_is_link_immobilized = 1;
-      sprite_ai_state[k]=3;
-    }
-    break;
-  case 3: // ReactToPlayerResponse
-    if (!choice_in_multiselect_box) {
-      if (!sprite_delay_main[k])
-        sprite_ai_state[k]++;
-      sprite_graphics[k] = frame_counter >> 4 & 1;
-    } else {
-      Sprite_ShowMessageUnconditional(0xf5);
-      sprite_ai_state[k] = 2;
-      flag_is_link_immobilized = 0;
-    }
-    break;
-  case 4: // FortuneTeller_PerformPseudoScience
-    FortuneTeller_PerformPseudoScience(k);
-    break;
-  case 5:  // ShowCostMessage
-    if (!dark_world)
-      sprite_graphics[k] = 0;
-    j = kFortuneTeller_Prices[sprite_A[k]>>1];
-    dialogue_number[0] = (j / 10) | (j % 10)<< 4 ;
-    dialogue_number[1] = 0;
-    Sprite_ShowMessageUnconditional(0xf4);
-    sprite_ai_state[k]++;
-    break;
-  case 6:  // DeductPayment
-    link_rupees_goal -= kFortuneTeller_Prices[sprite_A[k]>>1];
-    sprite_ai_state[k]++;
-    link_hearts_filler = 160;
-    flag_is_link_immobilized = 0;
-    break;
-  case 7:
-    break;
-  }
-}
-
-int GarnishAllocForce() {
-  int k = 29;
-  while (garnish_type[k--] && k >= 0) {}
-  return k + 1;
-}
-
-int GarnishAlloc() {
-  int k = 29;
-  while (garnish_type[k] && k >= 0) k--;
-  return k;
-}
-
-int GarnishAllocLow() {
-  int k = 14;
-  while (garnish_type[k] && k >= 0) k--;
-  return k;
-}
-
-int GarnishAllocLimit(int k) {
-  while (garnish_type[k] && k >= 0) k--;
-  return k;
-}
-
-int GarnishAllocOverwriteOldLow() {
-  int k = 14;
-  while (garnish_type[k] && k >= 0) k--;
-  if (k < 0) {
-    if (sign8(--byte_7E0FF8))
-      byte_7E0FF8 = 14;
-    k = byte_7E0FF8;
-  }
-  return k;
-}
-
-int GarnishAllocOverwriteOld() {
-  int k = 29;
-  while (garnish_type[k] && k >= 0) k--;
-  if (k < 0) {
-    if (sign8(--byte_7E0FF8))
-      byte_7E0FF8 = 29;
-    k = byte_7E0FF8;
-  }
-  return k;
-}
-
-void Garnish_SetX(int k, uint16 x) {
-  garnish_x_lo[k] = x;
-  garnish_x_hi[k] = x >> 8;
-}
-
-void Garnish_SetY(int k, uint16 y) {
-  garnish_y_lo[k] = y;
-  garnish_y_hi[k] = y >> 8;
-}
-
-void Sprite_WishPond3(int k) {
-  int j;
-
-  switch (sprite_ai_state[k]) {
-  case 0:
-    flag_is_link_immobilized = 0;
-    if (sprite_delay_main[k] || Sprite_CheckIfLinkIsBusy())
-      return;
-    if (Sprite_ShowMessageOnContact(k, 0x14a) & 0x100) {
-      sprite_ai_state[k] = 1;
-      Link_ResetProperties_A();
-      link_direction_facing = 0;
-      sprite_head_dir[k] = 0;
-    }
-    break;
-  case 1:
-    if (!choice_in_multiselect_box) {
-      Sprite_ShowMessageUnconditional(0x8a);
-      sprite_ai_state[k] = 2;
-      flag_is_link_immobilized = 1;
-    } else {
-      Sprite_ShowMessageUnconditional(0x14b);
-      sprite_ai_state[k] = 0;
-      sprite_delay_main[k] = 255;
-    }
-    break;
-  case 2: {
-    sprite_ai_state[k] = 3;
-    j = choice_in_multiselect_box;
-    sprite_C[k] = j;
-    uint8 item = (&link_item_bow)[j];
-    (&link_item_bow)[j] = 0;
-    uint8 t = kWishPondItemData[kWishPondItemOffs[j] + ((j == 3 || j == 32) ? 1 : item) - 1];
-    AncillaAdd_TossedPondItem(0x28, t, 4);
-    Hud_RefreshIcon();
-    sprite_graphics[k] = t;
-    sprite_D[k] = item;
-    sprite_delay_main[k] = 255;
-    break;
-  }
-  case 3:
-    if (sprite_delay_main[k] == 0) {
-      SpriteSpawnInfo info;
-      int j = Sprite_SpawnDynamically(k, 0x72, &info);
-      assert(j >= 0);
-      Sprite_SetX(j, info.r0_x);
-      Sprite_SetY(j, info.r2_y - 80);
-      music_control = 0x1b;
-      last_music_control = 0;
-      sprite_B[j] = 1;
-      Palette_AssertTranslucencySwap();
-      PaletteFilter_WishPonds();
-      sprite_E[k] = j;
-      sprite_ai_state[k] = 4;
-      sprite_delay_main[k] = 255;
-    }
-    break;
-  case 4:
-    if (!(frame_counter & 7)) {
-      PaletteFilter_SP5F();
-      if (!BYTE(palette_filter_countdown)) {
-        Sprite_ShowMessageUnconditional(0x8b);
-        Palette_RevertTranslucencySwap();
-        TS_copy = 0;
-        CGADSUB_copy = 0x20;
-        flag_update_cgram_in_nmi++;
-        sprite_ai_state[k] = 5;
-      }
-    }
-    break;
-  case 5:
-    if (!choice_in_multiselect_box) {
-      sprite_ai_state[k] = 6;
-    } else {
-      sprite_ai_state[k] = 11;
-    }
-    break;
-  case 6:
-    sprite_ai_state[k] = 7;
-    if (!savegame_is_darkworld) {
-      if (sprite_graphics[k] == 12) {
-        sprite_graphics[k] = 42;
-        sprite_head_dir[k] = 1;
-      } else if (sprite_graphics[k] == 4) {
-        sprite_graphics[k] = 5;
-        sprite_head_dir[k] = 2;
-      } else if (sprite_graphics[k] == 22) {
-        sprite_graphics[k] = 44;
-        sprite_head_dir[k] = 3;
-      } else {
-        Sprite_ShowMessageUnconditional(0x14d);
-        return;
-      }
-    } else {
-      if (sprite_graphics[k] == 58) {
-        sprite_graphics[k] = 59;
-        sprite_head_dir[k] = 4;
-        Sprite_ShowMessageUnconditional(0x14f);
-        return;
-      } else if (sprite_graphics[k] == 2) {
-        sprite_graphics[k] = 3;
-        sprite_head_dir[k] = 5;
-      } else if (sprite_graphics[k] == 22) {
-        sprite_graphics[k] = 44;
-        sprite_head_dir[k] = 3;
-      } else {
-        Sprite_ShowMessageUnconditional(0x14d);
-        return;
-      }
-    }
-    Sprite_ShowMessageUnconditional(0x8c);
-    break;
-  case 7:
-    if (sprite_C[k] == 3)
-      (&link_item_bow)[sprite_C[k]] = sprite_D[k];
-    Palette_AssertTranslucencySwap();
-    TS_copy = 2;
-    CGADSUB_copy = 0x30;
-    flag_update_cgram_in_nmi++;
-    sprite_ai_state[k] = 8;
-    break;
-  case 8:
-    if (!(frame_counter & 7)) {
-      PaletteFilter_SP5F();
-      if (BYTE(palette_filter_countdown) == 30) {
-        sprite_state[sprite_E[k]] = 0;
-      } else if (BYTE(palette_filter_countdown) == 0) {
-        sprite_ai_state[k] = 9;
-      }
-    }
-    break;
-  case 9:
-    PaletteFilter_RestoreSP5F();
-    Palette_RevertTranslucencySwap();
-    item_receipt_method = 2;
-    Link_ReceiveItem(sprite_graphics[k], 0);
-    sprite_ai_state[k] = 10;
-    break;
-  case 10: {
-    static const uint8 kWishPondMsgs[5] = { 0x8f, 0x90, 0x92, 0x91, 0x93 };
-    if (sprite_head_dir[k])
-      Sprite_ShowMessageUnconditional(kWishPondMsgs[sprite_head_dir[k] - 1]);
-    sprite_ai_state[k] = 0;
-    sprite_delay_main[k] = 255;
-    break;
-  }
-  case 11:
-    Sprite_ShowMessageUnconditional(0x8d);
-    sprite_ai_state[k] = 12;
-    break;
-  case 12:
-    if (!choice_in_multiselect_box)
-      sprite_ai_state[k] = 13;
-    else
-      sprite_ai_state[k] = 6;
-    break;
-  case 13:
-    Sprite_ShowMessageUnconditional(0x8e);
-    sprite_ai_state[k] = 7;
-    break;
-  }
-}
-
-int Sprite_SpawnSmallSplash(int k) {
-  SpriteSpawnInfo info;
-  int j = Sprite_SpawnDynamicallyEx(k, 0xec, &info, 14);
-  if (j >= 0) {
-    Sprite_SetSpawnedCoordinates(j, &info);
-    sound_effect_1 = 0;
-    SpriteSfx_QueueSfx2WithPan(k, 0x28);
-    sprite_state[j] = 3;
-    sprite_delay_main[j] = 15;
-    sprite_ai_state[j] = 0;
-    sprite_flags2[j] = 3;
-  }
-  return j;
-}
-
-void HeartUpgrade_CheckIfAlreadyObtained(int k) {
-  if (!player_is_indoors) {
-    if (BYTE(overworld_screen_index) == 0x3b && !(save_ow_event_info[0x3b] & 0x20) ||
-      save_ow_event_info[BYTE(overworld_screen_index)] & 0x40)
-      sprite_state[k] = 0;
-  } else {
-    int j = sprite_x_hi[k] & 1;
-    if (dung_savegame_state_bits & (j ? 0x2000 : 0x4000))
-      sprite_state[k] = 0;
-  }
-}
-
-void Sprite_EE_MovableMantle(int k) {
-  MovableMantle_Draw(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  if (!Sprite_CheckDamageToLink_same_layer(k))
-    return;
-  Sprite_NullifyHookshotDrag();
-  Sprite_RepelDash();
-
-  if (follower_indicator != 1 || !link_item_torch || link_is_running || sprite_G[k] == 0x90 || sign8(link_actual_vel_x - 24))
-    return;
-
-  which_starting_point = 4;
-  sprite_subtype2[k]++;
-
-  if (!(sprite_subtype2[k] & 1))
-    sprite_G[k]++;
-
-  if (sprite_G[k] < 8)
-    return;
-  if (sound_effect_1 == 0)
-    sound_effect_1 = 34;
-  sprite_x_vel[k] = 2;
-  Sprite_MoveXY(k);
-}
-
-void Sprite_GoodOrBadArcheryTarget(int k) {
-  static const uint8 kArcheryGame_CashPrize[10] = {4, 8, 16, 32, 64, 99, 99, 99, 99, 99};
-  if (sprite_A[k] == 1) {
-    // good target
-    if (sprite_G[k] >= 5)
-      sprite_B[k] = 6;
-    sprite_flags2[k] &= ~0x1f;
-    int j = sprite_delay_aux2[k] ? sprite_delay_aux2[k] : (sprite_subtype2[k] >> 3);
-    sprite_oam_flags[k] = sprite_oam_flags[k] & ~0x40 | (j & 4) << 4;
-    BYTE(cur_sprite_y) -= 3;
-    SpriteDraw_SingleLarge(k);
-    if (sprite_delay_aux2[k]) {
-      if (sprite_delay_aux2[k] == 96 && !submodule_index) {
-        sprite_delay_main[0] = 112;
-        link_rupees_goal += kArcheryGame_CashPrize[sprite_B[k] - 1];
-      }
-      sprite_flags2[k] |= 5;
-      ArcheryGame_DrawPrize(k);
-    }
-  } else {
-    // bad target
-    sprite_flags2[k] &= ~0x1f;
-    BYTE(cur_sprite_y) += 3;
-    SpriteDraw_SingleLarge(k);
-  }
-  if (Sprite_ReturnIfInactive(k))
-    return;
-
-  if (sprite_delay_aux3[k] == 1)
-    sound_effect_1 = 0x3c;
-  sprite_subtype2[k]++;
-  Sprite_MoveX(k);
-  if (!sprite_delay_aux1[k]) {
-    sprite_ignore_projectile[k] = sprite_delay_main[k];
-    if (sprite_delay_main[k] == 0) {
-      if (Sprite_CheckTileCollision(k)) {
-        sprite_delay_main[k] = 16;
-        sprite_delay_aux2[k] = 0;
-      }
-    } else if (sprite_delay_main[k] == 1) {
-      static const int8 kArcheryTarget_X[2] = {-24, 8};
-      sprite_x_lo[k] = kArcheryTarget_X[sprite_graphics[k]];
-      sprite_x_hi[k] = link_x_coord >> 8;
-      sprite_delay_aux1[k] = 32;
-      sprite_G[k] = 0;
-    }
-  }
-}
-
-static inline uint8 ChainBallMult(uint16 a, uint8 b) {
-  if (a >= 256)
-    return b;
-  int p = a * b;
-  return (p >> 8) + (p >> 7 & 1);
-}
-
-void ChainBallTrooper_Draw(int k) {
-  PrepOamCoordsRet info;
-  if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
-    return;
-  SpriteDraw_GuardHead(k, &info, 0x18 / 4);
-  SpriteDraw_BNCBody(k, &info, 0x14 / 4);
-  SpriteDraw_BNCFlail(k, &info);
-
-  if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
-    return;
-  if (sprite_flags3[k] & 0x10)
-    SpriteDraw_Shadow_custom(k, &info, kSoldier_DrawShadow[sprite_D[k]]);
-}
-
-void Sprite_6B_CannonTrooper(int k) {
-  if (sprite_C[k] != 0) {
-    Sprite_Cannonball(k);
-    return;
-  }
-  assert(0);
-}
-
-void Bee_PutInBottle(int k) {
-  Bee_HandleInteractions(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  if (!choice_in_multiselect_box) {
-    int j = Sprite_Find_EmptyBottle();
-    if (j >= 0) {
-      link_bottle_info[j] = 7 + sprite_head_dir[k];
-      Hud_RefreshIcon();
-      sprite_state[k] = 0;
-      return;
-    }
-    Sprite_ShowMessageUnconditional(0xca);
-  }
-  sprite_delay_aux4[k] = 64;
-  sprite_ai_state[k] = 1;
-}
-
-static inline uint8 GuruguruBarMult(uint16 a, uint8 b) {
-  if (a >= 256)
-    return b;
-  int p = a * b;
-  return (p >> 8) + (p >> 7 & 1);
-}
-
-static inline int8 GuruguruBarSin(uint16 a, uint8 b) {
-  uint8 t = GuruguruBarMult(kSinusLookupTable[a & 0xff], b);
-  return (a & 0x100) ? -t : t;
-}
-
-static inline uint8 ArrgiMult(uint16 a, uint8 b) {
-  if (a >= 256)
-    return b;
-  int p = a * b;
-  return (p >> 8) + (p >> 7 & 1);
-}
-
-static inline int8 ArrgiSin(uint16 a, uint8 b) {
-  uint8 t = ArrgiMult(kSinusLookupTable[a & 0xff], b);
-  return (a & 0x100) ? -t : t;
-}
-
-static inline uint8 HelmasaurMult(uint16 a, uint8 b) {
-  if (a >= 256)
-    return b;
-  int p = a * b;
-  return (p >> 8) + (p >> 7 & 1);
-}
-
-static inline int8 HelmasaurSin(uint16 a, uint8 b) {
-  uint8 t = HelmasaurMult(kSinusLookupTable[a & 0xff], b);
-  return (a & 0x100) ? -t : t;
-}
-
-void Sprite_Wizzbeam(int k) {
-  Wizzbeam_Draw(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  sprite_oam_flags[k] ^= 6;
-  sprite_subtype2[k]++;
-  if (!sprite_ai_state[k])
-    Sprite_CheckDamageToLink(k);
-  Sprite_MoveXY(k);
-  if (Sprite_CheckTileCollision(k))
-    sprite_state[k] = 0;
-}
-
-void Kiki_LyingInwait(int k) {
-  PrepOamCoordsRet info;
-  Sprite_PrepOamCoord(k, &info);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  if (link_is_bunny_mirror | link_disable_sprite_damage | countdown_for_blink || follower_indicator == 10)
-    return;
-  if (save_ow_event_info[BYTE(overworld_screen_index)] & 0x20)
-    return;
-  if (Sprite_CheckDamageToLink_same_layer(k)) {
-    // Kiki Big Bomb Fix
-    if (enhanced_features0 & kFeatures0_MiscBugFixes)
-      follower_dropped = 0;  // defuse bomb
-
-    follower_indicator = 10;
-    tagalong_var5 = 0;
-    LoadFollowerGraphics();
-    Follower_Initialize();
-  }
-}
-
-int ChainChomp_OneMult(uint8 a, uint8 b) {
-  uint8 at = sign8(a) ? -a : a;
-  uint8 prod = at * b >> 8;
-  return sign8(a) ? ~prod : prod;
-}
-
-static inline uint8 TrinexxMult(uint8 a, uint8 b) {
-  uint8 at = sign8(a) ? -a : a;
-  int p = at * b;
-  uint8 res = (p >> 8) + (p >> 7 & 1);
-  return sign8(a) ? -res : res;
-}
-
-static inline uint8 TrinexxHeadMult(uint16 a, uint8 b) {
-  if (a >= 256)
-    return b;
-  int p = a * b;
-  return (p >> 8) + (p >> 7 & 1);
-}
-
-static inline int8 TrinexxHeadSin(uint16 a, uint8 b) {
-  uint8 t = TrinexxHeadMult(kSinusLookupTable[a & 0xff], b);
-  return (a & 0x100) ? -t : t;
-}
-
-void Sprite_CC(int k) {
-  if (!sprite_E[k]) {
-    Sprite_Sidenexx(k);
-    return;
-  }
-  PrepOamCoordsRet info;
-  Sprite_PrepOamCoord(k, &info);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  Sprite_MoveXY(k);
-  Sprite_TrinexxFire_AddFireGarnish(k);
-  Sprite_CC_CD_Common(k);
-}
-
-void Sprite_CD(int k) {
-  if (!sprite_E[k]) {
-    Sprite_Sidenexx(k);
-    return;
-  }
-  PrepOamCoordsRet info;
-  Sprite_PrepOamCoord(k, &info);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  uint8 old_xvel = sprite_x_vel[k];
-  sprite_x_vel[k] += sprite_C[k];
-  Sprite_MoveXY(k);
-  sprite_x_vel[k] = old_xvel;
-  Sprite_CD_SpawnGarnish(k);
-  Sprite_CC_CD_Common(k);
-}
-
-static inline uint8 GanonMult(uint16 a, uint8 b) {
-  if (a >= 256)
-    return b;
-  int p = a * b;
-  return (p >> 8) + (p >> 7 & 1);
-}
-
-static inline int8 GanonSin(uint16 a, uint8 b) {
-  uint8 t = GanonMult(kSinusLookupTable[a & 0xff], b);
-  return (a & 0x100) ? -t : t;
-}
-
-void SpritePrep_IncrXYLow8(int k) {
-  sprite_x_lo[k] += 8;
-  sprite_y_lo[k] += 8;
-}
-
-void SpritePrep_FakeSword(int k) {
-}
-
-void SpritePrep_MedallionTable(int k) {
-  sprite_ignore_projectile[k]++;
-  if (BYTE(overworld_screen_index) != 3) {
-    sprite_x_lo[k] += 8;
-    if (link_item_bombos_medallion) {
-      sprite_graphics[k] = 4;
-      sprite_ai_state[k] = 3;
-    }
-  } else {
-    if (link_item_ether_medallion) {
-      sprite_graphics[k] = 4;
-      sprite_ai_state[k] = 3;
-    }
-  }
-}
-
-void Hobo_Draw(int k) {  // 84ea60
-  static const DrawMultipleData kHobo_Dmd[12] = {
-    {-5,   3, 0x00a6, 2},
-    { 3,   3, 0x00a7, 2},
-    {-5,   3, 0x00a6, 2},
-    { 3,   3, 0x00a7, 2},
-    {-5,   3, 0x00ab, 0},
-    { 3,   3, 0x00a7, 2},
-    {-5,   3, 0x00a6, 2},
-    { 3,   3, 0x00a7, 2},
-    { 5, -11, 0x008a, 2},
-    {-5,   3, 0x00ab, 0},
-    { 3,   3, 0x0088, 2},
-    {-5,   3, 0x00a6, 2},
-  };
-  Sprite_DrawMultiplePlayerDeferred(k, &kHobo_Dmd[sprite_graphics[k] * 4], 4, NULL);
-}
-
-bool Landmine_CheckDetonationFromHammer(int k) {  // 84ea81
-  if (!(link_item_in_hand & 10) || player_oam_y_offset == 0x80)
-    return false;
-  SpriteHitBox hb;
-  Player_SetupActionHitBox(&hb);
-  Sprite_SetupHitBox(k, &hb);
-  return CheckIfHitBoxesOverlap(&hb);
-}
-
-void Sprite_DrawLargeWaterTurbulence(int k) {  // 84ebe5
-  static const DrawMultipleData kWaterTurbulence_Dmd[6] = {
-    {-10, 14, 0x00c0, 2},
-    { -5, 16, 0x40c0, 2},
-    { -2, 18, 0x00c0, 2},
-    {  2, 18, 0x40c0, 2},
-    {  5, 16, 0x00c0, 2},
-    { 10, 14, 0x40c0, 2},
-  };
-  uint8 bak = sprite_oam_flags[k];
-  sprite_oam_flags[k] = (sprite_subtype2[k] >> 1 & 1) ? 0x44 : 4;
-  sprite_obj_prio[k] &= ~0xf;
-  Oam_AllocateFromRegionC(sprite_obj_prio[k]);  // wtf?????
-  Sprite_DrawMultiple(k, kWaterTurbulence_Dmd, 6, NULL);
-  sprite_oam_flags[k] = bak;
-}
-
-void Sprite_SpawnSparkleGarnish(int k) {  // 858008
-  static const int8 kSparkleGarnish_Coord[4] = {-4, 0, 4, 8};
-  if (frame_counter & 3)
-    return;
-  int j = GarnishAllocForce();
-  garnish_type[j] = 0x12;
-  garnish_active = 0x12;
-  int x = Sprite_GetX(k) + kSparkleGarnish_Coord[GetRandomNumber() & 3];
-  int y = Sprite_GetY(k) + kSparkleGarnish_Coord[GetRandomNumber() & 3];
-  garnish_x_lo[j] = x;
-  garnish_x_hi[j] = x >> 8;
-  garnish_y_lo[j] = y;
-  garnish_y_hi[j] = y >> 8;
-  garnish_sprite[j] = k;
-  garnish_countdown[j] = 15;
-}
-
-void Sprite_70_KingHelmasaurFireball(int k) {  // 85807f
-  static const uint8 kHelmasaurFireball_Char[3] = {0xcc, 0xcc, 0xca};
-  static const uint8 kHelmasaurFireball_Flags[2] = {0x33, 0x73};
-  static const uint8 kHelmasaurFireball_Gfx[4] = {2, 2, 1, 0};
-  OamEnt *oam = GetOamCurPtr();
-  uint8 flags = kHelmasaurFireball_Flags[++sprite_subtype2[k] >> 2 & 1];
-
-  if ((uint8)((oam->x = sprite_x_lo[k] - BG2HOFS_copy2) + 32) < 64 ||
-      (uint8)((oam->y = sprite_y_lo[k] - BG2VOFS_copy2) + 16) < 32) {
-    sprite_state[k] = 0;
-    return;
-  }
-  oam->charnum = kHelmasaurFireball_Char[sprite_graphics[k]];
-  oam->flags = flags;
-  bytewise_extended_oam[oam - oam_buf] = 2;
-
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  if (!((k ^ frame_counter) & 3) &&
-      (uint16)(link_x_coord - cur_sprite_x + 8) < 16 &&
-      (uint16)(link_y_coord - cur_sprite_y + 16) < 16) {
-    Sprite_AttemptDamageToLinkPlusRecoil(k);
-  }
-  switch (sprite_ai_state[k]) {
-  case 0:  // pre migrate down
-    if (!sprite_delay_main[k]) {
-      sprite_delay_main[k] = 18;
-      sprite_ai_state[k] = 1;
-      sprite_y_vel[k] = 36;
-    }
-    break;
-  case 1:  // migrate down
-    if (!sprite_delay_main[k]) {
-      sprite_ai_state[k] = 2;
-      sprite_delay_main[k] = 31;
-    }
-    sprite_y_vel[k] -= 2;
-    Sprite_MoveY(k);
-    break;
-  case 2:  // delay tri split
-    if (!sprite_delay_main[k])
-      HelmasaurFireball_TriSplit(k);
-    else
-      sprite_graphics[k] = kHelmasaurFireball_Gfx[sprite_delay_main[k] >> 3];
-    break;
-  case 3:  // delay quad split
-    if (!sprite_delay_main[k]) {
-      HelmasaurFireball_QuadSplit(k);
-    } else if (sprite_head_dir[k] < 20) {
-      sprite_head_dir[k]++;
-      Sprite_MoveXY(k);
-    }
-    break;
-  case 4:  // move
-    Sprite_MoveXY(k);
-    break;
-  }
-}
-
-void Sprite_66_WallCannonVerticalLeft(int k) {  // 858090
-  static const int8 kWallCannon_Xvel[4] = {0, 0, -16, 16};
-  static const int8 kWallCannon_Yvel[4] = {-16, 16, 0, 0};
-  static const uint8 kWallCannon_Gfx[4] = {0, 0, 2, 2};
-  static const uint8 kWallCannon_OamFlags[4] = {0x40, 0, 0, 0x80};
-  static const int8 kWallCannon_Spawn_X[4] = {8, -8, 0, 0};
-  static const int8 kWallCannon_Spawn_Y[4] = {0, 0, 8, -8};
-  static const int8 kWallCannon_Spawn_Xvel[4] = {24, -24, 0, 0};
-  static const int8 kWallCannon_Spawn_Yvel[4] = {0, 0, 24, -24};
-
-  int j = sprite_D[k];
-  sprite_graphics[k] = kWallCannon_Gfx[j] + (sprite_delay_aux2[k] != 0);
-  sprite_oam_flags[k] = sprite_oam_flags[k] & ~0x40 | kWallCannon_OamFlags[j];
-  SpriteDraw_SingleLarge(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  if (!sprite_delay_main[k]) {
-    sprite_delay_main[k] = 128;
-    sprite_A[k] ^= 1;
-  }
-  j = sprite_A[k];
-  sprite_x_vel[k] = kWallCannon_Xvel[j];
-  sprite_y_vel[k] = kWallCannon_Yvel[j];
-  Sprite_MoveXY(k);
-
-  if (!((k << 2) + frame_counter & 31))
-    sprite_delay_aux2[k] = 16;
-  if (sprite_delay_aux2[k] != 1 || sprite_pause[k])
-    return;
-  SpriteSpawnInfo info;
-  j = Sprite_SpawnDynamicallyEx(k, 0x6B, &info, 13);
-  if (j >= 0) {
-    SpriteSfx_QueueSfx3WithPan(k, 0x7);
-    sprite_C[j] = 1;
-    sprite_graphics[j] = 1;
-    int i = sprite_D[k];
-    Sprite_SetX(j, info.r0_x + kWallCannon_Spawn_X[i]);
-    Sprite_SetY(j, info.r2_y + kWallCannon_Spawn_Y[i]);
-    sprite_x_vel[j] = kWallCannon_Spawn_Xvel[i];
-    sprite_y_vel[j] = kWallCannon_Spawn_Yvel[i];
-    sprite_flags2[j] = sprite_flags2[j] & 0xf0 | 1;
-    sprite_flags3[j] |= 0x47;
-    sprite_defl_bits[j] |= 0x44;
-    sprite_delay_main[j] = 32;
-  }
-}
-
-void Sprite_65_ArcheryGame(int k) {  // 8581ff
-  link_num_arrows = sprite_subtype[k];
-  if (sprite_A[k] == 0)
-    ArcheryGame_Host(k);
-  else
-    Sprite_GoodOrBadArcheryTarget(k);
-}
-
-void ArcheryGame_Host(int k) {  // 858217
-  if (!archery_game_arrows_left)
-    archery_game_out_of_arrows++;
-  ArcheryGameGuy_Draw(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  sprite_flags4[k] = 0;
-  if (Sprite_CheckDamageToLink_same_layer(k)) {
-    Sprite_NullifyHookshotDrag();
-    link_speed_setting = 0;
-    Link_CancelDash();
-  }
-  if (sprite_delay_main[k]) {
-    if (!(sprite_delay_main[k] & 7))
-      SpriteSfx_QueueSfx2WithPan(k, 0x11);
-    sprite_graphics[k] = (sprite_delay_main[k] & 4) >> 2;
-  } else {
-    static const uint8 kArcheryGameGuy_Gfx[4] = {3, 4, 3, 2};
-    sprite_graphics[k] = kArcheryGameGuy_Gfx[sprite_ai_state[k] ? (frame_counter >> 5 & 3) : 0];
-  }
-
-  switch (sprite_ai_state[k]) {
-  case 0:
-    sprite_flags4[k] = 10;
-    if (Sprite_CheckDamageToLink_same_layer(k) && filtered_joypad_L & 0x80) {
-      sprite_ai_state[k] = 1;
-      ArcheryGameGuy_ShowMsg(k, 0x85);
-    }
-    break;
-  case 1:
-  case 3:
-    if (!choice_in_multiselect_box && link_rupees_goal >= 20) {
-      sprite_head_dir[k] = 0;
-      byte_7E0B88 = 0;
-      sprite_ai_state[k] = 2;
-      ArcheryGameGuy_ShowMsg(k, 0x86);
-    } else {
-      sprite_ai_state[k] = 0;
-      ArcheryGameGuy_ShowMsg(k, 0x87);
-    }
-    break;
-  case 2:
-    ArcheryGame_Host_ProctorGame(k);
-    break;
-  }
-}
-
-void ArcheryGameGuy_ShowMsg(int k, int msg) {  // 8582bf
-  dialogue_message_index = msg;
-  Sprite_ShowMessageMinimal();
-  sprite_delay_main[k] = 0;
-}
-
-void ArcheryGame_Host_ProctorGame(int k) {  // 8582d4
-  static const uint8 kArcheryGame_NumSpr[6] = {5, 4, 3, 2, 1, 0};
-  static const int8 kArcheryGame_X[18] = { 0, 0, 0, 0, 48, 48, 48, 48, 8, 8, 16, 16, 24, 24, 32, 32, 40, 40, };
-  static const int8 kArcheryGame_Y[18] = {-8, 0, 8, 16, -8, 0, 8, 16, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8 };
-  static const uint8 kArcheryGame_Char[18] = { 0x2b, 0x3b, 0x3b, 0x2b, 0x2b, 0x3b, 0x3b, 0x2b, 0x63, 0x73, 0x63, 0x73, 0x63, 0x73, 0x63, 0x73, 0x63, 0x73 };
-  static const uint8 kArcheryGame_Flags[18] = { 0x33, 0x33, 0xb3, 0xb3, 0x73, 0x73, 0xf3, 0xf3, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32 };
-
-  if (!sprite_head_dir[k]) {
-    archery_game_arrows_left = 5;
-    Sprite_InitializeSecondaryItemMinigame(2);
-    sprite_delay_aux1[k] = 39;
-    link_rupees_goal -= 20;
-    sprite_head_dir[k]++;
-  }
-  Oam_AllocateFromRegionA(0x34);
-  PrepOamCoordsRet info;
-  if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
-    return;
-  OamEnt *oam = GetOamCurPtr();
-  int i = sprite_delay_aux1[k] ? kArcheryGame_NumSpr[sprite_delay_aux1[k] >> 3] : archery_game_arrows_left;
-  i = i * 2 + 7;
-  do {
-    SetOamPlain(oam, info.x - 20 + kArcheryGame_X[i] + 1, info.y - 48 + kArcheryGame_Y[i] + 1,
-                 kArcheryGame_Char[i], kArcheryGame_Flags[i], 0);
-  } while (oam++, --i >= 0);
-
-  if (archery_game_arrows_left | sprite_delay_aux4[k] |
-      ancilla_type[0] | ancilla_type[1] | ancilla_type[2] | ancilla_type[3] | ancilla_type[4])
-    return;
-  sprite_flags4[k] = 0xA;
-  if (Sprite_CheckDamageToLink_same_layer(k) && filtered_joypad_L & 0x80) {
-    ArcheryGameGuy_ShowMsg(k, 0x88);
-    sprite_ai_state[k] = 3;
-  }
-}
-
-void ArcheryGame_DrawPrize(int k) {  // 8584cf
-  static const int8 kGoodArcheryTarget_X[5] = {-8, -8, 0, 8, 16};
-  static const int8 kGoodArcheryTarget_Y[5] = {-24, -16, -20, -20, -20};
-  static const uint8 kGoodArcheryTarget_Draw_Char[3] = {0xb, 0x1b, 0xb6};
-  static const int8 kGoodArcheryTarget_Draw_Flags[5] = {0x38, 0x38, 0x34, 0x35, 0x35};
-  static const uint8 kGoodArcheryTarget_Draw_Char3[6] = {0x12, 0x32, 0x31, 3, 0x22, 0x33};
-  static const uint8 kGoodArcheryTarget_Draw_Char4[6] = {0x7c, 0x7c, 0x22, 2, 0x12, 0x33};
-  PrepOamCoordsRet info;
-  if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
-    return;
-  OamEnt *oam = GetOamCurPtr() + 1;
-  int b = sprite_B[k];
-  for (int i = 4; i >= 0; i--, oam++) {
-    uint8 charnum = (i == 4) ? kGoodArcheryTarget_Draw_Char4[b - 1] :
-                    (i == 3) ? kGoodArcheryTarget_Draw_Char3[b - 1] : kGoodArcheryTarget_Draw_Char[i];
-    SetOamPlain(oam, info.x + kGoodArcheryTarget_X[i], info.y + kGoodArcheryTarget_Y[i], charnum,
-                 kGoodArcheryTarget_Draw_Flags[i] & (charnum < 0x7c ? 0xff : 0xfe), 0);
-  }
-  Sprite_DrawDistress_custom(info.x, info.y, frame_counter);
-}
-
-void Sprite_63_DebirandoPit(int k) {  // 858531
-  static const uint8 kDebirandoPit_OpeningGfx[4] = {5, 4, 3, 3};
-  static const uint8 kDebirandoPit_ClosingGfx[4] = {3, 3, 4, 5};
-
-  PointU8 pt;
-  Sprite_DirectionToFaceLink(k, &pt);
-  if ((uint8)(pt.y + 0x20) < 0x40 && (uint8)(pt.x + 0x20) < 0x40)
-    Oam_AllocateFromRegionB(16);
-
-  DebirandoPit_Draw(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  int j = sprite_head_dir[k];
-  if (sprite_state[j] == 6) {
-    sprite_state[k] = sprite_state[j];
-    sprite_delay_main[k] = sprite_delay_main[j];
-    sprite_flags2[k] += 4;
-    return;
-  }
-  if (sprite_graphics[k] < 3 && Sprite_CheckDamageToLink_same_layer(k)) {
-    Link_CancelDash();
-    if (!(filtered_joypad_L & 16))
-      link_prevent_from_moving = 1;
-    Sprite_ApplySpeedTowardsLink(k, 16);
-    uint8 v = sprite_y_vel[k];
-    int t;
-    sprite_A[k] = (t = (sign8(v) ? (uint8)-v : v) + sprite_A[k]);
-    if (t >= 256)
-      drag_player_y = sign8(v) ? 1 : -1;
-
-    v = sprite_x_vel[k];
-    sprite_B[k] = (t = (sign8(v) ? (uint8)-v : v) + sprite_B[k]);
-    if (t >= 256)
-      drag_player_x = sign8(v) ? 1 : -1;
-  }
-  switch (sprite_ai_state[k]) {
-  case 0:  // closed
-    sprite_graphics[k] = 6;
-    if (!sprite_delay_main[k]) {
-      sprite_ai_state[k] = 1;
-      sprite_delay_main[k] = 63;
-    }
-    break;
-  case 1:  // opening
-    if (!sprite_delay_main[k]) {
-      sprite_ai_state[k] = 2;
-      sprite_delay_main[k] = 255;
-    } else {
-      sprite_graphics[k] = kDebirandoPit_OpeningGfx[sprite_delay_main[k] >> 4];
-    }
-    break;
-  case 2:  // open
-    if (!(frame_counter & 15) && ++sprite_graphics[k] >= 3)
-      sprite_graphics[k] = 0;
-    if (!sprite_delay_main[k]) {
-      sprite_delay_main[k] = 63;
-      sprite_ai_state[k] = 3;
-    }
-    break;
-  case 3:  // closing
-    if (!sprite_delay_main[k]) {
-      sprite_ai_state[k] = 0;
-      sprite_delay_main[k] = 32;
-    } else {
-      sprite_graphics[k] = kDebirandoPit_ClosingGfx[sprite_delay_main[k] >> 4];
-    }
-    break;
-  }
-}
-
-void DebirandoPit_Draw(int k) {  // 8586e4
-  static const int16 kDebirandoPit_Draw_X[24] = {
-    -8, 8, -8, 8, -8, 8, -8, 8, -8, 8, -8, 8, 0, 8, 0, 8,
-    0, 8,  0, 8, -8, 8, -8, 8,
-  };
-  static const int16 kDebirandoPit_Draw_Y[24] = {
-    -8, -8, 8, 8, -8, -8, 8, 8, -8, -8, 8, 8, 0, 0, 8, 8,
-    0,  0, 8, 8, -8, -8, 8, 8,
-  };
-  static const uint8 kDebirandoPit_Draw_Char[24] = {
-    4,    4,    4,    4, 0x22, 0x22, 0x22, 0x22, 2, 2, 2, 2, 0x29, 0x29, 0x29, 0x29,
-    0x39, 0x39, 0x39, 0x39, 0x2a, 0x2a, 0x2a, 0x2a,
-  };
-  static const uint8 kDebirandoPit_Draw_Flags[24] = {
-    0, 0x40, 0x80, 0xc0, 0, 0x40, 0x80, 0xc0, 0, 0x40, 0x80, 0xc0, 0, 0x40, 0x80, 0xc0,
-    0, 0x40, 0x80, 0xc0, 0, 0x40, 0x80, 0xc0,
-  };
-  static const uint8 kDebirandoPit_Draw_Big[6] = {2, 2, 2, 0, 0, 2};
-  PrepOamCoordsRet info;
-  if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
-    return;
-  int g = sprite_graphics[k];
-  if (g == 6)
-    return;
-  OamEnt *oam = GetOamCurPtr();
-  uint8 big = kDebirandoPit_Draw_Big[g];
-  for (int i = 3; i >= 0; i--, oam++) {
-    int j = g * 4 + i;
-    SetOamHelper0(oam, info.x + kDebirandoPit_Draw_X[j],
-                       info.y + kDebirandoPit_Draw_Y[j],
-                       kDebirandoPit_Draw_Char[j],
-                       kDebirandoPit_Draw_Flags[j] | info.flags, big);
-  }
-}
-
-void Sprite_64_Debirando(int k) {  // 85874d
-  static const uint8 kDebirando_Emerge_Gfx[2] = {1, 0};
-  static const uint8 kDebirando_Submerge_Gfx[2] = {0, 1};
-  Debirando_Draw(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  switch (sprite_ai_state[k]) {
-  case 0:  // under sand
-    sprite_ignore_projectile[k] = sprite_delay_main[k];
-    if (!sprite_delay_main[k]) {
-      sprite_ai_state[k]++;
-      sprite_delay_main[k] = 31;
-    }
-    break;
-  case 1:  // emerge
-    Sprite_CheckDamageToAndFromLink(k);
-    if (!sprite_delay_main[k]) {
-      sprite_ai_state[k]++;
-      sprite_delay_main[k] = 128;
-    } else {
-      sprite_graphics[k] = kDebirando_Emerge_Gfx[sprite_delay_main[k] >> 4];
-    }
-    break;
-  case 2:  // fireball
-    Sprite_CheckDamageToAndFromLink(k);
-    if (!sprite_delay_main[k]) {
-      sprite_delay_main[k] = 31;
-      sprite_ai_state[k]++;
-    } else {
-      if (!(sprite_delay_main[k] & 31 | sprite_G[k] | submodule_index | sprite_pause[k] | flag_unk1))
-        Sprite_SpawnFireball(k);
-      sprite_graphics[k] = (++sprite_subtype2[k] >> 3 & 1) + 2;
-    }
-    break;
-  case 3:  // submerge
-    Sprite_CheckDamageToAndFromLink(k);
-    if (!sprite_delay_main[k]) {
-      sprite_ai_state[k] = 0;
-      sprite_delay_main[k] = 223;
-    } else {
-      sprite_graphics[k] = kDebirando_Submerge_Gfx[sprite_delay_main[k] >> 4];
-    }
-    break;
-  }
-}
-
-void Debirando_Draw(int k) {  // 858857
-  if (!sprite_ai_state[k])
-    return;
-  static const int8 kDebirando_Draw_X[16] = {0, 8, 0, 8, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0};
-  static const int8 kDebirando_Draw_Y[16] = {2, 2, 6, 6, -2, -2, 6, 6, -4, -4, -4, -4, -4, -4, -4, -4};
-  static const uint8 kDebirando_Draw_Char[16] = {0, 0, 0xd8, 0xd8, 0, 0, 0xd9, 0xd9, 0, 0, 0, 0, 0x20, 0x20, 0x20, 0x20};
-  static const uint8 kDebirando_Draw_Flags[16] = {1, 0x41, 0, 0x40, 1, 1, 0, 0x40, 1, 1, 1, 1, 1, 1, 1, 1};
-  static const uint8 kDebirando_Draw_Big[16] = {0, 0, 0, 0, 2, 2, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2};
-  PrepOamCoordsRet info;
-  if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
-    return;
-  OamEnt *oam = GetOamCurPtr();
-  int d = sprite_graphics[k] * 4;
-  for (int i = 3; i >= 0; i--, oam++) {
-    int j = d + i;
-    uint8 f = kDebirando_Draw_Flags[j];
-    SetOamHelper0(oam,
-                  info.x + kDebirando_Draw_X[j],
-                  info.y + kDebirando_Draw_Y[j],
-                  kDebirando_Draw_Char[j],
-                  (f ^ info.flags) & ((f & 0xf) == 0 ? 0xf0 : 0xff),
-                  kDebirando_Draw_Big[j]);
-  }
-}
-
-void Sprite_62_MasterSword(int k) {  // 8588c5
-  switch (sprite_subtype2[k]) {
-  case 0: MasterSword_Main(k); break;
-  case 1: Sprite_MasterSword_LightFountain(k); break;
-  case 2: Sprite_MasterSword_LightBeam(k); break;
-  case 3: Sprite_MasterSword_Prop(k); break;
-  case 4: Sprite_MasterSword_LightWell(k); break;
-  }
-}
-
-void MasterSword_Main(int k) {  // 8588d6
-  if (main_module_index != 26 && save_ow_event_info[BYTE(overworld_screen_index)] & 0x40) {
-    sprite_state[k] = 0;
-    return;
-  }
-  if (sprite_ai_state[k] != 5)
-    MasterSword_Draw(k);
-  switch (sprite_ai_state[k]) {
-  case 0:  // waiting
-    if (Sprite_CheckIfLinkIsBusy() || !Sprite_CheckDamageToLink_same_layer(k) || link_direction_facing != 2 ||
-      !(filtered_joypad_L & 0x80) || (link_which_pendants & 7) != 7)
-      return;
-
-    music_control = 10;
-    link_disable_sprite_damage = 1;
-    MasterSword_SpawnPendantProp(k, 9);
-    MasterSword_SpawnPendantProp(k, 11);
-    MasterSword_SpawnPendantProp(k, 15);
-    MasterSword_SpawnLightWell(k);
-    sprite_ai_state[k] = 1;
-    sprite_delay_main[k] = 240;
-    break;
-  case 1:  // pendants transfer
-    if (!sprite_delay_main[k]) {
-      MasterSword_SpawnLightFountain(k);
-      sprite_ai_state[k] = 2;
-      sprite_delay_main[k] = 192;
-    }
-    link_unk_master_sword = 10;
-    flag_is_link_immobilized = 1;
-    break;
-  case 2:  // light show
-    if (!sprite_delay_main[k]) {
-      MasterSword_SpawnLightBeam(k, 0, 0xff);
-      sprite_ai_state[k] = 3;
-      sprite_delay_main[k] = 8;
-    }
-    link_unk_master_sword = 10;
-    flag_is_link_immobilized = 1;
-    break;
-  case 3:  //
-    if (!sprite_delay_main[k]) {
-      MasterSword_SpawnLightBeam(k, 1, 0xff);
-      sprite_ai_state[k] = 4;
-      sprite_delay_main[k] = 16;
-    }
-    link_unk_master_sword = 11;
-    flag_is_link_immobilized = 1;
-    break;
-  case 4:  // give to player
-    if (!sprite_delay_main[k]) {
-      save_ow_event_info[BYTE(overworld_screen_index)] |= 0x40;
-      item_receipt_method = 0;
-      Link_ReceiveItem(1, 0);
-      savegame_map_icons_indicator = 5;
-      link_unk_master_sword = 0;
-      sprite_ai_state[k] = 5;
-    }
-    break;
-  case 5:  // stop
-    sprite_state[k] = 0;
-    break;
-  }
-}
-
-void Sprite_MasterSword_LightFountain(int k) {  // 8589dc
-  static const uint8 kMasterSword_Gfx1[9] = {0, 1, 1, 2, 2, 2, 1, 1, 0};
-  static const uint8 kMasterSword_NumLightBeams[9] = {0, 0, 1, 1, 2, 2, 0, 0, 0};
-  SpriteDraw_LightFountain(k);
-  sprite_A[k]++;
-  if (!sprite_A[k]) {
-    sprite_C[k]++;
-    sprite_state[k] = 0;
-  }
-  sprite_D[k] = sprite_A[k] >> 2 & 3;
-  int j = sprite_A[k] >> 5 & 7;
-  sprite_graphics[k] = kMasterSword_Gfx1[j];
-  if (kMasterSword_NumLightBeams[j])
-    MasterSword_SpawnLightBeam(k, sprite_A[k] >> 2 & 1, kMasterSword_NumLightBeams[j]);
-}
-
-void Sprite_MasterSword_LightWell(int k) {  // 858a16
-  SpriteDraw_LightFountain(k);
-  sprite_A[k]++;
-  if (!sprite_A[k]) {
-    sprite_C[k]++;
-    sprite_state[k] = 0;
-  }
-  sprite_D[k] = sprite_A[k] >> 2 & 3;
-  sprite_graphics[k] = 0;
-}
-
-void SpriteDraw_LightFountain(int k) {  // 858a94
-  static const DrawMultipleData kMasterSword_LightBall_Dmd[12] = {
-    {-6, 4, 0x0082, 2},
-    {-6, 4, 0x4082, 2},
-    {-6, 4, 0xc082, 2},
-    {-6, 4, 0x8082, 2},
-    {-6, 4, 0x00a0, 2},
-    {-6, 4, 0x40a0, 2},
-    {-6, 4, 0xc0a0, 2},
-    {-6, 4, 0x80a0, 2},
-    {-6, 4, 0x0080, 2},
-    {-6, 4, 0x4080, 2},
-    {-6, 4, 0xc080, 2},
-    {-6, 4, 0x8080, 2},
-  };
-  Oam_AllocateFromRegionC(4);
-  Sprite_DrawMultiple(k, &kMasterSword_LightBall_Dmd[sprite_graphics[k] * 4 + sprite_D[k]], 1, NULL);
-}
-
-void MasterSword_SpawnLightWell(int k) {  // 858ab6
-  SpriteSpawnInfo info;
-  int j = Sprite_SpawnDynamically(k, 0x62, &info);
-  Sprite_SetSpawnedCoordinates(j, &info);
-  sprite_subtype2[j] = 4;
-  sprite_oam_flags[j] = 5;
-  sprite_flags2[j] = 0;
-}
-
-void MasterSword_SpawnLightFountain(int k) {  // 858ad0
-  SpriteSpawnInfo info;
-  int j = Sprite_SpawnDynamically(k, 0x62, &info);
-  Sprite_SetSpawnedCoordinates(j, &info);
-  sprite_subtype2[j] = 1;
-  sprite_oam_flags[j] = 5;
-  sprite_flags2[j] = 0;
-}
-
-void Sprite_MasterSword_LightBeam(int k) {  // 858aea
-  SpriteDraw_SingleLarge(k);
-  if (sprite_A[k]) {
-    Sprite_MoveXY(k);
-    if (frame_counter & 3)
-      return;
-    MasterSword_SpawnReplacementLightBeam(k);
-  }
-  if (!--sprite_B[k])
-    sprite_state[k] = 0;
-}
-
-void MasterSword_SpawnReplacementLightBeam(int k) {  // 858b20
-  SpriteSpawnInfo info;
-  int j;
-  if ((j = Sprite_SpawnDynamically(k, 0x62, &info)) < 0)
-    return;
-  Sprite_SetX(j, info.r0_x);
-  Sprite_SetY(j, info.r2_y);
-  sprite_subtype2[j] = 2;
-  sprite_B[j] = 3;
-  sprite_graphics[j] = sprite_graphics[k];
-  sprite_oam_flags[j] = sprite_oam_flags[k];
-  sprite_flags2[j] = 0;
-}
-
-void MasterSword_SpawnLightBeam(int k, uint8 ain, uint8 yin) {  // 858b62
-  static const int8 kMasterSword_LightBeam_Xv0[2] = {0, -48};
-  static const int8 kMasterSword_LightBeam_Xv1[2] = {0, 48};
-  static const int8 kMasterSword_LightBeam_Xv2[2] = {-96, -48};
-  static const int8 kMasterSword_LightBeam_Xv3[2] = {96, 48};
-  static const int8 kMasterSword_LightBeam_Yv0[2] = {-96, -48};
-  static const int8 kMasterSword_LightBeam_Yv1[2] = {96, 48};
-  static const int8 kMasterSword_LightBeam_Yv2[2] = {0, 48};
-  static const int8 kMasterSword_LightBeam_Yv3[2] = {0, -48};
-  static const uint8 kMasterSword_LightBeam_Gfx0[2] = {1, 0};
-  static const uint8 kMasterSword_LightBeam_Gfx2[2] = {3, 2};
-  static const uint8 kMasterSword_LightBeam_Flags0[2] = {5, 0x45};
-  static const uint8 kMasterSword_LightBeam_Flags2[2] = {5, 5};
-
-  SpriteSpawnInfo info;
-  int j;
-  if ((j = Sprite_SpawnDynamically(k, 0x62, &info)) < 0)
-    return;
-  Sprite_SetX(j, info.r0_x - 4);
-  Sprite_SetY(j, info.r2_y + 4);
-  sprite_subtype2[j] = 2;
-  sprite_A[j] = 2;
-  sprite_flags2[j] = 0;
-  sprite_x_vel[j] = kMasterSword_LightBeam_Xv0[ain];
-  sprite_y_vel[j] = kMasterSword_LightBeam_Yv0[ain];
-  sprite_graphics[j] = kMasterSword_LightBeam_Gfx0[ain];
-  sprite_oam_flags[j] = kMasterSword_LightBeam_Flags0[ain];
-  sprite_B[j] = yin;
-
-  if ((j = Sprite_SpawnDynamically(k, 0x62, &info)) < 0)
-    return;
-  Sprite_SetX(j, info.r0_x - 4);
-  Sprite_SetY(j, info.r2_y + 4);
-  sprite_subtype2[j] = 2;
-  sprite_A[j] = 2;
-  sprite_flags2[j] = 0;
-  sprite_x_vel[j] = kMasterSword_LightBeam_Xv1[ain];
-  sprite_y_vel[j] = kMasterSword_LightBeam_Yv1[ain];
-  sprite_graphics[j] = kMasterSword_LightBeam_Gfx0[ain];
-  sprite_oam_flags[j] = kMasterSword_LightBeam_Flags0[ain];
-  sprite_B[j] = yin;
-
-  if ((j = Sprite_SpawnDynamically(k, 0x62, &info)) < 0)
-    return;
-  Sprite_SetX(j, info.r0_x - 4);
-  Sprite_SetY(j, info.r2_y + 4);
-  sprite_subtype2[j] = 2;
-  sprite_A[j] = 2;
-  sprite_flags2[j] = 0;
-  sprite_x_vel[j] = kMasterSword_LightBeam_Xv2[ain];
-  sprite_y_vel[j] = kMasterSword_LightBeam_Yv2[ain];
-  sprite_graphics[j] = kMasterSword_LightBeam_Gfx2[ain];
-  sprite_oam_flags[j] = kMasterSword_LightBeam_Flags2[ain];
-  sprite_B[j] = yin;
-
-  if ((j = Sprite_SpawnDynamically(k, 0x62, &info)) < 0)
-    return;
-  Sprite_SetX(j, info.r0_x - 4);
-  Sprite_SetY(j, info.r2_y + 4);
-  sprite_subtype2[j] = 2;
-  sprite_A[j] = 2;
-  sprite_flags2[j] = 0;
-  sprite_x_vel[j] = kMasterSword_LightBeam_Xv3[ain];
-  sprite_y_vel[j] = kMasterSword_LightBeam_Yv3[ain];
-  sprite_graphics[j] = kMasterSword_LightBeam_Gfx2[ain];
-  sprite_oam_flags[j] = kMasterSword_LightBeam_Flags2[ain];
-  sprite_B[j] = yin;
-}
-
-void MasterSword_SpawnPendantProp(int k, uint8 ain) {  // 858cd3
-  static const int8 kMasterSword_Pendant_Xv[4] = {-4, 4, 0, 0};
-  static const int8 kMasterSword_Pendant_Yv[4] = {-2, -2, -4, -4};
-  SpriteSpawnInfo info;
-  int j;
-  if ((j = Sprite_SpawnDynamically(k, 0x62, &info)) < 0)
-    return;
-  sprite_oam_flags[j] = ain;
-  Sprite_SetX(j, link_x_coord);
-  Sprite_SetY(j, link_y_coord + 8);
-  sprite_graphics[j] = 4;
-  sprite_subtype2[j] = 3;
-  sprite_flags2[j] = 64;
-  sprite_delay_main[j] = 228;
-  int i = ain >> 1 & 3;
-  sprite_x_vel[j] = kMasterSword_Pendant_Xv[i];
-  sprite_y_vel[j] = kMasterSword_Pendant_Yv[i];
-}
-
-void Sprite_MasterSword_Prop(int k) {  // 858d29
-  Oam_AllocateFromRegionB(4);
-  SpriteDraw_SingleLarge(k);
-  switch (sprite_ai_state[k]) {
-  case 0:  // drifting away
-    Sprite_MoveXY(k);
-    if (!sprite_delay_main[k]) {
-      sprite_ai_state[k] = 1;
-      sprite_delay_main[k] = 208;
-      sprite_A[k] = sprite_oam_flags[k];
-    }
-    break;
-  case 1:  // flashing
-    sprite_oam_flags[k] = (sprite_oam_flags[k] & ~0xe) | ((k << 1 ^ frame_counter) & 0xe);
-    if (!sprite_delay_main[k]) {
-      sprite_ai_state[k] = 2;
-      sprite_oam_flags[k] = sprite_A[k];
-    }
-    break;
-  case 2:  // fly
-    Sprite_MoveXY(k);
-    if (!sprite_delay_main[k]) {
-      sprite_x_vel[k] <<= 1;
-      sprite_y_vel[k] <<= 1;
-      sprite_delay_main[k] = 6;
-    }
-    sprite_E[k]++;
-    if (sprite_E[k] == 0)
-      sprite_state[k] = 0;
-    break;
-  }
-}
-
-void MasterSword_Draw(int k) {  // 858da8
-  static const int8 kMasterSword_Draw_X[6] = {-8, 0, -8, 0, -8, 0};
-  static const int8 kMasterSword_Draw_Y[6] = {-8, -8, 0, 0, 8, 8};
-  static const uint8 kMasterSword_Draw_Char[6] = {0xc3, 0xc4, 0xd3, 0xd4, 0xe0, 0xf0};
-  PrepOamCoordsRet info;
-  if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
-    return;
-  OamEnt *oam = GetOamCurPtr();
-  for (int i = 5; i >= 0; i--, oam++) {
-    oam->x = kMasterSword_Draw_X[i] + info.x;
-    oam->y = kMasterSword_Draw_Y[i] + info.y;
-    oam->charnum = kMasterSword_Draw_Char[i];
-    oam->flags = info.flags;
-  }
-  Sprite_CorrectOamEntries(k, 5, 0);
-}
-
-void Sprite_5D_Roller_VerticalDownFirst(int k) {  // 858dde
-  static const int8 kSpikeRoller_XYvel[6] = {-16, 16, 0, 0, -16, 16};
-  sprite_graphics[k] = sprite_subtype2[k] >> 1 & 1 | sprite_D[k] & 2;
-  SpikeRoller_Draw(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  Sprite_CheckDamageToAndFromLink(k);
-  if (!sprite_delay_main[k]) {
-    sprite_delay_main[k] = 112;
-    sprite_D[k] ^= 1;
-  }
-  int j = sprite_D[k];
-  sprite_x_vel[k] = kSpikeRoller_XYvel[j];
-  sprite_y_vel[k] = kSpikeRoller_XYvel[j + 2];
-  Sprite_MoveXY(k);
-  sprite_subtype2[k]++;
-}
-
-void SpikeRoller_Draw(int k) {  // 858ee3
-  static const uint8 kSpikeRoller_Draw_X[32] = {
-    0,    0,    0,    0,    0,    0,    0,    0, 0,    0,    0,    0,    0,    0,    0,    0,
-    0, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70,
-  };
-  static const uint8 kSpikeRoller_Draw_Y[32] = {
-    0, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70,
-    0,    0,    0,    0,    0,    0,    0,    0, 0,    0,    0,    0,    0,    0,    0,    0,
-  };
-  static const uint8 kSpikeRoller_Draw_Char[32] = {
-    0x8e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x8e, 0x8e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x8e,
-    0x88, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x88, 0x88, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x88,
-  };
-  static const uint8 kSpikeRoller_Draw_Flags[32] = {
-    0, 0, 0, 0x80, 0, 0, 0, 0x80, 0x40, 0x40, 0x40, 0xc0, 0x40, 0x40, 0x40, 0xc0,
-    0, 0, 0, 0x40, 0, 0, 0, 0x40, 0x80, 0x80, 0x80, 0xc0, 0x80, 0x80, 0x80, 0xc0,
-  };
-  PrepOamCoordsRet info;
-  if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
-    return;
-  OamEnt *oam = GetOamCurPtr();
-  int g = sprite_graphics[k];
-  uint8 chr = kSpikeRoller_Draw_Char[g * 8];
-
-  for (int i = sprite_ai_state[k] ? 7 : 3; i >= 0; i--, oam++) {
-    int j = g * 8 + i;
-    SetOamHelper0(oam,
-                  info.x + kSpikeRoller_Draw_X[j],
-                  info.y + kSpikeRoller_Draw_Y[j],
-                  chr ? chr : kSpikeRoller_Draw_Char[j],
-                  kSpikeRoller_Draw_Flags[j] | info.flags, 2);
-    chr = 0;
-  }
-}
-
-void Sprite_61_Beamos(int k) {  // 858f54
-  if (sprite_C[k] == 1) {
-    Sprite_Beamos_Laser(k);
-    return;
-  } else if (sprite_C[k] != 0) {
-    Sprite_Beamos_LaserHit(k);
-    return;
-  }
-
-  Beamos_Draw(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  Sprite_CheckTileCollision(k);
-  Sprite_CheckDamageToLink(k);
-  switch (sprite_ai_state[k]) {
-  case 0:
-    if (!((k ^ frame_counter) & 3)) {
-      Sprite_SpawnProbeAlways(k, sprite_D[k]);
-      sprite_D[k]++;
-    }
-    sprite_D[k] &= 63;
-    break;
-  case 3:
-    if (!sprite_delay_main[k]) {
-      sprite_ai_state[k] = 4;
-      sprite_delay_main[k] = 80;
-      SpritePrep_LoadPalette(k);
-    } else {
-      if (sprite_delay_main[k] == 15)
-        Beamos_FireLaser(k);
-      sprite_oam_flags[k] ^= (sprite_delay_main[k] >> 1 & 0xe);
-    }
-    break;
-  default:
-    if (!sprite_delay_main[k])
-      sprite_ai_state[k] = 0;
-    break;
-  }
-}
-
-void Beamos_FireLaser(int k) {  // 858fc2
-  if (sprite_limit_instance >= 4)
-    return;
-  SpriteSpawnInfo info;
-  int j, t;
-  if ((j = Sprite_SpawnDynamically(k, 0x61, &info)) < 0)
-    return;
-  SpriteSfx_QueueSfx3WithPan(k, 0x19);
-  Sprite_SetX(j, info.r0_x + (int8)BYTE(dungmap_var7));
-  Sprite_SetY(j, info.r2_y + (int8)HIBYTE(dungmap_var7));
-  Sprite_ApplySpeedTowardsLink(j, 0x20);
-  sprite_flags2[j] = 0x3f;
-  sprite_flags4[j] = 0x54;
-  sprite_C[j] = 1;
-  sprite_defl_bits[j] = 0x48;
-  sprite_oam_flags[j] = 3;
-  sprite_bump_damage[j] = 4;
-  sprite_delay_aux1[j] = 12;
-  sprite_graphics[j] = t = sprite_limit_instance++;
-  for (int i = 0; i < 32; i++) {
-    beamos_x_lo[t * 32 + i] = sprite_x_lo[j];
-    beamos_x_hi[t * 32 + i] = sprite_x_hi[j];
-    beamos_y_lo[t * 32 + i] = sprite_y_lo[j];
-    beamos_y_hi[t * 32 + i] = sprite_y_hi[j];
-  }
-}
-
-void Beamos_Draw(int k) {  // 859068
-  static const int8 kBeamos_Draw_Y[2] = {-16, 0};
-  static const int8 kBeamos_Draw_Char[2] = {0x48, 0x68};
-  PrepOamCoordsRet info;
-  if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
-    return;
-  int spr_offs = 0;
-  if (sprite_D[k] < 0x20) {
-    Oam_AllocateFromRegionB(12);
-    spr_offs = 1;
-  } else {
-    Oam_AllocateFromRegionC(12);
-  }
-  OamEnt *oam = GetOamCurPtr() + spr_offs;
-  for (int i = 1; i >= 0; i--, oam++)
-    SetOamHelper0(oam, info.x, info.y + kBeamos_Draw_Y[i], kBeamos_Draw_Char[i], info.flags, 2);
-  SpriteDraw_Beamos_Eyeball(k, &info);
-}
-
-void SpriteDraw_Beamos_Eyeball(int k, PrepOamCoordsRet *info) {  // 859151
-  static const int8 kBeamosEyeball_Draw_X[32] = {
-    -1,  0,  1,  2,  3,  4,  5, 7, 8, 10, 11, 12, 13, 14, 15, 16,
-    17, 15, 14, 13, 12, 11, 10, 8, 7,  5,  4,  3,  2,  1,  0, -2,
-  };
-  static const int8 kBeamosEyeball_Draw_Y[32] = {
-    11, 12, 13, 14, 14, 15, 15, 15, 15, 15, 15, 14, 14, 13, 12, 11,
-    10,  9,  8,  7,  7,  6,  6,  6,  6,  6,  6,  7,  7,  8,  9, 10,
-  };
-  static const uint8 kBeamosEyeball_Draw_Char[32] = {
-    0x5b, 0x5b, 0x5a, 0x5a, 0x4b, 0x4b, 0x4a, 0x4a, 0x4a, 0x4a, 0x4b, 0x4b, 0x5a, 0x5a, 0x5b, 0x5b,
-    0x5b, 0x5b, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x5b, 0x5b, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c,
-  };
-  static const uint8 kBeamosEyeball_Draw_Flags[32] = {
-    0,    0,    0,    0,    0,    0,    0,    0, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
-    0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,    0,    0,    0,    0,    0,    0,    0,    0,
-  };
-  int n = (sprite_D[k] < 0x20) ? 0 : 2;
-  OamEnt *oam = GetOamCurPtr() + n;
-  int i = sprite_D[k] >> 1;
-  BYTE(dungmap_var7) = kBeamosEyeball_Draw_X[i] - 3;
-  oam->x = BYTE(dungmap_var7) + info->x;
-  HIBYTE(dungmap_var7) = kBeamosEyeball_Draw_Y[i] - 18;
-  oam->y = HIBYTE(dungmap_var7) + info->y;
-  oam->charnum = kBeamosEyeball_Draw_Char[i];
-  oam->flags = info->flags&0x31|0xA|kBeamosEyeball_Draw_Flags[i];
-  oam_cur_ptr += n * 4;
-  oam_ext_cur_ptr += n;
-  Sprite_CorrectOamEntries(k, 0, 0);
-}
-
-void Sprite_Beamos_Laser(int k) {  // 8591b5
-  if (sprite_delay_aux1[k])
-    return;
-  BeamosLaser_Draw(k);
-  if (!sprite_state[k]) {
-    sprite_limit_instance--;
-    return;
-  }
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  for (int i = 3; i >= 0; i--) {
-    int t = (sprite_subtype2[k]++ & 31) + sprite_graphics[k] * 32;
-    beamos_y_hi[t] = sprite_y_hi[k];
-    beamos_y_lo[t] = sprite_y_lo[k];
-    beamos_x_hi[t] = sprite_x_hi[k];
-    beamos_x_lo[t] = sprite_x_lo[k];
-    Sprite_MoveXY(k);
-  }
-
-  if (sprite_delay_main[k]) {
-    if (sprite_delay_main[k] == 1) {
-      sprite_state[k] = 0;
-      sprite_limit_instance--;
-    }
-    return;
-  }
-  if (!Sprite_CheckDamageToLink_same_layer(k) && !Sprite_CheckTileCollision(k))
-    return;
-  SpriteSfx_QueueSfx3WithPan(k, 0x26);
-  sprite_delay_main[k] = 16;
-  Sprite_ZeroVelocity_XY(k);
-  SpriteSpawnInfo info;
-  int j = Sprite_SpawnDynamically(k, 0x61, &info);
-  if (j >= 0) {
-    Sprite_SetSpawnedCoordinates(j, &info);
-    sprite_delay_main[j] = 16;
-    sprite_flags2[j] = 3;
-    sprite_C[j] = 2;
-    sprite_flags3[j] = 0x40;
-  }
-  sprite_y_hi[k] = 128;
-}
-
-void BeamosLaser_Draw(int k) {  // 85925b
-  PrepOamCoordsRet info;
-  Sprite_PrepOamCoord(k, &info);
-  OamEnt *oam = GetOamCurPtr();
-  int g = sprite_graphics[k];
-  for (int i = 31; i >= 0; i--, oam++) {
-    int j = g * 32 + i;
-    uint16 x = (beamos_x_lo[j] | beamos_x_hi[j] << 8) - BG2HOFS_copy2;
-    uint16 y = (beamos_y_lo[j] | beamos_y_hi[j] << 8) - BG2VOFS_copy2;
-    SetOamHelper0(oam, x, y, 0x5c, info.flags, 0);
-  }
-}
-
-void Sprite_Beamos_LaserHit(int k) {  // 8592da
-  static const int8 kBeamosLaserHit_Draw_X[4] = {-4, 4, -4, 4};
-  static const int8 kBeamosLaserHit_Draw_Y[4] = {-4, -4, 4, 4};
-  static const uint8 kBeamosLaserHit_Draw_Flags[4] = {6, 0x46, 0x86, 0xc6};
-  if (!sprite_delay_main[k])
-    sprite_state[k] = 0;
-  PrepOamCoordsRet info;
-  if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
-    return;
-  OamEnt *oam = GetOamCurPtr();
-  for (int i = 3; i >= 0; i--, oam++) {
-    SetOamHelper0(oam, info.x + kBeamosLaserHit_Draw_X[i], info.y + kBeamosLaserHit_Draw_Y[i],
-                  0xd6, kBeamosLaserHit_Draw_Flags[i] | info.flags & 0x30, 0);
-  }
-}
-
-void Sprite_5B_Spark_Clockwise(int k) {  // 85933f
-  static const uint8 kSpark_OamFlags[4] = {0, 0x40, 0x80, 0xc0};
-  static const uint8 kSpark_directions[8] = {1, 3, 2, 0, 7, 5, 6, 4};
-  int j;
-
-  SpriteDraw_SingleLarge(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  if (!(frame_counter & 1))
-    sprite_oam_flags[k] ^= 6;
-  if (!sprite_ai_state[k]) {
-    sprite_ai_state[k] = 1;
-    sprite_x_vel[k] = sprite_y_vel[k] = 1;
-    uint8 coll = Sprite_CheckTileCollision(k);
-    sprite_x_vel[k] = sprite_y_vel[k] = -1;
-    coll |= Sprite_CheckTileCollision(k);
-    if (coll < 4)
-      j = (coll & 1) ? 0 : 1;
-    else
-      j = (coll & 4) ? 2 : 3;
-    sprite_D[k] = kSpark_directions[(sprite_type[k] != 0x5c) * 4 + j];
-  }
-
-  sprite_oam_flags[k] = sprite_oam_flags[k] & 0x3f | kSpark_OamFlags[frame_counter >> 2 & 3];
-  Sprite_MoveXY(k);
-  Sprite_CheckDamageToLink(k);
-  j = sprite_D[k];
-  sprite_x_vel[k] = kSoldierB_Xvel[j];
-  sprite_y_vel[k] = kSoldierB_Yvel[j];
-  Sprite_CheckTileCollision(k);
-
-  j = sprite_D[k];
-  if (sprite_delay_aux2[k]) {
-    if (sprite_delay_aux2[k] == 6)
-      j = kSoldierB_NextB[j];
-  } else {
-    if (!(sprite_wallcoll[k] & kSoldierB_Mask[j]))
-      sprite_delay_aux2[k] = 10;
-  }
-  if (sprite_wallcoll[k] & kSoldierB_Mask2[j])
-    j = kSoldierB_NextB2[j];
-  sprite_D[k] = j;
-  sprite_x_vel[k] = kSoldierB_Xvel2[j] * 2;
-  sprite_y_vel[k] = kSoldierB_Yvel2[j] * 2;
-}
-
-void Sprite_59_LostWoodsBird(int k) {  // 85940e
-  if (sprite_delay_aux1[k])
-    return;
-  sprite_oam_flags[k] = sprite_oam_flags[k] & ~0x40 | (sign8(sprite_x_vel[k]) ? 0 : 0x40);
-  SpriteDraw_SingleLarge(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  Sprite_MoveXY(k);
-  Sprite_MoveZ(k);
-  switch (sprite_ai_state[k]) {
-  case 0:
-    sprite_graphics[k] = 0;
-    if (sign8(--sprite_z_vel[k] - 0xf1))
-      sprite_ai_state[k] = 1;
-    break;
-  case 1:
-    sprite_z_vel[k] += 2;
-    if (!sign8(sprite_z_vel[k] - 0x10))
-      sprite_ai_state[k] = 0;
-    sprite_graphics[k] = ++sprite_subtype2[k] >> 1 & 1;
-    break;
-  }
-}
-
-void Sprite_5A_LostWoodsSquirrel(int k) {  // 859468
-  if (sprite_delay_aux1[k])
-    return;
-  sprite_oam_flags[k] = sprite_oam_flags[k] & ~0x40 | (sign8(sprite_x_vel[k]) ? 0 : 0x40);
-  SpriteDraw_SingleLarge(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  Sprite_MoveXY(k);
-  Sprite_MoveZ(k);
-  sprite_z_vel[k] -= 2;
-  if (sign8(sprite_z[k])) {
-    sprite_z[k] = 0;
-    sprite_z_vel[k] = 16;
-    sprite_delay_main[k] = 12;
-  }
-  sprite_graphics[k] = sprite_delay_main[k] ? 1 : 0;
-}
-
-void Sprite_58_Crab(int k) {  // 8594b5
-  static const int8 kCrab_Xvel[4] = {28, -28, 0, 0};
-  static const int8 kCrab_Yvel[4] = {0, 0, 12, -12};
-  Crab_Draw(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  if (Sprite_ReturnIfRecoiling(k))
-    return;
-  Sprite_CheckDamageToAndFromLink(k);
-  Sprite_MoveXY(k);
-  if (Sprite_CheckTileCollision(k) || !sprite_delay_main[k]) {
-    sprite_delay_main[k] = (GetRandomNumber() & 63) + 32;
-    sprite_D[k] = sprite_delay_main[k] & 3;
-  }
-  int j = sprite_D[k];
-  sprite_x_vel[k] = kCrab_Xvel[j & 3];
-  sprite_y_vel[k] = kCrab_Yvel[j & 3];
-  sprite_graphics[k] = (++sprite_subtype2[k] >> (j < 2 ? 1 : 3)) & 1;
-}
-
-void Crab_Draw(int k) {  // 859510
-  static const int16 kCrab_Draw_X[4] = {-8, 8, -8, 8};
-  static const uint8 kCrab_Draw_Char[4] = {0x8e, 0x8e, 0xae, 0xae};
-  static const int8 kCrab_Draw_Flags[4] = {0, 0x40, 0, 0x40};
-  PrepOamCoordsRet info;
-  if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
-    return;
-  OamEnt *oam = GetOamCurPtr();
-  int d = sprite_graphics[k] * 2;
-  for (int i = 1; i >= 0; i--, oam++) {
-    int j = d + i;
-    SetOamHelper0(oam, info.x + kCrab_Draw_X[j], info.y, kCrab_Draw_Char[j], kCrab_Draw_Flags[j] | info.flags, 2);
-  }
-  SpriteDraw_Shadow(k, &info);
-}
-
-void Sprite_57_DesertStatue(int k) {  // 85956d
-  static const uint8 kDesertBarrier_NextD[4] = {3, 2, 0, 1};
-  DesertBarrier_Draw(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  bool dmg = Sprite_CheckDamageToLink_same_layer(k);
-  if (dmg) {
-    Sprite_NullifyHookshotDrag();
-    Sprite_RepelDash();
-  }
-  if (sprite_delay_main[k] || sign8(sprite_ai_state[k]))
-    return;
-
-  if (sprite_ai_state[k] == 0) {
-    if (!byte_7E02F0)
-      return;
-    sprite_ai_state[k] = byte_7E02F0;
-    sprite_delay_main[k] = 128;
-    sound_effect_ambient = 7;
-  }
-
-  if (dmg && !link_incapacitated_timer) {
-    link_incapacitated_timer = 16;
-    Sprite_ApplySpeedTowardsLink(k, 32);
-  }
-
-  int j = sprite_D[k];
-  sprite_x_vel[k] = kDesertBarrier_Xv[j];
-  sprite_y_vel[k] = kDesertBarrier_Yv[j];
-  Sprite_MoveXY(k);
-  if (Sprite_CheckTileCollision(k))
-    sprite_D[k] = kDesertBarrier_NextD[sprite_D[k]];
-  flag_is_link_immobilized = 1;
-  if (!(++sprite_subtype2[k] & 1)) {
-    if (++sprite_G[k] == 130) {
-      sprite_ai_state[k] = 128;
-      flag_is_link_immobilized = 0;
-    }
-  }
-}
-
-void DesertBarrier_Draw(int k) {  // 859626
-  static const DrawMultipleData kDesertBarrier_Dmd[4] = {
-    {-8, -8, 0x008e, 2},
-    { 8, -8, 0x408e, 2},
-    {-8,  8, 0x00ae, 2},
-    { 8,  8, 0x40ae, 2},
-  };
-  if (sprite_delay_main[k] == 1) {
-    sound_effect_2 = 0x1b;
-    sound_effect_ambient = 5;
-  }
-  BYTE(cur_sprite_x) += (sprite_delay_main[k] >> 1) & 1;
-  PointU8 pt;
-  Sprite_DirectionToFaceLink(k, &pt);
-  if ((uint8)(pt.x + 0x20) < 0x40 && (uint8)(pt.y + 0x20) < 0x40)
-    Oam_AllocateFromRegionB(16);
-  Sprite_DrawMultiple(k, kDesertBarrier_Dmd, 4, NULL);
-}
-
-void Sprite_55_Zora(int k) {  // 85967b
-  if (sprite_E[k])
-    Sprite_Fireball(k);
-  else
-    Sprite_Zora_Main(k);
-}
-
-void Sprite_Fireball(int k) {  // 859683
-  static const uint8 kSprite_ZoraFireball_Offs[4] = {3, 2, 0, 0};
-  static const int8 kSprite_ZoraFireball_X[4] = {4, 4, -4, 16};
-  static const int8 kSprite_ZoraFireball_Y[4] = {0, 16, 8, 8};
-  static const uint8 kSprite_ZoraFireball_W[4] = {8, 8, 4, 4};
-  static const uint8 kSprite_ZoraFireball_H[4] = {4, 4, 8, 8};
-
-  sprite_ignore_projectile[k] = sprite_E[k];
-  if (sprite_delay_main[k])
-    Oam_AllocateFromRegionC(4);
-  SpriteDraw_SingleSmall(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  Fireball_SpawnTrailGarnish(k);
-  if (Sprite_CheckDamageToLink(k)) {
-    sprite_state[k] = 0;
-    return;
-  }
-  Sprite_MoveXY(k);
-  if (player_is_indoors && !sprite_delay_aux1[k] && !((k ^ frame_counter) & 3) && Sprite_CheckTileCollision(k)) {
-    sprite_state[k] = 0;
-    return;
-  }
-
-  if ((link_is_bunny_mirror | link_disable_sprite_damage) || sign8(link_state_bits) || link_shield_type < 2 ||
-      link_is_on_lower_level != sprite_floor[k])
-    return;
-  SpriteHitBox hb;
-  Sprite_SetupHitBox(k, &hb);
-  int j = link_direction_facing >> 1;
-  if (button_b_frames)
-    j = kSprite_ZoraFireball_Offs[j];
-  int x = link_x_coord + kSprite_ZoraFireball_X[j], y = link_y_coord + kSprite_ZoraFireball_Y[j];
-  hb.r0_xlo = x;
-  hb.r8_xhi = x >> 8;
-  hb.r2 = kSprite_ZoraFireball_W[j];
-  hb.r1_ylo = y;
-  hb.r9_yhi = y >> 8;
-  hb.r3 = kSprite_ZoraFireball_H[j];
-  if (CheckIfHitBoxesOverlap(&hb)) {
-    Sprite_PlaceRupulseSpark_2(k);
-    sprite_state[k] = 0;
-    SpriteSfx_QueueSfx2WithPan(k, 0x6);
-  }
-}
-
-void Sprite_Zora_Main(int k) {  // 859725
-  static const int8 kSprite_Zora_Surface_XY[8] = {-32, -24, -16, -8, 8, 16, 24, 32};
-  static const uint8 kSprite_Zora_AttackGfx[8] = {5, 5, 6, 10, 6, 5, 5, 5};
-  static const uint8 kSprite_Zora_SubmergeGfx[12] = {12, 11, 9, 8, 7, 0, 0, 0, 0, 0, 0, 0};
-  PrepOamCoordsRet info;
-  if (!sprite_ai_state[k])
-    Sprite_PrepOamCoord(k, &info);
-  else
-    Zora_Draw(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  switch (sprite_ai_state[k]) {
-  case 0:  // choose surfacing location
-    sprite_ignore_projectile[k] = sprite_delay_main[k];
-    if (!sprite_delay_main[k]) {
-      int org_x = (sprite_A[k] | sprite_B[k] << 8);
-      int org_y = (sprite_C[k] | sprite_head_dir[k] << 8);
-      Sprite_SetX(k, org_x + kSprite_Zora_Surface_XY[GetRandomNumber() & 7]);
-      Sprite_SetY(k, org_y + kSprite_Zora_Surface_XY[GetRandomNumber() & 7]);
-      Sprite_Get16BitCoords(k);
-      Sprite_CheckTileCollision(k);
-      if (sprite_tiletype == 8) spawn_anyway: {
-        sprite_delay_main[k] = 127;
-        sprite_ai_state[k]++;
-        sprite_flags3[k] |= 0x40;
-      } else {
-        // In Misery Mire some Zoras are placed in shallow water so they can't spawn
-        // This fixes so they will be able to spawn in shallow water after a delay.
-        if (enhanced_features0 & kFeatures0_GameChangingBugFixes) {
-          if (sprite_tiletype == 9 && sprite_delay_aux2[k] == 1)
-            goto spawn_anyway;
-          Sprite_SetX(k, org_x);
-          Sprite_SetY(k, org_y);
-          sprite_ignore_projectile[k] = 1;
-          if (sprite_delay_aux2[k] == 0)
-            sprite_delay_aux2[k] = 32;
-        }
-      }
-    }
-    break;
-  case 1:  // surfacing
-    sprite_ignore_projectile[k] = sprite_delay_main[k];
-    if (!sprite_delay_main[k]) {
-      sprite_ai_state[k]++;
-      sprite_delay_main[k] = 127;
-      sprite_flags3[k] &= ~0x40;
-    } else {
-      sprite_graphics[k] = kSprite_Zora_SurfacingGfx[sprite_delay_main[k] >> 3];
-    }
-    break;
-  case 2:  // attack
-    Sprite_CheckDamageToAndFromLink(k);
-    if (!sprite_delay_main[k]) {
-      sprite_ai_state[k]++;
-      sprite_delay_main[k] = 23;
-    } else {
-      if (sprite_delay_main[k] == 48)
-        Sprite_SpawnFireball(k);
-      sprite_graphics[k] = kSprite_Zora_AttackGfx[sprite_delay_main[k] >> 4];
-    }
-    break;
-  case 3:  // submerging
-    if (!sprite_delay_main[k]) {
-      sprite_delay_main[k] = 128;
-      sprite_graphics[k] = 0;
-      sprite_ai_state[k] = 0;
-    } else {
-      sprite_graphics[k] = kSprite_Zora_SubmergeGfx[sprite_delay_main[k] >> 2];
-    }
-    break;
-  }
-}
-
-void Zora_Draw(int k) {  // 8598f5
-  static const int8 kZora_Draw_X[26] = {
-    4, 4,  0,  0, 0, 0,  0,  0,  0,  0, 0, 0, 0, 0, 0, 0,
-    0, 0, -4, 11, 0, 4, -8, 18, -8, 18,
-  };
-  static const int8 kZora_Draw_Y[26] = {
-    4,  4,  0,  0,  0, 0,   0,  -3,   0,  -3, -3, -3, -3, -3, -3, -3,
-    -6, -6, -8, -9, -3, 5, -10, -11, -10, -11,
-  };
-  static const uint8 kZora_Draw_Char[26] = {
-    0xa8, 0xa8, 0x88, 0x88, 0x88, 0x88, 0x88, 0xa4, 0x88, 0xa4, 0xa4, 0xa4, 0xa6, 0xa6, 0xa4, 0xc0,
-    0x8a, 0x8a, 0xae, 0xaf, 0xa6, 0x8d, 0xcf, 0xcf, 0xdf, 0xdf,
-  };
-  static const uint8 kZora_Draw_Flags[26] = {
-    0x25, 0x25, 0x25, 0x25, 0xe5, 0xe5, 0x25, 0x20, 0xe5, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x24,
-    0x25, 0x25, 0x24, 0x64, 0x20, 0x26, 0x24, 0x64, 0x24, 0x64,
-  };
-  static const uint8 kZora_Draw_Big[26] = {
-    0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-    2, 2, 0, 0, 2, 0, 0, 0, 0, 0,
-  };
-  PrepOamCoordsRet info;
-  if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
-    return;
-  OamEnt *oam = GetOamCurPtr();
-  int d = sprite_graphics[k] * 2;
-  for (int i = 1; i >= 0; i--, oam++) {
-    int j = d + i;
-    uint8 f = kZora_Draw_Flags[j];
-    SetOamHelper0(oam, info.x + kZora_Draw_X[j], info.y + kZora_Draw_Y[j], kZora_Draw_Char[j], f | (f & 0xf ? 0 : info.flags), kZora_Draw_Big[j]);
-  }
-}
-
-void Sprite_52_KingZora(int k) {  // 85995b
-  ZoraKing_Draw(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  switch(sprite_ai_state[k]) {
-  case 0:  // WaitingForPlayer
-    if ((uint16)(link_x_coord - cur_sprite_x + 16) < 32 && (uint16)(link_y_coord - cur_sprite_y + 48) < 96) {
-      Link_CancelDash();
-      sprite_delay_main[k] = 127;
-      sound_effect_1 = 0x35;
-      sprite_ai_state[k] = 1;
-      for (int j = 15; j >= 0; j--) {
-        if (j != k && !(sprite_defl_bits[j] & 0x80)) {
-          if (sprite_state[j] == 10) {
-            link_state_bits = 0;
-            link_picking_throw_state = 0;
-          }
-          Sprite_KillSelf(j);
-        }
-      }
-    }
-    break;
-  case 1:  // RumblingGround
-    if (!sprite_delay_main[k]) {
-      sprite_ai_state[k] = 2;
-      sprite_delay_main[k] = 127;
-      bg1_x_offset = 0;
-      sprite_graphics[k] = 4;
-    } else {
-      bg1_x_offset = sprite_delay_main[k] & 1 ? -1 : 1;
-      flag_is_link_immobilized = 1;
-    }
-    break;
-  case 2: {  // Surfacing
-    static const uint8 kZoraKing_Surfacing_Gfx[16] = {0, 0, 0, 3, 9, 8, 7, 6, 9, 8, 7, 6, 5, 4, 5, 4};
-    if (!sprite_delay_main[k]) {
-      sprite_ai_state[k] = 3;
-      sprite_delay_main[k] = 127;
-    } else {
-      if (sprite_delay_main[k] == 28) {
-        sprite_delay_aux2[k] = 15;
-        Sprite_SpawnBigSplash(k);
-      }
-      sprite_graphics[k] = kZoraKing_Surfacing_Gfx[sprite_delay_main[k] >> 3];
-    }
-    break;
-  }
-  case 3: { // Dialogue
-    static const uint8 kZoraKing_Dialogue_Gfx[8] = {0, 0, 1, 2, 1, 2, 0, 0};
-    int j = sprite_delay_main[k];
-    if (!j) {
-      sprite_ai_state[k] = 4;
-      sprite_delay_main[k] = 36;
-      return;
-    }
-    sprite_graphics[k] = kZoraKing_Dialogue_Gfx[j >> 4];
-    if (j == 80) {
-      dialogue_message_index = 0x142;
-      Sprite_ShowMessageMinimal();
-    } else if (j == 79) {
-      if (choice_in_multiselect_box == 0) {
-        dialogue_message_index = 0x143;
-        Sprite_ShowMessageMinimal();
-      } else {
-        dialogue_message_index = 0x146;
-        Sprite_ShowMessageMinimal();
-        sprite_delay_main[k] = 0x30;
-      }
-    } else if (j == 78) {
-      if (choice_in_multiselect_box == 0 && link_rupees_goal >= 500) {
-        link_rupees_goal -= 500;
-        dialogue_message_index = 0x144;
-        Sprite_ShowMessageMinimal();
-        sprite_E[k] = 1;
-      } else {
-        dialogue_message_index = 0x145;
-        Sprite_ShowMessageMinimal();
-        sprite_delay_main[k] = 0x30;
-      }
-    } else if (j == 77) {
-      if (sprite_E[k])
-        Sprite_Zora_RegurgitateFlippers(k);
-    }
-    break;
-  }
-  case 4: {  // Submerge
-    static const uint8 kZoraKing_Submerge_Gfx[21] = {
-      12, 12, 12, 12, 12, 12, 11, 11, 11, 11, 11, 10, 10, 10, 10, 3,
-      3,  3,  3,  3,  3,
-    };
-    int j = sprite_delay_main[k];
-    if (!j) {
-      Sprite_KillSelf(k);
-      flag_is_link_immobilized = 0;
-    } else {
-      if (j == 29) {
-        sprite_delay_aux2[k] = 15;
-        Sprite_SpawnBigSplash(k);
-      }
-      sprite_graphics[k] = kZoraKing_Submerge_Gfx[sprite_delay_main[k] >> 1];
-    }
-    break;
-  }
-  }
-}
-
-void Sprite_SpawnBigSplash(int k) {  // 859b40
-  static const int8 kSpawnSplashRing_X[8] = {-8, -5, 4, 13, 16, 13, 4, -5};
-  static const int8 kSpawnSplashRing_Y[8] = {4, -5, -8, -5, 4, 13, 16, 13};
-  static const int8 kSpawnSplashRing_Xvel[8] = {-8, -6, 0, 6, 8, 6, 0, -6};
-  static const int8 kSpawnSplashRing_Yvel[8] = {0, -6, -8, -6, 0, 6, 8, 6};
-  SpriteSfx_QueueSfx2WithPan(k, 0x24);
-
-  for (int i = 7; i >= 0; i--) {
-    SpriteSpawnInfo info;
-    int j = Sprite_SpawnDynamically(k, 8, &info);
-    if (j >= 0) {
-      sprite_state[j] = 3;
-      Sprite_SetX(j, info.r0_x + kSpawnSplashRing_X[i] - 4);
-      Sprite_SetY(j, info.r2_y + kSpawnSplashRing_Y[i] - 4);
-      sprite_x_vel[j] = kSpawnSplashRing_Xvel[i];
-      sprite_y_vel[j] = kSpawnSplashRing_Yvel[i];
-      sprite_A[j] = i;
-      sprite_z_vel[j] = (GetRandomNumber() & 15) + 24;
-      sprite_ai_state[j] = 1;
-      sprite_z[j] = 0;
-      sprite_flags3[j] |= 0x40;
-      sprite_ignore_projectile[j] = sprite_flags3[j];
-    }
-  }
-}
-
-void ZoraKing_Draw(int k) {  // 859cab
-  PrepOamCoordsRet info;
-  if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
-    return;
-
-  if (sprite_ai_state[k] >= 2) {
-    static const int8 kZoraKing_Draw_X0[52] = {
-      -8,  8,  -8,  8, -8, 8, -8, 8, -8, 8, -8, 8,  -8,  8,  -8,  8,
-      0,  0,   0,  0,  0, 0,  0, 0, -8, 8, -8, 8,  -8,  8,  -8,  8,
-      -8,  8,  -8,  8, -8, 8, -8, 8, -9, 9, -9, 9, -10, 10, -10, 10,
-      -11, 11, -11, 11,
-    };
-    static const int8 kZoraKing_Draw_Y0[52] = {
-      -18, -18, -2, -2, -18, -18, -2, -2, -18, -18, -2, -2, -12, -12, 4, 4,
-      0,   0,  0,  0,   0,   0,  0,  0,  -8,  -8,  8,  8,  -8,  -8, 8, 8,
-      -8,  -8,  8,  8,  -8,  -8,  8,  8,  -5,  -5,  5,  5,  -5,  -5, 5, 5,
-      -5,  -5,  5,  5,
-    };
-    static const uint8 kZoraKing_Draw_Char0[52] = {
-      0xc0, 0xc0, 0xe0, 0xe0, 0xc2, 0xea, 0xe2, 0xe2, 0xea, 0xc2, 0xe2, 0xe2, 0xc0, 0xc0, 0xe4, 0xe6,
-      0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0xc4, 0xc6, 0xe4, 0xe6, 0xc6, 0xc4, 0xe6, 0xe4,
-      0xe6, 0xe4, 0xc6, 0xc4, 0xe4, 0xe6, 0xc4, 0xc6, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
-      0x88, 0x88, 0x88, 0x88,
-    };
-    static const uint8 kZoraKing_Draw_Flags0[52] = {
-      0, 0x40,    0, 0x40,    0, 0x40,    0, 0x40, 0, 0x40,    0, 0x40,    0, 0x40,    5,    5,
-      5,    5,    5,    5, 0xc5, 0xc5, 0xc5, 0xc5, 5,    5,    5,    5, 0x45, 0x45, 0x45, 0x45,
-      0xc5, 0xc5, 0xc5, 0xc5, 0x85, 0x85, 0x85, 0x85, 4, 0x44, 0x84, 0xc4,    4, 0x44, 0x84, 0xc4,
-      4, 0x44, 0x84, 0xc4,
-    };
-    OamEnt *oam = GetOamCurPtr();
-    int g = sprite_graphics[k];
-    for (int i = 3; i >= 0; i--, oam++) {
-      int j = g * 4 + i;
-      oam->x = kZoraKing_Draw_X0[j] + info.x;
-      oam->y = kZoraKing_Draw_Y0[j] + info.y;
-      oam->charnum = kZoraKing_Draw_Char0[j];
-      uint8 f = kZoraKing_Draw_Flags0[j];
-      oam->flags = (f & 0xf ? f : f | info.flags) | 0x20;
-    }
-    Sprite_CorrectOamEntries(k, 3, 2);
-    if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
-      return;
-  }
-
-  if (!sprite_delay_aux2[k])
-    return;
-
-  static const int8 kZoraKing_Draw_X1[8] = {-23, 23, 23, 23, -20, -15, 13, 18};
-  static const int8 kZoraKing_Draw_Y1[8] = {-8, -8, -8, -8, -7, 0, 0, -7};
-  static const uint8 kZoraKing_Draw_Char1[8] = {0xae, 0xae, 0xae, 0xae, 0xac, 0xac, 0xac, 0xac};
-  static const uint8 kZoraKing_Draw_Flags1[8] = {0, 0x40, 0x40, 0x40, 0, 0, 0x40, 0x40};
-  Oam_AllocateFromRegionC(0x10);
-  OamEnt *oam = GetOamCurPtr();
-  int g = (sprite_delay_aux2[k] >> 1) & 4;
-  for (int i = 3; i >= 0; i--, oam++) {
-    int j = g + i;
-    SetOamPlain(oam, kZoraKing_Draw_X1[j] + info.x, kZoraKing_Draw_Y1[j] + info.y,
-                 kZoraKing_Draw_Char1[j], kZoraKing_Draw_Flags1[j] | 0x24, 2);
-  }
-}
-
-void Sprite_56_WalkingZora(int k) {  // 859d4a
-  if (sprite_F[k]) {
-    sprite_F[k] = 0;
-    sprite_B[k] = 3;
-    sprite_G[k] = 192;
-    sprite_x_vel[k] = (int8)sprite_x_recoil[k] >> 1;
-    sprite_y_vel[k] = (int8)sprite_y_recoil[k] >> 1;
-  }
-  PrepOamCoordsRet info;
-  switch(sprite_B[k]) {
-  case 0:  // Waiting
-    Sprite_PrepOamCoord(k, &info);
-    if (Sprite_ReturnIfInactive(k))
-      return;
-    if (!sprite_delay_main[k]) {
-      sprite_delay_main[k] = 127;
-      sprite_B[k]++;
-      sprite_flags3[k] |= 64;
-    }
-    break;
-  case 1:  // Surfacing
-    Zora_Draw(k);
-    if (Sprite_ReturnIfInactive(k))
-      return;
-    sprite_ignore_projectile[k] = sprite_delay_main[k];
-    if (!sprite_delay_main[k]) {
-      sprite_flags3[k] &= ~0x40;
-      SpriteSfx_QueueSfx2WithPan(k, 0x28);
-      sprite_B[k]++;
-      sprite_z_vel[k] = 48;
-      sprite_head_dir[k] = sprite_D[k] = Sprite_DirectionToFaceLink(k, NULL);
-    } else {
-      sprite_graphics[k] = kSprite_Zora_SurfacingGfx[sprite_delay_main[k] >> 3];
-    }
-    break;
-  case 2:  // Ambulating
-    sprite_graphics[k] = kSprite_Recruit_Gfx[(sprite_subtype2[k] >> 1 & 4) + sprite_D[k]];
-    WalkingZora_Draw(k);
-    if (Sprite_ReturnIfInactive(k))
-      return;
-    Sprite_CheckDamageToAndFromLink(k);
-    Sprite_MoveZ(k);
-    sprite_z_vel[k] -= 2;
-    if (sign8(sprite_z[k] - 1)) {
-      if (sign8(sprite_z_vel[k] + 16))
-        Sprite_ZeroVelocity_XY(k);
-      sprite_z[k] = 0;
-      sprite_z_vel[k] = 0;
-      if (!((k ^ frame_counter) & 15)) {
-        int j = Sprite_DirectionToFaceLink(k, NULL);
-        sprite_head_dir[k] = j;
-        if (!((k ^ frame_counter) & 31)) {
-          sprite_D[k] = j;
-          Sprite_ApplySpeedTowardsLink(k, 8);
-        }
-      }
-    }
-    Sprite_MoveXY(k);
-    Sprite_CheckTileCollision(k);
-    if (sign8(sprite_z[k] - 1)) {
-      WalkingZora_AdjustShadow(k);
-      if (sprite_tiletype == 8) {
-        Sprite_KillSelf(k);
-        SpriteSfx_QueueSfx2WithPan(k, 0x28);
-        sprite_state[k] = 3;
-        sprite_delay_main[k] = 15;
-        sprite_ai_state[k] = 0;
-        sprite_flags2[k] = 3;
-      }
-    }
-    sprite_subtype2[k]++;
-    break;
-  case 3:  // Depressed
-    Sprite_CheckDamageFromLink(k);
-    if (!(frame_counter & 3) && !--sprite_G[k]) {
-      sprite_B[k] = 2;
-      if (sprite_state[k] == 10) {
-        link_state_bits = 0;
-        link_picking_throw_state = 0;
-      }
-      sprite_state[k] = 9;
-    }
-    if (sprite_G[k] < 48 && !(frame_counter & 1))
-      Sprite_SetX(k, Sprite_GetX(k) + (frame_counter & 2 ? -1 : 1));
-    sprite_graphics[k] = 0;
-    sprite_wallcoll[k] = 0;
-    WalkingZora_DrawWaterRipples(k);
-    sprite_flags2[k] -= 2;
-    SpriteDraw_SingleLarge(k);
-    sprite_flags2[k] += 2;
-    sprite_anim_clock[k] = 0;
-    if (Sprite_ReturnIfInactive(k))
-      return;
-    if (Sprite_ReturnIfRecoiling(k))
-      return;
-    Sprite_MoveXY(k);
-    ThrownSprite_TileAndSpriteInteraction(k);
-    WalkingZora_AdjustShadow(k);
-    break;
-  }
-}
-
-void WalkingZora_AdjustShadow(int k) {  // 859edb
-  sprite_anim_clock[k] = (sprite_z[k] == 0 && sprite_tiletype == 9);
-}
-
-void WalkingZora_Draw(int k) {  // 859f08
-  static const uint8 kWalkingZora_Draw_Char[4] = {0xce, 0xce, 0xa4, 0xee};
-  static const uint8 kWalkingZora_Draw_Flags[4] = {0x40, 0, 0, 0};
-  static const uint8 kWalkingZora_Draw_Char2[8] = {0xcc, 0xec, 0xcc, 0xec, 0xe8, 0xe8, 0xca, 0xca};
-  static const uint8 kWalkingZora_Draw_Flags2[8] = {0x40, 0x40, 0, 0, 0, 0x40, 0, 0x40};
-
-  PrepOamCoordsRet info;
-  WalkingZora_DrawWaterRipples(k);
-  if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
-    return;
-  OamEnt *oam = GetOamCurPtr();
-  int g = sprite_graphics[k];
-  if (g == 0 || g == 2)
-    info.y--;
-
-  int i = sprite_head_dir[k];
-  SetOamHelper0(oam + 0, info.x, info.y - 6, kWalkingZora_Draw_Char[i], info.flags | kWalkingZora_Draw_Flags[i], 2);
-  SetOamHelper0(oam + 1, info.x, info.y + 2, kWalkingZora_Draw_Char2[g], info.flags | kWalkingZora_Draw_Flags2[g], 2);
-
-  if (!sprite_anim_clock[k])
-    SpriteDraw_Shadow(k, &info);
-}
-
-void WalkingZora_DrawWaterRipples(int k) {  // 859fe0
-  if (sprite_anim_clock[k])
-    SpriteDraw_WaterRipple_WithOamAdjust(k);
-}
-
-void SpriteDraw_WaterRipple_WithOamAdjust(int k) {  // 859fe5
-  SpriteDraw_WaterRipple(k);
-  oam_cur_ptr += 8;
-  oam_ext_cur_ptr += 2;
-}
-
-void SpriteDraw_WaterRipple(int k) {  // 859ffa
-  static const DrawMultipleData kWaterRipple_Dmd[6] = {
-    {0, 10, 0x01d8, 0},
-    {8, 10, 0x41d8, 0},
-    {0, 10, 0x01d9, 0},
-    {8, 10, 0x41d9, 0},
-    {0, 10, 0x01da, 0},
-    {8, 10, 0x41da, 0},
-  };
-  static const uint8 kWaterRipple_Idx[4] = {0, 1, 2, 1};
-  Sprite_DrawMultiple(k, &kWaterRipple_Dmd[kWaterRipple_Idx[frame_counter >> 2 & 3] * 2], 2, NULL);
-  OamEnt *oam = GetOamCurPtr();
-  uint8 t = (oam[0].flags & 0x30) | 0x4;
-  oam[0].flags = t;
-  oam[1].flags = t | 0x40;
-}
-
-void Sprite_53_ArmosKnight(int k) {  // 85a036
-  static const uint8 kArmosKnight_Gfx1[5] = {5, 4, 3, 2, 1};
-  static const int8 kArmosKnight_Xv[2] = {16, -16};
-
-  sprite_obj_prio[k] |= 0x30;
-  ArmosKnight_Draw(k);
-  if (Sprite_ReturnIfPaused(k))
-    return;
-  if (sprite_state[k] != 9) {
-    if (sprite_delay_main[k]) {
-      sprite_graphics[k] = kArmosKnight_Gfx1[sprite_delay_main[k] >> 3];
-      return;
-    }
-    if (--byte_7E0FF8 == 1) {
-      for (int j = 5; j >= 0; j--) {
-        sprite_health[j] = 48;
-        sprite_x_vel[j] = sprite_y_vel[j] = sprite_z_vel[j] = 0;
-      }
-    }
-    sprite_state[k] = 0;
-    if (Sprite_CheckIfScreenIsClear()) {
-      SpriteSpawnInfo info;
-      int j = Sprite_SpawnDynamically(k, 0xea, &info);
-      assert(j >= 0);
-      Sprite_SetSpawnedCoordinates(j, &info);
-      sprite_z_vel[j] = 32;
-      sprite_A[j] = 1;
-    }
-    return;
-  }
-  Sprite_MoveXY(k);
-  Sprite_MoveZ(k);
-  sprite_z_vel[k] -= 4;
-  if (sign8(sprite_z[k])) {
-    sprite_z_vel[k] = 0;
-    sprite_z[k] = 0;
-    if (byte_7E0FF8 != 1 && sprite_A[k]) {
-      sprite_z_vel[k] = 48;
-      SpriteSfx_QueueSfx3WithPan(k, 0x16);
-    }
-  }
-  if (sprite_F[k]) {
-    Sprite_ZeroVelocity_XY(k);
-    sprite_ai_state[k] = 0;
-    sprite_G[k] = 0;
-  }
-  if (Sprite_ReturnIfRecoiling(k))
-    return;
-  if (!sprite_A[k]) {
-    if (!sprite_delay_main[k]) {
-      sprite_A[k]++;
-      sprite_flags2[k] = (sprite_flags2[k] & 0x7f) - 2;
-      sprite_defl_bits[k] &= ~4;
-      sprite_flags3[k] &= ~0x40;
-    } else {
-      if (sprite_delay_main[k] == 64) {
-        sound_effect_1 = 0x35;
-      } else if (sprite_delay_main[k] < 64) {
-        int j = ((sprite_delay_main[k] >> 1) ^ k) & 1;
-        sprite_x_vel[k] = kArmosKnight_Xv[j];
-        Sprite_MoveX(k);
-        sprite_x_vel[k] = 0;
-      }
-      Sprite_CheckDamageFromLink(k);
-      if (Sprite_CheckDamageToLink_same_layer(k)) {
-        Sprite_NullifyHookshotDrag();
-        Sprite_RepelDash();
-      }
-    }
-  } else if (byte_7E0FF8 == 1) {
-    Sprite_ArmosCrusher(k);
-  } else {
-    Sprite_CheckDamageToAndFromLink(k);
-    if (!sprite_ai_state[k]) {
-      uint16 x = overlord_y_hi[k] << 8 | overlord_x_hi[k];
-      uint16 y = overlord_floor[k] << 8 | overlord_gen2[k];
-      ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLocation(k, x, y, 16);
-      sprite_x_vel[k] = pt.x;
-      sprite_y_vel[k] = pt.y;
-      Sprite_Get16BitCoords(k);
-      if ((uint16)(x - cur_sprite_x + 2) < 4 && (uint16)(y - cur_sprite_y + 2) < 4)
-        sprite_ai_state[k] = 1;
-    } else {
-      sprite_x_lo[k] = overlord_x_hi[k];
-      sprite_x_hi[k] = overlord_y_hi[k];
-      sprite_y_lo[k] = overlord_gen2[k];
-      sprite_y_hi[k] = overlord_floor[k];
-    }
-  }
-}
-
-void ArmosKnight_Draw(int k) {  // 85a274
-  static const int8 kArmosKnight_Draw_X[24] = {
-    -8,  8,  -8,  8, -10, 10, -10, 10, -10, 10, -10, 10, -12, 12, -12, 12,
-    -14, 14, -14, 14, -16, 24, -16, 24,
-  };
-  static const int8 kArmosKnight_Draw_Y[24] = {
-    -8,  -8,  8,  8, -10, -10, 10, 10, -10, -10, 10, 10, -12, -12, 12, 12,
-    -14, -14, 14, 14, -16, -16, 24, 24,
-  };
-  static const uint8 kArmosKnight_Draw_Char[24] = {
-    0xc0, 0xc2, 0xe0, 0xe2, 0xc0, 0xc2, 0xe0, 0xe2, 0xc4, 0xc4, 0xc4, 0xc4, 0xc6, 0xc6, 0xc6, 0xc6,
-    0xc8, 0xc8, 0xc8, 0xc8, 0xd8, 0xd8, 0xd8, 0xd8,
-  };
-  static const uint8 kArmosKnight_Draw_Flags[24] = {
-    0, 0,    0,    0,    0, 0,    0,    0, 0x40, 0, 0xc0, 0x80, 0x40, 0, 0xc0, 0x80,
-    0x40, 0, 0xc0, 0x80, 0x40, 0, 0xc0, 0x80,
-  };
-  static const uint8 kArmosKnight_Draw_Big[24] = {
-    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-    2, 2, 2, 2, 0, 0, 0, 0,
-  };
-
-  PrepOamCoordsRet info;
-  if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
-    return;
-  if (!sprite_A[k] && submodule_index != 7)
-    Oam_AllocateDeferToPlayer(k);
-  OamEnt *oam = GetOamCurPtr();
-  int g = sprite_graphics[k];
-  for (int i = 3; i >= 0; i--, oam++) {
-    int j = g * 4 + i;
-    SetOamHelper0(oam, info.x + kArmosKnight_Draw_X[j], info.y + kArmosKnight_Draw_Y[j],
-                  kArmosKnight_Draw_Char[j], kArmosKnight_Draw_Flags[j] | info.flags,
-                  kArmosKnight_Draw_Big[j]);
-  }
-  if (g != 0)
-    return;
-  if (sprite_A[k]) {
-    int spr_idx = 76 + k * 2;
-    oam_cur_ptr = 0x800 + spr_idx * 4;
-    oam_ext_cur_ptr = 0xA20 + spr_idx;
-  }
-  oam = GetOamCurPtr();
-  int z = sprite_z[k];
-  z = ((z >= 32) ? 32 : z) >> 3;
-  uint16 y = Sprite_GetY(k) - BG2VOFS_copy2;
-  SetOamHelper0(oam + 4, info.x - 8 + z, y + 12, 0xe4, 0x25, 2);
-  SetOamHelper0(oam + 5, info.x + 8 - z, y + 12, 0xe4, 0x25 | 0x40, 2);
-}
-
-void Sprite_54_Lanmolas(int k) {  // 85a3a2
-  static const uint8 kLanmola_RandB[8] = {0x58, 0x50, 0x60, 0x70, 0x80, 0x90, 0xa0, 0x98};
-  static const uint8 kLanmola_RandC[8] = {0x68, 0x60, 0x70, 0x80, 0x90, 0xa0, 0xa8, 0x80};
-  static const int8 kLanmola_ZVel[2] = {2, -2};
-  PrepOamCoordsRet info;
-  Sprite_PrepOamCoord(k, &info);
-  Lanmola_Draw(k);
-  if (Sprite_ReturnIfPaused(k))
-    return;
-  switch(sprite_ai_state[k]) {
-  case 0:
-    if (!(sprite_delay_main[k] | sprite_pause[k])) {
-      sprite_delay_main[k] = 127;
-      sprite_ai_state[k] = 1;
-      SpriteSfx_QueueSfx2WithPan(k, 0x35);
-    }
-    break;
-  case 1:
-    if (!sprite_delay_main[k]) {
-      Lanmola_SpawnShrapnel(k);
-      sound_effect_ambient = 0x13;
-      sprite_B[k] = kLanmola_RandB[GetRandomNumber() & 7];
-      sprite_C[k] = kLanmola_RandC[GetRandomNumber() & 7];
-      sprite_ai_state[k] = 2;
-      sprite_z_vel[k] = 24;
-      sprite_anim_clock[k] = 0;
-      sprite_G[k] = 0;
-lbl_a:
-      sprite_D[k] = sprite_x_lo[k];
-      sprite_wallcoll[k] = sprite_y_lo[k];
-      sprite_delay_aux1[k] = 74;
-    }
-    break;
-  case 2: {
-    Sprite_CheckDamageToAndFromLink(k);
-    Sprite_MoveZ(k);
-    if (!sprite_anim_clock[k]) {
-      if (!--sprite_z_vel[k])
-        sprite_anim_clock[k]++;
-    } else if ((frame_counter & 1) == 0) {
-      int j = sprite_G[k] & 1;
-      if ((sprite_z_vel[k] += kLanmola_ZVel[j]) == (uint8)kDesertBarrier_Xv[j])
-        sprite_G[k]++;
-    }
-    uint16 x = Sprite_GetX(k), y = Sprite_GetY(k);
-    uint16 x2 = sprite_x_hi[k] << 8 | sprite_B[k];
-    uint16 y2 = sprite_y_hi[k] << 8 | sprite_C[k];
-    if ((uint16)(x - x2 + 2) < 4 && (uint16)(y - y2 + 2) < 4)
-      sprite_ai_state[k] = 3;
-    ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLocation(k, x2, y2, 10);
-    sprite_y_vel[k] = pt.y;
-    sprite_x_vel[k] = pt.x;
-    Sprite_MoveXY(k);
-    break;
-  }
-  case 3:
-    Sprite_CheckDamageToAndFromLink(k);
-    Sprite_MoveXY(k);
-    Sprite_MoveZ(k);
-    if (!sign8(sprite_z_vel[k] + 20))
-      sprite_z_vel[k] -= 1;
-    if (sign8(sprite_z[k])) {
-      sprite_ai_state[k] = 4;
-      sprite_delay_main[k] = 128;
-      goto lbl_a;
-    }
-    break;
-  case 4:
-    if (!sprite_delay_main[k]) {
-      sprite_ai_state[k] = 0;
-      sprite_x_lo[k] = kLanmola_RandB[GetRandomNumber() & 7];
-      sprite_y_lo[k] = kLanmola_RandC[GetRandomNumber() & 7];
-    }
-    break;
-  case 5:
-    if (!sprite_delay_main[k]) {
-      sprite_state[k] = 0;
-      if (Sprite_CheckIfScreenIsClear()) {
-        SpriteSpawnInfo info;
-        int j = Sprite_SpawnDynamically(k, 0xEA, &info);
-        assert(j >= 0);
-        Sprite_SetSpawnedCoordinates(j, &info);
-        sprite_z_vel[j] = 32;
-        sprite_A[j] = 3;
-      }
-    }
-    if (sprite_delay_main[k] >= 32 && sprite_delay_main[k] < 160 && !(sprite_delay_main[k] & 15)) {
-      int i = ((sprite_subtype2[k] - garnish_y_lo[k] * 8) & 0x3f) + k * 0x40;
-      uint8 xlo = moldorm_x_lo[i] - BG2HOFS_copy2;
-      uint8 ylo = moldorm_y_lo[i] - beamos_x_hi[i] - BG2VOFS_copy2;
-      SpriteSpawnInfo info;
-      int j = Sprite_SpawnDynamically(k, 0x00, &info);
-      if (j >= 0) {
-        load_chr_halfslot_even_odd = 11;
-        sprite_state[j] = 4;
-        sprite_delay_main[j] = 31;
-        sprite_A[j] = 31;
-        Sprite_SetX(j, BG2HOFS_copy2 + xlo);
-        Sprite_SetY(j, BG2VOFS_copy2 + ylo);
-        sprite_flags2[j] = 3;
-        sprite_oam_flags[j] = 0xc;
-        SpriteSfx_QueueSfx2WithPan(k, 0xc);
-        if (!sign8(garnish_y_lo[k]))
-          garnish_y_lo[k]--;
-      }
-    }
-    break;
-  }
-}
-
-void Lanmola_Draw(int k) {  // 85a64a
-  static const uint8 kLanmola_SprOffs[4] = {76, 60, 44, 28};
-  static const uint8 kLanmola_Draw_Char1[16] = {0xc4, 0xe2, 0xc2, 0xe0, 0xc0, 0xe0, 0xc2, 0xe2, 0xc4, 0xe2, 0xc2, 0xe0, 0xc0, 0xe0, 0xc2, 0xe2};
-  static const uint8 kLanmola_Draw_Char0[16] = {0xcc, 0xe4, 0xca, 0xe6, 0xc8, 0xe6, 0xca, 0xe4, 0xcc, 0xe4, 0xca, 0xe6, 0xc8, 0xe6, 0xca, 0xe4};
-  static const uint8 kLanmola_Draw_Flags[16] = {0xc0, 0xc0, 0xc0, 0xc0, 0x80, 0x80, 0x80, 0x80, 0, 0, 0, 0, 0x40, 0x40, 0x40, 0x40};
-
-  int spr_offs = kLanmola_SprOffs[k];
-  oam_cur_ptr = 0x800 + spr_offs * 4;
-  oam_ext_cur_ptr = 0xA20 + spr_offs;
-  sprite_graphics[k] = Sprite_ConvertVelocityToAngle(sprite_x_vel[k], sprite_y_vel[k] - sprite_z_vel[k]);
-  uint8 r2 = sprite_subtype2[k], r5 = r2;
-  int j = k * 64 + r2;
-  moldorm_x_lo[j] = sprite_x_lo[k];
-  moldorm_y_lo[j] = sprite_y_lo[k];
-  beamos_x_hi[j] = sprite_z[k];
-  beamos_y_hi[j] = sprite_graphics[k];
-  if (sprite_state[k] == 9 && !(submodule_index | flag_unk1))
-    sprite_subtype2[k] = sprite_subtype2[k] + 1 & 63;
-  uint8 r3 = sprite_oam_flags[k] | sprite_obj_prio[k];
-  uint8 n = garnish_y_lo[k];
-  if (sign8(n))
-    return;
-  j = sign8(sprite_y_vel[k]) ? 1 : 0;
-  int oam_step = (j ? -1 : 1);
-  OamEnt *oam = GetOamCurPtr() + (j ? 7 : 0);
-  uint8 i = n;
-  do {
-    int j = r2 + k * 64;
-    r2 = r2 - 8 & 63;
-    oam->x = moldorm_x_lo[j] - BG2HOFS_copy2;
-    if (!sign8(beamos_x_hi[j]))
-      oam->y = moldorm_y_lo[j] - beamos_x_hi[j] - BG2VOFS_copy2;
-    j = beamos_y_hi[j];
-    if (n != 7 || i != 0) {
-      oam->charnum = (n == i) ? kLanmola_Draw_Char1[j] : 0xc6;
-    } else {
-      oam->charnum = kLanmola_Draw_Char0[j];
-    }
-    oam->flags = kLanmola_Draw_Flags[j] | r3;
-    bytewise_extended_oam[oam - oam_buf] = 2;
-  } while (oam += oam_step, !sign8(--i));
-  oam = GetOamCurPtr() + 8;
-  i = n;
-  do {
-    int j = r5 + k * 64;
-    r5 = r5 - 8 & 63;
-    oam->x = moldorm_x_lo[j] - BG2HOFS_copy2;
-    if (!sign8(beamos_x_hi[j]))
-      oam->y = moldorm_y_lo[j] + 10 - BG2VOFS_copy2;
-    oam->charnum = 0x6c;
-    oam->flags = 0x34;
-    bytewise_extended_oam[oam - oam_buf] = 2;
-  } while (oam++, !sign8(--i));
-
-  if (sprite_ai_state[k] == 1) {
-    static const uint8 kLanmola_Draw_Idx2[16] = {4, 5, 4, 5, 4, 5, 4, 5, 4, 3, 2, 2, 1, 1, 0, 0};
-    static const uint8 kLanmola_Draw_Char2[6] = {0xee, 0xee, 0xec, 0xec, 0xce, 0xce};
-    static const uint8 kLanmola_Draw_Flags2[6] = {0, 0x40, 0, 0x40, 0, 0x40};
-    Oam_AllocateFromRegionB(4);
-    OamEnt *oam = GetOamCurPtr();
-    j = kLanmola_Draw_Idx2[sprite_delay_main[k] >> 3];
-    SetOamPlain(oam, sprite_x_lo[k] - BG2HOFS_copy2, sprite_y_lo[k] - BG2VOFS_copy2,
-                 kLanmola_Draw_Char2[j], kLanmola_Draw_Flags2[j] | 0x31, 2);
-  } else if (sprite_ai_state[k] != 5 && sprite_delay_aux1[k] != 0) {
-    static const int8 kLanmola_Draw_X4[8] = {-8, 8, -10, 10, -16, 16, -24, 32};
-    static const int8 kLanmola_Draw_Y4[8] = {0, 0, -1, -1, -1, -1, 3, 3};
-    static const uint8 kLanmola_Draw_Char4[8] = {0xe8, 0xe8, 0xe8, 0xe8, 0xea, 0xea, 0xea, 0xea};
-    static const uint8 kLanmola_Draw_Flags4[8] = {0, 0x40, 0, 0x40, 0, 0x40, 0, 0x40};
-    static const uint8 kLanmola_Draw_Big4[8] = {2, 2, 2, 2, 2, 2, 0, 0};
-
-    if (((sprite_y_vel[k] >> 6) ^ sprite_ai_state[k]) & 2)
-      Oam_AllocateFromRegionB(8);
-    else
-      Oam_AllocateFromRegionC(8);
-    OamEnt *oam = GetOamCurPtr();
-    uint8 r6 = (((sprite_delay_aux1[k] >> 2) & 3) ^ 3) * 2;
-    uint8 x = sprite_D[k] - BG2HOFS_copy2;
-    uint8 y = sprite_wallcoll[k] - BG2VOFS_copy2;
-    for (int i = 1; i >= 0; i--, oam++) {
-      int j = i + r6;
-      SetOamPlain(oam, x + kLanmola_Draw_X4[j], y + kLanmola_Draw_Y4[j], kLanmola_Draw_Char4[j], kLanmola_Draw_Flags4[j] | 0x31, kLanmola_Draw_Big4[j]);
-    }
-  }
-}
-
-void Sprite_6D_Rat(int k) {  // 85a8b0
-  static const uint8 kSpriteRat_Tab0[16] = {0, 0, 3, 3, 1, 2, 4, 5, 1, 2, 4, 5, 0, 0, 3, 3};
-  static const uint8 kSpriteRat_Tab1[16] = {0, 0x40, 0, 0x40, 0, 0, 0, 0, 0x40, 0x40, 0x40, 0x40, 0x80, 0xc0, 0x80, 0xc0};
-  static const uint8 kSpriteRat_Tab2[8] = {10, 11, 6, 7, 2, 3, 14, 15};
-  static const uint8 kSpriteRat_Tab4[8] = {8, 9, 4, 5, 0, 1, 12, 13};
-  static const int8 kSpriteRat_Xvel[4] = {24, -24, 0, 0};
-  static const int8 kSpriteRat_Yvel[4] = {0, 0, 24, -24};
-  static const uint8 kSpriteRat_Tab3[4] = {2, 3, 1, 0};
-
-  int j = sprite_A[k];
-  sprite_graphics[k] = kSpriteRat_Tab0[j];
-  sprite_oam_flags[k] = (sprite_oam_flags[k] & 0x3f) | kSpriteRat_Tab1[j];
-  SpriteDraw_SingleLarge(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  if (Sprite_ReturnIfRecoiling(k))
-    return;
-  Sprite_CheckDamageToAndFromLink(k);
-  Sprite_MoveXY(k);
-  Sprite_CheckTileCollision(k);
-  if (sprite_ai_state[k] != 0) {
-    if (sprite_delay_main[k] == 0) {
-      if (is_in_dark_world == 0)
-        SpriteSfx_QueueSfx3WithPan(k, 0x17);
-      sprite_ai_state[k] = 0;
-      sprite_delay_main[k] = 80;
-    }
-    j = sprite_D[k];
-    if (sprite_wallcoll[k] != 0)
-      sprite_D[k] = j = kSpriteRat_Tab3[j];
-    sprite_x_vel[k] = kSpriteRat_Xvel[j];
-    sprite_y_vel[k] = kSpriteRat_Yvel[j];
-    sprite_A[k] = kSpriteRat_Tab4[sprite_D[k] * 2 + (frame_counter >> 2 & 1)];
-  } else {
-    Sprite_ZeroVelocity_XY(k);
-    if (sprite_delay_main[k] == 0) {
-      uint8 a = GetRandomNumber();
-      sprite_D[k] = a & 3;
-      sprite_ai_state[k]++;
-      sprite_delay_main[k] = (a & 0x7f) + 0x40;
-    }
-    sprite_A[k] = kSpriteRat_Tab2[sprite_D[k] * 2 + (frame_counter >> 3 & 1)];
-  }
-}
-
-void Sprite_6E_Rope(int k) {  // 85a973
-  int j;
-  j = sprite_A[k];
-  sprite_graphics[k] = kSpriteRope_Gfx[j];
-  sprite_oam_flags[k] = (sprite_oam_flags[k] & 0x3f) | kSpriteRope_Flags[j];
-  SpriteDraw_SingleLarge(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  if (sprite_E[k]) {
-    OamEnt *oam = GetOamCurPtr();
-    oam[0].flags |= 0x30;
-
-    uint8 old_z = sprite_z[k];
-    Sprite_MoveZ(k);
-    if (!sign8(sprite_z_vel[k] - 0xc0))
-      sprite_z_vel[k] -= 2;
-    if (!sign8(old_z ^ sprite_z[k]) || !sign8(sprite_z[k]))
-      return;
-    sprite_z[k] = 0;
-    sprite_z_vel[k] = 0;
-    sprite_E[k] = 0;
-    sprite_flags3[k] &= ~0x10;
-  } else {
-    sprite_flags2[k] = 0;
-    if (Sprite_ReturnIfRecoiling(k))
-      return;
-    Sprite_CheckDamageToAndFromLink(k);
-    Sprite_MoveXY(k);
-    Sprite_CheckTileCollision(k);
-    if (sprite_ai_state[k] != 0) {
-      if (sprite_delay_main[k] == 0) {
-        sprite_ai_state[k] = 0;
-        sprite_delay_main[k] = 32;
-      }
-      j = sprite_D[k];
-      if (sprite_wallcoll[k] != 0)
-        sprite_D[k] = j = kSpriteRope_Tab0[j];
-
-      j += sprite_G[k];
-      sprite_x_vel[k] = kSpriteRope_Xvel[j];
-      sprite_y_vel[k] = kSpriteRope_Yvel[j];
-
-      int i = frame_counter;
-      if (j < 4)
-        i >>= 1;
-
-      sprite_A[k] = kSpriteRope_Tab1[sprite_D[k] * 2 + (i >> 1 & 1)];
-    } else {
-      Sprite_ZeroVelocity_XY(k);
-      if (sprite_delay_main[k] == 0) {
-        sprite_G[k] = 0;
-        uint8 a = GetRandomNumber();
-        sprite_D[k] = a & 3;
-        sprite_ai_state[k]++;
-        sprite_delay_main[k] = (a & 0x7f) + 0x40;
-
-        PointU8 pt;
-        uint8 dir = Sprite_DirectionToFaceLink(k, &pt);
-        if ((uint8)(pt.y + 0x10) < 0x20 || (uint8)(pt.x + 0x18) < 0x20) {
-          sprite_G[k] = 4;
-          sprite_D[k] = dir;
-        }
-      }
-      sprite_A[k] = kSpriteRope_Tab1[sprite_D[k] * 2 + (frame_counter >> 3 & 1)];
-    }
-  }
-}
-
-void Sprite_6F_Keese(int k) {  // 85aa8b
-  static const int8 kSpriteKeese_Tab1[2] = {1, -1};
-  static const int8 kSpriteKeese_Tab0[4] = {2, 10, 6, 14};
-
-  sprite_obj_prio[k] |= 0x30;
-  SpriteDraw_SingleLarge(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  if (Sprite_ReturnIfRecoiling(k))
-    return;
-  Sprite_CheckDamageToAndFromLink(k);
-  Sprite_MoveXY(k);
-  if (sprite_ai_state[k]) {
-    if (sprite_delay_main[k] == 0) {
-      sprite_ai_state[k] = 0;
-      sprite_delay_main[k] = 64;
-      sprite_graphics[k] = 0;
-      Sprite_ZeroVelocity_XY(k);
-    } else {
-      if ((sprite_delay_main[k] & 7) == 0) {
-        sprite_A[k] += kSpriteKeese_Tab1[sprite_B[k] & 1];
-        if (!(GetRandomNumber() & 3))
-          sprite_B[k]++;
-      }
-      int j = sprite_A[k] & 0xf;
-      sprite_x_vel[k] = kSpriteKeese_Tab2[j];
-      sprite_y_vel[k] = kSpriteKeese_Tab3[j];
-      sprite_graphics[k] = ((frame_counter >> 2) & 1) + 1;
-    }
-  } else {
-    if ((k ^ frame_counter) & 3 | sprite_delay_main[k])
-      return;
-
-    PointU8 pt;
-    uint8 dir = Sprite_DirectionToFaceLink(k, &pt);
-    if ((uint8)(pt.y + 0x28) >= 0x50 || (uint8)(pt.x + 0x28) >= 0x50)
-      return;
-    SpriteSfx_QueueSfx3WithPan(k, 0x1e);
-    sprite_ai_state[k]++;
-    sprite_delay_main[k] = 64;
-    sprite_B[k] = 64;
-    sprite_A[k] = kSpriteKeese_Tab0[dir];
-  }
-}
-
-void Sprite_Cannonball(int k) {  // 85ab54
-  SpriteDraw_SingleLarge(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  Sprite_MoveXY(k);
-  if (sprite_delay_main[k] == 30) {
-    Sprite_SpawnPoofGarnish(k);
-  } else if (sprite_delay_main[k] == 0 && Sprite_CheckTileCollision(k)) {
-    sprite_state[k] = 0;
-    sprite_x_lo[k] += 4;
-    sprite_y_lo[k] += 4;
-    Sprite_PlaceRupulseSpark_2(k);
-    SpriteSfx_QueueSfx2WithPan(k, 0x5);
-  }
-  Sprite_CheckDamageToAndFromLink(k);
-}
-
-void Sprite_SpawnPoofGarnish(int j) {  // 85ab9c
-  int k = GarnishAllocForce();
-  garnish_type[k] = 10;
-  garnish_active = 10;
-  garnish_x_lo[k] = sprite_x_lo[j];
-  garnish_x_hi[k] = sprite_x_hi[j];
-  int y = Sprite_GetY(j) + 16;
-  garnish_y_lo[k] = y;
-  garnish_y_hi[k] = y >> 8;
-  garnish_sprite[k] = sprite_floor[j];
-  garnish_countdown[k] = 15;
-}
-
-void Sprite_6C_MirrorPortal(int k) {  // 85af75
-  if (savegame_is_darkworld) {
-    sprite_state[k] = 0;
-  } else {
-    if (BYTE(overworld_screen_index) >= 0x80)
-      return;
-
-    if (submodule_index != 0x23 && byte_7E0FC6 < 3)
-      SpriteDraw_SingleLarge(k);
-    if (Sprite_ReturnIfInactive(k))
-      return;
-    int j = frame_counter >> 2 & 3;
-    sprite_oam_flags[k] = sprite_oam_flags[k] & 0x3f | kSprite_WarpVortex_Flags[j];
-    if (Sprite_CheckIfLinkIsBusy())
-      return;
-    if (Sprite_CheckDamageToLink_same_layer(k)) {
-      if (sprite_A[k] && (link_disable_sprite_damage | countdown_for_blink) == 0 && !flag_is_link_immobilized) {
-        submodule_index = 0x23;
-        link_triggered_by_whirlpool_sprite = 1;
-        subsubmodule_index = 0;
-        link_actual_vel_y = 0;
-        link_actual_vel_x = 0;
-        link_player_handler_state = kPlayerState_Mirror;
-        last_light_vs_dark_world = overworld_screen_index & 0x40;
-        sprite_state[k] = 0;
-      }
-    } else {
-      sprite_A[k] = 1;
-    }
-  }
-  if (++sprite_B[k] == 0)
-    sprite_A[k] = 1;
-  sprite_x_lo[k] = bird_travel_x_lo[15];
-  sprite_x_hi[k] = bird_travel_x_hi[15];
-  int t = (bird_travel_y_lo[15] | (bird_travel_y_hi[15] << 8)) + 8;
-  sprite_y_lo[k] = t;
-  sprite_y_hi[k] = t >> 8;
-}
-
-void Sprite_6A_BallNChain(int k) {  // 85b01b
-  ChainBallTrooper_Draw(k);
-  if (sprite_ai_state[k] < 2)
-    HIBYTE(dungmap_var8) = 0x80;
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  Guard_ParrySwordAttacks(k);
-
-  int t = sprite_B[k] << 8 | sprite_A[k];
-  t += kChainBallTrooper_Tab1[sprite_ai_state[k]];
-  sprite_A[k] = t;
-  sprite_B[k] = t >> 8 & 1;
-  if (Sprite_ReturnIfRecoiling(k))
-    return;
-  Sprite_CheckTileCollision(k);
-  Sprite_MoveXY(k);
-  Sprite_CheckDamageToLink(k);
-
-  PointU8 pt = { 0, 0 };
-
-  if (((k ^ frame_counter) & 0xf) == 0)
-    sprite_head_dir[k] = Sprite_DirectionToFaceLink(k, &pt);
-
-  switch (sprite_ai_state[k]) {
-  case 0:
-    if (((k ^ frame_counter) & 0xf) == 0) {
-      sprite_D[k] = sprite_head_dir[k];
-      if ((uint8)(pt.y + 0x40) < 0x68 && (uint8)(pt.x + 0x30) < 0x60) {
-        sprite_ai_state[k]++;
-        sprite_delay_main[k] = 24;
-        return;
-      }
-      Sprite_ApplySpeedTowardsLink(k, 8);
-    }
-    BallNChain_Animate(k);
-    break;
-  case 1:
-    Sprite_ZeroVelocity_XY(k);
-    if (!sprite_delay_main[k]) {
-      sprite_delay_main[k] = 48;
-      sprite_ai_state[k]++;
-    }
-    break;
-  case 2:
-    if (!sprite_delay_main[k] &&
-        sprite_head_dir[k] == kFlailTrooperAttackDir[(sprite_A[k] >> 7 & 1) + sprite_B[k] * 2]) {
-      sprite_ai_state[k]++;
-      sprite_delay_aux2[k] = 31;
-    }
-attack_common:
-    sprite_subtype2[k]++;
-    BallNChain_Animate(k);
-    if (((k ^ frame_counter) & 0xf) == 0)
-      SpriteSfx_QueueSfx3WithPan(k, 6);
-    break;
-  case 3:
-    Sprite_ZeroVelocity_XY(k);
-    t = sprite_delay_aux2[k];
-    if (t == 0)
-      sprite_ai_state[k] = 0;
-    else if (t >= 0x10)
-      goto attack_common;
-    sprite_subtype2[k]++;
-    BallNChain_Animate(k);
-    break;
-  }
-}
-
-void BallNChain_Animate(int k) {  // 85b0ab
-  sprite_graphics[k] = kFlailTrooperGfx[sprite_D[k] * 8 + (++sprite_subtype2[k] >> 2 & 7)];
-}
-
-void SpriteDraw_GuardHead(int k, PrepOamCoordsRet *info, int spr_offs) {  // 85b160
-  int j = sprite_head_dir[k];
-  OamEnt *oam = GetOamCurPtr() + spr_offs;
-  SetOamHelper0(oam, info->x, info->y - 9, kChainBallTrooperHead_Char[j], info->flags | kChainBallTrooperHead_Flags[j], 2);
-}
-
-void SpriteDraw_BNCBody(int k, PrepOamCoordsRet *info, int spr_offs) {  // 85b3cb
-  int g = sprite_graphics[k];
-  spr_offs += kFlailTrooperBody_SprOffs[g] >> 2;
-  OamEnt *oam = GetOamCurPtr() + spr_offs;
-  int n = kFlailTrooperBody_Num[g];
-  do {
-    int j = g * 3 + n;
-    SetOamHelper0(oam, info->x + kFlailTrooperBody_X[j], info->y + kFlailTrooperBody_Y[j],
-                  kFlailTrooperBody_Char[j], info->flags | kFlailTrooperBody_Flags[j],
-                  kFlailTrooperBody_Big[j]);
-    if (n == 2)
-      oam++;
-  } while (oam++, --n >= 0);
-}
-
-void SpriteDraw_BNCFlail(int k, PrepOamCoordsRet *info) {  // 85b468
-  OamEnt *oam = GetOamCurPtr();
-
-  BYTE(dungmap_var7) = info->x;
-  HIBYTE(dungmap_var7) = info->y;
-
-  uint8 t;
-  uint16 r0 = sprite_A[k] | sprite_B[k] << 8;
-  uint8 qq = sprite_ai_state[k] < 2 ? 0 : kFlailTrooperWeapon_Tab0[sprite_delay_aux2[k]];
-  uint8 r12 = kFlailTrooperWeapon_Tab1[sprite_D[k]];
-  uint8 r13 = kFlailTrooperWeapon_Tab2[sprite_D[k]];
-
-  uint16 r2 = (r0 + 0x80) & 0x1ff;
-
-  uint8 r14 = ChainBallMult(kSinusLookupTable[r0 & 0xff], qq);
-  uint8 r4 = (r0 & 0x100) ? -r14 : r14;
-
-  uint8 r15 = ChainBallMult(kSinusLookupTable[r2 & 0xff], qq);
-  uint8 r6 = (r2 & 0x100) ? -r15 : r15;
-
-  HIBYTE(dungmap_var8) = r4 - 4 + r12;
-  BYTE(dungmap_var8) = r6 - 4 + r13;
-
-  SetOamPlain(oam, HIBYTE(dungmap_var8) + BYTE(dungmap_var7), BYTE(dungmap_var8) + HIBYTE(dungmap_var7), 0x2a, 0x2d, 2);
-  oam++;
-
-  for (int i = 3; i >= 0; i--, oam++) {
-    t = (kFlailTrooperWeapon_Tab4[i] * r14) >> 8;
-    t = sign8(r4) ? -t : t;
-    uint8 x = t + BYTE(dungmap_var7) + r12;
-    uint8 ty = (kFlailTrooperWeapon_Tab4[i] * r15) >> 8;
-    ty = sign8(r6) ? -ty : ty;
-    uint8 y = ty + HIBYTE(dungmap_var7) + r13;
-    SetOamPlain(oam, x, y, 0x3f, 0x2d, 0);
-  }
-  Sprite_CorrectOamEntries(k, 4, 0xff);
-}
-
-void Sprite_50_Cannonball(int k) {  // 85b648
-  if (!sprite_ai_state[k])
-    SpriteDraw_SingleLarge(k);
-  else
-    SpriteDraw_BigCannonball(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  sprite_graphics[k] = ++sprite_subtype2[k] >> 2 & 1;
-  Sprite_MoveXY(k);
-  if (sprite_delay_main[k]) {
-    if (sprite_delay_main[k] == 1)
-      sprite_state[k] = 0;
-    return;
-  }
-  Sprite_CheckDamageToAndFromLink(k);
-  if (!sprite_delay_aux2[k] && Sprite_CheckTileCollision(k))
-    sprite_delay_main[k] = 16;
-}
-
-void SpriteDraw_BigCannonball(int k) {  // 85b6a4
-  static const int8 kMetalBallLarge_X[4] = {-8, 8, -8, 8};
-  static const int8 kMetalBallLarge_Y[4] = {-8, -8, 8, 8};
-  static const uint8 kMetalBallLarge_Char[8] = {0x84, 0x88, 0x88, 0x88, 0x86, 0x88, 0x88, 0x88};
-  static const uint8 kMetalBallLarge_Flags[4] = {0, 0, 0xc0, 0x80};
-
-  PrepOamCoordsRet info;
-  if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
-    return;
-  OamEnt *oam = GetOamCurPtr();
-  int g = sprite_graphics[k];
-  for (int i = 3; i >= 0; i--, oam++) {
-    SetOamHelper0(oam, info.x + kMetalBallLarge_X[i], info.y + kMetalBallLarge_Y[i],
-                  kMetalBallLarge_Char[g * 4 + i], kMetalBallLarge_Flags[i] | info.flags, 2);
-  }
-}
-
-void Sprite_51_ArmosStatue(int k) {  // 85b703
-  Armos_Draw(k);
-  if (sprite_F[k])
-    Sprite_ZeroVelocity_XY(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  Sprite_MoveZ(k);
-  sprite_z_vel[k] -= 2;
-  if (sign8(sprite_z[k])) {
-    sprite_z[k] = 0;
-    sprite_z_vel[k] = 0;
-    Sprite_ZeroVelocity_XY(k);
-  }
-  if (!sprite_ai_state[k]) {
-    sprite_flags3[k] |= 0x40;
-    if (sprite_delay_main[k] == 1) {
-      sprite_flags3[k] &= ~0x40;
-      sprite_ai_state[k]++;
-      sprite_flags2[k] &= ~0x80;
-      sprite_flags3[k] &= ~0x40;
-      sprite_oam_flags[k] = 0xb;
-    } else {
-      if (!((k ^ frame_counter) & 3) &&
-          (uint16)(link_x_coord - cur_sprite_x + 31) < 62 &&
-          (uint16)(link_y_coord + 8 - cur_sprite_y + 48) < 88 && !sprite_delay_main[k]) {
-        sprite_delay_main[k] = 48;
-        SpriteSfx_QueueSfx2WithPan(k, 0x22);
-      }
-      if (Sprite_CheckDamageToLink_same_layer(k)) {
-        Sprite_NullifyHookshotDrag();
-        Sprite_RepelDash();
-      }
-      if (sprite_delay_main[k])
-        sprite_oam_flags[k] ^= (sprite_delay_main[k] >> 1) & 0xe;
-    }
-  } else {
-    Sprite_CheckDamageToAndFromLink(k);
-    if (Sprite_ReturnIfRecoiling(k))
-      return;
-    Sprite_MoveXY(k);
-    Sprite_CheckTileCollision(k);
-    if ((sprite_delay_main[k] | sprite_z[k]) == 0) {
-      sprite_delay_main[k] = 8;
-      sprite_z_vel[k] = 16;
-      Sprite_ApplySpeedTowardsLink(k, 12);
-    }
-  }
-}
-
-void Armos_Draw(int k) {  // 85b7ef
-  static const DrawMultipleData kArmos_Dmd[2] = {
-    {0, -16, 0x00c0, 2},
-    {0,   0, 0x00e0, 2},
-  };
-  PrepOamCoordsRet info;
-  if (!sprite_ai_state[k]) {
-    if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
-      return;
-  }
-  Sprite_DrawMultiple(k, &kArmos_Dmd[0], 2, &info);
-  SpriteDraw_Shadow(k, &info);
-}
-
-void Sprite_4E_Popo(int k) {  // 85b80a
-  Bot_Draw(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  if (Sprite_ReturnIfRecoiling(k))
-    return;
-  sprite_subtype2[k]++;
-  sprite_A[k] = sprite_subtype2[k] >> 4 & 3;
-  Sprite_CheckDamageToAndFromLink(k);
-  switch (sprite_ai_state[k]) {
-  case 0:
-    if (!sprite_delay_main[k]) {
-      sprite_ai_state[k] = 1;
-      sprite_delay_main[k] = 105;
-    }
-    break;
-  case 1:
-    sprite_subtype2[k]++;
-    if (!sprite_delay_main[k]) {
-      sprite_delay_main[k] = (GetRandomNumber() & 63) + 128;
-      sprite_ai_state[k]++;
-      int j = GetRandomNumber() & 15;
-      sprite_x_vel[k] = kSpriteKeese_Tab2[j] << 2;
-      sprite_y_vel[k] = kSpriteKeese_Tab3[j] << 2;
-    }
-    break;
-  case 2:
-    sprite_subtype2[k]++;
-    if (sprite_delay_main[k]) {
-      if ((k ^ frame_counter) & sprite_B[k]) {
-        Sprite_CheckTileCollision(k);
-        return;
-      }
-      Sprite_MoveXY(k);
-      if (!sprite_wallcoll[k]) {
-        Sprite_CheckTileCollision(k);
-        return;
-      }
-    }
-    sprite_ai_state[k] = 0;
-    sprite_delay_main[k] = 80;
-    break;
-  }
-}
-
-void Bot_Draw(int k) {  // 85b89a
-  static const uint8 kBot_Gfx[4] = {0, 1, 0, 1};
-  static const uint8 kBot_OamFlags[4] = {0, 0, 0x40, 0x40};
-  int j = sprite_A[k];
-  sprite_graphics[k] = kBot_Gfx[j];
-  sprite_oam_flags[k] = sprite_oam_flags[k] & ~0x40 | kBot_OamFlags[j];
-  SpriteDraw_SingleLarge(k);
-}
-
-void Sprite_4C_Geldman(int k) {  // 85b8b3
-  static const uint8 kGerudoMan_EmergeGfx[8] = {3, 2, 0, 0, 0, 0, 0, 0};
-  static const uint8 kGerudoMan_PursueGfx[2] = {4, 5};
-  static const uint8 kGerudoMan_SubmergeGfx[5] = {0, 1, 2, 3, 3};
-  PrepOamCoordsRet info;
-  if (sprite_ai_state[k] < 2)
-    Sprite_PrepOamCoord(k, &info);
-  else
-    GerudoMan_Draw(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  if (Sprite_ReturnIfRecoiling(k))
-    return;
-  sprite_ignore_projectile[k] = 1;
-  switch (sprite_ai_state[k]) {
-  case 0:  // return
-    if (!sprite_delay_main[k]) {
-      sprite_x_lo[k] = sprite_A[k];
-      sprite_x_hi[k] = sprite_B[k];
-      sprite_y_lo[k] = sprite_C[k];
-      sprite_y_hi[k] = sprite_head_dir[k];
-      sprite_ai_state[k] = 1;
-    }
-    break;
-  case 1:  // wait
-    if (!((k ^ frame_counter) & 7) &&
-        (uint16)(link_x_coord - cur_sprite_x + 0x30) < 0x60 &&
-        (uint16)(link_y_coord - cur_sprite_y + 0x30) < 0x60) {
-      sprite_ai_state[k] = 2;
-      sprite_delay_main[k] = 31;
-    }
-    break;
-  case 2:  // emerge
-    if (!sprite_delay_main[k]) {
-      sprite_ai_state[k] = 3;
-      sprite_delay_main[k] = 96;
-      Sprite_ApplySpeedTowardsLink(k, 16);
-    } else {
-      sprite_graphics[k] = kGerudoMan_EmergeGfx[sprite_delay_main[k] >> 2];
-    }
-    break;
-  case 3:  // pursue
-    sprite_ignore_projectile[k] = 0;
-    if (!sprite_delay_main[k]) {
-      sprite_ai_state[k] = 4;
-      sprite_delay_main[k] = 8;
-    } else {
-      sprite_graphics[k] = kGerudoMan_PursueGfx[sprite_delay_main[k] >> 2 & 1];
-      Sprite_CheckDamageToAndFromLink(k);
-      Sprite_MoveXY(k);
-    }
-    break;
-  case 4:  // submerge
-    if (!sprite_delay_main[k]) {
-      sprite_ai_state[k] = 0;
-      sprite_delay_main[k] = 16;
-    } else {
-      sprite_graphics[k] = kGerudoMan_SubmergeGfx[sprite_delay_main[k] >> 1];
-    }
-    break;
-  }
-}
-
-void GerudoMan_Draw(int k) {  // 85ba24
-  static const int8 kGerudoMan_Draw_X[18] = { 4, 4, 4, 4, 4, 4, -8, 8, 8, -8, 8, 8, -16, 0, 16, -16, 0, 16 };
-  static const int8 kGerudoMan_Draw_Y[18] = { 8, 8, 8, 8, 8, 8, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
-  static const uint8 kGerudoMan_Draw_Char[18] = {
-    0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa4, 0xa2, 0xa0, 0xa0, 0xa2, 0xa4,
-  };
-  static const uint8 kGerudoMan_Draw_Flags[18] = {
-    0, 0, 0, 0x40, 0x40, 0x40, 0, 0x40, 0x40, 0, 0x40, 0x40, 0x40, 0x40, 0x40, 0, 0, 0,
-  };
-  static const uint8 kGerudoMan_Draw_Big[18] = { 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 };
-  PrepOamCoordsRet info;
-  if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
-    return;
-  OamEnt *oam = GetOamCurPtr();
-  int g = sprite_graphics[k];
-  for (int i = 2; i >= 0; i--, oam++) {
-    int j = g * 3 + i;
-    SetOamHelper0(oam, info.x + kGerudoMan_Draw_X[j], info.y + kGerudoMan_Draw_Y[j],
-                  kGerudoMan_Draw_Char[j], kGerudoMan_Draw_Flags[j] | info.flags, kGerudoMan_Draw_Big[j]);
-  }
-}
-
-void Sprite_4D_Toppo(int k) {  // 85ba85
-  static const int8 kToppo_XOffs[4] = {-32, 32, 0, 0};
-  static const int8 kToppo_YOffs[4] = {0, 0, -32, 32};
-
-  if (sprite_ai_state[k]) {
-    sprite_obj_prio[k] |= 0x30;
-    Toppo_Draw(k);
-  }
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  switch (sprite_ai_state[k]) {
-  case 0:  // Toppo_Hiding
-    if (!sprite_delay_main[k]) {
-      sprite_ai_state[k] = 1;
-      sprite_delay_main[k] = 8;
-      int j = GetRandomNumber() & 3;
-      uint16 x = sprite_A[k] | sprite_B[k] << 8;
-      uint16 y = sprite_C[k] | sprite_head_dir[k] << 8;
-      Sprite_SetX(k, x + kToppo_XOffs[j]);
-      Sprite_SetY(k, y + kToppo_YOffs[j]);
-    }
-    break;
-  case 1:  // Toppo_RustleGrass
-    if (!sprite_delay_main[k]) {
-      sprite_ai_state[k] = 2;
-      sprite_delay_main[k] = 16;
-    } else {
-      sprite_graphics[k] = sprite_delay_main[k] >> 2 & 1;
-      Toppo_VerifyTile(k);
-    }
-    break;
-  case 2:  // Toppo_PokingOut
-    if (!sprite_delay_main[k]) {
-      sprite_ai_state[k] = 3;
-      sprite_z_vel[k] = 64;
-    }
-    sprite_graphics[k] = 2;
-    Toppo_VerifyTile(k);
-    break;
-  case 3:  // Toppo_Leaping
-    Sprite_CheckDamageToAndFromLink(k);
-    Sprite_MoveZ(k);
-    sprite_z_vel[k] -= 2;
-    if (sign8(sprite_z[k])) {
-      sprite_z[k] = 0;
-      sprite_ai_state[k] = 4;
-      sprite_delay_main[k] = 16;
-      Toppo_VerifyTile(k);
-    }
-    break;
-  case 4:  // Toppo_Retreat
-    if (!sprite_delay_main[k]) {
-      sprite_ai_state[k] = 0;
-      sprite_delay_main[k] = 32;
-    } else {
-      sprite_graphics[k] = sprite_delay_main[k] >> 2 & 1;
-    }
-    Toppo_VerifyTile(k);
-    break;
-  case 5:  // Toppo_Flustered
-    Toppo_Flustered(k);
-    break;
-  }
-}
-
-void Toppo_VerifyTile(int k) {  // 85bb72
-  uint16 x = Sprite_GetX(k);
-  if (GetTileAttribute(0, &x, Sprite_GetY(k)) != 0x40)
-    sprite_ai_state[k] = 5;
-}
-
-void Toppo_Draw(int k) {  // 85bbff
-  static const int8 kToppo_Draw_X[15] = {0, 8, 8, 0, 8, 8, 0, 0, 8, 0, 0, 0, 0, 0, 0};
-  static const int8 kToppo_Draw_Y[15] = {8, 8, 8, 8, 8, 8, 0, 8, 8, 0, 0, 0, 0, 0, 0};
-  static const uint8 kToppo_Draw_Char[15] = {0xc8, 0xc8, 0xc8, 0xca, 0xca, 0xca, 0xc0, 0xc8, 0xc8, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2};
-  static const uint8 kToppo_Draw_Flags[15] = {0, 0x40, 0x40, 0, 0x40, 0x40, 0, 0, 0x40, 0, 0, 0, 0x40, 0x40, 0x40};
-  static const uint8 kToppo_Draw_Big[15] = {0, 0, 0, 0, 0, 0, 2, 0, 0, 2, 2, 2, 2, 2, 2};
-
-  PrepOamCoordsRet info;
-  if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
-    return;
-  OamEnt *oam = GetOamCurPtr();
-  int g = sprite_graphics[k];
-  uint16 ybase = Sprite_GetY(k) - BG2VOFS_copy2;
-  for (int i = 2; i >= 0; i--, oam++) {
-    int j = i + g * 3;
-    uint8 big = kToppo_Draw_Big[j];
-    uint8 flags = kToppo_Draw_Flags[j] | info.flags;
-    if (big == 0)
-      flags = flags & ~0xf | 2;
-    SetOamHelper0(oam,
-                  info.x + kToppo_Draw_X[j],
-                  (big ? info.y : ybase) + kToppo_Draw_Y[j],
-                  kToppo_Draw_Char[j], flags, big);
-  }
-}
-
-void Sprite_4B_GreenKnifeGuard(int k) {  // 85bca2
-  sprite_graphics[k] = kSprite_Recruit_Gfx[sprite_D[k] + (sprite_subtype2[k] >> 1 & 4) ];
-  Recruit_Draw(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  if (Sprite_ReturnIfRecoiling(k))
-    return;
-  Sprite_CheckDamageToAndFromLink(k);
-  Sprite_MoveXY(k);
-  Sprite_CheckTileCollision(k);
-  if (sprite_ai_state[k] != 0) {
-    GreenKnifeGuard_Moving(k);
-    return;
-  }
-  if (sprite_delay_main[k] != 0)
-    return;
-
-  sprite_delay_main[k] = (GetRandomNumber() & 0x3f) + 0x30;
-  sprite_ai_state[k]++;
-  sprite_D[k] = sprite_head_dir[k];
-  PointU8 out;
-  int j = sprite_D[k];
-  if (j == Sprite_DirectionToFaceLink(k, &out) &&
-     (((uint8)(out.x + 0x10) < 0x20) || ((uint8)(out.y + 0x10) < 0x20))) {
-    j += 4;
-    sprite_delay_main[k] = 128;
-  }
-  sprite_x_vel[k] = kSprite_Recruit_Xvel[j];
-  sprite_y_vel[k] = kSprite_Recruit_Yvel[j];
-}
-
-void GreenKnifeGuard_Moving(int k) {  // 85bd1e
-  uint8 t = 0x10;
-
-  if (sprite_wallcoll[k] == 0) {
-    if (sprite_delay_main[k] != 0)
-      goto out;
-    t = 0x30;
-  }
-  sprite_delay_main[k] = t;
-  Sprite_ZeroVelocity_XY(k);
-  sprite_head_dir[k] = kRecruit_Moving_HeadDir[sprite_D[k] * 2 | (GetRandomNumber() & 1)];
-  sprite_ai_state[k] = 0;
-out:
-  sprite_subtype2[k] += (sprite_delay_aux1[k] != 0) ? 2 : 1;
-}
-
-void Recruit_Draw(int k) {  // 85bd7e
-  PrepOamCoordsRet info;
-  if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
-    return;
-  OamEnt *oam = GetOamCurPtr();
-  int hd = sprite_head_dir[k];
-  SetOamHelper0(oam + 0, info.x, info.y - 11, kSoldier_Draw1_Char[hd], kSoldier_Draw1_Flags[hd] | info.flags, 2);
-  int r6 = sprite_graphics[k];
-  SetOamHelper0(oam + 1, info.x + kRecruit_Draw_X[r6], info.y, kRecruit_Draw_Char[r6], kRecruit_Draw_Flags[r6] | info.flags, 2);
-  SpriteDraw_Shadow(k, &info);
-}
-
-void Sprite_4A_BombGuard(int k) {  // 85be0a
-  if (sprite_C[k] == 0) {
-    BombGuard(k);
-    return;
-  }
-  if (sprite_C[k] < 2) {
-    SpriteBomb_ExplosionIncoming(k);
-    return;
-  }
-
-  if (sprite_C[k] == 2) {
-    for (int j = 15; j >= 0; j--) {
-      if (j != cur_object_index && sprite_state[j] >= 9 && !((frame_counter ^ j) & 7 | sprite_hit_timer[j]))
-        SpriteBomb_CheckDamageToSprite(k, j);
-    }
-    Sprite_CheckDamageToLink(k);
-  }
-  SpriteDraw_SpriteBombExplosion(k);
-  if (!sprite_delay_aux1[k])
-    sprite_state[k] = 0;
-}
-
-void SpriteBomb_CheckDamageToSprite(int k, int j) {  // 85be49
-  int x = Sprite_GetX(k) - 16, y = Sprite_GetY(k) - 16;
-  SpriteHitBox hb;
-  hb.r0_xlo = x;
-  hb.r8_xhi = x >> 8;
-  hb.r3 = hb.r2 = 48;
-  hb.r1_ylo = y;
-  hb.r9_yhi = y >> 8;
-  Sprite_SetupHitBox(j, &hb);
-  if (!CheckIfHitBoxesOverlap(&hb) || sprite_type[j] == 0x11)
-    return;
-  Ancilla_CheckDamageToSprite_preset(j, 8);
-  x = Sprite_GetX(j);
-  y = Sprite_GetY(j) - sprite_z[j];
-  ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLocation(k, x, y, 32);
-  sprite_y_recoil[j] = pt.y;
-  sprite_x_recoil[j] = pt.x;
-}
-
-void SpriteBomb_ExplosionIncoming(int k) {  // 85bed3
-  if (sprite_E[k])
-    sprite_obj_prio[k] |= 48;
-  SpriteDraw_SingleLarge(k);
-  if (sprite_hit_timer[k] || sprite_delay_aux1[k] == 1) {
-    sprite_hit_timer[k] = 0;
-    if (sprite_state[k] == 10)
-      link_state_bits = 0, link_picking_throw_state = 0;
-    SpriteSfx_QueueSfx2WithPan(k, 0xc);
-    sprite_C[k]++;
-    sprite_flags4[k] = 9;
-    sprite_oam_flags[k] = 2;
-    sprite_delay_aux1[k] = 31;
-    sprite_state[k] = 6;
-    sprite_flags2[k] = 3;
-    return;
-  }
-  if (sprite_delay_aux1[k] < 64)
-    sprite_oam_flags[k] = sprite_oam_flags[k] & ~0xe | (sprite_delay_aux1[k] >> 1) & 0xe;
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  if (!sprite_delay_aux3[k])
-    Sprite_CheckDamageFromLink(k);
-  Sprite_MoveXY(k);
-  if (player_is_indoors)
-    Sprite_CheckTileCollision(k);
-  ThrownSprite_TileAndSpriteInteraction(k);
-}
-
-void BombGuard(int k) {  // 85bf51
-  BombTrooper_Draw(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  Sprite_CheckDamageToAndFromLink(k);
-  sprite_head_dir[k] = sprite_D[k] = Sprite_DirectionToFaceLink(k, NULL);
-  if (sprite_ai_state[k] == 0) {
-    if (!sprite_delay_main[k]) {
-      sprite_ai_state[k] = 1;
-      sprite_delay_main[k] = 112;
-    }
-  } else {
-    int j = sprite_delay_main[k];
-    if (!j) {
-      sprite_ai_state[k] = 0;
-      sprite_delay_main[k] = 32;
-      return;
-    }
-    sprite_subtype2[k] = (j >= 80);
-    if (j == 32)
-      BombGuard_CreateBomb(k);
-    sprite_graphics[k] = kJavelinTrooper_Tab2[(sprite_D[k] << 3 | j >> 4) + 32];
-  }
-}
-
-void BombGuard_CreateBomb(int k) {  // 85bfc1
-  static const int8 kBombTrooperBomb_X[4] = {0, 1, 9, -8};
-  static const int8 kBombTrooperBomb_Y[4] = {-12, -12, -15, -13};
-  static const int8 kBombTrooperBomb_Zvel[16] = {32, 40, 48, 56, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64};
-  SpriteSpawnInfo info;
-  int j = Sprite_SpawnDynamically(k, 0x4a, &info);
-  if (j >= 0) {
-    int i = sprite_D[k];
-    Sprite_SetX(j, info.r0_x + kBombTrooperBomb_X[i]);
-    Sprite_SetY(j, info.r2_y + kBombTrooperBomb_Y[i]);
-    Sprite_ApplySpeedTowardsLink(j, 16);
-    PointU8 pt;
-    sprite_C[j] = 1;
-    Sprite_DirectionToFaceLink(j, &pt);
-    if (sign8(pt.x))
-      pt.x = -pt.x;
-    if (sign8(pt.y))
-      pt.y = -pt.y;
-    sprite_z_vel[j] = kBombTrooperBomb_Zvel[(pt.y | pt.x) >> 4];
-    sprite_flags3[j] = sprite_flags3[k] & 0xee | 0x18;
-    sprite_oam_flags[j] = 8;
-    sprite_delay_aux1[j] = 255;
-    sprite_health[j] = 0;
-    SpriteSfx_QueueSfx3WithPan(j, 0x13);
-  }
-}
-
-void BombTrooper_Draw(int k) {  // 85c04b
-  PrepOamCoordsRet info;
-  if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
-    return;
-  SpriteDraw_GuardHead(k, &info, 2);
-  SpriteDraw_BNCBody(k, &info, 1);
-  if (sprite_graphics[k] < 20)
-    SpriteDraw_BombGuard_Arm(k, &info);
-  SpriteDraw_Shadow_custom(k, &info, 10);
-}
-
-void SpriteDraw_BombGuard_Arm(int k, PrepOamCoordsRet *info) {  // 85c089
-  static const int8 kBombTrooper_DrawArm_X[8] = {-1, 1, 2, 0, 9, 9, -8, -8};
-  static const int8 kBombTrooper_DrawArm_Y[8] = {-12, -12, -12, -12, -16, -14, -12, -14};
-  OamEnt *oam = GetOamCurPtr();
-  int j = sprite_D[k] * 2 | sprite_subtype2[k];
-  SetOamHelper0(oam,
-                info->x + kBombTrooper_DrawArm_X[j],
-                info->y + kBombTrooper_DrawArm_Y[j], 0x6e, info->flags & 0x30 | 0x8, 2);
-}
-
-void SpriteDraw_SpriteBombExplosion(int k) {  // 85c113
-  static const int8 kEnemyBombExplosion_X[16] = {-12, 12, -12, 12, -8, 8, -8, 8, -8, 8, -8, 8, 0, 0, 0, 0};
-  static const int8 kEnemyBombExplosion_Y[16] = {-12, -12, 12, 12, -8, -8, 8, 8, -8, -8, 8, 8, 0, 0, 0, 0};
-  static const uint8 kEnemyBombExplosion_Char[16] = {0x88, 0x88, 0x88, 0x88, 0x8a, 0x8a, 0x8a, 0x8a, 0x84, 0x84, 0x84, 0x84, 0x86, 0x86, 0x86, 0x86};
-  static const uint8 kEnemyBombExplosion_Flags[16] = {0, 0x40, 0x80, 0xc0, 0, 0x40, 0x80, 0xc0, 0, 0x40, 0x80, 0xc0, 0, 0, 0, 0};
-  PrepOamCoordsRet info;
-  if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
-    return;
-  OamEnt *oam = GetOamCurPtr();
-  int base = sprite_delay_aux1[k] >> 1 & 0xc;
-  for (int i = 3; i >= 0; i--, oam++) {
-    int j = base + i;
-    oam->x = kEnemyBombExplosion_X[j] + info.x;
-    oam->y = kEnemyBombExplosion_Y[j] + info.y;
-    oam->charnum = kEnemyBombExplosion_Char[j];
-    oam->flags = kEnemyBombExplosion_Flags[j] | info.flags;
-  }
-  Sprite_CorrectOamEntries(k, 3, 2);
-}
-
-void Sprite_41_BlueGuard(int k) {  // 85c155
-  if (sprite_C[k])
-    Probe(k);
-  else
-    Guard_Main(k);
-}
-
-void Probe(int k) {  // 85c15d
-  SpriteAddXY(k, (int8)sprite_x_vel[k], (int8)sprite_y_vel[k]);
-  bool is_close;
-  if (sprite_type[sprite_C[k] - 1] == 0xce) {
-    // parent is blind the thief?
-    uint16 x = cur_sprite_x - link_x_coord + 16;
-    uint16 y = link_y_coord - cur_sprite_y + 24;
-    is_close = (x < 32 && y < 32);
-  } else {
-    if (Probe_CheckTileSolidity(k) && sprite_tiletype != 9 || link_cape_mode != 0) {
-      sprite_state[k] = 0;
-      return;
-    }
-    uint16 x = cur_sprite_x - link_x_coord;
-    uint16 y = cur_sprite_y - link_y_coord;
-    is_close = (x < 16 && y < 16 && sprite_floor[k] == link_is_on_lower_level);
-  }
-  if (is_close) {
-    int p = sprite_C[k] - 1;
-    if (sprite_ai_state[p] != 3) {
-      sprite_ai_state[p] = 3;
-      if (sprite_type[p] != 0xce) {
-        sprite_delay_main[p] = 16;
-        sprite_subtype2[p] = 0;
-      }
-    }
-    sprite_state[k] = 0;
-  } else {
-    PrepOamCoordsRet oam;
-    if (Sprite_PrepOamCoordOrDoubleRet(k, &oam))
-      return;
-    if ((oam.x | oam.y) >= 256)
-      sprite_state[k] = 0;
-  }
-}
-
-void Guard_Main(int k) {  // 85c227
-  uint8 bak1 = sprite_graphics[k];
-  uint8 bak2 = sprite_D[k];
-
-  if (sprite_delay_aux1[k]) {
-    sprite_D[k] = kSoldier_DirectionLockSettings[bak2];
-    sprite_graphics[k] = kSoldier_Gfx[bak2];
-  }
-  Guard_HandleAllAnimation(k);
-  sprite_D[k] = bak2;
-  sprite_graphics[k] = bak1;
-
-  if (sprite_state[k] == 5) {
-    if (submodule_index == 0) {
-      sprite_subtype2[k]++;
-      Guard_TickAndUpdateBody(k);
-      sprite_subtype2[k]++;
-      Guard_TickAndUpdateBody(k);
-    }
-    return;
-  }
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  Guard_ParrySwordAttacks(k);
-  if ((Sprite_CheckDamageToLink(k) || sprite_alert_flag) && sprite_ai_state[k] < 3) {
-    sprite_ai_state[k] = 3;
-    Guard_SetTimerAndAssertTileHitBox(k, 0x20);
-  } else if (sprite_F[k] != 0 && sprite_F[k] >= 4) {
-    sprite_ai_state[k] = 4;
-    Guard_SetTimerAndAssertTileHitBox(k, 0x80);
-  }
-  if (Sprite_ReturnIfRecoiling(k))
-    return;
-  if ((sprite_subtype[k] & 7) < 5) {
-    if (!sprite_wallcoll[k])
-      Sprite_MoveXY(k);
-    Sprite_CheckTileCollision(k);
-  } else {
-    Sprite_MoveXY(k);
-  }
-  if (sprite_ai_state[k] != 4)
-    sprite_G[k] = 0;
-
-  switch (sprite_ai_state[k]) {
-  case 0:
-    Sprite_ZeroVelocity_XY(k);
-    if (sprite_delay_main[k])
-      break;
-    sprite_ai_state[k]++;
-    if (sprite_subtype[k] && (sprite_subtype[k] & 7) < 5) {
-      sprite_delay_main[k] = kSoldier_Delay[sprite_subtype[k] >> 3 & 3];
-      sprite_D[k] ^= 1;
-      sprite_subtype2[k] = 0;
-    } else {
-      sprite_delay_main[k] = (GetRandomNumber() & 0x3f) + 0x28; // note: adc
-      uint8 t = sprite_D[k], u = GetRandomNumber() & 3;
-      sprite_D[k] = u;
-      if (t == u || (t ^ u) & 2)
-        return;
-    }
-    sprite_delay_aux1[k] = 12;
-    break;
-  case 1: {
-    Sprite_Guard_SendOutProbe(k);
-    if ((sprite_subtype[k] & 7) >= 5) {
-      Guard_ShootProbeAndStuff(k);
-      return;
-    }
-    if (!sprite_delay_main[k]) {
-      Sprite_ZeroVelocity_XY(k);
-      sprite_ai_state[k] = 2;
-      sprite_delay_main[k] = 160;
-      return;
-    }
-    if (!(sprite_subtype2[k] & 1))
-      sprite_delay_main[k]++;
-    if (sprite_wallcoll[k] & 0xf) {
-      sprite_D[k] ^= 1;
-      Guard_SetGlanceTo12(k);
-    }
-    int dir = sprite_D[k];
-    sprite_x_vel[k] = kSoldier_Xvel[dir];
-    sprite_y_vel[k] = kSoldier_Yvel[dir];
-    sprite_head_dir[k] = dir;
-    Guard_TickAndUpdateBody(k);
-    break;
-  }
-  case 2: {
-    Sprite_ZeroVelocity_XY(k);
-    Sprite_Guard_SendOutProbe(k);
-    if (sprite_delay_main[k] == 0) {
-      sprite_delay_main[k] = 0x20;
-      sprite_ai_state[k] = 0;
-    } else if (sprite_delay_main[k] < 0x80) {
-      int t = sprite_D[k] * 8 | (sprite_delay_main[k] >> 3 & 7);
-      sprite_head_dir[k] = kSoldier_HeadDirs[t];
-    }
-    break;
-  }
-  case 3:
-    Sprite_ZeroVelocity_XY(k);
-    sprite_head_dir[k] = Sprite_DirectionToFaceLink(k, NULL);
-    if (sprite_delay_main[k] == 0) {
-      sprite_ai_state[k] = 4;
-      Guard_SetTimerAndAssertTileHitBox(k, 255);
-    }
-    break;
-  case 4:
-    if (sprite_delay_main[k]) {
-      Soldier_Func12(k);
-    } else {
-      sprite_anim_clock[k] = kSoldier_Tab1[sprite_D[k]];
-      Sprite_ZeroVelocity_XY(k);
-      sprite_ai_state[k] = 2;
-      sprite_delay_main[k] = 160;
-    }
-    break;
-  }
-}
-
-void Guard_SetGlanceTo12(int k) {  // 85c32b
-  sprite_delay_aux1[k] = 12;
-}
-
-void Guard_ShootProbeAndStuff(int k) {  // 85c3a1
-  int i = sprite_B[k];
-  sprite_x_vel[k] = kSoldierB_Xvel[i];
-  sprite_y_vel[k] = kSoldierB_Yvel[i];
-  Sprite_CheckTileCollision(k);
-  if (sprite_delay_aux2[k]) {
-    if (sprite_delay_aux2[k] == 44)
-      sprite_B[k] = i = kSoldierB_NextB[i];
-  } else if (!(sprite_wallcoll[k] & kSoldierB_Mask[i])) {
-    sprite_delay_aux2[k] = 88;
-  }
-  if (sprite_wallcoll[k] & kSoldierB_Mask2[i])
-    sprite_B[k] = i = kSoldierB_NextB2[i];
-  sprite_x_vel[k] = kSoldierB_Xvel2[i];
-  sprite_y_vel[k] = kSoldierB_Yvel2[i];
-  sprite_head_dir[k] = sprite_D[k] = kSoldierB_Dir[i];
-  Guard_TickAndUpdateBody(k);
-}
-
-void Guard_TickAndUpdateBody(int k) {  // 85c454
-  sprite_subtype2[k]++;
-  int t = sprite_D[k] * 4 + (sprite_subtype2[k] >> 3 & 3);
-  sprite_graphics[k] = kSoldier_Gfx2[t];
-}
-
-void Guard_SetTimerAndAssertTileHitBox(int k, uint8 a) {  // 85c4d7
-  sprite_delay_main[k] = a;
-  sprite_subtype[k] = 0;
-  sprite_flags[k] = sprite_flags[k] & 0xf | 0x60;
-}
-
-void Soldier_Func12(int k) {  // 85c500
-  if (((k ^ frame_counter) & 0x1f) == 0) {
-    if (!sprite_G[k]) {
-      sprite_G[k] = 1;
-      SpriteSfx_QueueSfx3WithPan(k, 4);
-    }
-    Sprite_ApplySpeedTowardsLink(k, 16);
-    sprite_D[k] = sprite_head_dir[k] = Sprite_DirectionToFaceLink(k, NULL);
-  }
-  Guard_ApplySpeedInDirection(k);
-  sprite_subtype2[k]++;
-  Guard_TickAndUpdateBody(k);
-}
-
-void Guard_ApplySpeedInDirection(int k) {  // 85c542
-  if (!sprite_wallcoll[k])
-    return;
-  int i;
-  if (sprite_wallcoll[k] & 3) {
-    i = 2 + Sprite_IsBelowLink(k).a;
-  } else {
-    i = Sprite_IsRightOfLink(k).a;
-  }
-  sprite_x_vel[k] = kSoldier_SetTowardsVel[i];
-  sprite_y_vel[k] = kSoldier_SetTowardsVel[i + 2];
-}
-
-void Sprite_Guard_SendOutProbe(int k) {  // 85c5f2
-  if ((k + frame_counter & 3) | sprite_pause[k])
-    return;
-  uint8 a = sprite_anim_clock[k]++;
-  uint8 r15 = ((a & 0x1f) + kSprite_SpawnProbeStaggered_Tab[sprite_D[k]]) & 0x3f;
-  Sprite_SpawnProbeAlways(k, r15);
-}
-
-void Sprite_SpawnProbeAlways(int k, uint8 r15) {  // 85c612
-  SpriteSpawnInfo info;
-  int j = Sprite_SpawnDynamicallyEx(k, 0x41, &info, 10);
-  if (j < 0)
-    return;
-  int t = info.r0_x + 8;
-  sprite_x_lo[j] = t;
-  sprite_x_hi[j] = t >> 8;
-  t = info.r2_y + 4;
-  sprite_y_lo[j] = t;
-  sprite_y_hi[j] = t >> 8;
-  sprite_D[j] = r15;
-  sprite_x_vel[j] = kSpawnProbe_Xvel[r15];
-  sprite_y_vel[j] = kSpawnProbe_Yvel[r15];
-  sprite_flags2[j] = sprite_flags2[j] & 0xf0 | 0xa0;
-  sprite_C[j] = k + 1;
-  sprite_ignore_projectile[j] = k + 1;
-  sprite_flags4[j] = 0x40;
-  sprite_flags3[j] = 0x40;
-  sprite_defl_bits[j] = 2;
-}
-
-void Guard_HandleAllAnimation(int k) {  // 85c680
-  PrepOamCoordsRet poc;
-  if (Sprite_PrepOamCoordOrDoubleRet(k, &poc))
-    return;
-  Guard_AnimateHead(k, 0, &poc);
-  Guard_AnimateBody(k, kSoldier_Draw2_OamIdx[sprite_D[k]] >> 2, &poc);
-  Guard_AnimateWeapon(k, &poc);
-  if (sprite_flags3[k] & 0x10)
-    SpriteDraw_Shadow_custom(k, &poc, kSoldier_DrawShadow[sprite_D[k]]);
-}
-
-void Guard_AnimateHead(int k, int oam_offs, const PrepOamCoordsRet *poc) {  // 85c6de
-  OamEnt *oam = GetOamCurPtr() + oam_offs;
-  int dir = sprite_head_dir[k];
-  SetOamHelper0(oam, poc->x, poc->y - kSoldier_Draw1_Yd[sprite_graphics[k]],
-                kSoldier_Draw1_Char[dir], kSoldier_Draw1_Flags[dir] | poc->flags, 2);
-}
-
-void Guard_AnimateBody(int k, int oam_idx, const PrepOamCoordsRet *poc) {  // 85ca09
-  int g = sprite_graphics[k] * 4;
-  uint8 type = sprite_type[k];
-  OamEnt *oam = GetOamCurPtr() + oam_idx;
-  for (int i = 3; i >= 0; i--) {
-    int j = i + g;
-    if (type >= 0x46 && (!kSoldier_Draw2_Big[j] || i == 3 && kSoldier_Draw2_Char[j] == 0x20))
-      continue;
-    uint8 flags = kSoldier_Draw2_Flags[j] | poc->flags;
-    if (kSoldier_Draw2_Char[j] == 0x20) {
-      flags = flags & 0xf1 | 2;
-    } else if (kSoldier_Draw2_Big[j] == 0) {
-      flags = flags & 0xf1 | 8;
-    }
-    SetOamHelper0(oam, poc->x + kSoldier_Draw2_Xd[j], poc->y + kSoldier_Draw2_Yd[j],
-                  kSoldier_Draw2_Char[j], flags, kSoldier_Draw2_Big[j]);
-    if (oam->charnum == 0x20 && type == 0x46)
-      oam->y = 0xf0;
-    oam++;
-  }
-}
-
-void Guard_AnimateWeapon(int k, const PrepOamCoordsRet *poc) {  // 85cb64
-  int oam_idx = kSoldier_Draw3_OamIdx[sprite_D[k]] >> 2;
-  int g = sprite_graphics[k] * 2;
-  uint8 type = sprite_type[k];
-  OamEnt *oam = GetOamCurPtr() + oam_idx;
-  for (int i = 1; i >= 0; i--, oam++) {
-    int j = i + g;
-    dungmap_var8 = kSoldier_Draw3_Xd[j] << 8 | (uint8)kSoldier_Draw3_Yd[j];
-    SetOamHelper0(oam, poc->x + kSoldier_Draw3_Xd[j], poc->y + kSoldier_Draw3_Yd[j],
-                  kSoldier_Draw3_Char[j] + (type < 0x43 ? 3 : 0),
-                  kSoldier_Draw3_Flags[j] | poc->flags, 0);
-  }
-}
-
-void Sprite_45_HogSpearMan(int k) {  // 85cbe0
-  Guard_HandleAllAnimation(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  BoltGuard_TriggerChaseTheme(k);
-  Guard_ParrySwordAttacks(k);
-  if (Sprite_ReturnIfRecoiling(k))
-    return;
-  if (!sprite_wallcoll[k])
-    Sprite_MoveXY(k);
-  Sprite_CheckTileCollision(k);
-  Sprite_CheckDamageToLink(k);
-  if (!((k ^ frame_counter) & 15)) {
-    sprite_head_dir[k] = sprite_D[k] = Sprite_DirectionToFaceLink(k, NULL);
-    Sprite_ApplySpeedTowardsLink(k, 18);
-    Guard_ApplySpeedInDirection(k);
-  }
-  sprite_subtype2[k]++;
-  Guard_TickAndUpdateBody(k);
-}
-
-void BoltGuard_TriggerChaseTheme(int k) {  // 85cc3c
-  if (sprite_G[k] != 16 && sprite_G[k]++ == 15) {
-    SpriteSfx_QueueSfx3WithPan(k, 0x4);
-    if (sram_progress_indicator == 2 && BYTE(overworld_area_index) == 24)
-      music_control = 12;
-  }
-}
-
-void Sprite_44_BluesainBolt(int k) {  // 85cc65
-  PsychoTrooper_Draw(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  BoltGuard_TriggerChaseTheme(k);
-  Guard_ParrySwordAttacks(k);
-  if (Sprite_ReturnIfRecoiling(k))
-    return;
-  if (!sprite_wallcoll[k])
-    Sprite_MoveXY(k);
-  Sprite_CheckTileCollision(k);
-  Sprite_CheckDamageToLink(k);
-  if (!((k ^ frame_counter) & 15)) {
-    sprite_D[k] = sprite_head_dir[k] = Sprite_DirectionToFaceLink(k, NULL);
-    Sprite_ApplySpeedTowardsLink(k, 18);
-    Guard_ApplySpeedInDirection(k);
-  }
-  sprite_graphics[k] = kFlailTrooperGfx[++sprite_subtype2[k] >> 1 & 7 | sprite_D[k] << 3];
-}
-
-void PsychoTrooper_Draw(int k) {  // 85ccd5
-  PrepOamCoordsRet info;
-  if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
-    return;
-  SpriteDraw_GuardHead(k, &info, 3);
-  SpriteDraw_BNCBody(k, &info, 2);
-  SpriteDraw_GuardSpear(k, &info, 0);
-  if (sprite_flags3[k] & 0x10)
-    SpriteDraw_Shadow_custom(k, &info, kSoldier_DrawShadow[sprite_D[k]]);
-}
-
-void SpriteDraw_GuardSpear(int k, PrepOamCoordsRet *info, int spr_offs) {  // 85cd54
-  static const int8 kSolderThrowing_Draw_X[16] = {15, 7, 17, 9, -8, 0, -10, -2, 13, 13, 13, 13, -4, -4, -4, -4};
-  static const int8 kSolderThrowing_Draw_Y[16] = {-2, -2, -2, -2, -2, -2, -2, -2, 8, 0, 10, 2, -14, -6, -16, -8};
-  static const uint8 kSolderThrowing_Draw_Char[16] = {0x6f, 0x7f, 0x6f, 0x7f, 0x6f, 0x7f, 0x6f, 0x7f, 0x6e, 0x7e, 0x6e, 0x7e, 0x6e, 0x7e, 0x6e, 0x7e};
-  static const uint8 kSolderThrowing_Draw_Flags[16] = {0x40, 0x40, 0x40, 0x40, 0, 0, 0, 0, 0x80, 0x80, 0x80, 0x80, 0, 0, 0, 0};
-
-  OamEnt *oam = GetOamCurPtr() + spr_offs;
-  uint8 r6 = sprite_D[k] * 4 + (((sprite_A[k] ^ 1) << 1) & 2);
-  for (int i = 1; i >= 0; i--, oam++) {
-    int j = r6 + i;
-    uint16 x = info->x + kSolderThrowing_Draw_X[j];
-    uint16 y = info->y + kSolderThrowing_Draw_Y[j];
-    HIBYTE(dungmap_var8) = kSolderThrowing_Draw_X[j];
-    BYTE(dungmap_var8) = kSolderThrowing_Draw_Y[j];
-    SetOamHelper0(oam, x, y,
-                  kSolderThrowing_Draw_Char[j] - (sprite_type[k] >= 0x48 ? 3 : 0),
-                  (kSolderThrowing_Draw_Flags[j] | info->flags) & 0xf1 | 8, 0);
-  }
-}
-
-void Sprite_48_RedJavelinGuard(int k) {  // 85cde1
-  static const uint8 kJavelinTrooper_Gfx[4] = {12, 0, 18, 8};
-  uint8 bak0 = sprite_graphics[k];
-  int j = sprite_D[k];
-  if (sprite_delay_aux1[k] != 0) {
-    sprite_D[k] = kSoldier_DirectionLockSettings[j];
-    sprite_graphics[k] = kJavelinTrooper_Gfx[j];
-  }
-  JavelinTrooper_Draw(k);
-  sprite_D[k] = j;
-  sprite_graphics[k] = bak0;
-  SoldierThrowing_Common(k);
-}
-
-void Sprite_46_BlueArcher(int k) {  // 85cdff
-  uint8 bak0 = sprite_graphics[k];
-  int j = sprite_D[k];
-  if (sprite_delay_aux1[k] != 0) {
-    sprite_D[k] = kSoldier_DirectionLockSettings[j];
-    sprite_graphics[k] = kSoldier_Gfx[j];
-  }
-  ArcherSoldier_Draw(k);
-  sprite_D[k] = j;
-  sprite_graphics[k] = bak0;
-  SoldierThrowing_Common(k);
-}
-
-void SoldierThrowing_Common(int k) {  // 85ce23
-  int j;
-
-  static const uint8 kSolderThrowing_DirFlags[4] = {3, 3, 12, 12};
-  static const int8 kSolderThrowing_Xd[8] = {-80, 80, 0, -8, -80, 80, -8, 8};
-  static const int8 kSolderThrowing_Yd[8] = {8, 8, -80, 80, 8, 8, -80, 80};
-
-  if (Sprite_ReturnIfInactive(k))
-    return;
-
-  if ((Sprite_CheckDamageToAndFromLink(k) || sprite_alert_flag) && sprite_ai_state[k] < 3) {
-    sprite_ai_state[k] = 3;
-    sprite_delay_main[k] = 32;
-  }
-  if (sprite_F[k] >= 4) {
-    sprite_ai_state[k] = 4;
-    sprite_delay_main[k] = 60;
-    sprite_subtype2[k] = 0;
-  }
-  if (Sprite_ReturnIfRecoiling(k))
-    return;
-  if (!sprite_wallcoll[k])
-    Sprite_MoveXY(k);
-  Sprite_CheckTileCollision(k);
-  switch (sprite_ai_state[k]) {
-  case 0:  // resting
-    Sprite_ZeroVelocity_XY(k);
-    if (sprite_delay_main[k] == 0) {
-      sprite_ai_state[k]++;
-      sprite_delay_main[k] = 0x50 + (GetRandomNumber() & 0x7f);
-      uint8 jbak = sprite_D[k];
-      sprite_D[k] = GetRandomNumber() & 3;
-      if (sprite_D[k] != jbak && !((sprite_D[k] ^ jbak) & 2))
-        sprite_delay_aux1[k] = 12;
-    }
-    break;
-  case 1:  // walking
-    if (sprite_delay_main[k] == 0) {
-      sprite_ai_state[k] = 2;
-      sprite_delay_main[k] = 160;
-      return;
-    }
-    Sprite_Guard_SendOutProbe(k);
-    if (sprite_wallcoll[k] & 0xf) {
-      sprite_D[k] ^= 1;
-      Guard_SetGlanceTo12(k);
-    }
-    j = sprite_D[k];
-    sprite_x_vel[k] = kSoldier_Xvel[j];
-    sprite_y_vel[k] = kSoldier_Yvel[j];
-    sprite_head_dir[k] = j;
-agitated_jump_to:
-    sprite_subtype2[k]++;
-    if (!(sprite_subtype2[k] & 0xf) && ++sprite_A[k] == 2)
-      sprite_A[k] = 0;
-    sprite_graphics[k] = kSoldier_Gfx2[sprite_D[k] * 4 + sprite_A[k] + (sprite_type[k] == 0x48 ? 16 : 0)];
-    break;
-  case 2:  // looking
-    Sprite_ZeroVelocity_XY(k);
-    Sprite_Guard_SendOutProbe(k);
-    if (sprite_delay_main[k] == 0) {
-      sprite_delay_main[k] = 32;
-      sprite_ai_state[k] = 0;
-    } else if (sprite_delay_main[k] < 0x80) {
-      int t = sprite_D[k] * 8 | (sprite_delay_main[k] >> 3 & 7);
-      sprite_head_dir[k] = kSoldier_HeadDirs[t];
-    }
-    break;
-  case 3:  // noticed player
-    Sprite_ZeroVelocity_XY(k);
-    sprite_head_dir[k] = Sprite_DirectionToFaceLink(k, NULL);
-    if (sprite_delay_main[k] == 0) {
-      sprite_ai_state[k] = 4;
-      sprite_delay_main[k] = 60;
-      sprite_subtype2[k] = 0;
-    }
-    break;
-  case 4:  // agitated
-    j = sprite_D[k];
-    if (sprite_wallcoll[k] & kSolderThrowing_DirFlags[j] || !sprite_delay_main[k]) {
-      sprite_ai_state[k]++;
-      sprite_delay_main[k] = 24;
-      return;
-    }
-    if (!((frame_counter ^ k) & 7)) {
-      sprite_D[k] = sprite_head_dir[k] = j = Sprite_DirectionToFaceLink(k, NULL);
-      if (sprite_type[k] == 0x48)
-        j += 4;
-      uint16 x = link_x_coord + kSolderThrowing_Xd[j];
-      uint16 y = link_y_coord + kSolderThrowing_Yd[j];
-      ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLocation(k, x, y, 24);
-      sprite_x_vel[k] = pt.x;
-      sprite_y_vel[k] = pt.y;
-      if ((uint8)(pt.xdiff + 6) < 12 && (uint8)(pt.ydiff + 6) < 12) {
-        sprite_ai_state[k]++;
-        sprite_delay_main[k] = 24;
-        return;
-      }
-    }
-    sprite_subtype2[k]++;
-    goto agitated_jump_to;
-  case 5:  // attack
-    sprite_anim_clock[k] = kSoldier_Tab1[sprite_D[k]];
-    Sprite_ZeroVelocity_XY(k);
-    if ((j = sprite_delay_main[k]) == 0) {
-      sprite_ai_state[k] = 2;
-      sprite_delay_main[k] = 160;
-      return;
-    }
-    sprite_subtype2[k] = (j >= 40) ? 255 : 0;
-    if (j == 12)
-      Guard_LaunchProjectile(k);
-    sprite_graphics[k] = kJavelinTrooper_Tab2[sprite_D[k] * 8 + (j >> 3) + (sprite_type[k] == 0x48 ? 32 : 0)];
-    break;
-  }
-}
-
-void Guard_LaunchProjectile(int k) {  // 85d0c5
-  static const int8 kJavelinProjectile_X[8] = {16, -8, 3, 11, 12, -4, 12, -4};
-  static const int8 kJavelinProjectile_Y[8] = {2, 2, 16, -8, -2, -2, 2, -8};
-  static const int8 kJavelinProjectile_Xvel[8] = {48, -48, 0, 0, 32, -32, 0, 0};
-  static const int8 kJavelinProjectile_Yvel[8] = {0, 0, 48, -48, 0, 0, 32, -32};
-  static const uint8 kJavelinProjectile_Flags4[4] = {5, 5, 6, 6};
-
-  SpriteSpawnInfo info;
-  int j = Sprite_SpawnDynamically(k, 0x1b, &info);
-  if (j < 0)
-    return;
-  SpriteSfx_QueueSfx3WithPan(k, 0x5);
-  int i = sprite_D[k] + (sprite_type[k] >= 0x48 ? 4 : 0);
-
-  Sprite_SetX(j, info.r0_x + kJavelinProjectile_X[i]);
-  Sprite_SetY(j, info.r2_y + kJavelinProjectile_Y[i]);
-  sprite_x_vel[j] = kJavelinProjectile_Xvel[i];
-  sprite_y_vel[j] = kJavelinProjectile_Yvel[i];
-  i &= 3;
-  sprite_D[j] = i;
-  sprite_flags4[j] = kJavelinProjectile_Flags4[i];
-  sprite_z[j] = 0;
-  sprite_A[j] = (sprite_type[k] >= 0x48);
-  if (sprite_A[j] && link_shield_type == 0)
-    sprite_flags5[j] &= ~0x20;
-}
-
-void BushJavelinSoldier_Draw(int k) {  // 85d141
-  uint8 bak0 = sprite_graphics[k];
-  sprite_graphics[k] = 0;
-  uint8 bak1 = sprite_oam_flags[k];
-  sprite_oam_flags[k] = sprite_oam_flags[k] & 0xf1 | 2;
-  uint16 bak2 = cur_sprite_y;
-  cur_sprite_y += 8;
-  SpriteDraw_SingleLarge(k);
-  cur_sprite_y = bak2;
-  sprite_oam_flags[k] = bak1;
-  sprite_graphics[k] = bak0;
-
-  PrepOamCoordsRet info;
-  if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
-    return;
-  Guard_AnimateHead(k, 0x10 / 4, &info);
-  SpriteDraw_BNCBody(k, &info, 0xC / 4);
-  if (sprite_graphics[k] < 20)
-    SpriteDraw_GuardSpear(k, &info, 4 / 4);
-  if (sprite_flags3[k] & 0x10)
-    SpriteDraw_Shadow_custom(k, &info, kSoldier_DrawShadow[sprite_D[k]]);
-
-}
-
-void JavelinTrooper_Draw(int k) {  // 85d192
-  PrepOamCoordsRet info;
-  if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
-    return;
-  SpriteDraw_GuardHead(k, &info, 3);
-  SpriteDraw_BNCBody(k, &info, 2);
-  if (sprite_graphics[k] < 20)
-    SpriteDraw_GuardSpear(k, &info, 0);
-  if (sprite_flags3[k] & 0x10)
-    SpriteDraw_Shadow_custom(k, &info, kSoldier_DrawShadow[sprite_D[k]]);
-}
-
-void Sprite_49_RedBushGuard(int k) {  // 85d1ac
-  if (sprite_ai_state[k]) {
-    if (sprite_ai_state[k] == 2)
-      BushJavelinSoldier_Draw(k);
-    else
-      BushSoldierCommon_Draw(k);
-  }
-  Sprite_BushGuard_Main(k);
-}
-
-void Sprite_47_GreenBushGuard(int k) {  // 85d1bf
-  if (sprite_ai_state[k]) {
-    if (sprite_graphics[k] >= 14)
-      ArcherSoldier_Draw(k);
-    else
-      BushSoldierCommon_Draw(k);
-  }
-  Sprite_BushGuard_Main(k);
-}
-
-void Sprite_BushGuard_Main(int k) {  // 85d1d3
-  int j;
-  static const uint8 kBushSoldier_Gfx[32] = {
-    4, 4, 4, 4, 4, 4, 4, 4, 0, 1, 0, 1, 0, 1, 0, 1,
-    0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
-  };
-  static const uint8 kBushSoldier_Gfx2[16] = {0, 1, 0, 1, 0, 1, 0, 1, 0, 2, 3, 4, 4, 4, 4, 4};
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  sprite_ignore_projectile[k] = 1;
-  switch (sprite_ai_state[k]) {
-  case 0:
-    if (!sprite_delay_main[k]) {
-      sprite_ai_state[k] = 1;
-      sprite_delay_main[k] = 64;
-    }
-    break;
-  case 1:
-    Sprite_CheckDamageFromLink(k);
-    if (sprite_delay_main[k] == 0) {
-      sprite_ai_state[k] = 2;
-      sprite_delay_main[k] = 48;
-      sprite_head_dir[k] = sprite_D[k] = Sprite_DirectionToFaceLink(k, NULL);;
-    } else {
-      if (sprite_delay_main[k] == 0x20)
-        BushGuard_SpawnFoliage(k);
-      sprite_graphics[k] = kBushSoldier_Gfx[sprite_delay_main[k] >> 2];
-    }
-    break;
-  case 2:
-    sprite_ignore_projectile[k] = 0;
-    Sprite_CheckDamageToAndFromLink(k);
-    j = sprite_delay_main[k];
-    if (!j) {
-      sprite_ai_state[k] = 3;
-      sprite_delay_main[k] = 48;
-      goto case_3;
-    }
-    sprite_A[k] = j < 40 ? 0xff : 0x00;
-    if (j == 16)
-      Guard_LaunchProjectile(k);
-    sprite_graphics[k] = kJavelinTrooper_Tab2[sprite_D[k] * 8 + (j >> 3) + (sprite_type[k] == 0x49 ? 32 : 0)];
-    break;
-  case 3:
-  case_3:
-    Sprite_CheckDamageToAndFromLink(k);
-    if (!sprite_delay_main[k]) {
-      sprite_ai_state[k] = 0;
-      sprite_delay_main[k] = 64;
-    } else {
-      sprite_graphics[k] = kBushSoldier_Gfx2[sprite_delay_main[k] >> 2];
-    }
-    break;
-  }
-}
-
-void BushGuard_SpawnFoliage(int k) {  // 85d252
-  SpriteSpawnInfo info;
-  int j = Sprite_SpawnDynamically(k, 0xec, &info);
-  if (j < 0)
-    return;
-  Sprite_SetSpawnedCoordinates(j, &info);
-  sprite_state[j] = 6;
-  sprite_delay_main[j] = 32;
-  sprite_flags2[j] += 3;
-  sprite_C[j] = 2;
-}
-
-void BushSoldierCommon_Draw(int k) {  // 85d321
-  static const int8 kBushSoldierCommon_Y[14] = {8, 8, 8, 8, 2, 8, 0, 8, -3, 8, -3, 8, -3, 8};
-  static const uint8 kBushSoldierCommon_Char[14] = {0x20, 0x20, 0x20, 0x20, 0x40, 0x20, 0x40, 0x20, 0x40, 0x20, 0x42, 0x20, 0x42, 0x20};
-  static const uint8 kBushSoldierCommon_Flags[14] = {9, 3, 0x49, 0x43, 9, 3, 0x49, 0x43, 9, 3, 0x49, 0x43, 9, 3};
-  PrepOamCoordsRet info;
-  if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
-    return;
-  OamEnt *oam = GetOamCurPtr();
-  int g = sprite_graphics[k] * 2;
-  for (int i = 1; i >= 0; i--, oam++) {
-    int j = g + i;
-    uint8 flags = kBushSoldierCommon_Flags[j] | 0x20;
-    if (i == 0)
-      flags = flags & ~0xe | info.flags;
-    SetOamHelper0(oam, info.x, info.y + kBushSoldierCommon_Y[j], kBushSoldierCommon_Char[j], flags, 2);
-  }
-}
-
-void ArcherSoldier_Draw(int k) {  // 85d38c
-  static const uint8 kArcherSoldier_WeaponOamOffs[4] = {0, 0, 0, 16};
-  static const uint8 kArcherSoldier_HeadOamOffs[4] = {16, 16, 16, 0};
-  static const uint8 kArcherSoldier_BodyOamOffs[4] = {20, 20, 20, 4};
-  PrepOamCoordsRet info;
-  if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
-    return;
-  Guard_AnimateHead(k, kArcherSoldier_HeadOamOffs[sprite_D[k]] >> 2, &info);
-  Guard_AnimateBody(k, kArcherSoldier_BodyOamOffs[sprite_D[k]] >> 2, &info);
-  SpriteDraw_Archer_Weapon(k, kArcherSoldier_WeaponOamOffs[sprite_D[k]] >> 2, &info);
-  if (sprite_flags3[k] & 0x10)
-    SpriteDraw_Shadow_custom(k, &info, kSoldier_DrawShadow[sprite_D[k]]);
-}
-
-void SpriteDraw_Archer_Weapon(int k, int spr_offs, PrepOamCoordsRet *info) {  // 85d4d4
-  static const uint8 kArcherSoldier_Tab1[4] = {9, 3, 0, 6};
-  static const int8 kArcherSoldier_Draw_X[48] = {
-    -1,  7,  3,  3, -1,  7,  3,  3, -1,  7,  7,  7, -5, -5, -10, -2,
-    -4, -4, -6,  2, -5, -5, -5, -5,  6, 14, 11, 11,  6, 14,  11, 11,
-    6, 14, 14, 14, 11, 11, 18, 10, 12, 12, 14,  6, 11, 11,  11, 11,
-  };
-  static const int8 kArcherSoldier_Draw_Y[48] = {
-    7,  7,  3, 11,  6, 6, 1, 9,  7,  7,   7,  7, -2,  6,  2,  2,
-    -2,  6,  2,  2, -2, 6, 6, 6, -6, -6, -12, -4, -6, -6, -9, -1,
-    -6, -6, -6, -6, -2, 6, 2, 2, -2,  6,   2,  2, -2,  6,  6,  6,
-  };
-  static const uint8 kArcherSoldier_Draw_Char[48] = {
-    0xa,  0xa, 0x2a, 0x2b, 0x1a, 0x1a, 0x2a, 0x2b,  0xa,  0xa,  0xa,  0xa, 0xb, 0xb, 0x3d, 0x3a,
-    0x1b, 0x1b, 0x3d, 0x3a,  0xb,  0xb,  0xb,  0xb,  0xa,  0xa, 0x2b, 0x2a, 0xa, 0xa, 0x2b, 0x2a,
-    0xa,  0xa,  0xa,  0xa,  0xb,  0xb, 0x3d, 0x3a, 0x1b, 0x1b, 0x3d, 0x3a, 0xb, 0xb,  0xb,  0xb,
-  };
-  static const uint8 kArcherSoldier_Draw_Flags[48] = {
-    0xd, 0x4d,    8,    8,  0xd, 0x4d,    8,    8,  0xd, 0x4d, 0x4d, 0x4d,  0xd, 0x8d, 0x48, 0x48,
-    0xd, 0x8d, 0x48, 0x48,  0xd, 0x8d, 0x8d, 0x8d, 0x8d, 0xcd, 0x88, 0x88, 0x8d, 0xcd, 0x88, 0x88,
-    0x8d, 0xcd, 0xcd, 0xcd, 0x4d, 0xcd,    8,    8, 0x4d, 0xcd,    8,    8, 0x4d, 0xcd, 0xcd, 0xcd,
-  };
-  OamEnt *oam = GetOamCurPtr() + spr_offs;
-  int base = sprite_graphics[k] - 14;
-  if (base < 0)
-    base = kArcherSoldier_Tab1[sprite_D[k]];
-  for (int i = 3; i >= 0; i--, oam++) {
-    int j = base * 4 + i;
-    SetOamHelper0(oam, info->x + kArcherSoldier_Draw_X[j], info->y + kArcherSoldier_Draw_Y[j], kArcherSoldier_Draw_Char[j], kArcherSoldier_Draw_Flags[j] | 0x20, 0);
-  }
-}
-
-void TutorialSoldier_Draw(int k) {  // 85d64b
-  PrepOamCoordsRet info;
-  if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
-    return;
-  OamEnt *oam = GetOamCurPtr();
-  int d = sprite_graphics[k] * 5;
-  for (int i = 4; i >= 0; i--, oam++) {
-    int j = d + i;
-    uint8 flags = kTutorialSoldier_Flags[j] | info.flags;
-    if (kTutorialSoldier_Char[j] < 0x40)
-      flags = (flags & 0xf1) | 8;
-    SetOamHelper0(oam, info.x + kTutorialSoldier_X[j], info.y + kTutorialSoldier_Y[j], kTutorialSoldier_Char[j], flags, kTutorialSoldier_Big[j]);
-  }
-  SpriteDraw_Shadow_custom(k, &info, 12);
-}
-
-void PullSwitch_FacingUp(int k) {  // 85d6d4
-  static const uint8 kBadPullSwitch_Tab1[10] = {8, 24, 4, 4, 4, 4, 4, 4, 2, 10};
-  static const uint8 kBadPullSwitch_Tab0[10] = {6, 7, 8, 8, 8, 8, 8, 9, 9, 9};
-  PullSwitch_HandleUpPulling(k);
-  int j = sprite_graphics[k];
-  if (j != 0 && j != 11) {
-    link_unk_master_sword = kBadPullSwitch_Tab0[j - 1];
-    link_y_coord = Sprite_GetY(k) - 19;
-    link_x_coord = Sprite_GetX(k);
-    if (sprite_delay_main[k] == 0) {
-      sprite_graphics[k] = ++j;
-      if (j == 11) {
-        sound_effect_2 = 0x1b;
-        dung_flag_statechange_waterpuzzle = 1;
-      }
-      sprite_delay_main[k] = kBadPullSwitch_Tab1[j - 2];
-    }
-  }
-  if (sprite_type[k] != 7)
-    BadPullDownSwitch_Draw(k);
-  else
-    BadPullUpSwitch_Draw(k);
-}
-
-void PullSwitch_HandleUpPulling(int k) {  // 85d743
-  if (!Sprite_CheckDamageToLink_same_layer(k))
-    return;
-  link_actual_vel_y = 0;
-  link_actual_vel_x = 0;
-  Sprite_RepelDash();
-  bitmask_of_dragstate = 0;
-  uint8 y = link_y_coord - sprite_y_lo[k];
-  if (!sign8(y - 2)) {
-    link_y_coord = Sprite_GetY(k) + 9;
-  } else if (sign8(y - 244)) {
-    byte_7E0379++;
-    if (joypad1L_last & 0x80 && !(joypad1H_last & 3) && sprite_graphics[k] == 0) {
-      sprite_graphics[k] = 1;
-      sprite_delay_main[k] = 8;
-      SpriteSfx_QueueSfx2WithPan(k, 0x22);
-    }
-    link_y_coord = Sprite_GetY(k) - 21;
-  } else {
-    if (sign8(link_x_coord - sprite_x_lo[k]))
-      link_x_coord = Sprite_GetX(k) - 16;
-    else
-      link_x_coord = Sprite_GetX(k) + 14;
-  }
-}
-
-void BadPullDownSwitch_Draw(int k) {  // 85d7f9
-  PrepOamCoordsRet info;
-  if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
-    return;
-  Oam_AllocateDeferToPlayer(k);
-  OamEnt *oam = GetOamCurPtr();
-  uint8 yoff = kBadPullSwitch_Tab5[kBadPullSwitch_Tab4[sprite_graphics[k]]];
-  for (int i = 4; i >= 0; i--, oam++) {
-    SetOamPlain(oam, info.x + kBadPullDownSwitch_X[i], info.y + kBadPullDownSwitch_Y[i] - (i == 2 ? yoff : 0),
-                 kBadPullDownSwitch_Char[i], kBadPullDownSwitch_Flags[i] | 0x21, kBadPullDownSwitch_Big[i]);
-  }
-  Sprite_CorrectOamEntries(k, 4, 0xff);
-}
-
-void BadPullUpSwitch_Draw(int k) {  // 85d858
-  static const uint8 kBadPullUpSwitch_Tab2[2] = {0xa2, 0xa4};
-  PrepOamCoordsRet info;
-  if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
-    return;
-  Oam_AllocateDeferToPlayer(k);
-  OamEnt *oam = GetOamCurPtr();
-  uint8 yoff = kBadPullSwitch_Tab5[kBadPullSwitch_Tab4[sprite_graphics[k]]];
-  for (int i = 1; i >= 0; i--, oam++) {
-    SetOamHelper0(oam, info.x, info.y - ((i == 0) ? yoff : 0), kBadPullUpSwitch_Tab2[i], info.flags, 2);
-  }
-}
-
-void PullSwitch_FacingDown(int k) {  // 85d8b5
-  static const uint8 kGoodPullSwitch_Tab1[12] = {5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5};
-  static const uint8 kGoodPullSwitch_Tab0[12] = {1, 1, 2, 2, 3, 3, 1, 1, 4, 4, 5, 5};
-  static const uint8 kGoodPullSwitch_YOffs[12] = {9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14};
-  PullSwitch_HandleDownPulling(k);
-  int j = sprite_graphics[k];
-  if (j != 0 && j != 13) {
-    link_unk_master_sword = kGoodPullSwitch_Tab0[j - 1];
-    link_y_coord = Sprite_GetY(k) + kGoodPullSwitch_YOffs[j - 1];
-    link_x_coord = Sprite_GetX(k);
-    if (sprite_delay_main[k] == 0) {
-      sprite_graphics[k] = ++j;
-      if (j == 13) {
-        if (sprite_type[k] == 6) {
-          activate_bomb_trap_overlord = 1;
-          sound_effect_1 = 0x3c;
-        } else {
-          dung_flag_statechange_waterpuzzle = 1;
-          sound_effect_2 = 0x1b;
-        }
-      }
-      sprite_delay_main[k] = kGoodPullSwitch_Tab1[j - 2];
-    }
-  }
-  GoodPullSwitch_Draw(k);
-  if (sprite_pause[k])
-    sprite_graphics[k] = 0;
-}
-
-void GoodPullSwitch_Draw(int k) {  // 85d953
-  static const uint8 kGoodPullSwitch_Tab2[14] = {1, 1, 2, 3, 2, 3, 4, 5, 6, 7, 6, 7, 7, 7};
-  PrepOamCoordsRet info;
-  if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
-    return;
-  Oam_AllocateDeferToPlayer(k);
-  OamEnt *oam = GetOamCurPtr();
-  uint8 t = kGoodPullSwitch_Tab2[sprite_graphics[k]];
-  oam[0].x = oam[1].x = info.x;
-  oam[0].y = info.y - 1;
-  oam[1].y = info.y - 1 + t;
-  oam[0].charnum = 0xee;
-  oam[1].charnum = 0xce;
-  oam[0].flags = oam[1].flags = info.flags;
-  Sprite_CorrectOamEntries(k, 1, 2);
-}
-
-void PullSwitch_HandleDownPulling(int k) {  // 85d999
-  if (!Sprite_CheckDamageToLink_same_layer(k))
-    return;
-  link_actual_vel_y = 0;
-  link_actual_vel_x = 0;
-  Sprite_RepelDash();
-  bitmask_of_dragstate = 0;
-  uint8 y = link_y_coord - sprite_y_lo[k];
-  if (!sign8(y - 2)) {
-    byte_7E0379++;
-    if (joypad1L_last & 0x80 && !(joypad1H_last & 3)) {
-      link_unk_master_sword++;
-      if ((joypad1H_last & 4) && sprite_graphics[k] == 0) {
-        sprite_graphics[k] = 1;
-        sprite_delay_main[k] = 12;
-        SpriteSfx_QueueSfx2WithPan(k, 0x22);
-      }
-    }
-    link_y_coord = Sprite_GetY(k) + 9;
-  } else if (sign8(y - 244)) {
-    link_y_coord = Sprite_GetY(k) - 21;
-  } else {
-    if (sign8(link_x_coord - sprite_x_lo[k]))
-      link_x_coord = Sprite_GetX(k) - 16;
-    else
-      link_x_coord = Sprite_GetX(k) + 14;
-  }
-}
-
-void Priest_SpawnMantle(int k) {  // 85db27
-  sprite_state[15]++;
-  SpriteSpawnInfo info;
-  int j = Sprite_SpawnDynamically(k, 0x73, &info);
-  sprite_state[15] = 0;
-  sprite_flags2[j] = sprite_flags2[j] & 0xf0 | 0x3;
-  sprite_x_lo[j] = 0xF0;
-  sprite_x_hi[j] = 4;
-  sprite_y_lo[j] = 0x37;
-  sprite_y_hi[j] = 2;
-  sprite_E[j] = 2;
-  sprite_flags4[j] = 11;
-  sprite_defl_bits[j] |= 0x20;
-  sprite_subtype2[j] = 1;
-  if (link_y_coord < Sprite_GetY(j))
-    sprite_C[j] = 1;
-}
-
-void Sprite_SanctuaryMantle(int k) {  // 85db9b
-  SageMantle_Draw(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-
-  if (sprite_C[k]) {
-    sprite_A[k] = 0x40;
-    goto lbl2;
-  }
-  if (Sprite_CheckDamageToLink_same_layer(k)) {
-    Sprite_NullifyHookshotDrag();
-    link_speed_setting = 0;
-    Sprite_RepelDash();
-    sprite_delay_aux1[k] = 7;
-lbl:
-    sprite_subtype2[k] = 0;
-    bitmask_of_dragstate = 0x81;
-    link_speed_setting = 8;
-lbl2:
-    switch (sprite_ai_state[k]) {
-    case 0: {
-      uint16 x = Sprite_GetX(k);
-      Sprite_SetX(k, x + 19);
-      uint8 dir = Sprite_DirectionToFaceLink(k, NULL);
-      Sprite_SetX(k, x);
-      if (dir == 1 || dir == 3) {
-        sprite_A[k]++;
-        if (sprite_A[k] >= 64) {
-          sprite_ai_state[k]++;
-          flag_is_link_immobilized = 1;
-        }
-      }
-      break;
-    }
-    case 1:
-      SpriteSfx_QueueSfx3WithPan(k, 24);
-      sprite_ai_state[k]++;
-      sprite_delay_main[k] = 168;
-      sprite_x_vel[k] = 3;
-      sprite_delay_aux1[k] = 2;
-      break;
-    case 2:
-      Sprite_MoveXY(k);
-      if (sprite_delay_main[k] == 0) {
-        flag_is_link_immobilized = 0;
-        sprite_x_vel[k] = 0;
-        sprite_C[k] = 0;
-      } else {
-        sprite_delay_aux1[k] = 2;
-      }
-      break;
-    }
-  } else {  // no collision
-    if (sprite_delay_aux1[k])
-      goto lbl;
-    switch (sprite_subtype2[k]) {
-    case 0:
-      sprite_A[k] = 0;
-      bitmask_of_dragstate = 0;
-      link_speed_setting = 0;
-      sprite_subtype2[k]++;
-      break;
-    case 1:
-      break;
-    }
-  }
-}
-
-void SageMantle_Draw(int k) {  // 85dc8a
-  if (sprite_C[k] == 0)
-    Oam_AllocateFromRegionB(0x10);
-  Sprite_DrawMultiple(k, kSageMantle_Dmd, 4, NULL);
-}
-
-void Sprite_Priest(int k) {  // 85dce6
-  if (sprite_A[k] == 0)
-    Priest_Draw(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  Sprite_BehaveAsBarrier(k);
-  if (Sprite_TrackBodyToHead(k))
-    Sprite_MoveXY(k);
-  switch (sprite_subtype2[k]) {
-  case 0: Priest_Dying(k); break;
-  case 1: Priest_RunRescueCutscene(k); break;
-  case 2: Priest_Chillin(k); break;
-  }
-}
-
-void Priest_Dying(int k) {  // 85dd0a
-  sprite_head_dir[k] = 4;
-  sprite_D[k] = 4;
-  switch (sprite_ai_state[k]) {
-  case 0:  // Priest_LyingOnGround
-    if (Sprite_ShowSolicitedMessage(k, 0x1b) & 0x100) {
-      sprite_ai_state[k]++;
-      sprite_graphics[k]++;
-      sram_progress_flags |= 0x2;
-      sprite_delay_aux2[k] = 128;
-    }
-    break;
-  case 1:  // Priest_FinalWords
-    sprite_graphics[k] = 0;
-    if (sprite_delay_aux2[k] == 0)
-      sprite_ai_state[k]++;
-    sprite_A[k] = frame_counter & 2;
-    if (!(sprite_delay_aux2[k] & 7))
-      SpriteSfx_QueueSfx2WithPan(k, 0x33);
-    break;
-  case 2:  // Priest_Die
-    sprite_state[k] = 0;
-    break;
-  }
-}
-
-void Priest_RunRescueCutscene(int k) {  // 85dd63
-  int j;
-  switch (sprite_ai_state[k]) {
-  case 0:
-    sprite_head_dir[k] = 0;
-    sprite_D[k] = 0;
-    if (sprite_delay_main[k] == 0) {
-      Sprite_ShowMessageUnconditional(0x17);
-      sprite_ai_state[k]++;
-      byte_7FFE01 = 1;
-      Priest_SpawnRescuedPrincess();
-      flag_is_link_immobilized = 1;
-      savegame_map_icons_indicator = 1;
-    }
-    break;
-  case 1:
-    if (byte_7FFE01 == 2) {
-      Sprite_ShowMessageUnconditional(0x18);
-      sprite_ai_state[k]++;
-    }
-    break;
-  case 2:
-    if (choice_in_multiselect_box == 0) {
-      sprite_ai_state[k]++;
-      flag_is_link_immobilized = 0;
-    } else {
-      sprite_ai_state[k] = 1;
-    }
-    break;
-  case 3:
-    sprite_head_dir[k] = Sprite_DirectionToFaceLink(k, NULL) ^ 3;
-    j = Sprite_ShowSolicitedMessage(k, 0x16);
-    if (j & 0x100)
-      sprite_D[k] = sprite_head_dir[k] = (uint8)j;
-    break;
-  }
-}
-
-void Priest_Chillin(int k) {  // 85dde5
-  sprite_head_dir[k] = Sprite_DirectionToFaceLink(k, NULL) ^ 3;
-  int m = (link_which_pendants & 7) == 7 ? 0x1a :
-          savegame_map_icons_indicator >= 3 ? 0x19 : 0x16;
-  int j = Sprite_ShowSolicitedMessage(k, m);
-  if (j & 0x100) {
-    sprite_D[k] = sprite_head_dir[k] = (uint8)j;
-    link_hearts_filler = 0xa0;
-  }
-}
-
-void Sprite_Uncle(int k) {  // 85de2c
-  Uncle_Draw(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  if (sprite_subtype2[k] == 0)
-    Uncle_AtHouse(k);
-  else
-    Uncle_InPassage(k);
-}
-
-void Uncle_AtHouse(int k) {  // 85de3e
-  Sprite_MoveXY(k);
-  switch (sprite_ai_state[k]) {
-  case 0:  // Uncle_TriggerTelepathy
-    link_x_coord_prev = 0x940;
-    link_y_coord_prev = 0x215a;
-    Sprite_ShowMessageUnconditional(0x1f);
-    sprite_ai_state[k]++;
-    break;
-  case 1:  // Uncle_AwakenLink
-    if (frame_counter & 3)
-      break;
-    if (COLDATA_copy0 != 32) {
-      COLDATA_copy0--;
-      COLDATA_copy1--;
-      break;
-    }
-    link_pose_during_opening++;
-    player_sleep_in_bed_state++;
-    link_y_coord = 0x2157;
-    flag_is_link_immobilized = 1;
-    sprite_ai_state[k]++;
-    break;
-  case 2:  // Uncle_DeclareCurfew
-    Sprite_ShowMessageUnconditional(0x0d);
-    music_control = 3;
-    sprite_graphics[k] = 1;
-    sprite_ai_state[k]++;
-    break;
-  case 3:  // Uncle_Embark
-    sprite_graphics[k] = frame_counter >> 3 & 1;
-    if (!sprite_delay_main[k]) {
-      int j = sprite_A[k];
-      if (j == 2) {
-        sprite_ai_state[k]++;
-      } else {
-        sprite_A[k]++;
-        if (!j)
-          sprite_y_lo[k] -= 2;
-        sprite_delay_main[k] = kUncle_LeaveHouse_Delay[j];
-        sprite_D[k] = j = kUncle_LeaveHouse_Dir[j];
-        sprite_x_vel[k] = kUncle_LeaveHouse_Xvel[j];
-        sprite_y_vel[k] = kUncle_LeaveHouse_Yvel[j];
-      }
-    }
-    break;
-  case 4:  // Uncle_ApplyTelepathyFollower
-    follower_indicator = 5;
-    word_7E02CD = 0xdf3;
-    sram_progress_flags |= 0x10;
-    sprite_state[k] = 0;
-    flag_is_link_immobilized = 0;
-    break;
-  }
-}
-
-void Uncle_InPassage(int k) {  // 85df19
-  switch (sprite_ai_state[k]) {
-  case 0:  // RemoveZeldaTelepathTagalong
-    if (Sprite_CheckDamageToLink_same_layer(k))
-      Link_CancelDash();
-    if (Sprite_ShowMessageOnContact(k, 0xe) & 0x100) {
-      follower_indicator = 0;
-      sprite_ai_state[k]++;
-    }
-    break;
-  case 1:  // GiveSwordAndShield
-    item_receipt_method = 0;
-    Link_ReceiveItem(0, 0);
-    sprite_ai_state[k]++;
-    sprite_graphics[k] = 1;
-    which_starting_point = 3;
-    sram_progress_flags |= 1;
-    sram_progress_indicator = 1;
-    break;
-  }
-}
-
-void Sprite_QuarrelBros(int k) {  // 85e013
-  QuarrelBros_Draw(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  Sprite_TrackBodyToHead(k);
-  sprite_head_dir[k] = Sprite_DirectionToFaceLink(k, NULL) ^ 3;
-  if (!(dungeon_room_index & 1)) {
-    Sprite_ShowSolicitedMessage(k, 0x131);
-  } else if (!(dung_door_opened & 0xff00)) {
-    Sprite_ShowSolicitedMessage(k, 0x12f);
-  } else {
-    Sprite_ShowSolicitedMessage(k, 0x130);
-  }
-  Sprite_BehaveAsBarrier(k);
-}
-
-void QuarrelBros_Draw(int k) {  // 85e17f
-  static const DrawMultipleData kQuarrelBros_Dmd[16] = {
-    {0, -12, 0x0004, 2},
-    {0,   0, 0x000a, 2},
-    {0, -11, 0x0004, 2},
-    {0,   1, 0x400a, 2},
-    {0, -12, 0x0004, 2},
-    {0,   0, 0x000a, 2},
-    {0, -11, 0x0004, 2},
-    {0,   1, 0x400a, 2},
-    {0, -12, 0x0008, 2},
-    {0,   0, 0x000a, 2},
-    {0, -11, 0x0008, 2},
-    {0,   1, 0x400a, 2},
-    {0, -12, 0x4008, 2},
-    {0,   0, 0x000a, 2},
-    {0, -11, 0x4008, 2},
-    {0,   1, 0x400a, 2},
-  };
-  PrepOamCoordsRet info;
-  Sprite_DrawMultiplePlayerDeferred(k, &kQuarrelBros_Dmd[sprite_graphics[k] * 2 + sprite_D[k] * 4], 2, &info);
-  SpriteDraw_Shadow(k, &info);
-
-}
-
-void Sprite_YoungSnitchLady(int k) {  // 85e2f2
-  Sprite_OldSnitchLady(k);
-}
-
-void YoungSnitchLady_Draw(int k) {  // 85e37f
-  static const DrawMultipleData kYoungSnitchLady_Dmd[16] = {
-    {0, -8, 0x0026, 2},
-    {0,  0, 0x00e8, 2},
-    {0, -7, 0x0026, 2},
-    {0,  1, 0x40e8, 2},
-    {0, -8, 0x0024, 2},
-    {0,  0, 0x00c2, 2},
-    {0, -7, 0x0024, 2},
-    {0,  1, 0x40c2, 2},
-    {0, -8, 0x0028, 2},
-    {0,  0, 0x00e4, 2},
-    {0, -7, 0x0028, 2},
-    {0,  1, 0x00e6, 2},
-    {0, -8, 0x4028, 2},
-    {0,  0, 0x40e4, 2},
-    {0, -7, 0x4028, 2},
-    {0,  1, 0x40e6, 2},
-  };
-  PrepOamCoordsRet info;
-  Sprite_DrawMultiplePlayerDeferred(k, &kYoungSnitchLady_Dmd[sprite_graphics[k] * 2 + sprite_D[k] * 4], 2, &info);
-  SpriteDraw_Shadow(k, &info);
-}
-
-void Sprite_InnKeeper(int k) {  // 85e3af
-  InnKeeper_Draw(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  Sprite_BehaveAsBarrier(k);
-  Sprite_ShowSolicitedMessage(k, link_item_flippers ? 0x183 : 0x182);
-}
-
-void InnKeeper_Draw(int k) {  // 85e3dc
-  static const DrawMultipleData kInnKeeper_Dmd[2] = {
-    {0, -8, 0x00c4, 2},
-    {0,  0, 0x00ca, 2},
-  };
-  PrepOamCoordsRet info;
-  Sprite_DrawMultiplePlayerDeferred(k, kInnKeeper_Dmd, 2, &info);
-  SpriteDraw_Shadow(k, &info);
-}
-
-void Sprite_Witch(int k) {  // 85e3fb
-  Witch_Draw(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  uint8 bak0 = sprite_flags4[k];
-  sprite_flags4[k] = 2;
-  if (Sprite_CheckDamageToLink_same_layer(k)) {
-    Sprite_NullifyHookshotDrag();
-    link_speed_setting = 0;
-    Link_CancelDash();
-  }
-  sprite_flags4[k] = bak0;
-  if (!frame_counter)
-    sprite_A[k] = (GetRandomNumber() & 1) + 2;
-  int shift = sprite_A[k] + 1;
-  sprite_graphics[k] = (frame_counter >> shift) & 7;
-  if (Sprite_CheckIfLinkIsBusy())
-    return;
-  switch (sprite_ai_state[k]) {
-  case 0:  // main
-    if (link_item_mushroom == 0) {
-      if (save_dung_info[0x109] & 0x80)
-        Sprite_ShowSolicitedMessage(k, 0x4b);
-      else
-        Sprite_ShowSolicitedMessage(k, 0x4a);
-    } else if (link_item_mushroom == 1) {
-      if (!(joypad1H_last & 0x40)) {
-        Sprite_ShowSolicitedMessage(k, 0x4c);
-      } else if (Sprite_CheckDamageToLink_same_layer(k) && hud_cur_item == kHudItem_Mushroom) {
-        Witch_AcceptShroom(k);
-      }
-    } else {
-      Sprite_ShowSolicitedMessage(k, 0x4a);
-    }
-    break;
-  case 1:  // grant cane of byrna
-    sprite_ai_state[k] = 0;
-    item_receipt_method = 0;
-    Link_ReceiveItem(0x18, 0);
-    break;
-  }
-}
-
-void Witch_AcceptShroom(int k) {  // 85e4cf
-  link_item_mushroom = 0;
-  save_dung_info[0x109] |= 0x80;
-  sound_effect_1 = 0;
-  Hud_RefreshIcon();
-  Sprite_ShowMessageUnconditional(0x4b);
-  SpriteSfx_QueueSfx1WithPan(k, 0xd);
-  flag_overworld_area_did_change = 0;
-}
-
-void Witch_Draw(int k) {  // 85e55d
-  static const OamEntSigned kWitch_DrawDataA[16] = {
-    {-3,  8, 0xae, 0x00},
-    {-3, 16, 0xbe, 0x00},
-    {-2,  8, 0xae, 0x00},
-    {-2, 16, 0xbe, 0x00},
-    {-1,  8, 0xaf, 0x00},
-    {-1, 16, 0xbf, 0x00},
-    { 0,  9, 0xaf, 0x00},
-    { 0, 17, 0xbf, 0x00},
-    { 1, 10, 0xaf, 0x00},
-    { 1, 18, 0xbf, 0x00},
-    { 0, 11, 0xaf, 0x00},
-    { 0, 18, 0xbf, 0x00},
-    {-1, 10, 0xae, 0x00},
-    {-1, 18, 0xbe, 0x00},
-    {-3,  9, 0xae, 0x00},
-    {-3, 17, 0xbe, 0x00},
-  };
-  static const OamEntSigned kWitch_DrawDataB[3] = {
-      {  0, -4, 0x80, 0x00},
-      {-11, 15, 0x86, 0x04},
-      { -3, 15, 0x86, 0x44},
-  };
-  static const OamEntSigned kWitch_DrawDataC[2] = {
-      {0, 4, 0x84, 0x00},
-      {0, 4, 0x82, 0x00},
-  };
-
-  PrepOamCoordsRet info;
-  if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
-    return;
-  Oam_AllocateDeferToPlayer(k);
-  OamEnt *oam = GetOamCurPtr();
-  int g = sprite_graphics[k] * 2;
-  uint8 x = BYTE(dungmap_var7);
-  uint8 y = HIBYTE(dungmap_var7);
-
-  SetOamPlain(oam + 0, x + kWitch_DrawDataA[g + 0].x, y + kWitch_DrawDataA[g + 0].y, info.r4 | kWitch_DrawDataA[g + 0].charnum, info.flags, 0);
-  SetOamPlain(oam + 1, x + kWitch_DrawDataA[g + 1].x, y + kWitch_DrawDataA[g + 1].y, info.r4 | kWitch_DrawDataA[g + 1].charnum, info.flags, 0);
-
-  for (int i = 0; i < 3; i++) {
-    SetOamPlain(&oam[i + 2], x + kWitch_DrawDataB[i].x, y + kWitch_DrawDataB[i].y,
-                info.r4 ^ kWitch_DrawDataB[i].charnum,
-                info.flags ^ kWitch_DrawDataB[i].flags, 2);
-  }
-  int i = (uint16)(g - 6) < 6;
-  SetOamPlain(&oam[5], x + kWitch_DrawDataC[i].x, y + kWitch_DrawDataC[i].y,
-              info.r4 | kWitch_DrawDataC[i].charnum,
-              info.flags, 2);
-  Sprite_CorrectOamEntries(k, 5, 0xff);
-}
-
-void SpritePrep_Snitches(int k) {  // 85e67d
-  sprite_D[k] = 2;
-  sprite_head_dir[k] = 2;
-  sprite_ignore_projectile[k]++;
-  sprite_A[k] = sprite_x_lo[k];
-  sprite_B[k] = sprite_x_hi[k];
-  sprite_x_vel[k] = -9;
-}
-
-void Sprite_OldSnitchLady(int k) {  // 85e6aa
-  static const int8 kOldSnitchLady_Xd[2] = {-32, 32};
-  static const int8 kOldSnitchLady_Xvel[4] = {0, 0, -9, 9};
-  static const int8 kOldSnitchLady_Yvel[4] = {-9, 9, 0, 0};
-
-  int j;
-
-  if (sprite_type[k] == 0x34) {
-    if (sprite_ai_state[k] < 2)
-      YoungSnitchLady_Draw(k);
-  } else {
-    if (sprite_subtype[k]) {
-      Sprite_ChickenLady(k);
-      return;
-    }
-    if (sprite_ai_state[k] < 3)
-      Lady_Draw(k);
-  }
-
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  if (sprite_ai_state[k] < 3) {
-    if (player_is_indoors) {
-      Sprite_TrackBodyToHead(k);
-      sprite_head_dir[k] = Sprite_DirectionToFaceLink(k, NULL) ^ 3;
-      Sprite_ShowSolicitedMessage(k, 0xad);
-      return;
-    }
-    if (!sprite_ai_state[k] && Sprite_CheckDamageToLink_same_layer(k)) {
-      sprite_D[k] = Sprite_DirectionToFaceLink(k, NULL) ^ 3;
-      sprite_delay_main[k] = 1;
-    } else {
-      if (Sprite_TrackBodyToHead(k))
-        Sprite_MoveXY(k);
-      else
-        sprite_delay_main[k] = 1;
-    }
-  }
-
-  switch (sprite_ai_state[k]) {
-  case 0: {
-    if (sprite_delay_main[k] == 0) {
-      uint16 t = (sprite_A[k] | sprite_B[k] << 8) + kOldSnitchLady_Xd[sprite_C[k]];
-      if (t == Sprite_GetX(k)) {
-        sprite_head_dir[k] = (j = sprite_D[k] ^ 1);
-        sprite_x_vel[k] = kOldSnitchLady_Xvel[j];
-        sprite_y_vel[k] = kOldSnitchLady_Yvel[j];
-        sprite_C[k] ^= 1;
-      }
-    }
-    sprite_graphics[k] = (k ^ frame_counter) >> 4 & 1;
-    uint8 bak0 = sprite_flags4[k];
-    sprite_flags4[k] = 3;
-    j = Sprite_ShowMessageOnContact(k, 0x2f);
-    sprite_flags4[k] = bak0;
-    if (j & 0x100) {
-      sprite_D[k] = j;
-      Snitch_SpawnGuard(k);
-      sprite_ai_state[k] = 1;
-    }
-    break;
-  }
-  case 1: {
-    uint16 ovx = overlord_x_lo[byte_7E0FDE] | overlord_x_hi[byte_7E0FDE] << 8;
-    uint16 ovy = overlord_y_lo[byte_7E0FDE] | overlord_y_hi[byte_7E0FDE] << 8;
-    if (ovy >= Sprite_GetY(k)) {
-      sprite_ai_state[k] = 2;
-      sprite_x_vel[k] = 0;
-      sprite_y_vel[k] = 0;
-      sprite_flags4[k] = 2;
-      uint16 pos = ((ovy - overworld_offset_base_y) & overworld_offset_mask_y) * 8;
-      pos += (((ovx >> 3) - overworld_offset_base_x) & overworld_offset_mask_x);
-      Overworld_DrawWoodenDoor(pos, false);
-      sprite_delay_main[k] = 16;
-    } else {
-      flag_is_link_immobilized = 1;
-      ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLocation(k, ovx, ovy, 64);
-      sprite_x_vel[k] = pt.x;
-      sprite_y_vel[k] = pt.y;
-      sprite_D[k] = 0;
-      sprite_head_dir[k] = 0;
-      sprite_graphics[k] = (k ^ frame_counter) >> 3 & 1;
-    }
-    break;
-  }
-  case 2:
-    if (sprite_delay_main[k] == 0) {
-      uint16 ovx = overlord_x_lo[byte_7E0FDE] | overlord_x_hi[byte_7E0FDE] << 8;
-      uint16 ovy = overlord_y_lo[byte_7E0FDE] | overlord_y_hi[byte_7E0FDE] << 8;
-      Sprite_SetX(k, ovx);
-      Sprite_SetY(k, ovy);
-      uint16 pos = ((ovy - overworld_offset_base_y) & overworld_offset_mask_y) * 8;
-      pos += (((ovx >> 3) - overworld_offset_base_x) & overworld_offset_mask_x);
-      Overworld_DrawWoodenDoor(pos, true);
-      sprite_ai_state[k] = 3;
-    }
-    Sprite_MoveXY(k);
-    break;
-  case 3:
-    sprite_state[k] = 0;
-    flag_is_link_immobilized = 0;
-    break;
-  }
-}
-
-void SpritePrep_RunningMan(int k) {  // 85e896
-  sprite_head_dir[k] = 2;
-  sprite_D[k] = 2;
-  sprite_ignore_projectile[k]++;
-}
-
-void Sprite_RunningMan(int k) {  // 85e8b2
-  static const int8 kRunningMan_Xvel2[2] = {-24, 24};
-  static const int8 kRunningMan_Xvel[4] = {0, 0, -54, 54};
-  static const int8 kRunningMan_Yvel[4] = {-54, 54, 0, 0};
-  static const int8 kRunningMan_Dir[4] = {3, 1, 3, -1};
-  static const uint8 kRunningMan_A[4] = {120, 24, 128, 3};
-  int j;
-  RunningMan_Draw(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  Sprite_TrackBodyToHead(k);
-  Sprite_BehaveAsBarrier(k);
-  sprite_subtype[k] = 255;
-  Sprite_CheckTileCollision(k);
-  uint8 bak0 = sprite_flags4[k];
-  sprite_flags4[k] = 7;
-  if (Sprite_CheckDamageToLink_same_layer(k)) {
-    sprite_C[k] = sprite_ai_state[k];
-    sprite_ai_state[k] = 3;
-  }
-  sprite_flags4[k] = bak0;
-  switch (sprite_ai_state[k]) {
-  case 0:  // chill
-    Sprite_TrackBodyToHead(k);
-    j = Sprite_DirectionToFaceLink(k, NULL);
-    sprite_head_dir[k] = j ^ 3;
-    if (Sprite_CheckDamageToLink_same_layer(k)) {
-      Link_CancelDash();
-      sprite_D[k] = j ^ 3;
-      sprite_head_dir[k] = j | 2;
-      sprite_ai_state[k] = (j & 1) + 1;
-      sprite_x_vel[k] = kRunningMan_Xvel2[j & 1];
-      sprite_delay_main[k] = 32;
-    } else {
-      sprite_x_vel[k] = 0;
-      sprite_y_vel[k] = 0;
-    }
-    break;
-  case 1:  // run left
-  case 2:  // run right
-    if (sprite_delay_main[k] != 0) {
-      sprite_graphics[k] = frame_counter >> 3 & 1;
-      Sprite_MoveXY(k);
-    } else {
-      RunningBoy_SpawnDustGarnish(k);
-      sprite_graphics[k] = frame_counter >> 2 & 1;
-      j = sprite_head_dir[k];
-      sprite_x_vel[k] = kRunningMan_Xvel[j];
-      sprite_y_vel[k] = kRunningMan_Yvel[j];
-      Sprite_MoveXY(k);
-      if (sprite_A[k]) {
-        sprite_A[k]--;
-        break;
-      }
-      if (sprite_ai_state[k] == 1) {  // left
-        sprite_A[k] = 255;
-        sprite_head_dir[k] = 2;
-      } else {
-        j = sprite_B[k]++;
-        sprite_A[k] = kRunningMan_A[j];
-        if (kRunningMan_Dir[j] < 0) {
-          sprite_ai_state[k] = 0;
-          sprite_subtype2[k] = 0;
-        } else {
-          sprite_head_dir[k] = kRunningMan_Dir[j];
-        }
-      }
-    }
-    break;
-  case 3:  // caught
-    Sprite_ShowMessageUnconditional(0xa6);
-    if (link_player_handler_state >= kPlayerState_RecoilWall)  // wtf
-      sprite_D[k] = link_player_handler_state;
-    sprite_ai_state[k] = sprite_C[k];
-    break;
-
-  }
-}
-
-void RunningMan_Draw(int k) {  // 85ea4d
-  static const DrawMultipleData kRunningMan_Dmd[16] = {
-    {0, -8, 0x002c, 2},
-    {0,  0, 0x08ee, 2},
-    {0, -7, 0x002c, 2},
-    {0,  1, 0x48ee, 2},
-    {0, -8, 0x002a, 2},
-    {0,  0, 0x08ca, 2},
-    {0, -7, 0x002a, 2},
-    {0,  1, 0x48ca, 2},
-    {0, -8, 0x002e, 2},
-    {0,  0, 0x08cc, 2},
-    {0, -7, 0x002e, 2},
-    {0,  1, 0x08ce, 2},
-    {0, -8, 0x402e, 2},
-    {0,  0, 0x48cc, 2},
-    {0, -7, 0x402e, 2},
-    {0,  1, 0x48ce, 2},
-  };
-  PrepOamCoordsRet info;
-  Sprite_DrawMultiplePlayerDeferred(k, &kRunningMan_Dmd[(sprite_D[k] * 4 + sprite_graphics[k] * 2) & 0xf], 2, &info);
-  SpriteDraw_Shadow(k, &info);
-}
-
-void Sprite_BottleVendor(int k) {  // 85ea79
-  int j;
-
-  sprite_A[k] = BottleVendor_Draw(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  BottleMerchant_DetectFish(k);
-  Sprite_BehaveAsBarrier(k);
-  if (Sprite_CheckIfLinkIsBusy())
-    return;
-  if (GetRandomNumber() == 0) {
-    sprite_delay_main[k] = 20;
-    sprite_graphics[k] = 1;
-  } else if (!sprite_delay_main[k]) {
-    sprite_graphics[k] = 0;
-  }
-  switch (sprite_ai_state[k]) {
-  case 0:  // base
-    if (!sprite_A[k] && sprite_E[k])
-      sprite_ai_state[k] = 3;
-    else if (sram_progress_indicator_3 & 2)
-      Sprite_ShowSolicitedMessage(k, 0xd4);
-    else if (Sprite_ShowSolicitedMessage(k, 0xd1) & 0x100)
-      sprite_ai_state[k] = 1;
-    break;
-  case 1:  // selling
-    if (choice_in_multiselect_box == 0 && link_rupees_goal >= 100) {
-      Sprite_ShowMessageUnconditional(0xd2);
-      sprite_ai_state[k] = 2;
-    } else {
-      Sprite_ShowMessageUnconditional(0xd3);
-      sprite_ai_state[k] = 0;
-    }
-    break;
-  case 2:  // giving
-    item_receipt_method = 0;
-    Link_ReceiveItem(0x16, 0);
-    sram_progress_indicator_3 |= 2;
-    link_rupees_goal -= 100;
-    sprite_ai_state[k] = 0;
-    break;
-  case 3:  // buying
-    if (!sign8(sprite_E[k]))
-      Sprite_ShowMessageUnconditional(0xd5);
-    else
-      Sprite_ShowMessageUnconditional(0xd6);
-    sprite_ai_state[k] = 4;
-    break;
-  case 4:  // reward
-    j = sprite_E[k];
-    if (!sign8(j)) {
-      sprite_state[j - 1] = 0;
-      BottleMerchant_BuyBee(k);
-    } else {
-      sprite_state[j & 0xf] = 0;
-      BottleMerchant_BuyFish(k);
-    }
-    sprite_E[k] = 0;
-    sprite_ai_state[k] = 0;
-    break;
-  }
-
-}
-
-uint8 BottleVendor_Draw(int k) {  // 85eba7
-  PrepOamCoordsRet info;
-  static const DrawMultipleData kBottleVendor_Dmd[4] = {
-    {0, -7, 0x00ac, 2},
-    {0,  0, 0x0088, 2},
-    {0, -6, 0x00ac, 2},
-    {0,  0, 0x00a2, 2},
-  };
-  Sprite_DrawMultiplePlayerDeferred(k, &kBottleVendor_Dmd[sprite_graphics[k] * 2], 2, &info);
-  SpriteDraw_Shadow(k, &info);
-  return (info.x | info.y) >> 8;
-}
-
-void Priest_SpawnRescuedPrincess() {  // 85ec4c
-  SpriteSpawnInfo info;
-  int k = Sprite_SpawnDynamically(0, 0x76, &info);
-  if (k < 0)
-    return;
-  sprite_D[k] = sprite_head_dir[k] = tagalong_layerbits[tagalong_var2] & 3;
-  Sprite_SetX(k, link_x_coord);
-  Sprite_SetY(k, link_y_coord);
-  sprite_subtype2[k] = 1;
-  follower_indicator = 0;
-  sprite_ignore_projectile[k]++;
-  sprite_flags4[k] = 3;
-}
-
-void Sprite_76_Zelda(int k) {  // 85ec9e
-  CrystalMaiden_Draw(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  Sprite_BehaveAsBarrier(k);
-  if (Sprite_TrackBodyToHead(k))
-    Sprite_MoveXY(k);
-  switch (sprite_subtype2[k]) {
-  case 0: Zelda_InCell(k); break;
-  case 1: Zelda_EnteringSanctuary(k); break;
-  case 2: Zelda_AtSanctuary(k); break;
-  }
-}
-
-void Zelda_InCell(int k) {  // 85ecbf
-  int j;
-  sprite_head_dir[k] = Sprite_DirectionToFaceLink(k, NULL) ^ 3;
-  switch (sprite_ai_state[k]) {
-  case 0:  // AwaitingRescue
-    if (!Sprite_CheckDamageToLink_same_layer(k))
-      return;
-    sprite_ai_state[k]++;
-    flag_is_link_immobilized++;
-    j = sprite_head_dir[k];
-    sprite_x_vel[k] = kZelda_Xvel[j];
-    sprite_y_vel[k] = kZelda_Yvel[j];
-    sprite_delay_main[k] = 16;
-    break;
-  case 1:  // ApproachingPlayer
-    if (!sprite_delay_main[k]) {
-      sprite_ai_state[k]++;
-      Sprite_ShowMessageUnconditional(0x1c);
-      sprite_x_vel[k] = 0;
-      sprite_y_vel[k] = 0;
-      music_control = 25;
-    }
-    sprite_graphics[k] = frame_counter >> 3 & 1;
-    break;
-  case 2:  // TheWizardIsBadMkay
-    sprite_ai_state[k]++;
-    Sprite_ShowMessageUnconditional(0x25);
-    break;
-  case 3:  // WaitUntilPlayerPaysAttention
-    if (choice_in_multiselect_box) {
-      sprite_ai_state[k] = 2;
-    } else {
-      sprite_ai_state[k]++;
-      Sprite_ShowMessageUnconditional(0x24);
-    }
-    break;
-  case 4:  // TransitionToTagalong
-    flag_is_link_immobilized = 0;
-    which_starting_point = 2;
-    SavePalaceDeaths();
-    follower_indicator = 1;
-    Dungeon_FlagRoomData_Quadrants();
-    Sprite_BecomeFollower(k);
-    sprite_state[k] = 0;
-    music_control = 16;
-    break;
-  }
-}
-
-void Zelda_EnteringSanctuary(int k) {  // 85ed69
-  static const uint8 kZelda_Delay0[4] = {38, 26, 44, 1};
-  static const uint8 kZelda_Dir0[4] = {1, 3, 1, 2};
-  int j;
-  switch (sprite_ai_state[k]) {
-  case 0:  // walk to priest
-    if (sprite_delay_main[k] == 0) {
-      j = sprite_A[k];
-      if (j >= 4) {
-        sprite_ai_state[k]++;
-        sprite_head_dir[k] = sprite_D[k] = 0;
-        sprite_x_vel[k] = 0;
-        sprite_y_vel[k] = 0;
-        return;
-      }
-      sprite_delay_main[k] = kZelda_Delay0[j];
-      sprite_D[k] = sprite_head_dir[k] = j = kZelda_Dir0[j];
-      sprite_A[k]++;
-      sprite_x_vel[k] = kZelda_Xvel[j];
-      sprite_y_vel[k] = kZelda_Yvel[j];
-    }
-    sprite_graphics[k] = (frame_counter >> 3) & 1;
-    break;
-  case 1:  // respond to priest
-    Sprite_ShowMessageUnconditional(0x1d);
-    sprite_ai_state[k]++;
-    byte_7FFE01 = 2;
-    which_starting_point = 1;
-    SavePalaceDeaths();
-    sram_progress_indicator = 2;
-    Sprite_LoadGraphicsProperties_light_world_only();
-    break;
-  case 2:  // be careful
-    sprite_head_dir[k] = Sprite_DirectionToFaceLink(k, NULL) ^ 3;
-    j = Sprite_ShowSolicitedMessage(k, 0x1e);
-    if (j & 0x100)
-      sprite_D[k] = sprite_head_dir[k] = (uint8)j;
-    break;
-  }
-}
-
-void Zelda_AtSanctuary(int k) {  // 85ee0c
-  sprite_head_dir[k] = Sprite_DirectionToFaceLink(k, NULL) ^ 3;
-  int m = (link_which_pendants & 7) == 7 ? 0x27 :
-          savegame_map_icons_indicator >= 3 ? 0x26 : 0x1e;
-  int j = Sprite_ShowSolicitedMessage(k, m);
-  if (j & 0x100) {
-    sprite_D[k] = sprite_head_dir[k] = (uint8)j;
-    link_hearts_filler = 0xa0;
-  }
-}
-
-void SpritePrep_Mushroom(int k) {  // 85ee53
-  if (link_item_mushroom >= 2) {
-    sprite_state[k] = 0;
-  } else {
-    sprite_graphics[k] = 0;
-    sprite_oam_flags[k] |= 8;
-    sprite_ignore_projectile[k]++;
-  }
-}
-
-void Sprite_E7_Mushroom(int k) {  // 85ee78
-  SpriteDraw_SingleLarge(k);
-  if (Sprite_CheckIfLinkIsBusy())
-    return;
-
-  // If we're in the middle of a mirror warp, don't get the mushroom yet
-  if (enhanced_features0 & kFeatures0_MiscBugFixes && submodule_index != 0)
-    return;
-
-  if (Sprite_CheckDamageToLink_same_layer(k)) {
-    sprite_state[k] = 0;
-    item_receipt_method = 0;
-    Link_ReceiveItem(0x29, 0);
-  } else if ((frame_counter & 0x1f) == 0) {
-    sprite_oam_flags[k] ^= 0x40;
-  }
-}
-
-void Sprite_E8_FakeSword(int k) {  // 85eeaf
-  FakeSword_Draw(k);
-  if (Sprite_ReturnIfPaused(k))
-    return;
-  if (sprite_unk3[k] == 3) {
-    if (!sprite_C[k]) {
-      sprite_C[k] = 1;
-      Sprite_ShowMessageUnconditional(0x6f);
-    }
-  } else {
-    Sprite_MoveXY(k);
-    ThrownSprite_TileAndSpriteInteraction(k);
-  }
-}
-
-void FakeSword_Draw(int k) {  // 85eee6
-  Sprite_DrawMultiplePlayerDeferred(k, kFakeSword_Dmd, 2, NULL);
-}
-
-void SpritePrep_HeartContainer(int k) {  // 85ef01
-  HeartUpgrade_CheckIfAlreadyObtained(k);
-}
-
-void Sprite_HeartContainer(int k) {  // 85ef47
-  if (BYTE(cur_palace_index_x2) == 26) {
-    sprite_state[k] = 0;
-    return;
-  }
-  sprite_ignore_projectile[k] = sprite_G[k];
-  if (!sprite_G[k]) {
-    DecodeAnimatedSpriteTile_variable(3);
-    Sprite_Get16BitCoords(k);
-    sprite_G[k] = 1;
-  }
-
-  if (BYTE(dungeon_room_index2) == 6 && !sprite_z[k])
-    SpriteDraw_WaterRipple_WithOamAdjust(k);
-  SpriteDraw_SingleLarge(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  sprite_z_vel[k] -= 2;
-  Sprite_MoveZ(k);
-  if (sign8(sprite_z[k])) {
-    sprite_z[k] = 0;
-    sprite_z_vel[k] = (uint8)-sprite_z_vel[k] >> 2;
-    if (BYTE(dungeon_room_index2) == 6 && !sprite_subtype[k]) {
-      sprite_flags2[k] += 2;
-      sprite_subtype[k] = 1;
-      Sprite_SpawnWaterSplash(k);
-    }
-  }
-  if (Sprite_CheckIfLinkIsBusy())
-    return;
-  if (!Sprite_CheckDamageToLink_same_layer(k))
-    return;
-  sprite_state[k] = 0;
-  if (sprite_A[k]) {
-    item_receipt_method = 2;
-    Link_ReceiveItem(0x3e, 0);
-    dung_savegame_state_bits |= 0x8000;
-    return;
-  }
-  Link_CancelDash();
-  item_receipt_method = 0;
-  Link_ReceiveItem(0x26, 0);
-  if (!player_is_indoors)
-    save_ow_event_info[BYTE(overworld_screen_index)] |= 0x40;
-  else
-    dung_savegame_state_bits |= (sprite_x_hi[k] & 1) ? 0x2000 : 0x4000;
-}
-
-void Sprite_HeartPiece(int k) {  // 85f020
-  static const uint16 kHeartPieceMsg[4] = {0x158, 0x155, 0x156, 0x157};
-  if (!sprite_ai_state[k]) {
-    sprite_ai_state[k]++;
-    HeartUpgrade_CheckIfAlreadyObtained(k);
-    if (!sprite_state[k])
-      return;
-  }
-  SpriteDraw_SingleLarge(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  if (Sprite_CheckIfLinkIsBusy())
-    return;
-
-  if (Sprite_CheckTileCollision(k) & 3)
-    sprite_x_vel[k] = -sprite_x_vel[k];
-
-  sprite_z_vel[k]--;
-  Sprite_MoveZ(k);
-  Sprite_MoveXY(k);
-  if (sign8(sprite_z[k])) {
-    sprite_z[k] = 0;
-    sprite_z_vel[k] = ((sprite_z_vel[k] ^ 255) & 248) >> 1;
-    sprite_x_vel[k] = (int8)sprite_x_vel[k] >> 1;
-  }
-
-  if (sprite_delay_aux4[k] || !Sprite_CheckDamageToLink_same_layer(k))
-    return;
-
-  link_heart_pieces = link_heart_pieces + 1 & 3;
-  if (link_heart_pieces == 0) {
-    Link_CancelDash();
-    item_receipt_method = 0;
-    Link_ReceiveItem(0x26, 0);
-  } else {
-    SpriteSfx_QueueSfx3WithPan(k, 0x2d);
-    Sprite_ShowMessageUnconditional(kHeartPieceMsg[link_heart_pieces]);
-  }
-  sprite_state[k] = 0;
-  HeartUpgrade_SetObtainedFlag(k);
-}
-
-void HeartUpgrade_SetObtainedFlag(int k) {  // 85f0c3
-  if (!player_is_indoors) {
-    save_ow_event_info[BYTE(overworld_screen_index)] |= 0x40;
-  } else {
-    int j = sprite_x_hi[k] & 1;
-    dung_savegame_state_bits |= (j ? 0x2000 : 0x4000);
-  }
-}
-
-void Sprite_Aginah(int k) {  // 85f0ea
-  if (!(sram_progress_flags & 0x20))
-    goto default_msg;
-  if (link_sword_type >= 2) {
-    Sprite_ShowSolicitedMessage(k, 0x128);
-  } else if ((link_which_pendants & 7) == 7) {
-    Sprite_ShowSolicitedMessage(k, 0x126);
-  } else if ((link_which_pendants & 2) != 0) {
-    Sprite_ShowSolicitedMessage(k, 0x129);
-  } else if (link_item_book_of_mudora) {
-    Sprite_ShowSolicitedMessage(k, 0x127);
-  } else {
-default_msg:
-    sram_progress_flags |= 0x20;
-    Sprite_ShowSolicitedMessage(k, 0x125);
-  }
-  sprite_graphics[k] = frame_counter >> 5 & 1;
-}
-
-void Sprite_Sahasrahla(int k) {  // 85f14d
-  switch (sprite_ai_state[k]) {
-  case 0:  // dialogue
-    Sasha_Idle(k);
-    break;
-  case 1:  // mark map
-    Sprite_ShowMessageUnconditional(0x33);
-    sprite_ai_state[k] = 0;
-    savegame_map_icons_indicator = 3;
-    break;
-  case 2:  // grant boots
-    item_receipt_method = 0;
-    Link_ReceiveItem(0x4b, 0);
-    sprite_ai_state[k] = 3;
-    savegame_map_icons_indicator = 3;
-    break;
-  case 3:  // shamelessly promote ice rod
-    Sprite_ShowMessageUnconditional(0x37);
-    sprite_ai_state[k] = 0;
-    break;
-  }
-}
-
-void Sasha_Idle(int k) {  // 85f160
-  if (!(link_which_pendants & 4)) {
-    if (Sprite_ShowSolicitedMessage(k, 0x32) & 0x100)
-      sprite_ai_state[k] = 1;
-  } else if (!link_item_boots) {
-    int m = (savegame_map_icons_indicator >= 3) ? 0x38 : 0x39;
-    if (Sprite_ShowSolicitedMessage(k, m) & 0x100)
-      sprite_ai_state[k] = 2;
-  } else if (!link_item_ice_rod) {
-    Sprite_ShowSolicitedMessage(k, 0x37);
-  } else if ((link_which_pendants & 7) != 7) {
-    Sprite_ShowSolicitedMessage(k, 0x34);
-  } else if (link_sword_type < 2) {
-    Sprite_ShowSolicitedMessage(k, 0x30);
-  } else {
-    Sprite_ShowSolicitedMessage(k, 0x31);
-  }
-  sprite_graphics[k] = frame_counter >> 5 & 1;
-}
-
-void Elder_Draw(int k) {  // 85f23a
-  static const DrawMultipleData kElder_Dmd[4] = {
-    {0, -9, 0x00a0, 2},
-    {0,  0, 0x00a2, 2},
-    {0, -8, 0x00a0, 2},
-    {0,  0, 0x40a4, 2},
-  };
-  PrepOamCoordsRet info;
-  Sprite_DrawMultiplePlayerDeferred(k, &kElder_Dmd[sprite_graphics[k] * 2], 2, &info);
-  SpriteDraw_Shadow(k, &info);
-}
-
-void Sprite_DustCloud(int k) {  // 85f2b2
-  static const uint8 kDustCloud_Gfx[9] = {0, 1, 2, 3, 4, 5, 1, 0, 0xff};
-  DustCloud_Draw(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  if (sprite_delay_main[k])
-    return;
-  sprite_delay_main[k] = 5;
-  if (!sign8(kDustCloud_Gfx[sprite_A[k]])) {
-    sprite_graphics[k] = kDustCloud_Gfx[sprite_A[k]];
-    sprite_A[k]++;
-  } else {
-    sprite_state[k] = 0;
-  }
-}
-
-int Sprite_SpawnDustCloud(int k) {  // 85f2d6
-  SpriteSpawnInfo info;
-  int j = Sprite_SpawnDynamically(k, 0xF2, &info);
-  if (j >= 0) {
-    info.r2_y += (GetRandomNumber() & 15);
-    info.r0_x += (GetRandomNumber() & 15) - 8;
-    Sprite_SetSpawnedCoordinates(j, &info);
-    sprite_subtype2[j] = 1;
-  }
-  return j;
-}
-
-void MedallionTablet_Main(int k) {  // 85f30c
-  MedallionTablet_Draw(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  link_position_mode &= ~0x20;
-  sprite_A[k] = 0;
-  if (Sprite_CheckDamageToLink_same_layer(k)) {
-    Sprite_NullifyHookshotDrag();
-    link_speed_setting = 0;
-    Sprite_RepelDash();
-    sprite_A[k]++;
-  }
-  if (Sprite_CheckIfLinkIsBusy())
-    return;
-  switch (sprite_ai_state[k]) {
-  case 0:  // wait for mudora
-    if (BYTE(overworld_screen_index) != 3)
-      BombosTablet(k);
-    else
-      EtherTablet(k);
-    break;
-  case 1:  // delay
-    if (!sprite_delay_main[k]) {
-      sprite_ai_state[k]++;
-      sprite_delay_main[k] = 128;
-    }
-    break;
-  case 2:  // crumbling
-    if (!sprite_delay_main[k]) {
-      sprite_ai_state[k]++;
-      sprite_delay_main[k] = 240;
-    } else {
-      if (sprite_delay_main[k] == 0x20 || sprite_delay_main[k] == 0x40 || sprite_delay_main[k] == 0x60)
-        sprite_graphics[k]++;
-      if (!(frame_counter & 7))
-        Sprite_SpawnDustCloud(k);
-    }
-    break;
-  case 3:  // final animstate
-    sprite_graphics[k] = 4;
-    break;
-  }
-}
-
-void BombosTablet(int k) {  // 85f355
-  static const uint16 kMedallionTabletMsg[2] = {0x10d, 0x10f};
-  if (link_direction_facing || Sprite_DirectionToFaceLink(k, NULL) != 2)
-    return;
-  if ((uint16)(cur_sprite_y + 16) < link_y_coord)
-    return;
-  if (filtered_joypad_H & 0x80 && link_sword_type == 2)
-    return;
-
-  int j = 1;
-  if (!(hud_cur_item == kHudItem_BookMudora && (filtered_joypad_H & 0x40)) && (j = 0, !(filtered_joypad_L & 0x80)))
-    return;
-  if (j) {
-    player_handler_timer = 0;
-    link_position_mode = 32;
-    sound_effect_1 = 0;
-    if (!sign8(link_sword_type) && link_sword_type >= 2) {
-      sprite_ai_state[k]++;
-      BombosTablet_StartCutscene();
-      sprite_delay_main[k] = 64;
-    }
-  }
-  Sprite_ShowMessageUnconditional(kMedallionTabletMsg[j]);
-}
-
-void EtherTablet(int k) {  // 85f3c4
-  static const uint16 kMedallionTabletEtherMsg[2] = {0x10d, 0x10e};
-  if (link_direction_facing || Sprite_DirectionToFaceLink(k, NULL) != 2)
-    return;
-  if ((uint8)(sprite_y_lo[k] + 16) < BYTE(link_y_coord))
-    return;
-  if (filtered_joypad_H & 0x80 && link_sword_type == 2)
-    return;
-
-  int j = 1;
-  if (!(hud_cur_item == kHudItem_BookMudora && (filtered_joypad_H & 0x40)) && (j = 0, !(filtered_joypad_L & 0x80)))
-    return;
-
-  if (j) {
-    player_handler_timer = 0;
-    link_position_mode = 32;
-    sound_effect_1 = 0;
-    if (!sign8(link_sword_type) && link_sword_type >= 2) {
-      sprite_ai_state[k]++;
-      EtherTablet_StartCutscene();
-      sprite_delay_main[k] = 64;
-    }
-  }
-  Sprite_ShowMessageUnconditional(kMedallionTabletEtherMsg[j]);
-}
-
-void ElderWife_Draw(int k) {  // 85f505
-  static const DrawMultipleData kElderWife_Dmd[4] = {
-    {0, -5, 0x008e, 2},
-    {0,  5, 0x0028, 2},
-    {0, -4, 0x008e, 2},
-    {0,  5, 0x4028, 2},
-  };
-  Sprite_DrawMultiplePlayerDeferred(k, &kElderWife_Dmd[sprite_graphics[k] * 2], 2, NULL);
-}
-
-void SpritePrep_PotionShop(int k) {  // 85f529
-  MagicShopAssistant_SpawnPowder(k);
-  MagicShopAssistant_SpawnGreenCauldron(k);
-  MagicShopAssistant_SpawnBlueCauldron(k);
-  MagicShopAssistant_SpawnRedCauldron(k);
-  sprite_ignore_projectile[k]++;
-}
-
-void MagicShopAssistant_SpawnPowder(int k) {  // 85f539
-  if (!flag_overworld_area_did_change || link_item_mushroom == 2)
-    return;
-  if (save_dung_info[0x109] & 0x80) {
-    SpriteSpawnInfo info;
-    int j = Sprite_SpawnDynamically(k, 0xe9, &info);
-    sprite_subtype2[j] = 1;
-    Sprite_SetX(j, info.r0_x - 16);
-    Sprite_SetY(j, info.r2_y);
-    sprite_flags4[j] = 3;
-    sprite_defl_bits[j] |= 0x20;
-  }
-}
-
-void MagicShopAssistant_SpawnGreenCauldron(int k) {  // 85f58e
-  SpriteSpawnInfo info;
-  int j = Sprite_SpawnDynamically(k, 0xe9, &info);
-  sprite_subtype2[j] = 2;
-  Sprite_SetX(j, info.r0_x - 40);
-  Sprite_SetY(j, info.r2_y - 72);
-  sprite_flags4[j] = 3;
-  sprite_defl_bits[j] |= 0x20;
-}
-
-void MagicShopAssistant_SpawnBlueCauldron(int k) {  // 85f5bf
-  SpriteSpawnInfo info;
-  int j = Sprite_SpawnDynamically(k, 0xe9, &info);
-  sprite_subtype2[j] = 3;
-  Sprite_SetX(j, info.r0_x + 8);
-  Sprite_SetY(j, info.r2_y - 72);
-  sprite_flags4[j] = 3;
-  sprite_defl_bits[j] |= 0x20;
-}
-
-void MagicShopAssistant_SpawnRedCauldron(int k) {  // 85f5f0
-  SpriteSpawnInfo info;
-  int j = Sprite_SpawnDynamically(k, 0xe9, &info);
-  sprite_subtype2[j] = 4;
-  Sprite_SetX(j, info.r0_x - 88);
-  Sprite_SetY(j, info.r2_y - 72);
-  sprite_flags4[j] = 3;
-  sprite_defl_bits[j] |= 0x20;
-}
-
-void Sprite_E9_PotionShop(int k) {  // 85f633
-  switch(sprite_subtype2[k]) {
-  case 0: Sprite_MagicShopAssistant_Main(k); return;
-  case 1: Sprite_BagOfPowder(k); return;
-  case 2: Sprite_GreenCauldron(k); return;
-  case 3: Sprite_BlueCauldron(k); return;
-  case 4: Sprite_RedCauldron(k); return;
-  }
-}
-
-void Sprite_BagOfPowder(int k) {  // 85f644
-  MagicPowderItem_Draw(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  Sprite_BehaveAsBarrier(k);
-  if (!Sprite_CheckDamageToLink_same_layer(k) || !(filtered_joypad_L & 0x80))
-    return;
-  Link_CancelDash();
-  item_receipt_method = 0;
-  Link_ReceiveItem(0xd, 0);
-  sprite_state[k] = 0;
-}
-
-void MagicPowderItem_Draw(int k) {  // 85f67b
-  static const DrawMultipleData kMagicPowder_Dmd[2] = {
-    {0, 0, 0x04e6, 2},
-    {0, 0, 0x04e6, 2},
-  };
-  Sprite_DrawMultiplePlayerDeferred(k, kMagicPowder_Dmd, 2, NULL);
-}
-
-void Sprite_GreenCauldron(int k) {  // 85f68e
-  GreenPotionItem_Draw(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  Sprite_BehaveAsBarrier(k);
-  if (sprite_delay_main[k])
-    return;
-  if (!PotionCauldron_CheckBottles()) {
-    if (Sprite_ShowMessageOnContact(k, 0x4f) & 0x100)
-      PotionCauldron_GoBeep(k);
-    return;
-  }
-  if (!Sprite_CheckDamageToLink_same_layer(k) || !(filtered_joypad_L & 0x80))
-    return;
-  if (link_rupees_goal < 60) {
-    Sprite_ShowMessageUnconditional(0x17c);
-    PotionCauldron_GoBeep(k);
-    return;
-  }
-  if (Sprite_Find_EmptyBottle() < 0) {
-    Sprite_ShowMessageUnconditional(0x50);
-    PotionCauldron_GoBeep(k);
-    return;
-  }
-  SpriteSfx_QueueSfx3WithPan(k, 0x1d);
-  sprite_delay_main[k] = 64;
-  link_rupees_goal -= 60;
-  item_receipt_method = 0;
-  Link_ReceiveItem(0x2f, 0);
-}
-
-void GreenPotionItem_Draw(int k) {  // 85f718
-  static const DrawMultipleData kGreenPotionItem_Dmd[3] = {
-    { 0,  0, 0x08c0, 2},
-    { 8, 18, 0x0a30, 0},
-    {-1, 18, 0x0a22, 0},
-  };
-  Sprite_DrawMultiplePlayerDeferred(k, kGreenPotionItem_Dmd, 3, NULL);
-}
-
-void Sprite_BlueCauldron(int k) {  // 85f72b
-  BluePotionItem_Draw(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  Sprite_BehaveAsBarrier(k);
-  if (sprite_delay_main[k])
-    return;
-  if (!PotionCauldron_CheckBottles()) {
-    if (Sprite_ShowMessageOnContact(k, 0x4f) & 0x100)
-      PotionCauldron_GoBeep(k);
-    return;
-  }
-  if (!Sprite_CheckDamageToLink_same_layer(k) || !(filtered_joypad_L & 0x80))
-    return;
-  if (link_rupees_goal < 160) {
-    Sprite_ShowMessageUnconditional(0x17c);
-    PotionCauldron_GoBeep(k);
-    return;
-  }
-  if (Sprite_Find_EmptyBottle() < 0) {
-    Sprite_ShowMessageUnconditional(0x50);
-    PotionCauldron_GoBeep(k);
-    return;
-  }
-  SpriteSfx_QueueSfx3WithPan(k, 0x1d);
-  sprite_delay_main[k] = 64;
-  link_rupees_goal -= 160;
-  item_receipt_method = 0;
-  Link_ReceiveItem(0x30, 0);
-}
-
-void BluePotionItem_Draw(int k) {  // 85f7bd
-  static const DrawMultipleData kBluePotionItem_Dmd[4] = {
-    { 0,  0, 0x04c0, 2},
-    {13, 18, 0x0a30, 0},
-    { 5, 18, 0x0a22, 0},
-    {-3, 18, 0x0a31, 0},
-  };
-  Sprite_DrawMultiplePlayerDeferred(k, kBluePotionItem_Dmd, 4, NULL);
-}
-
-void Sprite_RedCauldron(int k) {  // 85f7d0
-  RedPotionItem_Draw(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  Sprite_BehaveAsBarrier(k);
-  if (sprite_delay_main[k])
-    return;
-  if (!PotionCauldron_CheckBottles()) {
-    if (Sprite_ShowMessageOnContact(k, 0x4f) & 0x100)
-      PotionCauldron_GoBeep(k);
-    return;
-  }
-  if (!Sprite_CheckDamageToLink_same_layer(k) || !(filtered_joypad_L & 0x80))
-    return;
-  if (link_rupees_goal < 120) {
-    Sprite_ShowMessageUnconditional(0x17c);
-    PotionCauldron_GoBeep(k);
-    return;
-  }
-  if (Sprite_Find_EmptyBottle() < 0) {
-    Sprite_ShowMessageUnconditional(0x50);
-    PotionCauldron_GoBeep(k);
-    return;
-  }
-  SpriteSfx_QueueSfx3WithPan(k, 0x1d);
-  sprite_delay_main[k] = 64;
-  link_rupees_goal -= 120;
-  item_receipt_method = 0;
-  Link_ReceiveItem(0x2e, 0);
-}
-
-void PotionCauldron_GoBeep(int k) {  // 85f846
-  SpriteSfx_QueueSfx2WithPan(k, 0x3c);
-}
-
-void RedPotionItem_Draw(int k) {  // 85f86d
-  static const DrawMultipleData kRedPotionItem_Dmd[4] = {
-    { 0,  0, 0x02c0, 2},
-    {13, 18, 0x0a30, 0},
-    { 5, 18, 0x0a02, 0},
-    {-3, 18, 0x0a31, 0},
-  };
-  Sprite_DrawMultiplePlayerDeferred(k, kRedPotionItem_Dmd, 4, NULL);
-}
-
-bool PotionCauldron_CheckBottles() {  // 85f880
-  return (link_bottle_info[0] | link_bottle_info[1] | link_bottle_info[2] | link_bottle_info[3]) >= 2;
-}
-
-void Sprite_MagicShopAssistant_Main(int k) {  // 85f893
-  Shopkeeper_Draw(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  Sprite_BehaveAsBarrier(k);
-  if (Sprite_CheckIfLinkIsBusy())
-    return;
-  if (sprite_ai_state[k]) {
-    link_hearts_filler = 160;
-    sprite_ai_state[k] = 0;
-  }
-  sprite_graphics[k] = frame_counter >> 5 & 1;
-  int msg;
-  if (link_bottle_info[0] >= 2 || link_bottle_info[1] >= 2 || link_bottle_info[2] >= 2 || link_bottle_info[3] >= 2 || !flag_overworld_area_did_change)
-    msg = 0x4e;
-  else
-    msg = 0x4d;
-  if (Sprite_ShowSolicitedMessage(k, msg) & 0x100)
-    sprite_ai_state[k] = 1;
-}
-
-void Shopkeeper_Draw(int k) {  // 85f91b
-  static const DrawMultipleData kShopkeeper_Dmd[4] = {
-    {0, -8, 0x0c00, 2},
-    {0,  0, 0x0c10, 2},
-    {0, -8, 0x0c00, 2},
-    {0,  0, 0x4c10, 2},
-  };
-  PrepOamCoordsRet info;
-  Sprite_DrawMultiplePlayerDeferred(k, &kShopkeeper_Dmd[sprite_graphics[k] * 2], 2, &info);
-  SpriteDraw_Shadow(k, &info);
-}
-
-void Sprite_DashItem(int k) {  // 85fbf7
-  switch (sprite_graphics[k]) {
-  case 0: Sprite_BookOfMudora(k); break;
-  case 1: Sprite_BonkKey(k); break;
-  case 2: Sprite_LumberjackTree(k); break;
-  }
-}
-
-void Sprite_BonkKey(int k) {  // 85fc04
-  Sprite_DrawThinAndTall(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  if (Sprite_CheckDamageToLink_same_layer(k))
-    sprite_ai_state[k] = 3;
-  Sprite_MoveXY(k);
-  sprite_z_vel[k]--;
-  Sprite_MoveZ(k);
-  if (sign8(sprite_z[k])) {
-    sprite_y_vel[k] = 0;
-    sprite_z[k] = 0;
-    sprite_z_vel[k] = (uint8)-sprite_z_vel[k] >> 2;
-    if (sprite_z_vel[k] & 254)
-      SpriteSfx_QueueSfx3WithPan(k, 0x14);
-  }
-  switch (sprite_ai_state[k]) {
-  case 0:  // wait for dash
-    if ((uint16)(cur_sprite_x - link_x_coord + 16) < 33 &&
-        (uint16)(cur_sprite_y - link_y_coord + 24) < 41 && (bg1_x_offset | bg1_y_offset))
-      sprite_ai_state[k] = 1;
-    break;
-  case 1:  // being falling
-    sprite_z_vel[k] = 32;
-    sprite_y_vel[k] = -5;
-    sound_effect_2 = 27;
-    sprite_ai_state[k] = 2;
-    break;
-  case 2:  // falling
-    if (!sprite_z[k])
-      sprite_floor[k] = link_is_on_lower_level;
-    break;
-  case 3:  // give to player
-    link_num_keys++;
-    sprite_state[k] = 0;
-    dung_savegame_state_bits |= (sprite_die_action[k] ? 0x2000 : 0x4000);
-    SpriteSfx_QueueSfx3WithPan(k, 0x2f);
-    break;
-  }
-}
-
-void Sprite_BookOfMudora(int k) {  // 85fc9e
-  SpriteDraw_SingleLarge(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  if (Sprite_CheckDamageToLink_same_layer(k))
-    sprite_ai_state[k] = 3;
-  Sprite_MoveXY(k);
-  sprite_z_vel[k]--;
-  Sprite_MoveZ(k);
-  if (sign8(sprite_z[k])) {
-    sprite_y_vel[k] = 0;
-    sprite_z[k] = 0;
-    sprite_z_vel[k] = (uint8)-sprite_z_vel[k] >> 2;
-    if (sprite_z_vel[k] & 254)
-      SpriteSfx_QueueSfx2WithPan(k, 0x21);
-  }
-  switch (sprite_ai_state[k]) {
-  case 0:  // wait for dash
-    if (link_direction_facing == 0 &&
-        (uint16)(cur_sprite_x - link_x_coord + 39) < 47 &&
-        (uint16)(cur_sprite_y - link_y_coord + 40) < 46 && (bg1_x_offset | bg1_y_offset))
-      sprite_ai_state[k] = 1;
-    break;
-  case 1:  // being falling
-    sprite_z_vel[k] = 32;
-    sprite_y_vel[k] = -5;
-    sound_effect_2 = 27;
-    sprite_ai_state[k] = 2;
-    break;
-  case 2:  // falling
-    if (!sprite_z[k])
-      sprite_floor[k] = link_is_on_lower_level;
-    break;
-  case 3:  // give to player
-    Link_CancelDash();
-    item_receipt_method = 0;
-    Link_ReceiveItem(0x1d, 0);
-    sprite_state[k] = 0;
-    break;
-  }
-}
-
-void Sprite_LumberjackTree(int k) {  // 85fd4d
-  sprite_flags2[k] = 0x8f;
-  sprite_flags4[k] = 0x47;
-  DashTreeTop_Draw(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  if (Sprite_CheckDamageToLink_same_layer(k)) {
-    Sprite_NullifyHookshotDrag();
-    link_speed_setting = 0;
-    Sprite_RepelDash();
-  }
-  Sprite_MoveXY(k);
-  sprite_z_vel[k]--;
-  Sprite_MoveZ(k);
-  if (sign8(sprite_z[k])) {
-    sprite_z[k] = 0;
-    sprite_z_vel[k] = (uint8)-sprite_z_vel[k] >> 2;
-  }
-  switch (sprite_ai_state[k]) {
-  case 0:  // wait for dash
-    sprite_subtype2[k] = 0;
-    if ((uint16)(cur_sprite_x - link_x_coord + 24) < 65 &&
-        (uint16)(cur_sprite_y - link_y_coord + 32) < 81 && (bg1_x_offset | bg1_y_offset) & 0xff) {
-      sprite_z_vel[k] = 20;
-      sprite_ai_state[k] = 1;
-    }
-    break;
-  case 1:  // spawn leaves
-    if (!sprite_z[k]) {
-      sprite_ai_state[k]++;
-      sound_effect_2 = 0x1b;
-      sprite_x_vel[k] = -4;
-      sprite_y_vel[k] = -4;
-      int j = LumberjackTree_SpawnLeaves(k);
-      sprite_x_vel[j] = 5;
-      sprite_y_vel[j] = 5;
-      j = LumberjackTree_SpawnLeaves(k);
-      sprite_x_vel[j] = 5;
-      sprite_y_vel[j] = -4;
-      j = LumberjackTree_SpawnLeaves(k);
-      sprite_x_vel[j] = -4;
-      sprite_y_vel[j] = 4;
-    }
-    break;
-  case 2: // dancing leaves
-    if (!sprite_delay_main[k]) {
-      sprite_delay_main[k] = 8;
-      if (sprite_subtype2[k] == 6)
-        sprite_state[k] = 0;
-      sprite_subtype2[k]++;
-    }
-    break;
-  }
-}
-
-void DashTreeTop_Draw(int k) {  // 85fe6f
-  static const uint16 kDashTreeTop_CharFlags[16] = {0x3100, 0x3102, 0x7102, 0x7100, 0x3120, 0x3122, 0x7122, 0x7120, 0x3104, 0x3106, 0x7106, 0x7104, 0x3124, 0x3126, 0x7126, 0x7124};
-  static const int8 kDashTreeTop_X[16] = {10, 22, 30, 1, 34, 5, 13, 29, 0, 17, 27, 44, 15, 33, 18, 26};
-  static const int8 kDashTreeTop_Y[16] = {0, 4, 2, 7, 10, 16, 24, 23, 34, 35, 30, 31, 46, 42, 10, 11};
-  static const int8 kDashTreeTop_Char[6] = {8, 8, 0x28, 0x28, 0x2a, 0x2a};
-  static const int8 kDashTreeTop_Flags[6] = {0x31, 0x71, 0x31, 0x71, 0x31, 0x71};
-  PrepOamCoordsRet info;
-  if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
-    return;
-  OamEnt *oam = GetOamCurPtr();
-
-  BYTE(dungmap_var7) -= 0x20;
-  HIBYTE(dungmap_var7) -= 0x20;
-
-  if (!sprite_subtype2[k]) {
-    uint8 x = BYTE(dungmap_var7);
-    uint8 y = HIBYTE(dungmap_var7);
-    for (int i = 0; i < 16; i++) {
-      oam[i].x = x + (i & 3) * 0x10;
-      oam[i].y = y + (i >> 2) * 0x10;
-      WORD(oam[i].charnum) = kDashTreeTop_CharFlags[i];
-    }
-    Sprite_CorrectOamEntries(k, 15, 2);
-  } else {
-    int j = sprite_subtype2[k] - 1;
-    for (int i = 15; i >= 0; i--, oam++) {
-      oam->x = BYTE(dungmap_var7) + kDashTreeTop_X[i];
-      oam->y = HIBYTE(dungmap_var7) + kDashTreeTop_Y[i];
-      oam->charnum = kDashTreeTop_Char[j];
-      oam->flags = kDashTreeTop_Flags[j];
-    }
-    Sprite_CorrectOamEntries(k, 15, 2);
-  }
-}
-
-int LumberjackTree_SpawnLeaves(int k) {  // 85ff39
-  SpriteSpawnInfo info;
-  int j = Sprite_SpawnDynamically(k, 0x3B, &info);
-  assert(j >= 0);
-  sprite_graphics[j] = 2;
-  sprite_z_vel[j] = sprite_z_vel[k];
-  sprite_subtype2[j] = 1;
-  sprite_ai_state[j] = 2;
-  sprite_delay_main[j] = 8;
-  Sprite_SetSpawnedCoordinates(j, &info);
-  return j;
-}
-
-void Sprite_TroughBoy(int k) {  // 85ff66
-  TroughBoy_Draw(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  Sprite_BehaveAsBarrier(k);
-  Sprite_TrackBodyToHead(k);
-  sprite_head_dir[k] = Sprite_DirectionToFaceLink(k, NULL) ^ 3;
-
-  if (savegame_map_icons_indicator < 3) {
-    if (Sprite_ShowSolicitedMessage(k, 0x147) & 0x100)
-      savegame_map_icons_indicator = 2;
-  } else {
-    Sprite_ShowSolicitedMessage(k, 0x148);
-  }
-}
-
-void TroughBoy_Draw(int k) {  // 85ffdf
-  static const DrawMultipleData kTroughBoy_Dmd[8] = {
-    {0, -8, 0x0882, 2},
-    {0,  0, 0x0aaa, 2},
-    {0, -8, 0x0882, 2},
-    {0,  0, 0x0aaa, 2},
-    {0, -8, 0x4880, 2},
-    {0,  0, 0x0aaa, 2},
-    {0, -8, 0x0880, 2},
-    {0,  0, 0x0aaa, 2},
-  };
-  PrepOamCoordsRet info;
-  Sprite_DrawMultiplePlayerDeferred(k, &kTroughBoy_Dmd[sprite_D[k] * 2], 2, &info);
-  SpriteDraw_Shadow(k, &info);
-}
-
-void BottleMerchant_DetectFish(int k) {  // 868000
-  for (int i = 15; i >= 0; i--) {
-    if (sprite_state[i] && sprite_type[i] == 0xd2) {
-      SpriteHitBox hb;
-      hb.r0_xlo = sprite_x_lo[k];
-      hb.r8_xhi = sprite_x_hi[k];
-      hb.r2 = 16;
-      hb.r1_ylo = sprite_y_lo[k];
-      hb.r9_yhi = sprite_y_hi[k];
-      hb.r3 = 16;
-      Sprite_SetupHitBox(i, &hb);
-      if (CheckIfHitBoxesOverlap(&hb))
-        sprite_E[k] = 0x80 | i;
-      return;
-    }
-  }
-}
-
-void BottleMerchant_BuyFish(int k) {  // 868054
-  static const uint8 kBottleVendor_FishRewardType[5] = {0xdb, 0xe0, 0xde, 0xe2, 0xd9};
-  static const int8 kBottleVendor_FishRewardXv[5] = {-6, -3, 0, 4, 7};
-  static const int8 kBottleVendor_FishRewardYv[5] = {11, 14, 16, 14, 11};
-  SpriteSpawnInfo info;
-  SpriteSfx_QueueSfx3WithPan(k, 0x13);
-  tmp_counter = 4;
-  do {
-    int j = Sprite_SpawnDynamically(k, kBottleVendor_FishRewardType[tmp_counter], &info);
-    if (j < 0)
-      return;
-    Sprite_SetSpawnedCoordinates(j, &info);
-    sprite_x_lo[j] = info.r0_x + 4;
-    sprite_stunned[j] = 0xff;
-    sprite_x_vel[j] = kBottleVendor_FishRewardXv[tmp_counter];
-    sprite_y_vel[j] = kBottleVendor_FishRewardYv[tmp_counter];
-    sprite_z_vel[j] = 32;
-    sprite_delay_aux4[j] = 32;
-  } while (!sign8(--tmp_counter));
-}
-
-void SpritePrep_ThrowableScenery(int k) {  // 86850f
-}
-
-void SpriteModule_Initialize(int k) {  // 86864d
-  SpritePrep_LoadProperties(k);
-  sprite_state[k]++;
-  kSpritePrep_Main[sprite_type[k]](k);
-}
-
-void SpritePrep_Mantle(int k) {  // 868841
-  sprite_y_lo[k] += 3;
-  sprite_x_lo[k] += 8;
-}
-
-void SpritePrep_Switch(int k) {  // 868859
-  int j = BYTE(dungeon_room_index2);
-  if (j == 0xce || j == 4 || j == 0x3f)
-    sprite_oam_flags[k] = 0xD;
-}
-
-void SpritePrep_SwitchFacingUp(int k) {  // 86886d
-}
-
-void SpritePrep_Snitch_bounce_1(int k) {  // 86886e
-  SpritePrep_Snitches(k);
-}
-
-void SpritePrep_DoNothingA(int k) {  // 868873
-}
-
-void SpritePrep_Rat(int k) {  // 868878
-  static const uint8 kSpriteRat_BumpDamage[2] = {0, 5};
-  static const uint8 kSpriteRat_Health[2] = {2, 8};
-  int j = is_in_dark_world;
-  sprite_bump_damage[k] = kSpriteRat_BumpDamage[j];
-  sprite_health[k] = kSpriteRat_Health[j];
-}
-
-void SpritePrep_Keese(int k) {  // 86888e
-  static const uint8 kSpriteKeese_BumpDamage[2] = {0x80, 0x85};
-  static const uint8 kSpriteKeese_Health[2] = {1, 4};
-  static const uint8 kSpriteKeese_Flags5[2] = {0, 7};
-  int j = is_in_dark_world;
-  sprite_bump_damage[k] = kSpriteKeese_BumpDamage[j];
-  sprite_health[k] = kSpriteKeese_Health[j];
-  sprite_flags5[k] = kSpriteKeese_Flags5[j];
-}
-
-void SpritePrep_Rope(int k) {  // 8688aa
-  static const uint8 kSpriteRope_BumpDamage[2] = {1, 5};
-  static const uint8 kSpriteRope_Health[2] = {4, 8};
-  static const uint8 kSpriteRope_Flags5[2] = {1, 7};
-  int j = is_in_dark_world;
-  sprite_bump_damage[k] = kSpriteRope_BumpDamage[j];
-  sprite_health[k] = kSpriteRope_Health[j];
-  sprite_flags5[k] = kSpriteRope_Flags5[j];
-}
-
-void SpritePrep_Swamola(int k) {  // 8688c0
-  SpritePrep_Swamola_InitializeSegments(k);
-  SpritePrep_Kyameron(k);
-}
-
-void SpritePrep_Blind(int k) {  // 8688c7
-  if (Sprite_ReturnIfBossFinished(k))
-    return;
-  SpritePrep_Blind_PrepareBattle(k);
-}
-
-void SpritePrep_Ganon(int k) {  // 8688cf
-  if (Sprite_ReturnIfBossFinished(k))
-    return;
-  Ganon_HandleAnimation_Idle(k);
-  sprite_delay_main[k] = 128;
-  sprite_room[k] = 2;
-  music_control = 0x1e;
-}
-
-void SpritePrep_Pokey(int k) {  // 8688df
-  static const int8 kHokbok_InitXvel[4] = {16, -16, 16, -16};
-  static const int8 kHokbok_InitYvel[4] = {16, 16, -16, -16};
-  sprite_A[k] = 3;
-  sprite_B[k] = 8;
-  int j = GetRandomNumber() & 3;
-  sprite_x_vel[k] = kHokbok_InitXvel[j];
-  sprite_y_vel[k] = kHokbok_InitYvel[j];
-}
-
-void SpritePrep_MiniVitreous(int k) {  // 8688fd
-  Sprite_ReturnIfBossFinished(k);
-}
-
-void SpritePrep_Gibo(int k) {  // 868901
-  sprite_z[k] = 16;
-  sprite_G[k] = 8;
-}
-
-void SpritePrep_Octoballoon(int k) {  // 868910
-  static const uint8 kSprite_Octoballoon_Delay[4] = {192, 208, 224, 240};
-  sprite_delay_main[k] = kSprite_Octoballoon_Delay[k & 3];
-}
-
-void SpritePrep_AgahnimsBarrier(int k) {  // 86891b
-  if (save_ow_event_info[BYTE(overworld_screen_index)] & 0x40)
-    sprite_graphics[k] = 4;
-  SpritePrep_MoveDown_8px_Right8px(k);
-  sprite_y_lo[k] -= 12;
-  sprite_ignore_projectile[k]++;
-}
-
-void SpritePrep_Catfish(int k) {  // 86892c
-  SpritePrep_MoveDown_8px_Right8px(k);
-  sprite_y_lo[k] -= 12;
-  SpritePrep_IgnoreProjectiles(k);
-}
-
-void SpritePrep_CutsceneAgahnim(int k) {  // 86893b
-  if (dung_savegame_state_bits & 0x4000) {
-    sprite_state[k] = 0;
-  } else {
-    CutsceneAgahnim_SpawnZeldaOnAltar(k);
-    sprite_ignore_projectile[k]++;
-  }
-}
-
-void SpritePrep_Vitreous(int k) {  // 86894d
-  if (Sprite_ReturnIfBossFinished(k))
-    return;
-  SpritePrep_MoveDown_8px_Right8px(k);
-  sprite_y_lo[k] -= 16;
-  Vitreous_SpawnSmallerEyes(k);
-  sprite_ignore_projectile[k]++;
-}
-
-void SpritePrep_Raven(int k) {  // 868969
-  static const uint8 kSpriteRaven_BumpDamage[2] = {0x81, 0x88};
-  static const uint8 kSpriteRaven_Health[2] = {4, 8};
-  static const uint8 kSpriteRaven_Flags5[2] = {6, 2};
-  int j = is_in_dark_world;
-  sprite_bump_damage[k] = kSpriteRaven_BumpDamage[j];
-  sprite_health[k] = kSpriteRaven_Health[j];
-  sprite_flags5[k] = kSpriteRaven_Flags5[j];
-  sprite_z[k] = 0;
-  sprite_A[k] = (sprite_x_lo[k] & 16) >> 4;
-  sprite_subtype[k] = 254;
-}
-
-void SpritePrep_Vulture(int k) {  // 86897e
-  sprite_z[k] = 0;
-  sprite_A[k] = (sprite_x_lo[k] & 16) >> 4;
-  sprite_subtype[k] = 254;
-}
-
-void SpritePrep_Poe(int k) {  // 868991
-  sprite_z[k] = 12;
-  sprite_subtype[k] = 254;
-}
-
-void SpritePrep_DoNothingC(int k) {  // 86899b
-  // empty
-}
-
-void SpritePrep_BlindMaiden(int k) {  // 86899c
-  if (!(save_dung_info[0xac] & 0x800)) {
-    sprite_ignore_projectile[k]++;
-    if (follower_indicator != 6) {
-      follower_indicator = 6;
-      follower_dropped = 0;
-      tagalong_var5 = 0;
-      LoadFollowerGraphics();
-      Follower_Initialize();
-      follower_indicator = 0;
-      return;
-    }
-  }
-  sprite_state[k] = 0;
-}
-
-void SpritePrep_MiniMoldorm_bounce(int k) {  // 8689d3
-  int j = 32 * k;
-  for (int i = 0; i < 32; i++, j++) {
-    moldorm_x_lo[j] = sprite_x_lo[k];
-    moldorm_x_hi[j] = sprite_x_hi[k];
-    moldorm_y_lo[j] = sprite_y_lo[k];
-    moldorm_y_hi[j] = sprite_y_hi[k];
-  }
-}
-
-void SpritePrep_Bomber(int k) {  // 8689d8
-  sprite_z[k] = 16;
-  sprite_subtype[k] = 254;
-}
-
-void SpritePrep_BombShoppe(int k) {  // 8689df
-  sprite_ignore_projectile[k]++;
-  SpriteSpawnInfo info;
-  int j = Sprite_SpawnDynamically(k, 0xb5, &info);
-  if (j >= 0) {
-    Sprite_SetX(j, info.r0_x - 24);
-    Sprite_SetY(j, info.r2_y - 24);
-    sprite_subtype2[j] = 1;
-    sprite_ignore_projectile[j] = 1;
-  }
-  if ((link_has_crystals & 5) == 5 && sram_progress_indicator_3 & 32) {
-    int j = Sprite_SpawnDynamically(k, 0xb5, &info);
-    if (j >= 0) {
-      Sprite_SetX(j, info.r0_x - 56);
-      Sprite_SetY(j, info.r2_y - 24);
-      sprite_subtype2[j] = 2;
-      sprite_ignore_projectile[j] = 2;
-    }
-  }
-}
-
-void SpritePrep_BullyAndVictim(int k) {  // 868a51
-  SpawnBully(k);
-  sprite_ignore_projectile[k]++;
-}
-
-void SpritePrep_PurpleChest(int k) {  // 868a59
-  if (follower_indicator != 12 && !(sram_progress_indicator_3 & 16) && sram_progress_indicator_3 & 32)
-    sprite_ignore_projectile[k]++;
-  else
-    sprite_state[k] = 0;
-}
-
-void SpritePrep_Smithy(int k) {  // 868a79
-  sprite_ignore_projectile[k]++;
-  if (savegame_is_darkworld & 64) {
-    if (sram_progress_indicator_3 & 32 || follower_indicator != 0)
-      sprite_state[k] = 0;
-    else
-      sprite_subtype2[k] = 2;
-    return;
-  }
-  Smithy_SpawnDumbBarrierSprite(k);
-  if (!(sram_progress_indicator_3 & 32)) {
-    sprite_x_lo[k] += 2;
-    sprite_y_lo[k] -= 3;
-    return;
-  }
-  sprite_x_lo[k] += 2;
-  sprite_y_lo[k] -= 3;
-  int j = Smithy_SpawnDwarfPal(k);
-  Smithy_SpawnDumbBarrierSprite(j);
-  sprite_E[j] = k;
-  sprite_E[k] = j;
-
-  if (sram_progress_indicator_3 & 0x80) {
-    sprite_ai_state[k] = 5;
-    sprite_ai_state[j] = 5;
-  }
-}
-
-void SpritePrep_Babasu(int k) {  // 868af0
-  SpritePrep_MoveDown_8px(k);
-  SpritePrep_Zoro(k);
-}
-
-void SpritePrep_Zoro(int k) {  // 868af3
-  sprite_D[k] = (sprite_type[k] - 0x9c) << 1;
-  sprite_graphics[k]--;
-}
-
-void SpritePrep_LaserEye_bounce(int k) {  // 868b03
-  int t = sprite_type[k];
-  sprite_D[k] = t - 0x95;
-  if (t >= 0x97) {
-    sprite_x_lo[k] += 8;
-    sprite_head_dir[k] = sprite_x_lo[k] & 16 ^ 16;
-    if (!sprite_head_dir[k])
-      sprite_y_lo[k] += (t & 1) ? -8 : 8;
-  } else {
-    sprite_head_dir[k] = sprite_y_lo[k] & 16;
-    if (!sprite_head_dir[k])
-      sprite_x_lo[k] += (t & 1) ? -8 : 8;
-  }
-}
-
-void SpritePrep_Popo(int k) {  // 868b08
-  sprite_B[k] = 7;
-}
-
-void SpritePrep_Popo2(int k) {  // 868b0c
-  sprite_B[k] = 15;
-}
-
-void SpritePrep_Statue(int k) {  // 868b12
-  sprite_y_lo[k] += 7;
-}
-
-void SpritePrep_Bari(int k) {  // 868b1c
-  sprite_z[k] = 6;
-  if (BYTE(dungeon_room_index2) == 206)
-    sprite_C[k]--;
-  sprite_delay_aux1[k] = (GetRandomNumber() & 63) + 128;
-}
-
-void SpritePrep_GreenStalfos(int k) {  // 868b2e
-  sprite_z[k] = 9;
-}
-
-void SpritePrep_WaterLever(int k) {  // 868b34
-  sprite_y_lo[k] += 5;
-}
-
-void SpritePrep_FireDebirando(int k) {  // 868b3e
-  sprite_type[k] = 0x63;
-  SpritePrep_LoadProperties(k);
-  sprite_G[k]--;
-  SpritePrep_DebirandoPit(k);
-}
-
-void SpritePrep_DebirandoPit(int k) {  // 868b4a
-  static const uint8 kDebirando_OamFlags[2] = {6, 8};
-  sprite_G[k]++;
-  sprite_delay_main[k] = 0;
-  sprite_graphics[k] = 6;
-  SpritePrep_IgnoreProjectiles(k);
-  SpriteSpawnInfo info;
-  int j = Sprite_SpawnDynamically(k, 0x64, &info);
-  if (j >= 0) {
-    Sprite_SetSpawnedCoordinates(j, &info);
-    sprite_delay_main[j] = 96;
-    sprite_head_dir[k] = j;
-    sprite_G[j] = sprite_G[k];
-    sprite_oam_flags[j] = kDebirando_OamFlags[sprite_G[j]];
-  }
-}
-
-void SpritePrep_WeakGuard(int k) {  // 868b81
-  sprite_D[k] = sprite_head_dir[k] = GetRandomNumber() & 3;
-  sprite_delay_main[k] = 16;
-}
-
-void SpritePrep_WallCannon(int k) {  // 868b93
-  sprite_D[k] = sprite_type[k] - 0x66;
-  sprite_A[k] = sprite_D[k] & 2;
-}
-
-void SpritePrep_ArrowGame_bounce(int k) {  // 868ba2
-  static const uint8 kArcheryGameGuy_X[8] = {0, 0x40, 0x80, 0xc0, 0x30, 0x60, 0x90, 0xc0};
-  static const uint8 kArcheryGameGuy_Y[8] = {0, 0x4f, 0x4f, 0x4f, 0x5a, 0x5a, 0x5a, 0x5a};
-  static const uint8 kArcheryGameGuy_A[8] = {0, 1, 1, 1, 2, 2, 2, 2};
-  static const int8 kArcheryGameGuy_Xvel[2] = {-8, 12};
-  static const uint8 kArcheryGameGuy_Flags4[2] = {0x1c, 0x15};
-  byte_7E0B88 = 0;
-  sprite_y_lo[k] -= 9;
-  for (int i = 7; i != 0; i--) {
-    sprite_type[i] = 0x65;
-    sprite_state[i] = 9;
-    SpritePrep_LoadProperties(i);
-    sprite_x_hi[i] = (link_x_coord >> 8);
-    sprite_x_lo[i] = kArcheryGameGuy_X[i];
-    sprite_y_hi[i] = (link_y_coord >> 8);
-    sprite_y_lo[i] = kArcheryGameGuy_Y[i];
-    sprite_A[i] = kArcheryGameGuy_A[i];
-    int j = kArcheryGameGuy_A[i] - 1;
-    sprite_graphics[i] = j;
-    sprite_x_vel[i] = kArcheryGameGuy_Xvel[j];
-    sprite_flags4[i] = kArcheryGameGuy_Flags4[j];
-    sprite_oam_flags[i] = 13;
-    sprite_floor[i] = link_is_on_lower_level;
-    sprite_subtype2[i] = GetRandomNumber();
-  }
-  sprite_ignore_projectile[k]++;
-  sprite_subtype[k] = link_num_arrows;
-}
-
-void SpritePrep_IgnoreProjectiles(int k) {  // 868ba7
-  sprite_ignore_projectile[k]++;
-}
-
-void SpritePrep_HauntedGroveAnimal(int k) {  // 868bab
-  sprite_D[k] = Sprite_IsRightOfLink(k).a;
-  SpritePrep_HauntedGroveOstritch(k);
-}
-
-void SpritePrep_HauntedGroveOstritch(int k) {  // 868bb2
-  if (link_item_flute >= 2)
-    sprite_state[k] = 0;
-  sprite_ignore_projectile[k]++;
-}
-
-void SpritePrep_DiggingGameGuy_bounce(int k) {  // 868bbf
-  if (link_y_coord < Sprite_GetY(k)) {
-    sprite_ai_state[k] = 5;
-    sprite_x_lo[k] -= 9;
-    sprite_graphics[k] = 1;
-  }
-  sprite_ignore_projectile[k]++;
-}
-
-void SpritePrep_ThievesTownGrate(int k) {  // 868bc4
-  if (save_ow_event_info[0x58] & 0x20)
-    sprite_state[k] = 0;
-  sprite_ignore_projectile[k]++;
-  Sprite_SetX(k, Sprite_GetX(k) - 8);
-}
-
-void SpritePrep_RupeePull(int k) {  // 868bcf
-  sprite_ignore_projectile[k]++;
-  Sprite_SetX(k, Sprite_GetX(k) - 8);
-}
-
-void SpritePrep_Shopkeeper(int k) {  // 868bf1
-  sprite_ignore_projectile[k]++;
-  sprite_flags2[k] |= 2;
-  sprite_oam_flags[k] |= 12;
-  sprite_flags3[k] |= 16;
-  static const uint8 kShopKeeperWhere[13] = {0xf, 0x10, 0, 6, 0x18, 0x12, 0x1e, 0xff, 0x1f, 0x23, 0x24, 0x25, 0x27};
-  uint8 room = BYTE(dungeon_room_index);
-  int j = FindInByteArray(kShopKeeperWhere, room, 13);
-  switch (j) {
-  case 0:
-    ShopKeeper_SpawnShopItem(k, 0, 7);
-    ShopKeeper_SpawnShopItem(k, 1, 8);
-    ShopKeeper_SpawnShopItem(k, 2, 12);
-    break;
-  case 1:
-    ShopKeeper_SpawnShopItem(k, 0, 9);
-    ShopKeeper_SpawnShopItem(k, 1, 13);
-    ShopKeeper_SpawnShopItem(k, 2, 11);
-    break;
-  case 2:
-    sprite_subtype2[k] = 4;
-    minigame_credits = 0xff;
-    break;
-  case 3:
-    sprite_subtype2[k] = sprite_graphics[k] = 1;
-    minigame_credits = 0xff;
-    break;
-  case 4:
-    sprite_subtype2[k] = 3;
-    minigame_credits = 0xff;
-    break;
-  case 5: case 7: case 8:
-    ShopKeeper_SpawnShopItem(k, 0, 7);
-    ShopKeeper_SpawnShopItem(k, 1, 10);
-    ShopKeeper_SpawnShopItem(k, 2, 12);
-    break;
-  case 6: case 9: case 12:
-    sprite_subtype2[k] = 2;
-    break;
-  case 10:
-    sprite_subtype2[k] = 5;
-    break;
-  case 11:
-    sprite_subtype2[k] = 6;
-    break;
-  default:
-    assert(0);
-  }
-}
-
-void SpritePrep_Storyteller(int k) {  // 868c9e
-  static const uint8 kStoryTellerRooms[5] = {0xe, 0xe, 0x12, 0x1a, 0x14};
-  int r = FindInByteArray(kStoryTellerRooms, BYTE(dungeon_room_index), 5);
-  if (r == 0 && sprite_x_hi[k] & 1)
-    r = 1;
-  sprite_subtype2[k] = r;
-  sprite_ignore_projectile[k]++;
-}
-
-void SpritePrep_Adults(int k) {  // 868cc1
-  static const uint8 kHumanMultiTypes[3] = {3, 0xe1, 0x19};
-  sprite_ignore_projectile[k]++;
-  sprite_subtype2[k] = FindInByteArray(kHumanMultiTypes, BYTE(dungeon_room_index), 3);
-}
-
-void SpritePrep_Whirlpool(int k) {  // 868cd5
-  sprite_ignore_projectile[k]++;
-  sprite_A[k] = 1;
-}
-
-void SpritePrep_Sage(int k) {  // 868cde
-  sprite_ignore_projectile[k]++;
-  if (BYTE(dungeon_room_index) == 10) {
-    sprite_subtype2[k]++;
-    sprite_oam_flags[k] = 11;
-  }
-}
-
-void SpritePrep_BonkItem(int k) {  // 868cf2
-  static const uint16 kDashItemMask[2] = {0x4000, 0x2000};
-  if (!player_is_indoors) {
-    sprite_graphics[k] = 2;
-    return;
-  }
-  sprite_floor[k] = 2;
-  if (dungeon_room_index == 0x107) {
-    if (link_item_book_of_mudora)
-      sprite_state[k] = 0;
-    else
-      DecodeAnimatedSpriteTile_variable(0xe);
-  } else {
-    int j = byte_7E0B9B++;
-    sprite_die_action[k] = j;
-    if (dung_savegame_state_bits & kDashItemMask[j])
-      sprite_state[k] = 0;
-    sprite_graphics[k]++;
-    sprite_oam_flags[k] = 8;
-    sprite_flags3[k] |= 0x20;
-  }
-}
-
-void SpritePrep_Kiki(int k) {  // 868d46
-  sprite_ignore_projectile[k]++;
-  if (save_ow_event_info[BYTE(overworld_screen_index)] & 0x20)
-    sprite_state[k] = 0;
-}
-
-void SpritePrep_Locksmith(int k) {  // 868d59
-  sprite_ignore_projectile[k]++;
-  if (follower_indicator == 9) {
-    sprite_state[k] = 0;
-    return;
-  }
-  if (follower_indicator == 12) {
-    sprite_ai_state[k] = 2;
-  }
-  if (sram_progress_indicator_3 & 0x10)
-    sprite_ai_state[k] = 4;
-}
-
-void SpritePrep_SickKid(int k) {  // 868d7f
-  if (link_item_bug_net)
-    sprite_ai_state[k] = 3;
-  sprite_ignore_projectile[k]++;
-}
-
-void SpritePrep_Tektite(int k) {  // 868d94
-  static const uint8 kGanonHelpers_OamFlags[2] = {9, 7};
-  static const uint8 kGanonHelpers_Health[2] = {8, 12};
-  static const uint8 kGanonHelpers_BumpDamage[2] = {3, 5};
-  int j;
-  sprite_A[k] = j = sprite_x_lo[k] >> 4 & 1;
-  sprite_oam_flags[k] = kGanonHelpers_OamFlags[j];
-  sprite_health[k] = kGanonHelpers_Health[j];
-  sprite_bump_damage[k] = kGanonHelpers_BumpDamage[j];
-  Sprite_ApplySpeedTowardsLink(k, 16);
-  sprite_z_vel[k] = 32;
-  sprite_ai_state[k]++;
-}
-
-void SpritePrep_Chainchomp_bounce(int k) {  // 868dc1
-  int i = k * 8;
-  for (int j = 5; j >= 0; j--, i++) {
-    chainchomp_x_hist[i] = cur_sprite_x;
-    chainchomp_y_hist[i] = cur_sprite_y;
-  }
-  sprite_A[k] = sprite_x_lo[k];
-  sprite_B[k] = sprite_x_hi[k];
-  sprite_C[k] = sprite_y_lo[k];
-  sprite_G[k] = sprite_y_hi[k];
-}
-
-void SpritePrep_BigFairy(int k) {  // 868dc6
-  sprite_z[k] = 24;
-  SpritePrep_MoveDown_8px_Right8px(k);
-  sprite_ignore_projectile[k]++;
-}
-
-void SpritePrep_MrsSahasrahla(int k) {  // 868dd1
-  sprite_y_lo[k] += 8;
-  SpritePrep_MagicBat(k);
-}
-
-void SpritePrep_MagicBat(int k) {  // 868dda
-  sprite_x_lo[k] += 8;
-  sprite_ignore_projectile[k]++;
-}
-
-void SpritePrep_FortuneTeller(int k) {  // 868de0
-  SpritePrep_IncrXYLow8(k);
-  sprite_ignore_projectile[k]++;
-}
-
-void SpritePrep_FairyPond(int k) {  // 868de9
-  static const uint8 kLeever_OamFlags[2] = {10, 2};
-  int j = sprite_x_lo[k] >> 4 & 1;
-  sprite_A[k] = j;
-  sprite_oam_flags[k] = kLeever_OamFlags[j];
-}
-
-void SpritePrep_Hobo(int k) {  // 868dfd
-  for (int i = 15; i; i--)
-    SpritePrep_Hobo_SpawnSmoke(k);
-  for (int i = 15; i; i--) {
-    if (sprite_type[i] == 0x2b)
-      sprite_state[i] = 0;
-  }
-  SpritePrep_Hobo_SpawnFire(k);
-  if (sram_progress_indicator_3 & 1)
-    sprite_ai_state[0] = 3;
-  sprite_ignore_projectile[0] = 1;
-}
-
-void SpritePrep_MasterSword(int k) {  // 868e30
-  sprite_x_lo[k] += 6;
-  sprite_y_lo[k] += 6;
-}
-
-void SpritePrep_Roller_HorizontalRightFirst(int k) {  // 868e42
-  sprite_ai_state[k] = (~sprite_x_lo[k] & 16) >> 4;
-  if (sprite_ai_state[k])
-    sprite_flags4[k]++;
-  sprite_D[k] = 0;
-}
-
-void SpritePrep_RollerLeftRight(int k) {  // 868e46
-  sprite_ai_state[k] = (~sprite_x_lo[k] & 16) >> 4;
-  if (sprite_ai_state[k])
-    sprite_flags4[k]++;
-  sprite_D[k] = 1;
-}
-
-void SpritePrep_Roller_VerticalDownFirst(int k) {  // 868e4f
-  sprite_ai_state[k] = (sprite_y_lo[k] & 16) >> 4;
-  if (sprite_ai_state[k])
-    sprite_flags4[k]++;
-  sprite_D[k] = 2;
-}
-
-void SpritePrep_RollerUpDown(int k) {  // 868e53
-  sprite_ai_state[k] = (sprite_y_lo[k] & 16) >> 4;
-  if (sprite_ai_state[k])
-    sprite_flags4[k]++;
-  sprite_D[k] = 3;
-}
-
-void SpritePrep_Kodongo(int k) {  // 868e6b
-  sprite_x_lo[k] += 4;
-  Sprite_SetY(k, Sprite_GetY(k) - 5);
-  sprite_subtype[k]--;
-}
-
-void SpritePrep_Spark(int k) {  // 868e85
-  sprite_subtype[k]--;
-}
-
-void SpritePrep_LostWoodsBird(int k) {  // 868ec1
-  sprite_z_vel[k] = (GetRandomNumber() & 0x1f) - 0x10;
-  sprite_z[k] = 64;
-  SpritePrep_LostWoodsSquirrel(k);
-}
-
-void SpritePrep_LostWoodsSquirrel(int k) {  // 868ed2
-  sprite_x_vel[k] = Sprite_IsRightOfLink(k).a ? -16 : 16;
-  sprite_ignore_projectile[k] = sprite_y_vel[k] = sign8(byte_7E069E[0]) ? 4 : -4;
-}
-
-void SpritePrep_Antifairy(int k) {  // 868ef2
-  static const int8 kBubble_Xvel[2] = {16, -16};
-  sprite_x_vel[k] = kBubble_Xvel[sprite_x_lo[k] >> 4 & 1];
-  sprite_y_vel[k] = -16;
-}
-
-void SpritePrep_FallingIce(int k) {  // 868f08
-  if (Sprite_ReturnIfBossFinished(k))
-    return;
-  sprite_ignore_projectile[k]++;
-}
-
-void SpritePrep_KingZora(int k) {  // 868f0f
-  if (link_item_flippers)
-    sprite_state[k] = 0;
-  else
-    sprite_ignore_projectile[k]++;
-}
-
-bool Sprite_ReturnIfBossFinished(int k) {  // 868f1c
-  if (dung_savegame_state_bits & 0x8000) {
-    sprite_state[k] = 0;
-    return true;
-  }
-  for (int j = 15; j >= 0; j--) {
-    if (!(kSpriteInit_BumpDamage[sprite_type[j]] & 0x10))
-      sprite_state[j] = 0;
-  }
-  return false;
-}
-
-void SpritePrep_ArmosKnight(int k) {  // 868f3f
-  if (Sprite_ReturnIfBossFinished(k))
-    return;
-  sprite_delay_main[k] = 255;
-  byte_7E0FF8++;
-  SpritePrep_MoveDown_8px_Right8px(k);
-}
-
-void SpritePrep_DesertStatue(int k) {  // 868f4d
-  sprite_A[k] = sprite_limit_instance;
-  sprite_limit_instance++;
-  SpritePrep_MoveDown_8px_Right8px(k);
-  sprite_D[k] = (sprite_x_lo[k] < 0x30) ? 1 : (sprite_x_lo[k] < 0xe0) ? 3 : 2;
-}
-
-void SpritePrep_DoNothingD(int k) {  // 868f6c
-  // empty
-}
-
-void SpritePrep_Octorok(int k) {  // 868f71
-  static const uint8 kOctorock_BumpDamage[2] = {3, 5};
-  static const uint8 kOctorock_Health[2] = {2, 4};
-  int j = is_in_dark_world;
-  sprite_health[k] = kOctorock_Health[j];
-  sprite_bump_damage[k] = kOctorock_BumpDamage[j];
-  sprite_delay_main[k] = GetRandomNumber() & 127;
-}
-
-void SpritePrep_Moldorm(int k) {  // 868f8a
-  if (Sprite_ReturnIfBossFinished(k))
-    return;
-  sprite_ignore_projectile[k]++;
-  Sprite_InitializedSegmented(k);
-}
-
-void SpritePrep_Lanmolas(int k) {  // 868f95
-  static const uint8 kLanmola_InitDelay[3] = {128, 192, 255};
-
-  if (Sprite_ReturnIfBossFinished(k))
-    return;
-  sprite_delay_main[k] = kLanmola_InitDelay[k];
-  sprite_z[k] = -1;
-  for (int i = 0; i < 64; i++)
-    beamos_x_hi[k * 0x40 + i] = 0xff;
-  garnish_y_lo[k] = 7;
-}
-
-void SpritePrep_BigSpike(int k) {  // 868f9d
-  SpritePrep_MoveDown_8px_Right8px(k);
-  SpritePrep_Kyameron(k);
-}
-
-void SpritePrep_SwimmingZora(int k) {  // 868fa2
-  sprite_delay_main[k] = 64;
-  SpritePrep_Geldman(k);
-}
-
-void SpritePrep_Geldman(int k) {  // 868fa7
-  sprite_x_lo[k] += 8;
-  SpritePrep_Kyameron(k);
-}
-
-void SpritePrep_Kyameron(int k) {  // 868fb0
-  sprite_A[k] = sprite_x_lo[k];
-  sprite_B[k] = sprite_x_hi[k];
-  sprite_C[k] = sprite_y_lo[k];
-  sprite_head_dir[k] = sprite_y_hi[k];
-}
-
-void SpritePrep_WalkingZora(int k) {  // 868fc9
-  sprite_delay_main[k] = 96;
-}
-
-void SpritePrep_StandardGuard(int k) {  // 868fd6
-  static const uint8 kSpriteSoldier_Tab0[8] = {0, 2, 1, 3, 6, 4, 5, 7};
-
-  uint8 subtype = sprite_subtype[k];
-  if (subtype != 0) {
-    if ((subtype & 7) >= 5) {
-      int j = ((subtype & 7) != 5) * 4 + (subtype >> 3 & 3);
-      sprite_B[k] = kSpriteSoldier_Tab0[j];
-      sprite_flags[k] = sprite_flags[k] & 0xf | 0x50;
-      SpritePrep_TrooperAndArcherSoldier(k);
-      return;
-    }
-    sprite_D[k] = ((subtype & 7) - 1) ^ 1;
-  }
-  if (player_is_indoors) {
-    sprite_flags5[k] &= ~0x80;
-    return;
-  }
-  sprite_ai_state[k] = 1;
-  sprite_delay_main[k] = 112;
-  sprite_D[k] = sprite_head_dir[k] = Sprite_DirectionToFaceLink(k, NULL);
-  SpritePrep_TrooperAndArcherSoldier(k);
-}
-
-void SpritePrep_TrooperAndArcherSoldier(int k) {  // 869001
-  uint8 bak0 = submodule_index;
-  submodule_index = 0;
-  sprite_defl_bits[k] = (sprite_defl_bits[k] >> 1) | 0x80;
-  SpriteActive_Main(k);
-  SpriteActive_Main(k);
-  sprite_defl_bits[k] <<= 1;
-  submodule_index = bak0;
-}
-
-void SpritePrep_TalkingTree(int k) {  // 869043
-  sprite_ignore_projectile[k]++;
-  Sprite_SetX(k, Sprite_GetX(k) - 8);
-  SpritePrep_TalkingTree_SpawnEyeball(k, 0);
-  SpritePrep_TalkingTree_SpawnEyeball(k, 1);
-}
-
-void SpritePrep_CrystalSwitch(int k) {  // 869064
-  sprite_oam_flags[k] |= kCrystalSwitchPal[orange_blue_barrier_state & 1];
-}
-
-void SpritePrep_FluteKid(int k) {  // 869075
-  sprite_ignore_projectile[k]++;
-  sprite_subtype2[k] = savegame_is_darkworld >> 6 & 1;
-  if (sprite_subtype2[k]) {
-    if (sram_progress_indicator_3 & 8 || link_item_flute > 2) {
-      sprite_graphics[k] = 3;
-      sprite_ai_state[k] = 5;
-    } else if (link_item_flute == 2) {
-      sprite_graphics[k] = 1;
-    }
-    sprite_x_lo[k] += 8;
-    sprite_y_lo[k] -= 8;
-  } else {
-    if (link_item_flute >= 2)
-      sprite_state[k] = 0;
-    else
-      sprite_x_lo[k] += 7;
-  }
-}
-
-void SpritePrep_MoveDown_8px(int k) {  // 8690cc
-  sprite_y_lo[k] += 8;
-}
-
-void SpritePrep_Zazakku(int k) {  // 8690d5
-  // empty
-}
-
-void SpritePrep_PedestalPlaque(int k) {  // 8690d6
-  sprite_ignore_projectile[k]++;
-  if (BYTE(overworld_screen_index) == 48)
-    sprite_x_lo[k] += 7;
-}
-
-void SpritePrep_Stalfos(int k) {  // 8690e0
-  sprite_subtype[k] = sprite_x_lo[k] & 16;
-  if (sprite_subtype[k])
-    sprite_oam_flags[k] = 7;
-}
-
-void SpritePrep_KholdstareShell(int k) {  // 8690f0
-  if (Sprite_ReturnIfBossFinished(k))
-    return;
-  sprite_delay_aux1[k] = 192;
-  SpritePrep_MoveDown_8px_Right8px(k);
-}
-
-void SpritePrep_Kholdstare(int k) {  // 8690fa
-  if (Sprite_ReturnIfBossFinished(k))
-    return;
-  sprite_ai_state[k] = 3;
-  SpritePrep_IgnoreProjectiles(k);
-  SpritePrep_MoveDown_8px_Right8px(k);
-}
-
-void SpritePrep_Bumper(int k) {  // 869107
-  sprite_ignore_projectile[k]++;
-  SpritePrep_MoveDown_8px_Right8px(k);
-}
-
-void SpritePrep_MoveDown_8px_Right8px(int k) {  // 86910a
-  sprite_x_lo[k] += 8;
-  sprite_y_lo[k] += 8;
-}
-
-void SpritePrep_HardhatBeetle(int k) {  // 869122
-  static const uint8 kHardHatBeetle_OamFlags[2] = {6, 8};
-  static const uint8 kHardHatBeetle_Health[2] = {32, 6};
-  static const uint8 kHardHatBeetle_A[2] = {16, 12};
-  static const uint8 kHardHatBeetle_State[2] = {1, 3};
-  static const uint8 kHardHatBeetle_Flags5[2] = {2, 6};
-  static const uint8 kHardHatBeetle_BumpDamage[2] = {5, 3};
-  int j = (sprite_x_lo[k] & 0x10) != 0;
-  sprite_oam_flags[k] = kHardHatBeetle_OamFlags[j];
-  sprite_health[k] = kHardHatBeetle_Health[j];
-  sprite_A[k] = kHardHatBeetle_A[j];
-  sprite_ai_state[k] = kHardHatBeetle_State[j];
-  sprite_flags5[k] = kHardHatBeetle_Flags5[j];
-  sprite_bump_damage[k] = kHardHatBeetle_BumpDamage[j];
-}
-
-void SpritePrep_MiniHelmasaur(int k) {  // 869151
-  sprite_A[k] = 16;
-  sprite_ai_state[k] = 1;
-}
-
-void SpritePrep_Fairy(int k) {  // 86915c
-  sprite_A[k] = GetRandomNumber() & 1;
-  sprite_D[k] = sprite_A[k] ^ 1;
-  SpritePrep_Absorbable(k);
-}
-
-void SpritePrep_Absorbable(int k) {  // 86916a
-  if (!player_is_indoors) {
-    sprite_E[k]++;
-    sprite_ignore_projectile[k]++;
-  }
-}
-
-void SpritePrep_OverworldBonkItem(int k) {  // 86916e
-  sprite_E[k]++;
-  sprite_ignore_projectile[k]++;
-}
-
-void SpritePrep_ShieldPickup(int k) {  // 869174
-}
-
-void SpritePrep_NiceBee(int k) {  // 869175
-  uint8 or_bottle = link_bottle_info[0] | link_bottle_info[1] | link_bottle_info[2] | link_bottle_info[3];
-  if (or_bottle & 8)
-    sprite_state[k] = 0;
-  sprite_E[k]++;
-  sprite_ignore_projectile[k]++;
-}
-
-void SpritePrep_Agahnim(int k) {  // 869195
-  static const uint8 kAgahnim_OamFlags[2] = {11, 7};
-  if (Sprite_ReturnIfBossFinished(k))
-    return;
-  sprite_graphics[k] = 0;
-  sprite_D[k] = 3;
-  SpritePrep_MoveDown_8px_Right8px(k);
-  sprite_oam_flags[k] = kAgahnim_OamFlags[is_in_dark_world];
-}
-
-void SpritePrep_DoNothingG(int k) {  // 8691ae
-  // empty
-}
-
-void SpritePrep_FireBar(int k) {  // 8691b4
-  sprite_B[k]++;
-  sprite_ignore_projectile[k]++;
-}
-
-void SpritePrep_Trinexx(int k) {  // 8691ba
-  if (Sprite_ReturnIfBossFinished(k))
-    return;
-  TrinexxComponents_Initialize(k);
-  for (int i = 15; i >= 0; i--)
-    alt_sprite_state[i] = 0;
-}
-
-void SpritePrep_HelmasaurKing(int k) {  // 8691c5
-  if (Sprite_ReturnIfBossFinished(k))
-    return;
-  HelmasaurKing_Initialize(k);
-  memset(alt_sprite_state, 0, 16);
-}
-
-void SpritePrep_Spike(int k) {  // 8691d7
-  sprite_x_vel[k] = 32;
-  sprite_y_vel[k] = -16;
-  Sprite_MoveY(k);
-  sprite_y_vel[k] = 0;
-}
-
-void SpritePrep_RockStal(int k) {  // 8691dc
-  sprite_y_vel[k] = -16;
-  Sprite_MoveY(k);
-  sprite_y_vel[k] = 0;
-}
-
-void SpritePrep_Blob(int k) {  // 8691e8
-  sprite_graphics[k] = 4;
-  SpritePrep_IgnoreProjectiles(k);
-}
-
-void SpritePrep_Arrghus(int k) {  // 8691f1
-  if (Sprite_ReturnIfBossFinished(k))
-    return;
-  sprite_z[k] = 24;
-}
-
-void SpritePrep_Arrghi(int k) {  // 8691fa
-  if (Sprite_ReturnIfBossFinished(k))
-    return;
-  sprite_subtype2[k] = GetRandomNumber();
-  if (k == 13) {
-    overlord_x_lo[2] = 0;
-    overlord_x_lo[3] = 0;
-    Arrghus_HandlePuffs(0);
-  }
-  sprite_x_lo[k] = overlord_x_lo[k + 7];
-  sprite_x_hi[k] = overlord_y_lo[k + 7];
-  sprite_y_lo[k] = overlord_gen1[k + 7];
-  sprite_y_hi[k] = overlord_gen3[k + 7];
-}
-
-void SpritePrep_Mothula(int k) {  // 86922f
-  if (Sprite_ReturnIfBossFinished(k))
-    return;
-  sprite_delay_main[k] = 80;
-  sprite_ignore_projectile[k]++;
-  sprite_graphics[k] = 2;
-  BYTE(dung_floor_move_flags)++;
-  sprite_C[k] = 112;
-}
-
-void SpritePrep_DoNothingH(int k) {  // 86924d
-  // empty
-}
-
-void SpritePrep_BigKey(int k) {  // 86924e
-  sprite_x_lo[k] += 8;
-  sprite_subtype[k] = 0xff;
-  SpritePrep_BigKey_load_graphics(k);
-}
-
-void SpritePrep_BigKey_load_graphics(int k) {  // 869256
-  DecodeAnimatedSpriteTile_variable(0x22);
-  SpritePrep_KeySetItemDrop(k);
-}
-
-void SpritePrep_SmallKey(int k) {  // 869262
-  sprite_subtype[k] = 255;
-  sprite_die_action[k] = byte_7E0B9B++;
-}
-
-void SpritePrep_KeySetItemDrop(int k) {  // 869267
-  sprite_die_action[k] = byte_7E0B9B;
-  byte_7E0B9B++;
-}
-
-void SpriteActive_Main(int k) {  // 869271
-  uint8 type = sprite_type[k];
-  kSpriteActiveRoutines[type](k);
-}
-
-void Sprite_09_GiantMoldorm(int k) {  // 869469
-  static const int8 kGiantMoldorm_Xvel[32] = {
-    24, 22, 17,  9, 0,  -9, -17, -22, -24, -22, -17,  -9, 0,  9, 17, 22,
-    36, 33, 25, 13, 0, -13, -25, -33, -36, -33, -25, -13, 0, 13, 25, 33,
-  };
-  static const int8 kGiantMoldorm_Yvel[32] = {
-    0,  9, 17, 22, 24, 22, 17,  9, 0,  -9, -17, -22, -24, -22, -17,  -9,
-    0, 13, 25, 33, 36, 33, 25, 13, 0, -13, -25, -33, -36, -33, -25, -13,
-  };
-  static const uint8 kGiantMoldorm_NextDir[16] = {8, 9, 10, 11, 12, 13, 14, 15, 0, 1, 2, 3, 4, 5, 6, 7};
-  GiantMoldorm_Draw(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  if (sprite_ai_state[k] == 3) {
-    // await death
-    if (!sprite_delay_aux4[k]) {
-      sprite_state[k] = 4;
-      sprite_A[k] = 0;
-      sprite_delay_main[k] = 224;
-    } else {
-      sprite_hit_timer[k] = sprite_delay_aux4[k] | 224;
-    }
-    return;
-  }
-
-  Sprite_CheckDamageFromLink(k);
-  bool low_health = (sprite_health[k] < 3);
-  sprite_subtype2[k] += low_health ? 2 : 1;
-  if (!(frame_counter & (low_health ? 3 : 7)))
-    SpriteSfx_QueueSfx3WithPan(k, 0x31);
-
-  if (sprite_F[k]) {
-    sprite_delay_aux2[k] = 64;
-    if (!(frame_counter & 3))
-      sprite_F[k]--;
-    return;
-  }
-
-  if (!link_incapacitated_timer && Sprite_CheckDamageToLink(k)) {
-    Link_CancelDash();
-    ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLink(k, 0x28);
-    link_actual_vel_y = pt.y;
-    link_actual_vel_x = pt.x;
-    link_incapacitated_timer = 24;
-    sprite_delay_aux1[k] = 48;
-    // For some reason they forgot to or in the sfx.
-    sound_effect_2 = Sprite_CalculateSfxPan(k) | (enhanced_features0 & kFeatures0_MiscBugFixes ? 0x32 : 0);
-  }
-
-  int j = sprite_D[k] + low_health * 16;
-  sprite_x_vel[k] = kGiantMoldorm_Xvel[j];
-  sprite_y_vel[k] = kGiantMoldorm_Yvel[j];
-  Sprite_MoveXY(k);
-  if (Sprite_CheckTileCollision(k)) {
-    sprite_D[k] = kGiantMoldorm_NextDir[sprite_D[k]];
-    SpriteSfx_QueueSfx2WithPan(k, 0x21);
-  }
-  switch(sprite_ai_state[k]) {
-  case 0:  // straight path
-    if (!sprite_delay_main[k]) {
-      j = 1;
-      if (++sprite_G[k] == 3)
-        sprite_G[k] = 0, j = 2;
-      sprite_ai_state[k] = j;
-      sprite_head_dir[k] = (GetRandomNumber() & 2) - 1;
-      sprite_delay_main[k] = (GetRandomNumber() & 31) + 32;
-    }
-    break;
-  case 1:  // spinning meander
-    if (!sprite_delay_main[k]) {
-      sprite_delay_main[k] = (GetRandomNumber() & 15) + 8;
-      sprite_ai_state[k] = 0;
-    } else if (!(sprite_delay_main[k] & 3)) {
-      sprite_D[k] = (sprite_D[k] + sprite_head_dir[k]) & 0xf;
-    }
-    break;
-  case 2:  // lunge at player
-    if (!((k ^ frame_counter) & 3)) {
-      Sprite_ApplySpeedTowardsLink(k, 0x1f);
-      uint8 dir = Sprite_ConvertVelocityToAngle(sprite_x_vel[k], sprite_y_vel[k]) - sprite_D[k];
-      if (dir == 0) {
-        sprite_ai_state[k] = 0;
-        sprite_delay_main[k] = 48;
-      } else {
-        sprite_D[k] += sign8(dir) ? -1 : 1;
-      }
-    }
-    break;
-  }
-}
-
-void Sprite_01_Vulture_bounce(int k) {  // 869473
-  static const uint8 kVulture_Gfx[4] = {1, 2, 3, 2};
-  sprite_obj_prio[k] |= 0x30;
-  Vulture_Draw(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  if (Sprite_ReturnIfRecoiling(k))
-    return;
-  Sprite_CheckDamageToAndFromLink(k);
-  Sprite_MoveXY(k);
-  switch (sprite_ai_state[k]) {
-  case 0:  // dormant
-    if (++sprite_subtype2[k] == 160) {
-      sprite_ai_state[k] = 1;
-      SpriteSfx_QueueSfx3WithPan(k, 0x1e);
-      sprite_delay_main[k] = 16;
-    }
-    break;
-  case 1: { // circling
-    sprite_graphics[k] = kVulture_Gfx[frame_counter >> 1 & 3];
-    if (sprite_delay_main[k]) {
-      sprite_z[k]++;
-      return;
-    }
-    if ((k ^ frame_counter) & 1)
-      return;
-    ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLink(k, (k & 0xf) + 24);
-    sprite_x_vel[k] = -pt.y;
-    sprite_y_vel[k] = pt.x;
-    if ((uint8)(pt.xdiff + 0x28) < 0x50 && (uint8)(pt.ydiff + 0x28) < 0x50)
-      return;
-    sprite_y_vel[k] += (int8)pt.y >> 2;
-    sprite_x_vel[k] += (int8)pt.x >> 2;
-    break;
-  }
-  }
-}
-
-void Sprite_27_Deadrock(int k) {  // 86948a
-  static const uint8 kDeadRock_Gfx[9] = {0, 1, 0, 1, 2, 2, 3, 3, 4};
-  static const uint8 kDeadRock_OamFlags[9] = {0x40, 0x40, 0, 0, 0, 0x40, 0, 0x40, 0};
-  static const int8 kDeadRock_Xvel[4] = {32, -32, 0, 0};
-  static const int8 kDeadRock_Yvel[4] = {0, 0, 32, -32};
-  int j = (sprite_delay_aux2[k] ? (sprite_delay_aux2[k] & 4) : (sprite_ai_state[k] != 2)) ? sprite_A[k] : 8;
-  sprite_graphics[k] = kDeadRock_Gfx[j];
-  sprite_oam_flags[k] = sprite_oam_flags[k] & ~0x40 | kDeadRock_OamFlags[j];
-  SpriteDraw_SingleLarge(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  if (!sprite_F[k] && (Sprite_CheckDamageFromLink(k) & kCheckDamageFromPlayer_Carry) && !sound_effect_1)
-    SpriteSfx_QueueSfx2WithPan(k, 0xb);
-  if (Sprite_CheckDamageToLink_same_layer(k)) {
-    Sprite_NullifyHookshotDrag();
-    Sprite_RepelDash();
-  }
-  if (sprite_F[k] == 14) {
-    sprite_ai_state[k] = 2;
-    sprite_delay_aux1[k] = 255;
-    sprite_delay_aux2[k] = 64;
-  }
-  if (Sprite_ReturnIfRecoiling(k))
-    return;
-  switch(sprite_ai_state[k]) {
-  case 0:  // pick dir
-    if (!sprite_delay_main[k]) {
-      sprite_flags2[k] &= ~0x80;
-      sprite_defl_bits[k] &= ~4;
-      sprite_flags3[k] &= ~0x40;
-      sprite_ai_state[k]++;
-      sprite_delay_main[k] = (GetRandomNumber() & 31) + 32;
-      if (++sprite_B[k] == 4) {
-        sprite_B[k] = 0;
-        j = Sprite_DirectionToFaceLink(k, NULL);
-      } else {
-        j = GetRandomNumber() & 3;
-      }
-set_dir:
-      sprite_D[k] = j;
-      sprite_x_vel[k] = kDeadRock_Xvel[j];
-      sprite_y_vel[k] = kDeadRock_Yvel[j];
-    }
-    break;
-  case 1:  // walk
-    if (!sprite_delay_main[k]) {
-      sprite_ai_state[k] = 0;
-      sprite_delay_main[k] = 32;
-    } else {
-      Sprite_MoveXY(k);
-      if (Sprite_CheckTileCollision(k)) {
-        j = sprite_D[k] ^ 1;
-        goto set_dir;
-      }
-      sprite_A[k] = sprite_D[k] << 1 | ++sprite_subtype2[k] >> 2 & 1;
-    }
-    break;
-  case 2:  // petrified
-    sprite_flags2[k] |= 0x80;
-    sprite_defl_bits[k] |= 4;
-    sprite_flags3[k] |= 0x40;
-    if (!(frame_counter & 1)) {
-      if (sprite_delay_aux1[k] == 0) {
-        sprite_ai_state[k] = 0;
-        sprite_delay_main[k] = 16;
-      } else if (sprite_delay_aux1[k] == 0x20) {
-        sprite_delay_aux2[k] = 0x40;
-      }
-    } else {
-      sprite_delay_aux1[k]++;
-    }
-    break;
-  }
-}
-
-void Sprite_20_Sluggula(int k) {  // 8695d9
-  static const uint8 kSluggula_Gfx[8] = {0, 1, 0, 1, 2, 3, 4, 5};
-  static const uint8 kSluggula_OamFlags[8] = {0x40, 0x40, 0, 0, 0, 0, 0, 0};
-  static const int8 kSluggula_XYvel[6] = {16, -16, 0, 0, 16, -16};
-  int j = sprite_D[k] << 1 | (sprite_subtype2[k] & 8) >> 3;
-  sprite_graphics[k] = kSluggula_Gfx[j];
-  sprite_oam_flags[k] = sprite_oam_flags[k] & 191 | kSluggula_OamFlags[j];
-  SpriteDraw_SingleLarge(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  if (Sprite_ReturnIfRecoiling(k))
-    return;
-  Sprite_CheckDamageToAndFromLink(k);
-  sprite_subtype2[k]++;
-  switch(sprite_ai_state[k]) {
-  case 0:  // normal
-    if (!sprite_delay_main[k]) {
-      sprite_ai_state[k] = 1;
-      sprite_delay_main[k] = (GetRandomNumber() & 31) + 32;
-      sprite_D[k] = j = sprite_delay_main[k] & 3;
-set_vel:
-      sprite_x_vel[k] = kSluggula_XYvel[j];
-      sprite_y_vel[k] = kSluggula_XYvel[j + 2];
-    } else if (sprite_delay_main[k] == 16 && !(GetRandomNumber() & 1)) {
-      Sluggula_DropBomb(k);
-    }
-    break;
-  case 1:  // break from bombing
-    if (!sprite_delay_main[k]) {
-      sprite_ai_state[k] = 0;
-      sprite_delay_main[k] = 32;
-    }
-    Sprite_MoveXY(k);
-    if (!Sprite_CheckTileCollision(k))
-      return;
-    j = (sprite_D[k] ^= 1);
-    goto set_vel;
-  }
-}
-
-void Sluggula_DropBomb(int k) {  // 869673
-  SpriteSpawnInfo info;
-  int j = Sprite_SpawnDynamicallyEx(k, 0x4a, &info, 11);
-  if (j >= 0) {
-    Sprite_SetSpawnedCoordinates(j, &info);
-    Sprite_TransmuteToBomb(j);
-  }
-}
-
-void Sprite_19_Poe(int k) {  // 869688
-  static const int8 kPoe_Accel[4] = {1, -1, 2, -2};
-  static const int8 kPoe_ZvelTarget[2] = {8, -8};
-  static const int8 kPoe_XvelTarget[4] = {16, -16, 28, -28};
-  static const uint8 kPoe_OamFlags[2] = {0x40, 0};
-  static const int8 kPoe_Yvel[2] = {8, -8};
-  int j;
-  sprite_D[k] = j = sprite_x_vel[k] >> 7;
-  sprite_oam_flags[k] = sprite_oam_flags[k] & ~0x40 | kPoe_OamFlags[j];
-  if (!sprite_E[k])
-    sprite_obj_prio[k] |= 0x30;
-  Poe_Draw(k);
-  oam_cur_ptr += 4;
-  oam_ext_cur_ptr++;
-  sprite_flags2[k]--;
-  SpriteDraw_SingleLarge(k);
-  sprite_flags2[k]++;
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  if (Sprite_ReturnIfRecoiling(k))
-    return;
-  if (sprite_E[k]) {
-    if (++sprite_z[k] == 12)
-      sprite_E[k] = 0;
-    return;
-  }
-  Sprite_CheckDamageToAndFromLink(k);
-  sprite_subtype2[k]++;
-  Sprite_MoveXY(k);
-  if (!(frame_counter & 1)) {
-    j = sprite_G[k] & 1;
-    sprite_z_vel[k] += kPoe_Accel[j];
-    if (sprite_z_vel[k] == (uint8)kPoe_ZvelTarget[j])
-      sprite_G[k]++;
-  }
-  Sprite_MoveZ(k);
-  sprite_y_vel[k] = 0;
-  switch(sprite_ai_state[k]) {
-  case 0:  // select vertical dir
-    if (!sprite_delay_main[k]) {
-      sprite_ai_state[k] = 1;
-      if (!(GetRandomNumber() & 12))
-        sprite_head_dir[k] = Sprite_IsBelowLink(k).a;
-      else
-        sprite_head_dir[k] = GetRandomNumber() & 1;
-    }
-    break;
-  case 1:  // roaming
-    if (!(frame_counter & 1)) {
-      int j = (sprite_anim_clock[k] & 1) + is_in_dark_world * 2;
-      sprite_x_vel[k] += kPoe_Accel[j];
-      if (sprite_x_vel[k] == (uint8)kPoe_XvelTarget[j]) {
-        sprite_anim_clock[k]++;
-        sprite_ai_state[k] = 0;
-        sprite_delay_main[k] = (GetRandomNumber() & 31) + 16;
-      }
-    }
-    sprite_y_vel[k] = kPoe_Yvel[sprite_head_dir[k]];
-    break;
-  }
-}
-
-void Poe_Draw(int k) {  // 869786
-  static const int8 kPoe_Draw_X[2] = {9, -1};
-  static const uint8 kPoe_Draw_Char[4] = {0x7c, 0x80, 0xb7, 0x80};
-  PrepOamCoordsRet info;
-  if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
-    return;
-  OamEnt *oam = GetOamCurPtr();
-  SetOamHelper0(oam, info.x + kPoe_Draw_X[sprite_D[k]], info.y + 9,
-                kPoe_Draw_Char[sprite_subtype2[k] >> 3 & 3], info.flags & 0xf0 | 2, 0);
-}
-
-void Sprite_18_MiniMoldorm(int k) {  // 869808
-  static const int8 kMoldorm_Xvel[16] = {24, 22, 17, 9, 0, -9, -17, -22, -24, -22, -17, -9, 0, 9, 17, 22};
-  static const int8 kMoldorm_Yvel[16] = {0, 9, 17, 22, 24, 22, 17, 9, 0, -9, -17, -22, -24, -22, -17, -9};
-  static const uint8 kMoldorm_NextDir[16] = {8, 9, 10, 11, 12, 13, 14, 15, 0, 1, 2, 3, 4, 5, 6, 7};
-
-  Moldorm_Draw(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  if (sprite_F[k])
-    SpritePrep_MiniMoldorm_bounce(k);
-  if (Sprite_ReturnIfRecoiling(k))
-    return;
-  Sprite_CheckDamageToAndFromLink(k);
-  sprite_subtype2[k]++;
-  int j = sprite_D[k];
-  sprite_x_vel[k] = kMoldorm_Xvel[j];
-  sprite_y_vel[k] = kMoldorm_Yvel[j];
-  Sprite_MoveXY(k);
-  if (Sprite_CheckTileCollision(k)) {
-    if (GetRandomNumber() & 1)
-      sprite_head_dir[k] = -sprite_head_dir[k];
-    sprite_D[k] = kMoldorm_NextDir[sprite_D[k]];
-  }
-  switch (sprite_ai_state[k]) {
-  case 0:  // configure
-    if (!sprite_delay_main[k]) {
-      if (++sprite_G[k] == 6)
-        sprite_G[k] = 0, sprite_ai_state[k] = 2;
-      else
-        sprite_ai_state[k] = 1;
-      sprite_head_dir[k] = (GetRandomNumber() & 2) - 1;
-      sprite_delay_main[k] = (GetRandomNumber() & 0x1f) + 0x20;
-    }
-    break;
-  case 1:  // meander
-    if (!sprite_delay_main[k]) {
-      sprite_delay_main[k] = (GetRandomNumber() & 15) + 8;
-      sprite_ai_state[k] = 0;
-    } else if ((sprite_delay_main[k] & 3) == 0) {
-      sprite_D[k] = (sprite_D[k] + sprite_head_dir[k]) & 0xf;
-    }
-    break;
-  case 2:  // seek player
-    if (!((k ^ frame_counter) & 3)) {
-      Sprite_ApplySpeedTowardsLink(k, 31);
-      uint8 d = Sprite_ConvertVelocityToAngle(sprite_x_vel[k], sprite_y_vel[k]) - sprite_D[k];
-      if (d == 0) {
-        sprite_ai_state[k] = 0;
-        sprite_delay_main[k] = 48;
-      } else {
-        sprite_D[k] = (sprite_D[k] + (sign8(d) ? -1 : 1)) & 0xf;
-      }
-    }
-    break;
-  }
-}
-
-void Sprite_12_Moblin(int k) {  // 8698e4
-  static const int8 kMoblin_Xvel[4] = {16, -16, 0, 0};
-  static const int8 kMoblin_Yvel[4] = {0, 0, 16, -16};
-  static const uint8 kMoblin_Delay[4] = {0x10, 0x20, 0x30, 0x40};
-  static const uint8 kMoblin_Gfx2[8] = {11, 10, 8, 9, 7, 5, 0, 2};
-  static const uint8 kMoblin_Dirs[8] = {2, 3, 2, 3, 0, 1, 0, 1};
-  static const uint8 kMoblin_Gfx[4] = {6, 4, 0, 2};
-  int j;
-  Moblin_Draw(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  if (Sprite_ReturnIfRecoiling(k))
-    return;
-  Sprite_CheckDamageToAndFromLink(k);
-  Sprite_MoveXY(k);
-  Sprite_CheckTileCollision2(k);
-  switch(sprite_ai_state[k]) {
-  case 0:  // select dir
-    if (!sprite_delay_main[k]) {
-      sprite_delay_main[k] = kMoblin_Delay[GetRandomNumber() & 3];
-      sprite_ai_state[k]++;
-      sprite_D[k] = sprite_head_dir[k];
-      j = sprite_head_dir[k];
-      sprite_x_vel[k] = kMoblin_Xvel[j];
-      sprite_y_vel[k] = kMoblin_Yvel[j];
-    }
-    break;
-  case 1:  // walk
-    sprite_graphics[k] = (sprite_subtype2[k] & 1) + kMoblin_Gfx[sprite_D[k]];
-    if (!sprite_wallcoll[k]) {
-      if (sprite_delay_main[k]) {
-        if (sign8(--sprite_E[k])) {
-          sprite_E[k] = 11;
-          sprite_subtype2[k]++;
-        }
-        return;
-      }
-      if (sprite_D[k] == Sprite_DirectionToFaceLink(k, NULL)) {
-        sprite_ai_state[k]++;
-        sprite_delay_main[k] = 32;
-        Sprite_ZeroVelocity_XY(k);
-        sprite_z_vel[k] = 0;
-        return;
-      }
-      sprite_delay_main[k] = 0x10;
-    } else {
-      sprite_delay_main[k] = 0xc;
-    }
-    sprite_head_dir[k] = kMoblin_Dirs[sprite_D[k] << 1 | GetRandomNumber() & 1];
-    sprite_ai_state[k] = 0;
-    if (++sprite_C[k] == 4) {
-      sprite_C[k] = 0;
-      sprite_head_dir[k] = Sprite_DirectionToFaceLink(k, NULL);
-    }
-    Sprite_ZeroVelocity_XY(k);
-    sprite_z_vel[k] = 0;
-    break;
-  case 2:  // throw spear
-    j = sprite_D[k];
-    if (!sprite_delay_main[k])
-      sprite_ai_state[k] = 0;
-    if (sprite_delay_main[k] < 16) {
-      if (sprite_delay_main[k] == 15) {
-        Moblin_MaterializeSpear(k);
-        sprite_delay_aux1[k] = 32;
-      }
-      j += 4;
-    }
-    sprite_graphics[k] = kMoblin_Gfx2[j];
-    break;
-  }
-}
-
-void Moblin_MaterializeSpear(int k) {  // 8699eb
-  static const int8 kMoblinSpear_X[4] = {11, -2, -3, 11};
-  static const int8 kMoblinSpear_Y[4] = {-3, -3, 3, -11};
-  static const int8 kMoblinSpear_Xvel[4] = {32, -32, 0, 0};
-  static const int8 kMoblinSpear_Yvel[4] = {0, 0, 32, -32};
-  SpriteSpawnInfo info;
-  int j = Sprite_SpawnDynamically(k, 0x1b, &info), i;
-  if (j >= 0) {
-    sprite_A[j] = 3;
-    sprite_D[j] = i = sprite_D[k];
-    Sprite_SetX(j, info.r0_x + kMoblinSpear_X[i]);
-    Sprite_SetY(j, info.r2_y + kMoblinSpear_Y[i]);
-    sprite_x_vel[j] = kMoblinSpear_Xvel[i];
-    sprite_y_vel[j] = kMoblinSpear_Yvel[i];
-  }
-}
-
-void Moblin_Draw(int k) {  // 869bc4
-  static const DrawMultipleData kMoblin_Dmd[48] = {
-    {-2,   3, 0x8091, 0},
-    {-2,  11, 0x8090, 0},
-    { 0, -10, 0x0086, 2},
-    { 0,   0, 0x008a, 2},
-    {-2,   7, 0x8091, 0},
-    {-2,  15, 0x8090, 0},
-    { 0, -10, 0x0086, 2},
-    { 0,   0, 0x408a, 2},
-    { 0,  -9, 0x0084, 2},
-    { 0,   0, 0x00a0, 2},
-    {11,  -5, 0x0090, 0},
-    {11,   3, 0x0091, 0},
-    { 0,  -9, 0x0084, 2},
-    { 0,   0, 0x40a0, 2},
-    {11,  -8, 0x0090, 0},
-    {11,   0, 0x0091, 0},
-    {-4,   8, 0x0080, 0},
-    { 4,   8, 0x0081, 0},
-    { 0,  -9, 0x0088, 2},
-    { 0,   0, 0x00a6, 2},
-    {-9,   6, 0x0080, 0},
-    {-1,   6, 0x0081, 0},
-    { 0,  -8, 0x0088, 2},
-    { 0,   0, 0x00a4, 2},
-    {12,   8, 0x4080, 0},
-    { 4,   8, 0x4081, 0},
-    { 0,  -9, 0x4088, 2},
-    { 0,   0, 0x40a6, 2},
-    {17,   6, 0x4080, 0},
-    { 9,   6, 0x4081, 0},
-    { 0,  -8, 0x4088, 2},
-    { 0,   0, 0x40a4, 2},
-    {-3,  -5, 0x8091, 0},
-    {-3,   3, 0x8090, 0},
-    { 0, -10, 0x0086, 2},
-    { 0,   0, 0x00a8, 2},
-    {11, -11, 0x0090, 0},
-    {11,  -3, 0x0091, 0},
-    { 0,  -9, 0x0084, 2},
-    { 0,   0, 0x4082, 2},
-    {-2,  -3, 0x0080, 0},
-    { 6,  -3, 0x0081, 0},
-    { 0,  -9, 0x0088, 2},
-    { 0,   0, 0x00a2, 2},
-    {10,  -3, 0x4080, 0},
-    { 2,  -3, 0x4081, 0},
-    { 0,  -9, 0x4088, 2},
-    { 0,   0, 0x40a2, 2},
-  };
-  static const uint8 kMoblin_ObjOffs[12] = {2, 2, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2};
-  static const uint8 kMoblin_HeadChar[4] = {0x88, 0x88, 0x86, 0x84};
-  static const uint8 kMoblin_HeadFlags[4] = {0x40, 0, 0, 0};
-  PrepOamCoordsRet info;
-  Sprite_DrawMultiple(k, &kMoblin_Dmd[sprite_graphics[k] * 4], 4, &info);
-  if (sprite_pause[k])
-    return;
-  OamEnt *oam = GetOamCurPtr();
-  if (sprite_delay_aux1[k]) {
-    for (int i = 0; i < 4; i++, oam++) {
-      if (!(bytewise_extended_oam[oam - oam_buf] & 2))
-        oam->y = 0xf0;
-    }
-  }
-  oam = GetOamCurPtr() + kMoblin_ObjOffs[sprite_graphics[k]];
-  int j = sprite_head_dir[k];
-  oam->charnum = kMoblin_HeadChar[j];
-  oam->flags = oam->flags &~0x40 | kMoblin_HeadFlags[j];
-  SpriteDraw_Shadow(k, &info);
-}
-
-void Sprite_0E_Snapdragon(int k) {  // 869c24
-  static const uint8 kSnapDragon_Delay[4] = {0x20, 0x30, 0x40, 0x50};
-  static const uint8 kSnapDragon_Gfx[4] = {4, 0, 6, 2};
-  static const int8 kSnapDragon_Xvel[8] = {8, -8, 8, -8, 16, -16, 16, -16};
-  static const int8 kSnapDragon_Yvel[8] = {8, 8, -8, -8, 16, 16, -16, -16};
-  int j;
-  sprite_graphics[k] = sprite_B[k] + kSnapDragon_Gfx[sprite_D[k]];
-  SnapDragon_Draw(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  if (Sprite_ReturnIfRecoiling(k))
-    return;
-  Sprite_CheckDamageToAndFromLink(k);
-  sprite_B[k] = 0;
-  switch(sprite_ai_state[k]) {
-  case 0:  // resting
-    if (!sprite_delay_main[k]) {
-      sprite_ai_state[k]++;
-      sprite_delay_main[k] = kSnapDragon_Delay[(GetRandomNumber() & 12) >> 2];
-      if (sign8(--sprite_A[k])) {
-        sprite_A[k] = 3;
-        sprite_delay_main[k] = 96;
-        sprite_C[k]++;
-        sprite_D[k] = Sprite_IsBelowLink(k).a * 2 + Sprite_IsRightOfLink(k).a;
-      } else {
-        sprite_D[k] = GetRandomNumber() & 3;
-      }
-    } else if (sprite_delay_main[k] & 0x18) {
-      sprite_B[k]++;
-    }
-    break;
-  case 1:  // attack
-    sprite_B[k]++;
-    Sprite_MoveXY(k);
-    if (Sprite_CheckTileCollision(k))
-      sprite_D[k] ^= 3;
-    j = sprite_D[k] + (sprite_C[k] ? 4 : 0);
-    sprite_x_vel[k] = kSnapDragon_Xvel[j];
-    sprite_y_vel[k] = kSnapDragon_Yvel[j];
-    Sprite_MoveZ(k);
-    sprite_z_vel[k] -= 4;
-    if (sign8(sprite_z[k])) {
-      sprite_z[k] = 0;
-      if (!sprite_delay_main[k]) {
-        sprite_ai_state[k] = 0;
-        sprite_C[k] = 0;
-        sprite_delay_main[k] = 63;
-      } else {
-        sprite_z_vel[k] = 20;
-      }
-    }
-    break;
-  }
-}
-
-void SnapDragon_Draw(int k) {  // 869e02
-  static const DrawMultipleData kSnapDragon_Dmd[32] = {
-    { 4, -8, 0x008f, 0},
-    {12, -8, 0x009f, 0},
-    {-4,  0, 0x008c, 2},
-    { 4,  0, 0x008d, 2},
-    { 4, -8, 0x002b, 0},
-    {12, -8, 0x003b, 0},
-    {-4,  0, 0x0028, 2},
-    { 4,  0, 0x0029, 2},
-    {-4, -8, 0x003c, 0},
-    { 4, -8, 0x003d, 0},
-    {-4,  0, 0x00aa, 2},
-    { 4,  0, 0x00ab, 2},
-    {-4, -8, 0x003e, 0},
-    { 4, -8, 0x003f, 0},
-    {-4,  0, 0x00ad, 2},
-    { 4,  0, 0x00ae, 2},
-    {-4, -8, 0x409f, 0},
-    { 4, -8, 0x408f, 0},
-    {-4,  0, 0x408d, 2},
-    { 4,  0, 0x408c, 2},
-    {-4, -8, 0x403b, 0},
-    { 4, -8, 0x402b, 0},
-    {-4,  0, 0x4029, 2},
-    { 4,  0, 0x4028, 2},
-    { 4, -8, 0x403d, 0},
-    {12, -8, 0x403c, 0},
-    {-4,  0, 0x40ab, 2},
-    { 4,  0, 0x40aa, 2},
-    { 4, -8, 0x403f, 0},
-    {12, -8, 0x403e, 0},
-    {-4,  0, 0x40ae, 2},
-    { 4,  0, 0x40ad, 2},
-  };
-  PrepOamCoordsRet info;
-  Sprite_DrawMultiple(k, &kSnapDragon_Dmd[sprite_graphics[k] * 4], 4, &info);
-  SpriteDraw_Shadow(k, &info);
-}
-
-void Sprite_22_Ropa(int k) {  // 869e1f
-  Ropa_Draw(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  if (Sprite_ReturnIfRecoiling(k))
-    return;
-  Sprite_CheckDamageToAndFromLink(k);
-  sprite_subtype2[k]++;
-  sprite_graphics[k] = sprite_subtype2[k] >> 3 & 3;
-  switch(sprite_ai_state[k]) {
-  case 0:  // stationary
-    if (!sprite_delay_main[k]) {
-      Sprite_ApplySpeedTowardsLink(k, 16);
-      sprite_z_vel[k] = (GetRandomNumber() & 15) + 20;
-      sprite_ai_state[k]++;
-    }
-    break;
-  case 1:  // pounce
-    Sprite_MoveXY(k);
-    if (Sprite_CheckTileCollision(k))
-      Sprite_ZeroVelocity_XY(k);
-    Sprite_MoveZ(k);
-    sprite_z_vel[k] -= 2;
-    if (sign8(sprite_z[k])) {
-      sprite_z[k] = 0;
-      sprite_delay_main[k] = 48;
-      sprite_ai_state[k] = 0;
-    }
-    break;
-  }
-}
-
-void Ropa_Draw(int k) {  // 869ee5
-  static const DrawMultipleData kRopa_Dmd[12] = {
-    {0, -8, 0x0026, 0},
-    {8, -8, 0x0027, 0},
-    {0,  0, 0x0008, 2},
-    {0, -8, 0x0036, 0},
-    {8, -8, 0x0037, 0},
-    {0,  0, 0x000a, 2},
-    {0, -8, 0x4027, 0},
-    {8, -8, 0x4026, 0},
-    {0,  0, 0x4008, 2},
-    {0, -8, 0x4037, 0},
-    {8, -8, 0x4036, 0},
-    {0,  0, 0x4008, 2},
-  };
-  PrepOamCoordsRet info;
-  Sprite_DrawMultiple(k, &kRopa_Dmd[sprite_graphics[k] * 3], 3, &info);
-  SpriteDraw_Shadow(k, &info);
-
-}
-
-void Sprite_11_Hinox(int k) {  // 869f05
-  Hinox_Draw(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  if (sprite_F[k]) {
-    Hinox_FaceLink(k);
-    sprite_ai_state[k] = 2;
-    sprite_delay_main[k] = 48;
-  }
-  if (Sprite_ReturnIfRecoiling(k))
-    return;
-  Sprite_CheckDamageToAndFromLink(k);
-  switch(sprite_ai_state[k]) {
-  case 0:  // select dir
-    if (!sprite_delay_main[k]) {
-      if (!(GetRandomNumber() & 3)) {
-        sprite_ai_state[k] = 2;
-        sprite_delay_main[k] = 64;
-      } else {
-        if (++sprite_C[k] == 4) {
-          sprite_C[k] = 0;
-          Hinox_FaceLink(k);
-        } else {
-          static const uint8 kHinox_RandomDirs[8] = {2, 3, 3, 2, 0, 1, 1, 0};
-          Hinox_SetDirection(k, kHinox_RandomDirs[sprite_D[k] * 2 + (GetRandomNumber() & 1)]);
-        }
-      }
-    }
-    break;
-  case 1:  // walk
-    if (sprite_delay_main[k]) {
-      if (sign8(--sprite_A[k])) {
-        sprite_A[k] = 11;
-        sprite_subtype2[k]++;
-      }
-      Sprite_MoveXY(k);
-      if (!Sprite_CheckTileCollision(k)) {
-        static const uint8 kHinox_WalkGfx[4] = {6, 4, 0, 2};
-        sprite_graphics[k] = kHinox_WalkGfx[sprite_D[k]] + (sprite_subtype2[k] & 1);
-        return;
-      }
-    }
-    sprite_delay_main[k] = 16;
-    sprite_ai_state[k] = 0;
-    break;
-  case 2:  // throw bomb
-    if (!sprite_delay_main[k]) {
-      sprite_ai_state[k] = 0;
-      sprite_delay_main[k] = 2;
-      return;
-    }
-    if (sprite_delay_main[k] == 32) {
-      static const int8 kHinox_BombX[4] = {8, -8, -13, 13};
-      static const int8 kHinox_BombY[4] = {-11, -11, -16, -16};
-      static const int8 kHinox_BombXvel[4] = {24, -24, 0, 0};
-      static const int8 kHinox_BombYvel[4] = {0, 0, 24, -24};
-      SpriteSpawnInfo info;
-      int j = Sprite_SpawnDynamically(k, 0x4a, &info);
-      if (j >= 0) {
-        Sprite_TransmuteToBomb(j);
-        sprite_delay_aux1[j] = 64;
-        int i = sprite_D[k];
-        Sprite_SetX(j, info.r0_x + kHinox_BombX[i]);
-        Sprite_SetY(j, info.r2_y + kHinox_BombY[i]);
-        sprite_x_vel[j] = kHinox_BombXvel[i];
-        sprite_y_vel[j] = kHinox_BombYvel[i];
-        sprite_z_vel[j] = 40;
-      }
-    } else {
-      static const uint8 kHinox_Gfx[8] = {11, 10, 8, 9, 7, 5, 1, 3};
-      sprite_graphics[k] = kHinox_Gfx[sprite_D[k] + (sprite_delay_main[k] < 32 ? 4 : 0)];
-    }
-    break;
-  }
-
-}
-
-void Hinox_ThrowBomb(int k) {  // 869f4a
-
-}
-
-void Hinox_FaceLink(int k) {  // 869fe1
-  Hinox_SetDirection(k, Sprite_DirectionToFaceLink(k, NULL));
-  sprite_x_vel[k] <<= 1;
-  sprite_y_vel[k] <<= 1;
-}
-
-void Hinox_SetDirection(int k, uint8 dir) {  // 86a004
-  static const int8 kHinox_Xvel[4] = {8, -8, 0, 0};
-  static const int8 kHinox_Yvel[4] = {0, 0, 8, -8};
-  sprite_D[k] = dir;
-  sprite_delay_main[k] = (GetRandomNumber() & 63) + 96;
-  sprite_ai_state[k]++;
-  sprite_x_vel[k] = kHinox_Xvel[dir];
-  sprite_y_vel[k] = kHinox_Yvel[dir];
-}
-
-void Hinox_Draw(int k) {  // 86a1f9
-  static const DrawMultipleData kHinox_Dmd[46] = {
-    {  0, -13, 0x0600, 2},
-    { -8,  -5, 0x0624, 2},
-    {  8,  -5, 0x4624, 2},
-    {  0,   1, 0x0606, 2},
-    {  0, -13, 0x0600, 2},
-    { -8,  -5, 0x0624, 2},
-    {  8,  -5, 0x4624, 2},
-    {  0,   1, 0x4606, 2},
-    { -8,  -6, 0x0624, 2},
-    {  8,  -6, 0x4624, 2},
-    {  0,   0, 0x0606, 2},
-    {  0, -13, 0x0604, 2},
-    { -8,  -6, 0x0624, 2},
-    {  8,  -6, 0x4624, 2},
-    {  0,   0, 0x4606, 2},
-    {  0, -13, 0x0604, 2},
-    { -3, -13, 0x0602, 2},
-    {  0,  -8, 0x060c, 2},
-    {  0,   0, 0x061c, 2},
-    { -3, -12, 0x0602, 2},
-    {  0,  -8, 0x060e, 2},
-    {  0,   0, 0x061e, 2},
-    {  3, -13, 0x4602, 2},
-    {  0,  -8, 0x460c, 2},
-    {  0,   0, 0x461c, 2},
-    {  3, -12, 0x4602, 2},
-    {  0,  -8, 0x460e, 2},
-    {  0,   0, 0x461e, 2},
-    {-13, -16, 0x056e, 2},
-    {  0, -13, 0x0600, 2},
-    { -8,  -5, 0x0620, 2},
-    {  8,  -5, 0x4624, 2},
-    {  0,   1, 0x0606, 2},
-    { -8,  -5, 0x0624, 2},
-    {  8,  -5, 0x4620, 2},
-    {  0,   1, 0x0606, 2},
-    {  0, -13, 0x0604, 2},
-    { 13, -16, 0x056e, 2},
-    { -8, -11, 0x056e, 2},
-    { -3, -13, 0x0602, 2},
-    {  0,   0, 0x0622, 2},
-    {  0,  -8, 0x060c, 2},
-    {  8, -11, 0x056e, 2},
-    {  3, -13, 0x4602, 2},
-    {  0,   0, 0x4622, 2},
-    {  0,  -8, 0x460c, 2},
-  };
-  PrepOamCoordsRet info;
-  static const uint8 kHinoxNum[12] = { 4, 4, 4, 4, 3, 3, 3, 3, 5, 5, 4, 4 };
-  static const uint8 kHinoxOffs[12] = { 0, 4, 8, 12, 16, 19, 22, 25, 28, 33, 38, 42 };
-  int j = sprite_graphics[k];
-  Sprite_DrawMultiple(k, &kHinox_Dmd[kHinoxOffs[j]], kHinoxNum[j], &info);
-  SpriteDraw_Shadow(k, &info);
-}
-
-void Sprite_23_RedBari(int k) {  // 86a23d
-  static const int8 kBari_Xvel2[16] = {0, 8, 11, 14, 16, 14, 11, 8, 0, -8, -11, -14, -16, -14, -11, -8};
-  static const int8 kBari_Yvel2[16] = {-16, -14, -11, -8, 0, 8, 11, 14, 16, 14, 11, 8, 0, -9, -11, -14};
-  static const uint8 kBari_Gfx[2] = {0, 3};
-  int j;
-
-  if (sign8(sprite_C[k])) {
-    if (sprite_head_dir[k] != 16) {
-      sprite_head_dir[k]++;
-    } else {
-      sprite_x_vel[k] = 255;
-      sprite_subtype[k] = 255;
-      Sprite_CheckTileCollision2(k);
-      sprite_subtype[k] = 0;
-      if (!sprite_tiletype) {
-        sprite_C[k] = 0;
-        sprite_ignore_projectile[k] = 0;
-        goto set_electrocute_delay;
-      }
-      sprite_ignore_projectile[k] = sprite_tiletype;
-    }
-    return;
-  }
-  if (sprite_C[k] != 0) {
-    SpriteDraw_SingleSmall(k);
-  } else if (sprite_graphics[k] >= 2) {
-    SpriteDraw_SingleLarge(k);
-  } else {
-    RedBari_Draw(k);
-  }
-
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  if (Sprite_ReturnIfRecoiling(k))
-    return;
-  if (sprite_delay_aux2[k])
-    goto recoil_from_split;
-
-  if (sprite_ai_state[k] == 2) {
-    static const int8 kBari_Xvel[2] = {8, -8};
-    sprite_ignore_projectile[k] = sprite_ai_state[k];
-    sprite_x_vel[k] = kBari_Xvel[frame_counter >> 1 & 1];
-    Sprite_MoveX(k);
-    if (!sprite_delay_main[k]) {
-      RedBari_Split(k);
-      sprite_state[k] = 0;
-    }
-    return;
-  }
-
-  Sprite_CheckDamageToAndFromLink(k);
-  if (!((k ^ frame_counter) & 15)) {
-    sprite_A[k] += (sprite_B[k] & 1) ? -1 : 1;
-    if (!(GetRandomNumber() & 3))
-      sprite_B[k]++;
-  }
-  j = sprite_A[k] & 15;
-  sprite_x_vel[k] = kBari_Xvel2[j];
-  sprite_y_vel[k] = kBari_Yvel2[j];
-
-  if (!((k ^ frame_counter) & 3 | sprite_delay_main[k])) {
-recoil_from_split:
-    if (!sprite_wallcoll[k])
-      Sprite_MoveXY(k);
-    Sprite_CheckTileCollision2(k);
-  }
-  j = sprite_C[k];
-  sprite_graphics[k] = (frame_counter >> 3 & 1) + kBari_Gfx[j];
-  if (sprite_ai_state[k]) {
-    if (sprite_delay_main[k]) {
-      sprite_graphics[k] = (frame_counter >> 1 & 2) + kBari_Gfx[j];
-      return;
-    }
-    sprite_ai_state[k] = 0;
-  } else if (sprite_delay_aux1[k]) {
-    return;
-  } else if (!(GetRandomNumber() & 1)) {
-    sprite_delay_main[k] = 128;
-    sprite_ai_state[k]++;
-    return;
-  }
-set_electrocute_delay:
-  sprite_delay_aux1[k] = (GetRandomNumber() & 63) + 128;
-}
-
-void RedBari_Split(int k) {  // 86a34e
-  static const int8 kRedBari_SplitX[2] = {0, 8};
-  static const int8 kRedBari_SplitXvel[2] = {-32, 32};
-
-  tmp_counter = 1;
-  do {
-    SpriteSpawnInfo info;
-    int j = Sprite_SpawnDynamically(k, 0x23, &info);
-    if (j >= 0) {
-      Sprite_SetSpawnedCoordinates(j, &info);
-      sprite_flags3[j] = 0x33;
-      sprite_oam_flags[j] = 3;
-      sprite_flags4[j] = 1;
-      sprite_C[j] = 1;
-      Sprite_SetX(j, info.r0_x + kRedBari_SplitX[tmp_counter]);
-      sprite_x_vel[j] = kRedBari_SplitXvel[tmp_counter];
-      sprite_delay_aux2[j] = 8;
-      sprite_delay_aux1[j] = 64;
-    }
-  } while (!sign8(--tmp_counter));
-
-}
-
-void RedBari_Draw(int k) {  // 86a3dc
-  static const DrawMultipleData kRedBari_Dmd[8] = {
-    {0, 0, 0x0022, 0},
-    {8, 0, 0x4022, 0},
-    {0, 8, 0x0032, 0},
-    {8, 8, 0x4032, 0},
-    {0, 0, 0x0023, 0},
-    {8, 0, 0x4023, 0},
-    {0, 8, 0x0033, 0},
-    {8, 8, 0x4033, 0},
-  };
-  PrepOamCoordsRet info;
-  Sprite_DrawMultiple(k, &kRedBari_Dmd[sprite_graphics[k] * 4], 4, &info);
-  SpriteDraw_Shadow(k, &info);
-}
-
-void Sprite_13_MiniHelmasaur(int k) {  // 86a409
-  static const uint8 kHelmasaur_Gfx[8] = {3, 4, 3, 4, 2, 2, 5, 5};
-  static const uint8 kHelmasaur_OamFlags[8] = {0x40, 0x40, 0, 0, 0, 0x40, 0x40, 0};
-  int j = sprite_subtype2[k] >> 2 & 1 | sprite_D[k] << 1;
-  sprite_graphics[k] = kHelmasaur_Gfx[j];
-  sprite_oam_flags[k] = sprite_oam_flags[k] & ~0x40 | kHelmasaur_OamFlags[j];
-  if (!((k ^ frame_counter) & 15)) {
-    uint8 x = sprite_x_vel[k];
-    if (sign8(x)) x = -x;
-    uint8 y = sprite_y_vel[k];
-    if (sign8(y)) y = -y;
-    sprite_D[k] = (x >= y) ? (sprite_x_vel[k] >> 7) : (sprite_y_vel[k] >> 7) + 2;
-  }
-  SpriteDraw_SingleLarge(k);
-  HelmasaurHardHatBeetleCommon(k);
-}
-
-void Sprite_26_HardhatBeetle(int k) {  // 86a460
-  sprite_graphics[k] = sprite_subtype2[k] >> 2 & 1;
-  HardHatBeetle_Draw(k);
-  HelmasaurHardHatBeetleCommon(k);
-}
-
-void HelmasaurHardHatBeetleCommon(int k) {  // 86a46d
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  sprite_subtype2[k]++;
-  if (Sprite_ReturnIfRecoiling(k))
-    return;
-  Sprite_CheckDamageToAndFromLink(k);
-  if (sprite_wallcoll[k] & 15) {
-    if (sprite_wallcoll[k] & 3)
-      sprite_x_vel[k] = 0;
-    sprite_y_vel[k] = 0;
-  } else {
-    Sprite_MoveXY(k);
-  }
-  Sprite_CheckTileCollision(k);
-  if (!((k ^ frame_counter) & 31)) {
-    ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLink(k, sprite_A[k]);
-    sprite_B[k] = pt.y;
-    sprite_C[k] = pt.x;
-  }
-  if ((k ^ frame_counter) & sprite_ai_state[k])
-    return;
-  sprite_y_vel[k] += sign8(sprite_y_vel[k] - sprite_B[k]) ? 1 : -1;
-  sprite_x_vel[k] += sign8(sprite_x_vel[k] - sprite_C[k]) ? 1 : -1;
-}
-
-void HardHatBeetle_Draw(int k) {  // 86a4f2
-  static const DrawMultipleData kHardHatBeetle_Dmd[4] = {
-    {0, -4, 0x0140, 2},
-    {0,  2, 0x0142, 2},
-    {0, -5, 0x0140, 2},
-    {0,  2, 0x0144, 2},
-  };
-  PrepOamCoordsRet info;
-  Sprite_DrawMultiple(k, &kHardHatBeetle_Dmd[sprite_graphics[k] * 2], 2, &info);
-  if (sprite_flags3[k] & 0x10)
-    SpriteDraw_Shadow(k, &info);
-}
-
-void Sprite_15_Antifairy(int k) {  // 86a50c
-  SpriteDraw_Antfairy(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  if (Sprite_CheckDamageToLink(k) && sprite_delay_main[k] == 0) {
-    sprite_delay_main[k] = 16;
-    int t = link_magic_power - 8;
-    if (t < 0)
-      t = 0;
-    else
-      sound_effect_2 = 0x1d;
-    link_magic_power = t;
-  }
-  Sprite_MoveXY(k);
-  Sprite_BounceFromTileCollision(k);
-}
-
-void Sprite_0B_Cucco(int k) {  // 86a5c2
-  if (sprite_x_vel[k] != 0)
-    sprite_oam_flags[k] = sprite_oam_flags[k] & ~0x40 | (sign8(sprite_x_vel[k]) ? 0 : 0x40);
-
-  SpriteDraw_SingleLarge(k);
-  if (sprite_head_dir[k] != 0) {
-    sprite_type[k] = 0x3d;
-    SpritePrep_LoadProperties(k);
-    sprite_subtype[k]++;
-    sprite_delay_main[k] = 48;
-    sound_effect_1 = 21;
-    sprite_ignore_projectile[k] = 21;
-    return;
-  }
-  if (sprite_state[k] == 10) {
-    sprite_ai_state[k] = 3;
-    if (submodule_index == 0) {
-      Chicken_IncrSubtype2(k, 3);
-      Cucco_DrawPANIC(k);
-      if (!(frame_counter & 0xf))
-        BawkBawk(k);
-    }
-  }
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  if (sprite_C[k] != 0) {
-    sprite_oam_flags[k] |= 0x10;
-    Sprite_MoveXY(k);
-    sprite_z[k] = 12;
-    sprite_ignore_projectile[k] = 12;
-    if (((k ^ frame_counter) & 7) == 0)
-      Sprite_CheckDamageToLink(k);
-    Chicken_IncrSubtype2(k, 4);
-  } else {
-    sprite_health[k] = 255;
-    if (sprite_B[k] >= 35)
-      Cucco_SummonAvenger(k);
-    if (sprite_F[k] != 0) {
-      sprite_F[k] = 0;
-      if (sprite_B[k] < 35) {
-        sprite_B[k]++;
-        BawkBawk(k);
-      }
-      sprite_ai_state[k] = 2;
-    }
-    Sprite_CheckDamageFromLink(k);
-    switch (sprite_ai_state[k]) {
-    case 0: Cucco_Calm(k); break;
-    case 1: Chicken_Hopping(k); break;
-    case 2: Cucco_Flee(k); break;
-    case 3: Cucco_Carried(k); break;
-    }
-  }
-}
-
-void Cucco_Calm(int k) {  // 86a67f
-  if (sprite_delay_main[k] == 0) {
-    int j = GetRandomNumber() & 0xf;
-    sprite_x_vel[k] = kSpriteKeese_Tab2[j];
-    sprite_y_vel[k] = kSpriteKeese_Tab3[j];
-    sprite_delay_main[k] = (GetRandomNumber() & 0x1f) + 0x10;
-    sprite_ai_state[k]++;
-  }
-  sprite_graphics[k] = 0;
-  Sprite_ReturnIfLifted(k);
-}
-
-void Chicken_Hopping(int k) {  // 86a6b1
-  if ((k ^ frame_counter) & 1 && Cucco_DoMovement_XY(k))
-    sprite_ai_state[k] = 0;
-  Sprite_MoveZ(k);
-  sprite_z_vel[k] -= 2;
-  if (sign8(sprite_z[k])) {
-    sprite_z[k] = 0;
-    if (sprite_delay_main[k] == 0) {
-      sprite_delay_main[k] = 32;
-      sprite_ai_state[k] = 0;
-    }
-    sprite_z_vel[k] = 10;
-  }
-  Chicken_IncrSubtype2(k, 4);
-}
-
-void Cucco_Flee(int k) {  // 86a6fc
-  Sprite_ReturnIfLifted(k);
-  Cucco_DoMovement_XY(k);
-  sprite_z[k] = 0;
-  if (!((k ^ frame_counter) & 0x1f)) {
-    ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLink(k, 16);
-    sprite_x_vel[k] = -pt.x;
-    sprite_y_vel[k] = -pt.y;
-  }
-  Chicken_IncrSubtype2(k, 5);
-  Cucco_DrawPANIC(k);
-}
-
-void Cucco_DrawPANIC(int k) {  // 86a727
-  PrepOamCoordsRet info;
-  if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
-    return;
-  Sprite_DrawDistress_custom(info.x, info.y, frame_counter);
-}
-
-void Cucco_Carried(int k) {  // 86a78e
-  Sprite_MoveZ(k);
-  if (Cucco_DoMovement_XY(k)) {
-    sprite_x_vel[k] = -sprite_x_vel[k];
-    sprite_y_vel[k] = -sprite_y_vel[k];
-    Sprite_MoveXY(k);
-    Sprite_HalveSpeed_XY(k);
-    Sprite_HalveSpeed_XY(k);
-    BawkBawk(k);
-  }
-  sprite_z_vel[k]--;
-  if (sign8(sprite_z[k])) {
-    sprite_z[k] = 0;
-    sprite_ai_state[k] = 2;
-    ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLink(k, 16);
-    sprite_x_vel[k] = -pt.x;
-    sprite_y_vel[k] = -pt.y;
-    Chicken_IncrSubtype2(k, 5);
-    Cucco_DrawPANIC(k);
-  } else {
-    Chicken_IncrSubtype2(k, 4);
-  }
-}
-
-uint8 Cucco_DoMovement_XY(int k) {  // 86a7bb
-  Sprite_MoveXY(k);
-  return Sprite_CheckTileCollision(k);
-}
-
-void Cucco_SummonAvenger(int k) {  // 86a7d3
-  static const uint8 kChicken_Avenger[2] = {0, 0xff};
-  if ((k ^ frame_counter) & 0xf | player_is_indoors)
-    return;
-  SpriteSpawnInfo info;
-  int j = Sprite_SpawnDynamicallyEx(k, 0xB, &info, 10);
-  if (j < 0)
-    return;
-  SpriteSfx_QueueSfx3WithPan(j, 0x1e);
-  sprite_C[j] = 1;
-  uint8 t = GetRandomNumber();
-  uint16 x = BG2HOFS_copy2, y = BG2VOFS_copy2;
-  if (t & 2)
-    x += t, y += kChicken_Avenger[t & 1];
-  else
-    y += t, x += kChicken_Avenger[t & 1];
-  Sprite_SetX(j, x);
-  Sprite_SetY(j, y);
-  Sprite_ApplySpeedTowardsLink(j, 32);
-  BawkBawk(k);
-}
-
-void BawkBawk(int k) {  // 86a84c
-  SpriteSfx_QueueSfx2WithPan(k, 0x30);
-}
-
-void Sprite_17_Hoarder(int k) {  // 86a86c
-  if (sprite_ai_state[k])
-    Sprite_Hoarder_Frantic(k);
-  else
-    Sprite_Hoarder_Covered(k);
-}
-
-void Sprite_Hoarder_Covered(int k) {  // 86a874
-  static const uint8 kRupeeCoveredGrab_Gfx[4] = {3, 4, 5, 4};
-  static const int8 kRupeeCoveredGrab_Xvel[4] = {-12, 12, 0, 0};
-  static const int8 kRupeeCoveredGrab_Yvel[4] = {0, 0, -12, 12};
-  CoveredRupeeCrab_Draw(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  sprite_graphics[k] = 0;
-  PointU8 pt;
-  uint8 dir = Sprite_DirectionToFaceLink(k, &pt);
-  if (sprite_delay_main[k])
-    goto lbl;
-  if ((uint8)(pt.y + 0x30) < 0x60 && (uint8)(pt.x + 0x20) < 0x40) {
-    sprite_delay_main[k] = 32;
-lbl:sprite_x_vel[k] = kRupeeCoveredGrab_Xvel[dir];
-    sprite_y_vel[k] = kRupeeCoveredGrab_Yvel[dir];
-    if (!sprite_wallcoll[k])
-      Sprite_MoveXY(k);
-    Sprite_CheckTileCollision2(k);
-    Sprite_CheckDamageFromLink(k);
-    sprite_graphics[k] = kRupeeCoveredGrab_Gfx[++sprite_subtype2[k] >> 1 & 3];
-  }
-  if (sprite_type[k] != 0x3e || link_item_gloves >= 1)
-    Sprite_ReturnIfLiftedPermissive(k);  // note, dont ret
-  if (sprite_state[k] != 9) {
-    sprite_C[k] = (sprite_type[k] == 0x17) ? 2 : 1;
-    sprite_type[k] = 0xec;
-    sprite_oam_flags[k] &= ~1;
-    sprite_graphics[k] = 0;
-    SpriteSpawnInfo info;
-    int j = Sprite_SpawnDynamically(k, 0x3e, &info);
-    if (j >= 0) {
-      Sprite_SetSpawnedCoordinates(j, &info);
-      sprite_flags2[j] &= ~0x80;
-      sprite_delay_aux2[j] = 128;
-      sprite_oam_flags[j] = 9;
-      sprite_ai_state[j] = 9;
-    }
-  }
-}
-
-void Sprite_Hoarder_Frantic(int k) {  // 86a91d
-  static const uint8 kRupeeCrab_Gfx[4] = {0, 1, 0, 1};
-  static const uint8 kRupeeCrab_OamFlags[4] = {0, 0, 0x40, 0};
-  static const int8 kRupeeCrab_Xvel[4] = {-16, 16, -16, 16};
-  static const int8 kRupeeCrab_Yvel[4] = {-16, -16, 16, 16};
-
-  SpriteDraw_SingleLarge(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  if (Sprite_ReturnIfRecoiling(k))
-    return;
-  Sprite_CheckDamageFromLink(k);
-  if (!sprite_delay_aux2[k])
-    Sprite_CheckDamageToLink(k);
-  int j = ++sprite_subtype2[k] >> 1 & 3;
-  sprite_graphics[k] = kRupeeCrab_Gfx[j];
-  sprite_oam_flags[k] = sprite_oam_flags[k] & ~0x40 | kRupeeCrab_OamFlags[j];
-  if (sprite_wallcoll[k]) {
-    sprite_delay_aux4[k] = 16;
-    j = GetRandomNumber() & 3;
-    sprite_x_vel[k] = kRupeeCrab_Xvel[j];
-    sprite_y_vel[k] = kRupeeCrab_Yvel[j];
-  } else {
-    Sprite_MoveXY(k);
-  }
-  Sprite_CheckTileCollision2(k);
-  if (!sprite_delay_aux4[k] && !((k ^ frame_counter) & 31)) {
-    ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLink(k, 16);
-    sprite_y_vel[k] = -pt.y;
-    sprite_x_vel[k] = -pt.x;
-  }
-  if (frame_counter & 1)
-    return;
-
-  int end;
-  uint8 type;
-  if (++sprite_G[k] == 192) {
-    sprite_delay_main[k] = 15;
-    sprite_state[k] = 6;
-    sprite_flags2[k] += 4;
-    end = 1;
-    type = 0xd9;
-  } else {
-    if (sprite_G[k] & 15)
-      return;
-    end = 0;
-    type = sprite_head_dir[k] == 6 ? 0xdb : 0xd9;
-  }
-  SpriteSpawnInfo info;
-  j = Sprite_SpawnDynamicallyEx(k, type, &info, end);
-  if (j >= 0) {
-    sprite_head_dir[k]++;
-    Sprite_SetSpawnedCoordinates(j, &info);
-    Sprite_SetX(j, info.r0_x + 8);
-    sprite_z_vel[j] = 32;
-    sprite_delay_aux4[j] = 16;
-    ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLink(j, 16);
-    sprite_y_vel[j] = ~pt.y;
-    sprite_x_vel[j] = ~pt.x;
-    SpriteSfx_QueueSfx3WithPan(k, 0x30);
-  }
-}
-
-void CoveredRupeeCrab_Draw(int k) {  // 86aa48
-  static const int8 kCoveredRupeeCrab_DrawY[12] = {0, 0, 0, -3, 0, -5, 0, -6, 0, -6, 0, -6};
-  static const uint8 kCoveredRupeeCrab_DrawChar[12] = {0x44, 0x44, 0xe8, 0x44, 0xe8, 0x44, 0xe6, 0x44, 0xe8, 0x44, 0xe6, 0x44};
-  static const uint8 kCoveredRupeeCrab_DrawFlags[12] = {0, 0xc, 3, 0xc, 3, 0xc, 3, 0xc, 3, 0xc, 0x43, 0xc};
-  PrepOamCoordsRet info;
-  if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
-    return;
-  if (byte_7E0FC6 >= 3)
-    return;
-  OamEnt *oam = GetOamCurPtr();
-  uint8 r7 = (sprite_type[k] == 0x17) ? 2 : 0;
-  uint8 r6 = sprite_graphics[k] * 2;
-  for (int i = 1; i >= 0; i--, oam++) {
-    int j = i + r6;
-    uint8 ch = kCoveredRupeeCrab_DrawChar[j];
-    SetOamHelper0(oam, info.x, info.y + kCoveredRupeeCrab_DrawY[j],
-                  ch + (ch == 0x44 ? r7 : 0),
-                  (info.flags & ~1) | kCoveredRupeeCrab_DrawFlags[j], 2);
-  }
-}
-
-void Sprite_EC_ThrownItem(int k) {  // 86aae0
-  if (byte_7E0FC6 < 3) {
-    if (sort_sprites_setting && sprite_floor[k]) {
-      int spr_slot = 0x2c + (k & 3);
-      oam_cur_ptr = 0x0800 + spr_slot * 4;
-      oam_ext_cur_ptr = 0x0A20 + spr_slot;
-    }
-    sprite_ignore_projectile[k] = sprite_state[k];
-    if (sprite_C[k] >= 6) {
-      SpriteDraw_ThrownItem_Gigantic(k);
-    } else {
-      SpriteDraw_SingleLarge(k);
-      OamEnt *oam = GetOamCurPtr();
-      uint8 t = player_is_indoors + is_in_dark_world;
-      int j = sprite_C[k];
-      oam->charnum = kThrowableScenery_Char[j + ((t >= 2) ? 6 : 0)];
-      oam->flags = (oam->flags & 0xf0) | kThrowableScenery_Flags[j];
-      sprite_oam_flags[k] = (sprite_oam_flags[k] & 0xc0) | (oam->flags & 0xf);
-    }
-  }
-  if (sprite_state[k] == 9) {
-    if (Sprite_ReturnIfInactive(k))
-      return;
-    ThrowableScenery_InteractWithSpritesAndTiles(k);
-  }
-}
-
-void SpriteDraw_ThrownItem_Gigantic(int k) {  // 86ab76
-  PrepOamCoordsRet info;
-  sprite_oam_flags[k] = kThrowableScenery_DrawLarge_OamFlags[sprite_C[k] - 6];
-
-  if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
-    return;
-
-  OamEnt *oam = GetOamCurPtr();
-  for (int i = 3; i >= 0; i--, oam++) {
-    SetOamHelper0(oam, info.x + kThrowableScenery_DrawLarge_X[i], info.y + kThrowableScenery_DrawLarge_Y[i],
-                  0x4a, kThrowableScenery_DrawLarge_Flags[i] | info.flags, 2);
-  }
-  Oam_AllocateFromRegionB(12);
-  oam = GetOamCurPtr();
-  info.y = Sprite_GetY(k) - BG2VOFS_copy2;
-  for (int i = 2; i >= 0; i--, oam++) {
-    SetOamHelper0(oam, info.x + kThrowableScenery_DrawLarge_X2[i], info.y + 12, 0x6c, 0x24, 2);
-  }
-}
-
-void ThrowableScenery_ScatterIntoDebris(int k) {  // 86ac41
-  if (!sign8(sprite_C[k]) && sprite_C[k] >= 6) {
-    for (int i = 3; i >= 0; i--) {
-      SpriteSpawnInfo info;
-      int j = Sprite_SpawnDynamically(k, 0xec, &info);
-      if (j >= 0) {
-        sprite_z[j] = sprite_z[k];
-        Sprite_SetX(j, info.r0_x + kScatterDebris_X[i]);
-        Sprite_SetY(j, info.r2_y + kScatterDebris_Y[i]);
-        sprite_C[j] = 1;
-        Sprite_ScheduleForBreakage(j);
-        sprite_oam_flags[j] = (sprite_C[k] < 7) ? 12 : 0;
-      }
-    }
-    sprite_state[k] = 0;
-  } else {
-    sprite_state[k] = 0;
-    PrepOamCoordsRet info;
-    if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
-      return;
-    int j = 29;
-    while (garnish_type[j--] && j >= 0) {}
-    j++;
-    garnish_type[j] = 22;
-    garnish_active = 22;
-    garnish_x_lo[j] = sprite_x_lo[k];
-    garnish_x_hi[j] = sprite_x_hi[k];
-    uint16 y = Sprite_GetY(k) - sprite_z[k] + 0x10;
-    garnish_y_lo[j] = (uint8)y;
-    garnish_y_hi[j] = (uint8)(y >> 8);
-    garnish_oam_flags[j] = info.flags;
-    garnish_floor[j] = sprite_floor[k];
-    garnish_countdown[j] = 31;
-    garnish_sprite[j] = sprite_C[k];
-  }
-}
-
-void Sprite_TransmuteToBomb(int k) {  // 86ad50
-  sprite_type[k] = 0x4a;
-  sprite_C[k] = 1;
-  sprite_delay_aux1[k] = 255;
-  sprite_flags3[k] = 0x18;
-  sprite_oam_flags[k] = 8;
-  sprite_health[k] = 0;
-}
-
-void Sprite_28_DarkWorldHintNPC(int k) {  // 86ad6f
-  StoryTeller_1_Draw(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  Sprite_BehaveAsBarrier(k);
-  if (!sprite_delay_main[k])
-    sprite_graphics[k] = frame_counter >> 4 & 1;
-
-  switch(sprite_subtype2[k]) {
-  case 0:
-    switch (sprite_ai_state[k]) {
-    case 0: DarkWorldHintNPC_Idle(k); break;
-    case 1:
-      if (choice_in_multiselect_box == 0 && DarkWorldHintNPC_HandlePayment()) {
-        Sprite_ShowMessageUnconditional(0xff);
-        sprite_ai_state[k] = 2;
-      } else {
-        Sprite_ShowMessageUnconditional(0x100);
-        sprite_ai_state[k] = 0;
-      }
-      break;
-    case 2: DarkWorldHintNPC_RestoreHealth(k); break;
-    }
-    break;
-  case 1:
-    switch (sprite_ai_state[k]) {
-    case 0: DarkWorldHintNPC_Idle(k); break;
-    case 1:
-      if (choice_in_multiselect_box == 0 && DarkWorldHintNPC_HandlePayment()) {
-        Sprite_ShowMessageUnconditional(0x101);
-        sprite_ai_state[k] = 2;
-      } else {
-        Sprite_ShowMessageUnconditional(0x100);
-        sprite_ai_state[k] = 0;
-      }
-      break;
-    case 2: DarkWorldHintNPC_RestoreHealth(k); break;
-    }
-    break;
-  case 2:
-    switch (sprite_ai_state[k]) {
-    case 0: DarkWorldHintNPC_Idle(k); break;
-    case 1:
-      if (choice_in_multiselect_box == 0 && DarkWorldHintNPC_HandlePayment()) {
-        Sprite_ShowMessageUnconditional(0x102);
-        sprite_ai_state[k] = 2;
-      } else {
-        Sprite_ShowMessageUnconditional(0x100);
-        sprite_ai_state[k] = 0;
-      }
-      break;
-    case 2: DarkWorldHintNPC_RestoreHealth(k); break;
-    }
-    break;
-  case 3:
-    if (sprite_delay_main[k] == 0) {
-      if ((frame_counter & 0x3f) == 0)
-        sprite_oam_flags[k] ^= 0x40;
-      if (GetRandomNumber() == 0)
-        sprite_delay_main[k] = 32;
-    }
-    Sprite_ShowSolicitedMessage(k, 0x149);
-    break;
-  case 4:
-    sprite_graphics[k] = frame_counter >> 1 & 1;
-    Sprite_MoveZ(k);
-    if (sign8(sprite_z[k]))
-      sprite_z[k] = 0;
-    sprite_z_vel[k] += (sprite_z[k] >= 4) ? -1 : 1;
-    switch (sprite_ai_state[k]) {
-    case 0: DarkWorldHintNPC_Idle(k); break;
-    case 1:
-      if (choice_in_multiselect_box == 0 && DarkWorldHintNPC_HandlePayment()) {
-        Sprite_ShowMessageUnconditional(0x103);
-        sprite_ai_state[k] = 2;
-      } else {
-        Sprite_ShowMessageUnconditional(0x100);
-        sprite_ai_state[k] = 0;
-      }
-      break;
-    case 2: DarkWorldHintNPC_RestoreHealth(k); break;
-    }
-    break;
-  }
-}
-
-void DarkWorldHintNPC_Idle(int k) {  // 86ada7
-  if (Sprite_ShowSolicitedMessage(k, 0xfe) & 0x100)
-    sprite_ai_state[k] = 1;
-}
-
-void DarkWorldHintNPC_RestoreHealth(int k) {  // 86adb5
-  link_hearts_filler = 0xa0;
-  sprite_ai_state[k] = 0;
-}
-
-bool DarkWorldHintNPC_HandlePayment() {  // 86aeab
-  if (link_rupees_goal < 20)
-    return false;
-  link_rupees_goal -= 20;
-  return true;
-}
-
-void StoryTeller_1_Draw(int k) {  // 86af1a
-  static const DrawMultipleData kStoryTeller_Dmd[10] = {
-    {0, 0, 0x0a4a, 2},
-    {0, 0, 0x4a6e, 2},
-    {0, 0, 0x0a24, 2},
-    {0, 0, 0x4a24, 2},
-    {0, 0, 0x0804, 2},
-    {0, 0, 0x4804, 2},
-    {0, 0, 0x0a6a, 2},
-    {0, 0, 0x0a6c, 2},
-    {0, 0, 0x0a0e, 2},
-    {0, 0, 0x0a2e, 2},
-  };
-  PrepOamCoordsRet info;
-  Sprite_DrawMultiplePlayerDeferred(k, &kStoryTeller_Dmd[sprite_subtype2[k] * 2 + sprite_graphics[k]], 1, &info);
-  SpriteDraw_Shadow(k, &info);
-}
-
-void Sprite_2E_FluteKid(int k) {  // 86af3b
-  switch (sprite_head_dir[k]) {
-  case 0:
-    switch (sprite_subtype2[k]) {
-    case 0: FluteKid_Human(k); break;
-    case 1: Sprite_FluteKid_Stumpy(k); break;
-    }
-    break;
-  case 1: Sprite_FluteKid_Quaver(k); break;
-  }
-}
-
-void FluteKid_Human(int k) {  // 86af51
-  if (sprite_ai_state[k] != 3)
-    sprite_C[k] = FluteBoy_Draw(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  if (!sprite_C[k] && !sprite_B[k]) {
-    sound_effect_ambient = 11;
-    sprite_B[k] = 11;
-  }
-  sprite_graphics[k] = frame_counter >> 5 & 1;
-  switch (sprite_ai_state[k]) {
-  case 0:  // wait
-    if (link_item_flute >= 2 || FluteBoy_CheckIfPlayerClose(k)) {
-      sprite_ai_state[k] = 1;
-      sprite_D[k]++;
-      byte_7E0FDD++;
-      sprite_delay_main[k] = 176;
-      flag_is_link_immobilized = 1;
-    }
-    if (!sprite_delay_main[k]) {
-      sprite_delay_main[k] = 25;
-      FluteKid_SpawnQuaver(k);
-    }
-    break;
-  case 1:  // prep phase out
-    flag_is_link_immobilized = 1;
-    if (!sprite_delay_main[k]) {
-      TS_copy = 2;
-      CGADSUB_copy = 48;
-      BYTE(palette_filter_countdown) = 0;
-      BYTE(darkening_or_lightening_screen) = 0;
-      Palette_AssertTranslucencySwap();
-      sprite_ai_state[k] = 2;
-      sound_effect_ambient = 128;
-      SpriteSfx_QueueSfx2WithPan(k, 0x33);
-    }
-    break;
-  case 2:  // phase out
-    if (!(frame_counter & 15)) {
-      PaletteFilter_SP5F();
-      if (!BYTE(palette_filter_countdown))
-        sprite_ai_state[k] = 3;
-    }
-    break;
-  case 3:  // phased out
-    PaletteFilter_RestoreSP5F();
-    Palette_RevertTranslucencySwap();
-    sprite_state[k] = 0;
-    flag_is_link_immobilized = 0;
-    break;
-  }
-}
-
-void Sprite_FluteKid_Stumpy(int k) {  // 86b040
-  static const int8 kFluteAardvark_Gfx[20] = {
-    1, 1, 1, 1, 2, 1, 2, 1, 2, 1, 2, 3, 2, 3, 2, 3, 2, 3, 2, -1,
-  };
-  static const int8 kFluteAardvark_Delay[19] = {
-    -1, -1, -1, 16, 2, 12, 6, 8, 10, 4, 14, 2, 10, 6, 6, 10, 2, 14,  2,
-  };
-  FluteAardvark_Draw(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  switch (sprite_ai_state[k]) {
-  case 0:  //
-    switch (link_item_flute & 3) {
-    case 0:  // supplicate
-      if (Sprite_ShowSolicitedMessage(k, 0xe5) & 0x100)
-        sprite_ai_state[k] = 1;
-      break;
-    case 1:  // give me flute
-      Sprite_ShowSolicitedMessage(k, 0xe8);
-      break;
-    case 2:  // thanks
-      sprite_graphics[k] = 1;
-      if (Sprite_ShowSolicitedMessage(k, 0xe9) & 0x100)
-        sprite_ai_state[k] = 3;
-      break;
-    case 3:  // already did
-      sprite_graphics[k] = 3;
-      break;
-    }
-    break;
-  case 1:  //
-    if (!choice_in_multiselect_box) {
-      Sprite_ShowMessageUnconditional(0xe6);
-      sprite_ai_state[k] = 2;
-    } else {
-      Sprite_ShowMessageUnconditional(0xe7);
-      sprite_ai_state[k] = 0;
-    }
-    break;
-  case 2:  // grant shovel
-    item_receipt_method = 0;
-    Link_ReceiveItem(0x13, 0);
-    sprite_ai_state[k] = 0;
-    break;
-  case 3:  // wait for music
-    if (hud_cur_item == kHudItem_Flute && joypad1H_last & 0x40) {
-      sprite_ai_state[k] = 4;
-      music_control = 0xf2;
-      sound_effect_1 = 0;
-      sound_effect_ambient = 23;
-      flag_is_link_immobilized++;
-    }
-    break;
-  case 4:  //
-    if (!sprite_delay_main[k]) {
-      if (sprite_A[k] >= 3)
-        SpriteSfx_QueueSfx2WithPan(k, 0x33);
-      int j = sprite_A[k]++;
-      if (kFluteAardvark_Gfx[j] >= 0) {
-        sprite_graphics[k] = kFluteAardvark_Gfx[j];
-        sprite_delay_main[k] = kFluteAardvark_Delay[j];
-      } else {
-        music_control = 0xf3;
-        sprite_ai_state[k] = 5;
-        flag_is_link_immobilized = 0;
-      }
-    }
-    break;
-  case 5:  // done
-    sprite_graphics[k] = 3;
-    sram_progress_indicator_3 |= 8;
-    break;
-  }
-}
-
-void Sprite_FluteKid_Quaver(int k) {  // 86b173
-  SpriteDraw_SingleSmall(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  Sprite_MoveXY(k);
-  Sprite_MoveZ(k);
-  if (!sprite_delay_main[k])
-    sprite_state[k] = 0;
-  if (!(frame_counter & 1))
-    sprite_x_vel[k] += (frame_counter >> 5 ^ cur_object_index) & 1 ? -1 : 1;
-}
-
-void FluteKid_SpawnQuaver(int k) {  // 86b1a5
-  SpriteSpawnInfo info;
-  int j = Sprite_SpawnDynamically(k, 0x2e, &info);
-  if (j >= 0) {
-    Sprite_SetX(j, info.r0_x + 4);
-    Sprite_SetY(j, info.r2_y - 4);
-    sprite_head_dir[j] = 1;
-    sprite_z_vel[j] = 8;
-    sprite_delay_main[j] = 96;
-    sprite_ignore_projectile[j] = 96;
-  }
-}
-
-void Sprite_1A_Smithy(int k) {  // 86b1ee
-  switch (sprite_subtype2[k]) {
-  case 0: Smithy_Main(k); break;
-  case 1: Smithy_Spark(k); break;
-  case 2: Smithy_Frog(k); break;
-  case 3: Smithy_Homecoming(k); break;
-  }
-}
-
-void Smithy_Homecoming(int k) {  // 86b1fd
-  ReturningSmithy_Draw(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  switch(sprite_ai_state[k]) {
-  case 0: { // ApproachTheBench
-    static const int8 kReturningSmithy_Delay[3] = {104, 12, 0};
-    static const int8 kReturningSmithy_Dir[3] = {0, 2, -1};
-    static const int8 kReturningSmithy_Xvel[4] = {0, 0, -13, 13};
-    static const int8 kReturningSmithy_Yvel[4] = {-13, 13, 0, 0};
-    Sprite_MoveXY(k);
-    sprite_graphics[k] = frame_counter >> 3 & 1;
-    if (sprite_delay_main[k])
-      return;
-    int j = sprite_A[k]++;
-    sprite_delay_main[k] = kReturningSmithy_Delay[j];
-    if ((j = kReturningSmithy_Dir[j]) >= 0) {
-      sprite_D[k] = j;
-      sprite_x_vel[k] = kReturningSmithy_Xvel[j];
-      sprite_y_vel[k] = kReturningSmithy_Yvel[j];
-    } else {
-      sprite_ai_state[k] = 1;
-    }
-    break;
-  }
-  case 1: // Thankful
-    Sprite_BehaveAsBarrier(k);
-    Sprite_ShowSolicitedMessage(k, 0xe3);
-    flag_is_link_immobilized = 0;
-    sprite_D[k] = 1;
-    sram_progress_indicator_3 |= 32;
-    break;
-  }
-}
-
-void Smithy_Frog(int k) {  // 86b274
-  SmithyFrog_Draw(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  Sprite_BehaveAsBarrier(k);
-  sprite_z_vel[k] -= 2;
-  Sprite_MoveZ(k);
-  if (sign8(sprite_z[k])) {
-    sprite_z[k] = 0;
-    sprite_z_vel[k] = 16;
-  }
-  if (!sprite_ai_state[k]) {
-    sprite_D[k] = 1;
-    if (Sprite_ShowSolicitedMessage(k, 0xe1) & 0x100)
-      sprite_ai_state[k] = 1;
-  } else {
-    follower_indicator = 7;
-    LoadFollowerGraphics();
-    Sprite_BecomeFollower(k);  // zelda bug: doesn't save X
-    sprite_state[k] = 0;
-  }
-}
-
-void ReturningSmithy_Draw(int k) {  // 86b308
-  static const DrawMultipleData kReturningSmithy_Dmd[8] = {
-    {0, 0, 0x4122, 2},
-    {0, 0, 0x0122, 2},
-    {0, 0, 0x4122, 2},
-    {0, 0, 0x0122, 2},
-    {0, 0, 0x0122, 2},
-    {0, 0, 0x0122, 2},
-    {0, 0, 0x4122, 2},
-    {0, 0, 0x4122, 2},
-  };
-  static const uint8 kReturningSmithy_Dma[8] = {0xc0, 0xc0, 0xa0, 0xa0, 0x80, 0x60, 0x80, 0x60};
-  int j = sprite_D[k] * 2 + sprite_graphics[k];
-  PrepOamCoordsRet info;
-  BYTE(dma_var7) = kReturningSmithy_Dma[j];
-  Sprite_DrawMultiplePlayerDeferred(k, &kReturningSmithy_Dmd[j], 1, &info);
-  SpriteDraw_Shadow(k, &info);
-}
-
-void SmithyFrog_Draw(int k) {  // 86b339
-  static const DrawMultipleData kSmithyFrog_Dmd[1] = {
-    {0, 0, 0x00c8, 2},
-  };
-  PrepOamCoordsRet info;
-  Sprite_DrawMultiplePlayerDeferred(k, kSmithyFrog_Dmd, 1, &info);
-  SpriteDraw_Shadow(k, &info);
-}
-
-void Smithy_Main(int k) {  // 86b34e
-  Smithy_Draw(k);
-  sprite_z_vel[k] -= 2;
-  Sprite_MoveZ(k);
-  if (sign8(sprite_z[k])) {
-    sprite_z[k] = 0;
-    sprite_z_vel[k] = 0;
-  }
-  if (Sprite_ReturnIfInactive(k))
-    return;
-
-  int j = sprite_ai_state[sprite_E[k]];
-  int i = sprite_ai_state[k];
-  if ((j == 5 || j == 7 || j == 9 || i == 5 || i == 7 || i == 9 || (i | j) == 0) && sprite_B[k]-- == 0) {
-    static const uint8 kSmithy_Gfx[8] = {0, 1, 2, 3, 3, 2, 1, 0};
-    static const uint8 kSmithy_B[8] = {24, 4, 1, 16, 16, 5, 10, 16};
-    j = sprite_A[k];
-    sprite_A[k] = j + 1 & 7;
-    sprite_graphics[k] = kSmithy_Gfx[j];
-    sprite_B[k] = kSmithy_B[j];
-    if (j == 1)
-      sprite_z_vel[k] = 16;
-    if (j == 3) {
-      Smithy_SpawnSpark(k);
-      SpriteSfx_QueueSfx2WithPan(k, 0x5);
-    }
-  }
-  switch(sprite_ai_state[k]) {
-  case 0:  // ConversationStart
-    sprite_C[k] = 0;
-    if (follower_indicator != 8) {
-      if (Smithy_ListenForHammer(k)) {
-        Sprite_ShowMessageUnconditional(0xe4);
-        sprite_delay_aux1[k] = 96;
-        sprite_C[k]++;
-      } else if (sram_progress_indicator_3 & 0x20) {
-        if (Sprite_ShowSolicitedMessage(k, 0xd8) & 0x100) {
-          sprite_ai_state[k]++;
-          sprite_C[k]++;
-        }
-      } else {
-        Sprite_ShowSolicitedMessage(k, 0xdf);
-      }
-    } else {
-      if (BYTE(link_y_coord) < 0xc2) {
-        Sprite_ShowMessageUnconditional(0xe0);
-        sprite_ai_state[k] = 10;
-        flag_is_link_immobilized++;
-      }
-    }
-    break;
-  case 1:  // ProvideTemperingChoice
-    if (!choice_in_multiselect_box) {
-      Sprite_ShowMessageUnconditional(0xd9);
-      sprite_ai_state[k] = 2;
-    } else {
-      Sprite_ShowMessageUnconditional(0xdc);
-      sprite_ai_state[k] = 0;
-    }
-    break;
-  case 2:  // HandleTemperingChoice
-    if (choice_in_multiselect_box == 0) {
-      if (link_sword_type < 3) {
-        Sprite_ShowMessageUnconditional(0xda);
-        sprite_ai_state[k] = 3;
-      } else {
-        Sprite_ShowMessageUnconditional(0xdb);
-        sprite_ai_state[k] = 0;
-      }
-    } else {
-      Sprite_ShowMessageUnconditional(0xdc);
-      sprite_ai_state[k] = 0;
-    }
-    break;
-  case 3:  // HandleTemperingCost
-    if (choice_in_multiselect_box || link_rupees_goal < 10) {
-      Sprite_ShowMessageUnconditional(0xdc);
-      sprite_ai_state[k] = 0;
-    } else {
-      link_rupees_goal -= 10;
-      Sprite_ShowMessageUnconditional(0xdd);
-      sprite_ai_state[sprite_E[k]] = 5;
-      sprite_ai_state[k] = 5;
-      flag_overworld_area_did_change = 0;
-      link_sword_type = 255;
-      sram_progress_indicator_3 |= 128;
-    }
-    break;
-  case 4:  // TemperingSword
-  case 5:  //
-    sprite_C[k] = 0;
-    if (Smithy_ListenForHammer(k)) {
-      Sprite_ShowMessageUnconditional(0xe4);
-      sprite_delay_aux1[k] = 96;
-      sprite_C[k]++;
-    } else if (flag_overworld_area_did_change) {
-      if (Sprite_ShowSolicitedMessage(k, 0xde) & 0x100) {
-        sprite_ai_state[k]++;
-        sprite_graphics[k] = 4;
-      }
-    } else {
-      Sprite_ShowSolicitedMessage(k, 0xe2);
-    }
-    break;
-  case 6:  // Smithy_GiveTemperedSword
-    sprite_ai_state[k] = 0;
-    sprite_ai_state[sprite_E[k]] = 0;
-    item_receipt_method = 0;
-    Link_ReceiveItem(2, 0);
-    sram_progress_indicator_3 &= ~0x80;
-    break;
-  case 7:  //
-  case 8:  //
-  case 9:  //
-    break;
-  case 10: { // Smithy_SpawnFriend
-    SpriteSpawnInfo info;
-    int j = Sprite_SpawnDynamically(k, 0x1a, &info);
-    if (j >= 0) {
-      Sprite_SetX(j, link_x_coord);
-      Sprite_SetY(j, link_y_coord);
-      sprite_subtype2[j] = 3;
-      sprite_ignore_projectile[j] = 3;
-    }
-    sprite_ai_state[k] = 11;
-    follower_indicator = 0;
-    sprite_graphics[k] = 4;
-    break;
-  }
-  case 11:  // Smithy_CopiouslyThankful
-    Sprite_ShowSolicitedMessage(k, 0xe3);
-    break;
-
-  }
-}
-
-bool Smithy_ListenForHammer(int k) {  // 86b43d
-  return sprite_delay_aux1[k] == 0 && hud_cur_item == kHudItem_Hammer && (link_item_in_hand & 2) && player_handler_timer == 2 && Sprite_CheckDamageToLink_same_layer(k);
-}
-
-int Smithy_SpawnDwarfPal(int k) {  // 86b5a6
-  SpriteSpawnInfo info;
-  int j = Sprite_SpawnDynamically(k, 0x1a, &info);
-  if (j < 0)
-    return j;
-  Sprite_SetX(j, info.r0_x);
-  Sprite_SetY(j, info.r2_y);
-  sprite_x_lo[j] += 0x2C;
-  sprite_D[j] = 1;
-  sprite_A[j] = 4;
-  sprite_ignore_projectile[j] = 4;
-  return j;
-}
-
-void Smithy_Draw(int k) {  // 86b673
-  static const DrawMultipleData kSmithy_Dmd[20] = {
-    {  1,   0, 0x4040, 2},
-    {-11, -10, 0x4060, 2},
-    { -1,   0, 0x0040, 2},
-    { 11, -10, 0x0060, 2},
-    {  1,   0, 0x4040, 2},
-    { -3, -14, 0x4044, 2},
-    { -1,   0, 0x0040, 2},
-    {  3, -14, 0x0044, 2},
-    {  1,   0, 0x4042, 2},
-    { 11, -10, 0x0060, 2},
-    { -1,   0, 0x0042, 2},
-    {-11, -10, 0x4060, 2},
-    {  1,   0, 0x4042, 2},
-    { 13,   2, 0x4062, 2},
-    { -1,   0, 0x0042, 2},
-    {-13,   2, 0x0062, 2},
-    {  0,   0, 0x4064, 2},
-    {  0,   0, 0x4062, 2},
-    {  0,   0, 0x0064, 2},
-    {  0,   0, 0x0064, 2},
-  };
-  PrepOamCoordsRet info;
-  Sprite_DrawMultiplePlayerDeferred(k, &kSmithy_Dmd[sprite_graphics[k] * 4 + sprite_D[k] * 2], 2, &info);
-  SpriteDraw_Shadow(k, &info);
-}
-
-void Smithy_Spark(int k) {  // 86b6a3
-  static const int8 kSmithySpark_Gfx[7] = {0, 1, 2, 1, 2, 1, -1};
-  static const int8 kSmithySpark_Delay[6] = {4, 1, 3, 2, 1, 1};
-  SmithySpark_Draw(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  if (!sprite_delay_main[k]) {
-    int j = sprite_A[k];
-    sprite_A[k] = j + 1 & 7;
-    if (sign8(kSmithySpark_Gfx[j])) {
-      sprite_state[k] = 0;
-      return;
-    }
-    sprite_graphics[k] = kSmithySpark_Gfx[j];
-    sprite_delay_main[k] = kSmithySpark_Delay[j];
-  }
-}
-
-void Smithy_SpawnSpark(int k) {  // 86b6cd
-  SpriteSpawnInfo info;
-  int j = Sprite_SpawnDynamically(k, 0x1a, &info);
-  if (j >= 0) {
-    Sprite_SetX(j, info.r0_x);
-    Sprite_SetY(j, info.r2_y);
-    sprite_x_lo[j] += sprite_D[k] ? -15 : 15;
-    sprite_y_lo[j] += 2;
-    sprite_subtype2[j] = 1;
-  }
-}
-
-void SmithySpark_Draw(int k) {  // 86b72c
-  Oam_AllocateFromRegionB(8);
-  static const DrawMultipleData kSmithySpark_Dmd[6] = {
-    { 0,  3, 0x41aa, 2},
-    { 0, -1, 0x41aa, 2},
-    {-4,  0, 0x0190, 0},
-    {12,  0, 0x4190, 0},
-    {-5, -2, 0x0191, 0},
-    {13, -2, 0x0191, 0},
-  };
-  Sprite_DrawMultiple(k, &kSmithySpark_Dmd[sprite_graphics[k] * 2], 2, NULL);
-}
-
-void Sprite_1B_Arrow(int k) {  // 86b754
-  int j;
-  static const int8 kEnemyArrow_Xvel[8] = {0, 0, 16, 16, 0, 0, -16, -16};
-  static const int8 kEnemyArrow_Yvel[8] = {16, 16, 0, 0, -16, -16, 0, 0};
-  static const uint8 kEnemyArrow_Dirs[4] = {0, 2, 1, 3};
-
-  EnemyArrow_Draw(k);
-  if (Sprite_ReturnIfPaused(k))
-    return;
-  if (sprite_state[k] == 9) {
-    j = sprite_delay_main[k];
-    if (j != 0) {
-      if (--j == 0) {
-        sprite_state[k] = 0;
-      } else if (j >= 32 && !(j & 1)) {
-        j = (frame_counter << 1 & 4) | sprite_D[k];
-        sprite_x_vel[k] = kEnemyArrow_Xvel[j];
-        sprite_y_vel[k] = kEnemyArrow_Yvel[j];
-        Sprite_MoveXY(k);
-      }
-      return;
-    }
-    Sprite_CheckDamageToLink_same_layer(k);
-    if (sprite_E[k] == 0 && Sprite_CheckTileCollision(k)) {
-      if (sprite_A[k]) {
-        SpriteSfx_QueueSfx2WithPan(k, 0x5);
-        Sprite_ScheduleForBreakage(k);
-        Sprite_PlaceWeaponTink(k);
-      } else {
-        sprite_delay_main[k] = 48;
-        sprite_A[k] = 2;
-        SpriteSfx_QueueSfx2WithPan(k, 0x8);
-      }
-    } else {
-      Sprite_MoveXY(k);
-    }
-  } else {
-    if (sprite_ai_state[k] == 0) {
-      Sprite_ApplyRicochet(k);
-      sprite_z_vel[k] = 24;
-      sprite_delay_main[k] = 255;
-      sprite_ai_state[k]++;
-      sprite_hit_timer[k] = 0;
-    }
-    sprite_D[k] = kEnemyArrow_Dirs[sprite_delay_main[k] >> 3 & 3];
-    Sprite_MoveZ(k);
-    Sprite_MoveXY(k);
-    sprite_z_vel[k] -= 2;
-    if (sign8(sprite_z[k]))
-      sprite_state[k] = 0;
-  }
-}
-
-void EnemyArrow_Draw(int k) {  // 86b867
-  static const int16 kEnemyArrow_Draw_X[8] = {-8, 0, 0, 8, 0, 0, 0, 0};
-  static const int16 kEnemyArrow_Draw_Y[8] = {0, 0, 0, 0, -8, 0, 0, 8};
-  static const uint8 kEnemyArrow_Draw_Char[32] = {
-    0x3a, 0x3d, 0x3d, 0x3a, 0x2a, 0x2b, 0x2b, 0x2a, 0x7c, 0x6c, 0x6c, 0x7c, 0x7b, 0x6b, 0x6b, 0x7b,
-    0x3a, 0x3b, 0x3b, 0x3a, 0x2a, 0x3c, 0x3c, 0x2a, 0x81, 0x80, 0x80, 0x81, 0x91, 0x90, 0x90, 0x91,
-  };
-  static const uint8 kEnemyArrow_Draw_Flags[32] = {
-    8,    8, 0x48, 0x48, 8, 8, 0x88, 0x88,    9, 0x49, 9, 0x49,    9, 0x89, 9, 0x89,
-    8, 0x88, 0xc8, 0x48, 8, 8, 0x88, 0x88, 0x49, 0x49, 9,    9, 0x89, 0x89, 9,    9,
-  };
-
-  PrepOamCoordsRet info;
-  if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
-    return;
-  OamEnt *oam = GetOamCurPtr();
-  uint8 r6 = sprite_D[k] * 2, r7 = sprite_A[k] * 8;
-  for (int i = 1; i >= 0; i--, oam++) {
-    int j = r6 + i;
-    SetOamHelper0(oam, info.x + kEnemyArrow_Draw_X[j], info.y + kEnemyArrow_Draw_Y[j],
-                  kEnemyArrow_Draw_Char[j + r7], kEnemyArrow_Draw_Flags[j + r7] | info.flags, 0);
-  }
-}
-
-void Sprite_1E_CrystalSwitch(int k) {  // 86b8d0
-  sprite_oam_flags[k] = sprite_oam_flags[k] & ~0xe | kCrystalSwitchPal[orange_blue_barrier_state & 1];
-  Oam_AllocateDeferToPlayer(k);
-  SpriteDraw_SingleLarge(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  if (Sprite_CheckDamageToLink_same_layer(k)) {
-    Sprite_NullifyHookshotDrag();
-    link_speed_setting = 0;
-    Sprite_RepelDash();
-  }
-  if (sprite_delay_main[k] == 0) {
-    Sprite_GarnishSpawn_Sparkle(k, frame_counter & 7, GetRandomNumber() & 7);
-    sprite_delay_main[k] = 31;
-  }
-  if (sprite_F[k] == 0) {
-    if (sign8(button_b_frames - 9))
-      Sprite_CheckDamageFromLink(k);
-  } else if (sprite_F[k]-- == 11) {
-    orange_blue_barrier_state ^= 1;
-    submodule_index = 22;
-    SpriteSfx_QueueSfx3WithPan(k, 0x25);
-  }
-}
-
-void Sprite_1F_SickKid(int k) {  // 86b94c
-  static const int8 kBugNetKid_Gfx[8] = {0, 1, 0, 1, 0, 1, 2, -1};
-  static const uint8 kBugNetKid_Delay[7] = {8, 12, 8, 12, 8, 96, 16};
-  int j;
-  BugNetKid_Draw(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  switch (sprite_ai_state[k]) {
-  case 0:  // resting
-    if (Sprite_CheckIfLinkIsBusy() || !Sprite_CheckDamageToLink_same_layer(k))
-      return;
-    if ((link_bottle_info[0] | link_bottle_info[1] | link_bottle_info[2] | link_bottle_info[3]) < 2) {
-      Sprite_ShowSolicitedMessage(k, 0x104);
-    } else {
-      flag_is_link_immobilized++;
-      sprite_ai_state[k] = 1;
-    }
-    break;
-  case 1:  // perk
-    if (sprite_delay_main[k])
-      return;
-    j = sprite_A[k];
-    if (kBugNetKid_Gfx[j] >= 0) {
-      sprite_graphics[k] = kBugNetKid_Gfx[j];
-      sprite_delay_main[k] = kBugNetKid_Delay[j];
-      sprite_A[k] = j + 1;
-    } else {
-      Sprite_ShowMessageUnconditional(0x105);
-      sprite_ai_state[k] = 2;
-    }
-    break;
-  case 2:  // grant
-    item_receipt_method = 0;
-    Link_ReceiveItem(0x21, 0);
-    flag_is_link_immobilized = 0;
-    sprite_ai_state[k] = 3;
-    break;
-  case 3:  // back to rest
-    sprite_graphics[k] = 1;
-    Sprite_ShowSolicitedMessage(k, 0x106);
-    break;
-  }
-}
-
-void Sprite_21_WaterSwitch(int k) {  // 86b9fa
-  PushSwitch_Draw(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  switch(sprite_ai_state[k]) {
-  case 0:
-    if (sprite_C[k]) {
-      if (!--sprite_B[k])
-        sprite_ai_state[k] = 1;
-      if (!(frame_counter & 3))
-        SpriteSfx_QueueSfx2WithPan(k, 0x22);
-    } else {
-      sprite_B[k] = 48;
-    }
-    break;
-  case 1:
-    if (!sprite_delay_main[k]) {
-      static const uint8 kPushSwitch_Delay[10] = {40, 6, 3, 3, 3, 5, 1, 1, 3, 12};
-      static const uint8 kPushSwitch_Dir[10] = {0, 1, 2, 3, 4, 5, 5, 6, 7, 6};
-      int j = ++sprite_A[k];
-      if (j == 10) {
-        sprite_ai_state[k] = 2;
-        dung_flag_statechange_waterpuzzle++;
-        SpriteSfx_QueueSfx3WithPan(k, 0x25);
-      } else {
-        sprite_delay_main[k] = kPushSwitch_Delay[j];
-        sprite_D[k] = kPushSwitch_Dir[j];
-        SpriteSfx_QueueSfx2WithPan(k, 0x22);
-      }
-    }
-    break;
-  case 2:
-    break;
-  }
-}
-
-void PushSwitch_Draw(int k) {  // 86bb22
-  static const OamEntSigned kPushSwitch_Oam[40] = {
-    {  4, 20, 0xdc, 0x20},
-    {  4, 12, 0xdd, 0x20},
-    {  4, 12, 0xdd, 0x20},
-    {  4, 12, 0xdd, 0x20},
-    {  0,  0, 0xca, 0x20},
-    {  3, 12, 0xdd, 0x20},
-    {  3, 20, 0xdc, 0x20},
-    {  3, 20, 0xdc, 0x20},
-    {  3, 20, 0xdc, 0x20},
-    {  0,  0, 0xca, 0x20},
-    { -8,  8, 0xea, 0x20},
-    {  0,  8, 0xeb, 0x20},
-    { -8, 16, 0xfa, 0x20},
-    {  0, 16, 0xfb, 0x20},
-    {  0,  0, 0xca, 0x20},
-    {-12,  4, 0xcc, 0x20},
-    { -4,  4, 0xcd, 0x20},
-    { -4,  4, 0xcd, 0x20},
-    { -4,  4, 0xcd, 0x20},
-    {  0,  0, 0xca, 0x20},
-    {-10,  4, 0xcc, 0x20},
-    { -4,  4, 0xcd, 0x20},
-    { -4,  4, 0xcd, 0x20},
-    { -4,  4, 0xcd, 0x20},
-    {  0,  0, 0xca, 0x20},
-    { -8,  4, 0xcc, 0x20},
-    { -4,  4, 0xcd, 0x20},
-    { -4,  4, 0xcd, 0x20},
-    { -4,  4, 0xcd, 0x20},
-    {  0,  0, 0xca, 0x20},
-    {  4,  3, 0xe2, 0x20},
-    { -6,  4, 0xcc, 0x20},
-    { -4,  4, 0xcd, 0x20},
-    { -4,  4, 0xcd, 0x20},
-    {  0,  0, 0xca, 0x20},
-    {  4,  3, 0xf1, 0x20},
-    { -6,  4, 0xcc, 0x20},
-    { -4,  4, 0xcd, 0x20},
-    { -4,  4, 0xcd, 0x20},
-    {  0,  0, 0xca, 0x20},
-  };
-  static const uint8 kPushSwitch_WH[16] = {8, 6, 0x10, 0x10, 0x10, 8, 0x10, 8, 0x10, 8, 0x10, 8, 0x10, 3, 0x10, 8};
-  Oam_AllocateDeferToPlayer(k);
-  PrepOamCoordsRet info;
-  if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
-    return;
-  uint8 flags;
-  sprite_oam_flags[k] = flags = palette_swap_flag ? sprite_oam_flags[k] | 0xe : sprite_oam_flags[k] & ~0xe;
-  uint8 r1 = sprite_B[k] >> 2 & 3;
-
-  oam_cur_ptr += 4, oam_ext_cur_ptr += 1;
-
-  OamEnt *oam = GetOamCurPtr();
-  memcpy(oam, &kPushSwitch_Oam[sprite_D[k] * 5], 20);
-
-  uint8 xv = -r1 + BYTE(dungmap_var7);
-  uint8 yv = HIBYTE(dungmap_var7) - (r1 >> 1);
-
-  oam[0].x += xv;
-  oam[1].x += xv;
-  oam[2].x += xv;
-  oam[3].x += xv;
-  oam[4].x += BYTE(dungmap_var7);
-
-  oam[0].y += yv;
-  oam[1].y += yv;
-  oam[2].y += yv;
-  oam[3].y += yv;
-  oam[4].y += HIBYTE(dungmap_var7);
-
-  oam[0].flags |= flags;
-  oam[1].flags |= flags;
-  oam[2].flags |= flags;
-  oam[3].flags |= flags;
-  oam[4].flags |= flags;
-
-  uint8 *big = &g_ram[oam_ext_cur_ptr];
-  big[0] = big[1] = big[2] = big[3] = 0;
-  big[4] = 2;
-
-  Sprite_CorrectOamEntries(k, 4, 0xff);
-
-  if (sprite_floor[k] == link_is_on_lower_level) {
-    sprite_C[k] = 0;
-    int d = sprite_D[k];
-    int x = Sprite_GetX(k) + (int8)kPushSwitch_Oam[d * 4].x;
-    int y = Sprite_GetY(k) + (int8)kPushSwitch_Oam[d * 4].y;
-
-    SpriteHitBox hb;
-    hb.r4_spr_xlo = x;
-    hb.r10_spr_xhi = x >> 8;
-    hb.r5_spr_ylo = y;
-    hb.r11_spr_yhi = y >> 8;
-    hb.r6_spr_xsize = kPushSwitch_WH[d * 2 + 0];
-    hb.r7_spr_ysize = kPushSwitch_WH[d * 2 + 1];
-    Link_SetupHitBox(&hb);
-    if (CheckIfHitBoxesOverlap(&hb)) {
-      uint16 oldy = Sprite_GetY(k);
-      Sprite_SetY(k, oldy + 19);
-      uint8 new_dir = Sprite_DirectionToFaceLink(k, NULL);
-      Sprite_SetY(k, oldy);
-      if (new_dir == 0 && link_direction_facing == 4)
-        sprite_C[k]++;
-    } else {
-      if (!Sprite_CheckDamageToLink_same_layer(k))
-        return;
-    }
-    Sprite_NullifyHookshotDrag();
-    link_speed_setting = 0;
-    Sprite_RepelDash();
-  }
-}
-
-void Sprite_39_Locksmith(int k) {  // 86bcac
-  uint8 bak;
-  int j;
-
-  MiddleAgedMan_Draw(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  Sprite_BehaveAsBarrier(k);
-
-  switch (sprite_ai_state[k]) {
-  case 0:  // chilling
-    Sprite_ShowSolicitedMessage(k, 0x107);
-    bak = sprite_x_lo[k];
-    sprite_x_lo[k] -= 16;
-    Sprite_Get16BitCoords(k);
-    sprite_x_vel[k] = 1;
-    sprite_y_vel[k] = 1;
-    if (!Sprite_CheckTileCollision(k)) {
-      sprite_ai_state[k]++;
-      if (follower_indicator != 0)
-        sprite_ai_state[k] = 5;
-    }
-    sprite_x_lo[k] = bak;
-    break;
-  case 1:  // transition to tagalong
-    follower_indicator = 9;
-    tagalong_var5 = 0;
-    LoadFollowerGraphics();
-    Follower_Initialize();
-    word_7E02CD = 0x40;
-    sprite_state[k] = 0;
-    break;
-  case 2:  // offer chest
-    if (Sprite_CheckIfLinkIsBusy())
-      return;
-    if (follower_dropped) {
-      j = Sprite_ShowSolicitedMessage(k, 0x109);
-    } else {
-      j = Sprite_ShowMessageOnContact(k, 0x109);
-    }
-    if (j & 0x100)
-      sprite_ai_state[k] = 3;
-    break;
-  case 3:  // react to secret keeping
-    if (!choice_in_multiselect_box) {
-      if (follower_dropped) {
-        Sprite_ShowMessageUnconditional(0x10c);
-        sprite_ai_state[k] = 2;
-      } else {
-        item_receipt_method = 0;
-        Link_ReceiveItem(0x16, 0);
-        sram_progress_indicator_3 |= 0x10;
-        sprite_ai_state[k] = 4;
-        follower_indicator = 0;
-      }
-    } else {
-      Sprite_ShowMessageUnconditional(0x10a);
-      sprite_ai_state[k] = 2;
-    }
-    break;
-  case 4:  // promise reminder
-    Sprite_ShowSolicitedMessage(k, 0x10b);
-    break;
-  case 5:  // silence other tagalong
-    Sprite_ShowSolicitedMessage(k, 0x107);
-    break;
-  }
-}
-
-void MiddleAgedMan_Draw(int k) {  // 86bdac
-  static const DrawMultipleData kMiddleAgedMan_Dmd[2] = {
-    {0, -8, 0x00ea, 2},
-    {0,  0, 0x00ec, 2},
-  };
-  PrepOamCoordsRet info;
-  Sprite_DrawMultiplePlayerDeferred(k, &kMiddleAgedMan_Dmd[0], 2, &info);
-  SpriteDraw_Shadow(k, &info);
-}
-
-void Sprite_2B_Hobo(int k) {  // 86bdc1
-  switch (sprite_subtype2[k]) {
-  case 0:
-    Sprite_Hobo_Bum(k);
-    break;
-  case 1:
-    Sprite_Hobo_Bubble(k);
-    break;
-  case 2:
-    Sprite_Hobo_Fire(k);
-    break;
-  case 3:
-    Sprite_Hobo_Smoke(k);
-    break;
-  }
-}
-
-void Sprite_Hobo_Bum(int k) {  // 86bdd0
-  Hobo_Draw(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  sprite_flags4[k] = 3;
-  if (Sprite_CheckDamageToLink_same_layer(k)) {
-    Sprite_NullifyHookshotDrag();
-    link_speed_setting = 0;
-    Link_CancelDash();
-  }
-  switch(sprite_ai_state[k]) {
-  case 0:  // sleeping
-    sprite_flags4[k] = 7;
-    if (Sprite_CheckDamageToLink_same_layer(k) && (filtered_joypad_L & 0x80)) {
-      sprite_ai_state[k] = 1;
-      int j = sprite_E[k];
-      sprite_delay_main[j] = 4;
-      flag_is_link_immobilized = 1;
-    }
-    if (!sprite_delay_aux2[k]) {
-      sprite_delay_aux2[k] = 160;
-      sprite_E[k] = Hobo_SpawnBubble(k);
-    }
-    break;
-  case 1: // wake up
-    if (!sprite_delay_main[k]) {
-      static const int8 kHobo_Gfx[7] = {0, 1, 0, 1, 0, 1, 2};
-      static const int8 kHobo_Delay[7] = {6, 2, 6, 6, 2, 100, 30};
-      int j = sprite_A[k];
-      if (j != 7) {
-        sprite_graphics[k] = kHobo_Gfx[j];
-        sprite_delay_main[k] = kHobo_Delay[j];
-        sprite_A[k]++;
-      } else {
-        Sprite_ShowMessageUnconditional(0xd7);
-        sprite_ai_state[k] = 2;
-      }
-    }
-    break;
-  case 2:  // grant bottle
-    sprite_ai_state[k] = 3;
-    sprite_graphics[k] = 1;
-    save_ow_event_info[BYTE(overworld_screen_index)] |= 0x20;
-    item_receipt_method = 0;
-    Link_ReceiveItem(0x16, 0);
-    sram_progress_indicator_3 |= 1;
-    break;
-  case 3:  // back to sleep
-    flag_is_link_immobilized = 0;
-    sprite_graphics[k] = 0;
-    if (!sprite_delay_main[k]) {
-      sprite_delay_main[k] = 160;
-      Hobo_SpawnBubble(k);
-    }
-    break;
-  }
-}
-
-void SpritePrep_Hobo_SpawnSmoke(int k) {  // 86be9d
-  SpriteSpawnInfo info;
-  int j = Sprite_SpawnDynamically(k, 0x2b, &info);
-  if (j >= 0) {
-    Sprite_SetSpawnedCoordinates(j, &info);
-    sprite_subtype2[j] = 0;
-    sprite_ignore_projectile[j] = 0;
-  }
-}
-
-void Sprite_Hobo_Bubble(int k) {  // 86beb4
-  Oam_AllocateFromRegionC(4);
-  SpriteDraw_SingleSmall(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  sprite_graphics[k] = (frame_counter >> 4 & 1) + 2;
-  if (!sprite_delay_aux1[k]) {
-    sprite_graphics[k]++;
-    Sprite_MoveZ(k);
-    if (!sprite_delay_main[k])
-      sprite_state[k] = 0;
-  }
-  if (sprite_delay_main[k] < 4)
-    sprite_graphics[k] = 3;
-}
-
-int Hobo_SpawnBubble(int k) {  // 86beed
-  SpriteSpawnInfo info;
-  int j = Sprite_SpawnDynamically(k, 0x2b, &info);
-  if (j >= 0) {
-    Sprite_SetSpawnedCoordinates(j, &info);
-    sprite_subtype2[j] = 1;
-    sprite_z_vel[j] = 2;
-    sprite_delay_main[j] = 96;
-    sprite_delay_aux1[j] = 96 >> 1;
-    sprite_ignore_projectile[j] = 96 >> 1;
-    sprite_flags2[j] = 0;
-  }
-  return j;
-}
-
-void Sprite_Hobo_Fire(int k) {  // 86bf15
-  SpriteDraw_SingleSmall(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  sprite_graphics[k] = frame_counter >> 3 & 1;
-  sprite_oam_flags[k] &= ~0x40;
-  if (!sprite_delay_main[k]) {
-    Hobo_SpawnSmoke(k);
-    sprite_delay_main[k] = 47;
-  }
-}
-
-void SpritePrep_Hobo_SpawnFire(int k) {  // 86bf4b
-  SpriteSpawnInfo info;
-  int j = Sprite_SpawnDynamically(k, 0x2b, &info);
-  if (j >= 0) {
-    Sprite_SetX(j, 0x194);
-    Sprite_SetY(j, 0x03f);
-    sprite_subtype2[j] = 2;
-    sprite_ignore_projectile[j] = 2;
-    sprite_flags2[j] = 0;
-    sprite_oam_flags[j] = sprite_oam_flags[j] & ~0xE | 2;
-  }
-}
-
-void Sprite_Hobo_Smoke(int k) {  // 86bf81
-  static const uint8 kHoboSmoke_OamFlags[4] = {0, 64, 128, 192};
-  sprite_graphics[k] = 6;
-  SpriteDraw_SingleSmall(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  Sprite_MoveXY(k);
-  Sprite_MoveZ(k);
-  sprite_oam_flags[k] = sprite_oam_flags[k] & 0x3f | kHoboSmoke_OamFlags[frame_counter >> 4 & 3];
-  if (!sprite_delay_main[k])
-    sprite_state[k] = 0;
-}
-
-void Hobo_SpawnSmoke(int k) {  // 86bfaf
-  SpriteSpawnInfo info;
-  int j = Sprite_SpawnDynamically(k, 0x2b, &info);
-  if (j >= 0) {
-    Sprite_SetSpawnedCoordinates(j, &info);
-    Sprite_SetY(j, info.r2_y - 4);
-    sprite_subtype2[j] = 3;
-    sprite_z_vel[j] = 7;
-    sprite_delay_main[j] = 96;
-    sprite_ignore_projectile[j] = 96;
-    sprite_flags2[j] = 0;
-  }
-}
-
-void Sprite_73_UncleAndPriest(int k) {  // 86bfe0
-  switch (sprite_E[k]) {
-  case 0:
-    Sprite_Uncle(k);
-    break;
-  case 1:
-    Sprite_Priest(k);
-    break;
-  case 2:
-    Sprite_SanctuaryMantle(k);
-    break;
-  }
-}
-
-void SpritePrep_UncleAndPriest_bounce(int k) {  // 86bfe5
-  if (BYTE(dungeon_room_index) == 18) {
-    Priest_SpawnMantle(k);
-    if (sram_progress_indicator >= 3)
-      sram_progress_flags |= 2;
-    if (sram_progress_flags & 2) {
-      sprite_state[k] = 0;
-      return;
-    }
-    sprite_E[k] = 1;
-    sprite_flags2[k] = sprite_flags2[k] & 0xf0 | 0x2;
-    sprite_flags4[k] = 3;
-    int j;
-    if (link_sword_type >= 2) {
-      sprite_D[k] = 4;
-      sprite_graphics[k] = 0;
-      j = 0;
-    } else {
-      sprite_D[k] = sprite_head_dir[k] = Sprite_DirectionToFaceLink(k, NULL) ^ 3;
-      if (follower_indicator == 1) {
-        sram_progress_flags |= 0x4;
-        save_ow_event_info[0x1b] |= 0x20;
-        sprite_delay_main[k] = 170;
-        j = 1;
-      } else {
-        j = 2;
-      }
-    }
-    sprite_subtype2[k] = j;
-    static const int16 kUncleAndSage_Y[3] = {0, -9, 0};
-    Sprite_SetX(k, Sprite_GetX(k) - 6);
-    Sprite_SetY(k, Sprite_GetY(k) + kUncleAndSage_Y[j]);
-    sprite_ignore_projectile[k]++;
-    byte_7FFE01 = 0;
-  } else if (BYTE(dungeon_room_index) == 4) {
-    if (!(sram_progress_flags & 0x10))
-      sprite_x_lo[k] += 8;
-    else
-      sprite_state[k] = 0;
-  } else {
-    if (!(sram_progress_flags & 1)) {
-      sprite_D[k] = 3;
-      sprite_subtype2[k] = 1;
-    } else {
-      sprite_state[k] = 0;
-    }
-  }
-}
-
-void SpritePrep_OldMan_bounce(int k) {  // 86bff9
-  sprite_ignore_projectile[k]++;
-  if (BYTE(dungeon_room_index) == 0xe4) {
-    sprite_subtype2[k] = 2;
-    return;
-  }
-  if (follower_indicator == 0) {
-    if (link_item_mirror == 2)
-      sprite_state[k] = 0;
-    follower_indicator = 4;
-    LoadFollowerGraphics();
-    follower_indicator = 0;
-  } else {
-    sprite_state[k] = 0;
-    LoadFollowerGraphics();
-  }
-}
-
-void Sprite_TutorialGuardOrBarrier(int k) {  // 86bffe
-  if (sprite_type[k] == 0x40) {
-    Sprite_EvilBarrier(k);
-    return;
-  }
-  int jbak = sprite_D[k];
-  if (sprite_delay_aux1[k])
-    sprite_D[k] = kSoldier_DirectionLockSettings[jbak];
-
-  sprite_graphics[k] = kSprite_TutorialEntities_Tab[sprite_D[k]];
-  TutorialSoldier_Draw(k);
-  sprite_D[k] = jbak;
-
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  Sprite_CheckDamageFromLink(k);
-
-  if (BYTE(overworld_area_index) == 0x1b && (sprite_y_lo[k] == 0x50 || sprite_y_lo[k] == 0x90)) {
-    Sprite_TutorialGuard_ShowMessageOnContact(k, sprite_y_lo[k] == 0x50 ? 0xB2 : 0xB3);
-  } else {
-    if (Sprite_TutorialGuard_ShowMessageOnContact(k, byte_7E0B69 + 0xf)) {
-      byte_7E0B69 = byte_7E0B69 != 6 ? byte_7E0B69 + 1 : 0;
-    }
-  }
-  Sprite_CheckDamageToAndFromLink(k);
-  if (((k ^ frame_counter) & 0x1f) == 0) {
-    uint8 jbak = sprite_D[k];
-    sprite_D[k] = Sprite_DirectionToFaceLink(k, NULL);
-    if (sprite_D[k] != jbak && !((sprite_D[k] ^ jbak) & 2))
-      sprite_delay_aux1[k] = 12;
-  }
-}
-
-void Sprite_F2_MedallionTablet(int k) {  // 86c00d
-  switch (sprite_subtype2[k]) {
-  case 0:
-    MedallionTablet_Main(k);
-    break;
-  case 1:
-    Sprite_DustCloud(k);
-    break;
-  }
-}
-
-void Sprite_33_RupeePull(int k) {  // 86c017
-  PrepOamCoordsRet info;
-  Sprite_PrepOamCoord(k, &info);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  if (Sprite_CheckIfLinkIsBusy())
-    return;
-  if (Sprite_CheckDamageToLink_same_layer(k)) {
-    link_need_for_pullforrupees_sprite = 1;
-    sprite_A[k] = 1;
-  } else {
-    if (sprite_A[k]) {
-      link_need_for_pullforrupees_sprite = 0;
-      if (link_state_bits & 1) {
-        sprite_state[k] = 0;
-        RupeePull_SpawnPrize(k);
-        Sprite_SpawnPoofGarnish(k);
-      }
-    }
-  }
-}
-
-void Sprite_14_ThievesTownGrate(int k) {  // 86c01c
-  PrepOamCoordsRet info;
-  Sprite_PrepOamCoord(k, &info);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  if (Sprite_CheckIfLinkIsBusy())
-    return;
-  if (Sprite_CheckDamageToLink_same_layer(k)) {
-    link_need_for_pullforrupees_sprite = 1;
-    sprite_A[k] = 1;
-  } else {
-    if (!sprite_A[k])
-      return;
-    link_need_for_pullforrupees_sprite = 0;
-    if (!(link_state_bits & 1))
-      return;
-    SpriteSfx_QueueSfx2WithPan(k, 0x1f);
-    OpenGargoylesDomain();
-    int j = Sprite_SpawnDustCloud(k);
-    Sprite_SetX(j, Sprite_GetX(k));
-    Sprite_SetY(j, Sprite_GetY(k));
-    sprite_state[k] = 0;
-  }
-}
-
-void SpritePrep_Snitch_bounce_2(int k) {  // 86c026
-  SpritePrep_Snitches(k);
-}
-
-void SpritePrep_Snitch_bounce_3(int k) {  // 86c030
-  SpritePrep_Snitches(k);
-}
-
-void Sprite_37_Waterfall(int k) {  // 86c03a
-  switch (sprite_subtype2[k]) {
-  case 0: Waterfall(k); break;
-  case 1: Sprite_BatCrash(k); break;
-  }
-}
-
-void Sprite_38_EyeStatue(int k) {  // 86c03f
-  if (!sprite_B[k]) {
-    PrepOamCoordsRet info;
-    Sprite_PrepOamCoord(k, &info);
-    if (Sprite_ReturnIfInactive(k))
-      return;
-    if (Sprite_DirectionToFaceLink(k, NULL) == 2 && sprite_unk2[k] == 9) {
-      dung_flag_statechange_waterpuzzle++;
-      sprite_B[k] = 1;
-    }
-  }
-}
-
-void Sprite_3A_MagicBat(int k) {  // 86c044
-  if (sprite_head_dir[k]) {
-    Sprite_MadBatterBolt(k);
-    return;
-  }
-
-  if (sprite_ai_state[k])
-    SpriteDraw_SingleLarge(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  Sprite_MoveXY(k);
-  Sprite_MoveZ(k);
-  switch(sprite_ai_state[k]) {
-  case 0:  // wait for summon
-    if (link_magic_consumption >= 2)
-      return;
-    if (!Sprite_CheckDamageToLink_same_layer(k))
-      return;
-    for (int i = 4; i >= 0; i--) {
-      if (ancilla_type[i] == 0x1a) {
-        Sprite_SpawnSuperficialBombBlast(k);
-        SpriteSfx_QueueSfx1WithPan(k, 0xd);
-        sprite_ai_state[k]++;
-        sprite_A[k] = 20;
-        flag_is_link_immobilized = 1;
-        sprite_oam_flags[k] |= 32;
-        return;
-      }
-    }
-    break;
-  case 1:  // RisingUp
-    if (!sprite_delay_main[k]) {
-      sprite_delay_main[k] = --sprite_A[k];
-      if (sprite_delay_main[k] != 1) {
-        static const int8 kMadBatter_RisingUp_XAccel[2] = {-8, 7};
-        sprite_z_vel[k] = sprite_delay_main[k] >> 2;
-        sprite_x_vel[k] += kMadBatter_RisingUp_XAccel[sprite_A[k] & 1];
-        sprite_graphics[k] ^= 1;
-      } else {
-        Sprite_ShowMessageUnconditional(0x110);
-        sprite_ai_state[k]++;
-        sprite_graphics[k] = 0;
-        sprite_z_vel[k] = 0;
-        sprite_x_vel[k] = 0;
-        sprite_delay_main[k] = 255;
-      }
-    }
-    break;
-  case 2: { // PseudoAttackPlayer
-    if (!sprite_delay_main[k]) {
-      sprite_ai_state[k]++;
-      sprite_delay_aux1[k] = 64;
-    }
-    static const int8 kMadBatter_PseudoAttack_OamFlags[8] = {0xa, 4, 2, 4, 2, 0xa, 4, 2};
-    sprite_oam_flags[k] = sprite_oam_flags[k] & ~0xE | kMadBatter_PseudoAttack_OamFlags[sprite_delay_main[k] >> 1 & 7];
-    if (sprite_delay_main[k] == 240)
-      Sprite_MagicBat_SpawnLightning(k);
-    break;
-  }
-  case 3:  // DoublePlayerMagicPower
-    if (!sprite_delay_aux1[k]) {
-      Sprite_ShowMessageUnconditional(0x111);
-      Palette_Restore_BG_And_HUD();
-      flag_update_cgram_in_nmi++;
-      sprite_ai_state[k]++;
-      link_magic_consumption = 1;
-      Hud_RefreshIcon();
-    } else if (sprite_delay_aux1[k] == 0x10) {
-      intro_times_pal_flash = 0x10;
-    }
-    break;
-  case 4:  // LaterBitches
-    Sprite_SpawnDummyDeathAnimation(k);
-    sprite_state[k] = 0;
-    flag_is_link_immobilized = 0;
-    break;
-  }
-}
-
-void SpritePrep_Zelda_bounce(int k) {  // 86c06c
-  if (link_sword_type >= 2) {
-    sprite_state[k] = 0;
-    return;
-  }
-  sprite_ignore_projectile[k]++;
-  sprite_D[k] = sprite_head_dir[k] = Sprite_DirectionToFaceLink(k, NULL) ^ 3;
-  uint8 bak0 = follower_indicator;
-  follower_indicator = 1;
-  LoadFollowerGraphics();
-  follower_indicator = bak0;
-
-  if (BYTE(dungeon_room_index) == 0x12) {
-    sprite_subtype2[k] = 2;
-    if (!(sram_progress_flags & 4)) {
-      sprite_state[k] = 0;
-    } else {
-      Sprite_SetX(k, Sprite_GetX(k) + 6);
-      Sprite_SetY(k, Sprite_GetY(k) + 15);
-      sprite_flags4[k] = 3;
-    }
-  } else {
-    sprite_subtype2[k] = 0;
-    if (follower_indicator == 1 || (sram_progress_flags & 4))
-      sprite_state[k] = 0;
-  }
-}
-
-void Sprite_78_MrsSahasrahla(int k) {  // 86c071
-  ElderWife_Draw(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  Sprite_BehaveAsBarrier(k);
-  switch (sprite_ai_state[k]) {
-  case 0:  // initial
-    if (link_sword_type < 2) {
-      if (Sprite_ShowSolicitedMessage(k, 0x2b) & 0x100)
-        sprite_ai_state[k] = 1;
-    } else {
-      Sprite_ShowSolicitedMessage(k, 0x2e);
-    }
-    sprite_graphics[k] = frame_counter >> 4 & 1;
-    break;
-  case 1:  // tell legend
-    Sprite_ShowMessageUnconditional(0x2c);
-    sprite_ai_state[k] = 2;
-    break;
-  case 2:  // loop until player not dumb
-    if (choice_in_multiselect_box == 0) {
-      sprite_ai_state[k] = 3;
-      Sprite_ShowMessageUnconditional(0x2d);
-    } else {
-      Sprite_ShowMessageUnconditional(0x2c);
-    }
-    break;
-  case 3:  // go away find old man
-    Sprite_ShowSolicitedMessage(k, 0x2d);
-    sprite_graphics[k] = frame_counter >> 4 & 1;
-    break;
-  }
-}
-
-void Sprite_16_Elder_bounce(int k) {  // 86c08a
-  Elder_Draw(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  Sprite_BehaveAsBarrier(k);
-  switch (sprite_subtype2[k]) {
-  case 0:
-    Sprite_Sahasrahla(k);
-    break;
-  case 1:
-    Sprite_Aginah(k);
-    break;
-  }
-}
-
-void SpritePrep_HeartPiece(int k) {  // 86c0a8
-  HeartUpgrade_CheckIfAlreadyObtained(k);
-}
-
-void Sprite_2D_TelepathicTile(int k) {  // 86c0b2
-  assert(0);
-}
-
-void Sprite_25_TalkingTree(int k) {  // 86c0d5
-  switch (sprite_subtype2[k]) {
-  case 0: TalkingTree_Mouth(k); break;
-  case 1: TalkingTree_Eye(k); break;
-  }
-}
-
-void Sprite_1C_Statue(int k) {  // 86c0e8
-  static const uint8 kMovableStatue_Dir[4] = {4, 6, 0, 2};
-  static const uint8 kMovableStatue_Joypad[4] = {1, 2, 4, 8};
-  static const int8 kMovableStatue_Xvel[4] = {-16, 16, 0, 0};
-  static const int8 kMovableStatue_Yvel[4] = {0, 0, -16, 16};
-  int j;
-  if (sprite_D[k]) {
-    sprite_D[k] = 0;
-    link_speed_setting = 0;
-    bitmask_of_dragstate = 0;
-  }
-  if (sprite_delay_main[k]) {
-    sprite_D[k] = 1;
-    bitmask_of_dragstate = 129;
-    link_speed_setting = 8;
-  }
-  MovableStatue_Draw(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  Statue_BlockSprites(k);
-  dung_flag_statechange_waterpuzzle = 0;
-  if (Statue_CheckForSwitch(k))
-    dung_flag_statechange_waterpuzzle = 1;
-  Sprite_MoveXY(k);
-  Sprite_Get16BitCoords(k);
-  Sprite_CheckTileCollision2(k);
-  Sprite_ZeroVelocity_XY(k);
-  if (Sprite_CheckDamageToLink_same_layer(k)) {
-    sprite_delay_main[k] = 7;
-    Sprite_RepelDash();
-    if (sprite_delay_aux1[k]) {
-      Sprite_NullifyHookshotDrag();
-      return;
-    }
-    j = Sprite_DirectionToFaceLink(k, NULL);
-    sprite_x_vel[k] = kMovableStatue_Xvel[j];
-    sprite_y_vel[k] = kMovableStatue_Yvel[j];
-  } else {
-    if (!sprite_delay_main[k])
-      sprite_delay_aux1[k] = 13;
-    if ((uint16)(cur_sprite_x - link_x_coord + 16) < 35 &&
-        (uint16)(cur_sprite_y - link_y_coord + 12) < 36 &&
-        link_direction_facing == kMovableStatue_Dir[j = Sprite_DirectionToFaceLink(k, NULL)] &&
-        !link_is_running) {
-      link_is_near_moveable_statue = 1;
-      sprite_A[k] = 1;
-      if (!(link_grabbing_wall & 2) || !(kMovableStatue_Joypad[j] & joypad1H_last) || (link_x_vel | link_y_vel) == 0)
-        return;
-      j ^= 1;
-      sprite_x_vel[k] = kMovableStatue_Xvel[j];
-      sprite_y_vel[k] = kMovableStatue_Yvel[j];
-    } else {
-      if (sprite_A[k]) {
-        sprite_A[k] = 0;
-        link_speed_setting = 0;
-        link_grabbing_wall = 0;
-        link_is_near_moveable_statue = 0;
-        link_cant_change_direction &= ~1;
-      }
-      return;
-    }
-  }
-  if (!(link_grabbing_wall & 2))
-    Sprite_NullifyHookshotDrag();
-  if (!(sprite_wallcoll[k] & 15) && !sprite_delay_aux4[k]) {
-    SpriteSfx_QueueSfx2WithPan(k, 0x22);
-    sprite_delay_aux4[k] = 8;
-  }
-}
-
-bool Statue_CheckForSwitch(int k) {  // 86c203
-  static const int8 kMovableStatue_SwitchX[4] = {3, 12, 3, 12};
-  static const int8 kMovableStatue_SwitchY[4] = {3, 3, 12, 12};
-  for (int j = 3; j >= 0; j--) {
-    uint16 x = Sprite_GetX(k) + kMovableStatue_SwitchX[j];
-    uint16 y = Sprite_GetY(k) + kMovableStatue_SwitchY[j];
-    uint8 t = GetTileAttribute(sprite_floor[k], &x, y);
-    if (t != 0x23 && t != 0x24 && t != 0x25 && t != 0x3b)
-      return false;
-  }
-  return true;
-}
-
-void MovableStatue_Draw(int k) {  // 86c264
-  static const DrawMultipleData kMovableStatue_Dmd[3] = {
-    {0, -8, 0x00c2, 0},
-    {8, -8, 0x40c2, 0},
-    {0,  0, 0x00c0, 2},
-  };
-  Sprite_DrawMultiplePlayerDeferred(k, &kMovableStatue_Dmd[0], 3, NULL);
-}
-
-void Statue_BlockSprites(int k) {  // 86c277
-  for (int j = 15; j >= 0; j--) {
-    if (sprite_type[j] == 0x1c || j == k || (j ^ frame_counter) & 1 || sprite_state[j] < 9)
-      continue;
-    int x = Sprite_GetX(j), y = Sprite_GetY(j);
-    if ((uint16)(cur_sprite_x - x + 12) < 24 &&
-        (uint16)(cur_sprite_y - y + 12) < 36) {
-      sprite_F[j] = 4;
-      ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLocation(k, x, y, 32);
-      sprite_y_recoil[j] = pt.y;
-      sprite_x_recoil[j] = pt.x;
-    }
-  }
-}
-
-void Sprite_1D_FluteQuest(int k) {  // 86c2e5
-  PrepOamCoordsRet info;
-  Sprite_PrepOamCoord(k, &info);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  if (BYTE(overworld_screen_index) == 0x18) {
-    if (link_item_flute == 3)
-      sprite_state[k] = 0;
-  } else {
-    if (link_item_flute & 2)
-      sprite_state[k] = 0;
-  }
-}
-
-void Sprite_72_FairyPond(int k) {  // 86c319
-  if (sprite_A[k]) {
-    if (!--sprite_C[k])
-      sprite_state[k] = 0;
-    sprite_graphics[k] = sprite_C[k] >> 3;
-    Oam_AllocateFromRegionC(4);
-    SpriteDraw_SingleSmall(k);
-    return;
-  }
-  if (sprite_B[k]) {
-    FaerieQueen_Draw(k);
-    sprite_graphics[k] = frame_counter >> 4 & 1;
-    if (frame_counter & 15)
-      return;
-    SpriteSpawnInfo info;
-    int j = Sprite_SpawnDynamically(k, 0x72, &info);
-    if (j >= 0) {
-      Sprite_SetX(j, info.r0_x + kWishPond_X[GetRandomNumber() & 7]);
-      Sprite_SetY(j, info.r2_y + kWishPond_Y[GetRandomNumber() & 7]);
-      sprite_C[j] = 31;
-      sprite_A[j] = 31;
-      sprite_flags2[j] = 0;
-      sprite_flags3[j] = 0x48;
-      sprite_oam_flags[j] = 0x48 & 0xf;
-      sprite_B[j] = 1;
-    }
-    return;
-  }
-  PrepOamCoordsRet info;
-  Sprite_PrepOamCoord(k, &info);
-  Sprite_WishPond2(k);
-}
-
-void Sprite_WishPond2(int k) {  // 86c41d
-  WishPond2_Draw(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  if (BYTE(dungeon_room_index) != 21)
-    Sprite_WishPond3(k);
-  else
-    Sprite_HappinessPond(k);
-}
-
-void Sprite_HappinessPond(int k) {  // 86c44c
-  static const uint8 kHappinessPondCost[4] = {5, 20, 25, 50};
-  static const uint8 kHappinessPondCostHex[4] = {5, 0x20, 0x25, 0x50};
-  switch (sprite_ai_state[k]) {
-  case 0:
-    flag_is_link_immobilized = 0;
-    if (sprite_delay_main[k] || Sprite_CheckIfLinkIsBusy())
-      return;
-    if (Sprite_ShowMessageOnContact(k, 0x89) & 0x100) {
-      sprite_ai_state[k] = 1;
-      Link_ResetProperties_A();
-      Ancilla_TerminateSparkleObjects();
-      link_direction_facing = 0;
-    }
-    break;
-  case 1:
-    if (choice_in_multiselect_box == 0) {
-      int i = (link_bomb_upgrades | link_arrow_upgrades) != 0;
-      sprite_graphics[k] = i * 2;
-      WORD(dialogue_number[0]) = WORD(kHappinessPondCostHex[i * 2]);
-      Sprite_ShowMessageUnconditional(0x14e);
-      sprite_ai_state[k] = 2;
-      flag_is_link_immobilized = 1;
-    } else {
-show_later_msg:
-      Sprite_ShowMessageUnconditional(0x14c);
-      sprite_ai_state[k] = 0;
-      sprite_delay_main[k] = 255;
-    }
-    break;
-  case 2: {
-    int i = sprite_graphics[k] + choice_in_multiselect_box;
-    dialogue_number[1] = kHappinessPondCostHex[i];
-    if (link_rupees_goal < kHappinessPondCost[i]) {
-      goto show_later_msg;
-    } else {
-      sprite_D[k] = kHappinessPondCost[i];
-      sprite_head_dir[k] = i;
-      sprite_ai_state[k] = 3;
-    }
-    break;
-  }
-  case 3: {
-    sprite_delay_main[k] = 80;
-    int i = sprite_D[k];
-    link_rupees_goal -= i;
-    link_rupees_in_pond += i;
-    AddHappinessPondRupees(sprite_head_dir[k]);
-    if (link_rupees_in_pond >= 100) {
-      link_rupees_in_pond -= 100;
-      sprite_ai_state[k] = 5;
-      return;
-    }
-    dialogue_number[0] = (link_rupees_in_pond / 10) * 16 + (link_rupees_in_pond % 10);
-    sprite_ai_state[k] = 4;
-    break;
-  }
-  case 4:
-    if (sprite_delay_main[k] == 0) {
-      Sprite_ShowMessageUnconditional(0x94);
-      sprite_ai_state[k] = 13;
-    }
-    break;
-  case 5:
-    if (sprite_delay_main[k] == 0) {
-      SpriteSpawnInfo info;
-      int j = Sprite_SpawnDynamically(k, 0x72, &info);
-      assert(j >= 0);
-      Sprite_SetX(j, info.r0_x);
-      Sprite_SetY(j, info.r2_y - 80);
-      music_control = 0x1b;
-      last_music_control = 0;
-      sprite_B[j] = 1;
-      Palette_AssertTranslucencySwap();
-      PaletteFilter_WishPonds();
-      sprite_E[k] = j;
-      sprite_ai_state[k] = 6;
-      sprite_delay_main[k] = 255;
-    }
-    break;
-  case 6:
-    if (!(frame_counter & 7)) {
-      PaletteFilter_SP5F();
-      if (!BYTE(palette_filter_countdown)) {
-        Sprite_ShowMessageUnconditional(0x95);
-        Palette_RevertTranslucencySwap();
-        TS_copy = 0;
-        CGADSUB_copy = 0x20;
-        flag_update_cgram_in_nmi++;
-        sprite_ai_state[k] = 7;
-      }
-    }
-    break;
-  case 7:
-    if (!choice_in_multiselect_box)
-      sprite_ai_state[k] = 8;
-    else
-      sprite_ai_state[k] = 12;
-    break;
-  case 8: {
-    static const uint8 kMaxBombsForLevelHex[8] = {0x10, 0x15, 0x20, 0x25, 0x30, 0x35, 0x40, 0x50};
-    int i = link_bomb_upgrades + 1;
-    if (i != 8) {
-      link_bomb_upgrades = i;
-      dialogue_number[0] = link_bomb_filler = kMaxBombsForLevelHex[i];
-      Sprite_ShowMessageUnconditional(0x96);
-    } else {
-      link_rupees_goal += 100;
-      Sprite_ShowMessageUnconditional(0x98);
-    }
-    sprite_ai_state[k] = 9;
-    break;
-  }
-  case 9:
-    Palette_AssertTranslucencySwap();
-    TS_copy = 2;
-    CGADSUB_copy = 0x30;
-    flag_update_cgram_in_nmi++;
-    sprite_ai_state[k] = 10;
-    break;
-  case 10:
-    if (!(frame_counter & 7)) {
-      PaletteFilter_SP5F();
-      if (BYTE(palette_filter_countdown) == 30) {
-        sprite_state[sprite_E[k]] = 0;
-      } else if (BYTE(palette_filter_countdown) == 0) {
-        sprite_ai_state[k] = 11;
-      }
-    }
-    break;
-  case 11:
-    PaletteFilter_RestoreSP5F();
-    Palette_RevertTranslucencySwap();
-    sprite_ai_state[k] = 0;
-    sprite_delay_main[k] = 255;
-    break;
-  case 12: {
-    static const uint8 kMaxArrowsForLevelHex[8] = {0x30, 0x35, 0x40, 0x45, 0x50, 0x55, 0x60, 0x70};
-    int i = link_arrow_upgrades + 1;
-    if (i != 8) {
-      link_arrow_upgrades = i;
-      dialogue_number[0] = link_arrow_filler = kMaxArrowsForLevelHex[i];
-      Sprite_ShowMessageUnconditional(0x97);
-    } else {
-      link_rupees_goal += 100;
-      Sprite_ShowMessageUnconditional(0x98);
-    }
-    sprite_ai_state[k] = 9;
-    break;
-  }
-  case 13:
-    Sprite_ShowMessageUnconditional(0x154);
-    sprite_ai_state[k] = 14;
-    break;
-  case 14: {
-    static const uint16 kHappinessPondLuckMsg[4] = {0x150, 0x151, 0x152, 0x153};
-    static const uint8 kHappinessPondLuck[4] = {1, 0, 0, 2};
-    int i = GetRandomNumber() & 3;
-    item_drop_luck = kHappinessPondLuck[i];
-    luck_kill_counter = 0;
-    Sprite_ShowMessageUnconditional(kHappinessPondLuckMsg[i]);
-    sprite_ai_state[k] = 0;
-    sprite_delay_main[k] = 255;
-    break;
-  }
-  }
-}
-
-void WishPond2_Draw(int k) {  // 86c4b5
-  static const DrawMultipleData kWishPond2_Dmd[8] = {
-    {32, -64, 0x0024, 0},
-    {32, -56, 0x0034, 0},
-    {32, -64, 0x0024, 0},
-    {32, -56, 0x0034, 0},
-    {32, -64, 0x0024, 2},
-    {32, -64, 0x0024, 2},
-    {32, -64, 0x0024, 2},
-    {32, -64, 0x0024, 2},
-  };
-  if (BYTE(dungeon_room_index) == 21)
-    return;
-  uint8 t = sprite_ai_state[k];
-  if (t != 5 && t != 6 && t != 11 && t != 12)
-    return;
-  int g = sprite_graphics[k];
-  uint8 f = kWishPond2_OamFlags[g];
-  if (f == 0xff)
-    f = 5;
-  sprite_oam_flags[k] = (f & 7) * 2;
-  Sprite_DrawMultiple(k, &kWishPond2_Dmd[(kReceiveItem_Tab1[g] >> 1) * 4], 4, NULL);
-}
-
-void FaerieQueen_Draw(int k) {  // 86cb26
-  static const uint8 kFaerieQueen_Draw_X[24] = {
-    0, 16, 0, 8, 16, 24, 0,  8, 16, 24, 0, 16, 0, 16, 0, 8, 16, 24, 0, 8, 16, 24, 0, 16,
-  };
-  static const uint8 kFaerieQueen_Draw_Y[24] = {
-    0,  0, 16, 16, 16, 16, 24, 24, 24, 24, 32, 32, 0, 0, 16, 16, 16, 16, 24, 24, 24, 24, 32, 32,
-  };
-  static const uint8 kFaerieQueen_Draw_Char[24] = {
-    0xc7, 0xc7, 0xcf, 0xca, 0xca, 0xcf, 0xdf, 0xda, 0xda, 0xdf, 0xcb, 0xcb, 0xcd, 0xcd, 0xc9, 0xca,
-    0xca, 0xc9, 0xd9, 0xda, 0xda, 0xd9, 0xcb, 0xcb,
-  };
-  static const uint8 kFaerieQueen_Draw_Flags[24] = {
-    0, 0x40, 0, 0, 0x40, 0x40, 0, 0, 0x40, 0x40, 0, 0x40, 0, 0x40, 0, 0, 0x40, 0x40, 0, 0, 0x40, 0x40, 0, 0x40,
-  };
-  static const uint8 kFaerieQueen_Draw_Big[24] = {
-    2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2,
-  };
-  static const DrawMultipleData kFaerieQueen_Dmd[20] = {
-    { 0,  0, 0x00e9, 2},
-    {16,  0, 0x40e9, 2},
-    { 0,  0, 0x00e9, 2},
-    {16,  0, 0x40e9, 2},
-    { 0,  0, 0x00e9, 2},
-    {16,  0, 0x40e9, 2},
-    { 0, 16, 0x00eb, 2},
-    {16, 16, 0x40eb, 2},
-    { 0, 32, 0x00ed, 2},
-    {16, 32, 0x40ed, 2},
-    { 0,  0, 0x00ef, 0},
-    {24,  0, 0x40ef, 0},
-    { 0,  8, 0x00ff, 0},
-    {24,  8, 0x40ff, 0},
-    { 0,  0, 0x00e9, 2},
-    {16,  0, 0x40e9, 2},
-    { 0, 16, 0x00eb, 2},
-    {16, 16, 0x40eb, 2},
-    { 0, 32, 0x00ed, 2},
-    {16, 32, 0x40ed, 2},
-  };
-  if (!savegame_is_darkworld) {
-    PrepOamCoordsRet info;
-    if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
-      return;
-    OamEnt *oam = GetOamCurPtr();
-    int g = sprite_graphics[k];
-    for (int i = 11; i >= 0; i--, oam++) {
-      int j = g * 12 + i;
-      SetOamPlain(oam, kFaerieQueen_Draw_X[j] + info.x, kFaerieQueen_Draw_Y[j] + info.y,
-                   kFaerieQueen_Draw_Char[j], info.flags | kFaerieQueen_Draw_Flags[j], kFaerieQueen_Draw_Big[j]);
-    }
-    Sprite_CorrectOamEntries(k, 11, 0xff);
-  } else {
-    Sprite_DrawMultiple(k, &kFaerieQueen_Dmd[sprite_graphics[k] * 10], 10, NULL);
-  }
-}
-
-void Sprite_71_Leever(int k) {  // 86cba2
-  static const uint8 kLeever_EmergeGfx[16] = {10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, 1, 2, 1, 0, 0};
-  static const uint8 kLeever_AttackGfx[4] = {9, 10, 11, 12};
-  static const uint8 kLeever_AttackSpd[2] = {12, 8};
-  static const uint8 kLeever_SubmergeGfx[16] = {10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, 1, 2, 1, 0, 0};
-
-  if (sprite_ai_state[k])
-    Leever_Draw(k);
-  else {
-    PrepOamCoordsRet info;
-    Sprite_PrepOamCoord(k, &info);
-  }
-  if (sprite_pause[k])
-    sprite_state[k] = 8;
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  if (Sprite_ReturnIfRecoiling(k))
-    return;
-  switch(sprite_ai_state[k]) {
-  case 0:  // under sand
-    sprite_ignore_projectile[k] = sprite_delay_main[k];
-    if (!sprite_delay_main[k]) {
-      sprite_ai_state[k] = 1;
-      sprite_delay_main[k] = 127;
-    } else {
-      Sprite_ApplySpeedTowardsLink(k, 16);
-      Sprite_MoveXY(k);
-      Sprite_CheckTileCollision2(k);
-    }
-    break;
-  case 1:  // emerge
-    sprite_ignore_projectile[k] = sprite_delay_main[k];
-    if (!sprite_delay_main[k]) {
-      sprite_ai_state[k]++;
-      sprite_delay_main[k] = (GetRandomNumber() & 63) + 160;
-      Sprite_ZeroVelocity_XY(k);
-    } else {
-      sprite_graphics[k] = kLeever_EmergeGfx[sprite_delay_main[k] >> 3];
-    }
-    break;
-  case 2:  // attack
-    Sprite_CheckDamageToAndFromLink(k);
-    if (!sprite_delay_main[k]) {
-stop_attack:
-      sprite_ai_state[k]++;
-      sprite_delay_main[k] = 127;
-    } else {
-      if (!(sprite_subtype2[k] & 7))
-        Sprite_ApplySpeedTowardsLink(k, kLeever_AttackSpd[sprite_A[k]]);
-      Sprite_MoveXY(k);
-      if (Sprite_CheckTileCollision(k))
-        goto stop_attack;
-      sprite_graphics[k] = kLeever_AttackGfx[++sprite_subtype2[k] >> 2 & 3];
-    }
-    break;
-  case 3:  // submerge
-    sprite_ignore_projectile[k] = sprite_delay_main[k];
-    if (!sprite_delay_main[k]) {
-      sprite_ai_state[k] = 0;
-      sprite_delay_main[k] = (GetRandomNumber() & 31) + 64;
-    } else {
-      sprite_graphics[k] = kLeever_SubmergeGfx[sprite_delay_main[k] >> 3 ^ 15];
-    }
-    break;
-  }
-
-}
-
-void Leever_Draw(int k) {  // 86ce45
-  static const uint8 kLeever_Draw_Num[14] = {1, 1, 1, 3, 3, 3, 3, 3, 3, 1, 1, 1, 1, 1};
-  static const int8 kLeever_Draw_X[56] = {
-    2, 6, 6, 6, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 0, 8,
-    0, 8, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8,
-    0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, 0, 0, 0, 0, 0,
-  };
-  static const int8 kLeever_Draw_Y[56] = {
-    8,  8,  8, 8, 8,  8,  8, 8, 8,  8,  8, 8, 5,  5,  8, 8,
-    5,  5,  8, 8, 2,  2,  8, 8, 1,  1,  8, 8, 0,  0,  8, 8,
-    -1, -1,  8, 8, 8, -2, -2, 0, 8, -2, -2, 0, 8, -2, -2, 0,
-    8, -2, -2, 0, 8, -2, -2, 0,
-  };
-  static const uint8 kLeever_Draw_Char[56] = {
-    0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x38, 0x38, 0x38, 0x38,    8, 9, 0x28, 0x28,
-    8,    9, 0xd9, 0xd9,    8,    8, 0xd8, 0xd8,    8,    8, 0xda, 0xda,    6, 6, 0xd9, 0xd9,
-    0x26, 0x26, 0xd8, 0xd8, 0x6c,    6,    6,    0, 0x6c, 0x26, 0x26,    0, 0x6c, 6,    6,    0,
-    0x6c, 0x26, 0x26,    0, 0x6c,    8,    8,    0,
-  };
-  static const uint8 kLeever_Draw_Flags[56] = {
-    1, 0x41, 0x41, 0x41, 1, 0x41, 0x41, 0x41, 1, 0x41, 0x41, 0x41, 1, 1, 1, 0x41,
-    1,    1,    0, 0x40, 1,    1,    0, 0x40, 1,    1,    0, 0x40, 1, 1, 0, 0x40,
-    0,    1,    0, 0x40, 6, 0x41, 0x41,    0, 6, 0x41, 0x41,    0, 6, 1, 1,    0,
-    6,    1,    1,    0, 6,    1,    1,    0,
-  };
-  static const uint8 kLeever_Draw_Big[56] = {
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, 0, 2, 2, 0, 0, 2, 2, 0, 0, 2, 2, 0, 0,
-    2, 2, 0, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0,
-    2, 2, 2, 0, 2, 2, 2, 0,
-  };
-  PrepOamCoordsRet info;
-  if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
-    return;
-  OamEnt *oam = GetOamCurPtr();
-  int d = sprite_graphics[k];
-  for (int i = kLeever_Draw_Num[d]; i >= 0; i--, oam++) {
-    int j = d * 4 + i;
-    uint8 charnum = kLeever_Draw_Char[j];
-    uint8 f = info.flags;
-    if (charnum >= 0x60 || charnum == 0x28 || charnum == 0x38)
-      f &= 0xf0;
-    SetOamHelper0(oam, info.x + kLeever_Draw_X[j], info.y + kLeever_Draw_Y[j],
-                  charnum, kLeever_Draw_Flags[j] | f, kLeever_Draw_Big[j]);
-  }
-}
-
-void Sprite_D8_Heart(int k) {  // 86cec0
-  if (SpriteDraw_AbsorbableTransient(k, true))
-    return;
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  Sprite_CheckAbsorptionByPlayer(k);
-
-  // Avoid calling Sprite_HandleAbsorptionByPlayer twice, it's called
-  // also from within Sprite_HandleDraggingByAncilla
-  if (sprite_state[k] == 0 && (enhanced_features0 & kFeatures0_MiscBugFixes))
-    return;
-
-  if (Sprite_HandleDraggingByAncilla(k))
-    return;
-  Sprite_MoveXY(k);
-  Sprite_MoveZ(k);
-  if (sign8(sprite_z[k])) {
-    sprite_z[k] = 0;
-    sprite_ai_state[k]++;
-    sprite_graphics[k] = 0;
-  }
-  sprite_oam_flags[k] &= ~0x40;
-  if (!sign8(sprite_x_vel[k]))
-    sprite_oam_flags[k] |= 0x40;
-  switch (sprite_ai_state[k] >= 3 ? 3 : sprite_ai_state[k]) {
-  case 0:  // InitializeAscent
-    sprite_ai_state[k]++;
-    sprite_delay_main[k] = 18;
-    sprite_z_vel[k] = 20;
-    sprite_graphics[k] = 1;
-    sprite_D[k] = 0;
-    break;
-  case 1:  // BeginDescending
-    if (sprite_delay_main[k] != 0) {
-      sprite_z_vel[k]--;
-    } else {
-      sprite_ai_state[k]++;
-      sprite_z_vel[k] = 253;
-      sprite_x_vel[k] = 0;
-    }
-    break;
-  case 2:  // GlideGroundward
-    if (sprite_delay_main[k] == 0) {
-      int j = sprite_D[k] & 1;
-      sprite_x_vel[k] += kHeartRefill_AccelX[j];
-      if (sprite_x_vel[k] == (uint8)kHeartRefill_VelTarget[j]) {
-        sprite_D[k]++;
-        sprite_delay_main[k] = 8;
-      }
-    }
-    break;
-  case 3:  // Grounded
-    sprite_z_vel[k] = sprite_x_vel[k] = sprite_y_vel[k] = 0;
-    break;
-  }
-}
-
-void Sprite_E3_Fairy(int k) {  // 86cf94
-  sprite_ignore_projectile[k] = 1;
-  if (!sprite_ai_state[k]) {
-    if (!player_is_indoors)
-      sprite_obj_prio[k] = 48;
-    if (SpriteDraw_AbsorbableTransient(k, true))
-      return;
-  }
-  Fairy_CheckIfTouchable(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  switch (sprite_ai_state[k]) {
-  case 0: // normal
-    if (!sprite_delay_aux4[k]) {
-      if (Sprite_CheckDamageToLink(k)) {
-        Sprite_HandleAbsorptionByPlayer(k);
-      } else if (Sprite_CheckDamageFromLink(k) & kCheckDamageFromPlayer_Ne) {
-        sprite_ai_state[k]++;
-        Sprite_ShowMessageUnconditional(0xc9);
-        return;
-      }
-    }
-    // Avoid calling Sprite_HandleAbsorptionByPlayer twice, it's called
-    // also from within Sprite_HandleDraggingByAncilla
-    if (sprite_state[k] == 0 && (enhanced_features0 & kFeatures0_MiscBugFixes))
-      return;
-    if (Sprite_HandleDraggingByAncilla(k))
-      return;
-    Faerie_HandleMovement(k);
-    break;
-  case 1: // capture
-    if (choice_in_multiselect_box == 0) {
-      int j = Sprite_Find_EmptyBottle();
-      if (j >= 0) {
-        link_bottle_info[j] = 6;
-        Hud_RefreshIcon();
-        sprite_state[k] = 0;
-        return;
-      }
-      Sprite_ShowMessageUnconditional(0xca);
-    }
-    sprite_delay_aux4[k] = 48;
-    sprite_ai_state[k] = 0;
-    break;
-  }
-}
-
-void Fairy_CheckIfTouchable(int k) {  // 86d011
-  if (submodule_index == 2 && (dialogue_message_index == 0xc9 || dialogue_message_index == 0xca))
-    sprite_delay_aux4[k] = 40;
-}
-
-void Sprite_E4_SmallKey(int k) {  // 86d032
-  if (dung_savegame_state_bits & (kAbsorbBigKey[sprite_die_action[k]] << 8)) {
-    sprite_state[k] = 0;
-    return;
-  }
-  Sprite_DrawRippleIfInWater(k);
-  if (SpriteDraw_AbsorbableTransient(k, false))
-    return;
-  Sprite_Absorbable_Main(k);
-}
-
-void Sprite_D9_GreenRupee(int k) {  // 86d04a
-  Sprite_DrawRippleIfInWater(k);
-  if (SpriteDraw_AbsorbableTransient(k, true))
-    return;
-  Sprite_Absorbable_Main(k);
-}
-
-void Sprite_Absorbable_Main(int k) {  // 86d051
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  Sprite_MoveZ(k);
-  Sprite_MoveXY(k);
-  if (sprite_delay_aux3[k] == 0) {
-    Sprite_CheckTileCollision2(k);
-    Sprite_BounceOffWall(k);
-  }
-  sprite_z_vel[k] -= 2;
-  if (sign8(sprite_z[k])) {
-    sprite_z[k] = 0;
-    sprite_x_vel[k] = (int8)sprite_x_vel[k] >> 1;
-    sprite_y_vel[k] = (int8)sprite_y_vel[k] >> 1;
-    uint8 t = -sprite_z_vel[k];
-    t >>= 1;
-    if (t < 9) {
-      sprite_z_vel[k] = sprite_x_vel[k] = sprite_y_vel[k] = 0;
-    } else {
-      sprite_z_vel[k] = t;
-      if (sprite_I[k] == 8 || sprite_I[k] == 9) {
-        sprite_z_vel[k] = 0;
-        int j = Sprite_SpawnSmallSplash(k);
-        if (j >= 0 && sprite_flags3[k] & 0x20) {
-          // wtf carry propagation
-          Sprite_SetX(j, Sprite_GetX(j) - 4);
-          Sprite_SetY(j, Sprite_GetY(j) - 4);
-        }
-      } else {
-        if (sprite_type[k] >= 0xe4 && player_is_indoors)
-          SpriteSfx_QueueSfx2WithPan(k, 5);
-      }
-    }
-  }
-  if (Sprite_HandleDraggingByAncilla(k))
-    return;
-  Sprite_CheckAbsorptionByPlayer(k);
-}
-
-void Sprite_08_Octorok(int k) {  // 86d377
-  static const uint8 kOctorock_Tab0[20] = {
-    0, 2, 2, 2, 1, 1, 1, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 1, 1, 0,
-  };
-  static const uint8 kOctorock_Tab1[10] = {2, 2, 2, 2, 2, 2, 2, 2, 1, 0};
-  static const uint8 kOctorock_NextDir[4] = {2, 3, 1, 0};
-  static const uint8 kOctorock_Dir[4] = {3, 2, 0, 1};
-  static const int8 kOctorock_Xvel[4] = {24, -24, 0, 0};
-  static const int8 kOctorock_Yvel[4] = {0, 0, 24, -24};
-  static const uint8 kOctorock_OamFlags[4] = {0x40, 0, 0, 0};
-
-  int j = sprite_D[k];
-  if (sprite_delay_aux1[k])
-    sprite_D[k] = kOctorock_Dir[j];
-  sprite_oam_flags[k] = sprite_oam_flags[k] & ~0x40 | kOctorock_OamFlags[j] | (sprite_graphics[k] == 7 ? 0x40 : 0);
-  Octorock_Draw(k);
-  sprite_D[k] = j;
-
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  if (Sprite_ReturnIfRecoiling(k))
-    return;
-  Sprite_MoveXY(k);
-  Sprite_CheckDamageToAndFromLink(k);
-  if (!(sprite_ai_state[k] & 1)) {
-    sprite_graphics[k] = ++sprite_subtype2[k] >> 3 & 3 | (sprite_D[k] & 2) << 1;
-    if (!sprite_delay_main[k]) {
-      sprite_ai_state[k]++;
-      sprite_delay_main[k] = sprite_type[k] == 8 ? 60 : 160;
-    } else {
-      j = sprite_D[k];
-      sprite_x_vel[k] = kOctorock_Xvel[j];
-      sprite_y_vel[k] = kOctorock_Yvel[j];
-      if (Sprite_CheckTileCollision(k))
-        sprite_D[k] ^= 1;
-    }
-    return;
-  } else {
-    Sprite_ZeroVelocity_XY(k);
-    if (!sprite_delay_main[k]) {
-      sprite_ai_state[k]++;
-      sprite_delay_main[k] = (GetRandomNumber() & 0x3f) + 48;
-      sprite_D[k] = sprite_delay_main[k] & 3;
-    } else {
-      switch (sprite_type[k]) {
-      case 8:  // normal
-        j = sprite_delay_main[k];
-        if (j == 28)
-          Octorok_FireLoogie(k);
-        sprite_C[k] = kOctorock_Tab0[j >> 3];
-        break;
-      case 10:  // four shooter
-        j = sprite_delay_main[k];
-        if (j < 128) {
-          if (!(j & 15))
-            sprite_D[k] = kOctorock_NextDir[sprite_D[k]];
-          if ((j & 15) == 8)
-            Octorok_FireLoogie(k);
-        }
-        sprite_C[k] = kOctorock_Tab1[j >> 4];
-        break;
-      }
-    }
-  }
-}
-
-void Octorok_FireLoogie(int k) {  // 86d4cd
-  static const int8 kOctorock_Spit_X[4] = {12, -12, 0, 0};
-  static const int8 kOctorock_Spit_Y[4] = {4, 4, 12, -12};
-  static const int8 kOctorock_Spit_Xvel[4] = {44, -44, 0, 0};
-  static const int8 kOctorock_Spit_Yvel[4] = {0, 0, 44, -44};
-  SpriteSpawnInfo info;
-  SpriteSfx_QueueSfx2WithPan(k, 0x7);
-  int j = Sprite_SpawnDynamically(k, 0xc, &info);
-  if (j >= 0) {
-    int i = sprite_D[k];
-    Sprite_SetX(j, info.r0_x + kOctorock_Spit_X[i]);
-    Sprite_SetY(j, info.r2_y + kOctorock_Spit_Y[i]);
-    sprite_x_vel[j] = kOctorock_Spit_Xvel[i];
-    sprite_y_vel[j] = kOctorock_Spit_Yvel[i];
-  }
-}
-
-void Octorock_Draw(int k) {  // 86d54a
-  static const int8 kOctorock_Draw_X[9] = {8, 0, 4, 8, 0, 4, 9, -1, 4};
-  static const int8 kOctorock_Draw_Y[9] = {6, 6, 9, 6, 6, 9, 6, 6, 9};
-  static const uint8 kOctorock_Draw_Char[9] = {0xbb, 0xbb, 0xba, 0xab, 0xab, 0xaa, 0xa9, 0xa9, 0xb9};
-  static const uint8 kOctorock_Draw_Flags[9] = {0x65, 0x25, 0x25, 0x65, 0x25, 0x25, 0x65, 0x25, 0x25};
-  PrepOamCoordsRet info;
-  if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
-    return;
-  if (sprite_D[k] != 3) {
-    OamEnt *oam = GetOamCurPtr();
-    int j = sprite_C[k] * 3 + sprite_D[k];
-    SetOamHelper0(oam, info.x + kOctorock_Draw_X[j], info.y + kOctorock_Draw_Y[j],
-                  kOctorock_Draw_Char[j], kOctorock_Draw_Flags[j] | info.flags, 0);
-  }
-  oam_cur_ptr += 4;
-  oam_ext_cur_ptr++;
-  sprite_flags2[k]--;
-  Sprite_PrepAndDrawSingleLargeNoPrep(k, &info);
-  sprite_flags2[k]++;
-}
-
-void Sprite_0C_OctorokStone(int k) {  // 86d5b9
-  if (sprite_state[k] == 6) {
-    SpriteDraw_OctorokStoneCrumbling(k);
-    if (Sprite_ReturnIfPaused(k))
-      return;
-    if (sprite_delay_main[k] == 30)
-      SpriteSfx_QueueSfx2WithPan(k, 0x1f);
-  } else {
-    SpriteDraw_SingleLarge(k);
-    if (Sprite_ReturnIfInactive(k))
-      return;
-    Sprite_CheckDamageToLink(k);
-    Sprite_MoveXY(k);
-    if (!((k ^ frame_counter) & 3) && Sprite_CheckTileCollision(k))
-      Sprite_Func3(k);
-  }
-}
-
-void SpriteDraw_OctorokStoneCrumbling(int k) {  // 86d643
-  static const int8 kOctostone_Draw_X[16] = {0, 8, 0, 8, -8, 16, -8, 16, -12, 20, -12, 20, -14, 22, -14, 22};
-  static const int8 kOctostone_Draw_Y[16] = {0, 0, 8, 8, -8, -8, 16, 16, -12, -12, 20, 20, -14, -14, 22, 22};
-  static const uint8 kOctostone_Draw_Flags[16] = {0, 0x40, 0x80, 0xc0, 0, 0x40, 0x80, 0xc0, 0, 0x40, 0x80, 0xc0, 0, 0x40, 0x80, 0xc0};
-
-  PrepOamCoordsRet info;
-  if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
-    return;
-  OamEnt *oam = GetOamCurPtr();
-  int g = ((sprite_delay_main[k] >> 1 & 0xc) ^ 0xc);
-  for (int i = 3; i >= 0; i--, oam++) {
-    int j = g + i;
-    SetOamHelper0(oam, info.x + kOctostone_Draw_X[j], info.y + kOctostone_Draw_Y[j],
-                  0xbc, kOctostone_Draw_Flags[j] | 0x2d, 0);
-  }
-
-}
-
-void Sprite_0F_Octoballoon(int k) {  // 86d6aa
-  static const uint8 kSprite_Octoballoon_Z[8] = {16, 17, 18, 19, 20, 19, 18, 17};
-  sprite_z[k] = kSprite_Octoballoon_Z[sprite_subtype2[k] >> 3 & 7];
-  Octoballoon_Draw(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  if (!sprite_delay_main[k]) {
-    sprite_delay_main[k] = 3;
-    if (!Octoballoon_Find()) {
-      sprite_state[k] = 6;
-      sprite_hit_timer[k] = 0;
-      sprite_delay_main[k] = 15;
-      return;
-    }
-  }
-  if (Sprite_ReturnIfRecoiling(k))
-    return;
-  sprite_subtype2[k]++;
-  if (!((k ^ frame_counter) & 15)) {
-    ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLink(k, 4);
-    if (sprite_x_vel[k] - pt.x)
-      sprite_x_vel[k] += sign8(sprite_x_vel[k] - pt.x) ? 1 : -1;
-    if (sprite_y_vel[k] - pt.y)
-      sprite_y_vel[k] += sign8(sprite_y_vel[k] - pt.y) ? 1 : -1;
-  }
-  Sprite_MoveXY(k);
-  if (Sprite_CheckDamageToLink(k))
-    Octoballoon_RecoilLink(k);
-  Sprite_CheckDamageFromLink(k);
-  Sprite_CheckTileCollision2(k);
-  Sprite_BounceOffWall(k);
-}
-
-void Octoballoon_RecoilLink(int k) {  // 86d72b
-  if (!link_incapacitated_timer) {
-    link_incapacitated_timer = 4;
-    Sprite_ApplyRecoilToLink(k, 16);
-    Sprite_InvertSpeed_XY(k);
-  }
-}
-
-void Octoballoon_Draw(int k) {  // 86d784
-  static const int8 kOctoballoon_Draw_X[12] = {-4, 4, -4, 4, -8, 8, -8, 8, -4, 4, -4, 4};
-  static const int8 kOctoballoon_Draw_Y[12] = {-4, -4, 4, 4, -8, -8, 8, 8, -4, -4, 4, 4};
-  static const uint8 kOctoballoon_Draw_Char[12] = {0x8c, 0x8c, 0x9c, 0x9c, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86};
-  static const uint8 kOctoballoon_Draw_Flags[12] = {0, 0x40, 0, 0x40, 0, 0x40, 0x80, 0xc0, 0, 0x40, 0x80, 0xc0};
-  int d = 0;
-  if (sprite_state[k] == 6) {
-    if (sprite_delay_main[k] == 6 && !submodule_index)
-      Octoballoon_FormBabby(k);
-    d = (sprite_delay_main[k] >> 1 & 4) + 4;
-  }
-  PrepOamCoordsRet info;
-  if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
-    return;
-  OamEnt *oam = GetOamCurPtr();
-  for (int i = 3; i >= 0; i--, oam++) {
-    int j = d + i;
-    SetOamHelper0(oam, info.x + kOctoballoon_Draw_X[j], info.y + kOctoballoon_Draw_Y[j],
-                  kOctoballoon_Draw_Char[j], kOctoballoon_Draw_Flags[j] | info.flags, 2);
-  }
-  SpriteDraw_Shadow(k, &info);
-}
-
-void Octoballoon_FormBabby(int k) {  // 86d80e
-  static const int8 kOctoballoon_Spawn_Xv[6] = {16, 11, -11, -16, -11, 11};
-  static const int8 kOctoballoon_Spawn_Yv[6] = {0, 11, 11, 0, -11, -11};
-
-  SpriteSfx_QueueSfx2WithPan(k, 0xc);
-  for (int i = 5; i >= 0; i--) {
-    SpriteSpawnInfo info;
-    int j = Sprite_SpawnDynamically(k, 0x10, &info);
-    if (j >= 0) {
-      Sprite_SetSpawnedCoordinates(j, &info);
-      sprite_x_vel[j] = kOctoballoon_Spawn_Xv[i];
-      sprite_y_vel[j] = kOctoballoon_Spawn_Yv[i];
-      sprite_z_vel[j] = 48;
-      sprite_subtype2[j] = 255;
-    }
-  }
-}
-
-void Sprite_10_OctoballoonBaby(int k) {  // 86d853
-  if (!sprite_subtype2[k])
-    sprite_state[k] = 0;
-  if (sprite_subtype2[k] >= 64 || !(sprite_subtype2[k] & 1))
-    SpriteDraw_SingleSmall(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  sprite_subtype2[k]--;
-  if (Sprite_ReturnIfRecoiling(k))
-    return;
-  sprite_z_vel[k]--;
-  Sprite_MoveZ(k);
-  if (sign8(sprite_z[k])) {
-    sprite_z[k] = 0;
-    sprite_z_vel[k] = 16;
-  }
-  Sprite_MoveXY(k);
-  Sprite_CheckTileCollision2(k);
-  Sprite_BounceOffWall(k);
-  Sprite_CheckDamageToAndFromLink(k);
-}
-
-void Sprite_0D_Buzzblob(int k) {  // 86d89a
-  static const uint8 kBuzzBlob_Gfx[4] = {0, 1, 0, 2};
-  static const uint8 kBuzzBlob_ObjPrio[4] = {10, 2, 8, 2};
-  if (sprite_delay_aux1[k])
-    sprite_obj_prio[k] = sprite_obj_prio[k] & 0xf1 | kBuzzBlob_ObjPrio[sprite_delay_aux1[k] >> 1 & 3];
-  Sprite_Cukeman(k);
-  BuzzBlob_Draw(k);
-  sprite_graphics[k] = kBuzzBlob_Gfx[sprite_subtype2[k] >> 3 & 3] + (sprite_delay_aux1[k] ? 3 : 0);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  if (Sprite_ReturnIfRecoiling(k))
-    return;
-  sprite_subtype2[k]++;
-  if (!sprite_delay_main[k])
-    Buzzblob_SelectNewDirection(k);
-  if (!sprite_delay_aux1[k])
-    Sprite_MoveXY(k);
-  Sprite_CheckTileCollision2(k);
-  Sprite_BounceOffWall(k);
-  Sprite_CheckDamageToAndFromLink(k);
-}
-
-void Buzzblob_SelectNewDirection(int k) {  // 86d906
-  static const int8 kBuzzBlob_Xvel[8] = {3, 2, -2, -3, -2, 2, 0, 0};
-  static const int8 kBuzzBlob_Yvel[8] = {0, 2, 2, 0, -2, -2, 0, 0};
-  static const uint8 kBuzzBlob_Delay[8] = {48, 48, 48, 48, 48, 48, 64, 64};
-  int j = GetRandomNumber() & 7;
-  sprite_x_vel[k] = kBuzzBlob_Xvel[j];
-  sprite_y_vel[k] = kBuzzBlob_Yvel[j];
-  sprite_delay_main[k] = kBuzzBlob_Delay[j];
-}
-
-void BuzzBlob_Draw(int k) {  // 86d953
-  static const uint16 kBuzzBlob_DrawX[3] = {0, 8, 0};
-  static const int16 kBuzzBlob_DrawY[3] = {-8, -8, 0};
-  static const uint8 kBuzzBlob_DrawChar[18] = { 0xf0, 0xf0, 0xe1, 0, 0, 0xce, 0, 0, 0xce, 0xe3, 0xe3, 0xca, 0xe4, 0xe5, 0xcc, 0xe5, 0xe4, 0xcc };
-  static const uint8 kBuzzBlob_DrawFlags[18] = { 0, 0x40, 0, 0, 0, 0, 0, 0, 0x40, 0, 0x40, 0, 0, 0, 0, 0x40, 0x40, 0x40 };
-  static const uint8 kBuzzBlob_DrawExt[3] = {0, 0, 2};
-
-  PrepOamCoordsRet info;
-  if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
-    return;
-  OamEnt *oam = GetOamCurPtr();
-  int g = sprite_graphics[k];
-  for (int i = 2; i >= 0; i--, oam++) {
-    SetOamHelper0(oam, info.x + kBuzzBlob_DrawX[i], info.y + kBuzzBlob_DrawY[i],
-                  kBuzzBlob_DrawChar[g * 3 + i],
-                  kBuzzBlob_DrawFlags[g * 3 + i] | info.flags, kBuzzBlob_DrawExt[i]);
-    if (oam->charnum == 0)
-      oam->y = 240;
-  }
-  SpriteDraw_Shadow(k, &info);
-}
-
-void Sprite_02_StalfosHead(int k) {  // 86ddb7
-  static const uint8 kStalfosHead_OamFlags[4] = {0, 0, 0, 0x40};
-  static const uint8 kStalfosHead_Gfx[4] = {0, 1, 2, 1};
-
-  sprite_floor[k] = link_is_on_lower_level;
-  if (sprite_delay_aux1[k])
-    Oam_AllocateFromRegionC(8);
-  int j = sprite_subtype2[k] >> 3 & 3;
-  sprite_oam_flags[k] = sprite_oam_flags[k] & ~0x40 | kStalfosHead_OamFlags[j];
-  sprite_graphics[k] = kStalfosHead_Gfx[j];
-  sprite_obj_prio[k] = 0x30;
-  SpriteDraw_SingleLarge(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  if (Sprite_ReturnIfRecoiling(k))
-    return;
-  Sprite_CheckDamageToAndFromLink(k);
-  if (sprite_F[k])
-    Sprite_ZeroVelocity_XY(k);
-  Sprite_MoveXY(k);
-  sprite_subtype2[k]++;
-  ProjectSpeedRet pt;
-  if (sprite_delay_main[k]) {
-    if (sprite_delay_main[k] & 1)
-      return;
-    pt = Sprite_ProjectSpeedTowardsLink(k, 16);
-  } else {
-    if ((k ^ frame_counter) & 3)
-      return;
-    pt = Sprite_ProjectSpeedTowardsLink(k, 16);
-    pt.x = -pt.x;
-    pt.y = -pt.y;
-  }
-  if (sprite_x_vel[k] - pt.x != 0)
-    sprite_x_vel[k] += sign8(sprite_x_vel[k] - pt.x) ? 1 : -1;
-  if (sprite_y_vel[k] - pt.y != 0)
-    sprite_y_vel[k] += sign8(sprite_y_vel[k] - pt.y) ? 1 : -1;
-}
-
-bool Pipe_ValidateEntry() {  // 87f4f1
-  for (int k = 4; k >= 0; k--) {
-    if (ancilla_type[k] == 0x31) {
-      link_position_mode = 0;
-      link_cant_change_direction = 0;
-      ancilla_type[k] = 0;
-      break;
-    }
-  }
-  return ((link_state_bits & 0x80) | link_auxiliary_state) != 0;
-}
-
-void Ancilla_TerminateSparkleObjects() {  // 89adc7
-  for (int i = 4; i >= 0; i--) {
-    uint8 t = ancilla_type[i];
-    if (t == 0x2a || t == 0x2b || t == 0x30 || t == 0x31 || t == 0x18 || t == 0x19 || t == 0xc)
-      ancilla_type[i] = 0;
-  }
-}
-
-int Sprite_SpawnSuperficialBombBlast(int k) {  // 89ae40
-  SpriteSpawnInfo info;
-  int j = Sprite_SpawnDynamically(k, 0x4a, &info);
-  if (j >= 0) {
-    sprite_state[j] = 6;
-    sprite_delay_aux1[j] = 31;
-    sprite_C[j] = 3;
-    sprite_flags2[j] = 3;
-    sprite_oam_flags[j] = 4;
-    SpriteSfx_QueueSfx2WithPan(k, 0x15);
-    Sprite_SetSpawnedCoordinates(j, &info);
-  }
-  return j;
-}
-
-void Sprite_SpawnDummyDeathAnimation(int k) {  // 89ae7e
-  SpriteSpawnInfo info;
-  int j = Sprite_SpawnDynamically(k, 0xb, &info);
-  if (j >= 0) {
-    Sprite_SetSpawnedCoordinates(j, &info);
-    sprite_state[j] = 6;
-    sprite_delay_main[j] = 15;
-    SpriteSfx_QueueSfx2WithPan(k, 0x14);
-    sprite_floor[j] = 2;
-  }
-}
-
-void Sprite_MagicBat_SpawnLightning(int k) {  // 89aea8
-  static const int8 kSpawnMadderBolts_Xvel[4] = {-8, -4, 4, 8};
-  static const int8 kSpawnMadderBolts_St2[4] = {0, 0x11, 0x22, 0x33};
-  for (int i = 0; i < 4; i++) {
-    SpriteSpawnInfo info;
-    int j = Sprite_SpawnDynamically(k, 0x3a, &info);
-    if (j >= 0) {
-      SpriteSfx_QueueSfx3WithPan(k, 0x1);
-      Sprite_SetSpawnedCoordinates(j, &info);
-      Sprite_SetX(j, info.r0_x + 4);
-      Sprite_SetY(j, info.r2_y + 12 - sprite_z[k]);
-      sprite_z[j] = 0;
-      sprite_y_vel[j] = 24;
-      sprite_head_dir[j] = 24;
-      sprite_ignore_projectile[j] = 24;
-      sprite_flags2[j] = 0x80;
-      sprite_flags3[j] = 3;
-      sprite_oam_flags[j] = 3;
-      sprite_delay_main[j] = 32;
-      sprite_graphics[j] = 2;
-      int i = sprite_G[k];
-      sprite_x_vel[j] = kSpawnMadderBolts_Xvel[i];
-      sprite_subtype2[j] = kSpawnMadderBolts_St2[i];
-      sprite_floor[j] = 2;
-      sprite_G[k]++;
-    }
-  }
-}
-
-void Fireball_SpawnTrailGarnish(int k) {  // 89b020
-  if ((k ^ frame_counter) & 3)
-    return;
-  int j = GarnishAlloc();
-  garnish_type[j] = 8;
-  garnish_active = 8;
-  garnish_countdown[j] = 11;
-  garnish_x_lo[j] = cur_sprite_x;
-  garnish_x_hi[j] = cur_sprite_x >> 8;
-  garnish_y_lo[j] = cur_sprite_y + 16;
-  garnish_y_hi[j] = (cur_sprite_y + 16) >> 8;
-  garnish_sprite[j] = k;
-}
-
-void GarnishSpawn_PyramidDebris(int8 x, int8 y, int8 xvel, int8 yvel) {  // 89b1bd
-  int k = GarnishAllocForce();
-  sound_effect_2 = 3;
-  sound_effect_1 = 31;
-  sound_effect_ambient = 5;
-
-  garnish_type[k] = 19;
-  garnish_active = 19;
-  garnish_x_lo[k] = 232 + x;
-  garnish_y_lo[k] = 96 + y;
-  garnish_x_vel[k] = xvel;
-  garnish_y_vel[k] = yvel;
-  garnish_countdown[k] = (GetRandomNumber() & 31) + 48;
-}
-
-void Snitch_SpawnGuard(int k) {  // 89c02f
-  static const uint16 kCrazyVillageSoldier_X[3] = {0x120, 0x340, 0x2e0};
-  static const uint16 kCrazyVillageSoldier_Y[3] = {0x100, 0x3b0, 0x160};
-  SpriteSpawnInfo info;
-  int j = Sprite_SpawnDynamicallyEx(k, 0x45, &info, 0);
-  if (j < 0)
-    return;
-  int i = sprite_type[k] == 0x3d ? 0 :
-          sprite_type[k] == 0x35 ? 1 : 2;
-  Sprite_SetX(j, kCrazyVillageSoldier_X[i] + (sprcoll_x_base & 0xff00));
-  Sprite_SetY(j, kCrazyVillageSoldier_Y[i] + (sprcoll_y_base & 0xff00));
-  sprite_floor[j] = 0;
-  sprite_health[j] = 4;
-  sprite_defl_bits[j] = 0x80;
-  sprite_flags5[j] = 0x90;
-  sprite_oam_flags[j] = 0xb;
-}
-
-void Babusu_Draw(int k) {  // 8dbd20
-  static const DrawMultipleData kBabusu_Dmd[40] = {
-    { 0,  4, 0x4380, 0},
-    { 0,  4, 0x4380, 0},
-    { 0,  4, 0x43b6, 0},
-    { 0,  4, 0x43b6, 0},
-    { 0,  4, 0x43b7, 0},
-    { 8,  4, 0x0380, 0},
-    { 0,  4, 0x4380, 0},
-    { 8,  4, 0x03b6, 0},
-    { 8,  4, 0x03b7, 0},
-    { 8,  4, 0x03b7, 0},
-    { 8,  4, 0x0380, 0},
-    { 8,  4, 0x0380, 0},
-    { 4,  0, 0x8380, 0},
-    { 4,  0, 0x8380, 0},
-    { 4,  0, 0x83b6, 0},
-    { 4,  0, 0x83b6, 0},
-    { 4,  0, 0x83b7, 0},
-    { 4,  8, 0x0380, 0},
-    { 4,  0, 0x8380, 0},
-    { 4,  8, 0x03b6, 0},
-    { 4,  8, 0x03b7, 0},
-    { 4,  8, 0x03b7, 0},
-    { 4,  8, 0x0380, 0},
-    { 4,  8, 0x0380, 0},
-    { 0, -8, 0x0a4e, 2},
-    { 0,  0, 0x0a5e, 2},
-    { 0, -8, 0x4a4e, 2},
-    { 0,  0, 0x4a5e, 2},
-    { 8,  0, 0x0a6c, 2},
-    { 0,  0, 0x0a6b, 2},
-    { 8,  0, 0x8a6c, 2},
-    { 0,  0, 0x8a6b, 2},
-    { 0,  8, 0x8a4e, 2},
-    { 0,  0, 0x8a5e, 2},
-    { 0,  8, 0xca4e, 2},
-    { 0,  0, 0xca5e, 2},
-    {-8,  0, 0x4a6c, 2},
-    { 0,  0, 0x4a6b, 2},
-    {-8,  0, 0xca6c, 2},
-    { 0,  0, 0xca6b, 2},
-  };
-  if (sprite_graphics[k] != 0xff) {
-    Sprite_DrawMultiple(k, &kBabusu_Dmd[sprite_graphics[k] * 2], 2, NULL);
-  } else {
-    PrepOamCoordsRet info;
-    Sprite_PrepOamCoord(k, &info);
-  }
-}
-
-void Wizzrobe_Draw(int k) {  // 8dbe06
-  static const DrawMultipleData kWizzrobe_Dmd[24] = {
-    {0, -8, 0x00b2, 0},
-    {8, -8, 0x00b3, 0},
-    {0,  0, 0x0088, 2},
-    {0, -8, 0x00b2, 0},
-    {8, -8, 0x00b3, 0},
-    {0,  0, 0x0086, 2},
-    {0, -8, 0x00b2, 0},
-    {8, -8, 0x00b3, 0},
-    {0,  0, 0x008c, 2},
-    {0, -8, 0x00b2, 0},
-    {8, -8, 0x00b3, 0},
-    {0,  0, 0x008a, 2},
-    {0, -8, 0x00b2, 0},
-    {8, -8, 0x00b3, 0},
-    {0,  0, 0x408c, 2},
-    {0, -8, 0x00b2, 0},
-    {8, -8, 0x00b3, 0},
-    {0,  0, 0x408a, 2},
-    {0, -8, 0x00b2, 0},
-    {8, -8, 0x00b3, 0},
-    {0,  0, 0x00a4, 2},
-    {0, -8, 0x00b2, 0},
-    {8, -8, 0x00b3, 0},
-    {0,  0, 0x008e, 2},
-  };
-  Sprite_DrawMultiple(k, &kWizzrobe_Dmd[sprite_graphics[k] * 3], 3, NULL);
-}
-
-void Wizzbeam_Draw(int k) {  // 8dbe68
-  static const DrawMultipleData kWizzbeam_Dmd[8] = {
-    { 0, -4, 0x00c5, 0},
-    { 0,  4, 0x80c5, 0},
-    { 0, -4, 0x40c5, 0},
-    { 0,  4, 0xc0c5, 0},
-    {-4,  0, 0x40d2, 0},
-    { 4,  0, 0x00d2, 0},
-    {-4,  0, 0xc0d2, 0},
-    { 4,  0, 0x80d2, 0},
-  };
-  Sprite_DrawMultiple(k, &kWizzbeam_Dmd[sprite_D[k] * 2], 2, NULL);
-}
-
-void Freezor_Draw(int k) {  // 8dbfa6
-
-  static const DrawMultipleData kFreezor_Dmd0[28] = {
-    {-8,  0, 0x00a6, 2},
-    { 8,  0, 0x40a6, 2},
-    {-8,  0, 0x00a6, 2},
-    { 8,  0, 0x40a6, 2},
-    {-8,  0, 0x00a6, 2},
-    { 8,  0, 0x40a6, 2},
-    { 0, 11, 0x00ab, 0},
-    { 8, 11, 0x40ab, 0},
-    {-8,  0, 0x00ac, 2},
-    { 8,  0, 0x40a8, 2},
-    { 0, 11, 0x00ba, 0},
-    { 8, 11, 0x00bb, 0},
-    {-8,  0, 0x00a8, 2},
-    { 8,  0, 0x40ac, 2},
-    { 0, 11, 0x40bb, 0},
-    { 8, 11, 0x40ba, 0},
-    { 0,  2, 0x00ae, 0},
-    { 8,  2, 0x40ae, 0},
-    { 0, 10, 0x00be, 0},
-    { 8, 10, 0x40be, 0},
-    { 0,  4, 0x00af, 0},
-    { 8,  4, 0x40af, 0},
-    { 0, 12, 0x00bf, 0},
-    { 8, 12, 0x40bf, 0},
-    { 0,  8, 0x00aa, 0},
-    { 8,  8, 0x40aa, 0},
-    { 0,  8, 0x00aa, 0},
-    { 8,  8, 0x40aa, 0},
-  };
-  static const DrawMultipleData kFreezor_Dmd1[8] = {
-    { 0, 0, 0x00ae, 0},
-    { 8, 0, 0x40ae, 0},
-    { 0, 8, 0x00be, 0},
-    { 8, 8, 0x40be, 0},
-    {-2, 0, 0x00ae, 0},
-    {10, 0, 0x40ae, 0},
-    {-2, 8, 0x00be, 0},
-    {10, 8, 0x40be, 0},
-  };
-  if (sprite_graphics[k] != 7) {
-    Sprite_DrawMultiple(k, &kFreezor_Dmd0[sprite_graphics[k] * 4], 4, NULL);
-  } else {
-    Sprite_DrawMultiple(k, kFreezor_Dmd1, 8, NULL);
-  }
-}
-
-void Zazak_Draw(int k) {  // 8dc0a6
-  static const uint8 kZazak_Char[8] = {0x82, 0x82, 0x80, 0x84, 0x88, 0x88, 0x86, 0x84};
-  static const uint8 kZazak_Flags[8] = {0x40, 0, 0, 0, 0x40, 0, 0, 0};
-  static const DrawMultipleData kZazak_Dmd[24] = {
-    { 0, -8, 0x0008, 2},
-    {-4,  0, 0x00a0, 2},
-    { 4,  0, 0x00a1, 2},
-    { 0, -7, 0x0008, 2},
-    {-4,  1, 0x40a1, 2},
-    { 4,  1, 0x40a0, 2},
-    { 0, -8, 0x000e, 2},
-    {-4,  0, 0x00a3, 2},
-    { 4,  0, 0x00a4, 2},
-    { 0, -7, 0x000e, 2},
-    {-4,  1, 0x40a4, 2},
-    { 4,  1, 0x40a3, 2},
-    { 0, -9, 0x000c, 2},
-    { 0,  0, 0x00a6, 2},
-    { 0,  0, 0x00a6, 2},
-    { 0, -8, 0x000c, 2},
-    { 0,  0, 0x00a8, 2},
-    { 0,  0, 0x00a8, 2},
-    { 0, -9, 0x400c, 2},
-    { 0,  0, 0x40a6, 2},
-    { 0,  0, 0x40a6, 2},
-    { 0, -8, 0x400c, 2},
-    { 0,  0, 0x40a8, 2},
-    { 0,  0, 0x40a8, 2},
-  };
-  PrepOamCoordsRet info;
-  Sprite_DrawMultiple(k, &kZazak_Dmd[sprite_graphics[k] * 3], 3, &info);
-  if (sprite_pause[k])
-    return;
-  int i = sprite_head_dir[k] + (sprite_delay_aux1[k] == 0 ? 0 : 4);
-  OamEnt *oam = GetOamCurPtr();
-  oam->charnum = kZazak_Char[i];
-  oam->flags = (oam->flags & ~0x40) | kZazak_Flags[i];
-  SpriteDraw_Shadow(k, &info);
-}
-
-void Stalfos_Draw(int k) {  // 8dc21c
-  static const uint8 kStalfos_Char[4] = {2, 2, 0, 4};
-  static const uint8 kStalfos_Flags[4] = {0x70, 0x30, 0x30, 0x30};
-  static const DrawMultipleData kStalfos_Dmd[36] = {
-    { 0, -10, 0x0000, 2},
-    { 0,   0, 0x0006, 2},
-    { 0,   0, 0x0006, 2},
-    { 0,  -9, 0x0000, 2},
-    { 0,   1, 0x4006, 2},
-    { 0,   1, 0x4006, 2},
-    { 0, -10, 0x0004, 2},
-    { 0,   0, 0x0006, 2},
-    { 0,   0, 0x0006, 2},
-    { 0,  -9, 0x0004, 2},
-    { 0,   1, 0x4006, 2},
-    { 0,   1, 0x4006, 2},
-    { 0, -10, 0x0002, 2},
-    { 5,   5, 0x002e, 0},
-    { 0,   0, 0x0024, 2},
-    { 0, -10, 0x0002, 2},
-    { 0,   0, 0x000e, 2},
-    { 0,   0, 0x000e, 2},
-    { 0, -10, 0x4002, 2},
-    { 3,   5, 0x402e, 0},
-    { 0,   0, 0x4024, 2},
-    { 0, -10, 0x4002, 2},
-    { 0,   0, 0x400e, 2},
-    { 0,   0, 0x000e, 2},
-    { 2,  -8, 0x4002, 2},
-    { 0,   0, 0x4008, 2},
-    { 0,   0, 0x4008, 2},
-    {-2,  -8, 0x0002, 2},
-    { 0,   0, 0x0008, 2},
-    { 0,   0, 0x0008, 2},
-    { 0,  -6, 0x0000, 2},
-    { 0,   0, 0x000a, 2},
-    { 0,   0, 0x000a, 2},
-    { 0,   0, 0x000a, 2},
-    { 0,  -6, 0x0004, 2},
-    { 0,  -6, 0x0004, 2},
-  };
-  PrepOamCoordsRet info;
-  if (sprite_delay_aux2[k]) {
-    Sprite_PrepOamCoord(k, &info);
-    return;
-  }
-  Sprite_DrawMultiple(k, &kStalfos_Dmd[sprite_graphics[k] * 3], 3, &info);
-  if (sprite_graphics[k] < 8 && !sprite_pause[k]) {
-    OamEnt *oam = GetOamCurPtr();
-    int i = sprite_head_dir[k];
-    oam->charnum = kStalfos_Char[i];
-    oam->flags = (oam->flags & ~0x70) | kStalfos_Flags[i];
-  }
-  SpriteDraw_Shadow(k, &info);
-}
-
-bool Probe_CheckTileSolidity(int k) {  // 8dc26e
-  uint8 tiletype;
-  if (player_is_indoors) {
-    int t = (sprite_floor[k] >= 1) ? 0x1000 : 0;
-    t += (cur_sprite_x & 0x1f8) >> 3;
-    t += (cur_sprite_y & 0x1f8) << 3;
-    tiletype = dung_bg2_attr_table[t];
-  } else {
-    tiletype = Overworld_ReadTileAttribute(cur_sprite_x >> 3, cur_sprite_y);
-  }
-  sprite_tiletype = tiletype;
-  return kSprite_SimplifiedTileAttr[tiletype] >= 1;
-}
-
-void Sprite_HumanMulti_1(int k) {  // 8dc2d9
-  switch (sprite_subtype2[k]) {
-  case 0: Sprite_FluteDad(k); break;
-  case 1: Sprite_ThiefHideoutGuy(k); break;
-  case 2: Sprite_BlindsHutGuy(k); break;
-  }
-
-}
-
-void Sprite_BlindsHutGuy(int k) {  // 8dc2e6
-  BlindHideoutGuy_Draw(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  Sprite_BehaveAsBarrier(k);
-  Sprite_TrackBodyToHead(k);
-  sprite_head_dir[k] = 0;
-  int j = Sprite_ShowSolicitedMessage(k, 0x172);
-  if (j & 0x100)
-    sprite_D[k] = sprite_head_dir[k] = j;
-}
-
-void Sprite_ThiefHideoutGuy(int k) {  // 8dc308
-  if (!(frame_counter & 3)) {
-    sprite_graphics[k] = 2;
-    uint8 dir = Sprite_DirectionToFaceLink(k, NULL);
-    sprite_head_dir[k] = dir == 3 ? 2 : dir;
-  }
-  sprite_oam_flags[k] = 15;
-  Oam_AllocateDeferToPlayer(k);
-  Thief_Draw(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  Sprite_BehaveAsBarrier(k);
-  Sprite_ShowSolicitedMessage(k, 0x171);
-  sprite_graphics[k] = 2;
-}
-
-void Sprite_FluteDad(int k) {  // 8dc343
-  FluteBoyFather_Draw(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  Sprite_BehaveAsBarrier(k);
-  sprite_graphics[k] = (frame_counter < 48) ? 2 : (frame_counter >> 7) & 1;
-
-  if (sprite_ai_state[k]) {
-    Sprite_ShowSolicitedMessage(k, 0xa3);
-    sprite_graphics[k] = 2;
-  } else if (link_item_flute < 2) {
-    Sprite_ShowSolicitedMessage(k, 0xa1);
-  } else if (!(Sprite_ShowSolicitedMessage(k, 0xa4) & 0x100) &&
-             hud_cur_item == kHudItem_Flute && (joypad1H_last&0x40) && Sprite_CheckDamageToLink_same_layer(k)) {
-    Sprite_ShowMessageUnconditional(0xa2);
-    sprite_ai_state[k]++;
-    sprite_graphics[k] = 2;
-  }
-}
-
-void FluteBoyFather_Draw(int k) {  // 8dc3e1
-  static const DrawMultipleData kFluteBoyFather_Dmd[6] = {
-    {0, -7, 0x0086, 2},
-    {0,  0, 0x0088, 2},
-    {0, -6, 0x0086, 2},
-    {0,  0, 0x0088, 2},
-    {0, -8, 0x0084, 2},
-    {0,  0, 0x0088, 2},
-  };
-  PrepOamCoordsRet info;
-  Sprite_DrawMultiplePlayerDeferred(k, &kFluteBoyFather_Dmd[sprite_graphics[k] * 2], 2, &info);
-  SpriteDraw_Shadow(k, &info);
-}
-
-void BlindHideoutGuy_Draw(int k) {  // 8dc481
-  static const DrawMultipleData kBlindHideoutGuy_Dmd[16] = {
-    {0, -8, 0x000c, 2},
-    {0,  0, 0x00ca, 2},
-    {0, -8, 0x000c, 2},
-    {0,  0, 0x40ca, 2},
-    {0, -8, 0x000c, 2},
-    {0,  0, 0x00ca, 2},
-    {0, -8, 0x000c, 2},
-    {0,  0, 0x40ca, 2},
-    {0, -8, 0x000e, 2},
-    {0,  0, 0x00ca, 2},
-    {0, -8, 0x000e, 2},
-    {0,  0, 0x40ca, 2},
-    {0, -8, 0x400e, 2},
-    {0,  0, 0x00ca, 2},
-    {0, -8, 0x400e, 2},
-    {0,  0, 0x40ca, 2},
-  };
-  PrepOamCoordsRet info;
-  Sprite_DrawMultiplePlayerDeferred(k, &kBlindHideoutGuy_Dmd[sprite_graphics[k] * 2 + sprite_D[k] * 4], 2, &info);
-  SpriteDraw_Shadow(k, &info);
-}
-
-void Sprite_SweepingLady(int k) {  // 8dc4ad
-  SweepingLady_Draw(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  Sprite_ShowSolicitedMessage(k, 0xa5);
-  Sprite_BehaveAsBarrier(k);
-  sprite_graphics[k] = frame_counter >> 4 & 1;
-}
-
-void SweepingLady_Draw(int k) {  // 8dc4eb
-  static const DrawMultipleData kSweepingLadyDmd[4] = {
-    {0, -7, 0x008e, 2},
-    {0,  5, 0x008a, 2},
-    {0, -8, 0x008e, 2},
-    {0,  4, 0x008c, 2},
-  };
-  PrepOamCoordsRet info;
-  Sprite_DrawMultiplePlayerDeferred(k, &kSweepingLadyDmd[sprite_graphics[k] * 2], 2, &info);
-  SpriteDraw_Shadow(k, &info);
-}
-
-void Sprite_Lumberjacks(int k) {  // 8dc51b
-  static const uint16 kLumberJackMsg[4] = {0x12c, 0x12d, 0x12e, 0x12d};
-  Lumberjacks_Draw(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  if (Lumberjack_CheckProximity(k, 0)) {
-    Sprite_NullifyHookshotDrag();
-    link_speed_setting = 0;
-    Link_CancelDash();
-  }
-  if (!Sprite_CheckIfLinkIsBusy() && Lumberjack_CheckProximity(k, 1) && (filtered_joypad_L & 0x80)) {
-    int msg = (BYTE(link_x_coord) >= sprite_x_lo[k]) + (link_sword_type >= 2) * 2;
-    Sprite_ShowMessageUnconditional(kLumberJackMsg[msg]);
-  }
-  sprite_graphics[k] = frame_counter >> 5 & 1;
-}
-
-bool Lumberjack_CheckProximity(int k, int j) {  // 8dc58f
-  static const uint8 kLumberJacks_X[2] = {48, 52};
-  static const uint8 kLumberJacks_Y[2] = {19, 20};
-  static const uint8 kLumberJacks_W[2] = {98, 106};
-  static const uint8 kLumberJacks_H[2] = {37, 40};
-  return (uint16)(cur_sprite_x - link_x_coord + kLumberJacks_X[j]) < kLumberJacks_W[j] &&
-         (uint16)(cur_sprite_y - link_y_coord + kLumberJacks_Y[j]) < kLumberJacks_H[j];
-}
-
-void Lumberjacks_Draw(int k) {  // 8dc6ba
-  static const DrawMultipleData kLumberJacks_Dmd[33] = {
-    {-23,  5, 0x02be, 0},
-    {-15,  5, 0x02bf, 0},
-    { -7,  5, 0x02bf, 0},
-    {  1,  5, 0x02bf, 0},
-    {  9,  5, 0x02bf, 0},
-    { 17,  5, 0x02bf, 0},
-    { 25,  5, 0x42be, 0},
-    {-32, -8, 0x40a8, 2},
-    {-32,  4, 0x40a6, 2},
-    { 30, -8, 0x00a8, 2},
-    { 31,  4, 0x00a4, 2},
-    {-19,  5, 0x02be, 0},
-    {-11,  5, 0x02bf, 0},
-    { -3,  5, 0x02bf, 0},
-    {  5,  5, 0x02bf, 0},
-    { 13,  5, 0x02bf, 0},
-    { 21,  5, 0x02bf, 0},
-    { 29,  5, 0x42be, 0},
-    {-31, -8, 0x40a8, 2},
-    {-32,  4, 0x40a4, 2},
-    { 31, -8, 0x00a8, 2},
-    { 31,  4, 0x00a6, 2},
-    {-19,  5, 0x02be, 0},
-    {-11,  5, 0x02bf, 0},
-    { -3,  5, 0x02bf, 0},
-    {  5,  5, 0x02bf, 0},
-    { 13,  5, 0x02bf, 0},
-    { 21,  5, 0x02bf, 0},
-    { 29,  5, 0x42be, 0},
-    {-32, -8, 0x400e, 2},
-    {-32,  4, 0x40a4, 2},
-    { 32, -8, 0x000e, 2},
-    { 31,  4, 0x00a6, 2},
-  };
-  Sprite_DrawMultiple(k, &kLumberJacks_Dmd[sprite_graphics[k] * 11], 11, NULL);
-}
-
-void Sprite_FortuneTeller(int k) {  // 8dc762
-  switch (sprite_subtype2[k]) {
-  case 0: // fortuneteller main
-    FortuneTeller_Draw(k);
-    if (Sprite_ReturnIfInactive(k))
-      return;
-    FortuneTeller_LightOrDarkWorld(k, savegame_is_darkworld >> 6 & 1);
-    break;
-  case 1: // dwarf solidity
-    if (Sprite_ReturnIfInactive(k))
-      return;
-    if (Sprite_CheckDamageToLink_same_layer(k)) {
-      Sprite_NullifyHookshotDrag();
-      link_speed_setting = 0;
-      Link_CancelDash();
-    }
-    break;
-  }
-}
-
-void FortuneTeller_PerformPseudoScience(int k) {  // 8dc849
-  sprite_graphics[k] = 0;
-  sprite_ai_state[k]++;
-
-  static const uint8 kFortuneTeller_Readings[16] = {0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd};
-
-  uint8 slots[2] = { 0, 0 };
-  int n = 0;
-#define ADD_MSG(q) { slots[n++]=(q); if (n==2) goto done; }
-
-  if (savegame_map_icons_indicator < 3)
-    goto done;
-  if (!link_item_book_of_mudora) ADD_MSG(2);
-  if (!(link_which_pendants & 2)) ADD_MSG(1);
-  if (link_item_mushroom < 2) ADD_MSG(3);
-  if (!link_item_flippers) ADD_MSG(4);
-  if (!link_item_moon_pearl) ADD_MSG(5);
-  if (sram_progress_indicator < 3) ADD_MSG(6);
-  if (!link_magic_consumption) ADD_MSG(7);
-  if (!link_item_bombos_medallion) ADD_MSG(8);
-  if (!(sram_progress_indicator_3 & 0x10)) ADD_MSG(9);
-  if (!(sram_progress_indicator_3 & 0x20)) ADD_MSG(10);
-  if (!link_item_cape) ADD_MSG(11);
-  if (!(save_ow_event_info[0x5b] & 2)) ADD_MSG(12);
-  if (link_sword_type < 4) ADD_MSG(13);
-  ADD_MSG(14);
-  ADD_MSG(15);
-  int j;
-done:
-  j = ((sram_progress_flags ^= 0x40) & 0x40) != 0;
-  Sprite_ShowMessageUnconditional(kFortuneTeller_Readings[slots[j]]);
-}
-
-void FortuneTeller_Draw(int k) {  // 8dcb01
-  static const DrawMultipleData kFortuneTeller_Dmd[12] = {
-    { 0, -48, 0x000c, 2},
-    { 0, -32, 0x002c, 0},
-    { 8, -32, 0x402c, 0},
-    { 0, -48, 0x000a, 2},
-    { 0, -32, 0x002a, 0},
-    { 8, -32, 0x402a, 0},
-    {-4, -40, 0x0066, 2},
-    { 4, -40, 0x4066, 2},
-    {-4, -40, 0x0066, 2},
-    {-4, -40, 0x0068, 2},
-    { 4, -40, 0x4068, 2},
-    {-4, -40, 0x0068, 2},
-  };
-  int j = (savegame_is_darkworld >> 6 & 1) * 2 + sprite_graphics[k];
-  Sprite_DrawMultiple(k, &kFortuneTeller_Dmd[j * 3], 3, NULL);
-}
-
-void Smithy_SpawnDumbBarrierSprite(int k) {  // 8dcb2a
-  SpriteSpawnInfo info;
-  int j = Sprite_SpawnDynamically(k, 0x31, &info);
-  if (j < 0)
-    return;
-  Sprite_SetX(j, info.r0_x);
-  Sprite_SetY(j, info.r2_y);
-  sprite_subtype2[j] = 1;
-  sprite_flags4[j] = 0;
-  sprite_ignore_projectile[j] = 1;
-}
-
-void Sprite_MazeGameLady(int k) {  // 8dcb5c
-  Lady_Draw(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  Sprite_TrackBodyToHead(k);
-  sprite_head_dir[k] = Sprite_DirectionToFaceLink(k, NULL) ^ 3;
-  switch (sprite_ai_state[k]) {
-  case 0:  // startup
-    if (sprite_x_lo[k] < BYTE(link_x_coord)) {
-      int j = Sprite_ShowMessageOnContact(k, 0xcc);
-      if (j & 0x100) {
-        sprite_D[k] = sprite_head_dir[k] = (uint8)j;
-        sprite_ai_state[k] = 1;
-        word_7FFE00 = 0;
-        word_7FFE02 = 0;
-        sprite_A[k] = 0;
-        flag_overworld_area_did_change = 0;
-      }
-    } else {
-      Sprite_ShowMessageOnContact(k, 0xd0);
-    }
-    break;
-  case 1:  // sound
-    SpriteSfx_QueueSfx3WithPan(k, 0x7);
-    sprite_ai_state[k] = 2;
-    break;
-  case 2:  // accumulate time
-    if (++sprite_A[k] == 63) {
-      sprite_A[k] = 0;
-      word_7FFE00 += 1;
-      if (word_7FFE00 == 0)
-        word_7FFE02++;
-    }
-    break;
-  }
-}
-
-void Sprite_MazeGameGuy(int k) {  // 8dcbf2
-  int j;
-  MazeGameGuy_Draw(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  Sprite_TrackBodyToHead(k);
-  sprite_head_dir[k] = 0;
-  Sprite_BehaveAsBarrier(k);
-  sprite_graphics[k] = frame_counter >> 3 & 1;
-  if (flag_overworld_area_did_change) {
-    Sprite_ShowMessageOnContact(k, 0xd0);
-    return;
-  }
-  switch (sprite_ai_state[k]) {
-  case 0: {  // parse time
-    word_7FFE04 = word_7FFE00;
-    word_7FFE06 = word_7FFE02;
-    int t = word_7FFE04 % 6000;
-    int a = t / 600;
-    t %= 600;
-    int b = t / 60;
-    t %= 60;
-    int c = t / 10;
-    t %= 10;
-    dialogue_number[0] = t | c << 4;
-    dialogue_number[1] = b | a << 4;
-    t = Sprite_ShowMessageOnContact(k, 0xcb);
-    if (t & 0x100) {
-      sprite_D[k] = sprite_head_dir[k] = (uint8)t;
-      sprite_ai_state[k] = 1;
-    }
-    break;
-  }
-  case 1:  // check qualify
-    if (save_ow_event_info[BYTE(overworld_screen_index)] & 0x40) {
-      Sprite_ShowMessageUnconditional(0xcf);
-      sprite_ai_state[k] = 4;
-    } else if (word_7FFE04 < 16) {
-      Sprite_ShowMessageUnconditional(0xcd);
-      sprite_D[k] = sprite_head_dir[k] = (uint8)link_player_handler_state;  // wtf
-      sprite_ai_state[k] = 3;
-    } else {
-      Sprite_ShowMessageUnconditional(0xce);
-      sprite_D[k] = sprite_head_dir[k] = (uint8)link_player_handler_state;  // wtf
-      sprite_ai_state[k] = 2;
-    }
-    break;
-  case 2:  // sorry
-    j = Sprite_ShowMessageOnContact(k, 0xce);
-    if (j & 0x100)
-      sprite_D[k] = sprite_head_dir[k] = (uint8)j;
-    break;
-  case 3:  // can have it
-    j = Sprite_ShowSolicitedMessage(k, 0xcd);
-    if (j & 0x100)
-      sprite_D[k] = sprite_head_dir[k] = (uint8)j;
-    break;
-  case 4:  // nothing more
-    j = Sprite_ShowSolicitedMessage(k, 0xcf);
-    if (j & 0x100)
-      sprite_D[k] = sprite_head_dir[k] = (uint8)j;
-    break;
-  }
-}
-
-void MazeGameGuy_Draw(int k) {  // 8dcda7
-  static const DrawMultipleData kMazeGameGuy_Dmd[16] = {
-    {0, -10, 0x0000, 2},
-    {0,   0, 0x0020, 2},
-    {0, -10, 0x0000, 2},
-    {0,   0, 0x0020, 2},
-    {0, -10, 0x0000, 2},
-    {0,   0, 0x0020, 2},
-    {0, -10, 0x0000, 2},
-    {0,   0, 0x0020, 2},
-    {0, -10, 0x4002, 2},
-    {0,   0, 0x0020, 2},
-    {0, -10, 0x4002, 2},
-    {0,   0, 0x0020, 2},
-    {0, -10, 0x0002, 2},
-    {0,   0, 0x0020, 2},
-    {0, -10, 0x0002, 2},
-    {0,   0, 0x0020, 2},
-  };
-  PrepOamCoordsRet info;
-  Sprite_DrawMultiplePlayerDeferred(k, &kMazeGameGuy_Dmd[sprite_graphics[k] * 2 + sprite_D[k] * 4], 2, &info);
-  SpriteDraw_Shadow(k, &info);
-}
-
-void CrystalMaiden_Draw(int k) {  // 8dce5f
-  int j = sprite_D[k] * 2 + sprite_graphics[k];
-  BYTE(dma_var6) = kCrystalMaiden_Dma[j * 2 + 0];
-  BYTE(dma_var7) = kCrystalMaiden_Dma[j * 2 + 1];
-  Sprite_DrawMultiplePlayerDeferred(k, kCrystalMaiden_SpriteData + j * 2, 2, NULL);
-}
-
-void Priest_Draw(int k) {  // 8dcf31
-  int j = sprite_D[k] * 2 + sprite_graphics[k];
-  PrepOamCoordsRet info;
-  Sprite_DrawMultiplePlayerDeferred(k, kPriest_Dmd + j * 2, 2, &info);
-  SpriteDraw_Shadow(k, &info);
-}
-
-uint8 FluteBoy_Draw(int k) {  // 8dcfd9
-  static const DrawMultipleData kFluteBoy_Dmd[16] = {
-    {-1,  -1, 0x0abe, 0},
-    { 0,   0, 0x0aaa, 2},
-    { 0, -10, 0x0aa8, 2},
-    { 0,   0, 0x0aaa, 2},
-    {-1,  -1, 0x0abe, 0},
-    { 0,   8, 0x0abf, 0},
-    { 0, -10, 0x0aa8, 2},
-    { 0,   0, 0x0aaa, 2},
-    {-1,  -1, 0x0abe, 0},
-    { 0,   0, 0x0aaa, 2},
-    { 0, -10, 0x0aa8, 2},
-    { 0,   0, 0x0aaa, 2},
-    {-1,  -1, 0x0abe, 0},
-    { 0,   8, 0x0abf, 0},
-    { 0, -10, 0x0aa8, 2},
-    { 0,   0, 0x0aaa, 2},
-  };
-  Oam_AllocateFromRegionB(0x10);
-  PrepOamCoordsRet info;
-  Sprite_DrawMultiple(k, &kFluteBoy_Dmd[sprite_D[k] * 8 + sprite_graphics[k] * 4], 4, &info);
-  return (info.x | info.y) >> 8;
-}
-
-void FluteAardvark_Draw(int k) {  // 8dd040
-  static const DrawMultipleData kFluteAardvark_Dmd[8] = {
-    {0, -16, 0x06e6, 2},
-    {0,  -8, 0x06c8, 2},
-    {0, -16, 0x06e6, 2},
-    {0,  -8, 0x06ca, 2},
-    {0, -16, 0x06e8, 2},
-    {0,  -8, 0x06ca, 2},
-    {0, -16, 0x00cc, 2},
-    {0,  -8, 0x00dc, 2},
-  };
-  Sprite_DrawMultiplePlayerDeferred(k, &kFluteAardvark_Dmd[sprite_graphics[k] * 2], 2, NULL);
-}
-
-void DustCloud_Draw(int k) {  // 8dd120
-  static const DrawMultipleData kDustCloud_Dmd[24] = {
-    { 0, -3, 0x008b, 0},
-    { 3,  0, 0x009b, 0},
-    {-3,  0, 0xc08b, 0},
-    { 0,  3, 0xc09b, 0},
-    { 0, -5, 0x008a, 2},
-    { 5,  0, 0x008a, 2},
-    {-5,  0, 0x008a, 2},
-    { 0,  5, 0x008a, 2},
-    { 0, -7, 0x0086, 2},
-    { 7,  0, 0x0086, 2},
-    {-7,  0, 0x0086, 2},
-    { 0,  7, 0x0086, 2},
-    { 0, -9, 0x8086, 2},
-    { 9,  0, 0x8086, 2},
-    {-9,  0, 0x8086, 2},
-    { 0,  9, 0x8086, 2},
-    { 0, -9, 0xc086, 2},
-    { 9,  0, 0xc086, 2},
-    {-9,  0, 0xc086, 2},
-    { 0,  9, 0xc086, 2},
-    { 0, -7, 0x4086, 2},
-    { 7,  0, 0x4086, 2},
-    {-7,  0, 0x4086, 2},
-    { 0,  7, 0x4086, 2},
-  };
-  sprite_oam_flags[k] = 0x14;
-  Sprite_DrawMultiple(k, &kDustCloud_Dmd[sprite_graphics[k] * 4], 4, NULL);
-}
-
-void MedallionTablet_Draw(int k) {  // 8dd1e2
-  static const DrawMultipleData kMedallionTablet_Dmd[20] = {
-    {-8, -16, 0x008c, 2},
-    { 8, -16, 0x408c, 2},
-    {-8,   0, 0x00ac, 2},
-    { 8,   0, 0x40ac, 2},
-    {-8, -13, 0x008a, 2},
-    { 8, -13, 0x408a, 2},
-    {-8,   0, 0x00ac, 2},
-    { 8,   0, 0x40ac, 2},
-    {-8,  -8, 0x008a, 2},
-    { 8,  -8, 0x408a, 2},
-    {-8,   0, 0x00ac, 2},
-    { 8,   0, 0x40ac, 2},
-    {-8,  -4, 0x008a, 2},
-    { 8,  -4, 0x408a, 2},
-    {-8,   0, 0x00aa, 2},
-    { 8,   0, 0x40aa, 2},
-    {-8,   0, 0x00aa, 2},
-    { 8,   0, 0x40aa, 2},
-    {-8,   0, 0x00aa, 2},
-    { 8,   0, 0x40aa, 2},
-  };
-  Sprite_DrawMultiplePlayerDeferred(k, &kMedallionTablet_Dmd[sprite_graphics[k] * 4], 4, NULL);
-}
-
-void Uncle_Draw(int k) {  // 8dd391
-  static const DrawMultipleData kUncleDraw_Table[48] = {
-    {  0, -10, 0x0e00, 2},
-    {  0,   0, 0x0c06, 2},
-    {  0, -10, 0x0e00, 2},
-    {  0,   0, 0x0c06, 2},
-    {  0, -10, 0x0e00, 2},
-    {  0,   0, 0x0c06, 2},
-    {  0, -10, 0x0e02, 2},
-    {  0,   0, 0x0c06, 2},
-    {  0, -10, 0x0e02, 2},
-    {  0,   0, 0x0c06, 2},
-    {  0, -10, 0x0e02, 2},
-    {  0,   0, 0x0c06, 2},
-    { -7,   2, 0x0d07, 2},
-    { -7,   2, 0x0d07, 2},
-    { 10,  12, 0x8d05, 0},
-    { 10,   4, 0x8d15, 0},
-    {  0, -10, 0x0e00, 2},
-    {  0,   0, 0x0c04, 2},
-    { -7,   1, 0x0d07, 2},
-    { -7,   1, 0x0d07, 2},
-    { 10,  13, 0x8d05, 0},
-    { 10,   5, 0x8d15, 0},
-    {  0,  -9, 0x0e00, 2},
-    {  0,   1, 0x4c04, 2},
-    { -7,   8, 0x8d05, 0},
-    {  1,   8, 0x8d06, 0},
-    {  0, -10, 0x0e02, 2},
-    { -6,  -1, 0x4d07, 2},
-    {  0,   0, 0x0c23, 2},
-    {  0,   0, 0x0c23, 2},
-    { -9,   7, 0x8d05, 0},
-    { -1,   7, 0x8d06, 0},
-    {  0,  -9, 0x0e02, 2},
-    { -6,   0, 0x4d07, 2},
-    {  0,   1, 0x0c25, 2},
-    {  0,   1, 0x0c25, 2},
-    {-10, -17, 0x0d07, 2},
-    { 15, -12, 0x8d15, 0},
-    { 15,  -4, 0x8d05, 0},
-    {  0, -28, 0x0e08, 2},
-    { -8, -19, 0x0c20, 2},
-    {  8, -19, 0x4c20, 2},
-    {  0, -28, 0x0e08, 2},
-    {  0, -28, 0x0e08, 2},
-    { -8, -19, 0x0c20, 2},
-    {  8, -19, 0x4c20, 2},
-    { -8, -19, 0x0c20, 2},
-    {  8, -19, 0x4c20, 2},
-  };
-  static const uint8 kUncleDraw_Dma3[8] = { 8, 8, 0, 0, 6, 6, 0, 0 };
-  static const uint8 kUncleDraw_Dma4[8] = { 0, 0, 0, 0, 4, 4, 0, 0x8b }; // wtf
-
-  Oam_AllocateFromRegionB(0x18);
-  const DrawMultipleData *src = &kUncleDraw_Table[sprite_D[k] * 12 + sprite_graphics[k] * 6];
-
-  int j = sprite_D[k] * 2 + sprite_graphics[k];
-  link_dma_var3 = kUncleDraw_Dma3[j];
-  link_dma_var4 = kUncleDraw_Dma4[j];
-  PrepOamCoordsRet info;
-  Sprite_DrawMultiple(k, src, 6, &info);
-
-  if (sprite_D[k] != 0 && sprite_D[k] != 3)
-    SpriteDraw_Shadow(k, &info);
-}
-
-void BugNetKid_Draw(int k) {  // 8dd47b
-  static const DrawMultipleData kBugNetKid_Dmd[18] = {
-    { 4,  0, 0x0027, 0},
-    { 0, -5, 0x000e, 2},
-    {-8,  6, 0x040a, 2},
-    { 8,  6, 0x440a, 2},
-    {-8, 14, 0x840a, 2},
-    { 8, 14, 0xc40a, 2},
-    { 0, -5, 0x000e, 2},
-    { 0, -5, 0x000e, 2},
-    {-8,  6, 0x040a, 2},
-    { 8,  6, 0x440a, 2},
-    {-8, 14, 0x840a, 2},
-    { 8, 14, 0xc40a, 2},
-    { 0, -5, 0x002e, 2},
-    { 0, -5, 0x002e, 2},
-    {-8,  7, 0x040a, 2},
-    { 8,  7, 0x440a, 2},
-    {-8, 14, 0x840a, 2},
-    { 8, 14, 0xc40a, 2},
-  };
-  Sprite_DrawMultiplePlayerDeferred(k, &kBugNetKid_Dmd[sprite_graphics[k] * 6], 6, NULL);
-}
-
-void Bomber_Draw(int k) {  // 8dd56c
-  static const DrawMultipleData kBomber_Dmd[22] = {
-    { 0, 0, 0x40c6, 2},
-    { 0, 0, 0x40c6, 2},
-    { 0, 0, 0x40c4, 2},
-    { 0, 0, 0x40c4, 2},
-    { 0, 0, 0x00c6, 2},
-    { 0, 0, 0x00c6, 2},
-    { 0, 0, 0x00c4, 2},
-    { 0, 0, 0x00c4, 2},
-    {-8, 0, 0x00c0, 2},
-    { 8, 0, 0x40c0, 2},
-    {-8, 0, 0x00c2, 2},
-    { 8, 0, 0x40c2, 2},
-    {-8, 0, 0x00e0, 2},
-    { 8, 0, 0x40e0, 2},
-    {-8, 0, 0x00e2, 2},
-    { 8, 0, 0x40e2, 2},
-    {-8, 0, 0x00e4, 2},
-    { 8, 0, 0x40e4, 2},
-    { 0, 0, 0x40e6, 2},
-    { 0, 0, 0x40e6, 2},
-    { 0, 0, 0x00e6, 2},
-    { 0, 0, 0x00e6, 2},
-  };
-  PrepOamCoordsRet info;
-  Sprite_DrawMultiple(k, &kBomber_Dmd[sprite_graphics[k] * 2], 2, &info);
-  SpriteDraw_Shadow(k, &info);
-}
-
-void SpriteDraw_ZirroBomb(int k) {  // 8dd606
-  static const DrawMultipleData kBomberPellet_Dmd[15] = {
-    {-11,   0, 0x019b, 0},
-    {  0,  -8, 0xc19b, 0},
-    {  6,   6, 0x419b, 0},
-    {-15,  -6, 0x018a, 2},
-    { -4, -14, 0x018a, 2},
-    {  2,   0, 0x018a, 2},
-    {-15,  -6, 0x0186, 2},
-    { -4, -14, 0x0186, 2},
-    {  2,   0, 0x0186, 2},
-    { -4,  -4, 0x0186, 2},
-    { -4,  -4, 0x0186, 2},
-    { -4,  -4, 0x0186, 2},
-    { -4,  -4, 0x01aa, 2},
-    { -4,  -4, 0x01aa, 2},
-    { -4,  -4, 0x01aa, 2},
-  };
-  if (!sprite_delay_main[k])
-    sprite_state[k] = 0;
-  Sprite_DrawMultiple(k, &kBomberPellet_Dmd[(sprite_delay_main[k] >> 2) * 3], 3, NULL);
-}
-
-void PlayerBee_HoneInOnTarget(int j, int k) {  // 8dd631
-  if (sprite_type[j] != 0x88 && (sprite_flags[j] & 2))
-    return;
-  uint16 x = Sprite_GetX(j);
-  uint16 y = Sprite_GetY(j);
-  if ((uint16)(cur_sprite_x - x + 16) >= 24 ||
-      (uint16)(cur_sprite_y - y - 8) >= 24)
-    return;
-  if (sprite_type[j] == 0x75) {
-    sprite_E[j] = k + 1;
-    return;
-  }
-  Ancilla_CheckDamageToSprite_preset(j, 1);
-  sprite_F[j] = 15;
-  sprite_x_recoil[j] = sprite_x_vel[k] << 1;
-  sprite_y_recoil[j] = sprite_y_vel[k] << 1;
-  sprite_B[k]++;
-}
-
-void Pikit_Draw(int k) {  // 8dd6e6
-  static const DrawMultipleData kPikit_Dmd[8] = {
-    { 0, 0, 0x00c8, 2},
-    { 0, 0, 0x00c8, 2},
-    { 0, 0, 0x00ca, 2},
-    { 0, 0, 0x00ca, 2},
-    {-8, 0, 0x00cc, 2},
-    { 8, 0, 0x40cc, 2},
-    {-8, 0, 0x00ce, 2},
-    { 8, 0, 0x40ce, 2},
-  };
-  PrepOamCoordsRet info;
-  if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
-    return;
-  SpriteDraw_Pikit_Tongue(k, &info);
-  OamEnt *oam = GetOamCurPtr();
-  tmp_counter = oam->x;
-  byte_7E0FB6 = oam->y;
-  oam_cur_ptr += 24;
-  oam_ext_cur_ptr += 6;
-  Sprite_DrawMultiple(k, &kPikit_Dmd[sprite_graphics[k] * 2], 2, &info);
-  uint8 bak = sprite_flags2[k];
-  sprite_flags2[k] -= 6;
-  SpriteDraw_Shadow(k, &info);
-  sprite_flags2[k] = bak;
-  SpriteDraw_Pikit_Loot(k, &info);
-}
-
-void SpriteDraw_Pikit_Tongue(int k, PrepOamCoordsRet *info) {  // 8dd74a
-  static const uint8 kPikit_TongueMult[4] = {0x33, 0x66, 0x99, 0xcc};
-  static const uint8 kPikit_Draw_Char[8] = {0xee, 0xfd, 0xed, 0xfd, 0xee, 0xfd, 0xed, 0xfd};
-  static const uint8 kPikit_Draw_Flags[8] = {0, 0, 0, 0x40, 0x40, 0xc0, 0x80, 0x80};
-  if (sprite_ai_state[k] != 2 || sprite_pause[k])
-    return;
-  OamEnt *oam = GetOamCurPtr();
-  int x = info->x + 4, y = info->y + 3;
-  oam[5].x = x;
-  oam[5].y = y;
-  oam[0].x = x + sprite_A[k];
-  oam[0].y = y + sprite_B[k];
-  oam[0].charnum = oam[5].charnum = 0xfe;
-  oam[0].flags = oam[5].flags = info->flags;
-  oam++;
-  int g = sprite_D[k];
-  for (int i = 3; i >= 0; i--, oam++) {
-    oam->x = x + (int8)sprite_A[k] * kPikit_TongueMult[i] / 256;
-    oam->y = y + (int8)sprite_B[k] * kPikit_TongueMult[i] / 256;
-    oam->charnum = kPikit_Draw_Char[g];
-    oam->flags = kPikit_Draw_Flags[g] | info->flags;
-  }
-  Sprite_CorrectOamEntries(k, 5, 0);
-}
-
-void SpriteDraw_Pikit_Loot(int k, PrepOamCoordsRet *info) {  // 8dd858
-  static const int8 kPikit_DrawGrabbedItem_X[20] = {
-    -4, 4, -4, 4, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, -4, 4, -4, 4,
-  };
-  static const int8 kPikit_DrawGrabbedItem_Y[20] = {
-    -4, -4, 4, 4, -4, -4, 4, 4, -4, -4, 4, 4, -4, -4, 4, 4, -4, -4, 4, 4,
-  };
-  static const uint8 kPikit_DrawGrabbedItem_Char[20] = {
-    0x6e, 0x6f, 0x7e, 0x7f, 0x63, 0x7c, 0x73, 0x7c, 0xb, 0x7c, 0x1b, 0x7c, 0xec, 0xf9, 0xfc, 0xf9,
-    0xea, 0xeb, 0xfa, 0xfb,
-  };
-  static const uint8 kPikit_DrawGrabbedItem_Flags[5] = {0x24, 0x24, 0x28, 0x29, 0x2f};
-  if (!sprite_G[k])
-    return;
-  int g = sprite_G[k] - 1;
-  if (g == 3)
-    g = sprite_subtype[k] + 2;
-  Oam_AllocateFromRegionC(0x10);
-  OamEnt *oam = GetOamCurPtr();
-  for (int i = 3; i >= 0; i--, oam++) {
-    int j = g * 4 + i;
-    oam->x = tmp_counter + kPikit_DrawGrabbedItem_X[j];
-    oam->y = byte_7E0FB6 + kPikit_DrawGrabbedItem_Y[j];
-    oam->charnum = kPikit_DrawGrabbedItem_Char[j];
-    oam->flags = kPikit_DrawGrabbedItem_Flags[g];
-  }
-  Sprite_CorrectOamEntries(k, 3, 0);
-}
-
-void Kholdstare_Draw(int k) {  // 8dd98f
-  static const DrawMultipleData kKholdstare_Dmd[16] = {
-    {-8, -8, 0x0080, 2},
-    { 8, -8, 0x0082, 2},
-    {-8,  8, 0x00a0, 2},
-    { 8,  8, 0x00a2, 2},
-    {-7, -7, 0x0080, 2},
-    { 7, -7, 0x0082, 2},
-    {-7,  7, 0x00a0, 2},
-    { 7,  7, 0x00a2, 2},
-    {-7, -7, 0x0084, 2},
-    { 7, -7, 0x0086, 2},
-    {-7,  7, 0x00a4, 2},
-    { 7,  7, 0x00a6, 2},
-    {-8, -8, 0x0084, 2},
-    { 8, -8, 0x0086, 2},
-    {-8,  8, 0x00a4, 2},
-    { 8,  8, 0x00a6, 2},
-  };
-  static const int8 kKholdstare_Draw_X[16] = {8, 7, 4, 2, 0, -2, -4, -7, -8, -7, -4, -2, 0, 2, 4, 7};
-  static const int8 kKholdstare_Draw_Y[16] = {0, 2, 4, 7, 8, 7, 4, 2, 0, -2, -4, -7, -8, -7, -4, -2};
-  static const uint8 kKholdstare_Draw_Char[16] = {0xac, 0xac, 0xaa, 0x8c, 0x8c, 0x8c, 0xaa, 0xac, 0xac, 0xaa, 0xaa, 0x8c, 0x8c, 0x8c, 0xaa, 0xac};
-  static const uint8 kKholdstare_Draw_Flags[16] = {0x40, 0x40, 0x40, 0, 0, 0, 0, 0, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xc0, 0xc0};
-  PrepOamCoordsRet info;
-  if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
-    return;
-  OamEnt *oam = GetOamCurPtr();
-  int j = sprite_A[k];
-  SetOamHelper0(oam, info.x + kKholdstare_Draw_X[j], info.y + kKholdstare_Draw_Y[j],
-                kKholdstare_Draw_Char[j], kKholdstare_Draw_Flags[j] | info.flags, 2);
-  oam_cur_ptr += 4, oam_ext_cur_ptr += 1;
-  Sprite_DrawMultiple(k, &kKholdstare_Dmd[sprite_graphics[k] * 4], 4, &info);
-}
-
-int Sprite_SpawnFireball(int k) {  // 8dda06
-  SpriteSpawnInfo info;
-  SpriteSfx_QueueSfx3WithPan(k, 0x19);
-  int j = Sprite_SpawnDynamicallyEx(k, 0x55, &info, 13);
-  if (j < 0)
-    return j;
-  Sprite_SetX(j, info.r0_x + 4);
-  Sprite_SetY(j, info.r2_y + 4 - info.r4_z);
-
-  sprite_flags3[j] = sprite_flags3[j] & 0xfe | 0x40;
-  sprite_oam_flags[j] = 6;
-  sprite_flags4[j] = 0x54;
-  sprite_E[j] = 0x54;
-  sprite_flags2[j] = 0x20;
-  Sprite_ApplySpeedTowardsLink(j, 0x20);
-  sprite_delay_main[j] = 20;
-  sprite_delay_aux1[j] = 16;
-  sprite_flags5[j] = 0;
-  sprite_defl_bits[j] = 0x48;
-  return j;
-}
-
-void ArcheryGameGuy_Draw(int k) {  // 8ddac4
-  static const int8 kArcheryGameGuy_Draw_X[15] = {0, 0, 0, 0, 0, -5, 0, -1, -1, 0, 0, 0, 0, 1, 1};
-  static const int8 kArcheryGameGuy_Draw_Y[15] = {0, -10, -10, 0, -10, -3, 0, -10, -10, 0, -10, -10, 0, -10, -10};
-  static const uint8 kArcheryGameGuy_Draw_Char[15] = {0x26, 6, 6, 8, 6, 0x3a, 0x26, 6, 6, 0x26, 6, 6, 0x26, 6, 6};
-  static const uint8 kArcheryGameGuy_Draw_Flags[15] = {8, 6, 6, 8, 6, 8, 8, 6, 6, 8, 6, 6, 8, 6, 6};
-  static const uint8 kArcheryGameGuy_Draw_Big[15] = {2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2};
-
-  Oam_AllocateDeferToPlayer(k);
-  PrepOamCoordsRet info;
-  Sprite_PrepOamCoord(k, &info);
-  OamEnt *oam = GetOamCurPtr();
-  int g = sprite_graphics[k];
-  for (int i = 2; i >= 0; i--, oam++) {
-    int j = g * 3 + i;
-    SetOamPlain(oam, info.x + kArcheryGameGuy_Draw_X[j], info.y + kArcheryGameGuy_Draw_Y[j],
-                 kArcheryGameGuy_Draw_Char[j], kArcheryGameGuy_Draw_Flags[j] | info.flags, kArcheryGameGuy_Draw_Big[j]);
-  }
-  SpriteDraw_Shadow(k, &info);
-}
-
-void ShopKeeper_RapidTerminateReceiveItem() {  // 8ffaea
-  for (int i = 4; i >= 0; i--) {
-    if (ancilla_type[i] == 0x22)
-      ancilla_aux_timer[i] = 1;
-  }
-}
-
-void Sprite_InitializeSecondaryItemMinigame(int what) {  // 8ffd86
-  is_archer_or_shovel_game = what;
-  Link_ResetProperties_C();
-  for (int k = 4; k >= 0; k--) {
-    if (ancilla_type[k] == 0x30 || ancilla_type[k] == 0x31) {
-      ancilla_type[k] = 0;
-    } else if (ancilla_type[k] == 5) {
-      flag_for_boomerang_in_place = 0;
-      ancilla_type[k] = 0;
-    }
-  }
-}
-
-void Waterfall(int k) {  // 9af5b8
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  if (Sprite_CheckDamageToLink_same_layer(k)) {
-    if (BYTE(overworld_screen_index) == 0x43)
-      AncillaAdd_GTCutscene();
-    else
-      AncillaAdd_WaterfallSplash();
-  }
-}
-
-void Sprite_BatCrash(int k) {  // 9af5d9
-  static const uint16 kRetreatBat_Xpos[4] = {0x7dc, 0x7f0, 0x820, 0x818};
-  static const uint16 kRetreatBat_Ypos[4] = {0x62e, 0x636, 0x630, 0x5e0};
-  static const uint8 kRetreatBat_Delay[5] = {4, 3, 4, 6, 0};
-  int j;
-  RetreatBat_Draw(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  Sprite_MoveXY(k);
-  BatCrash_DrawHardcodedGarbage(k);
-  bg1_y_offset = 0;
-  if (sprite_delay_aux3[k]) {
-    if (sprite_delay_aux3[k] == 1)
-      sound_effect_ambient = 5;
-    bg1_y_offset = sprite_delay_aux3[k] & 1 ? 1 : -1;
-  }
-  if (!sprite_delay_main[k]) {
-    sprite_graphics[k] = sprite_graphics[k] + 1 & 3;
-    if (sprite_graphics[k] == 0 && sprite_ai_state[k] < 2)
-      SpriteSfx_QueueSfx2WithPan(k, 0x3);
-    sprite_delay_main[k] = kRetreatBat_Delay[sprite_D[k]];
-  }
-  switch(sprite_ai_state[k]) {
-  case 0: {
-    j = sprite_A[k];
-    if (kRetreatBat_Xpos[j] < cur_sprite_x) {
-      if (j >= 2) {
-        sprite_ai_state[k]++;
-        sprite_delay_aux1[k] = 208;
-      }
-      sprite_A[k]++;
-      sprite_D[k]++;
-    }
-update_pos:
-    if (!(frame_counter & 7))
-      sprite_y_vel[k] += (kRetreatBat_Ypos[j] >= cur_sprite_y) ? 1 : -1;
-    if (!(frame_counter & 15))
-      sprite_x_vel[k]++;
-    break;
-  }
-  case 1:
-    if (!sprite_delay_aux1[k]) {
-      sprite_ai_state[k]++;
-      SpriteSfx_QueueSfx3WithPan(k, 0x26);
-      sprite_D[k]++;
-      sprite_x_lo[k] = 232;
-      sprite_x_hi[k] = 7;
-      sprite_y_lo[k] = 224;
-      sprite_y_hi[k] = 5;
-      sprite_x_vel[k] = 0;
-      sprite_y_vel[k] = 64;
-      sprite_delay_aux1[k] = 45;
-    } else {
-      if (!(frame_counter & 3))
-        sprite_x_vel[k]--;
-      j = sprite_A[k];
-      goto update_pos;
-    }
-    break;
-  case 2:
-    if (!sprite_delay_aux1[k]) {
-      sprite_y_vel[k] = 0;
-      sprite_delay_aux1[k] = 96;
-      sprite_ai_state[k]++;
-    }
-    if (sprite_delay_aux1[k] == 9) {
-      BatCrash_SpawnDebris(k);
-      CreatePyramidHole();
-    }
-    break;
-  case 3:  // Finishing Up
-    if (!sprite_delay_aux1[k]) {
-      sprite_state[k] = 0;
-      overworld_map_state++;
-    }
-    break;
-  }
-}
-
-void Sprite_SpawnBatCrashCutscene() {  // 9af6f5
-  SpriteSpawnInfo info;
-  int j = Sprite_SpawnDynamically(0, 0x37, &info);
-  if (j >= 0) {
-    sprite_y_vel[j] = 0;
-    sprite_B[j] = 0;
-    sprite_D[j] = 0;
-    sprite_floor[j] = 0;
-    sprite_subtype2[j] = 1;
-    sprite_flags2[j] = 1;
-    sprite_flags3[j] = 1;
-    sprite_oam_flags[j] = 1;
-    sprite_x_lo[j] = 204;
-    sprite_x_hi[j] = 7;
-    sprite_y_lo[j] = 50;
-    sprite_y_hi[j] = 6;
-    sprite_defl_bits[j] = 128;
-  }
-}
-
-void BatCrash_DrawHardcodedGarbage(int k) {  // 9af750
-  static const OamEntSigned kRetreatBat_Oams[8] = {
-    { 104, -105, 0x57, 0x01},
-    { 120, -105, 0x57, 0x01},
-    {-120, -105, 0x57, 0x01},
-    { 104,  -89, 0x57, 0x01},
-    { 120,  -89, 0x57, 0x01},
-    {-120,  -89, 0x57, 0x01},
-    { 101, -112, 0x57, 0x01},
-    {-117, -112, 0x57, 0x01},
-  };
-  memcpy(oam_buf + 76, kRetreatBat_Oams, 32);
-  for (int i = 0; i < 9; i++) // wtf 9
-    bytewise_extended_oam[i + 76] = 2;
-}
-
-void BatCrash_SpawnDebris(int k) {  // 9af7e5
-  static const int8 kPyramidDebris_X[30] = {
-    -8,  0,  8, 16, 24, 32, -8,  0,  8, 16, 24, 32, -8,  0, 8, 16,
-    24, 32, -8,  0,  8, 16, 24, 32, -8,  0,  8, 16, 24, 32,
-  };
-  static const int8 kPyramidDebris_Y[30] = {
-    0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x20, 0x20, 0x20, 0x20,
-    0x20, 0x20, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
-  };
-  static const int8 kPyramidDebris_Xvel[30] = {
-    -30, -25,  -8,   8,  25, 30, -50, -45, -20,  20,  45, 50, -50, -35, -25, 25,
-     35,  50, -45, -50, -60, 60,  50,  45, -30, -35, -40, 40,  35,  30,
-  };
-  static const int8 kPyramidDebris_Yvel[30] = {
-     2,  5,  10,  10,   5,   2,   5,  20,  30,  30,  20,   5,  10,  30, 40, 40,
-    30, 10, -20, -40, -60, -60, -40, -20, -10, -20, -40, -40, -20, -10,
-  };
-  for (int j = 29; j >= 0; j--) {
-    GarnishSpawn_PyramidDebris(kPyramidDebris_X[j], kPyramidDebris_Y[j], kPyramidDebris_Xvel[j], kPyramidDebris_Yvel[j]);
-  }
-  sprite_delay_aux3[k] = 32;
-}
-
-void RetreatBat_Draw(int k) {  // 9af833
-  static const DrawMultipleData kRetreatBat_Dmds[18] = {
-    { 0,  0, 0x044b, 0},
-    { 5, -4, 0x045b, 0},
-    {-2, -4, 0x0464, 2},
-    {-2, -4, 0x0449, 2},
-    {-8, -9, 0x046c, 2},
-    { 8, -9, 0x446c, 2},
-    {-8, -7, 0x044c, 2},
-    { 8, -7, 0x444c, 2},
-    {-8, -9, 0x0444, 2},
-    { 8, -9, 0x4444, 2},
-    {-8, -8, 0x0462, 2},
-    { 8, -8, 0x4462, 2},
-    {-8, -7, 0x0460, 2},
-    { 8, -7, 0x4460, 2},
-    { 0,  0, 0x044e, 2},
-    {16,  0, 0x444e, 2},
-    { 0, 16, 0x046e, 2},
-    {16, 16, 0x446e, 2},
-  };
-  static const uint8 kOffs[] = {0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 6, 6, 8, 10, 12, 10, 14, 14, 14, 14};
-  static const uint8 kCount[20] = { 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 4, 4, 4, 4, };
-  oam_cur_ptr = 0x960;
-  oam_ext_cur_ptr = 0xa78;
-  int j = sprite_D[k] * 4 + sprite_graphics[k];
-  Sprite_DrawMultiple(k, &kRetreatBat_Dmds[kOffs[j]], kCount[j], NULL);
-}
-
-void DrinkingGuy_Draw(int k) {  // 9af88c
-  static const DrawMultipleData kDrinkingGuy_Dmd[6] = {
-    {8,  2, 0x00ae, 0},
-    {0, -9, 0x0822, 2},
-    {0,  0, 0x0006, 2},
-    {7,  0, 0x00af, 0},
-    {0, -9, 0x0822, 2},
-    {0,  0, 0x0006, 2},
-  };
-  PrepOamCoordsRet info;
-  Sprite_DrawMultiplePlayerDeferred(k, &kDrinkingGuy_Dmd[sprite_graphics[k] * 3], 3, &info);
-  SpriteDraw_Shadow(k, &info);
-}
-
-void Lady_Draw(int k) {  // 9af92c
-  static const DrawMultipleData kLadyDmd[16] = {
-    {0, -8, 0x00e0, 2},
-    {0,  0, 0x00e8, 2},
-    {0, -7, 0x00e0, 2},
-    {0,  1, 0x40e8, 2},
-    {0, -8, 0x00c0, 2},
-    {0,  0, 0x00c2, 2},
-    {0, -7, 0x00c0, 2},
-    {0,  1, 0x40c2, 2},
-    {0, -8, 0x00e2, 2},
-    {0,  0, 0x00e4, 2},
-    {0, -7, 0x00e2, 2},
-    {0,  1, 0x00e6, 2},
-    {0, -8, 0x40e2, 2},
-    {0,  0, 0x40e4, 2},
-    {0, -7, 0x40e2, 2},
-    {0,  1, 0x40e6, 2},
-  };
-  PrepOamCoordsRet info;
-  Sprite_DrawMultiplePlayerDeferred(k, &kLadyDmd[sprite_graphics[k] * 2 + sprite_D[k] * 4], 2, &info);
-  SpriteDraw_Shadow(k, &info);
-}
-
-void Lanmola_SpawnShrapnel(int k) {  // 9af981
-  static const int8 kLanmolaShrapnel_Yvel[8] = {28, -28, 28, -28, 0, 36, 0, -36};
-  static const int8 kLanmolaShrapnel_Xvel[8] = {-28, -28, 28, 28, -36, 0, 36, 0};
-
-  tmp_counter = (sprite_state[0] + sprite_state[1] + sprite_state[2]) < 10 ? 7 : 3;
-  do {
-    SpriteSpawnInfo info;
-    int j = Sprite_SpawnDynamically(k, 0xC2, &info);
-    if (j >= 0) {
-      Sprite_SetSpawnedCoordinates(j, &info);
-      sprite_x_lo[j] = info.r0_x + 4;
-      sprite_y_lo[j] = info.r2_y + 4;
-      sprite_ignore_projectile[j] = 1;
-      sprite_bump_damage[j] = 1;
-      sprite_flags4[j] = 1;
-      sprite_z[j] = 0;
-      sprite_flags2[j] = 0x20;
-      sprite_x_vel[j] = kLanmolaShrapnel_Xvel[tmp_counter];
-      sprite_y_vel[j] = kLanmolaShrapnel_Yvel[tmp_counter];
-      sprite_graphics[j] = GetRandomNumber() & 1;
-    }
-  } while (!sign8(--tmp_counter));
-}
-
-void Sprite_Cukeman(int k) {  // 9afa0c
-  if (sprite_head_dir[k] == 0)
-    return;
-
-  if (sprite_state[k] == 9 && !(submodule_index | flag_unk1) &&
-      (uint16)(cur_sprite_x - link_x_coord + 0x18) < 0x30 &&
-      (uint16)(link_y_coord - cur_sprite_y + 0x20) < 0x30 &&
-      (filtered_joypad_L & 0x80)) {
-    dialogue_message_index = 0x17a + (sprite_subtype[k]++ & 1);
-    Sprite_ShowMessageMinimal();
-  }
-
-  uint8 old = sprite_oam_flags[k] & 0xf0;
-  sprite_oam_flags[k] = old | 8;
-  Cukeman_Draw(k);
-  sprite_oam_flags[k] = old | 0xd;
-  Oam_AllocateFromRegionA(0x10);
-}
-
-void Cukeman_Draw(int k) {  // 9afb0e
-  static const DrawMultipleData kCukeman_Dmd[18] = {
-    { 0, 0, 0x01f3, 0},
-    { 7, 0, 0x41f3, 0},
-    { 4, 7, 0x07e0, 0},
-    {-1, 2, 0x01f3, 0},
-    { 6, 1, 0x41f3, 0},
-    { 4, 8, 0x07e0, 0},
-    { 1, 1, 0x01f3, 0},
-    { 8, 2, 0x41f3, 0},
-    { 4, 8, 0x07e0, 0},
-    {-2, 0, 0x01f3, 0},
-    {10, 0, 0x41f3, 0},
-    { 4, 7, 0x07e0, 0},
-    { 0, 0, 0x01f3, 0},
-    { 8, 0, 0x41f3, 0},
-    { 4, 6, 0x07e0, 0},
-    {-5, 0, 0x01f3, 0},
-    {16, 0, 0x41f3, 0},
-    { 4, 8, 0x07e0, 0},
-  };
-  Sprite_DrawMultiple(k, &kCukeman_Dmd[sprite_graphics[k] * 3], 3, NULL);
-}
-
-void RunningBoy_SpawnDustGarnish(int k) {  // 9afb2c
-  if (++sprite_die_action[k] & 0xf)
-    return;
-  int j = GarnishAllocForce();
-  garnish_type[j] = 20;
-  garnish_active = 20;
-  Garnish_SetX(j, Sprite_GetX(k) + 4);
-  Garnish_SetY(j, Sprite_GetY(k) + 28);
-  garnish_countdown[j] = 10;
-}
-
-void MovableMantle_Draw(int k) {  // 9afcb3
-  Oam_AllocateFromRegionB(0x20);
-  PrepOamCoordsRet info;
-  if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
-    return;
-  OamEnt *oam = GetOamCurPtr();
-  for (int i = 5; i >= 0; i--, oam++) {
-    oam->x = kMovableMantle_X[i] + info.x;
-    oam->y = kMovableMantle_Y[i] + info.y;
-    oam->charnum = kMovableMantle_Char[i];
-    oam->flags = kMovableMantle_Flags[i];
-  }
-  Sprite_CorrectOamEntries(k, 5, 2);
-}
-
-void Mothula_Draw(int k) {  // 9afdb5
-  static const DrawMultipleData kMothula_Dmd[24] = {
-    {-24, -8, 0x0080, 2},
-    { -8, -8, 0x0082, 2},
-    {  8, -8, 0x4082, 2},
-    { 24, -8, 0x4080, 2},
-    {-24,  8, 0x00a0, 2},
-    { -8,  8, 0x00a2, 2},
-    {  8,  8, 0x40a2, 2},
-    { 24,  8, 0x40a0, 2},
-    {-24, -8, 0x0084, 2},
-    { -8, -8, 0x0086, 2},
-    {  8, -8, 0x4086, 2},
-    { 24, -8, 0x4084, 2},
-    {-24,  8, 0x00a4, 2},
-    { -8,  8, 0x00a6, 2},
-    {  8,  8, 0x40a6, 2},
-    { 24,  8, 0x40a4, 2},
-    { -8, -8, 0x0088, 2},
-    { -8, -8, 0x0088, 2},
-    {  8, -8, 0x4088, 2},
-    {  8, -8, 0x4088, 2},
-    { -8,  8, 0x00a8, 2},
-    { -8,  8, 0x00a8, 2},
-    {  8,  8, 0x40a8, 2},
-    {  8,  8, 0x40a8, 2},
-  };
-  oam_cur_ptr = 0x920;
-  oam_ext_cur_ptr = 0xa68;
-  PrepOamCoordsRet info;
-  Sprite_DrawMultiple(k, &kMothula_Dmd[sprite_graphics[k] * 8], 8, &info);
-  if (sprite_pause[k])
-    return;
-  info.y += sprite_z[k];
-  static const int8 kMothula_Draw_X[27] = {
-    0,  3, 6, 9, 12, -3, -6, -9, -12,  0,  2, 4, 6, 8, -2, -4,
-    -6, -8, 0, 1,  2,  3,  4, -1,  -2, -3, -4,
-  };
-  OamEnt *oam = GetOamCurPtr() + 10;
-  int g = sprite_graphics[k];
-  for (int i = 8; i >= 0; i--, oam++) {
-    SetOamHelper0(oam, info.x + kMothula_Draw_X[g * 9 + i], info.y + 16,
-                  0x6c, 0x24, 2);
-  }
-}
-
-void BottleMerchant_BuyBee(int k) {  // 9afe88
-  static const int8 kBottleVendor_GoodBeeX[5] = {-6, -3, 0, 4, 7};
-  static const int8 kBottleVendor_GoodBeeY[5] = {11, 14, 16, 14, 11};
-  SpriteSpawnInfo info;
-  SpriteSfx_QueueSfx3WithPan(k, 0x13);
-  tmp_counter = 4;
-  do {
-    int j = Sprite_SpawnDynamically(k, 0xdb, &info);
-    if (j >= 0) {
-      Sprite_SetSpawnedCoordinates(j, &info);
-      sprite_x_lo[j] = info.r0_x + 4;
-      sprite_stunned[j] = 0xff;
-      sprite_x_vel[j] = kBottleVendor_GoodBeeX[tmp_counter];
-      sprite_y_vel[j] = kBottleVendor_GoodBeeY[tmp_counter];
-      sprite_z_vel[j] = 32;
-      sprite_delay_aux4[j] = 32;
-    }
-  } while (!sign8(--tmp_counter));
-}
-
-void Sprite_ChickenLady(int k) {  // 9afed3
-  sprite_D[k] = 1;
-  Lady_Draw(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  if (sprite_delay_main[k] == 1) {
-    dialogue_message_index = 0x17d;
-    Sprite_ShowMessageMinimal();
-  }
-  sprite_graphics[k] = frame_counter >> 4 & 1;
-}
-
-void Overworld_DrawWoodenDoor(uint16 pos, bool unlocked) {  // 9bc952
-  Overworld_DrawMap16_Persist(pos, unlocked ? 0xda5 : 0xda4);
-  Overworld_DrawMap16_Persist(pos+2, unlocked ? 0xda7 : 0xda6);
-  nmi_load_bg_from_vram = 1;
-}
-
-void Sprite_D4_Landmine(int k) {  // 9d8099
-  static const uint8 kLandMine_OamFlags[4] = {4, 2, 8, 2};
-
-  Landmine_Draw(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  if (!Landmine_CheckDetonationFromHammer(k)) {
-    if (!sprite_delay_main[k]) {
-      sprite_oam_flags[k] = 4;
-      if (Sprite_CheckDamageToLink(k))
-        sprite_delay_main[k] = 8;
-      return;
-    }
-    if (sprite_delay_main[k] != 1) {
-      sprite_oam_flags[k] = kLandMine_OamFlags[sprite_delay_main[k] >> 1 & 3];
-      return;
-    }
-  }
-  sprite_state[k] = 0;
-  int j = Sprite_SpawnBomb(k);
-  if (j >= 0) {
-    sprite_state[j] = 6;
-    sprite_C[j] = 2;
-    sprite_oam_flags[j] = 2;
-    sprite_flags4[j] = 9;
-    sprite_delay_aux1[j] = 31;
-    sprite_flags2[j] = 3;
-    sound_effect_1 = Sprite_CalculateSfxPan(k) | 12;
-  }
-}
-
-void Landmine_Draw(int k) {  // 9d810c
-  static const DrawMultipleData kLandmine_Dmd[2] = {
-    {0, 4, 0x0070, 0},
-    {8, 4, 0x4070, 0},
-  };
-  Oam_AllocateFromRegionB(8);
-  if (byte_7E0FC6 >= 3)
-    return;
-  Sprite_DrawMultiple(k, kLandmine_Dmd, 2, NULL);
-}
-
-void Sprite_D3_Stal(int k) {  // 9d8129
-  static const uint8 kStal_Gfx[5] = {2, 2, 1, 0, 1};
-  if (byte_7E0FC6 < 3) {
-    if (!sprite_ai_state[k])
-      Oam_AllocateFromRegionB(4);
-    Stal_Draw(k);
-  }
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  if (Sprite_ReturnIfRecoiling(k))
-    return;
-  switch(sprite_ai_state[k]) {
-  case 0: // dormant
-    sprite_ignore_projectile[k] = 1;
-    if (Sprite_CheckDamageToLink_same_layer(k)) {
-      Sprite_NullifyHookshotDrag();
-      Sprite_RepelDash();
-      if (!sprite_delay_main[k]) {
-        sprite_delay_main[k] = 64;
-        SpriteSfx_QueueSfx2WithPan(k, 0x22);
-      }
-    }
-    if (sprite_delay_main[k] != 0) {
-      if (sprite_delay_main[k] - 1) {
-        sprite_hit_timer[k] = (sprite_delay_main[k] - 1) | 64;
-      } else {
-        sprite_ignore_projectile[k] = 0;
-        sprite_ai_state[k]++;
-        sprite_hit_timer[k] = 0;
-        sprite_flags3[k] &= ~0x40;
-        sprite_flags2[k] &= ~0x80;
-      }
-    }
-    break;
-  case 1: // active
-    Sprite_CheckDamageToAndFromLink(k);
-    Sprite_MoveXYZ(k);
-    Sprite_CheckTileCollision(k);
-    sprite_z_vel[k]-=2;
-    if (sign8(sprite_z[k])) {
-      sprite_z[k] = 0;
-      sprite_z_vel[k] = 16;
-      Sprite_ApplySpeedTowardsLink(k, 12);
-    }
-    if (!(frame_counter & 3) && ++sprite_subtype2[k] == 5)
-      sprite_subtype2[k] = 0;
-    sprite_graphics[k] = kStal_Gfx[sprite_subtype2[k]];
-    break;
-  }
-}
-
-void Stal_Draw(int k) {  // 9d820c
-  static const DrawMultipleData kStal_Dmd[6] = {
-    {0,  0, 0x0044, 2},
-    {4, 11, 0x0070, 0},
-    {0,  0, 0x0044, 2},
-    {4, 12, 0x0070, 0},
-    {0,  0, 0x0044, 2},
-    {4, 13, 0x0070, 0},
-  };
-  PrepOamCoordsRet info;
-  int n = sprite_ai_state[k] ? 2 : 1;
-  Sprite_DrawMultiple(k, &kStal_Dmd[sprite_graphics[k] * 2], n, &info);
-  if (sprite_ai_state[k])
-    SpriteDraw_Shadow(k, &info);
-}
-
-void Sprite_D2_FloppingFish(int k) {  // 9d8235
-  static const int8 kFish_Xvel[8] = {0, 12, 16, 12, 0, -12, -16, -12};
-  static const int8 kFish_Yvel[8] = {-16, -12, 0, 12, 16, 12, 0, -12};
-  static const uint8 kFish_Tab1[2] = {2, 0};
-  static const uint8 kFish_Gfx[3] = {1, 5, 3};
-  static const uint8 kFish_Gfx2[17] = {5, 5, 6, 6, 5, 5, 4, 4, 3, 7, 7, 8, 8, 7, 7, 8, 8 };
-
-  if (byte_7E0FC6 < 3)
-    Fish_Draw(k);
-  if (sprite_state[k] == 10) {
-    sprite_ai_state[k] = 4;
-    sprite_graphics[k] = (frame_counter >> 4 & 1) + 3;
-  }
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  switch (sprite_ai_state[k]) {
-  case 0:  // check deep water
-    Sprite_CheckTileCollision(k);
-    if (sprite_tiletype == 8)
-      sprite_state[k] = 0;
-    else
-      sprite_ai_state[k] = 1;
-    break;
-  case 1:  // flop around
-    Sprite_CheckIfLifted_permissive(k);
-    Sprite_BounceFromTileCollision(k);
-    Sprite_MoveXYZ(k);
-    sprite_z_vel[k] -= 2;
-    if (sign8(sprite_z[k])) {
-      sprite_z[k] = 0;
-      if (sprite_tiletype == 9) {
-        Sprite_SpawnSmallSplash(k);
-      } else if (sprite_tiletype == 8) {
-        sprite_state[k] = 0;
-        Sprite_SpawnSmallSplash(k);
-      }
-      sprite_z_vel[k] = (GetRandomNumber() & 15) + 16;
-      int j = GetRandomNumber() & 7;
-      sprite_x_vel[k] = kFish_Xvel[j];
-      sprite_y_vel[k] = kFish_Yvel[j];
-      sprite_D[k]++;
-      sprite_subtype2[k] = 3;
-    }
-    sprite_subtype2[k]++;
-    if (!(sprite_subtype2[k] & 7)) {
-      int j = sprite_D[k] & 1;
-      if (sprite_A[k] != kFish_Tab1[j])
-        sprite_A[k] += j ? -1 : 1;
-    }
-    sprite_graphics[k] = kFish_Gfx[sprite_A[k]] + (frame_counter >> 3 & 1);
-    break;
-  case 2:  // pause before leap
-    if (!sprite_delay_main[k]) {
-      sprite_ai_state[k] = 3;
-      sprite_z_vel[k] = 48;
-      Sprite_SpawnSmallSplash(k);
-    }
-    break;
-  case 3:  // leaping
-    Sprite_MoveZ(k);
-    sprite_z_vel[k] -= 2;
-    if (sprite_z_vel[k] == 0 && sprite_A[k] != 0) {
-      dialogue_message_index = 0x176;
-      Sprite_ShowMessageMinimal();
-    }
-    if (sign8(sprite_z[k])) {
-      sprite_z[k] = 0;
-      Sprite_SpawnSmallSplash(k);
-      if (sprite_A[k]) {
-        SpriteSpawnInfo info;
-        int j = Sprite_SpawnDynamically(k, 0xdb, &info);
-        if (j >= 0) {
-          Sprite_SetSpawnedCoordinates(j, &info);
-          Sprite_SetX(j, info.r0_x + 4);
-          sprite_stunned[j] = 255;
-          sprite_z_vel[j] = 48;
-          sprite_delay_aux3[j] = 48;
-          Sprite_ApplySpeedTowardsLink(j, 16);
-        }
-      }
-      sprite_state[k] = 0;
-    }
-    sprite_graphics[k] = kFish_Gfx2[++sprite_subtype2[k] >> 2];
-    break;
-  case 4:  // wiggle
-    if (!sprite_z[k])
-      sprite_ai_state[k] = 1;
-    Sprite_MoveXY(k);
-    ThrownSprite_TileAndSpriteInteraction(k);
-    break;
-  }
-}
-
-void Fish_Draw(int k) {  // 9d8483
-  static const DrawMultipleData kFish_Dmd[16] = {
-    {-4, 8, 0x045e, 0},
-    { 4, 8, 0x045f, 0},
-    {-4, 8, 0x845e, 0},
-    { 4, 8, 0x845f, 0},
-    {-4, 8, 0x445f, 0},
-    { 4, 8, 0x445e, 0},
-    {-4, 8, 0xc45f, 0},
-    { 4, 8, 0xc45e, 0},
-    { 0, 0, 0x0461, 0},
-    { 0, 8, 0x0471, 0},
-    { 0, 0, 0x4461, 0},
-    { 0, 8, 0x4471, 0},
-    { 0, 0, 0x8471, 0},
-    { 0, 8, 0x8461, 0},
-    { 0, 0, 0xc471, 0},
-    { 0, 8, 0xc461, 0},
-  };
-  static const DrawMultipleData kFish_Dmd2[9] = {
-    {-2, 11, 0x0438, 0},
-    { 0, 11, 0x0438, 0},
-    { 2, 11, 0x0438, 0},
-    {-1, 11, 0x0438, 0},
-    { 0, 11, 0x0438, 0},
-    { 1, 11, 0x0438, 0},
-    { 0, 11, 0x0438, 0},
-    { 0, 11, 0x0438, 0},
-    { 0, 11, 0x0438, 0},
-  };
-  PrepOamCoordsRet info;
-  if (sprite_graphics[k] == 0) {
-    Sprite_PrepOamCoord(k, &info);
-    return;
-  }
-  cur_sprite_x += 4;
-  Sprite_DrawMultiple(k, &kFish_Dmd[(sprite_graphics[k] - 1) * 2], 2, &info);
-  cur_sprite_y += sprite_z[k];
-  int j = sprite_z[k] >> 2;
-  oam_cur_ptr += 8, oam_ext_cur_ptr += 2;
-  Sprite_DrawMultiple(k, &kFish_Dmd2[((j >= 2) ? 2 : j) * 3], 3, &info);
-  Sprite_Get16BitCoords(k);
-}
-
-void ChimneySmoke_Draw(int k) {  // 9d8531
-  static const DrawMultipleData kChimneySmoke_Dmd[8] = {
-    {0, 0, 0x0086, 0},
-    {8, 0, 0x0087, 0},
-    {0, 8, 0x0096, 0},
-    {8, 8, 0x0097, 0},
-    {1, 1, 0x0086, 0},
-    {7, 1, 0x0087, 0},
-    {1, 7, 0x0096, 0},
-    {7, 7, 0x0097, 0},
-  };
-  Sprite_DrawMultiple(k, &kChimneySmoke_Dmd[(sprite_graphics[k] & 1) * 4], 4, NULL);
-}
-
-void Sprite_D1_BunnyBeam(int k) {  // 9d858b
-  if (player_is_indoors)
-    Sprite_BunnyBeam(k);
-  else
-    Sprite_Chimney(k);
-
-}
-
-void Sprite_Chimney(int k) {  // 9d858f
-  sprite_flags3[k] = 64;
-  sprite_ignore_projectile[k] = 64;
-  if (!sprite_ai_state[k]) {
-    if (Sprite_ReturnIfInactive(k))
-      return;
-    if (sprite_delay_main[k])
-      return;
-    sprite_delay_main[k] = 67;
-    SpriteSpawnInfo info;
-    int j = Sprite_SpawnDynamically(k, 0xd1, &info);
-    if (j < 0)
-      return;
-    Sprite_SetSpawnedCoordinates(j, &info);
-    int t = (uint8)info.r0_x + 8;
-    sprite_x_lo[j] = t;
-    sprite_y_lo[j] = info.r2_y + 4 + (t >> 8);
-    sprite_oam_flags[j] = 4;
-    sprite_ai_state[j] = 4;
-    sprite_flags2[j] = 67;
-    sprite_flags3[j] = 67;
-    sprite_x_vel[j] = -4;
-    sprite_y_vel[j] = -6;
-  } else {
-    sprite_obj_prio[k] = 0x30;
-    ChimneySmoke_Draw(k);
-    if (Sprite_ReturnIfInactive(k))
-      return;
-    Sprite_MoveXY(k);
-    if (!(++sprite_subtype2[k] & 7)) {
-      int j = sprite_D[k] & 1;
-      sprite_x_vel[k] += j ? -1 : 1;
-      if (sprite_x_vel[k] == (uint8)(j ? -4 : 4))
-        sprite_D[k]++;
-    }
-    if (!(sprite_subtype2[k] & 31))
-      sprite_graphics[k]++;
-  }
-}
-
-void Sprite_BunnyBeam(int k) {  // 9d85e0
-  static const uint8 kRabbitBeam_Gfx[6] = {0xd7, 0xd7, 0xd7, 0x91, 0x91, 0x91};
-  PrepOamCoordsRet info;
-  if (!sprite_ai_state[k]) {
-    Sprite_PrepOamCoord(k, &info);
-    if (Sprite_ReturnIfInactive(k))
-      return;
-    if (!Sprite_CheckTileCollision(k)) {
-      sprite_ai_state[k]++;
-      sprite_delay_main[k] = 128;
-    }
-    return;
-  }
-
-  SpriteDraw_Antfairy(k);
-  if (!sprite_pause[k]) {
-    OamEnt *oam = GetOamCurPtr();
-    uint8 charnum = kRabbitBeam_Gfx[sprite_graphics[k]];
-    for (int i = 0; i < 5; i++) {
-      oam[i].charnum = charnum;
-      oam[i].flags = oam[i].flags & 0xf0 | 2;
-    }
-  }
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  if (!sprite_delay_main[k]) {
-    sprite_bump_damage[k] = 0x30;
-    if (Sprite_CheckDamageToLink(k)) {
-      sprite_state[k] = 0;
-      link_timer_tempbunny = 256;
-    }
-    if (link_is_on_lower_level == sprite_floor[k])
-      Sprite_ApplySpeedTowardsLink(k, 16);
-    Sprite_MoveXY(k);
-    if (Sprite_CheckTileCollision(k)) {
-      sprite_state[k] = 0;
-      Sprite_SpawnPoofGarnish(k);
-      SpriteSfx_QueueSfx2WithPan(k, 0x15);
-    }
-  }
-}
-
-void Sprite_D0_Lynel(int k) {  // 9d866a
-  static const int8 kLynel_AttackGfx[4] = {5, 2, 8, 10};
-  static const int8 kLynel_Gfx[8] = {3, 0, 6, 9, 4, 1, 7, 10};
-  Lynel_Draw(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  if (Sprite_ReturnIfRecoiling(k))
-    return;
-  sprite_D[k] = Sprite_DirectionToFaceLink(k, NULL);
-  Sprite_CheckDamageToAndFromLink(k);
-  switch(sprite_ai_state[k]) {
-  case 0:  // target
-    if (!sprite_delay_main[k]) {
-      static const int8 kLynel_Xtarget[4] = {-96, 96, 0, 0};
-      static const int8 kLynel_Ytarget[4] = {8, 8, -96, 112};
-      int j = sprite_D[k];
-      int x = link_x_coord + kLynel_Xtarget[j];
-      sprite_A[k] = x, sprite_B[k] = x >> 8;
-      int y = link_y_coord + kLynel_Ytarget[j];
-      sprite_C[k] = y, sprite_E[k] = y >> 8;
-      sprite_ai_state[k]++;
-      sprite_delay_main[k] = 80;
-    }
-    sprite_graphics[k] = kLynel_Gfx[sprite_subtype2[k] & 4 | sprite_D[k]];
-    break;
-  case 1:  // approach
-    if (sprite_delay_main[k]) {
-      if (!((k ^ frame_counter) & 3)) {
-        uint16 x = sprite_A[k] | sprite_B[k] << 8;
-        uint16 y = sprite_C[k] | sprite_E[k] << 8;
-        if ((uint16)(x - cur_sprite_x + 5) < 10 && (uint16)(y - cur_sprite_y + 5) < 10)
-          goto incr_state;
-        ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLocation(k, x, y, 24);
-        sprite_x_vel[k] = pt.x;
-        sprite_y_vel[k] = pt.y;
-      }
-      Sprite_MoveXY(k);
-      if (Sprite_CheckTileCollision(k))
-        goto incr_state;
-      sprite_graphics[k] = kLynel_Gfx[++sprite_subtype2[k] & 4 | sprite_D[k]];
-    } else {
-incr_state:
-      sprite_ai_state[k]++;
-      sprite_delay_main[k] = 32;
-    }
-    break;
-  case 2:  // attack
-    if (!sprite_delay_main[k]) {
-      sprite_delay_main[k] = (GetRandomNumber() & 15) + 16;
-      sprite_ai_state[k] = 0;
-      return;
-    }
-    if (sprite_delay_main[k] == 16) {
-      int j = Sprite_SpawnFirePhlegm(k);
-      if (j >= 0 && link_shield_type != 3)
-        sprite_flags5[j] = 0;
-    }
-    sprite_graphics[k] = kLynel_AttackGfx[sprite_D[k]];
-    Sprite_CheckTileCollision(k);
-    break;
-  }
-}
-
-void Lynel_Draw(int k) {  // 9d8880
-  static const DrawMultipleData kLynel_Dmd[33] = {
-    {-5, -11, 0x00cc, 2},
-    {-4,   0, 0x00e4, 2},
-    { 4,   0, 0x00e5, 2},
-    {-5, -10, 0x00cc, 2},
-    {-4,   0, 0x00e7, 2},
-    { 4,   0, 0x00e8, 2},
-    {-5, -11, 0x00c8, 2},
-    {-4,   0, 0x00e4, 2},
-    { 4,   0, 0x00e5, 2},
-    { 5, -11, 0x40cc, 2},
-    {-4,   0, 0x40e5, 2},
-    { 4,   0, 0x40e4, 2},
-    { 5, -10, 0x40cc, 2},
-    {-4,   0, 0x40e8, 2},
-    { 4,   0, 0x40e7, 2},
-    { 5, -11, 0x40c8, 2},
-    {-4,   0, 0x40e8, 2},
-    { 4,   0, 0x40e7, 2},
-    { 0,  -9, 0x00ce, 2},
-    {-4,   0, 0x00ea, 2},
-    { 4,   0, 0x00eb, 2},
-    { 0,  -9, 0x00ce, 2},
-    {-4,   0, 0x40eb, 2},
-    { 4,   0, 0x40ea, 2},
-    { 0,  -9, 0x00ca, 2},
-    {-4,   0, 0x40eb, 2},
-    { 4,   0, 0x00eb, 2},
-    { 0, -14, 0x00c6, 2},
-    {-4,   0, 0x00ed, 2},
-    { 4,   0, 0x00ee, 2},
-    { 0, -14, 0x00c6, 2},
-    {-4,   0, 0x40ee, 2},
-    { 4,   0, 0x40ed, 2},
-  };
-  PrepOamCoordsRet info;
-  Sprite_DrawMultiple(k, &kLynel_Dmd[sprite_graphics[k] * 3], 3, &info);
-  SpriteDraw_Shadow(k, &info);
-}
-
-void Sprite_SpawnPhantomGanon(int k) {  // 9d88a1
-  SpriteSpawnInfo info;
-  int j = Sprite_SpawnDynamically(k, 0xc9, &info);
-  Sprite_SetSpawnedCoordinates(j, &info);
-  sprite_flags2[j] = 2;
-  sprite_ignore_projectile[j] = 2;
-  sprite_anim_clock[j] = 1;
-  sprite_oam_flags[j] = 0;
-}
-
-void Sprite_PhantomGanon(int k) {  // 9d88bc
-  static const uint8 kGanonBat_Gfx[4] = {0, 1, 2, 1};
-  static const int8 kGanonBat_TargetXvel[2] = {32, -32};
-  static const int8 kGanonBat_TargetYvel[2] = {16, -16};
-
-  if (!sprite_ai_state[k]) {
-    PhantomGanon_Draw(k);
-    if (Sprite_ReturnIfInactive(k))
-      return;
-    Sprite_MoveY(k);
-    if (!(++sprite_subtype2[k] & 31)) {
-      if (--sprite_y_vel[k] == 252) {
-        int j = SpawnBossPoof(k);
-        Sprite_SetY(j, Sprite_GetY(j) - 20);
-      } else if (sprite_y_vel[k] == 251) {
-        sprite_ai_state[k]++;
-        sprite_delay_main[k] = 255;
-        sprite_y_vel[k] = -4;
-      }
-    }
-  } else {
-    GanonBat_Draw(k);
-    if (sprite_pause[k]) {
-      sprite_state[k] = 0;
-      dung_savegame_state_bits |= 0x8000;
-    }
-    if (Sprite_ReturnIfInactive(k))
-      return;
-    sprite_graphics[k] = kGanonBat_Gfx[frame_counter >> 2 & 3];
-    if (sprite_delay_main[k]) {
-      if (sprite_delay_main[k] < 208) {
-        int j = sprite_head_dir[k] & 1;
-        sprite_y_vel[k] += j ? -1 : 1;
-        if (sprite_y_vel[k] == (uint8)kGanonBat_TargetYvel[j])
-          sprite_head_dir[k]++;
-        j = sprite_D[k] & 1;
-        sprite_x_vel[k] += j ? -1 : 1;
-        if (sprite_x_vel[k] == (uint8)kGanonBat_TargetXvel[j])
-          sprite_D[k]++;
-        if (sprite_x_vel[k] == 0)
-          SpriteSfx_QueueSfx3WithPan(k, 0x1e);
-      }
-      ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLocation(k, link_x_coord & 0xff00 | 0x78, link_y_coord & 0xff00 | 0x50, 5);
-      uint8 xvel = sprite_x_vel[k], yvel = sprite_y_vel[k];
-      sprite_x_vel[k] = xvel + pt.x, sprite_y_vel[k] = yvel + pt.y;
-      Sprite_MoveXY(k);
-      sprite_x_vel[k] = xvel, sprite_y_vel[k] = yvel;
-    } else {
-      Sprite_MoveXY(k);
-      if (sprite_x_vel[k] != 64) {
-        sprite_x_vel[k]++;
-        sprite_y_vel[k]--;
-      }
-    }
-  }
-}
-
-void GanonBat_Draw(int k) {  // 9d89eb
-  static const DrawMultipleData kGanonBat_Dmd[6] = {
-    {-8, 0, 0x0560, 2},
-    { 8, 0, 0x4560, 2},
-    {-8, 0, 0x0562, 2},
-    { 8, 0, 0x4562, 2},
-    {-8, 0, 0x0544, 2},
-    { 8, 0, 0x4544, 2},
-  };
-  Sprite_DrawMultiple(k, &kGanonBat_Dmd[sprite_graphics[k] * 2], 2, NULL);
-}
-
-void PhantomGanon_Draw(int k) {  // 9d8a84
-  static const DrawMultipleData kPhantomGanon_Dmd[16] = {
-    {-16, -8, 0x0d46, 2},
-    { -8, -8, 0x0d47, 2},
-    {  8, -8, 0x4d47, 2},
-    { 16, -8, 0x4d46, 2},
-    {-16,  8, 0x0d69, 2},
-    { -8,  8, 0x0d6a, 2},
-    {  8,  8, 0x4d6a, 2},
-    { 16,  8, 0x4d69, 2},
-    {-16, -8, 0x0d46, 2},
-    { -8, -8, 0x0d47, 2},
-    {  8, -8, 0x4d47, 2},
-    { 16, -8, 0x4d46, 2},
-    {-16,  8, 0x0d66, 2},
-    { -8,  8, 0x0d67, 2},
-    {  8,  8, 0x4d67, 2},
-    { 16,  8, 0x4d66, 2},
-  };
-  oam_cur_ptr = 0x950;
-  oam_ext_cur_ptr = 0xa74;
-  Sprite_DrawMultiple(k, &kPhantomGanon_Dmd[sprite_graphics[k] * 8], 8, NULL);
-}
-
-void SwishEvery16Frames(int k) {  // 9d8aa9
-  if (!(frame_counter & 15))
-    SpriteSfx_QueueSfx3WithPan(k, 0x6);
-}
-
-void Sprite_GanonTrident(int k) {  // 9d8ab6
-  Trident_Draw(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  Sprite_CheckDamageToAndFromLink(k);
-  SwishEvery16Frames(k);
-  Sprite_MoveXY(k);
-  sprite_G[k] = kGanon_G_Func2[--sprite_subtype2[k] >> 2 & 7];
-  if (sprite_delay_main[k]) {
-    if (sprite_delay_main[k] & 1)
-      return;
-    ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLink(k, 32);
-    Sprite_ApproachTargetSpeed(k, pt.x, pt.y);
-  } else {
-    int x = Sprite_GetX(0) + (sprite_D[0] ? -16 : 24);
-    int y = Sprite_GetY(0) - 16;
-    if (Ganon_AttemptTridentCatch(x, y)) {
-      sprite_state[k] = 0;
-      sprite_ai_state[0] = 3;
-      sprite_delay_main[0] = 16;
-    }
-    ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLocation(k, x, y, 32);
-    Sprite_ApproachTargetSpeed(k, pt.x, pt.y);
-  }
-}
-
-void Sprite_FireBat_Trailer(int k) {  // 9d8b49
-  FireBat_Draw(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  FireBat_Move(k);
-}
-
-void Sprite_SpiralFireBat(int k) {  // 9d8b52
-  FireBat_Draw(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  {
-    uint16 x = sprite_A[k] | sprite_B[k] << 8;
-    uint16 y = sprite_C[k] | sprite_E[k] << 8;
-    ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLocation(k, x, y, 2);
-    ProjectSpeedRet pt2 = Sprite_ProjectSpeedTowardsLocation(k, x, y, 80);
-    sprite_x_vel[k] = pt2.y - pt.x;
-    sprite_y_vel[k] = -pt2.x - pt.y;
-  }
-  FireBat_Move(k);
-}
-
-void FireBat_Move(int k) {  // 9d8b90
-  FireBat_Animate(k);
-  Sprite_MoveXY(k);
-  if (sprite_subtype2[k] & 7)
-    return;
-  int j = Garnish_FlameTrail(k, true);
-//  garnish_type[j] = 0x10;
-  garnish_countdown[j] = (sprite_anim_clock[k] == 5) ? 0x2f : 0x4f;
-}
-
-void Sprite_FireBat_Launched(int k) {  // 9d8bd7
-  FireBat_Draw(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  Sprite_CheckDamageToLink(k);
-  switch (sprite_ai_state[k]) {
-  case 0:
-    GetPositionRelativeToTheGreatOverlordGanon(k);
-    if (!sprite_delay_main[k]) {
-      sprite_ai_state[k] = 1;
-    } else {
-      sprite_graphics[k] = sprite_delay_main[k] >> 2 & 1;
-    }
-    break;
-  case 1:
-    GetPositionRelativeToTheGreatOverlordGanon(k);
-    sprite_graphics[k] = ++sprite_subtype2[k] >> 2 & 1;
-    break;
-  case 2:
-    Sprite_MoveXY(k);
-    sprite_defl_bits[k] = 64;
-    if (sprite_delay_aux1[k] == 0) {
-      if (sprite_delay_main[k] == 0) {
-        FireBat_Animate(k);
-        FireBat_Animate(k);
-
-      } else {
-        uint8 t = sprite_delay_main[k] - 1;
-        if (t == 0)
-          sprite_delay_aux1[k] = t = 35;
-        sprite_graphics[k] = t >> 2 & 1;
-      }
-    } else if (sprite_delay_aux1[k] == 1) {
-      Sprite_ApplySpeedTowardsLink(k, 48);
-      SpriteSfx_QueueSfx3WithPan(k, 0x1e);
-      FireBat_Animate(k);
-      FireBat_Animate(k);
-    } else {
-      static const uint8 kFirebat_Gfx2[9] = { 4, 4, 4, 3, 3, 3, 2, 2, 2 };
-      sprite_graphics[k] = kFirebat_Gfx2[sprite_delay_aux1[k] >> 2];
-    }
-    break;
-  }
-}
-
-void GetPositionRelativeToTheGreatOverlordGanon(int k) {  // 9d8bee
-  static const int8 kFirebat_X[2] = { 20, -18 };
-  static const int8 kFirebat_Y[2] = { -20, -20 };
-
-  int j = sprite_D[0];
-  Sprite_SetX(k, (overlord_x_hi[k] | overlord_y_hi[k] << 8) + kFirebat_X[j]);
-  Sprite_SetY(k, (overlord_gen2[k] | overlord_floor[k] << 8) + kFirebat_Y[j]);
-}
-
-void FireBat_Animate(int k) {  // 9d8c43
-  static const uint8 kFirebat_Gfx[4] = { 4, 5, 6, 5 };
-  sprite_graphics[k] = kFirebat_Gfx[++sprite_subtype2[k] >> 2 & 3];
-}
-
-void FireBat_Draw(int k) {  // 9d8ca9
-  static const int8 kFirebat_Draw_X[2] = { -8, 8 };
-  static const uint8 kFirebat_Draw_Char[7] = { 0x88, 0x88, 0x8a, 0x8c, 0x68, 0xaa, 0xa8 };
-  static const uint8 kFirebat_Draw_Flags[14] = { 0, 0xc0, 0x80, 0x40, 0, 0x40, 0, 0x40, 0, 0x40, 0, 0x40, 0, 0x40 };
-
-  PrepOamCoordsRet info;
-  if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
-    return;
-  OamEnt *oam = GetOamCurPtr();
-  int g = sprite_graphics[k];
-  for (int i = 1; i >= 0; i--, oam++) {
-    SetOamHelper0(oam, info.x + kFirebat_Draw_X[i], info.y, kFirebat_Draw_Char[g],
-                  kFirebat_Draw_Flags[g * 2 + i] | info.flags, 2);
-  }
-}
-
-bool Ganon_AttemptTridentCatch(uint16 x, uint16 y) {  // 9d8d06
-  return (uint16)(cur_sprite_x - x + 4) < 8 && (uint16)(cur_sprite_y - y + 4) < 8;
-}
-
-void Ganon_HandleFireBatCircle(int k) {  // 9d8d70
-  static const int8 kGanonMath_X[16] = { 0, 16, 24, 28, 32, 28, 24, 16, 0, -16, -24, -28, -32, -28, -24, -16 };
-  static const int8 kGanonMath_Y[16] = { 32, 28, 24, 16, 0, -16, -24, -28, -32, -28, -24, -16, 0, 16, 24, 28 };
-
-  WORD(overlord_x_lo[0]) -= 4;
-
-  for (int i = 0; i != 8; i++) {
-    int t = WORD(overlord_x_lo[0]) + i * 64 & 0x1ff;
-    if (sprite_ai_state[i + 1] != 2) {
-      int j = (t >> 5) - 4 & 0xf;
-      sprite_x_vel[i + 1] = (int8)kGanonMath_X[j] >> 2;
-      sprite_y_vel[i + 1] = (int8)kGanonMath_Y[j] >> 2;
-    }
-    int x = Sprite_GetX(0) + GanonSin(t, overlord_x_lo[2]);
-    overlord_x_hi[i + 1] = x;
-    overlord_y_hi[i + 1] = x >> 8;
-
-    int y = Sprite_GetY(0) + GanonSin(t + 0x80, overlord_x_lo[2]);
-    overlord_gen2[i + 1] = y;
-    overlord_floor[i + 1] = y >> 8;
-  }
-  tmp_counter = 8;
-}
-
-void Ganon_SpawnSpiralBat(int k) {  // 9d8e7c
-  SpriteSpawnInfo info;
-  int j = Sprite_SpawnDynamicallyEx(k, 0xc9, &info, 8);
-  if (j < 0)
-    return;
-  Sprite_SetSpawnedCoordinates(j, &info);
-  sprite_anim_clock[j] = 4;
-  sprite_oam_flags[j] = 3;
-  sprite_flags3[j] = 0x40;
-  sprite_flags2[j] = 1;
-  sprite_defl_bits[j] = 0x80;
-  sprite_y_hi[j] = 128;
-  sprite_delay_main[j] = 48;
-  sprite_bump_damage[j] = 7;
-  sprite_ignore_projectile[j] = 7;
-}
-
-void Sprite_D6_Ganon(int k) {  // 9d8eb4
-  int j;
-
-  if (sign8(sprite_ai_state[k])) {
-    if (Sprite_ReturnIfInactive(k))
-      return;
-    if (!sprite_delay_main[k])
-      sprite_state[k] = 0;
-    if (!(sprite_delay_main[k] & 1))
-      Ganon_Draw(k);
-    return;
-  }
-
-  if (sprite_delay_aux4[k]) {
-    static const uint8 kGanon_GfxB[2] = { 16, 10 };
-    sprite_graphics[k] = kGanon_GfxB[sprite_D[k]];
-  }
-
-  if (byte_7E04C5 == 2 && byte_7E04C5 != sprite_room[k])
-    sprite_delay_aux1[k] = 64;
-
-  sprite_room[k] = byte_7E04C5;
-
-  Ganon_Draw(k);
-  if (sprite_delay_aux1[k]) {
-    sprite_graphics[k] = 15;
-    Ganon_EnableInvincibility(k);
-    Sprite_CheckDamageToAndFromLink(k);
-    return;
-  }
-
-  if (Sprite_ReturnIfInactive(k))
-    return;
-
-  if (sprite_delay_aux2[k] == 1)
-    Ganon_ExtinguishTorch();
-  else if (sprite_delay_aux2[k] == 16)
-    Ganon_ExtinguishTorch_adjust_translucency();
-
-  PairU8 pair = Sprite_IsRightOfLink(k);
-  static const uint8 kGanon_HeadDir0[2] = { 2, 0 };
-  sprite_head_dir[k] = (uint8)(pair.b + 32) < 64 ? 1 : kGanon_HeadDir0[pair.a];
-
-  if (sprite_delay_aux4[k]) {
-    sprite_ignore_projectile[k] = sprite_delay_aux4[k];
-    if (Sprite_ReturnIfRecoiling(k))
-      return;
-    sprite_delay_main[k] = 0;
-    return;
-  }
-
-  if (!(sprite_ignore_projectile[k] | flag_is_link_immobilized) && byte_7E04C5 == 2)
-    Sprite_CheckDamageToAndFromLink(k);
-  sprite_ignore_projectile[k] = 0;
-  switch (sprite_ai_state[k]) {
-  case 0:  //
-    if (sprite_delay_main[k] == 0) {
-      sprite_ai_state[k] = 1;
-      sprite_delay_main[k] = 128;
-    } else if (sprite_delay_main[k] == 32) {
-      music_control = 0x1f;
-    } else if (sprite_delay_main[k] == 64) {
-      dialogue_message_index = 0x16f;
-      Sprite_ShowMessageMinimal();
-    }
-    break;
-  case 1:  //
-    if (sprite_health[k] < 209)
-      sprite_health[k] = 208;
-    if (sprite_delay_main[k] < 64) {
-      static const uint8 kGanon_Gfx1[2] = { 2, 10 };
-      if (sprite_delay_main[k] == 0) {
-        Ganon_SelectWarpLocation(k, 5);
-      } else {
-        sprite_graphics[k] = kGanon_Gfx1[sprite_D[k]];
-      }
-    } else if (sprite_delay_main[k] != 64) {
-      Ganon_Phase1_AnimateTridentSpin(k);
-    } else {
-      static const int8 kGanon_X1[2] = { 24, -16 };
-      static const int8 kGanon_Y1[2] = { 4, 4 };
-      static const int8 kGanon_Xvel1[16] = { 32, 28, 24, 16, 0, -16, -24, -28, -32, -28, -24, -16, 0, 16, 24, 28 };
-      static const int8 kGanon_Yvel1[16] = { 0, 16, 24, 28, 32, 28, 24, 16, 0, -16, -24, -28, -32, -28, -24, -16 };
-      sprite_G[k] = 0;
-      SpriteSpawnInfo info;
-      int j = Sprite_SpawnDynamically(k, 0xc9, &info);
-      int i = sprite_D[k];
-      Sprite_SetX(j, info.r0_x + kGanon_X1[i]);
-      Sprite_SetY(j, info.r2_y + kGanon_Y1[i]);
-      Sprite_ApplySpeedTowardsLink(k, 31);
-      uint8 angle = Sprite_ConvertVelocityToAngle(sprite_x_vel[k], sprite_y_vel[k]);
-      sprite_x_vel[j] = kGanon_Xvel1[angle - 2 & 0xf];
-      sprite_y_vel[j] = kGanon_Yvel1[angle - 2 & 0xf];
-      sprite_delay_main[j] = 112;
-      sprite_anim_clock[j] = 2;
-      sprite_oam_flags[j] = 1;
-      sprite_flags2[j] = 4;
-      sprite_defl_bits[j] = 0x84;
-      sprite_D[j] = 2;
-      sprite_bump_damage[j] = 7;
-      sprite_ignore_projectile[j] = 7;
-    }
-    break;
-  case 2: {  //
-    static const uint8 kGanon_Gfx2_0[2] = { 0, 8 };
-    if (sprite_health[k] < 209)
-      sprite_health[k] = 208;
-    sprite_graphics[k] = kGanon_Gfx2_0[sprite_D[k]];
-    if (sprite_delay_main[k]) {
-      sprite_ignore_projectile[k]++;
-      if (sprite_delay_main[k] & 1)
-        sprite_graphics[k] = 255;
-    }
-    break;
-  }
-  case 3:  //
-    if (sprite_health[k] < 209)
-      sprite_health[k] = 208;
-    if (sprite_delay_main[k] != 0) {
-      Ganon_Phase1_AnimateTridentSpin(k);
-    } else {
-      sprite_ai_state[k] = 6;
-      sprite_delay_main[k] = 127;
-      Ganon_HandleAnimation_Idle(k);
-    }
-    break;
-  case 4:  //
-    if (sprite_health[k] < 209)
-      sprite_health[k] = 208;
-    if (sprite_delay_main[k] != 0)
-      Ganon_ShakeHead(k);
-    else
-      Ganon_SelectWarpLocation(k, 5);
-    break;
-  case 13:  //
-    sprite_health[k] = 100;
-    // fall through
-  case 5:  //
-  case 10:  //
-  case 18: { //
-    sprite_ignore_projectile[k]++;
-    uint16 x = sprite_x_hi[k] << 8 | swamola_target_x_lo[0];
-    uint16 y = sprite_y_hi[k] << 8 | swamola_target_y_lo[0];
-    if (Ganon_AttemptTridentCatch(x, y)) {
-      sprite_D[k] = sprite_subtype[k] >> 2;
-      if (sprite_ai_state[k] == 5) {
-        sprite_ai_state[k] = 2;
-        sprite_delay_main[k] = 32;
-      } else if (sprite_health[k] >= 161) {
-        sprite_ai_state[k] = 11;
-        sprite_delay_main[k] = 40;
-      } else if (sprite_health[k] >= 97) {
-        sprite_ai_state[k] = 14;
-        sprite_delay_main[k] = 40;
-      } else {
-        sprite_ai_state[k] = 17;
-        sprite_delay_main[k] = 104;
-      }
-    } else {
-      ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLocation(k, x, y, 32);
-      Sprite_ApproachTargetSpeed(k, pt.x, pt.y);
-      Sprite_MoveXY(k);
-      if (sprite_delay_main[k] == 0 || frame_counter & 1) {
-        sprite_graphics[k] = 255;
-        return;
-      }
-      static const uint8 kGanon_Gfx5[2] = { 2, 10 };
-      sprite_graphics[k] = kGanon_Gfx5[sprite_D[k]];
-      if (!(frame_counter & 7)) {
-        SpriteSpawnInfo info;
-        int j = Sprite_SpawnDynamically(k, 0xd6, &info);
-        if (j >= 0) {
-          Sprite_SetSpawnedCoordinates(j, &info);
-          sprite_ignore_projectile[j] = 24;
-          sprite_delay_main[j] = 24;
-          sprite_ai_state[j] = 255;
-          sprite_graphics[j] = sprite_graphics[k];
-          sprite_head_dir[j] = sprite_head_dir[k];
-        }
-      }
-    }
-    break;
-  }
-  case 6:  //
-    if (sprite_health[k] < 209)
-      sprite_health[k] = 208;
-    if (!sprite_delay_main[k]) {
-      if (sprite_health[k] >= 209) {
-        sprite_ai_state[k] = 1;
-        sprite_delay_main[k] = 128;
-      } else {
-        sprite_delay_main[k] = 255;
-        sprite_ai_state[k] = 7;
-      }
-    } else {
-      Ganon_ShakeHead(k);
-    }
-    break;
-  case 7:  //
-    if (sprite_health[k] < 161)
-      sprite_health[k] = 160;
-    overlord_x_lo[2] = 40;
-    if (!sprite_delay_main[k]) {
-      sprite_ai_state[k] = 8;
-      sprite_delay_main[k] = 255;
-    } else {
-      if (sprite_delay_main[k] < 0xc0 && (sprite_delay_main[k] & 0xf) == 0)
-        Ganon_SpawnSpiralBat(k);
-      Ganon_Phase1_AnimateTridentSpin(k);
-      Ganon_HandleFireBatCircle(k);
-    }
-    break;
-  case 8: {  //
-    static const int8 kGanon_Tab2[16] = { 0, 0, 0, 0, -1, -1, -2, -1, 0, 0, 0, 0, 1, 2, 1, 1 };
-    static const uint8 kGanon_Delay8[8] = { 0x10, 0x30, 0x50, 0x70, 0x90, 0xb0, 0xd0, 0xbd };
-
-    if (sprite_health[k] < 161)
-      sprite_health[k] = 160;
-    if (!sprite_delay_main[k]) {
-      sprite_ai_state[k] = 9;
-      sprite_delay_main[k] = 127;
-      Ganon_HandleAnimation_Idle(k);
-      for (int j = 8; j != 0; j--) {
-        sprite_ai_state[j] = 2;
-        sprite_delay_main[j] = kGanon_Delay8[j - 1];
-      }
-    } else {
-      overlord_x_lo[2] += kGanon_Tab2[sprite_delay_main[k] >> 4 & 15];
-      Ganon_Phase1_AnimateTridentSpin(k);
-      Ganon_HandleFireBatCircle(k);
-    }
-    break;
-  }
-  case 9:  //
-    if (sprite_health[k] < 161)
-      sprite_health[k] = 160;
-    if (!sprite_delay_main[k]) {
-      Ganon_SelectWarpLocation(k, 10);
-    } else {
-      Ganon_ShakeHead(k);
-    }
-    break;
-  case 11:  //
-    sprite_ignore_projectile[k]++;
-    Ganon_HandleAnimation_Idle(k);
-    if (!sprite_delay_main[k]) {
-      sprite_delay_main[k] = 255;
-      sprite_ai_state[k] = 7;
-    } else if (sprite_delay_main[k] & 1) {
-      sprite_graphics[k] = 255;
-    }
-    break;
-  case 12: { //
-    j = sprite_delay_main[k];
-    if (j == 0) {
-      Ganon_SelectWarpLocation(k, 13);
-      return;
-    }
-    int t = 0;
-    if (j < 96) {
-      t = 1;
-      if (j < 72) {
-        if (j == 66)
-          Ganon_Func1(k, 3);
-        t = 2;
-      }
-    }
-    if (sprite_D[k])
-      t += 3;
-    static const uint8 kGanon_Gfx12[6] = { 5, 6, 7, 13, 14, 10 };
-    sprite_graphics[k] = kGanon_Gfx12[t];
-    if ((sprite_hit_timer[k] & 127) == 1) {
-      sprite_ai_state[k] = 15;
-      sprite_z_vel[k] = 24;
-      sprite_delay_main[k] = 0;
-    }
-    break;
-  }
-  case 14:  //
-    sprite_ignore_projectile[k]++;
-    Ganon_HandleAnimation_Idle(k);
-    sprite_G[k] = 0;
-    if (!sprite_delay_main[k]) {
-      if (GetRandomNumber() & 1) {
-        Ganon_SelectWarpLocation(k, 13);
-      } else {
-        sprite_delay_main[k] = 127;
-        sprite_ai_state[k] = 12;
-      }
-    } else if (sprite_delay_main[k] & 1) {
-      sprite_graphics[k] = 255;
-    }
-    break;
-  case 15: {  //
-    static const uint8 kGanon_Gfx15[2] = { 6, 14 };
-    if (sprite_delay_main[k]) {
-      if (sprite_delay_main[k] == 1) {
-        sprite_ai_state[k] = 16;
-        sprite_z_vel[k] = 160;
-        return;
-      }
-    } else {
-      Sprite_MoveZ(k);
-      if (--sprite_z_vel[k] == 0)
-        sprite_delay_main[k] = 32;
-
-    }
-    sprite_graphics[k] = kGanon_Gfx15[sprite_D[k]];
-    break;
-  }
-  case 16: { //
-    bg1_y_offset = 0;
-    if (sprite_delay_main[k]) {
-      if (sprite_delay_main[k] == 1) {
-        sound_effect_ambient = 5;
-        Ganon_SelectWarpLocation(k, 13);
-        flag_is_link_immobilized = 0;
-        Ganon_SpawnFallingTilesOverlord(k);
-        if (sprite_anim_clock[k] >= 4) {
-          Ganon_SelectWarpLocation(k, 10);
-          sprite_health[k] = 96;
-          sprite_delay_aux2[k] = 224;
-          dialogue_message_index = 0x170;
-          Sprite_ShowMessageMinimal();
-        }
-      } else {
-        bg1_y_offset = (sprite_delay_main[k] - 1) & 1 ? -1 : 1;
-        flag_is_link_immobilized = 1;
-      }
-    } else {
-      static const uint8 kGanon_Gfx16[2] = { 2, 10 };
-
-      Sprite_MoveZ(k);
-      if (sign8(sprite_z[k])) {
-        sprite_z_vel[k] = 0;
-        sprite_z[k] = 0;
-        sprite_delay_main[k] = 96;
-        sound_effect_ambient = 7;
-        SpriteSfx_QueueSfx2WithPan(k, 0xc);
-      }
-      sprite_graphics[k] = kGanon_Gfx16[sprite_D[k]];
-    }
-    break;
-  }
-  case 17: {  //
-    static const uint8 kGanon_Gfx17b[2] = { 6, 14 };
-    static const uint8 kGanon_Gfx17[2] = { 7, 10 };
-    sprite_graphics[k] = kGanon_Gfx17b[sprite_D[k]];
-    if (!sprite_delay_main[k]) {
-      Ganon_SelectWarpLocation(k, 0x12);
-      return;
-    } else if (sprite_delay_main[k] == 52) {
-      Ganon_Func1(k, 5);
-    } else if (sprite_delay_main[k] < 52) {
-      sprite_graphics[k] = kGanon_Gfx17[sprite_D[k]];
-    }
-    if (sprite_delay_main[k] >= 72 || sprite_delay_main[k] < 40) {
-      sprite_ignore_projectile[k]++;
-      if (sprite_delay_main[k] & 1)
-        sprite_graphics[k] = 0xff;
-    }
-    Ganon_EnableInvincibility(k);
-    break;
-  }
-  case 19:  //
-    sprite_oam_flags[k] = 5;
-    sprite_flags[k] = 2;
-    if (!sprite_delay_main[k]) {
-      sprite_oam_flags[k] = 1;
-      Ganon_SelectWarpLocation(k, 18);
-      sprite_type[k] = 0xd6;
-      sprite_hit_timer[k] = 0;
-    } else {
-      static const uint8 kGanon_Gfx19[2] = { 5, 13 };
-      sprite_graphics[k] = kGanon_Gfx19[sprite_D[k]];
-    }
-    break;
-  }
-}
-
-void Ganon_EnableInvincibility(int k) {  // 9d8ffa
-  if ((sprite_hit_timer[k] & 127) == 26) {
-    sprite_hit_timer[k] = 0;
-    sprite_ai_state[k] = 19;
-    sprite_delay_main[k] = 127;
-    sprite_type[k] = 215;
-  }
-}
-
-void Ganon_SpawnFallingTilesOverlord(int k) {  // 9d90d0
-  static const uint8 kGanon_Ov_Type[4] = { 12, 13, 14, 15 };
-  static const uint8 kGanon_Ov_X[4] = { 0x18, 0xd8, 0xd8, 0x18 };
-  static const uint8 kGanon_Ov_Y[4] = { 0x28, 0x28, 0xd8, 0xd8 };
-
-  int j;
-  for (j = 7; j >= 0 && overlord_type[j] != 0; j--);
-
-  int t = sprite_anim_clock[k];
-  if (t >= 4)
-    return;
-  sprite_anim_clock[k] = t + 1;
-
-  overlord_type[j] = kGanon_Ov_Type[t];
-  overlord_x_lo[j] = kGanon_Ov_X[t];
-  overlord_x_hi[j] = link_x_coord >> 8;
-  overlord_y_lo[j] = kGanon_Ov_Y[t];
-  overlord_y_hi[j] = link_y_coord >> 8;
-  overlord_gen1[j] = 0;
-  overlord_gen2[j] = 0;
-}
-
-void Ganon_Func1(int k, int t) {  // 9d9162
-  tmp_counter = t;
-  SpriteSpawnInfo info;
-  int j = Sprite_SpawnDynamicallyEx(k, 0xC9, &info, 8);
-  if (j < 0)
-    return;
-  SpriteSfx_QueueSfx2WithPan(k, 0x2a);
-  Sprite_SetSpawnedCoordinates(j, &info);
-  sprite_ignore_projectile[j] = sprite_anim_clock[j] = t;
-  sprite_oam_flags[j] = 3;
-  sprite_flags3[j] = 0x40;
-  sprite_flags2[j] = 0x21;
-  sprite_defl_bits[j] = 0x40;
-  static const int8 kGanon_Gfx16_Y[2] = { 0, -16 };
-  Sprite_SetY(j, info.r2_y + kGanon_Gfx16_Y[sprite_D[k]]);
-  Sprite_ApplySpeedTowardsLink(j, 32);
-  sprite_delay_main[j] = 16;
-  sprite_A[j] = sprite_x_lo[0];
-  sprite_B[j] = sprite_x_hi[0];
-  sprite_C[j] = sprite_y_lo[0];
-  sprite_E[j] = sprite_y_hi[0];
-  sprite_bump_damage[j] = 7;
-  sprite_ignore_projectile[j] = 7;
-}
-
-void Ganon_Phase1_AnimateTridentSpin(int k) {  // 9d93db
-  static const uint8 kGanon_GfxFunc2[16] = { 0, 0, 1, 1, 0, 0, 1, 1, 8, 8, 9, 9, 8, 8, 9, 9 };
-
-  int j = (sprite_delay_main[k] >> 2 & 7) + (sprite_D[k] ? 8 : 0);
-  sprite_G[k] = kGanon_G_Func2[j];
-  sprite_graphics[k] = kGanon_GfxFunc2[j];
-  SwishEvery16Frames(k);
-}
-
-void Ganon_HandleAnimation_Idle(int k) {  // 9d9443
-  static const uint8 kGanon_G[2] = { 9, 10 };
-  static const uint8 kGanon_Gfx[2] = { 2, 10 };
-  sprite_G[k] = kGanon_G[sprite_D[k]];
-  sprite_graphics[k] = kGanon_Gfx[sprite_D[k]];
-}
-
-void Ganon_SelectWarpLocation(int k, int a) {  // 9d947f
-  int j;
-  static const uint8 kGanon_NextSubtype[32] = {
-    4, 5, 6, 7, 4, 5, 6, 7, 4, 5, 6, 7, 4, 5, 6, 7,
-    0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3,
-  };
-  static const uint8 kGanon_NextY[8] = { 0x40, 0x30, 0x30, 0x40, 0xb0, 0xc0, 0xc0, 0xb0 };
-  static const uint8 kGanon_NextX[8] = { 0x30, 0x50, 0xa0, 0xc0, 0x40, 0x60, 0x90, 0xb0 };
-
-  sprite_subtype[k] = j = kGanon_NextSubtype[GetRandomNumber() & 3 | sprite_subtype[k] << 2];
-  swamola_target_x_lo[0] = kGanon_NextX[j];
-  swamola_target_y_lo[0] = kGanon_NextY[j];
-  sprite_ai_state[k] = a;
-  sprite_x_vel[k] = sprite_y_vel[k] = 0;
-  sprite_delay_main[k] = 48;
-  SpriteSfx_QueueSfx3WithPan(k, 0x28);
-}
-
-void Ganon_ShakeHead(int k) {  // 9d94ba
-  static const uint8 kGanon_HeadDir[18] = {
-    0,  0, 0, 1, 2, 2, 2, 1, 0, 0, 0, 1, 1, 1, 1, 1,
-    0, 16,
-  };
-  sprite_head_dir[k] = kGanon_HeadDir[sprite_delay_main[k] >> 3];
-}
-
-void Ganon_Draw(int k) {  // 9d9adf
-  PrepOamCoordsRet info;
-  if (sign8(sprite_graphics[k]) ||
-      sprite_ai_state[k] != 19 && sprite_delay_aux4[k] == 0 && byte_7E04C5 == 0) {
-    Sprite_PrepOamCoordOrDoubleRet(k, &info);
-    return;
-  }
-  Trident_Draw(k);
-  if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
-    return;
-  OamEnt *oam = GetOamCurPtr() + 5;
-  int g = sprite_graphics[k];
-  for (int i = 0; i < 12; i++, oam++) {
-    int j = g * 12 + i;
-    SetOamPlain(oam, info.x + kGanon_Draw_X[j], info.y + kGanon_Draw_Y[j], kGanon_Draw_Char[j],
-                 info.flags | (kGanon_Draw_Flags[j] & ((info.flags & 0xf) >= 5 ? 0xf0 : 0xff)), 2);
-  }
-  static const uint8 kGanon_SprOffs[17] = {
-    1, 1, 1, 1, 1, 1, 15, 1, 4, 4, 4, 4, 4, 4, 4, 15, 15,
-  };
-  if (kGanon_SprOffs[g] != 15) {
-    oam = oam - 12 + kGanon_SprOffs[g];
-    int j = sprite_head_dir[k] * 2 + (sprite_D[k] ? 6 : 0);
-    oam[0].charnum = kGanon_Draw_Char2[j];
-    oam[0].flags = (oam[0].flags & 0x3f) | kGanon_Draw_Flags2[j];
-
-    oam[1].charnum = kGanon_Draw_Char2[j + 1];
-    oam[1].flags = (oam[1].flags & 0x3f) | kGanon_Draw_Flags2[j + 1];
-
-  }
-  if (submodule_index)
-    Sprite_CorrectOamEntries(k, 9, 0xff);
-
-  if (sprite_G[k] == 9) {
-    static const DrawMultipleData kGanon_Dmd[2] = {
-      {16, -3, 0x4c0a, 2},
-      {16,  5, 0x4c1a, 2},
-    };
-    oam_cur_ptr = 0x828, oam_ext_cur_ptr = 0xa2a;
-    Sprite_DrawMultiple(k, kGanon_Dmd, 2, NULL);
-  }
-
-  uint16 z = sprite_z[k] - 1;
-  int frame = (z >> 11) > 4 ? 4 : (z >> 11);
-  cur_sprite_y += z;
-  oam_cur_ptr = 0x9f4;
-  oam_ext_cur_ptr = 0xa9d;
-  uint8 bak = sprite_oam_flags[k];
-  sprite_oam_flags[k] = 0;
-  sprite_obj_prio[k] = 48;
-  Sprite_DrawMultiple(k, &kLargeShadow_Dmd[frame * 3], 3, NULL);
-  sprite_oam_flags[k] = bak;
-  Sprite_Get16BitCoords(k);
-}
-
-void Trident_Draw(int k) {  // 9d9c1c
-  static const DrawMultipleData kTrident_Dmd[50] = {
-  { 10, -10, 0x0864, 0},
-  {  5, -15, 0x0864, 0},
-  {  0, -20, 0x0864, 0},
-  { -5, -25, 0x0864, 0},
-  {-18, -38, 0x0844, 2},
-  {  1,  -4, 0x0865, 0},
-  {  1, -11, 0x0865, 0},
-  {  1, -18, 0x0865, 0},
-  {  1, -25, 0x0865, 0},
-  { -3, -40, 0x0862, 2},
-  { -8,  -9, 0x4864, 0},
-  { -3, -14, 0x4864, 0},
-  {  3, -20, 0x4864, 0},
-  {  9, -26, 0x4864, 0},
-  { 12, -37, 0x4844, 2},
-  {-10, -20, 0x4874, 0},
-  { -3, -20, 0x4874, 0},
-  {  4, -20, 0x4874, 0},
-  { 11, -20, 0x4874, 0},
-  { 18, -23, 0x4860, 2},
-  {-10, -30, 0xc864, 0},
-  { -4, -24, 0xc864, 0},
-  {  2, -18, 0xc864, 0},
-  {  8, -12, 0xc864, 0},
-  { 12,  -8, 0xc844, 2},
-  {  1, -32, 0x8865, 0},
-  {  1, -25, 0x8865, 0},
-  {  1, -18, 0x8865, 0},
-  {  1, -11, 0x8865, 0},
-  { -3,  -5, 0x8862, 2},
-  { 13, -30, 0x8864, 0},
-  {  8, -25, 0x8864, 0},
-  {  2, -19, 0x8864, 0},
-  { -4, -13, 0x8864, 0},
-  {-16,  -9, 0x8844, 2},
-  { 14, -20, 0x0874, 0},
-  {  7, -20, 0x0874, 0},
-  {  0, -20, 0x0874, 0},
-  { -7, -20, 0x0874, 0},
-  {-21, -23, 0x0860, 2},
-  { 13, -30, 0x8864, 0},
-  {  8, -25, 0x8864, 0},
-  {  2, -19, 0x8864, 0},
-  { -4, -13, 0x8864, 0},
-  {-16,  -9, 0x8844, 2},
-  {-10, -30, 0xc864, 0},
-  { -4, -24, 0xc864, 0},
-  { -4, -24, 0xc864, 0},
-  { -4, -24, 0xc864, 0},
-  { -4, -24, 0xc864, 0},
-  };
-  int g = sprite_G[k];
-  if (g == 0)
-    return;
-  static const int8 kTrident_Draw_X[5] = { 24, -16, 0, 16, -8 };
-  static const int8 kTrident_Draw_Y[5] = { 4, 4, 16, 21, 19 };
-
-  int j = sprite_G[k] == 9 ? 3 :
-          sprite_G[k] >= 9 ? 4 : sprite_D[k];
-  cur_sprite_x += kTrident_Draw_X[j];
-  cur_sprite_y += kTrident_Draw_Y[j];
-  uint8 bak = sprite_obj_prio[k];
-  sprite_obj_prio[k] &= ~0xf;
-  Sprite_DrawMultiple(k, &kTrident_Dmd[(g - 1) * 5], 5, NULL);
-  sprite_obj_prio[k] = bak;
-  Sprite_Get16BitCoords(k);
-}
-
-void SpritePrep_Swamola_InitializeSegments(int k) {  // 9d9c80
-  int j;
-
-  // The snes code uses the wrong bank.. Causes glitches with lanmolas in misery mire
-  if (enhanced_features0 & kFeatures0_MiscBugFixes) {
-    j = k * 32;
-  } else {
-    static const uint8 kBuggySwamolaLookup[6] = { 0x1c, 0xa9, 0x03, 0x9d, 0x90, 0x0d };  // wrong bank
-    j = kBuggySwamolaLookup[k];
-  }
-  for (int i = 0; i < 32; i++, j++) {
-    swamola_x_lo[j] = sprite_x_lo[k];
-    swamola_x_hi[j] = sprite_x_hi[k];
-    swamola_y_lo[j] = sprite_y_lo[k];
-    swamola_y_hi[j] = sprite_y_hi[k];
-  }
-}
-
-void Sprite_CF_Swamola(int k) {  // 9d9cb0
-  static const uint8 kSwamola_Target_Dir[8] = {1, 2, 3, 4, 5, 6, 7, 8};
-  static const int8 kSwamola_Target_X[9] = {0, 0, 32, 32, 32, 0, -32, -32, -32};
-  static const int8 kSwamola_Target_Y[9] = {0, -32, -32, 0, 32, 32, 32, 0, -32};
-  int j;
-
-  if (sprite_ai_state[k]) {
-    if (sign8(sprite_ai_state[k])) {
-      Sprite_Swamola_Ripples(k);
-      return;
-    }
-    Swamola_Draw(k);
-  }
-  Sprite_Get16BitCoords(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  sprite_subtype2[k]++;
-  Sprite_CheckDamageToAndFromLink(k);
-  uint8 old_vel = sprite_y_vel[k];
-  sprite_y_vel[k] += sprite_z_vel[k];
-  Sprite_MoveXY(k);
-  sprite_y_vel[k] = old_vel;
-  switch(sprite_ai_state[k]) {
-  case 0: {  // emerge
-    if (!sprite_delay_main[k] && (j = kSwamola_Target_Dir[GetRandomNumber() & 7]) != sprite_D[k]) {
-      int t = (sprite_B[k] << 8 | sprite_A[k]) + kSwamola_Target_X[j];
-      swamola_target_x_lo[k] = t, swamola_target_x_hi[k] = t >> 8;
-      t = (sprite_head_dir[k] << 8 | sprite_C[k]) + kSwamola_Target_Y[j];
-      swamola_target_y_lo[k] = t, swamola_target_y_hi[k] = t >> 8;
-      sprite_ai_state[k] = 1;
-      sprite_x_vel[k] = sprite_y_vel[k] = 0;
-      sprite_z_vel[k] = -15;
-      Swamola_SpawnRipples(k);
-    }
-    break;
-  }
-  case 1:  // ascending
-    if (!(sprite_subtype2[k] & 3)) {
-      if (!++sprite_z_vel[k])
-        sprite_ai_state[k] = 2;
-      ProjectSpeedRet pt = Swamola_ProjectVelocityTowardsTarget(k);
-      Sprite_ApproachTargetSpeed(k, pt.x, pt.y);
-    }
-    break;
-  case 2: {  // wiggle
-    static const int8 kSwamola_Z_Accel[2] = {2, -2};
-    static const int8 kSwamola_Z_Vel_Target[2] = {12, -12};
-    int j = sprite_G[k] & 1;
-    sprite_z_vel[k] += kSwamola_Z_Accel[j];
-    if (sprite_z_vel[k] == (uint8)kSwamola_Z_Vel_Target[j])
-      sprite_G[k]++;
-    uint16 x = swamola_target_x_hi[k] << 8 | swamola_target_x_lo[k];
-    uint16 y = swamola_target_y_hi[k] << 8 | swamola_target_y_lo[k];
-    if ((uint16)(cur_sprite_x - x + 8) < 16 && (uint16)(cur_sprite_y - y + 8) < 16)
-      sprite_ai_state[k] = 3;
-    ProjectSpeedRet pt = Swamola_ProjectVelocityTowardsTarget(k);
-    sprite_x_vel[k] = pt.x;
-    sprite_y_vel[k] = pt.y;
-    break;
-  }
-  case 3:  // descending
-    if (!(sprite_subtype2[k] & 3) && ++sprite_z_vel[k] == 16) {
-      sprite_ai_state[k] = 4;
-      Swamola_SpawnRipples(k);
-      sprite_y_hi[k] = 128;
-      sprite_delay_main[k] = 80;
-    }
-    if (!(sprite_subtype2[k] & 3))
-      Sprite_ApproachTargetSpeed(k, 0, 0);
-    break;
-  case 4:  // submerge
-    if (!sprite_delay_main[k]) {
-      sprite_D[k] = j = kSwamola_Target_Dir[GetRandomNumber() & 7];
-      Sprite_SetX(k, (sprite_B[k] << 8 | sprite_A[k]) + kSwamola_Target_X[j]);
-      Sprite_SetY(k, (sprite_head_dir[k] << 8 | sprite_C[k]) + kSwamola_Target_Y[j]);
-      sprite_ai_state[k] = 0;
-      sprite_delay_main[k] = 48;
-      sprite_x_vel[k] = sprite_y_vel[k] = 0;
-      sprite_z_vel[k] = 0;
-    }
-    break;
-  }
-}
-
-ProjectSpeedRet Swamola_ProjectVelocityTowardsTarget(int k) {  // 9d9e13
-  uint16 x = swamola_target_x_hi[k] << 8 | swamola_target_x_lo[k];
-  uint16 y = swamola_target_y_hi[k] << 8 | swamola_target_y_lo[k];
-  return Sprite_ProjectSpeedTowardsLocation(k, x, y, 15);
-}
-
-void Swamola_SpawnRipples(int k) {  // 9d9eaa
-  SpriteSpawnInfo info;
-  int j = Sprite_SpawnDynamically(k, 0xcf, &info);
-  if (j >= 0) {
-    Sprite_SetSpawnedCoordinates(j, &info);
-    sprite_ai_state[j] = 128;
-    sprite_delay_main[j] = 32;
-    sprite_oam_flags[j] = 4;
-    sprite_ignore_projectile[j] = 4;
-    sprite_flags2[j] = 0;
-  }
-}
-
-void Sprite_Swamola_Ripples(int k) {  // 9d9ece
-  SwamolaRipples_Draw(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  if (!sprite_delay_main[k])
-    sprite_state[k] = 0;
-}
-
-void SwamolaRipples_Draw(int k) {  // 9d9f1d
-  static const DrawMultipleData kSwamolaRipples_Dmd[8] = {
-    {0, 4, 0x00d8, 0},
-    {8, 4, 0x40d8, 0},
-    {0, 4, 0x00d9, 0},
-    {8, 4, 0x40d9, 0},
-    {0, 4, 0x00da, 0},
-    {8, 4, 0x40da, 0},
-    {0, 4, 0x00d9, 0},
-    {8, 4, 0x40d9, 0},
-  };
-  Oam_AllocateFromRegionB(8);
-  Sprite_DrawMultiple(k, &kSwamolaRipples_Dmd[(sprite_delay_main[k] >> 2 & 3) * 2], 2, NULL);
-}
-
-void Swamola_Draw(int k) {  // 9d9f64
-  static const uint8 kSwamola_Gfx[16] = {7, 6, 5, 4, 3, 4, 5, 6, 7, 6, 5, 4, 3, 4, 5, 6};
-  static const uint8 kSwamola_Gfx2[4] = {0, 0, 1, 2};
-  static const uint8 kSwamola_Draw_OamFlags[16] = {0xc0, 0xc0, 0xc0, 0xc0, 0x80, 0x80, 0x80, 0x80, 0, 0, 0, 0, 0, 0x40, 0x40, 0x40};
-  static const uint8 kSwamola_HistOffs[4] = {8, 16, 22, 26};
-  int j = Sprite_ConvertVelocityToAngle(sprite_x_vel[k], sprite_y_vel[k] + sprite_z_vel[k]);
-  sprite_graphics[k] = kSwamola_Gfx[j];
-  sprite_oam_flags[k] = sprite_oam_flags[k] & 63 | kSwamola_Draw_OamFlags[j];
-  SpriteDraw_SingleLarge(k);
-  j = (sprite_subtype2[k] & 0x1f) + k * 32;
-  swamola_x_lo[j] = sprite_x_lo[k];
-  swamola_x_hi[j] = sprite_x_hi[k];
-  swamola_y_lo[j] = sprite_y_lo[k];
-  swamola_y_hi[j] = sprite_y_hi[k];
-  j = sign8(sprite_y_vel[k]) ? 5 : 0;
-  int delta = sign8(sprite_y_vel[k]) ? -1 : 1;
-  oam_cur_ptr += j * 4, oam_ext_cur_ptr += j;
-  for (int i = 0; i < 4; i++) {
-    sprite_graphics[k] = kSwamola_Gfx2[i];
-    j = (sprite_subtype2[k] - kSwamola_HistOffs[i] & 31) + k * 32;
-    cur_sprite_x = swamola_x_hi[j] << 8 | swamola_x_lo[j];
-    cur_sprite_y = swamola_y_hi[j] << 8 | swamola_y_lo[j];
-    oam_cur_ptr += delta * 4, oam_ext_cur_ptr += delta;
-    SpriteDraw_SingleLarge(k);
-  }
-  byte_7E0FB6 = 4;
-}
-
-void SpritePrep_Blind_PrepareBattle(int k) {  // 9da081
-  if (follower_indicator != 6 && dung_savegame_state_bits & 0x2000) {
-    sprite_delay_aux2[k] = 96;
-    sprite_C[k] = 1;
-    sprite_D[k] = 2;
-    sprite_head_dir[k] = 4;
-    sprite_graphics[k] = 7;
-    byte_7E0B69 = 0;
-  } else {
-    sprite_state[k] = 0;
-  }
-}
-
-void BlindLaser_SpawnTrailGarnish(int j) {  // 9da0b1
-  int k = GarnishAllocOverwriteOld();
-  garnish_type[k] = 15;
-  garnish_active = 15;
-  garnish_oam_flags[k] = sprite_graphics[j];
-  garnish_sprite[k] = j;
-  garnish_x_lo[k] = sprite_x_lo[j];
-  garnish_x_hi[k] = sprite_x_hi[j];
-  uint16 y = Sprite_GetY(j) + 16;
-  garnish_y_lo[k] = y;
-  garnish_y_hi[k] = y >> 8;
-  garnish_countdown[k] = 10;
-}
-
-void Sprite_Blind_Head(int k) {  // 9da118
-  static const uint8 kBlindHead_XposLimit[2] = {0x98, 0x58};
-  static const uint8 kBlindHead_YposLimit[2] = {0xb0, 0x50};
-  static const int8 kBlindHead_YvelLimit[2] = {24, -24};
-  static const int8 kBlindHead_XvelLimit[2] = {32, -32};
-
-  sprite_obj_prio[k] |= 48;
-  SpriteDraw_SingleLarge(k);
-  OamEnt *oam = GetOamCurPtr();
-  int j = sprite_head_dir[k];
-  oam->charnum = kBlindHead_Draw_Char[j];
-  oam->flags = oam->flags & 0x3f | kBlindHead_Draw_Flags[j];
-
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  if (sprite_F[k] == 14)
-    sprite_F[k] = 8;
-  if (Sprite_ReturnIfRecoiling(k))
-    return;
-  if (sign8(--sprite_subtype[k])) {
-    sprite_subtype[k] = 2;
-    sprite_head_dir[k] = sprite_head_dir[k] + 1 & 15;
-  }
-  if (sprite_delay_main[k])
-    return;
-  Sprite_CheckDamageToAndFromLink(k);
-  sprite_subtype2[k]++;
-  j = Blind_SpitFireball(k, 0x1f);
-  if (j >= 0 && sign8(--sprite_z_subpos[k])) {
-    sprite_z_subpos[k] = 4;
-    ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLink(k, 32);
-    sprite_x_vel[j] = pt.x;
-    sprite_y_vel[j] = pt.y;
-  }
-  j = sprite_G[k] & 1;
-  if (sprite_x_vel[k] != (uint8)kBlindHead_XvelLimit[j])
-    sprite_x_vel[k] += j ? -1 : 1;
-  if ((sprite_x_lo[k] & ~1) == kBlindHead_XposLimit[j])
-    sprite_G[k]++;
-  j = sprite_anim_clock[k] & 1;
-  if (sprite_y_vel[k] != (uint8)kBlindHead_YvelLimit[j])
-    sprite_y_vel[k] += j ? -1 : 1;
-  if ((sprite_y_lo[k] & ~1) == kBlindHead_YposLimit[j])
-    sprite_anim_clock[k]++;
-  if (!sprite_F[k])
-    Sprite_MoveXY(k);
-}
-
-void Blind_SpawnHead(int k) {  // 9da1ed
-  SpriteSpawnInfo info;
-  int j = Sprite_SpawnDynamically(k, 0xce, &info);
-  if (j >= 0) {
-    Sprite_SetSpawnedCoordinates(j, &info);
-    sprite_flags3[j] = 0x5b;
-    sprite_oam_flags[j] = 0x5b & 15;
-    sprite_defl_bits[j] = 4;
-    sprite_A[j] = 2;
-    sprite_flags2[j] = 1;
-    sprite_flags4[j] = 0;
-    sprite_flags[j] = 0;
-    sprite_z[j] = 23;
-    sprite_y_lo[j] = 23 + info.r2_y;
-    sprite_G[j] = (info.r0_x >> 7) & 1;
-    sprite_anim_clock[j] = (info.r2_y >> 7) & 1;
-    sprite_delay_main[j] = 48;
-  }
-}
-
-void Sprite_CE_Blind(int k) {  // 9da263
-  if (sign8(sprite_A[k]))
-    Sprite_BlindLaser(k);
-  else if (sprite_A[k] == 2)
-    Sprite_Blind_Head(k);
-  else
-    Sprite_Blind_Blind_Blind(k);
-}
-
-void Sprite_BlindLaser(int k) {  // 9da268
-  static const uint8 kBlindLaser_Gfx[16] = {7, 7, 8, 9, 10, 9, 8, 7, 7, 7, 8, 9, 10, 9, 8, 7};
-  static const uint8 kBlindLaser_OamFlags[16] = {0, 0, 0, 0, 0, 0x40, 0x40, 0x40, 0x40, 0x40, 0xc0, 0xc0, 0x80, 0x80, 0x80, 0x80};
-  int j = sprite_head_dir[k];
-  sprite_graphics[k] = kBlindLaser_Gfx[j];
-  sprite_oam_flags[k] = kBlindLaser_OamFlags[j] | 3;
-  PrepOamCoordsRet info;
-  Sprite_PrepOamCoord(k, &info);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  if (sprite_delay_main[k]) {
-    if (sprite_delay_main[k] == 1)
-      sprite_state[k] = 0;
-    return;
-  }
-  Sprite_CheckDamageToLink_same_layer(k);
-  Sprite_SetX(k, Sprite_GetX(k) + (int8)sprite_x_vel[k]);
-  Sprite_SetY(k, Sprite_GetY(k) + (int8)sprite_y_vel[k]);
-  if (Sprite_CheckTileCollision(k))
-    sprite_delay_main[k] = 12;
-  BlindLaser_SpawnTrailGarnish(k);
-}
-
-void Sprite_Blind_Blind_Blind(int k) {  // 9da2d2
-  int j;
-
-  sprite_obj_prio[k] |= 0x30;
-  Blind_Draw(k);
-  sprite_oam_flags[k] = 1;
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  uint8 a = sprite_F[k];
-  if (a)
-    sprite_F[k]--;
-
-  if (a == 11) {
-    sprite_hit_timer[k] = 0;
-    sprite_wallcoll[k] = 0;
-    if (!sprite_delay_aux4[k]) {
-      sprite_health[k] = 128;
-      sprite_delay_aux4[k] = 48;
-      sprite_oam_flags[k] &= 1;
-      if (++sprite_z_subpos[k] < 3) {
-        sprite_wallcoll[k] = 96;
-        sprite_subtype[k] = 1;
-      } else {
-        sprite_z_subpos[k] = 0;
-        if (++sprite_limit_instance == 3) {
-          Sprite_KillFriends();
-          sprite_state[k] = 4;
-          sprite_A[k] = 0;
-          sprite_delay_main[k] = 255;
-          sprite_hit_timer[k] = 255;
-          flag_block_link_menu++;
-          SpriteSfx_QueueSfx3WithPan(k, 0x22);
-          return;
-        }
-        sprite_y_vel[k] = sprite_x_vel[k] = 0;
-        sprite_C[k] = 6;
-        sprite_delay_aux2[k] = 255;
-        sprite_ignore_projectile[k] = 255;
-        Blind_SpawnHead(k);
-      }
-    }
-  }
-
-  if (sprite_A[k]) {
-    static const uint8 kBlind_Gfx0[7] = {20, 19, 18, 17, 16, 15, 15};
-    if (!sprite_delay_main[k])
-      sprite_state[k] = 0;
-    sprite_graphics[k] = kBlind_Gfx0[sprite_delay_main[k] >> 3];
-    return;
-  }
-  if (!(++sprite_subtype2[k] & 1))
-    sprite_delay_main[k]++;
-
-  if (sprite_delay_aux1[k]) {
-    sprite_ai_state[k] = 0;
-    if (sprite_delay_aux1[k] == 8)
-      Blind_SpawnLaser(k);
-    Blind_CheckBumpDamage(k);
-    return;
-  }
-  byte_7E0B69++;
-  if (!sprite_stunned[k]) {
-    if (sprite_ai_state[k]) {
-      sprite_delay_aux1[k] = 16;
-      sprite_stunned[k] = 128;
-      sprite_ai_state[k] = 0;
-    }
-  } else {
-    sprite_stunned[k]--;
-    sprite_ai_state[k] = 0;
-  }
-  sprite_x_hi[k] = HIBYTE(link_x_coord);
-  sprite_y_hi[k] = HIBYTE(link_y_coord);
-  switch(sprite_C[k]) {
-  case 0:  // blinded
-    BYTE(dma_var6) = 0;
-    BYTE(dma_var7) = 0xA0;
-    if (sprite_delay_aux2[k] == 0) {
-      sprite_C[k]++;
-      sprite_delay_aux2[k] = 96;
-    } else if (sprite_delay_aux2[k] == 80) {
-      dialogue_message_index = 0x123;
-      Sprite_ShowMessageMinimal();
-    } else if (sprite_delay_aux2[k] == 24) {
-      SpawnBossPoof(k);
-    }
-    break;
-  case 1:  // retreat to back wall
-    Blind_CheckBumpDamage(k);
-    sprite_graphics[k] = 9;
-    if (sprite_delay_aux2[k] == 0) {
-      sprite_C[k]++;
-      sprite_delay_main[k] = 255;
-      sprite_ignore_projectile[k] = 0;
-    } else if (sprite_delay_aux2[k] < 64) {
-      sprite_y_vel[k] = -8;
-      Sprite_MoveY(k);
-    }
-    Blind_Animate(k);
-    sprite_head_dir[k] = 4;
-    break;
-  case 2: { // oscillate
-    static const int8 kBlind_Oscillate_YVelTarget[2] = {18, -18};
-    static const int8 kBlind_Oscillate_XVelTarget[2] = {24, -24};
-    static const uint8 kBlind_Oscillate_XPosTarget[2] = {164, 76};
-    Blind_CheckBumpDamage(k);
-    Blind_Animate(k);
-    if ((!(sprite_subtype2[k] & 127) && Sprite_IsBelowLink(k).a + 2 != sprite_D[k] || sprite_delay_main[k] == 0) && sprite_x_lo[k] < 0x78) {
-      sprite_C[k]++;
-      sprite_y_vel[k] &= ~1;
-      sprite_x_vel[k] &= ~1;
-      sprite_delay_aux2[k] = 0x30;
-      return;
-    }
-    j = sprite_B[k] & 1;
-    sprite_y_vel[k] += j ? -1 : 1;
-    if (sprite_y_vel[k] == (uint8)kBlind_Oscillate_YVelTarget[j])
-      sprite_B[k]++;
-    j = sprite_G[k] & 1;
-    if (sprite_x_vel[k] != (uint8)kBlind_Oscillate_XVelTarget[j])
-      sprite_x_vel[k] += j ? -1 : 1;
-    if ((sprite_x_lo[k] & ~1) == kBlind_Oscillate_XPosTarget[j])
-      sprite_G[k]++;
-    Sprite_MoveXY(k);
-    if (sprite_wallcoll[k]) {
-      Blind_FireballFlurry(k, sprite_wallcoll[k]);
-    } else if (!(sprite_subtype2[k] & 7)) {
-      Sprite_SpawnProbeAlways(k, sprite_head_dir[k] << 2);
-    }
-    break;
-  }
-  case 3:  // switch walls
-    Blind_CheckBumpDamage(k);
-    if (sprite_delay_aux2[k]) {
-      Blind_Decelerate_X(k);
-      Sprite_MoveX(k);
-      Blind_Decelerate_Y(k);
-    } else {
-      static const int8 kBlind_SwitchWall_YVelTarget[2] = {64, -64};
-      static const uint8 kBlind_SwitchWall_YPosTarget[2] = {0x90, 0x50};
-      j = sprite_D[k] - 2;
-      if (sprite_y_vel[k] != (uint8)kBlind_SwitchWall_YVelTarget[j])
-        sprite_y_vel[k] += j ? -2 : 2;
-      if ((sprite_y_lo[k] & ~3) == kBlind_SwitchWall_YPosTarget[j]) {
-        sprite_C[k]++;
-        sprite_B[k] = sprite_D[k] - 1;
-      }
-      Sprite_MoveXY(k);
-      Blind_Decelerate_X(k);
-    }
-    break;
-  case 4: { // whirl around
-    Blind_CheckBumpDamage(k);
-    if (!(sprite_subtype2[k] & 7)) {
-      static const uint8 kBlind_WhirlAround_Gfx[2] = {0, 9};
-      j = sprite_D[k] - 2;
-      if (sprite_graphics[k] == kBlind_WhirlAround_Gfx[j]) {
-        sprite_delay_main[k] = 254;
-        sprite_C[k] = 2;
-        sprite_D[k] ^= 1;
-        sprite_G[k] = sprite_x_lo[k] >> 7;
-      } else {
-        sprite_graphics[k] += j ? 1 : -1;
-      }
-    }
-    Blind_Decelerate_Y(k);
-    break;
-  }
-  case 5:  // fireball reprisal
-    Blind_FireballFlurry(k, 0x65); // wtf: argument
-    break;
-  case 6:  // behind the curtain
-    sprite_hit_timer[k] = 0;
-    sprite_head_dir[k] = 12;
-    if (sprite_delay_aux2[k] == 0) {
-      sprite_C[k]++;
-      sprite_delay_aux2[k] = 39;
-      SpriteSfx_QueueSfx1WithPan(k, 0x13);
-    } else if (sprite_delay_aux2[k] >= 224) {
-      static const uint8 kBlind_Gfx_BehindCurtain[4] = {14, 13, 12, 10};
-      sprite_graphics[k] = kBlind_Gfx_BehindCurtain[(sprite_delay_aux2[k] - 224) >> 3];
-    } else {
-      sprite_graphics[k] = 14;
-    }
-    break;
-  case 7:  // rerobe
-    if (sprite_delay_aux2[k] == 0) {
-      sprite_C[k] = 2;
-      sprite_delay_main[k] = 128;
-      sprite_D[k] = (sprite_y_lo[k] >> 7) + 2;
-      sprite_G[k] = (sprite_x_lo[k] << 2) | (sprite_x_lo[k] >> 7);
-      sprite_x_vel[k] = sprite_y_vel[k] = 0;
-      sprite_ignore_projectile[k] = 0;
-    } else {
-      static const uint8 kBlind_Gfx_Rerobe[5] = {10, 11, 12, 13, 14};
-      sprite_graphics[k] = kBlind_Gfx_Rerobe[sprite_delay_aux2[k] >> 3];
-    }
-    break;
-  }
-
-
-}
-
-void Blind_FireballFlurry(int k, uint8 a) {  // 9da465
-  sprite_wallcoll[k]--;
-  sprite_oam_flags[k] = (a & 7) * 2 + 1;
-  if (sign8(--sprite_E[k])) {
-    sprite_E[k] = sprite_subtype[k];
-    sprite_head_dir[k] = sprite_head_dir[k] + 1 & 15;
-  }
-  if (!(sprite_subtype2[k] & 31) && sprite_subtype[k] != 5)
-    sprite_subtype[k]++;
-  Blind_AnimateRobes(k);
-  Blind_SpitFireball(k, 0xf);
-}
-
-int Blind_SpitFireball(int k, uint8 a) {  // 9da49d
-  static const int8 kBlindHead_SpawnFireball_Xvel[16] = {-32, -28, -24, -16, 0, 16, 24, 28, 32, 28, 24, 16, 0, -16, -24, -28};
-  static const int8 kBlindHead_SpawnFireball_Yvel[16] = {0, 16, 24, 28, 32, 28, 24, 16, 0, -16, -24, -28, -32, -28, -24, -16};
-  if (sprite_subtype2[k] & a)
-    return -1;
-  int j = Sprite_SpawnFireball(k);
-  if (j >= 0) {
-    SpriteSfx_QueueSfx3WithPan(k, 0x19);
-    int i = sprite_head_dir[k];
-    sprite_x_vel[j] = kBlindHead_SpawnFireball_Xvel[i];
-    sprite_y_vel[j] = kBlindHead_SpawnFireball_Yvel[i];
-    sprite_defl_bits[j] |= 8;
-    sprite_bump_damage[j] = 4;
-  }
-  return j;
-}
-
-int SpawnBossPoof(int k) {  // 9da4f9
-  SpriteSpawnInfo info;
-  int j = Sprite_SpawnDynamically(k, 0xce, &info);
-  Sprite_SetX(j, info.r0_x + 16);
-  Sprite_SetY(j, info.r2_y + 40);
-  sprite_graphics[j] = 0xf;
-  sprite_A[j] = 1;
-  sprite_delay_main[j] = 47;
-  sprite_flags2[j] = 9;
-  sprite_ignore_projectile[j] = 9;
-  sound_effect_1 = 12;
-  return j;
-}
-
-void Blind_Decelerate_X(int k) {  // 9da647
-  if (sprite_x_vel[k] != 0)
-    sprite_x_vel[k] += sign8(sprite_x_vel[k]) ? 2 : -2;
-  Blind_AnimateRobes(k);
-  if (sprite_wallcoll[k])
-    Blind_FireballFlurry(k, sprite_wallcoll[k]);
-}
-
-void Blind_Decelerate_Y(int k) {  // 9da6a4
-  if (sprite_y_vel[k] != 0)
-    sprite_y_vel[k] += sign8(sprite_y_vel[k]) ? 4 : -4;
-  Sprite_MoveY(k);
-  if (sprite_wallcoll[k])
-    Blind_FireballFlurry(k, sprite_wallcoll[k]);
-}
-
-void Blind_CheckBumpDamage(int k) {  // 9da6c0
-  if (!(sprite_delay_aux4[k] | sprite_F[k]))
-    Sprite_CheckDamageToAndFromLink(k);
-  if ((uint16)(link_x_coord - cur_sprite_x + 14) < 28 &&
-      (uint16)(link_y_coord - cur_sprite_y) < 28 &&
-      !(countdown_for_blink | link_disable_sprite_damage)) {
-    link_auxiliary_state = 1;
-    link_give_damage = 8;
-    link_incapacitated_timer = 16;
-    link_actual_vel_x ^= 255;
-    link_actual_vel_y ^= 255;
-  }
-}
-
-void Blind_Animate(int k) {  // 9da6ef
-  static const uint8 kBlind_HeadDir[17] = {0, 1, 2, 3, 4, 3, 2, 1, 0, 15, 14, 13, 12, 13, 14, 15, 0};
-  static const uint8 kBlind_Animate_Tab[8] = {0, 1, 1, 2, 2, 3, 3, 4};
-
-  if (!sprite_wallcoll[k]) {
-    int t1 = kBlind_Animate_Tab[BYTE(link_x_coord) >> 5];
-    t1 = (sprite_D[k] == 3) ? -t1 : t1;
-    int t0 = (sprite_D[k] - 2) * 8;
-    int idx = (byte_7E0B69 >> 3 & 7) + (byte_7E0B69 >> 2 & 1) + t0;
-    sprite_head_dir[k] = (kBlind_HeadDir[idx] + t1) & 15;
-  }
-  Blind_AnimateRobes(k);
-}
-
-void Blind_AnimateRobes(int k) {  // 9da729
-  static const uint8 kBlind_Gfx_Animate[8] = {7, 8, 9, 8, 0, 1, 2, 1};
-  sprite_graphics[k] = kBlind_Gfx_Animate[(sprite_subtype2[k] >> 3 & 3) + ((sprite_D[k] - 2) << 2)];
-}
-
-void Blind_SpawnLaser(int k) {  // 9da765
-  static const int8 kBlind_Laser_Xvel[16] = {-8, -8, -8, -4, 0, 4, 8, 8, 8, 8, 8, 4, 0, -4, -8, -8};
-  static const int8 kBlind_Laser_Yvel[16] = {0, 0, 4, 8, 8, 8, 4, 0, 0, 0, -4, -8, -8, -8, -4, 0};
-  SpriteSpawnInfo info;
-  int j = Sprite_SpawnDynamically(k, 0xce, &info), i;
-  if (j >= 0) {
-    sound_effect_2 = Sprite_CalculateSfxPan(k) | 0x26;
-    Sprite_SetSpawnedCoordinates(j, &info);
-    sprite_x_lo[j] = info.r0_x + 4;
-    sprite_head_dir[j] = i = sprite_head_dir[k];
-    sprite_x_vel[j] = kBlind_Laser_Xvel[i];
-    sprite_y_vel[j] = kBlind_Laser_Yvel[i];
-    sprite_A[j] = 128;
-    sprite_ignore_projectile[j] = 128;
-    sprite_flags2[j] = 0x40;
-    sprite_flags4[j] = 0x14;
-  }
-}
-
-void Blind_Draw(int k) {  // 9dac6c
-
-  if (sprite_graphics[k] >= 15) {
-    static const DrawMultipleData kBlindPoof_Dmd[37] = {
-      {-16, -20, 0x0586, 2},
-      {-11, -28, 0x0586, 2},
-      {-23, -26, 0x0586, 2},
-      { -8, -17, 0x0586, 2},
-      {-20, -13, 0x0586, 2},
-      {-16, -37, 0x0586, 2},
-      {-27, -31, 0x0586, 2},
-      {-10, -28, 0x0586, 2},
-      { -5, -28, 0x0586, 2},
-      {-20, -27, 0x0586, 2},
-      {-27, -17, 0x0586, 2},
-      { -4, -17, 0x0586, 2},
-      {-16, -13, 0x0586, 2},
-      {-18, -37, 0x458a, 2},
-      { -5, -33, 0x458a, 2},
-      {-32, -32, 0x058a, 2},
-      {-23, -31, 0x458a, 2},
-      {-15, -24, 0x458a, 2},
-      {-23, -31, 0x458a, 2},
-      {-15, -24, 0x458a, 2},
-      {-29, -22, 0x058a, 2},
-      { -5, -22, 0x058a, 2},
-      {-16, -14, 0x058a, 2},
-      {-12, -32, 0x458a, 2},
-      {-26, -29, 0x458a, 2},
-      { -6, -22, 0x458a, 2},
-      {-19, -20, 0x058a, 2},
-      {-26, -29, 0x458a, 2},
-      { -6, -22, 0x458a, 2},
-      {-19, -20, 0x058a, 2},
-      {-17, -27, 0x059b, 0},
-      {-10, -26, 0x059b, 0},
-      {  0, -22, 0x459b, 0},
-      {-19, -16, 0x459b, 0},
-      { -6, -12, 0x059b, 0},
-      {  0,  13, 0x0b20, 2},
-      {  0,  23, 0x0b22, 2},
-    };
-    static const uint8 kOffs[] = { 0, 1, 5, 13, 23, 30, 35, 37 };
-    int j = sprite_graphics[k] - 15;
-    Sprite_DrawMultiple(k, &kBlindPoof_Dmd[kOffs[j]], kOffs[j + 1] - kOffs[j], NULL);
-    return;
-  }
-  static const DrawMultipleData kBlind_Dmd[105] = {
-    { -8,  7, 0x0c8e, 2},
-    {  8,  7, 0x4c8e, 2},
-    { -8, 23, 0x0ca0, 2},
-    {  8, 23, 0x4ca4, 2},
-    {  0,  0, 0x0a8c, 2},
-    {-19,  3, 0x0aa6, 2},
-    { 19,  3, 0x4aa6, 2},
-    { -8,  7, 0x0c8e, 2},
-    {  8,  7, 0x4c8e, 2},
-    { -8, 23, 0x0ca2, 2},
-    {  8, 23, 0x4ca0, 2},
-    {  0,  0, 0x0a8c, 2},
-    {-19,  3, 0x0aa8, 2},
-    { 19,  3, 0x4aa8, 2},
-    { -8,  7, 0x0c8e, 2},
-    {  8,  7, 0x4c8e, 2},
-    { -8, 23, 0x0ca4, 2},
-    {  8, 23, 0x4ca2, 2},
-    {  0,  0, 0x0a8c, 2},
-    {-19,  3, 0x0aaa, 2},
-    { 19,  3, 0x4aaa, 2},
-    {-15,  5, 0x0aa6, 2},
-    { -6,  7, 0x0c8e, 2},
-    {  6,  7, 0x4c8e, 2},
-    { -6, 23, 0x0ca4, 2},
-    {  6, 23, 0x4ca0, 2},
-    {  0,  0, 0x0a8a, 2},
-    { 16, -1, 0x4aa6, 2},
-    {-11,  9, 0x0aa6, 2},
-    { -4,  7, 0x0c8e, 2},
-    {  5,  7, 0x4c8e, 2},
-    { -4, 23, 0x0ca4, 2},
-    {  5, 23, 0x4ca0, 2},
-    {  0,  0, 0x0a88, 2},
-    { 10, -2, 0x4aa6, 2},
-    {  0,  0, 0x0a84, 2},
-    { 13,  8, 0x4aa6, 2},
-    {-10, -2, 0x0aa6, 2},
-    { -5,  7, 0x0c8e, 2},
-    {  5,  7, 0x4c8e, 2},
-    { -5, 23, 0x0ca0, 2},
-    {  5, 23, 0x4ca4, 2},
-    {  0,  0, 0x0a82, 2},
-    { 18,  4, 0x4aa6, 2},
-    {-15, -1, 0x0aa6, 2},
-    { -6,  7, 0x0c8e, 2},
-    {  6,  7, 0x4c8e, 2},
-    { -6, 23, 0x0ca0, 2},
-    {  6, 23, 0x4ca4, 2},
-    {  0,  0, 0x0a80, 2},
-    {-19,  3, 0x0aa6, 2},
-    { 19,  3, 0x4aa6, 2},
-    { -8,  7, 0x0c8e, 2},
-    {  8,  7, 0x4c8e, 2},
-    { -8, 23, 0x0ca0, 2},
-    {  8, 23, 0x4ca4, 2},
-    {  0,  0, 0x0a80, 2},
-    {-19,  3, 0x0aa8, 2},
-    { 19,  3, 0x4aa8, 2},
-    { -8,  7, 0x0c8e, 2},
-    {  8,  7, 0x4c8e, 2},
-    { -8, 23, 0x0ca2, 2},
-    {  8, 23, 0x4ca0, 2},
-    {  0,  0, 0x0a80, 2},
-    {-19,  3, 0x0aaa, 2},
-    { 19,  3, 0x4aaa, 2},
-    { -8,  7, 0x0c8e, 2},
-    {  8,  7, 0x4c8e, 2},
-    { -8, 23, 0x0ca0, 2},
-    {  8, 23, 0x4ca4, 2},
-    { -8,  9, 0x0c8e, 2},
-    {  8,  9, 0x4c8e, 2},
-    { -8, 23, 0x0cae, 2},
-    {  8, 23, 0x4cae, 2},
-    {  8, 23, 0x4cae, 2},
-    {  8, 23, 0x4cae, 2},
-    {  0,  2, 0x0a8c, 2},
-    { -8, 16, 0x0c8e, 2},
-    {  8, 16, 0x4c8e, 2},
-    { -8, 23, 0x0cae, 2},
-    {  8, 23, 0x4cae, 2},
-    {  8, 23, 0x4cae, 2},
-    {  8, 23, 0x4cae, 2},
-    {  0,  9, 0x0a8c, 2},
-    { -8, 23, 0x0cae, 2},
-    {  8, 23, 0x4cae, 2},
-    {  8, 23, 0x4cae, 2},
-    {  8, 23, 0x4cae, 2},
-    {  8, 23, 0x4cae, 2},
-    {  8, 23, 0x4cae, 2},
-    {  0, 16, 0x0a8c, 2},
-    { -8, 23, 0x0cac, 2},
-    {  8, 23, 0x4cac, 2},
-    {  8, 23, 0x4cac, 2},
-    {  8, 23, 0x4cac, 2},
-    {  8, 23, 0x4cac, 2},
-    {  8, 23, 0x4cac, 2},
-    {  0, 20, 0x0a8c, 2},
-    { -8, 23, 0x0cac, 2},
-    {  8, 23, 0x4cac, 2},
-    {  8, 23, 0x4cac, 2},
-    {  8, 23, 0x4cac, 2},
-    {  8, 23, 0x4cac, 2},
-    {  8, 23, 0x4cac, 2},
-    {  0, 23, 0x0a8c, 2},
-  };
-  Sprite_DrawMultiple(k, &kBlind_Dmd[sprite_graphics[k] * 7], 7, NULL);
-  OamEnt *oam = GetOamCurPtr();
-  if (sprite_wallcoll[k] == 0) {
-    if (sprite_C[k] == 6) {
-      oam[6].y = 0xf0;
-      return;
-    }
-    if (sprite_C[k] == 4)
-      return;
-  }
-  if (sprite_graphics[k] >= 10)
-    return;
-  static const uint8 kBlind_OamIdx[10] = {4, 4, 4, 5, 5, 0, 0, 0, 0, 0};
-  oam += kBlind_OamIdx[sprite_graphics[k]];
-  int j = sprite_head_dir[k];
-  oam->charnum = kBlindHead_Draw_Char[j];
-  oam->flags = oam->flags & 0x3f | kBlindHead_Draw_Flags[j];
-}
-
-void TrinexxComponents_Initialize(int k) {  // 9dad16
-  switch (sprite_type[k]) {
-  case 0xcb: {
-    sprite_x_lo[k] += 8;
-    sprite_y_lo[k] += 16;
-    Trinexx_CachePosition(k);
-    overlord_x_lo[2] = 0;
-    overlord_x_lo[3] = 0;
-    overlord_x_lo[5] = 0;
-    overlord_x_lo[7] = 0;
-    overlord_x_hi[0] = 0;
-    overlord_x_lo[6] = 255;
-    Trinexx_RestoreXY(k);
-    break;
-  }
-  case 0xcc:
-    sprite_graphics[k] = 3;
-    sprite_delay_main[k] = 128;
-common:
-    for (int j = 0x1a; j >= 0; j--) {
-      alt_sprite_type[j] = 0x40;
-      alt_sprite_x_hi[j] = 0;
-      alt_sprite_y_hi[j] = 0;
-    }
-    sprite_subtype2[k] = 1;
-    Trinexx_CachePosition(k);
-    break;
-  case 0xcd:
-    sprite_delay_main[k] = 255;
-    goto common;
-  }
-}
-
-void Trinexx_RestoreXY(int k) {  // 9dad4f
-  sprite_x_lo[k] = sprite_A[k];
-  Sprite_SetY(k, (sprite_G[k] << 8) + sprite_C[k] + 12);
-}
-
-void Trinexx_CachePosition(int k) {  // 9dad8c
-  sprite_A[k] = sprite_x_lo[k];
-  sprite_B[k] = sprite_x_hi[k];
-  sprite_C[k] = sprite_y_lo[k];
-  sprite_G[k] = sprite_y_hi[k];
-}
-
-void Sprite_Trinexx_FinalPhase(int k) {  // 9dadb5
-  static const uint8 kSprite_TrinexxD_Gfx3[8] = {6, 7, 0, 1, 2, 3, 4, 5};
-  static const uint8 kSprite_TrinexxD_Gfx[8] = {7, 7, 1, 1, 3, 3, 5, 5};
-  static const int8 kSprite_TrinexxD_Xvel[4] = {0, -31, 0, 31};
-  static const int8 kSprite_TrinexxD_Yvel[4] = {31, 0, -31, 0};
-
-  int j = Sprite_ConvertVelocityToAngle(sprite_x_vel[k], sprite_y_vel[k]) >> 1;
-  uint8 gfx = kSprite_TrinexxD_Gfx3[j];
-  sprite_graphics[k] = sprite_delay_aux1[k] ? kSprite_TrinexxD_Gfx[gfx] : gfx;
-
-  Sprite_TrinexxD_Draw(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  if (sign8(sprite_ai_state[k])) {
-    uint8 t = sprite_delay_main[k];
-    sprite_hit_timer[k] = t | 0xe0;
-    if (t == 0) {
-      sprite_delay_main[k] = 12;
-      if (sprite_anim_clock[k] == 0) {
-        sprite_hit_timer[k] = 255;
-        Sprite_ScheduleBossForDeath(k);
-      } else {
-        sprite_anim_clock[k]--;
-        Sprite_MakeBossExplosion(k);
-      }
-    }
-    return;
-  }
-  if (!(frame_counter & 7))
-    SpriteSfx_QueueSfx3WithPan(k, 0x31);
-
-  j = ++sprite_subtype2[k] & 0x7f;
-  moldorm_x_lo[j] = sprite_x_lo[k];
-  moldorm_y_lo[j] = sprite_y_lo[k];
-  moldorm_x_hi[j] = sprite_x_hi[k];
-  moldorm_y_hi[j] = sprite_y_hi[k];
-
-  if (sprite_F[k] == 14) {
-    sprite_F[k] = 8;
-    if (sprite_ai_state[k] == 0)
-      sprite_ai_state[k] = 2;
-  }
-  Sprite_MoveXY(k);
-  Sprite_CheckDamageToAndFromLink(k);
-  switch(sprite_ai_state[k]) {
-  case 0:
-    if (!--sprite_A[k]) {
-      sprite_ai_state[k] = 1;
-      sprite_delay_main[k] = 192;
-    }
-    Sprite_Get16BitCoords(k);
-    if (Sprite_CheckTileCollision(k)) {
-      sprite_D[k] = sprite_D[k] + 1 & 3;
-      sprite_delay_aux1[k] = 8;
-    }
-    j = sprite_D[k];
-    sprite_x_vel[k] = kSprite_TrinexxD_Xvel[j];
-    sprite_y_vel[k] = kSprite_TrinexxD_Yvel[j];
-    break;
-  case 1:
-    if (!(frame_counter & 1)) {
-      ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLink(k, 31);
-      Sprite_ApproachTargetSpeed(k, pt.x, pt.y);
-    }
-    break;
-  }
-}
-
-void Sprite_TrinexxD_Draw(int k) {  // 9daf84
-  static const int8 kTrinexxD_HistPos[24] = {
-    8,  0xc, 0x10, 0x18, 0x20, 0x28, 0x30, 0x34, 0x38, 0x3c, 0x40, 0x44, 0x48, 0x4c, 0x50, 0x54,
-    0x58, 0x5c, 0x60, 0x64, 0x68, 0x6c, 0x70, 0x74,
-  };
-  static const int8 kSprite_TrinexxD_Gfx2[24] = {
-    2, 2, 2, 3, 3, 3, 2, 2, 1, 1, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, 0, 0, 0, 0, 0,
-  };
-  static const int16 kTrinexxD_OamOffs[24] = {
-    0x10, 4, 4, 4, 0x10, 0x10, 0x10, 4, 4, 4, 4, 4, 4, 4, 4, 4,
-    4, 4, 4, 4,    4,    4,    4, 4,
-  };
-
-  sprite_obj_prio[k] |= 0x30;
-  PrepOamCoordsRet info;
-  SpriteDraw_TrinexxRockHead(k, &info);
-  for (int i = 0; i != sprite_anim_clock[k]; i++) {
-    int j = sprite_subtype2[k] - kTrinexxD_HistPos[i] & 0x7f;
-    cur_sprite_x = moldorm_x_hi[j] << 8 | moldorm_x_lo[j];
-    cur_sprite_y = moldorm_y_hi[j] << 8 | moldorm_y_lo[j];
-
-    if ((uint16)(link_x_coord - cur_sprite_x + 8) < 16 &&
-        (uint16)(link_y_coord - cur_sprite_y + 16) < 16 &&
-        !sign8(sprite_ai_state[k]) &&
-        !(countdown_for_blink | link_disable_sprite_damage | submodule_index | flag_unk1)) {
-      link_auxiliary_state = 1;
-      link_give_damage = 8;
-      link_incapacitated_timer = 16;
-      link_actual_vel_x ^= 255;
-      link_actual_vel_y ^= 255;
-    }
-    oam_cur_ptr += kTrinexxD_OamOffs[i];
-    oam_ext_cur_ptr += (kTrinexxD_OamOffs[i] >> 2);
-    sprite_oam_flags[k] = 1;
-    if (i == 4 && sprite_ai_state[k] != 0) {
-      Sprite_Trinexx_CheckDamageToFlashingSegment(k);
-      sprite_oam_flags[k] = (sprite_subtype2[k] & 6) ^ sprite_oam_flags[k];
-    }
-    sprite_graphics[k] = kSprite_TrinexxD_Gfx2[i];
-    if (sprite_graphics[k] != 3) {
-      SpriteDraw_SingleLarge(k);
-    } else {
-      sprite_graphics[k] = 8;
-      SpriteDraw_TrinexxRockHead(k, &info);
-    }
-  }
-  byte_7E0FB6 = sprite_anim_clock[k];
-}
-
-void Sprite_Trinexx_CheckDamageToFlashingSegment(int k) {  // 9db079
-  uint16 old_x = Sprite_GetX(k);
-  uint16 old_y = Sprite_GetY(k);
-  Sprite_SetX(k, cur_sprite_x);
-  Sprite_SetY(k, cur_sprite_y);
-  sprite_defl_bits[k] = 0x80;
-  sprite_flags3[k] = 0;
-  Sprite_CheckDamageFromLink(k);
-  sprite_defl_bits[k] = 0x84;
-  sprite_flags3[k] = 0x40;
-  Sprite_SetX(k, old_x);
-  Sprite_SetY(k, old_y);
-}
-
-void Sprite_CB_TrinexxRockHead(int k) {  // 9db0ca
-  if (overlord_x_hi[0]) {
-    Sprite_Trinexx_FinalPhase(k);
-    return;
-  }
-  TM_copy = 0x17;
-  TS_copy = 0;
-  SpriteDraw_TrinexxRockHeadAndBody(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  if (sign8(sprite_ai_state[k])) {
-    flag_block_link_menu = sprite_ai_state[k];
-    if (!sprite_delay_main[k]) {
-      overlord_x_hi[0]++;
-      Sprite_InitializedSegmented(k);
-      sprite_subtype2[k] = 0;
-      sprite_head_dir[k] = 0;
-      sprite_flags3[k] &= ~0x40;
-      sprite_defl_bits[k] = 0x80;
-      sprite_ai_state[k] = 0;
-      sprite_D[k] = 0;
-      sprite_A[k] = 0;
-      sprite_anim_clock[k] = 16;
-      sprite_x_vel[k] = sprite_y_vel[k] = 0;
-      sprite_A[k] = 128;
-      HIBYTE(dung_floor_y_vel) = 255;
-    } else if (sprite_delay_main[k] >= 0xff) {
-    } else if (sprite_delay_main[k] >= 0xe0) {
-      if (!(sprite_delay_main[k] & 3)) {
-        dung_floor_y_vel = -1;
-        dung_hdr_collision_2_mirror = 1;
-      }
-      sprite_y_vel[k] = -8;
-      Sprite_MoveY(k);
-      Trinexx_CachePosition(k);
-      sprite_C[k] = sprite_y_lo[k] - 12;
-      overlord_x_lo[7] += 2;
-    } else {
-      if (!(sprite_delay_main[k] & 3))
-        SpriteSfx_QueueSfx2WithPan(k, 0xc);
-      if (!(sprite_delay_main[k] & 1)) {
-        static const int8 kTrinexx_X0[8] = {0, 8, 16, 24, -24, -16, -8, 0};
-        static const int8 kTrinexx_Y0[8] = {0, 8, 16, 24, -24, -16, -8, 0};
-        cur_sprite_x = Sprite_GetX(k) + kTrinexx_X0[GetRandomNumber() & 7];
-        cur_sprite_y = Sprite_GetY(k) + kTrinexx_Y0[GetRandomNumber() & 7] - 8;
-        Sprite_MakeBossDeathExplosion_NoSound(k);
-      }
-      sprite_head_dir[k] = 255;
-    }
-    return;
-  }
-  if ((sprite_state[1] | sprite_state[2]) == 0 && sprite_ai_state[k] < 2) {
-    sprite_delay_main[k] = 255;
-    sprite_ai_state[k] = 255;
-    sound_effect_2 = 0x22;
-    return;
-  }
-
-  Trinexx_WagTail(k);
-  Trinexx_HandleShellCollision(k);
-  Sprite_CheckDamageToAndFromLink(k);
-  if (!(frame_counter & 63)) {
-    PairU8 pair = Sprite_IsRightOfLink(k);
-    sprite_graphics[k] = (uint8)(pair.b + 24) < 48 ? 0 : pair.a ? 1 : 7;
-  }
-  if (overlord_x_lo[6]) {
-    if (!(frame_counter & 1))
-      overlord_x_lo[6]--;
-    return;
-  }
-  if (sprite_state[1] && sprite_ai_state[1] == 3)
-    return;
-  if (sprite_state[2] && sprite_ai_state[2] == 3)
-    return;
-
-  switch (sprite_ai_state[k]) {
-  case 0:
-    if (!sprite_delay_main[k]) {
-      int j = GetRandomNumber() & 3;
-      if ((sprite_subtype[k] & 0x7f) == j)
-        return;
-      if (++sprite_anim_clock[k] == 2) {
-        sprite_anim_clock[k] = 0;
-        sprite_ai_state[k] = 2;
-        sprite_delay_main[k] = 80;
-        return;
-      }
-      static const uint8 kTrinexx_Tab0[4] = {0x60, 0x78, 0x78, 0x90};
-      static const uint8 kTrinexx_Tab1[4] = {0x80, 0x70, 0x60, 0x80};
-      overlord_x_lo[0] = kTrinexx_Tab0[j];
-      overlord_x_lo[1] = kTrinexx_Tab1[j];
-      sprite_subtype[k] = j + ((GetRandomNumber() & 3) == 0) * 0x80;
-      sprite_ai_state[k] = 1;
-    }
-    break;
-  case 1: {
-    if (sprite_subtype[k] == 0xff && (sprite_delay_main[k] == 0 || Sprite_IsBelowLink(k).a == 0)) {
-      sprite_subtype[k] = 0;
-      sprite_ai_state[k] = 0;
-      sprite_delay_main[k] = 48;
-    } else {
-      uint16 x = sprite_x_hi[k] << 8 | overlord_x_lo[0];
-      uint16 y = sprite_y_hi[k] << 8 | overlord_x_lo[1];
-      ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLocation(k, x, y, sign8(sprite_subtype[k]) ? 16 : 8);
-      sprite_x_vel[k] = pt.x;
-      sprite_y_vel[k] = pt.y;
-
-      uint8 bakx = sprite_x_lo[k];
-      uint8 baky = sprite_y_lo[k];
-      Sprite_MoveXY(k);
-      dung_floor_y_vel = (int8)(baky - sprite_y_lo[k]);
-      dung_floor_x_vel = (int8)(bakx - sprite_x_lo[k]);
-
-      dung_hdr_collision_2_mirror = 1;
-      Trinexx_CachePosition(k);
-      sprite_C[k] = sprite_y_lo[k] - 12;
-      if ((uint8)(overlord_x_lo[0] - sprite_x_lo[k] + 2) < 4 &&
-          (uint8)(overlord_x_lo[1] - sprite_y_lo[k] + 2) < 4) {
-        sprite_ai_state[k] = 0;
-        sprite_delay_main[k] = 48;
-      }
-    }
-    int i = sign8(sprite_subtype[k]) ? 2 : 1;
-    do {
-      sprite_subtype2[k] += sign8(sprite_x_vel[k]) ? 1 : -1;
-      if (!(sprite_subtype2[k] & 0xf))
-        SpriteSfx_QueueSfx2WithPan(k, 0x21);
-    } while (--i);
-    break;
-  }
-  case 2:
-    Trinexx_WagTail(k);
-    Trinexx_WagTail(k);
-    if (!sprite_delay_main[k]) {
-      sprite_ai_state[k] = 3;
-      Sprite_ApplySpeedTowardsLink(k, 48);
-      sprite_delay_main[k] = 64;
-      sound_effect_2 = 0x26;
-    }
-    break;
-  case 3:
-    Sprite_MoveXY(k);
-    if (!sprite_delay_main[k]) {
-      Trinexx_RestoreXY(k);
-      sprite_ai_state[k] = 0;
-      sprite_delay_main[k] = 48;
-    } else if (sprite_delay_main[k] == 0x20) {
-      sprite_x_vel[k] = -sprite_x_vel[k];
-      sprite_y_vel[k] = -sprite_y_vel[k];
-    }
-    break;
-  }
-}
-
-void Trinexx_WagTail(int k) {  // 9db3b5
-  if (!overlord_x_lo[5]) {
-    if (!(++overlord_x_lo[4] & 3)) {
-      int j = overlord_x_lo[3] & 1;
-      overlord_x_lo[2] += j ? -1 : 1;
-      if (overlord_x_lo[2] == (j ? 0 : 6)) {
-        overlord_x_lo[3] += 1;
-        overlord_x_lo[5] = 8;
-      }
-    }
-  } else {
-    --overlord_x_lo[5];
-  }
-}
-
-void Trinexx_HandleShellCollision(int k) {  // 9db3e6
-  uint16 x = sprite_A[k] | sprite_B[k] << 8;
-  uint16 y = sprite_C[k] | sprite_G[k] << 8;
-  if ((uint16)(x - link_x_coord + 40) < 80 && (uint16)(y - link_y_coord + 16) < 64 && !(countdown_for_blink | link_disable_sprite_damage)) {
-    link_auxiliary_state = 1;
-    link_give_damage = 8;
-    link_incapacitated_timer = 16;
-    ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLink(k, 32);
-    link_actual_vel_x = pt.x;
-    link_actual_vel_y = pt.y;
-  }
-}
-
-void SpriteDraw_TrinexxRockHead(int k, PrepOamCoordsRet *info) {  // 9db560
-  static const DrawMultipleData kTrinexx_Draw1_Dmd[36] = {
-    {-8, -8, 0x40c0, 2},
-    { 8, -8, 0x00c0, 2},
-    {-8,  8, 0x40e0, 2},
-    { 8,  8, 0x00e0, 2},
-
-    {-8, -8, 0x0000, 2},
-    { 8, -8, 0x0002, 2},
-    {-8,  8, 0x0020, 2},
-    { 8,  8, 0x0022, 2},
-
-    {-8, -8, 0x00c2, 2},
-    { 8, -8, 0x00c4, 2},
-    {-8,  8, 0x80c2, 2},
-    { 8,  8, 0x80c4, 2},
-
-    {-8, -8, 0x8020, 2},
-    { 8, -8, 0x8022, 2},
-    {-8,  8, 0x8000, 2},
-    { 8,  8, 0x8002, 2},
-    {-8, -8, 0xc0e0, 2},
-    { 8, -8, 0x80e0, 2},
-    {-8,  8, 0xc0c0, 2},
-    { 8,  8, 0x80c0, 2},
-    {-8, -8, 0xc022, 2},
-    { 8, -8, 0xc020, 2},
-    {-8,  8, 0xc002, 2},
-    { 8,  8, 0xc000, 2},
-    {-8, -8, 0x40c4, 2},
-    { 8, -8, 0x40c2, 2},
-    {-8,  8, 0xc0c4, 2},
-    { 8,  8, 0xc0c2, 2},
-    {-8, -8, 0x4002, 2},
-    { 8, -8, 0x4000, 2},
-    {-8,  8, 0x4022, 2},
-    { 8,  8, 0x4020, 2},
-    {-8, -8, 0x0026, 2},
-    { 8, -8, 0x4026, 2},
-    {-8,  8, 0x8026, 2},
-    { 8,  8, 0xc026, 2},
-  };
-  if (!sign8(sprite_ai_state[k]))
-    sprite_obj_prio[k] |= 0x30;
-  Sprite_DrawMultiple(k, &kTrinexx_Draw1_Dmd[sprite_graphics[k] * 4], 4, info);
-}
-
-void SpriteDraw_TrinexxRockHeadAndBody(int k) {  // 9db587
-  static const int8 kTrinexx_Draw_X[35] = {
-    0,   3,   9, 16, 24,  0,  2,  7,  13, 20,  0,  1,   4,   9, 15,  0,
-    0,   0,   0,  0,  0, -1, -4, -9, -15,  0, -2, -7, -13, -20,  0, -3,
-    -9, -16, -24,
-  };
-  static const int8 kTrinexx_Draw_Y[35] = {
-    0x18, 0x20, 0x25, 0x25, 0x21, 0x18, 0x20, 0x27, 0x2a, 0x2c, 0x18, 0x20, 0x28, 0x2f, 0x34, 0x18,
-    0x21, 0x2a, 0x34, 0x3d, 0x18, 0x20, 0x28, 0x2f, 0x34, 0x18, 0x20, 0x27, 0x2a, 0x2c, 0x18, 0x20,
-    0x25, 0x25, 0x21,
-  };
-  static const uint8 kTrinexx_Draw_Char[5] = {6, 0x28, 0x28, 0x2c, 0x2c};
-  static const uint8 kTrinexx_Mults[8] = {0xfc, 0xe0, 0xc0, 0xa0, 0x80, 0x60, 0x40, 0x20};
-  static const int8 kTrinexx_Draw_Xoffs[16] = {0, 2, 3, 4, 4, 4, 3, 2, 0, -2, -3, -4, -4, -4, -3, -2};
-  static const int8 kTrinexx_Draw_Yoffs[16] = {-4, -4, -3, -2, 0, 2, 3, 4, 4, 4, 3, 2, 0, -2, -3, -4};
-  if (sign8(sprite_head_dir[k]))
-    return;
-
-  PrepOamCoordsRet info;
-  SpriteDraw_TrinexxRockHead(k, &info);
-
-  info.flags &= ~0x10;
-
-  if (sprite_ai_state[k] == 3) {
-    OamEnt *oam = GetOamCurPtr() + 4;
-    uint8 xb = sprite_A[k] - sprite_x_lo[k];
-    uint8 yb = sprite_C[k] - sprite_y_lo[k];
-    for (int i = 7; i >= 0; i--, oam++) {
-      SetOamPlain(oam, info.x + TrinexxMult(xb, kTrinexx_Mults[i]), info.y + TrinexxMult(yb, kTrinexx_Mults[i]), 0x28, info.flags, 2);
-    }
-    byte_7E0FB6 = 0x30;
-  }
-  oam_cur_ptr = 0x9f0;
-  oam_ext_cur_ptr = 0xa9c;
-  OamEnt *oam = GetOamCurPtr();
-  uint8 xb = sprite_A[k] - BG2HOFS_copy2;
-  uint16 yb = (sprite_C[k] | sprite_y_hi[k] << 8) - BG2VOFS_copy2;
-
-  uint8 xidx = (uint8)(sprite_x_vel[k] + 3) < 7 ? 0 : (sprite_subtype2[k] >> 2);
-  uint8 yidx = sprite_subtype2[k] >> 2;
-
-  for (int i = 1; i >= 0; i--, oam += 2) {
-    uint8 x = xb + (i ? -28 : 28) + kTrinexx_Draw_Xoffs[xidx + (1 - i) * 8 & 0xf];
-    uint8 y = yb - 8 + kTrinexx_Draw_Yoffs[yidx + i * 8 & 0xf];
-    uint8 f = info.flags | (i ? 0 : 0x40);
-    SetOamPlain(oam + 0, x, y, 0xc, f, 2);
-    SetOamPlain(oam + 1, x, y + 16, 0x2a, f, 2);
-  }
-
-  oam = (OamEnt *)&g_ram[0x800] + 91;
-  int g = overlord_x_lo[2];
-  for (int i = 0; i < 5; i++, oam++) {
-    int j = g * 5 + i;
-    SetOamHelper0(oam,
-                  xb + kTrinexx_Draw_X[j], yb - kTrinexx_Draw_Y[j] - 0x20 + WORD(overlord_x_lo[7]),
-                  kTrinexx_Draw_Char[i], info.flags, 2);
-  }
-  tmp_counter = 0xff;
-
-  if (submodule_index)
-    Sprite_CorrectOamEntries(k, 3, 2);
-}
-
-void Sprite_Sidenexx(int k) {  // 9db8a7
-  static const int8 kTrinexxHead_Xoffs[2] = {-14, 13};
-
-  int xx = (sprite_B[0] << 8 | sprite_A[0]) + kTrinexxHead_Xoffs[sprite_type[k] - 0xcc];
-  sprite_A[k] = xx, sprite_B[k] = xx >> 8;
-
-  int yy = (sprite_G[0] << 8 | sprite_C[0]) - 0x20;
-  sprite_C[k] = yy, sprite_G[k] = yy >> 8;
-  sprite_obj_prio[k] |= 0x30;
-  TrinexxHead_Draw(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  if (sign8(sprite_ai_state[k])) {
-    sprite_ignore_projectile[k] = sprite_ai_state[k];
-    Sidenexx_Explode(k);
-    return;
-  }
-
-  if (sprite_hit_timer[k] && sprite_ai_state[k] != 4) {
-    sprite_hit_timer[k] = 0;
-    sprite_delay_main[k] = 128;
-    sprite_ai_state[k] = 4;
-    sprite_z_vel[k] = sprite_oam_flags[k];
-    sprite_oam_flags[k] = 3;
-  }
-  Sprite_CheckDamageToAndFromLink(k);
-  sprite_defl_bits[k] |= 4;
-  switch(sprite_ai_state[k]) {
-  case 0:
-    sprite_flags3[k] |= 0x40;
-    if (!sprite_delay_main[k]) {
-      sprite_ai_state[k] = 2;
-      sprite_subtype2[k] = 9;
-      sprite_flags3[k] &= ~0x40;
-    }
-    break;
-  case 1:
-    if (!sprite_delay_main[k]) {
-      int i = (GetRandomNumber() & 7) + 1;
-      int j = sprite_D[k];
-      if (i < 5 && sprite_D[k] != i) {
-        sprite_D[k] = i;
-        sprite_ai_state[k] = 2;
-        if (j == 1 && !(GetRandomNumber() & 1) && sprite_ai_state[0] < 2) {
-          sprite_graphics[k] = 0;
-          sprite_ai_state[k] = 3;
-          sprite_delay_main[k] = 127;
-        }
-      }
-    }
-    break;
-  case 2: {
-    static const uint8 kTrinexxHead_Target0[45] = {
-      0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x58, 0x64, 0x6a, 0x6f, 0x74, 0x7a, 0x7e,
-      0x80, 0x80, 0x39, 0x48, 0x52, 0x5c, 0x65, 0x73, 0x77, 0x7a, 0x80, 0x1e, 0x24, 0x29, 0x2e, 0x34,
-      0x3a, 0x44, 0x4d, 0x80,  0xa, 0x11, 0x17, 0x1c, 0x22, 0x2a, 0x36, 0x3a, 0x80,
-    };
-    static const uint8 kTrinexxHead_Target1[45] = {
-      0x30, 0x28, 0x23, 0x1e, 0x19, 0x13,  0xc,    6,    0, 0x2f, 0x26, 0x21, 0x1d, 0x18, 0x12,  0xc,
-      6,    0, 0x2f, 0x27, 0x22, 0x1d, 0x18, 0x12,  0xc,    6,    0, 0x2f, 0x27, 0x22, 0x1d, 0x18,
-      0x12,  0xc,    6,    0, 0x48, 0x3a, 0x32, 0x29, 0x22, 0x19, 0x10,    7,    0,
-    };
-
-    int j = sprite_D[k] * 9, f = k * 9;
-    int n = 0;
-    for (int i = 8; i >= 0; i--, j++, f++) {
-      if (alt_sprite_type[f] - kTrinexxHead_Target0[j]) {
-        alt_sprite_type[f] += sign8(alt_sprite_type[f] - kTrinexxHead_Target0[j]) ? 1 : -1;
-        n++;
-      }
-      if (alt_sprite_type[f] - kTrinexxHead_Target0[j]) {
-        alt_sprite_type[f] += sign8(alt_sprite_type[f] - kTrinexxHead_Target0[j]) ? 1 : -1;
-        n++;
-      }
-      if (alt_sprite_y_hi[f] - kTrinexxHead_Target1[j]) {
-        alt_sprite_y_hi[f] += sign8(alt_sprite_y_hi[f] - kTrinexxHead_Target1[j]) ? 1 : -1;
-        n++;
-      }
-    }
-    if (n == 0) {
-      sprite_ai_state[k] = 1;
-      sprite_delay_main[k] = GetRandomNumber() & 15;
-    }
-    break;
-  }
-  case 3: {
-    static const uint8 kTrinexxHead_FrameMask[8] = {1, 1, 3, 3, 7, 0xf, 0x1f, 0x1f};
-    int j = sprite_delay_main[k];
-    if (!j) {
-      sprite_ai_state[k] = 0;
-      sprite_delay_main[k] = 32;
-      return;
-    }
-    if (j == 64)
-      Sidenexx_ExhaleDanger(k);
-    sprite_subtype[k] = (j < 8) ? j : (j < 121) ? 8 : ~(sprite_delay_main[k] + 0x80);
-    if (j >= 64 && !(frame_counter & kTrinexxHead_FrameMask[(j - 64) >> 3])) {
-      int x = (GetRandomNumber() & 0xf) - 3;
-      int y = (GetRandomNumber() & 0xf) + 12;
-      int j = Sprite_GarnishSpawn_Sparkle(k, x, y);
-      if (sprite_type[k] == 0xcc)
-        garnish_type[j] = 0xe;
-    }
-    break;
-  }
-  case 4: {
-    sprite_defl_bits[k] &= ~4;
-    sprite_subtype[k] = 0;
-    int j = sprite_delay_main[k];
-    if (!j) {
-      sprite_ai_state[k] = 1;
-      sprite_delay_main[k] = 32;
-      sprite_oam_flags[k] = sprite_z_vel[k];
-      sprite_hit_timer[k] = 0;
-    }
-    if (j >= 15) {
-      if (j >= 63 && j < 78) {
-        if (sprite_type[k] == 0xcd)
-          Trinexx_FlashShellPalette_Blue();
-        else
-          Trinexx_FlashShellPalette_Red();
-      }
-    } else {
-      if (sprite_type[k] == 0xcd)
-        Trinexx_UnflashShellPalette_Blue();
-      else
-        Trinexx_UnflashShellPalette_Red();
-    }
-  }
-  }
-}
-
-void Sidenexx_ExhaleDanger(int k) {  // 9dbae8
-  SpriteSpawnInfo info;
-  if (sprite_type[k] == 0xcd) {
-    for (int i = 0; i < 2; i++) {
-      int j = Sprite_SpawnDynamically(k, 0xcd, &info);
-      if (j >= 0) {
-        Sprite_SetSpawnedCoordinates(j, &info);
-        sprite_C[j] = i ? 1 : -2;
-        SpriteSfx_QueueSfx3WithPan(k, 0x19);
-        sprite_ignore_projectile[j] = sprite_E[j] = 1;
-        sprite_y_vel[j] = 24;
-        sprite_flags2[j] = 0;
-        sprite_flags3[j] = 0x40;
-      }
-    }
-    byte_7E0FB6 = 1;
-  } else {
-    int j = Sprite_SpawnDynamically(k, sprite_type[k], &info);
-    if (j >= 0) {
-      Sprite_SetSpawnedCoordinates(j, &info);
-      SpriteSfx_QueueSfx2WithPan(k, 0x2a);
-      sprite_ignore_projectile[j] = sprite_E[j] = 1;
-      sprite_y_vel[j] = 24;
-      sprite_flags2[j] = 0;
-      sprite_flags3[j] = 0x40;
-    }
-  }
-}
-
-void Sidenexx_Explode(int k) {  // 9dbb3f
-  if (!sprite_delay_main[k]) {
-    sprite_delay_main[k] = 12;
-    if (sprite_subtype2[k] == 1)
-      sprite_state[k] = 0;
-    sprite_subtype2[k]--;
-    BYTE(cur_sprite_x) += BG2HOFS_copy2;
-    BYTE(cur_sprite_y) += BG2VOFS_copy2;
-    Sprite_MakeBossExplosion(k);
-  }
-}
-
-void TrinexxHead_Draw(int k) {  // 9dbb70
-  sprite_x_lo[k] = sprite_A[k];
-  sprite_x_hi[k] = sprite_B[k];
-  sprite_y_lo[k] = sprite_C[k];
-  sprite_y_hi[k] = sprite_G[k];
-  Sprite_Get16BitCoords(k);
-  PrepOamCoordsRet info;
-  if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
-    return;
-  OamEnt *oam = GetOamCurPtr();
-  int i = 0;
-  do {
-    int j = i + k * 9;
-
-    uint16 r6 = (k != 2) ? 0x100 + (uint8)(-alt_sprite_type[j]) : alt_sprite_type[j];
-    uint8 r15 = alt_sprite_y_hi[j];
-
-    BYTE(dungmap_var7) = TrinexxHeadSin(r6, r15);
-    HIBYTE(dungmap_var7) = TrinexxHeadSin(r6 + 0x80, r15);
-
-    if (i == 0) {
-      static const int8 kTrinexxHead_FirstPart_X[5] = {-8, 8, -8, 8, 0};
-      static const int8 kTrinexxHead_FirstPart_Y[5] = {-8, -8, 8, 8, 2};
-      static const uint8 kTrinexxHead_FirstPart_Char[5] = {4, 4, 0x24, 0x24, 0xa};
-      static const uint8 kTrinexxHead_FirstPart_Flags[5] = {0x40, 0, 0x40, 0, 0};
-
-      for (int m = 0; m < 5; m++) {
-        BYTE(cur_sprite_x) = info.x + BYTE(dungmap_var7);
-        uint8 x = BYTE(cur_sprite_x) + kTrinexxHead_FirstPart_X[m];
-
-        BYTE(cur_sprite_y) = info.y + HIBYTE(dungmap_var7);
-        uint8 y = BYTE(cur_sprite_y) + kTrinexxHead_FirstPart_Y[m] + (m == 4 ? sprite_subtype[k] : 0);
-
-        SetOamPlain(oam, x, y, kTrinexxHead_FirstPart_Char[m], info.flags | kTrinexxHead_FirstPart_Flags[m], 2);
-        oam++;
-      }
-      Sprite_SetX(k, (sprite_B[k] << 8 | sprite_A[k]) + (int8)BYTE(dungmap_var7));
-      Sprite_SetY(k, (sprite_G[k] << 8 | sprite_C[k]) + (int8)HIBYTE(dungmap_var7));
-    } else {
-      uint8 x = info.x + BYTE(dungmap_var7);
-      uint8 y = info.y + HIBYTE(dungmap_var7);
-      BYTE(cur_sprite_x) = x;
-      BYTE(cur_sprite_y) = y;
-      SetOamPlain(oam, x, y, 8, info.flags, 2);
-      oam++;
-    }
-  } while (++i != sprite_subtype2[k]);
-
-  tmp_counter = i;
-  byte_7E0FB6 = i * 4 + 16;
-  if (submodule_index)
-    Sprite_CorrectOamEntries(k, 4, 2);
-}
-
-void Sprite_CC_CD_Common(int k) {  // 9dbd44
-  if (!(frame_counter & 3)) {
-    int m = Sprite_IsRightOfLink(k).a ? -1 : 1;
-    if (sprite_x_vel[k] != (uint8)(m * 16))
-      sprite_x_vel[k] += m;
-  }
-  if (Sprite_CheckTileCollision(k))
-    sprite_state[k] = 0;
-}
-
-void Sprite_CD_SpawnGarnish(int k) {  // 9dbd65
-  if (++sprite_subtype2[k] & 7)
-    return;
-  SpriteSfx_QueueSfx3WithPan(k, 0x14);
-  int j = GarnishAllocOverwriteOld();
-  garnish_active = garnish_type[j] = 0xc;
-  garnish_sprite[j] = k;
-  Garnish_SetX(j, Sprite_GetX(k));
-  Garnish_SetY(j, Sprite_GetY(k) + 16);
-  garnish_countdown[j] = 127;
-}
-
-void Sprite_TrinexxFire_AddFireGarnish(int k) {  // 9dbdd6
-  if (++sprite_subtype2[k] & 7)
-    return;
-  SpriteSfx_QueueSfx2WithPan(k, 0x2a);
-  Garnish_FlameTrail(k, false);
-}
-
-int Garnish_FlameTrail(int k, bool is_low) {  // 9dbde8
-  int j = is_low ? GarnishAllocOverwriteOldLow() : GarnishAllocOverwriteOld();
-  garnish_active = garnish_type[j] = 0x10;
-  garnish_sprite[j] = k;
-  Garnish_SetX(j, Sprite_GetX(k));
-  Garnish_SetY(j, Sprite_GetY(k) + 16);
-  garnish_countdown[j] = 127;
-  return j;
-}
-
-void Sprite_CA_ChainChomp(int k) {  // 9dbe7d
-  ChainChomp_Draw(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  Sprite_CheckDamageToAndFromLink(k);
-  ChainChomp_HandleLeash(k);
-  if (!((k ^ frame_counter) & 3) && (sprite_x_vel[k] | sprite_y_vel[k]))
-    sprite_D[k] = Sprite_ConvertVelocityToAngle(sprite_x_vel[k], sprite_y_vel[k]) & 0xf;
-  Sprite_MoveXYZ(k);
-  sprite_z_vel[k] -= 2;
-  if (sign8(sprite_z[k])) {
-    sprite_z[k] = 0;
-    sprite_z_vel[k] = 0;
-  }
-  Sprite_Get16BitCoords(k);
-  uint16 x = sprite_A[k] | sprite_B[k] << 8;
-  uint16 y = sprite_C[k] | sprite_G[k] << 8;
-  sprite_anim_clock[k] = (uint16)(cur_sprite_x - x + 48) < 96 && (uint16)(cur_sprite_y - y + 48) < 96;
-  switch(sprite_ai_state[k]) {
-  case 0:  //
-    if (!sprite_delay_main[k]) {
-      static const int8 kChainChomp_Xvel[16] = {0, 8, 11, 14, 16, 14, 11, 8, 0, -8, -11, -14, -16, -14, -11, -8};
-      static const int8 kChainChomp_Yvel[16] = {-16, -14, -11, -8, 0, 8, 11, 14, 16, 14, 11, 8, 0, -9, -11, -14};
-      if (++sprite_subtype2[k] == 4) {
-        sprite_subtype2[k] = 0;
-        sprite_ai_state[k] = 2;
-        int j = GetRandomNumber() & 15;
-        sprite_x_vel[k] = kChainChomp_Xvel[j] << 2;
-        sprite_y_vel[k] = kChainChomp_Yvel[j] << 2;
-        GetRandomNumber();
-        Sprite_ApplySpeedTowardsLink(k, 64);
-        SpriteSfx_QueueSfx3WithPan(k, 0x4);
-      } else {
-        sprite_delay_main[k] = (GetRandomNumber() & 31) + 16;
-        int j = GetRandomNumber() & 15;
-        sprite_x_vel[k] = kChainChomp_Xvel[j];
-        sprite_y_vel[k] = kChainChomp_Yvel[j];
-        sprite_ai_state[k] = 1;
-      }
-    } else {
-      sprite_x_vel[k] = 0;
-      sprite_y_vel[k] = 0;
-    }
-    break;
-  case 1:  //
-    if (!sprite_delay_main[k]) {
-      sprite_delay_main[k] = 32;
-      sprite_ai_state[k] = 0;
-    }
-    if (!(sprite_delay_main[k] & 15))
-      ChainChomp_MoveChain(k);
-    if (!sprite_z[k])
-      sprite_z_vel[k] = 16;
-    if (!sprite_anim_clock[k]) {
-      uint16 x = sprite_A[k] | sprite_B[k] << 8;
-      uint16 y = sprite_C[k] | sprite_G[k] << 8;
-      ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLocation(k, x, y, 16);
-      sprite_x_vel[k] = pt.x;
-      sprite_y_vel[k] = pt.y;
-      Sprite_MoveXY(k);
-      sprite_delay_main[k] = 12;
-    }
-    break;
-  case 2:  //
-    if (!sprite_anim_clock[k]) {
-      sprite_x_vel[k] = -sprite_x_vel[k];
-      sprite_y_vel[k] = -sprite_y_vel[k];
-      Sprite_MoveXY(k);
-      sprite_x_vel[k] = sprite_y_vel[k] = 0;
-      sprite_ai_state[k] = 3;
-      sprite_delay_aux1[k] = 48;
-    }
-    ChainChomp_MoveChain(k);
-    ChainChomp_MoveChain(k);
-    break;
-  case 3:  //
-    if (!sprite_delay_aux1[k]) {
-      sprite_ai_state[k] = 0;
-      sprite_delay_main[k] = 48;
-    }
-    ChainChomp_MoveChain(k);
-    ChainChomp_MoveChain(k);
-    break;
-  }
-
-}
-
-void ChainChomp_MoveChain(int k) {  // 9dc02a
-  static const uint8 kChainChomp_Muls[6] = {205, 154, 102, 51, 8, 0xbd}; // wtf
-  uint16 x = sprite_A[k] | sprite_B[k] << 8;
-  uint16 y = sprite_C[k] | sprite_G[k] << 8;
-  int pos = k * 8;
-  uint16 x2 = chainchomp_x_hist[pos] - x;
-  uint16 y2 = chainchomp_y_hist[pos] - y;
-  pos++;
-  for (int i = 5; i >= 0; i--) {
-    uint16 x3 = x + ChainChomp_OneMult(x2, kChainChomp_Muls[(pos & 7) - 1]);
-    uint16 y3 = y + ChainChomp_OneMult(y2, kChainChomp_Muls[(pos & 7) - 1]);
-    if (chainchomp_x_hist[pos] - x3)
-      chainchomp_x_hist[pos] += sign16(chainchomp_x_hist[pos] - x3) ? 1 : -1;
-    if (chainchomp_y_hist[pos] - y3)
-      chainchomp_y_hist[pos] += sign16(chainchomp_y_hist[pos] - y3) ? 1 : -1;
-    pos++;
-  }
-}
-
-void ChainChomp_HandleLeash(int k) {  // 9dc0f2
-  int pos = k * 8;
-  chainchomp_x_hist[pos] = cur_sprite_x;
-  chainchomp_y_hist[pos] = cur_sprite_y;
-  for (int i = 0; i < 6; i++, pos++) {
-    uint16 x = chainchomp_x_hist[pos] - chainchomp_x_hist[pos + 1];
-    if (!sign16(x - 8))
-      chainchomp_x_hist[pos + 1] = chainchomp_x_hist[pos] - 8;
-    else if (sign16(x + 8))
-      chainchomp_x_hist[pos + 1] = chainchomp_x_hist[pos] + 8;
-
-    uint16 y = chainchomp_y_hist[pos] - chainchomp_y_hist[pos + 1];
-    if (!sign16(y - 8))
-      chainchomp_y_hist[pos + 1] = chainchomp_y_hist[pos] - 8;
-    else if (sign16(y + 8))
-      chainchomp_y_hist[pos + 1] = chainchomp_y_hist[pos] + 8;
-  }
-}
-
-void ChainChomp_Draw(int k) {  // 9dc192
-  static const uint8 kChainChomp_Gfx[16] = {0, 1, 2, 3, 3, 3, 2, 1, 0, 0, 0, 4, 4, 4, 0, 0};
-  static const uint8 kChainChomp_OamFlags[16] = {0x40, 0x40, 0x40, 0x40, 0, 0, 0, 0, 0, 0, 0, 0, 0x40, 0x40, 0x40, 0x40};
-
-  int j = sprite_D[k];
-  sprite_graphics[k] = kChainChomp_Gfx[j];
-  sprite_oam_flags[k] = sprite_oam_flags[k] & 0x3f | kChainChomp_OamFlags[j];
-  SpriteDraw_SingleLarge(k);
-  OamEnt *oam = GetOamCurPtr() + 1;
-  uint8 flags = sprite_oam_flags[k] ^ sprite_obj_prio[k];
-  int r8 = (sprite_delay_aux1[k] & 1) + 4;
-  int pos = k * 8;
-  for (int i = 5; i >= 0; i--, pos++, oam++) {
-    SetOamHelper0(oam,
-                  chainchomp_x_hist[pos] + r8 - BG2HOFS_copy2,
-                  chainchomp_y_hist[pos] + r8 - BG2VOFS_copy2,
-                  0x8b,
-                  flags & 0xf0 | 0xd, 0);
-  }
-}
-
-void Sprite_C9_Tektite(int k) {  // 9dc275
-  int j = sprite_anim_clock[k];
-  if (j) {
-    sprite_ignore_projectile[k] = j;
-    sprite_obj_prio[k] = 0x30;
-  }
-  switch (j) {
-  case 0: Sprite_Tektite(k); break;
-  case 1: Sprite_PhantomGanon(k); break;
-  case 2: Sprite_GanonTrident(k); break;
-  case 3: Sprite_SpiralFireBat(k); break;
-  case 4: Sprite_FireBat_Launched(k); break;
-  case 5: Sprite_FireBat_Trailer(k); break;
-  }
-}
-
-void Sprite_Tektite(int k) {  // 9dc293
-  int j;
-
-  if (sprite_delay_aux1[k])
-    sprite_graphics[k] = 0;
-  Tektite_Draw(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  if (Sprite_ReturnIfRecoiling(k))
-    return;
-  Sprite_CheckDamageToAndFromLink(k);
-  Sprite_MoveXYZ(k);
-  Sprite_BounceFromTileCollision(k);
-  sprite_z_vel[k] -= 1;
-  if (sign8(sprite_z[k])) {
-    sprite_z[k] = 0;
-    sprite_z_vel[k] = 0;
-  }
-  switch(sprite_ai_state[k]) {
-  case 0: { // Stationary
-    static const uint8 kTektite_Dir[4] = {3, 2, 1, 0};
-    static const int8 kTektite_Xvel[4] = {16, -16, 16, -16};
-    static const int8 kTektite_Yvel[4] = {16, 16, -16, -16};
-    PointU8 pt;
-    j = Sprite_DirectionToFaceLink(k, &pt);
-    if ((uint8)(pt.x + 40) < 80 && (uint8)(pt.y + 40) < 80 && player_oam_y_offset != 0x80 &&
-        !(sprite_z[k] | sprite_pause[k]) && link_is_on_lower_level == sprite_floor[k] && j != kTektite_Dir[link_direction_facing >> 1]) {
-      ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLink(k, 32);
-      sprite_x_vel[k] = -pt.x;
-      sprite_y_vel[k] = -pt.y;
-      sprite_z_vel[k] = 16;
-      sprite_ai_state[k] = 1;
-      return;
-    }
-    if (!sprite_delay_main[k]) {
-      sprite_ai_state[k]++;
-      sprite_B[k]++;
-      if (sprite_B[k] == 4) {
-        sprite_B[k] = 0;
-        sprite_ai_state[k]++;
-        sprite_delay_main[k] = (GetRandomNumber() & 63) + 48;
-        sprite_z_vel[k] = 12;
-        j = Sprite_IsBelowLink(k).a * 2 + Sprite_IsRightOfLink(k).a;
-      } else {
-        sprite_z_vel[k] = (GetRandomNumber() & 7) + 24;
-        j = GetRandomNumber() & 3;
-      }
-      sprite_x_vel[k] = kTektite_Xvel[j];
-      sprite_y_vel[k] = kTektite_Yvel[j];
-    } else {
-      sprite_graphics[k] = sprite_delay_main[k] >> 4 & 1;
-    }
-    break;
-  }
-  case 1: // Aloft
-    if (!sprite_z[k]) {
-reset_state:
-      sprite_ai_state[k] = 0;
-      sprite_delay_main[k] = (GetRandomNumber() & 63) + 72;
-      sprite_y_vel[k] = 0;
-      sprite_x_vel[k] = 0;
-    } else {
-      sprite_graphics[k] = 2;
-    }
-    break;
-  case 2: // RepeatingHop
-    if (!sprite_delay_main[k])
-      goto reset_state;
-    if (!sprite_z[k]) {
-      sprite_z_vel[k] = 12;
-      sprite_z[k]++;
-      sprite_delay_aux1[k] = 8;
-    }
-    sprite_graphics[k] = 2;
-    break;
-  }
-}
-
-void Tektite_Draw(int k) {  // 9dc3f5
-  static const DrawMultipleData kTektite_Dmd[6] = {
-    {-8, 0, 0x00c8, 2},
-    { 8, 0, 0x40c8, 2},
-    {-8, 0, 0x00ca, 2},
-    { 8, 0, 0x40ca, 2},
-    {-8, 0, 0x00ea, 2},
-    { 8, 0, 0x40ea, 2},
-  };
-  PrepOamCoordsRet info;
-  Sprite_DrawMultiple(k, &kTektite_Dmd[sprite_graphics[k] * 2], 2, &info);
-  SpriteDraw_Shadow(k, &info);
-}
-
-void Sprite_C8_BigFairy(int k) {  // 9dc414
-  if (sprite_head_dir[k])
-    Sprite_FairyCloud(k);
-  else
-    Sprite_BigFairy(k);
-}
-
-void Sprite_FairyCloud(int k) {  // 9dc41c
-  PrepOamCoordsRet info;
-  Sprite_PrepOamCoord(k, &info);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  sprite_subtype2[k]++;
-  FaerieCloud_Draw(k);
-  if (!(sprite_subtype2[k] & 31))
-    SpriteSfx_QueueSfx2WithPan(k, 0x31);
-  switch (sprite_ai_state[k]) {
-  case 0:
-    sprite_A[k] = 0;
-    Sprite_ApplySpeedTowardsLink(k, 8);
-    Sprite_MoveXY(k);
-    Sprite_Get16BitCoords(k);
-    if ((uint16)(link_x_coord - cur_sprite_x + 3) < 6 &&
-        (uint16)(link_y_coord - cur_sprite_y + 11) < 6) {
-      WORD(link_hearts_filler) += 0xa0;
-      sprite_ai_state[k] = 1;
-    }
-    break;
-  case 1:
-    if (link_health_current == link_health_capacity) {
-      sprite_ai_state[k]++;
-      sprite_delay_aux2[0] = 112; // zelda bug
-    }
-    break;
-  case 2:
-    if ((sprite_subtype2[k] & 15) || sign8(sprite_A[k]))
-      return;
-    sprite_A[k] = sprite_A[k] * 2 + 1;
-    if (sprite_A[k] >= 0x80) {
-      sprite_A[k] = 255;
-      flag_is_link_immobilized = 0;
-      sprite_state[k] = 0;
-    }
-    break;
-  }
-}
-
-void Sprite_BigFairy(int k) {  // 9dc4bf
-  PointU8 pt;
-  int i = sprite_delay_aux2[k];
-  if (i != 0 && i < 0x40) {
-    if (--i == 0)
-      sprite_state[k] = 0;
-    if (i & 1)
-      return;
-  }
-  BigFaerie_Draw(k);
-  if (sign8(--sprite_G[k])) {
-    sprite_G[k] = 5;
-    sprite_graphics[k] = sprite_graphics[k] + 1 & 3;
-  }
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  sprite_subtype2[k]++;
-  switch (sprite_ai_state[k]) {
-  case 0:  // await close player
-    FaerieCloud_Draw(k);
-    sprite_A[k] = 1;
-    Sprite_DirectionToFaceLink(k, &pt);
-    if ((uint8)(pt.x + 0x30) < 0x60 && (uint8)(pt.y + 0x30) < 0x60) {
-      Link_CancelDash();
-      sprite_ai_state[k] = 1;
-      dialogue_message_index = 0x15a;
-      Sprite_ShowMessageMinimal();
-      flag_is_link_immobilized = 1;
-      SpriteSpawnInfo info;
-      int j = Sprite_SpawnDynamically(k, 0xC8, &info);
-      Sprite_SetSpawnedCoordinates(j, &info);
-      sprite_head_dir[j] = 1;
-      sprite_y_lo[j] -= sprite_z[k];
-      sprite_z[j] = 0;
-    }
-    break;
-  case 1:  // dormant
-    break;
-  }
-}
-
-void BigFaerie_Draw(int k) {  // 9dc5d0
-  static const DrawMultipleData kBigFaerie_Dmd[16] = {
-    {-4, -8, 0x008e, 2},
-    { 4, -8, 0x408e, 2},
-    {-4,  8, 0x00ae, 2},
-    { 4,  8, 0x40ae, 2},
-    {-4, -8, 0x008c, 2},
-    { 4, -8, 0x408c, 2},
-    {-4,  8, 0x00ac, 2},
-    { 4,  8, 0x40ac, 2},
-    {-4, -8, 0x008a, 2},
-    { 4, -8, 0x408a, 2},
-    {-4,  8, 0x00aa, 2},
-    { 4,  8, 0x40aa, 2},
-    {-4, -8, 0x008c, 2},
-    { 4, -8, 0x408c, 2},
-    {-4,  8, 0x00ac, 2},
-    { 4,  8, 0x40ac, 2},
-  };
-  PrepOamCoordsRet info;
-  Sprite_DrawMultiple(k, &kBigFaerie_Dmd[sprite_graphics[k] * 4], 4, &info);
-  SpriteDraw_Shadow(k, &info);
-}
-
-void FaerieCloud_Draw(int k) {  // 9dc616
-  static const int8 kFaerieCloud_Draw_XY[8] = {-12, -6, 0, 6, 12, 18, 0, 6};
-  if (!sign8(sprite_A[k]) && !(sprite_A[k] & sprite_subtype2[k])) {
-    int x = kFaerieCloud_Draw_XY[GetRandomNumber() & 7];
-    int y = kFaerieCloud_Draw_XY[GetRandomNumber() & 7];
-    Sprite_GarnishSpawn_Sparkle(k, x, y);
-  }
-}
-
-void Sprite_C7_Pokey(int k) {  // 9dc64f
-  if (sprite_C[k]) {
-    SpriteDraw_SingleLarge(k);
-    if (Sprite_ReturnIfInactive(k))
-      return;
-    Sprite_CheckDamageToAndFromLink(k);
-    Sprite_MoveXYZ(k);
-    sprite_z_vel[k] -= 2;
-    if (sign8(sprite_z[k])) {
-      sprite_z_vel[k] = 16;
-      sprite_z[k] = 0;
-    }
-    if (Sprite_BounceFromTileCollision(k))
-      SpriteSfx_QueueSfx2WithPan(k, 0x21);
-    if (sprite_G[k] >= 3) {
-      sprite_state[k] = 6;
-      sprite_delay_main[k] = 10;
-      sprite_flags5[k] = 0;
-      SpriteSfx_QueueSfx2WithPan(k, 0x1e);
-    }
-    return;
-  }
-
-  Hokbok_Draw(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  if (sprite_A[k] && sprite_F[k] == 15) {
-    sprite_F[k] = 6;
-    sprite_z[k] += sprite_B[k];
-    if (!--sprite_A[k])
-      sprite_health[k] = 17;
-    sprite_x_vel[k] += sign8(sprite_x_vel[k]) ? -4 : 4;
-    sprite_y_vel[k] += sign8(sprite_y_vel[k]) ? -4 : 4;
-
-    SpriteSpawnInfo info;
-    int j = Sprite_SpawnDynamically(k, 0xc7, &info);
-    if (j >= 0) {
-      Sprite_SetSpawnedCoordinates(j, &info);
-      sprite_C[j] = 1;
-      sprite_health[j] = 1;
-      sprite_x_vel[j] = sprite_x_recoil[k];
-      sprite_y_vel[j] = sprite_y_recoil[k];
-      sprite_defl_bits[j] = 64;
-    }
-  }
-  if (Sprite_ReturnIfRecoiling(k))
-    return;
-  Sprite_CheckDamageToAndFromLink(k);
-  switch(sprite_ai_state[k]) {
-  case 0:
-    if (!sprite_delay_main[k]) {
-      sprite_ai_state[k] = 1;
-      sprite_z_vel[k] = 16;
-    } else {
-      static const uint8 kHokbok_B[8] = {8, 7, 6, 5, 4, 5, 6, 7};
-      sprite_B[k] = kHokbok_B[sprite_delay_main[k] >> 1];
-    }
-    break;
-  case 1:
-    Sprite_MoveXYZ(k);
-    sprite_z_vel[k] -= 2;
-    if (sign8(sprite_z[k])) {
-      sprite_z[k] = 0;
-      sprite_ai_state[k] = 0;
-      sprite_delay_main[k] = 15;
-    }
-    Sprite_BounceFromTileCollision(k);
-    break;
-  }
-}
-
-void Hokbok_Draw(int k) {  // 9dc77d
-  PrepOamCoordsRet info;
-  if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
-    return;
-  OamEnt *oam = GetOamCurPtr() + 3;
-  int d = sprite_B[k];
-  uint16 y = info.y;
-  for (int i = sprite_A[k]; i >= 0; i--, oam--) {
-    SetOamHelper0(oam, info.x, y,
-                  ((i == 0) ? 0xa2 : 0xa0) - ((d < 7) ? 0x20 : 0), info.flags, 2);
-    y -= d;
-  }
-  SpriteDraw_Shadow(k, &info);
-}
-
-void Sprite_C5_Medusa(int k) {  // 9dc7eb
-  PrepOamCoordsRet info;
-  Sprite_PrepOamCoord(k, &info);
-  if (!player_is_indoors) {
-    sprite_x_vel[k] = 255;
-    sprite_subtype[k] = 255;
-    if (!Sprite_CheckTileCollision(k))
-      return;
-    if (Sprite_ReturnIfInactive(k))
-      return;
-    sprite_type[k] = 0x19;
-    SpritePrep_LoadProperties(k);
-    sprite_E[k]++;
-    sprite_x_lo[k] += 8;
-    sprite_y_lo[k] -= 8;
-    SpriteSfx_QueueSfx3WithPan(k, 0x19);
-    sprite_defl_bits[k] = 0x80;
-  } else {
-    if (Sprite_ReturnIfInactive(k))
-      return;
-    sprite_subtype2[k]++;
-    if (!(sprite_subtype2[k] & 0x7f) && sprite_floor[k] == link_is_on_lower_level) {
-      int j = Sprite_SpawnFireball(k);
-      if (j >= 0) {
-        sprite_defl_bits[j] = sprite_defl_bits[j] | 8;
-        sprite_bump_damage[j] = 4;
-      }
-    }
-  }
-}
-
-void Sprite_C6_4WayShooter(int k) {  // 9dc869
-  static const int8 kFireballJunction_X[4] = {12, -12, 0, 0};
-  static const int8 kFireballJunction_Y[4] = {0, 0, 12, -12};
-  static const int8 kFireballJunction_XYvel[6] = {0, 0, 40, -40, 0, 0};
-  PrepOamCoordsRet info;
-  Sprite_PrepOamCoord(k, &info);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  if (sprite_delay_main[k] == 24) {
-    int j = Sprite_SpawnFireball(k);
-    if (j >= 0) {
-      sprite_defl_bits[j] |= 8;
-      sprite_bump_damage[j] = 4;
-      int i = Sprite_DirectionToFaceLink(j, NULL);
-      sprite_x_vel[j] = kFireballJunction_XYvel[i + 2];
-      sprite_y_vel[j] = kFireballJunction_XYvel[i];
-      Sprite_SetX(j, Sprite_GetX(j) + kFireballJunction_X[i]);
-      Sprite_SetY(j, Sprite_GetY(j) + kFireballJunction_Y[i]);
-    }
-  } else if (sprite_delay_main[k] == 0) {
-    if (button_b_frames && sprite_floor[k] == link_is_on_lower_level)
-      sprite_delay_main[k] = 32;
-  }
-}
-
-void Sprite_C4_Thief(int k) {  // 9dc8d8
-  int j;
-
-
-
-  Thief_Draw(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  if (Sprite_ReturnIfRecoiling(k))
-    return;
-  Sprite_CheckDamageFromLink(k);
-  if (sprite_ai_state[k] != 3) {
-    j = Sprite_DirectionToFaceLink(k, NULL);
-    sprite_head_dir[k] = j;
-    if ((j ^ sprite_D[k]) == 1)
-      sprite_D[k] = j;
-  }
-  switch (sprite_ai_state[k]) {
-  case 0:  // loitering
-    Thief_CheckCollisionWithLink(k);
-    if (!sprite_delay_main[k]) {
-      if ((uint16)(link_x_coord - cur_sprite_x + 0x50) < 0xa0 &&
-        (uint16)(link_y_coord - cur_sprite_y + 0x50) < 0xa0) {
-        sprite_ai_state[k]++;
-        sprite_delay_main[k] = 16;
-      }
-    }
-    sprite_graphics[k] = kThief_Gfx[sprite_D[k]];
-    break;
-  case 1:  // watch player
-    Thief_CheckCollisionWithLink(k);
-    sprite_D[k] = sprite_head_dir[k] = Sprite_DirectionToFaceLink(k, NULL);
-    if (!sprite_delay_main[k]) {
-      sprite_ai_state[k] = 2;
-      sprite_delay_main[k] = 32;
-    }
-thief_common:
-    if (!(frame_counter & 31))
-      sprite_D[k] = sprite_head_dir[k];
-    sprite_graphics[k] = kThief_Gfx[4 + sprite_D[k] + (++sprite_subtype2[k] & 4)];
-    break;
-  case 2:  // chase player
-    Sprite_ApplySpeedTowardsLink(k, 18);
-    if (!sprite_wallcoll[k])
-      Sprite_MoveXY(k);
-    Sprite_CheckTileCollision(k);
-    if (!sprite_delay_main[k]) {
-      if ((uint16)(link_x_coord - cur_sprite_x + 0x50) >= 0xa0 ||
-        (uint16)(link_y_coord - cur_sprite_y + 0x50) >= 0xa0) {
-        sprite_ai_state[k] = 0;
-        sprite_delay_main[k] = 128;
-      }
-    }
-    if (Sprite_CheckDamageToLink(k)) {
-      sprite_ai_state[k]++;
-      sprite_delay_main[k] = 32;
-      Thief_SpillItems(k);
-      SpriteSfx_QueueSfx2WithPan(k, 0xb);
-    }
-    goto thief_common;
-  case 3:  // steal
-    Thief_CheckCollisionWithLink(k);
-    j = Thief_ScanForBooty(k);
-
-    if (!sprite_delay_main[k]) {
-      sprite_graphics[k] = kThief_Gfx[4 + sprite_D[k] + (++sprite_subtype2[k] & 4)];
-      if (!sprite_wallcoll[k])
-        Sprite_MoveXY(k);
-      Sprite_CheckTileCollision(k);
-      sprite_D[k] = sprite_head_dir[k];
-    }
-    if (!((k ^ frame_counter) & 3))
-      sprite_head_dir[k] = Sprite_DirectionToFaceLocation(k, Sprite_GetX(j), Sprite_GetY(j));
-    break;
-  }
-}
-
-uint8 Thief_ScanForBooty(int k) {  // 9dca24
-  for (int j = 15; j >= 0; j--) {
-    if (sprite_state[j] && (sprite_type[j] == 0xdc || sprite_type[j] == 0xe1 || sprite_type[j] == 0xd9)) {
-      Thief_TargetBooty(k, j);
-      return j;
-    }
-  }
-  sprite_ai_state[k] = 0;
-  sprite_delay_main[k] = 64;
-  return 0xff;
-}
-
-void Thief_TargetBooty(int k, int j) {  // 9dca4c
-  if (!((k ^ frame_counter) & 3)) {
-    ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLocation(k, Sprite_GetX(j), Sprite_GetY(j), 19);
-    sprite_x_vel[k] = pt.x;
-    sprite_y_vel[k] = pt.y;
-  }
-  for (j = 15; j >= 0; j--) {
-    if (!((j ^ frame_counter) & 3 | sprite_delay_aux4[j]) && sprite_state[j] &&
-        (sprite_type[j] == 0xdc || sprite_type[j] == 0xe1 || sprite_type[j] == 0xd9)) {
-      Thief_GrabBooty(k, j);
-    }
-  }
-}
-
-void Thief_GrabBooty(int k, int j) {  // 9dca9e
-  if ((uint16)(Sprite_GetX(j) - cur_sprite_x + 8) < 16 &&
-      (uint16)(Sprite_GetY(j) - cur_sprite_y + 12) < 24) {
-    sprite_state[j] = 0;
-
-    int t = sprite_type[j] - 0xd8;
-    SpriteSfx_QueueSfx3WithPan(t, kAbsorptionSfx[t]);
-    sprite_delay_main[k] = 14;
-  }
-}
-
-void Thief_CheckCollisionWithLink(int k) {  // 9dcaf2
-  if (Sprite_CheckDamageToLink_same_layer(k)) {
-    ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLink(k, 32);
-    link_actual_vel_y = pt.y;
-    sprite_y_recoil[k] = pt.y ^ 0xff;
-    link_actual_vel_x = pt.x;
-    sprite_x_recoil[k] = pt.x ^ 0xff;
-    link_incapacitated_timer = 4;
-    sprite_F[k] = 12;
-    SpriteSfx_QueueSfx2WithPan(k, 0xb);
-  }
-}
-
-void Thief_SpillItems(int k) {  // 9dcb30
-  static const uint8 kThiefSpawn_Items[4] = {0xd9, 0xe1, 0xdc, 0xd9};
-  static const int8 kThiefSpawn_Xvel[6] = {0, 24, 24, 0, -24, -24};
-  static const int8 kThiefSpawn_Yvel[6] = {-32, -16, 16, 32, 16, -16};
-
-  tmp_counter = 5;
-  do {
-    byte_7E0FB6 = GetRandomNumber() & 3;
-    int j;
-    if (byte_7E0FB6 == 1) {
-      j = link_num_arrows;
-    } else if (byte_7E0FB6 == 2) {
-      j = link_item_bombs;
-    } else {
-      j = link_rupees_goal;
-    }
-    if (!j)
-      return;
-    SpriteSpawnInfo info;
-    j = Sprite_SpawnDynamicallyEx(k, kThiefSpawn_Items[byte_7E0FB6], &info, 7);
-    if (j < 0)
-      return;
-    if (byte_7E0FB6 == 1)
-      link_num_arrows--;
-    else if (byte_7E0FB6 == 2)
-      link_item_bombs--;
-    else
-      link_rupees_goal--;
-    Sprite_SetX(j, link_x_coord);
-    Sprite_SetY(j, link_y_coord);
-    sprite_z_vel[j] = 0x18;
-    sprite_x_vel[j] = kThiefSpawn_Xvel[tmp_counter];
-    sprite_y_vel[j] = kThiefSpawn_Yvel[tmp_counter];
-    sprite_delay_aux4[j] = 32;
-    sprite_head_dir[j] = 1;
-    sprite_stunned[j] = 255;
-  } while (!sign8(--tmp_counter));
-}
-
-void Thief_Draw(int k) {  // 9dcc9e
-  static const DrawMultipleData kThief_Dmd[24] = {
-    {0, -6, 0x0000, 2},
-    {0,  0, 0x0006, 2},
-    {0, -6, 0x0000, 2},
-    {0,  0, 0x4006, 2},
-    {0, -6, 0x0000, 2},
-    {0,  0, 0x0020, 2},
-    {0, -7, 0x0004, 2},
-    {0,  0, 0x0022, 2},
-    {0, -7, 0x0004, 2},
-    {0,  0, 0x4022, 2},
-    {0, -7, 0x0004, 2},
-    {0,  0, 0x0024, 2},
-    {0, -8, 0x0002, 2},
-    {0,  0, 0x000a, 2},
-    {0, -7, 0x0002, 2},
-    {0,  0, 0x000e, 2},
-    {0, -7, 0x0002, 2},
-    {0,  0, 0x000a, 2},
-    {0, -8, 0x4002, 2},
-    {0,  0, 0x400a, 2},
-    {0, -7, 0x4002, 2},
-    {0,  0, 0x400e, 2},
-    {0, -7, 0x4002, 2},
-    {0,  0, 0x400a, 2},
-  };
-  static const uint8 kThief_DrawChar[4] = {2, 2, 0, 4};
-  static const uint8 kThief_DrawFlags[4] = {0x40, 0, 0, 0};
-  PrepOamCoordsRet info;
-  Sprite_DrawMultiple(k, &kThief_Dmd[sprite_graphics[k] * 2], 2, &info);
-  if (!sprite_pause[k]) {
-    OamEnt *oam = GetOamCurPtr();
-    int j = sprite_head_dir[k];
-    oam->charnum = kThief_DrawChar[j];
-    oam->flags = (oam->flags & ~0x40) | kThief_DrawFlags[j];
-    SpriteDraw_Shadow(k, &info);
-  }
-}
-
-void Sprite_C3_Gibo(int k) {  // 9dcce1
-  if (sprite_B[k]) {
-    SpriteDraw_SingleLarge(k);
-    if (Sprite_ReturnIfInactive(k))
-      return;
-    Sprite_CheckDamageToAndFromLink(k);
-    sprite_oam_flags[k] = sprite_oam_flags[k] & 0x3f | kGibo_OamFlags[++sprite_subtype2[k] >> 2 & 3];
-    if (sprite_delay_main[k]) {
-      Sprite_MoveXY(k);
-      Sprite_BounceFromTileCollision(k);
-    }
-    return;
-  }
-  Gibo_Draw(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  sprite_anim_clock[k]++;
-  int j = sprite_head_dir[k], i;
-  if (sprite_state[j] == 6) {
-    sprite_state[k] = sprite_state[j];
-    sprite_delay_main[k] = sprite_delay_main[j];
-    sprite_flags2[k] += 4;
-    return;
-  }
-  sprite_subtype2[k] = frame_counter >> 3 & 3;
-  if (!(frame_counter & 63))
-    sprite_D[k] = Sprite_IsRightOfLink(k).a << 2;
-  Sprite_CheckDamageToLink(k);  // original destroys y which is a bug
-  switch(sprite_ai_state[k]) {
-  case 0:  // expel nucleus
-    if (sprite_delay_main[k] == 0) {
-      sprite_ai_state[k]++;
-      sprite_delay_main[k] = 48;
-      sprite_A[k]++;
-      SpriteSpawnInfo info;
-      j = Sprite_SpawnDynamically(k, 0xc3, &info);
-      if (j >= 0) {
-        static const int8 kGibo_Xvel[8] = {16, 16, 0, -16, -16, -16, 0, 16};
-        static const int8 kGibo_Yvel[8] = {0, 0, 16, -16, 16, 16, -16, -16};
-        Sprite_SetSpawnedCoordinates(j, &info);
-        sprite_head_dir[k] = j;
-        sprite_flags2[j] = 1;
-        sprite_B[j] = 1;
-        sprite_flags3[j] = 16;
-        sprite_health[j] = sprite_G[k];
-        sprite_oam_flags[j] = 7;
-        sprite_delay_main[j] = 48;
-        if (++sprite_C[k] == 3) {
-          sprite_C[k] = 0;
-          i = Sprite_DirectionToFaceLink(k, NULL);
-        } else {
-          i = GetRandomNumber() & 7;
-        }
-        sprite_x_vel[j] = kGibo_Xvel[i];
-        sprite_y_vel[j] = kGibo_Yvel[i];
-      }
-    } else if (sprite_delay_main[k] == 32) {
-      sprite_delay_aux1[k] = 32;
-    }
-    break;
-  case 1:  // delay pursuit
-    if (!sprite_delay_main[k])
-      sprite_ai_state[k]++;
-    break;
-  case 2:  // pursue nucleus
-    if (!((k ^ frame_counter) & 3)) {
-      uint16 x = Sprite_GetX(j), y = Sprite_GetY(j);
-      if ((uint16)(cur_sprite_x - x + 2) < 4 &&
-          (uint16)(cur_sprite_y - y + 2) < 4) {
-        j = sprite_head_dir[k];
-        sprite_state[j] = 0;
-        sprite_A[k] = 0;
-        sprite_ai_state[k] = 0;
-        sprite_G[k] = sprite_health[j];
-        sprite_delay_main[k] = (GetRandomNumber() & 31) + 32;
-        return;
-      }
-      ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLocation(k, x, y, 16);
-      sprite_x_vel[k] = pt.x;
-      sprite_y_vel[k] = pt.y;
-    }
-    Sprite_MoveXY(k);
-    break;
-  }
-}
-
-void Gibo_Draw(int k) {  // 9dcf5e
-  static const DrawMultipleData kGibo_Dmd[32] = {
-    { 4, -4, 0x408a, 2},
-    {-4, -4, 0x408f, 0},
-    {12, 12, 0x408e, 0},
-    {-4,  4, 0x408c, 2},
-    { 4, -4, 0x40aa, 2},
-    {-4, -4, 0x409f, 0},
-    {12, 12, 0x409e, 0},
-    {-4,  4, 0x40ac, 2},
-    { 3, -3, 0x40aa, 2},
-    {-3, -3, 0x409f, 0},
-    {11, 11, 0x409e, 0},
-    {-3,  3, 0x40ac, 2},
-    { 3, -3, 0x408a, 2},
-    {-3, -3, 0x408f, 0},
-    {11, 11, 0x408e, 0},
-    {-3,  3, 0x408c, 2},
-    {-3, -4, 0x008a, 2},
-    {13, -4, 0x008f, 0},
-    {-3, 12, 0x008e, 0},
-    { 5,  4, 0x008c, 2},
-    {-3, -4, 0x00aa, 2},
-    {13, -4, 0x009f, 0},
-    {-3, 12, 0x009e, 0},
-    { 5,  4, 0x00ac, 2},
-    {-2, -3, 0x00aa, 2},
-    {12, -3, 0x009f, 0},
-    {-2, 11, 0x009e, 0},
-    { 4,  3, 0x00ac, 2},
-    {-2, -3, 0x008a, 2},
-    {12, -3, 0x008f, 0},
-    {-2, 11, 0x008e, 0},
-    { 4,  3, 0x008c, 2},
-  };
-  if (!sprite_A[k]) {
-    uint8 bak0 = sprite_flags2[k];
-    sprite_flags2[k] = 1;
-    uint8 bak1 = sprite_oam_flags[k];
-    sprite_oam_flags[k] = kGibo_OamFlags[sprite_anim_clock[k] >> 2 & 3] |
-                          kGibo_OamFlags2[sprite_delay_aux1[k] >> 2 & 1];
-    SpriteDraw_SingleLarge(k);
-    sprite_oam_flags[k] = bak1;
-    sprite_flags2[k] = bak0;
-  }
-  oam_cur_ptr += 8;
-  oam_ext_cur_ptr += 2;
-  Sprite_DrawMultiple(k, &kGibo_Dmd[(sprite_subtype2[k] + sprite_D[k]) * 4], 4, NULL);
-}
-
-void Sprite_C2_Boulder(int k) {  // 9dcfcb
-  if (!player_is_indoors) {
-    Boulder_OutdoorsMain(k);
-    return;
-  }
-  if (byte_7E0FC6 < 3)
-    SpriteDraw_SingleSmall(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  sprite_oam_flags[k] = frame_counter << 2 & 0xc0;
-  Sprite_MoveXYZ(k);
-  if ((k ^ frame_counter) & 3)
-    return;
-  if ((uint16)(cur_sprite_x - link_x_coord + 4) < 16 && (uint16)(cur_sprite_y - link_y_coord - 4) < 12)
-    Sprite_AttemptDamageToLinkPlusRecoil(k);
-  if (!((k ^ frame_counter) & 3) && Sprite_CheckTileCollision(k))
-    sprite_state[k] = 0;
-}
-
-void Boulder_OutdoorsMain(int k) {  // 9dd02a
-  static const int8 kBoulder_Zvel[2] = {32, 48};
-  static const int8 kBoulder_Yvel[2] = {8, 32};
-  static const int8 kBoulder_Xvel[4] = {24, 16, -24, -16};
-  sprite_obj_prio[k] = 0x30;
-  Boulder_Draw(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  sprite_subtype2[k] -= sprite_D[k];
-  Sprite_CheckDamageToAndFromLink(k);
-  Sprite_MoveXYZ(k);
-  sprite_z_vel[k]-=2;
-  if (sign8(sprite_z[k])) {
-    sprite_z[k] = 0;
-    int j = Sprite_CheckTileCollision(k) != 0;
-    sprite_z_vel[k] = kBoulder_Zvel[j];
-    sprite_y_vel[k] = kBoulder_Yvel[j];
-    j += (GetRandomNumber() & 1) * 2;
-    sprite_x_vel[k] = kBoulder_Xvel[j];
-    sprite_D[k] = (j & 2) - 1;
-    SpriteSfx_QueueSfx2WithPan(k, 0xb);
-
-  }
-}
-
-void Boulder_Draw(int k) {  // 9dd185
-  static const DrawMultipleData kBoulder_Dmd[16] = {
-    {-8, -8, 0x01cc, 2},
-    { 8, -8, 0x01ce, 2},
-    {-8,  8, 0x01ec, 2},
-    { 8,  8, 0x01ee, 2},
-    {-8, -8, 0x41ce, 2},
-    { 8, -8, 0x41cc, 2},
-    {-8,  8, 0x41ee, 2},
-    { 8,  8, 0x41ec, 2},
-    {-8, -8, 0xc1ee, 2},
-    { 8, -8, 0xc1ec, 2},
-    {-8,  8, 0xc1ce, 2},
-    { 8,  8, 0xc1cc, 2},
-    {-8, -8, 0x81ec, 2},
-    { 8, -8, 0x81ee, 2},
-    {-8,  8, 0x81cc, 2},
-    { 8,  8, 0x81ce, 2},
-  };
-  PrepOamCoordsRet info;
-  Sprite_DrawMultiple(k, &kBoulder_Dmd[(sprite_subtype2[k] >> 3 & 3) * 4], 4, &info);
-  Sprite_DrawLargeShadow2(k);
-}
-
-void SpriteDraw_BigShadow(int k, int anim) {  // 9dd1a8
-  cur_sprite_y += sprite_z[k];
-  oam_cur_ptr += 16;
-  oam_ext_cur_ptr += 4;
-  Sprite_DrawMultiple(k, &kLargeShadow_Dmd[anim * 3], 3, NULL);
-  Sprite_Get16BitCoords(k);
-}
-
-void Sprite_DrawLargeShadow2(int k) {  // 9dd1af
-  int z = sprite_z[k] >> 3;
-  SpriteDraw_BigShadow(k, (z > 4) ? 4 : z);
-}
-
-void CutsceneAgahnim_SpawnZeldaOnAltar(int k) {  // 9dd1fd
-  sprite_x_lo[k] += 8;
-  sprite_y_lo[k] += 6;
-  SpriteSpawnInfo info;
-  int j = Sprite_SpawnDynamically(k, 0xc1, &info);
-  sprite_A[j] = 1;
-  sprite_ignore_projectile[j] = 1;
-  Sprite_SetSpawnedCoordinates(j, &info);
-  sprite_y_lo[j] = info.r2_y + 40;
-  sprite_flags2[j] = 0;
-  sprite_oam_flags[j] = 12;
-}
-
-void Sprite_C1_CutsceneAgahnim(int k) {  // 9dd234
-  switch (sprite_A[k]) {
-  case 0: CutsceneAgahnim_Agahnim(k); break;
-  case 1: Sprite_CutsceneAgahnim_Zelda(k); break;
-  }
-
-}
-
-void CutsceneAgahnim_Agahnim(int k) {  // 9dd23f
-  static const uint8 kChattyAgahnim_LevitateGfx[4] = {2, 0, 3, 0};
-  int j;
-  PrepOamCoordsRet info;
-
-  if (sprite_C[k]) {
-    if (!sprite_delay_main[k])
-      sprite_state[k] = 0;
-    if (!(sprite_delay_main[k] & 1))
-      ChattyAgahnim_Draw(k, &info);
-    return;
-  }
-  ChattyAgahnim_Draw(k, &info);
-  SpriteDraw_CutsceneAgahnimSpell(k, &info);
-  if (sprite_pause[k]) {
-    sprite_ai_state[k] = 0;
-    sprite_B[k] = 0;
-    sprite_graphics[k] = 0;
-    sprite_delay_main[k] = 64;
-  }
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  switch(sprite_ai_state[k]) {
-  case 0:  // problab
-    if (!sprite_delay_main[k]) {
-      flag_is_link_immobilized = 1;
-      dialogue_message_index = 0x13d;
-      Sprite_ShowMessageMinimal();
-      sprite_ai_state[k]++;
-    }
-    break;
-  case 1:  // levitate zelda
-    j = ++sprite_B[k];
-    sprite_graphics[k] = sprite_z[15] < 16 ? kChattyAgahnim_LevitateGfx[j >> 5 & 3] : 1;
-    if ((j & 15) == 0) {
-      sprite_graphics[15] = 1;
-      if (++sprite_z[15] == 22) {
-        sound_effect_2 = 0x27;
-        sprite_ai_state[k]++;
-        sprite_delay_main[k] = 255;
-        sprite_subtype2[k] = 2;
-        sprite_subtype[k] = 255;
-      }
-    }
-    break;
-  case 2:  // do telewarp
-    if (!sprite_delay_main[k]) {
-      sprite_ai_state[k]++;
-      sprite_delay_main[k] = 80;
-    } else if (sprite_delay_main[k] == 120) {
-      intro_times_pal_flash = 120;
-    } else if (sprite_delay_main[k] < 128 && (sprite_delay_main[k] & 3) == 0) {
-      sound_effect_2 = 0x2b;
-      if (sprite_subtype2[k] != 14)
-        sprite_subtype2[k] += 4;
-    }
-    break;
-  case 3:  // complete telewarp
-    if (sprite_delay_main[k]) {
-      if (!(sprite_delay_main[k] & 3) && sprite_subtype[k] != 9)
-        sprite_subtype[k] += 2;
-    } else {
-      sprite_delay_main[15] = 19;
-      sprite_ai_state[k]++;
-      sprite_delay_main[k] = 80;
-      sprite_subtype2[k] = 0;
-      sound_effect_1 = 0x33;
-    }
-    break;
-  case 4:  // epiblab
-    if (!sprite_delay_main[k]) {
-      dialogue_message_index = 0x13e;
-      Sprite_ShowMessageMinimal();
-      sprite_ai_state[k]++;
-      sprite_delay_main[k] = 2;
-    }
-    break;
-  case 5:  // teleport to curtains
-    if (sprite_delay_main[k] == 1)
-      sound_effect_2 = 0x28;
-    sprite_y_vel[k] = -32;
-    Sprite_MoveY(k);
-    if (sprite_y_lo[k] < 48) {
-      sprite_delay_aux4[k] = 66;
-      sprite_ai_state[k]++;
-    }
-    Sprite_Agahnim_ApplyMotionBlur(k);
-    break;
-  case 6:  // linger then terminate
-    if (!sprite_delay_aux4[k]) {
-      flag_is_link_immobilized = 0;
-      sprite_state[k] = 0;
-      Sprite_ManuallySetDeathFlagUW(k);
-      dung_savegame_state_bits |= 0x4000;
-    }
-    break;
-  }
-}
-
-int Sprite_Agahnim_ApplyMotionBlur(int k) {  // 9dd392
-  if (frame_counter & 3)
-    return -1;
-  SpriteSpawnInfo info;
-  int j = Sprite_SpawnDynamically(k, 0xc1, &info);
-  if (j >= 0) {
-    Sprite_SetSpawnedCoordinates(j, &info);
-    sprite_graphics[j] = sprite_graphics[k];
-    sprite_delay_main[j] = 32;
-    sprite_ignore_projectile[j] = 32;
-    sprite_C[j] = 32;
-  }
-  return j;
-}
-
-void ChattyAgahnim_Draw(int k, PrepOamCoordsRet *info) {  // 9dd451
-  static const DrawMultipleData kChattyAgahnim_Dmd[16] = {
-    {-8, -8, 0x0b82, 2},
-    { 8, -8, 0x4b82, 2},
-    {-8,  8, 0x0ba2, 2},
-    { 8,  8, 0x4ba2, 2},
-    {-8, -8, 0x0b80, 2},
-    { 8, -8, 0x4b80, 2},
-    {-8,  8, 0x0ba0, 2},
-    { 8,  8, 0x4ba0, 2},
-    {-8, -8, 0x0b80, 2},
-    { 8, -8, 0x4b82, 2},
-    {-8,  8, 0x0ba0, 2},
-    { 8,  8, 0x4ba2, 2},
-    {-8, -8, 0x0b82, 2},
-    { 8, -8, 0x4b80, 2},
-    {-8,  8, 0x0ba2, 2},
-    { 8,  8, 0x4ba0, 2},
-  };
-  if (sprite_delay_aux4[k] & 1)
-    return;
-
-  if (sprite_C[k] == 0) {
-    oam_cur_ptr = 0x900;
-    oam_ext_cur_ptr = 0xa60;
-  }
-  Sprite_DrawMultiple(k, &kChattyAgahnim_Dmd[sprite_graphics[k] * 4], 4, info);
-  SpriteDraw_Shadow_custom(k, info, 18);
-}
-
-void SpriteDraw_CutsceneAgahnimSpell(int k, PrepOamCoordsRet *info) {  // 9dd516
-  static const OamEntSigned kChattyAgahnim_Telewarp_Data[28] = {
-    {-10, -16, 0xce, 0x06},
-    { 18, -16, 0xce, 0x06},
-    { 20, -13, 0x26, 0x06},
-    { 20,  -5, 0x36, 0x06},
-    {-12, -13, 0x26, 0x46},
-    {-12,  -5, 0x36, 0x46},
-    { 18,   0, 0x26, 0x06},
-    { 18,   8, 0x36, 0x06},
-    {-10,   0, 0x26, 0x46},
-    {-10,   8, 0x36, 0x46},
-    { -8,   0, 0x22, 0x06},
-    {  8,   0, 0x22, 0x46},
-    { -8,  16, 0x22, 0x86},
-    {  8,  16, 0x22, 0xc6},
-    {-10, -16, 0xce, 0x04},
-    { 18, -16, 0xce, 0x04},
-    { 20, -13, 0x26, 0x44},
-    { 20,  -5, 0x36, 0x44},
-    {-12, -13, 0x26, 0x04},
-    {-12,  -5, 0x36, 0x04},
-    { 18,   0, 0x26, 0x44},
-    { 18,   8, 0x36, 0x44},
-    {-10,   0, 0x26, 0x04},
-    {-10,   8, 0x36, 0x04},
-    { -8,   0, 0x20, 0x04},
-    {  8,   0, 0x20, 0x44},
-    { -8,  16, 0x20, 0x84},
-    {  8,  16, 0x20, 0xc4},
-  };
-  static const uint8 kChattyAgahnim_Telewarp_Data_Big[14] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2};
-  Oam_AllocateFromRegionA(0x38);
-  const OamEntSigned *data = kChattyAgahnim_Telewarp_Data;
-  if (!(frame_counter & 2))
-    data += 14;
-  const uint8 *bigp = kChattyAgahnim_Telewarp_Data_Big;
-  if (!sprite_subtype2[k])
-    return;
-  OamEnt *oam = GetOamCurPtr();
-  uint8 kn = sprite_subtype2[k] - 1;
-  uint8 end = sprite_subtype[k];
-  uint8 t = end + 1;
-  oam += t;
-  bigp += t;
-  data += t;
-  do {
-    SetOamPlain(oam, info->x + data->x, info->y + data->y - 8, data->charnum, data->flags | 0x31, *bigp);
-  } while (data++, bigp++, oam++, --kn != end);
-}
-
-void Sprite_CutsceneAgahnim_Zelda(int k) {  // 9dd57d
-  static const DrawMultipleData kAltarZelda_Dmd[4] = {
-    {-4, 0, 0x0103, 2},
-    { 4, 0, 0x0104, 2},
-    {-4, 0, 0x0100, 2},
-    { 4, 0, 0x0101, 2},
-  };
-  int j = sprite_delay_main[k];
-  if (j != 0) {
-    SpriteDraw_AltarZeldaWarp(k);
-    if (j == 1)
-      sprite_state[k] = 0;
-    if (j < 12)
-      return;
-  }
-  Oam_AllocateFromRegionA(8);
-  PrepOamCoordsRet info;
-  Sprite_DrawMultiple(k, &kAltarZelda_Dmd[sprite_graphics[k] * 2], 2, &info);
-  AltarZelda_DrawBody(k, &info);
-}
-
-void AltarZelda_DrawBody(int k, PrepOamCoordsRet *info) {  // 9dd5e9
-  static const uint8 kAltarZelda_XOffs[16] = {4, 4, 3, 3, 2, 2, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0};
-  Oam_AllocateFromRegionA(8);
-  int z = sprite_z[k] < 31 ? sprite_z[k] : 31;
-  uint8 xoffs = kAltarZelda_XOffs[z >> 1];
-  int y = Sprite_GetY(k) - BG2VOFS_copy2;
-  OamEnt *oam = GetOamCurPtr();
-  SetOamHelper0(oam + 0, info->x + xoffs, y + 7, 0x6c, 0x24, 2);
-  SetOamHelper0(oam + 1, info->x - xoffs, y + 7, 0x6c, 0x24, 2);
-}
-
-void SpriteDraw_AltarZeldaWarp(int k) {  // 9dd6b1
-  static const DrawMultipleData kAltarZelda_Warp_Dmd[10] = {
-    { 4, 4, 0x0480, 0},
-    { 4, 4, 0x0480, 0},
-    { 4, 4, 0x04b7, 0},
-    { 4, 4, 0x04b7, 0},
-    {-6, 0, 0x0524, 2},
-    { 6, 0, 0x4524, 2},
-    {-8, 0, 0x0524, 2},
-    { 8, 0, 0x4524, 2},
-    { 0, 0, 0x05c6, 2},
-    { 0, 0, 0x05c6, 2},
-  };
-  Oam_AllocateFromRegionA(8);
-  Sprite_DrawMultiple(k, &kAltarZelda_Warp_Dmd[(sprite_delay_main[k] >> 2) * 2], 2, NULL);
-}
-
-void Sprite_InitializedSegmented(int k) {  // 9dd6d1
-  for (int i = 0; i < 128; i++) {
-    moldorm_x_lo[i] = sprite_x_lo[k];
-    moldorm_x_hi[i] = sprite_x_hi[k];
-    moldorm_y_lo[i] = sprite_y_lo[k];
-    moldorm_y_hi[i] = sprite_y_hi[k];
-  }
-}
-
-void GiantMoldorm_Draw(int k) {  // 9dd881
-  PrepOamCoordsRet info;
-  if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
-    return;
-  sprite_oam_flags[k] = 11;
-  SpriteDraw_Moldorm_Eyeballs(k, &info);
-  oam_cur_ptr += 8, oam_ext_cur_ptr += 2;
-
-  int j = sprite_subtype2[k] & 0x7f;
-  moldorm_x_lo[j] = sprite_x_lo[k];
-  moldorm_x_hi[j] = sprite_x_hi[k];
-  moldorm_y_lo[j] = sprite_y_lo[k];
-  moldorm_y_hi[j] = sprite_y_hi[k];
-
-  SpriteDraw_Moldorm_Head(k);
-  if (sprite_B[k] < 4) {
-    GiantMoldorm_DrawSegment_AB(k, 16);
-    if (sprite_B[k] < 3) {
-      GiantMoldorm_DrawSegment_AB(k, 28);
-      if (sprite_B[k] < 2) {
-        SpriteDraw_Moldorm_SegmentC(k);
-        if (sprite_B[k] == 0)
-          Moldorm_HandleTail(k);
-      }
-    }
-  }
-  GiantMoldorm_IncrementalSegmentExplosion(k);
-  Sprite_Get16BitCoords(k);
-}
-
-void GiantMoldorm_IncrementalSegmentExplosion(int k) {  // 9dd8f2
-  if (sprite_state[k] == 9 && sprite_delay_aux4[k] && sprite_delay_aux4[k] < 80 &&
-      !(sprite_delay_aux4[k] & 15 | submodule_index | flag_unk1)) {
-    sprite_B[k]++;
-    Sprite_MakeBossExplosion(k);
-  }
-}
-
-void SpriteDraw_Moldorm_Head(int k) {  // 9dd993
-  static const DrawMultipleData kGiantMoldorm_Head_Dmd[16] = {
-    {-8, -8, 0x0080, 2},
-    { 8, -8, 0x0082, 2},
-    {-8,  8, 0x00a0, 2},
-    { 8,  8, 0x00a2, 2},
-    {-8, -8, 0x4082, 2},
-    { 8, -8, 0x4080, 2},
-    {-8,  8, 0x40a2, 2},
-    { 8,  8, 0x40a0, 2},
-    {-6, -6, 0x0080, 2},
-    { 6, -6, 0x0082, 2},
-    {-6,  6, 0x00a0, 2},
-    { 6,  6, 0x00a2, 2},
-    {-6, -6, 0x4082, 2},
-    { 6, -6, 0x4080, 2},
-    {-6,  6, 0x40a2, 2},
-    { 6,  6, 0x40a0, 2},
-  };
-  int t = (sprite_subtype2[k] >> 1 & 1) + (sprite_delay_aux1[k] & 2);
-  Sprite_DrawMultiple(k, &kGiantMoldorm_Head_Dmd[t * 4], 4, NULL);
-}
-
-void SpriteDraw_Moldorm_SegmentC(int k) {  // 9dda5f
-  sprite_graphics[k] = 0;
-  oam_cur_ptr += 0x10;
-  oam_ext_cur_ptr += 4;
-  GiantMoldorm_DrawSegment_C_OrTail(k, 0x28);
-}
-
-void Moldorm_HandleTail(int k) {  // 9ddaba
-  SpriteDraw_Moldorm_Tail(k);
-  if (!sprite_delay_aux2[k]) {
-    sprite_A[k] = 1;
-    sprite_flags4[k] = 0;
-    sprite_defl_bits[k] = 0;
-    uint16 oldx = Sprite_GetX(k);
-    uint16 oldy = Sprite_GetY(k);
-    Sprite_SetX(k, cur_sprite_x);
-    Sprite_SetY(k, cur_sprite_y);
-    Sprite_CheckDamageFromLink(k);
-    sprite_A[k] = 0;
-    sprite_flags4[k] = 9;
-    sprite_defl_bits[k] = 4;
-    Sprite_SetX(k, oldx);
-    Sprite_SetY(k, oldy);
-  }
-}
-
-void SpriteDraw_Moldorm_Tail(int k) {  // 9ddb17
-  oam_cur_ptr += 4;
-  oam_ext_cur_ptr += 1;
-  sprite_graphics[k]++;
-  sprite_oam_flags[k] = 13;
-  GiantMoldorm_DrawSegment_C_OrTail(k, 0x30);
-}
-
-void SpriteDraw_Moldorm_Eyeballs(int k, PrepOamCoordsRet *info) {  // 9ddb9e
-  static const int16 kGiantMoldorm_Eye_X[16] = {16, 15, 12, 6, 0, -6, -12, -13, -16, -13, -12, -6, 0, 6, 12, 15};
-  static const int16 kGiantMoldorm_Eye_Y[16] = {0, 6, 12, 15, 16, 15, 12, 6, 0, -6, -12, -13, -16, -13, -12, -6};
-  static const uint8 kGiantMoldorm_Eye_Char[16] = {0xaa, 0xaa, 0xa8, 0xa8, 0x8a, 0x8a, 0xa8, 0xa8, 0xaa, 0xaa, 0xa8, 0xa8, 0x8a, 0x8a, 0xa8, 0xa8};
-  static const uint8 kGiantMoldorm_Eye_Flags[16] = {0, 0, 0, 0, 0x80, 0x80, 0x40, 0x40, 0x40, 0x40, 0xc0, 0xc0, 0, 0, 0x80, 0x80};
-  OamEnt *oam = GetOamCurPtr();
-  int r7 = sprite_F[k] ? frame_counter : 0;
-  int r6 = sprite_D[k] - 1;
-  for (int i = 1; i >= 0; i--, oam++, r6 += 2) {
-    uint16 x = info->x + kGiantMoldorm_Eye_X[r6 & 0xf];
-    uint16 y = info->y + kGiantMoldorm_Eye_Y[r6 & 0xf];
-    SetOamHelper0(oam, x, y, kGiantMoldorm_Eye_Char[(r6 + r7) & 0xf], info->flags | kGiantMoldorm_Eye_Flags[(r6 + r7) & 0xf], 2);
-  }
-}
-
-void Sprite_ScheduleBossForDeath(int k) {  // 9ddc16
-  sprite_state[k] = 4;
-  sprite_A[k] = 0;
-  sprite_delay_main[k] = 224;
-}
-
-void Sprite_MakeBossExplosion(int k) {  // 9ddc2a
-  SpriteSfx_QueueSfx2WithPan(k, 0xc);
-  Sprite_MakeBossDeathExplosion_NoSound(k);
-}
-
-void Sprite_MakeBossDeathExplosion_NoSound(int k) {  // 9ddc30
-  SpriteSpawnInfo info;
-  int j = Sprite_SpawnDynamically(k, 0x00, &info);
-  if (j >= 0) {
-    load_chr_halfslot_even_odd = 11;
-    sprite_state[j] = 4;
-    sprite_flags2[j] = 3;
-    sprite_oam_flags[j] = 12;
-    Sprite_SetX(j, cur_sprite_x);
-    Sprite_SetY(j, cur_sprite_y);
-    sprite_delay_main[j] = 31;
-    sprite_A[j] = 31;
-    sprite_floor[j] = 2;
-  }
-}
-
-void Vulture_Draw(int k) {  // 9ddd5e
-  static const DrawMultipleData kVulture_Dmd[8] = {
-    {-8, 0, 0x0086, 2},
-    { 8, 0, 0x4086, 2},
-    {-8, 0, 0x0080, 2},
-    { 8, 0, 0x4080, 2},
-    {-8, 0, 0x0082, 2},
-    { 8, 0, 0x4082, 2},
-    {-8, 0, 0x0084, 2},
-    { 8, 0, 0x4084, 2},
-  };
-  PrepOamCoordsRet info;
-  Sprite_DrawMultiple(k, &kVulture_Dmd[sprite_graphics[k] * 2], 2, &info);
-  SpriteDraw_Shadow(k, &info);
-
-}
-
-void Sprite_Raven(int k) {  // 9ddd85
-  static const uint8 kRaven_AscendTime[2] = {16, 248};
-  int j;
-  bool fleeing = false;
-  sprite_obj_prio[k] |= 0x30;
-  SpriteDraw_SingleLarge(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  if (Sprite_ReturnIfRecoiling(k))
-    return;
-  Sprite_CheckDamageToAndFromLink(k);
-  Sprite_MoveXY(k);
-  switch (sprite_ai_state[k]) {
-  case 0: { // inwait
-    PairU8 r = Sprite_IsRightOfLink(k);
-    sprite_oam_flags[k] = sprite_oam_flags[k] & ~0x40 | r.a * 0x40;
-    int x = link_x_coord - cur_sprite_x;
-    int y = link_y_coord - cur_sprite_y;
-    if ((uint16)(x + 0x50 + (x >= 0)) < 0xa0 && (uint16)(y + 0x58 + (y >= 0)) < 0xa0) {
-      sprite_ai_state[k]++;
-      sprite_delay_main[k] = 24;
-      SpriteSfx_QueueSfx3WithPan(k, 0x1e);
-    }
-    break;
-  }
-  case 1:  // ascend
-    if (!sprite_delay_main[k]) {
-      sprite_ai_state[k]++;
-      int j = sprite_A[k];
-      sprite_delay_main[k] = kRaven_AscendTime[j];
-      Sprite_ApplySpeedTowardsLink(k, 32);
-    }
-    sprite_z[k]++;
-    sprite_graphics[k] = (frame_counter >> 1 & 1) + 1;
-    break;
-  case 2:  // attack
-    if (!sprite_delay_main[k] && !(is_in_dark_world && sprite_A[k]) )
-      sprite_ai_state[k]++;
-fly:
-    if (!((k ^ frame_counter) & 1)) {
-      ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLink(k, fleeing ? 48 : 32);
-      if (fleeing)
-        pt.x = -pt.x, pt.y = -pt.y;
-      if (sprite_x_vel[k] - pt.x)
-        sprite_x_vel[k] += sign8(sprite_x_vel[k] - pt.x) ? 1 : -1;
-      if (sprite_y_vel[k] - pt.y)
-        sprite_y_vel[k] += sign8(sprite_y_vel[k] - pt.y) ? 1 : -1;
-    }
-    sprite_graphics[k] = (frame_counter >> 1 & 1) + 1;
-    j = (sprite_x_vel[k] >> 7) & 1;
-    sprite_oam_flags[k] = sprite_oam_flags[k] & ~0x40 | j * 0x40;
-    break;
-  case 3:  // flee
-    fleeing = true;
-    goto fly;
-  }
-}
-
-void Vitreous_SpawnSmallerEyes(int k) {  // 9ddecb
-  sprite_G[k] = 9;
-  sprite_graphics[k] = 4;
-
-  SpriteSpawnInfo info;
-  int j = Sprite_SpawnDynamicallyEx(k, 0x4, &info, 13);
-
-  static const int8 kVitreous_SpawnSmallerEyes_X[13] = {8, 22, -8, -22, 0, 14, 19, 33, 26, -14, -19, -33, -26};
-  static const int8 kVitreous_SpawnSmallerEyes_Y[13] = {-8, -12, -8, -12, 0, -20, -1, -12, -24, -20, -1, -12, -24};
-  static const int8 kVitreous_SpawnSmallerEyes_Gfx[13] = {1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0};
-
-  for (j = 13; j != 0; j--) {
-    sprite_state[j] = 9;
-    sprite_type[j] = 0xbe;
-    SpritePrep_LoadProperties(j);
-    sprite_floor[j] = 0;
-    Sprite_SetX(j, info.r0_x + kVitreous_SpawnSmallerEyes_X[j - 1]);
-    Sprite_SetY(j, info.r2_y + kVitreous_SpawnSmallerEyes_Y[j - 1] + 32);
-    sprite_A[j] = sprite_x_lo[j];
-    sprite_B[j] = sprite_x_hi[j];
-    sprite_C[j] = sprite_y_lo[j];
-    sprite_D[j] = sprite_y_hi[j];
-    sprite_ignore_projectile[j] = sprite_graphics[j] = kVitreous_SpawnSmallerEyes_Gfx[j - 1];
-    sprite_subtype2[j] = (j - 1) * 8 + GetRandomNumber();
-  }
-}
-
-void Sprite_C0_Catfish(int k) {  // 9ddf49
-  if (sprite_A[k] & 0x80)
-    Sprite_Catfish_SplashOfWater(k);
-  else if (sprite_A[k] == 0)
-    Catfish_BigFish(k);
-  else
-    Sprite_Catfish_QuakeMedallion(k);
-}
-
-void Sprite_Catfish_QuakeMedallion(int k) {  // 9ddf54
-  if (!sprite_z[k]) {
-    SpriteDraw_WaterRipple_WithOamAdjust(k);
-    if (!submodule_index && Sprite_CheckDamageToLink_same_layer(k)) {
-      sprite_state[k] = 0;
-      item_receipt_method = 0;
-      Link_ReceiveItem(sprite_A[k], 0);
-    }
-  }
-  if (sprite_delay_aux3[k])
-    Oam_AllocateFromRegionC(8);
-  SpriteDraw_SingleLarge(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  Sprite_MoveXYZ(k);
-  sprite_z_vel[k] -= 2;
-  if (sign8(sprite_z[k])) {
-    sprite_z[k] = 0;
-    sprite_x_vel[k] = (int8)sprite_x_vel[k] >> 1;
-    sprite_y_vel[k] = (int8)sprite_y_vel[k] >> 1;
-    int j = sprite_ai_state[k];
-    if (j == 4) {
-      sprite_x_vel[k] = 0;
-      sprite_y_vel[k] = 0;
-      sprite_z_vel[k] = 0;
-    } else {
-      sprite_ai_state[k]++;
-      static const uint8 kStandaloneItem_Zvel[4] = {0x20, 0x10, 8, 0};
-      sprite_z_vel[k] = kStandaloneItem_Zvel[j];
-      if (j < 2 && (j = Sprite_SpawnWaterSplash(k)) >= 0)
-        sprite_delay_main[j] = 16;
-    }
-  }
-}
-
-void Catfish_BigFish(int k) {  // 9ddfd1
-  GreatCatfish_Draw(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  switch(sprite_ai_state[k]) {
-  case 0:  // AwaitSpriteThrownInCircle
-    for (int j = 15; j >= 0; j--) {
-      if (j == k || sprite_state[j] != 3)
-        continue;
-      if ((uint16)(cur_sprite_x - Sprite_GetX(j) + 32) < 64 && (uint16)(cur_sprite_y - Sprite_GetY(j) + 32) < 64) {
-        sprite_ai_state[k] = 1;
-        sprite_delay_main[k] = 255;
-        return;
-      }
-    }
-    break;
-  case 1: { // RumbleBeforeEmergence
-    int j = sprite_delay_main[k];
-    if (!sprite_delay_main[k]) {
-      sprite_ai_state[k] = 2;
-      sprite_delay_main[k] = 255;
-      bg1_x_offset = 0;
-      sound_effect_ambient = 5;
-      sprite_z_vel[k] = 48;
-      sprite_x_vel[k] = 0;
-      Catfish_SpawnPlop(k);
-    } else if (sprite_delay_main[k] < 0xc0) {
-      if (sprite_delay_main[k] == 0xbf)
-        sound_effect_ambient = 7;
-      bg1_x_offset = (j & 1) ? -1 : 1;
-      flag_is_link_immobilized = 1;
-    }
-    break;
-  }
-  case 2: { // Emerge
-    static const uint8 kGreatCatfish_Emerge_Gfx[16] = {1, 2, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 0, 0, 0, 0};
-    sprite_subtype2[k]++;
-    Sprite_MoveXYZ(k);
-    sprite_z_vel[k] -= 2;
-    if (sprite_z_vel[k] == (uint8)(-48))
-      Catfish_SpawnPlop(k);
-    if (sign8(sprite_z[k])) {
-      sprite_z[k] = 0;
-      sprite_ai_state[k]++;
-      sprite_delay_main[k] = 255;
-    }
-    sprite_graphics[k] = kGreatCatfish_Emerge_Gfx[sprite_subtype2[k] >> 2];
-    break;
-  }
-  case 3: { // ConversateThenSubmerge
-    int j = sprite_delay_main[k];
-    static const uint8 kGreatCatfish_Conversate_Gfx[20] = { 0, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 6, 6 };
-    if (j == 0) {
-      sprite_state[k] = 0;
-    } else {
-      if (j == 160 || j == 252 || j == 4) {
-        Sprite_SpawnWaterSplash(k);
-      } else if (j == 10) {
-        Catfish_SpawnPlop(k);
-      } else if (j == 96) {
-        flag_is_link_immobilized = 0;
-        dialogue_message_index = link_item_quake_medallion ? 0x12b : 0x12a;
-        Sprite_ShowMessageMinimal();
-        return;
-      } else if (j == 80) {
-        if (link_item_quake_medallion) {
-          if (GetRandomNumber() & 1)
-            Sprite_SpawnBomb(k);
-          else
-            Sprite_SpawnFireball(k);
-        } else {
-          Catfish_RegurgitateMedallion(k);
-        }
-      }
-      if (j < 160)
-        sprite_graphics[k] = kGreatCatfish_Conversate_Gfx[j >> 3];
-    }
-    break;
-  }
-  }
-}
-
-int Sprite_SpawnBomb(int k) {  // 9de144
-  SpriteSpawnInfo info;
-  int j = Sprite_SpawnDynamically(k, 0x4a, &info);
-  if (j >= 0) {
-    Sprite_SetSpawnedCoordinates(j, &info);
-    Sprite_TransmuteToBomb(j);
-    sprite_delay_aux1[j] = 80;
-    sprite_x_vel[j] = 24;
-    sprite_z_vel[j] = 48;
-  }
-  return j;
-}
-
-void Catfish_RegurgitateMedallion(int k) {  // 9de16c
-  SpriteSpawnInfo info;
-  int j = Sprite_SpawnDynamically(k, 0xc0, &info);
-  if (j >= 0) {
-    Sprite_SetSpawnedCoordinates(j, &info);
-    sprite_x_vel[j] = 24;
-    sprite_z_vel[j] = 48;
-    sprite_A[j] = 17;
-    SpriteSfx_QueueSfx2WithPan(j, 0x20);
-    sprite_flags2[j] = 0x83;
-    sprite_flags3[j] = 0x58;
-    sprite_oam_flags[j] = 0x58 & 0xf;
-    DecodeAnimatedSpriteTile_variable(0x1c);
-  }
-}
-
-void Sprite_Zora_RegurgitateFlippers(int k) {  // 9de1aa
-  SpriteSpawnInfo info;
-  int j = Sprite_SpawnDynamically(k, 0xc0, &info);
-  if (j < 0)
-    return;
-  Sprite_SetSpawnedCoordinates(j, &info);
-  sprite_z_vel[j] = 32;
-  sprite_y_vel[j] = 16;
-  sprite_A[j] = 30;
-  SpriteSfx_QueueSfx2WithPan(j, 0x20);
-  sprite_flags2[j] = 0x83;
-  sprite_flags3[j] = 0x54;
-  sprite_oam_flags[j] = 0x54 & 15;
-  sprite_delay_aux3[j] = 0x30;
-  DecodeAnimatedSpriteTile_variable(0x11);
-}
-
-void Catfish_SpawnPlop(int k) {  // 9de1ed
-  SpriteSpawnInfo info;
-  int j = Sprite_SpawnDynamically(k, 0xec, &info);
-  if (j >= 0) {
-    Sprite_SetSpawnedCoordinates(j, &info);
-    sprite_state[j] = 3;
-    sprite_delay_main[j] = 15;
-    sprite_ai_state[j] = 0;
-    sprite_flags2[j] = 3;
-    SpriteSfx_QueueSfx2WithPan(k, 0x28);
-  }
-}
-
-int Sprite_SpawnWaterSplash(int k) {  // 9de21c
-  SpriteSpawnInfo info;
-  int j = Sprite_SpawnDynamically(k, 0xc0, &info);
-  if (j >= 0) {
-    Sprite_SetSpawnedCoordinates(j, &info);
-    sprite_A[j] = 0x80;
-    sprite_flags2[j] = 2;
-    sprite_ignore_projectile[j] = 2;
-    sprite_oam_flags[j] = 4;
-    sprite_delay_main[j] = 31;
-  }
-  return j;
-}
-
-void GreatCatfish_Draw(int k) {  // 9de320
-  static const DrawMultipleData kGreatCatfish_Dmd[28] = {
-    {-4,  4, 0x008c, 2},
-    { 4,  4, 0x008d, 2},
-    {-4,  4, 0x008c, 2},
-    { 4,  4, 0x008d, 2},
-    {-4, -4, 0x008c, 2},
-    { 4, -4, 0x008d, 2},
-    {-4,  4, 0x009c, 2},
-    { 4,  4, 0x009d, 2},
-    {-4, -4, 0x408d, 2},
-    { 4, -4, 0x408c, 2},
-    {-4,  4, 0x409d, 2},
-    { 4,  4, 0x409c, 2},
-    {-4, -4, 0xc09d, 2},
-    { 4, -4, 0xc09c, 2},
-    {-4,  4, 0xc08d, 2},
-    { 4,  4, 0xc08c, 2},
-    {-4,  4, 0xc09d, 2},
-    { 4,  4, 0xc09c, 2},
-    {-4,  4, 0xc09d, 2},
-    { 4,  4, 0xc09c, 2},
-    { 0,  8, 0x00bd, 0},
-    { 8,  8, 0x40bd, 0},
-    { 8,  8, 0x40bd, 0},
-    { 8,  8, 0x40bd, 0},
-    {-8,  0, 0x0086, 2},
-    { 8,  0, 0x4086, 2},
-    { 8,  0, 0x4086, 2},
-    { 8,  0, 0x4086, 2},
-  };
-  if (sprite_graphics[k])
-    Sprite_DrawMultiple(k, &kGreatCatfish_Dmd[(sprite_graphics[k] - 1) * 4], 4, NULL);
-}
-
-void Sprite_Catfish_SplashOfWater(int k) {  // 9de37d
-  static const DrawMultipleData kWaterSplash_Dmd[8] = {
-    {-8, -4, 0x0080, 0},
-    {18, -7, 0x0080, 0},
-    {-5, -2, 0x00bf, 0},
-    {15, -4, 0x40af, 0},
-    { 0, -4, 0x00e7, 2},
-    { 0, -4, 0x00e7, 2},
-    { 0, -4, 0x00c0, 2},
-    { 0, -4, 0x00c0, 2},
-  };
-  if (!sprite_delay_main[k])
-    sprite_state[k] = 0;
-  Sprite_DrawMultiple(k, &kWaterSplash_Dmd[(sprite_delay_main[k] >> 3) * 2], 2, NULL);
-}
-
-void Sprite_BF_Lightning(int k) {  // 9de3ed
-  static const uint8 kSpriteLightning_Gfx[8] = {0, 1, 2, 3, 0, 1, 2, 3};
-  static const uint8 kSpriteLightning_OamFlags[8] = {0, 0, 0, 0, 0x40, 0x40, 0x40, 0x40};
-  static const int8 kSpriteLightning_Xoff[64] = {
-    -15,  0,  0, -15,  0, -15, -15,  0, -15,  0,  0, -15,  0, -15, -15,  0,
-    0, 15, 15,   0, 15,   0,   0, 15,   0, 15, 15,   0, 15,   0,   0, 15,
-    0, 15, 15,   0, 15,   0,   0, 15,   0, 15, 15,   0, 15,   0,   0, 15,
-    -15,  0,  0, -15,  0, -15, -15,  0, -15,  0,  0, -15,  0, -15, -15,  0,
-  };
-  int j = sprite_A[k];
-  sprite_oam_flags[k] = sprite_oam_flags[k] & 0xb1 | kSpriteLightning_OamFlags[j] | frame_counter << 1 & 14;
-  sprite_graphics[k] = kSpriteLightning_Gfx[j] + (BYTE(dungeon_room_index2) == 0x20 ? 4 : 0);
-  SpriteDraw_SingleLarge(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  if (sprite_delay_main[k])
-    return;
-  Lightning_SpawnGarnish(k);
-  sprite_delay_main[k] = 2;
-  Sprite_SetY(k, Sprite_GetY(k) + 16);
-  if ((uint8)(sprite_y_lo[k] - BG2VOFS_copy2) >= 0xd0) {
-    sprite_state[k] = 0;
-    return;
-  }
-  int rr = GetRandomNumber() & 7;
-  Sprite_SetX(k, Sprite_GetX(k) + kSpriteLightning_Xoff[sprite_A[k] << 3 | rr]);
-  sprite_A[k] = rr;
-}
-
-void Lightning_SpawnGarnish(int k) {  // 9de475
-  int j = GarnishAllocOverwriteOld();
-  garnish_type[j] = 9;
-  garnish_active = 9;
-  garnish_sprite[j] = sprite_A[k];
-  garnish_x_lo[j] = sprite_x_lo[k];
-  garnish_x_hi[j] = sprite_x_hi[k];
-  int y = Sprite_GetY(k) + 16;
-  garnish_y_lo[j] = y;
-  garnish_y_hi[j] = y >> 8;
-  garnish_countdown[j] = 32;
-}
-
-void Sprite_BD_Vitreous(int k) {  // 9de4c8
-  if (sprite_delay_aux4[k])
-    sprite_graphics[k] = 3;
-  Vitreous_Draw(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  Vitreous_SetMinionsForth(k);
-  Sprite_CheckDamageToAndFromLink(k);
-  switch(sprite_ai_state[k]) {
-  case 0:  // dormant
-    byte_7E0FF8 = 0;
-    sprite_F[k] = 0;
-    sprite_flags3[k] |= 64;
-    if (!(frame_counter & 1) && !--sprite_A[k]) {
-      sprite_flags3[k] &= ~0x40;
-      sprite_delay_aux4[k] = 16;
-      sprite_ai_state[k] = 1;
-      sprite_delay_main[k] = 128;
-      if (!sprite_G[k]) {
-        sprite_ai_state[k] = 2;
-        sprite_delay_main[k] = 64;
-        sprite_ignore_projectile[k] = 0;
-        sound_effect_1 = 0x35;
-        return;
-      }
-    }
-    sprite_graphics[k] = frame_counter & 0x30 ? 4 : 5;
-    break;
-  case 1:  // spew lighting
-    sprite_F[k] = 0;
-    if (!sprite_delay_main[k]) {
-      static const uint8 kVitreous_AfromG[10] = {0x20, 0x20, 0x20, 0x40, 0x60, 0x80, 0xa0, 0xc0, 0xe0, 0};
-      sprite_delay_aux4[k] = 16;
-      sprite_ai_state[k] = 0;
-      sprite_A[k] = kVitreous_AfromG[sprite_G[k]];
-    } else {
-      Vitreous_Animate(k, sprite_delay_main[k]);
-    }
-    break;
-  case 2:  // pursue player
-    Vitreous_Animate(k, 0x8B);
-    if (Sprite_ReturnIfRecoiling(k))
-      return;
-    if (sprite_delay_main[k]) {
-      static const int8 kVitreous_Xvel[2] = {8, -8};
-      sprite_x_vel[k] = kVitreous_Xvel[(sprite_delay_main[k] & 2) >> 1];
-      Sprite_MoveX(k);
-    } else {
-      Sprite_MoveXYZ(k);
-      Sprite_CheckTileCollision(k);
-      sprite_z_vel[k] -= 2;
-      if (sign8(sprite_z[k])) {
-        sprite_z[k] = 0;
-        sprite_z_vel[k] = 32;
-        Sprite_ApplySpeedTowardsLink(k, 16);
-        SpriteSfx_QueueSfx2WithPan(k, 0x21);
-      }
-    }
-    break;
-  }
-}
-
-void Vitreous_Animate(int k, uint8 a) {  // 9de563
-  static const int8 kVitreous_Animate_Gfx[2] = {2, 1};
-  if (a == 0x40 || a == 0x41 || a == 0x42)
-    Sprite_SpawnLightning(k);
-  sprite_graphics[k] = 0;
-  PairU8 pair = Sprite_IsRightOfLink(k);
-  if ((uint8)(pair.b + 16) >= 32)
-    sprite_graphics[k] = kVitreous_Animate_Gfx[pair.a];
-}
-
-void Vitreous_SetMinionsForth(int k) {  // 9de5da
-  static const uint8 kVitreous_WhichToActivate[16] = {5, 6, 7, 8, 9, 10, 11, 12, 13, 5, 6, 7, 8, 9, 10, 11};
-  if (!(++sprite_subtype2[k] & 63)) {
-    int j = kVitreous_WhichToActivate[GetRandomNumber() & 15];
-    if (sprite_ai_state[j] == 0) {
-      sprite_ai_state[j] = 1;
-      sound_effect_1 = 0x15;
-    } else {
-      sprite_subtype2[k]--;
-    }
-  }
-}
-
-void Sprite_SpawnLightning(int k) {  // 9de612
-  static const int8 kAgahnim_Lighting_X[8] = {-8, 8, 8, -8, 8, -8, -8, 8};
-
-  SpriteSpawnInfo info;
-  int j = Sprite_SpawnDynamically(k, 0xBF, &info), i;
-  if (j >= 0) {
-    sound_effect_2 = 0x26;
-    Sprite_SetSpawnedCoordinates(j, &info);
-    sprite_A[j] = i = GetRandomNumber() & 7;
-    int t = info.r0_x + (uint16)kAgahnim_Lighting_X[i];
-    Sprite_SetX(j, info.r0_x + kAgahnim_Lighting_X[i]);
-    sprite_y_lo[j] = info.r2_y + 12 + (t >> 16);
-    sprite_delay_main[j] = 2;
-    intro_times_pal_flash = 32;
-  }
-}
-
-void Vitreous_Draw(int k) {  // 9de716
-  static const DrawMultipleData kVitreous_Dmd[24] = {
-    {-8, -8, 0x01c0, 2},
-    { 8, -8, 0x41c0, 2},
-    {-8,  8, 0x01e0, 2},
-    { 8,  8, 0x41e0, 2},
-    {-8, -8, 0x01c8, 2},
-    { 8, -8, 0x01ca, 2},
-    {-8,  8, 0x01e8, 2},
-    { 8,  8, 0x01ea, 2},
-    {-8, -8, 0x41ca, 2},
-    { 8, -8, 0x41c8, 2},
-    {-8,  8, 0x41ea, 2},
-    { 8,  8, 0x41e8, 2},
-    {-8, -8, 0x01c2, 2},
-    { 8, -8, 0x41c2, 2},
-    {-8,  8, 0x01e2, 2},
-    { 8,  8, 0x41e2, 2},
-    {-8, -8, 0x01c4, 2},
-    { 8, -8, 0x41c4, 2},
-    {-8,  8, 0x01e4, 2},
-    { 8,  8, 0x41e4, 2},
-    {-7, -7, 0x01c4, 2},
-    { 7, -7, 0x41c4, 2},
-    {-7,  7, 0x01e4, 2},
-    { 7,  7, 0x41e4, 2},
-  };
-  if (sprite_ai_state[k] == 2 && sprite_state[k] == 9)
-    oam_cur_ptr = 0x800, oam_ext_cur_ptr = 0xa20;
-  Sprite_DrawMultiple(k, &kVitreous_Dmd[sprite_graphics[k] * 4], 4, NULL);
-  if (sprite_ai_state[k] == 2) {
-    sprite_obj_prio[k] &= ~0xe;
-    Sprite_DrawLargeShadow2(k);
-  }
-}
-
-void Sprite_BE_VitreousEye(int k) {  // 9de773
-  static const int8 kSprite_Vitreolus_Dx[4] = {1, 0, -1, 0};
-  static const int8 kSprite_Vitreolus_Dy[4] = {0, 1, 0, -1};
-  int j = sprite_subtype2[k] >> 4 & 3;
-  cur_sprite_x += kSprite_Vitreolus_Dx[j];
-  cur_sprite_y += kSprite_Vitreolus_Dy[j];
-  SpriteDraw_SingleLarge(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  sprite_subtype2[k]++;
-  if (sprite_graphics[k])
-    return;
-  Sprite_CheckDamageFromLink(k);
-  Sprite_CheckDamageToLink(k);
-  if (sprite_F[k] == 14)
-    sprite_F[k] = 5;
-  switch (sprite_ai_state[k]) {
-  case 0:  // target player
-    sprite_G[k] = link_x_coord;
-    sprite_head_dir[k] = link_x_coord >> 8;
-    sprite_anim_clock[k] = link_y_coord;
-    sprite_subtype[k] = link_y_coord >> 8;
-    break;
-  case 1:  // pursue player
-    if (Sprite_ReturnIfRecoiling(k))
-      return;
-    if (!((k ^ frame_counter) & 1)) {
-      uint16 x = sprite_head_dir[k] << 8 | sprite_G[k];
-      uint16 y = sprite_subtype[k] << 8 | sprite_anim_clock[k];
-      ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLocation(k, x, y, 16);
-      sprite_x_vel[k] = pt.x;
-      sprite_y_vel[k] = pt.y;
-    }
-    Sprite_MoveXY(k);
-    if ((uint8)(sprite_G[k] - sprite_x_lo[k] + 4) < 8 && (uint8)(sprite_anim_clock[k] - sprite_y_lo[k] + 4) < 8)
-      sprite_ai_state[k] = 2;
-    break;
-  case 2:  // return
-    if (Sprite_ReturnIfRecoiling(k))
-      return;
-    if (!((k ^ frame_counter) & 1)) {
-      uint16 x = sprite_A[k] | sprite_B[k] << 8;
-      uint16 y = sprite_C[k] | sprite_D[k] << 8;
-      ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLocation(k, x, y, 16);
-      sprite_x_vel[k] = pt.x;
-      sprite_y_vel[k] = pt.y;
-    }
-    Sprite_MoveXY(k);
-    if ((uint8)(sprite_A[k] - sprite_x_lo[k] + 4) < 8 && (uint8)(sprite_C[k] - sprite_y_lo[k] + 4) < 8) {
-      sprite_x_lo[k] = sprite_A[k];
-      sprite_x_hi[k] = sprite_B[k];
-      sprite_y_lo[k] = sprite_C[k];
-      sprite_y_hi[k] = sprite_D[k];
-      sprite_ai_state[k] = 0;
-    }
-    break;
-  }
-}
-
-void HelmasaurFireball_TriSplit(int k) {  // 9deed3
-  static const int8 kHelmasaurFireball_TriSplit_Xvel[3] = {0, 28, -28};
-  static const int8 kHelmasaurFireball_TriSplit_Yvel[3] = {-32, 24, 24};
-  static const uint8 kHelmasaurFireball_TriSplit_Delay[6] = {32, 80, 128, 32, 80, 128};
-
-  SpriteSfx_QueueSfx3WithPan(k, 0x36);
-  sprite_state[k] = 0;
-
-  byte_7E0FB6 = GetRandomNumber();
-  for (int i = 2; i >= 0; i--) {
-    SpriteSpawnInfo info;
-    int j = Sprite_SpawnDynamically(k, 0x70, &info);
-    if (j >= 0) {
-      Sprite_SetSpawnedCoordinates(j, &info);
-      sprite_x_vel[j] = kHelmasaurFireball_TriSplit_Xvel[i];
-      sprite_y_vel[j] = kHelmasaurFireball_TriSplit_Yvel[i];
-      sprite_ai_state[j] = 3;
-      sprite_ignore_projectile[j] = 3;
-      sprite_delay_main[j] = kHelmasaurFireball_TriSplit_Delay[(byte_7E0FB6 & 3) + i];
-      sprite_head_dir[j] = 0;
-      sprite_graphics[j] = 1;
-    }
-  }
-  tmp_counter = -1;
-}
-
-void HelmasaurFireball_QuadSplit(int k) {  // 9def3d
-  static const int8 kHelmasaurFireball_QuadSplit_Xvel[4] = {32, 32, -32, -32};
-  static const int8 kHelmasaurFireball_QuadSplit_Yvel[4] = {-32, 32, -32, 32};
-  SpriteSfx_QueueSfx3WithPan(k, 0x36);
-  sprite_state[k] = 0;
-  for (int i = 3; i >= 0; i--) {
-    SpriteSpawnInfo info;
-    int j = Sprite_SpawnDynamically(k, 0x70, &info);
-    if (j >= 0) {
-      Sprite_SetSpawnedCoordinates(j, &info);
-      sprite_x_vel[j] = kHelmasaurFireball_QuadSplit_Xvel[i];
-      sprite_y_vel[j] = kHelmasaurFireball_QuadSplit_Yvel[i];
-      sprite_ai_state[j] = 4;
-      sprite_ignore_projectile[j] = 4;
-    }
-  }
-  tmp_counter = -1;
-}
-
-void Sprite_ArmosCrusher(int k) {  // 9def7e
-  sprite_oam_flags[k] = 7;
-  bg1_y_offset = sprite_delay_aux4[k] ? (sprite_delay_aux4[k] & 1 ? -1 : 1) : 0;
-  switch (sprite_G[k]) {
-  case 0:  // retarget
-    Sprite_CheckDamageToAndFromLink(k);
-    if (!(sprite_delay_main[k] | sprite_z[k])) {
-      Sprite_ApplySpeedTowardsLink(k, 32);
-      sprite_z_vel[k] = 32;
-      sprite_G[k]++;
-      sprite_B[k] = link_x_coord;
-      sprite_C[k] = link_x_coord >> 8;
-      sprite_E[k] = link_y_coord;
-      sprite_head_dir[k] = link_y_coord >> 8;
-      SpriteSfx_QueueSfx2WithPan(k, 0x20);
-    }
-    break;
-  case 1:  // approach target
-    sprite_z_vel[k] += 3;
-    if (Sprite_CheckTileCollision(k))
-      goto advance;
-    Sprite_Get16BitCoords(k);
-    uint16 x, y;
-    x = sprite_B[k] | sprite_C[k] << 8;
-    y = sprite_E[k] | sprite_head_dir[k] << 8;
-    if ((uint16)(x - cur_sprite_x + 16) < 32 && (uint16)(y - cur_sprite_y + 16) < 32) {
-advance:
-      sprite_G[k]++;
-      sprite_delay_main[k] = 16;
-      sprite_x_vel[k] = 0;
-      sprite_y_vel[k] = 0;
-    }
-    break;
-  case 2:  // hover
-    sprite_z_vel[k] = 0;
-    if (!sprite_delay_main[k])
-      sprite_G[k]++;
-    break;
-  case 3:  // crush
-    sprite_z_vel[k] = -104;
-    if (!sign8(sprite_z[k])) {
-      sprite_delay_main[k] = 32;
-      sprite_delay_aux4[k] = 32;
-      sprite_G[k] = 0;
-      SpriteSfx_QueueSfx2WithPan(k, 0xc);
-    }
-    break;
-  }
-}
-
-void Sprite_EvilBarrier(int k) {  // 9df06b
-  EvilBarrier_Draw(k);
-  if (sprite_graphics[k] == 4)
-    return;
-
-  sprite_graphics[k] = frame_counter >> 1 & 3;
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  if (Sprite_CheckDamageFromLink(k) && link_sword_type < 2) {
-    sprite_hit_timer[k] = 0;
-    Sprite_AttemptDamageToLinkPlusRecoil(k);
-    if (!countdown_for_blink)
-      link_electrocute_on_touch = 64;
-  }
-
-  if ((uint16)(link_y_coord - cur_sprite_y + 8) < 24 &&
-      (uint16)(link_x_coord - cur_sprite_x + 32) < 64 &&
-      sign8(link_actual_vel_y - 1)) {
-    link_electrocute_on_touch = 64;
-    link_incapacitated_timer = 12;
-    link_auxiliary_state = 1;
-    link_give_damage = 2;
-    link_actual_vel_x = 0;
-    link_actual_vel_y = 48;
-  }
-}
-
-void EvilBarrier_Draw(int k) {  // 9df249
-  static const DrawMultipleData kEvilBarrier_Dmd[45] = {
-    {  0,  0, 0x00e8, 2},
-    {-29,  3, 0x00ca, 0},
-    {-29, 11, 0x00da, 0},
-    { 37,  3, 0x40ca, 0},
-    { 37, 11, 0x40da, 0},
-    {-24, -2, 0x00e6, 2},
-    { -8, -2, 0x00e6, 2},
-    {  8, -2, 0x40e6, 2},
-    { 24, -2, 0x40e6, 2},
-    {  0,  0, 0x00cc, 2},
-    {-29,  3, 0x00cb, 0},
-    {-29, 11, 0x00db, 0},
-    { 37,  3, 0x40cb, 0},
-    { 37, 11, 0x40db, 0},
-    {  0,  0, 0x00cc, 2},
-    {  0,  0, 0x00cc, 2},
-    {  0,  0, 0x00cc, 2},
-    {  0,  0, 0x00cc, 2},
-    {  0,  0, 0x00cc, 2},
-    {-29,  3, 0x00cb, 0},
-    {-29, 11, 0x00db, 0},
-    { 37,  3, 0x40cb, 0},
-    { 37, 11, 0x40db, 0},
-    {-24, -2, 0x80e6, 2},
-    { -8, -2, 0x80e6, 2},
-    {  8, -2, 0xc0e6, 2},
-    { 24, -2, 0xc0e6, 2},
-    {  0,  0, 0x00e8, 2},
-    {-29,  3, 0x00ca, 0},
-    {-29, 11, 0x00da, 0},
-    { 37,  3, 0x40ca, 0},
-    { 37, 11, 0x40da, 0},
-    {  0,  0, 0x00e8, 2},
-    {  0,  0, 0x00e8, 2},
-    {  0,  0, 0x00e8, 2},
-    {  0,  0, 0x00e8, 2},
-    {-29,  3, 0x00cb, 0},
-    {-29, 11, 0x00db, 0},
-    { 37,  3, 0x40cb, 0},
-    { 37, 11, 0x40db, 0},
-    { 37, 11, 0x40db, 0},
-    { 37, 11, 0x40db, 0},
-    { 37, 11, 0x40db, 0},
-    { 37, 11, 0x40db, 0},
-    { 37, 11, 0x40db, 0},
-  };
-  cur_sprite_y += 8;
-  Sprite_DrawMultiple(k, &kEvilBarrier_Dmd[sprite_graphics[k] * 9], 9, NULL);
-  Sprite_Get16BitCoords(k);
-}
-
-void SpriteDraw_Antfairy(int k) {  // 9df395
-  static const DrawMultipleData kDrawFourAroundOne_Dmd[30] = {
-    { 4,  2, 0x02e1, 0},
-    { 4, -3, 0x02e3, 0},
-    {-1,  2, 0x02e3, 0},
-    { 9,  2, 0x02e3, 0},
-    { 4,  7, 0x02e3, 0},
-    { 4,  2, 0x02e1, 0},
-    { 3, -3, 0x02e3, 0},
-    { 9,  1, 0x02e3, 0},
-    {-1,  3, 0x02e3, 0},
-    { 5,  7, 0x02e3, 0},
-    { 4,  2, 0x02e1, 0},
-    { 1, -3, 0x02e3, 0},
-    { 9, -1, 0x02e3, 0},
-    {-1,  5, 0x02e3, 0},
-    { 7,  7, 0x02e3, 0},
-    { 4,  2, 0x02e1, 0},
-    { 0, -2, 0x02e3, 0},
-    { 8, -2, 0x02e3, 0},
-    { 0,  6, 0x02e3, 0},
-    { 8,  6, 0x02e3, 0},
-    { 4,  2, 0x02e1, 0},
-    { 7, -3, 0x02e3, 0},
-    {-1, -1, 0x02e3, 0},
-    { 9,  5, 0x02e3, 0},
-    { 1,  7, 0x02e3, 0},
-    { 4,  2, 0x02e1, 0},
-    { 5, -3, 0x02e3, 0},
-    {-1,  1, 0x02e3, 0},
-    { 9,  3, 0x02e3, 0},
-    { 3,  7, 0x02e3, 0},
-  };
-  if (!(++sprite_subtype2[k] & 1 | submodule_index | flag_unk1)) {
-    if (++sprite_graphics[k] == 6)
-      sprite_graphics[k] = 0;
-  }
-  Sprite_DrawMultiple(k, &kDrawFourAroundOne_Dmd[sprite_graphics[k] * 5], 5, NULL);
-}
-
-void Toppo_Flustered(int k) {  // 9df3d4
-  sprite_flags2[k] = 130;
-  sprite_ignore_projectile[k] = 130;
-  sprite_flags3[k] = 73;
-  if (!sprite_subtype[k]) {
-    if (Sprite_CheckDamageToLink(k)) {
-      dialogue_message_index = 0x174;
-      Sprite_ShowMessageMinimal();
-      sprite_subtype[k] = 1;
-    }
-  } else if (sprite_subtype[k] < 16) {
-    sprite_subtype[k]++;
-  } else if (sprite_subtype[k] == 16) {
-    sprite_flags5[k] = 0;
-    sprite_state[k] = 6;
-    sprite_delay_main[k] = 15;
-    sprite_flags2[k] += 4;
-    SpriteSfx_QueueSfx2WithPan(k, 0x15);
-    SpriteSpawnInfo info;
-    int j = Sprite_SpawnDynamically(k, 0x4d, &info);
-    if (j >= 0) {
-      Sprite_SetSpawnedCoordinates(j, &info);
-      ForcePrizeDrop(j, 6, 6);
-    }
-    sprite_subtype[k]++;
-  }
-  sprite_graphics[k] = ((++sprite_subtype2[k] & 4) >> 2) + 3;
-}
-
-void Goriya_Draw(int k) {  // 9df589
-  static const DrawMultipleData kGoriya_Dmd2[3] = {
-    {10, 4, 0x4077, 0},
-    {-2, 4, 0x0077, 0},
-    { 4, 4, 0x0076, 0},
-  };
-  static const DrawMultipleData kGoriya_Dmd[32] = {
-    {-4, -8, 0x0044, 2},
-    {12, -8, 0x4044, 0},
-    {-4,  8, 0x0064, 0},
-    { 4,  0, 0x4054, 2},
-    {-4, -8, 0x0044, 2},
-    {12, -8, 0x4044, 0},
-    {-4,  8, 0x4074, 0},
-    { 4,  0, 0x4062, 2},
-    {-4, -8, 0x0044, 0},
-    { 4, -8, 0x4044, 2},
-    {-4,  0, 0x0062, 2},
-    {12,  8, 0x4064, 0},
-    {-4, -8, 0x0046, 2},
-    {12, -8, 0x4046, 0},
-    {-4,  8, 0x0066, 0},
-    { 4,  0, 0x4056, 2},
-    {-4, -8, 0x0046, 2},
-    {12, -8, 0x4046, 0},
-    {-4,  8, 0x4075, 0},
-    { 4,  0, 0x406a, 2},
-    {-4, -8, 0x0046, 0},
-    { 4, -8, 0x4046, 2},
-    {-4,  0, 0x006a, 2},
-    {12,  8, 0x0075, 0},
-    {-2, -8, 0x004e, 2},
-    { 0,  0, 0x006c, 2},
-    {-2, -7, 0x004e, 2},
-    { 0,  0, 0x006e, 2},
-    { 2, -8, 0x404e, 2},
-    { 0,  0, 0x406c, 2},
-    { 2, -7, 0x404e, 2},
-    { 0,  0, 0x406e, 2},
-  };
-  static const uint8 kGoriyaDmdOffs[] = { 0, 4, 8, 12, 16, 20, 24, 26, 28, 30, 32 };
-  if (sprite_delay_aux1[k] && sprite_D[k] != 3)
-    Sprite_DrawMultiple(k, &kGoriya_Dmd2[sprite_D[k]], 1, NULL);
-
-  PrepOamCoordsRet info;
-  oam_cur_ptr += 4, oam_ext_cur_ptr++;
-  int g = sprite_graphics[k];
-  Sprite_DrawMultiple(k, &kGoriya_Dmd[kGoriyaDmdOffs[g]], kGoriyaDmdOffs[g + 1] - kGoriyaDmdOffs[g], &info);
-  sprite_flags2[k]--;
-  SpriteDraw_Shadow(k, &info);
-  sprite_flags2[k]++;
-}
-
-void Moldorm_Draw(int k) {  // 9df822
-  static const int8 kMoldorm_Draw_X[16] = {11, 10, 9, 6, 3, 0, -2, -3, -4, -3, -2, 1, 4, 7, 9, 10};
-  static const int8 kMoldorm_Draw_Y[16] = {4, 6, 9, 10, 11, 10, 9, 6, 3, 0, -2, -3, -4, -3, -2, 1};
-  static const uint8 kMoldorm_Draw_Char[3] = {0x5d, 0x62, 0x60};
-  static const int8 kMoldorm_Draw_XY[3] = {4, 0, 0};
-  static const uint8 kMoldorm_Draw_Big[3] = {0, 2, 2};
-  static const uint8 kMoldorm_Draw_GetOffs[3] = {21, 26, 0};
-
-  PrepOamCoordsRet info;
-  if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
-    return;
-  OamEnt *oam = GetOamCurPtr();
-  uint8 base = sprite_D[k] - 1;
-  for (int i = 1; i >= 0; i--, oam++, base += 2) {
-    SetOamHelper0(oam, info.x + kMoldorm_Draw_X[base & 0xf], info.y + kMoldorm_Draw_Y[base & 0xf],
-                  0x4d, info.flags, 0);
-  }
-  oam_cur_ptr += 8;
-  oam_ext_cur_ptr += 2;
-
-  int j = (sprite_subtype2[k] & 0x1f) + k * 32;
-  moldorm_x_lo[j] = sprite_x_lo[k];
-  moldorm_x_hi[j] = sprite_x_hi[k];
-  moldorm_y_lo[j] = sprite_y_lo[k];
-  moldorm_y_hi[j] = sprite_y_hi[k];
-
-  for (int i = 2; i >= 0; i--, oam++) {
-    j = ((sprite_subtype2[k] + kMoldorm_Draw_GetOffs[i]) & 0x1f) + k * 32;
-    uint16 x = (moldorm_x_lo[j] | moldorm_x_hi[j] << 8) - BG2HOFS_copy2 + kMoldorm_Draw_XY[i];
-    uint16 y = (moldorm_y_lo[j] | moldorm_y_hi[j] << 8) - BG2VOFS_copy2 + kMoldorm_Draw_XY[i];
-    SetOamHelper0(oam, x, y, kMoldorm_Draw_Char[i], info.flags, kMoldorm_Draw_Big[i]);
-  }
-}
-
-void TalkingTree_Mouth(int k) {  // 9df956
-  static const int8 kTalkingTree_Gfx2[4] = {0, 2, 3, 1};
-  int j;
-  TalkingTree_Draw(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  sprite_flags4[k] = 0;
-  switch(sprite_ai_state[k]) {
-  case 0:
-    sprite_graphics[k] = 0;
-    if (Sprite_CheckDamageToLink_same_layer(k)) {
-      Link_CancelDash();
-      link_incapacitated_timer = 16;
-      ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLink(k, 48);
-      link_actual_vel_y = pt.y;
-      link_actual_vel_x = pt.x;
-      SpriteSfx_QueueSfx3WithPan(k, 0x32);
-      sprite_ai_state[k]++;
-      sprite_delay_main[k] = 48;
-    }
-    break;
-  case 1:
-    if (!sprite_delay_main[k]) {
-      sprite_ai_state[k]++;
-      sprite_delay_main[k] = 8;
-    }
-    sprite_graphics[k] = sprite_delay_main[k] >> 1 & 3;
-    break;
-  case 2:
-    sprite_graphics[k] = kTalkingTree_Gfx2[sprite_delay_main[k] >> 1]; // zelda bug wtf
-    if (sprite_delay_main[k] == 7)
-      TalkingTree_SpawnBomb(k);
-    if (!sprite_delay_main[k])
-      sprite_ai_state[k]++;
-    break;
-  case 3:
-    sprite_flags4[k] = 7;
-    if (!sprite_A[k]) {
-      static const uint8 kTalkingTree_Msgs2[2] = { 0x82, 0x7d };
-      j = sprite_x_lo[k] >> 4 & 1 ^ 1;
-      sprite_A[k] = j;
-      if (!(Sprite_ShowSolicitedMessage(k, kTalkingTree_Msgs2[j]) & 0x100))
-        sprite_A[k] = 0;
-    } else {
-      static const uint8 kTalkingTree_Msgs[4] = {0x7e, 0x7f, 0x80, 0x81};
-      static const uint8 kTalkingTree_Screens[4] = {0x58, 0x5d, 0x72, 0x6b};
-      j = FindInByteArray(kTalkingTree_Screens, BYTE(overworld_screen_index), 4);
-      Sprite_ShowMessageUnconditional(kTalkingTree_Msgs[j]);
-      sprite_A[k] = 0;
-    }
-    if (!sprite_delay_main[k]) {
-      static const uint8 kTalkingTree_Gfx[8] = { 1, 2, 3, 1, 3, 1, 2, 3 };
-      static const uint8 kTalkingTree_Delay[8] = { 13, 13, 13, 11, 11, 6, 16, 8 };
-      sprite_B[k] = j = sprite_B[k] + 1 & 7;
-      sprite_graphics[k] = kTalkingTree_Gfx[j];
-      sprite_delay_main[k] = kTalkingTree_Delay[j];
-    }
-    break;
-  }
-}
-
-void TalkingTree_SpawnBomb(int k) {  // 9dfa4e
-  SpriteSpawnInfo info;
-  int j = Sprite_SpawnDynamically(k, 0x4a, &info);
-  if (j >= 0) {
-    Sprite_TransmuteToBomb(j);
-    Sprite_SetSpawnedCoordinates(j, &info);
-    sprite_delay_aux1[j] = 64;
-    sprite_y_vel[j] = 24;
-    sprite_z_vel[j] = 18;
-  }
-}
-
-void TalkingTree_Draw(int k) {  // 9dfadb
-  static const DrawMultipleData kTalkingTree_Dmd[12] = {
-    {1, -1, 0x00e8, 0},
-    {1,  7, 0x00f8, 0},
-    {7, -1, 0x40e8, 0},
-    {7,  7, 0x40f8, 0},
-    {0, -1, 0x00e8, 0},
-    {0,  7, 0x00f8, 0},
-    {8, -1, 0x40e8, 0},
-    {8,  7, 0x40f8, 0},
-    {0,  0, 0x00e8, 0},
-    {0,  7, 0x00f8, 0},
-    {8,  0, 0x40e8, 0},
-    {8,  7, 0x40f8, 0},
-  };
-  int g = sprite_graphics[k] - 1;
-  if (g < 0)
-    return;
-  Sprite_DrawMultiplePlayerDeferred(k, &kTalkingTree_Dmd[g * 4], 4, NULL);
-}
-
-void TalkingTree_Eye(int k) {  // 9dfb0a
-  static const int8 kTalkingTree_Type1_X[2] = {9, -9};
-  SpriteDraw_SingleSmall(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  int j = sprite_head_dir[k];
-  Sprite_SetX(k, (sprite_A[k] | sprite_B[k] << 8) + kTalkingTree_Type1_X[j]);
-  Sprite_SetY(k, (sprite_C[k] | sprite_E[k] << 8));
-  ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLink(k, 2);
-  if (!sign8(pt.y)) {
-    sprite_D[k] = pt.x + 2;
-  } else if (sprite_D[k] != 2) {
-    sprite_D[k] += (sprite_D[k] >= 2) ? -1 : 1;
-  }
-  static const int8 kTalkingTree_X1[5] = {-2, -1, 0, 1, 2};
-  static const int8 kTalkingTree_Y1[5] = {-1, 0, 0, 0, -1};
-  j = sprite_D[k];
-  Sprite_SetX(k, (sprite_A[k] | sprite_B[k] << 8) + kTalkingTree_X1[j]);
-  Sprite_SetY(k, (sprite_C[k] | sprite_E[k] << 8) + kTalkingTree_Y1[j]);
-}
-
-void SpritePrep_TalkingTree_SpawnEyeball(int k, int dir) {  // 9dfb8a
-  static const int8 kTalkingTree_SpawnX[2] = {-4, 14};
-  SpriteSpawnInfo info;
-  int j = Sprite_SpawnDynamically(k, 0x25, &info);
-  if (j >= 0) {
-    sprite_head_dir[j] = dir;
-    int x = info.r0_x + kTalkingTree_SpawnX[dir];
-    int y = info.r2_y - 11;
-    Sprite_SetX(j, x);
-    Sprite_SetY(j, y);
-    sprite_A[j] = x;
-    sprite_B[j] = x >> 8;
-    sprite_C[j] = y;
-    sprite_E[j] = y >> 8;
-    sprite_subtype2[j] = 1;
-  }
-}
-
-void RupeePull_SpawnPrize(int k) {  // 9dfbd7
-  static const int8 kSpawnRupees_Xvel[4] = {-18, -12, 12, 18};
-  static const int8 kSpawnRupees_Yvel[4] = {16, 24, 24, 16};
-  static const uint8 kSpawnRupees_Type[3] = {0xd9, 0xda, 0xdb};
-  if (num_sprites_killed) {
-    byte_7E0FB6 = num_sprites_killed < 4 ? 0 :
-                  number_of_times_hurt_by_sprites ? 1 : 2;
-    tmp_counter = 3;
-    do {
-      SpriteSpawnInfo info;
-      int j = Sprite_SpawnDynamically(k, kSpawnRupees_Type[byte_7E0FB6], &info);
-      if (j < 0)
-        break;
-      Sprite_SetSpawnedCoordinates(j, &info);
-      sprite_x_vel[j] = kSpawnRupees_Xvel[tmp_counter];
-      sprite_y_vel[j] = kSpawnRupees_Yvel[tmp_counter];
-      sprite_stunned[j] = 255;
-      sprite_delay_aux4[j] = 32;
-      sprite_delay_aux3[j] = 32;
-      sprite_z_vel[j] = 32;
-    } while (!sign8(--tmp_counter));
-  }
-  num_sprites_killed = 0;
-  number_of_times_hurt_by_sprites = 0;
-}
-
-void Sprite_D5_DigGameGuy(int k) {  // 9dfc38
-  DiggingGameGuy_Draw(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  Sprite_BehaveAsBarrier(k);
-  Sprite_MoveXY(k);
-  sprite_x_vel[k] = 0;
-  switch(sprite_ai_state[k]) {
-  case 0:  // intro
-    if ((uint8)(sprite_y_lo[k] + 7) < BYTE(link_y_coord) && Sprite_DirectionToFaceLink(k, NULL) == 2) {
-      if (follower_indicator == 0) {
-        if (Sprite_ShowSolicitedMessage(k, 0x187) & 0x100)
-          sprite_ai_state[k]++;
-      } else {
-        Sprite_ShowSolicitedMessage(k, 0x18c);
-      }
-    }
-    break;
-  case 1:  // do you want to play
-    if (choice_in_multiselect_box == 0 && link_rupees_goal >= 80) {
-      link_rupees_goal -= 80;
-      Sprite_ShowMessageUnconditional(0x188);
-      sprite_ai_state[k] = 2;
-      sprite_graphics[k] = 1;
-      sprite_delay_main[k] = 80;
-      beamos_x_hi[0] = 0;
-      beamos_x_hi[1] = 0;
-      sprite_delay_aux1[k] = 5;
-      Sprite_InitializeSecondaryItemMinigame(1);
-      music_control = 14;
-    } else {
-      Sprite_ShowMessageUnconditional(0x189);
-      sprite_ai_state[k] = 0;
-    }
-    break;
-  case 2:  // move out of the way
-    if (!sprite_delay_main[k]) {
-      sprite_ai_state[k]++;
-      sprite_graphics[k] = 1;
-    } else if (!sprite_delay_aux1[k]) {
-      sprite_graphics[k] ^= 3;
-      if (sprite_graphics[k] & 1)
-        sprite_x_vel[k] = -16;
-      sprite_delay_aux1[k] = 5;
-    }
-    break;
-  case 3:  // start timer
-    sprite_ai_state[k]++;
-    super_bomb_indicator_unk1 = 0;
-    super_bomb_indicator_unk2 = 30;
-    break;
-  case 4:  // terminate
-    if ((int8)super_bomb_indicator_unk2 > 0 || link_position_mode & 1)
-      return;
-    music_control = 9;
-    sprite_ai_state[k]++;
-    is_archer_or_shovel_game = 0;
-    dialogue_message_index = 0x18a;
-    Sprite_ShowMessageMinimal();
-    super_bomb_indicator_unk2 = 254;
-    break;
-  case 5:  // come back later
-    Sprite_ShowSolicitedMessage(k, 0x18b);
-    break;
-  }
-}
-
-void DiggingGameGuy_Draw(int k) {  // 9dfe4b
-  static const DrawMultipleData kDiggingGameGuy_Dmd[9] = {
-    { 0, -8, 0x0a40, 2},
-    { 4,  9, 0x0c56, 0},
-    { 0,  0, 0x0a42, 2},
-    { 0, -8, 0x0a40, 2},
-    { 0,  0, 0x0a42, 2},
-    { 0,  0, 0x0a42, 2},
-    {-1, -7, 0x0a40, 2},
-    {-1,  0, 0x0a44, 2},
-    {-1,  0, 0x0a44, 2},
-  };
-  PrepOamCoordsRet info;
-  Sprite_DrawMultiplePlayerDeferred(k, &kDiggingGameGuy_Dmd[sprite_graphics[k] * 3], 3, &info);
-  SpriteDraw_Shadow(k, &info);
-}
-
-void OldMountainMan_Draw(int k) {  // 9dff0e
-  static const DrawMultipleData kOldMountainMan_Dmd0[2] = {
-    {0, 0, 0x00ac, 2},
-    {0, 8, 0x00ae, 2},
-  };
-  static const DrawMultipleData kOldMountainMan_Dmd1[16] = {
-    { 0, 0, 0x0120, 2},
-    { 0, 8, 0x0122, 2},
-    { 0, 1, 0x0120, 2},
-    { 0, 9, 0x4122, 2},
-    { 0, 0, 0x0120, 2},
-    { 0, 8, 0x0122, 2},
-    { 0, 1, 0x0120, 2},
-    { 0, 9, 0x4122, 2},
-    {-2, 0, 0x0120, 2},
-    { 0, 8, 0x0122, 2},
-    {-2, 1, 0x0120, 2},
-    { 0, 9, 0x0122, 2},
-    { 2, 0, 0x4120, 2},
-    { 0, 8, 0x4122, 2},
-    { 2, 1, 0x4120, 2},
-    { 0, 9, 0x4122, 2},
-  };
-  static const uint8 kOldMountainMan_Dma[16] = {0x20, 0xc0, 0x20, 0xc0, 0, 0xa0, 0, 0xa0, 0x40, 0x80, 0x40, 0x60, 0x40, 0x80, 0x40, 0x60};
-  if (sprite_subtype2[k] != 2) {
-    int j = sprite_D[k] * 4 + sprite_graphics[k] * 2;
-    BYTE(dma_var6) = kOldMountainMan_Dma[j + 0];
-    BYTE(dma_var7) = kOldMountainMan_Dma[j + 1];
-    Sprite_DrawMultiplePlayerDeferred(k, &kOldMountainMan_Dmd1[j], 2, NULL);
-  } else {
-    Sprite_DrawMultiplePlayerDeferred(k, kOldMountainMan_Dmd0, 2, NULL);
-  }
-
-}
-
-void HelmasaurKing_Initialize(int k) {  // 9e8000
-  overlord_gen1[7] = 0x30;
-  overlord_gen1[5] = 0x80;
-  overlord_gen1[6] = 0;
-  overlord_gen2[0] = 0;
-  overlord_gen2[3] = 0;
-  overlord_gen2[1] = 0;
-  overlord_gen2[2] = 0;
-  HelmasaurKing_Reinitialize(k);
-}
-
-void HelmasaurKing_Reinitialize(int k) {  // 9e8019
-  uint8 t = sprite_subtype2[k];
-  for (int i = 3; i >= 0; i--) {
-    overlord_x_lo[i] = kHelmasaur_Tab0[t + i * 8 & 0x1f];
-  }
-}
-
-void Sprite_92_HelmasaurKing(int k) {  // 9e8039
-  int t, j;
-
-  if (sign8(sprite_C[k])) {
-    if (sprite_delay_main[k] == 1)
-      sprite_state[k] = 0;
-    SpriteDraw_SingleLarge(k);
-    if (Sprite_ReturnIfInactive(k))
-      return;
-    if (!(frame_counter & 7 | sprite_delay_aux1[k]))
-      sprite_oam_flags[k] ^= 0x40;
-    Sprite_MoveXYZ(k);
-    sprite_z_vel[k] -= 2;
-    if (sign8(sprite_z[k])) {
-      sprite_z[k] = 0;
-      sprite_delay_main[k] = 12;
-      sprite_z_vel[k] = 24;
-      sprite_graphics[k] = 6;
-    }
-    return;
-  }
-  if (sprite_C[k] < 3) {
-    sprite_obj_prio[k] &= ~0xE;
-    sprite_flags[k] = 0xA;
-  } else {
-    sprite_flags4[k] = 0x1F;
-    sprite_flags[k] = 2;
-  }
-  HelmasaurKing_Draw(k);
-  if (sprite_state[k] == 6) {
-    t = sprite_delay_main[k];
-    if (!t) {
-      sprite_state[k] = 4;
-      sprite_A[k] = 0;
-      sprite_delay_main[k] = 224;
-      return;
-    }
-    sprite_hit_timer[k] = t | 240;
-    if (t < 128 && (t & 7) == 0 && (j = overlord_gen2[3]) != 0x10) {
-      overlord_gen2[3]++;
-      cur_sprite_x = Sprite_GetX(k) + (int8)overlord_x_lo[5 + j];
-      cur_sprite_y = Sprite_GetY(k) + (int8)overlord_y_lo[5 + j];
-      Sprite_MakeBossExplosion(k);
-    }
-    return;
-  }
-
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  static const uint8 kHelmasaurKing_Tab1[13] = {3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 1, 1, 0};
-  t = kHelmasaurKing_Tab1[sprite_health[k] >> 2];
-  sprite_C[k] = t;
-  if (t == 3) {
-    if (t != sprite_E[k]) {
-      sprite_hit_timer[k] = 0;
-      HelmasaurKing_ExplodeMask(k);
-    }
-  } else {
-    if (t != sprite_E[k])
-      HelmasaurKing_ChipAwayAtMask(k);
-  }
-  sprite_E[k] = sprite_C[k];
-  Sprite_CheckDamageFromLink(k);
-  HelmasaurKing_SwingTail(k);
-  HelmasaurKing_AttemptDamage(k);
-  HelmasaurKing_CheckMaskDamageFromHammer(k);
-  if (sprite_delay_aux1[k] == 0) {
-    if (sprite_delay_aux2[k] != 0) {
-      if (sprite_delay_aux2[k] == 0x40) {
-        HelmasaurKing_SpitFireball(k);
-        if (sprite_C[k] >= 3) {
-anim_clk:
-          if (!sprite_anim_clock[k]) {
-            sprite_anim_clock[k]++;
-            sprite_delay_aux3[k] = 32;
-          }
-        }
-      }
-      return;
-    }
-  } else {
-    if (sprite_delay_aux1[k] == 96)
-      goto anim_clk;
-    return;
-  }
-  static const int8 kHelmasaurKing_Xvel0[8] = {-12, -12, -4, 0, 4, 12, 12, 0};
-  static const int8 kHelmasaurKing_Yvel0[8] = {0, 4, 12, 12, 12, 4, 0, 12};
-  switch (sprite_ai_state[k]) {
-  case 0:
-    if ((sprite_hit_timer[k] || !sprite_delay_main[k]) && !HelmasaurKing_MaybeFireball(k)) {
-      j = GetRandomNumber() & 7;
-      sprite_x_vel[k] = kHelmasaurKing_Xvel0[j];
-      sprite_y_vel[k] = kHelmasaurKing_Yvel0[j];
-      sprite_delay_main[k] = 64;
-      if (sprite_C[k] >= 3) {
-        sprite_x_vel[k] <<= 1;
-        sprite_y_vel[k] <<= 1;
-        sprite_delay_main[k] >>= 1;
-      }
-      sprite_ai_state[k]++;
-    }
-    break;
-  case 1:
-    HelmasaurKing_HandleMovement(k);
-    if (!sprite_delay_main[k]) {
-      sprite_delay_main[k] = 32;
-      sprite_ai_state[k]++;
-    }
-    break;
-  case 2:
-    if ((sprite_hit_timer[k] || !sprite_delay_main[k]) && !HelmasaurKing_MaybeFireball(k)) {
-      sprite_delay_main[k] = 64;
-      if (sprite_E[k] >= 3)
-        sprite_delay_main[k] >>= 1;
-      sprite_x_vel[k] = -sprite_x_vel[k];
-      sprite_y_vel[k] = -sprite_y_vel[k];
-      sprite_ai_state[k]++;
-    }
-    break;
-  case 3:
-    HelmasaurKing_HandleMovement(k);
-    if (!sprite_delay_main[k]) {
-      sprite_ai_state[k] = 0;
-      sprite_delay_main[k] = 64;
-    }
-    break;
-  }
-}
-
-void HelmasaurKing_HandleMovement(int k) {  // 9e81e6
-  int n = 1 + ((frame_counter & 3) == 0) + (sprite_C[k] >= 3);
-  do {
-    if (!(++sprite_subtype2[k] & 15))
-      sound_effect_1 = 0x21;
-  } while (--n);
-  Sprite_MoveXY(k);
-}
-
-bool HelmasaurKing_MaybeFireball(int k) {  // 9e8253
-  if (++sprite_subtype[k] != 4)
-    return false;
-  sprite_subtype[k] = 0;
-  if (GetRandomNumber() & 1) {
-    sprite_delay_aux2[k] = 127;
-    SpriteSfx_QueueSfx3WithPan(k, 0x2a);
-  } else {
-    sprite_delay_aux1[k] = 160;
-  }
-  return true;
-}
-
-void HelmasaurKing_SwingTail(int k) {  // 9e82a0
-  overlord_x_lo[4]++;
-  HelmasaurKing_Reinitialize(k);
-  uint8 mask = sprite_anim_clock[k] ? 0 : 1;
-  if (!(frame_counter & mask)) {
-    int j = sprite_D[k] & 1;
-    overlord_gen2[0] += j ? -1 : 1;
-    if (overlord_gen2[0] == (uint8)kFluteBoyAnimal_Xvel[j])
-      sprite_D[k]++;
-    WORD(overlord_gen1[5]) += (int8)overlord_gen2[0];
-  }
-  if (!sprite_anim_clock[k])
-    return;
-  if (!overlord_gen2[0])
-    SpriteSfx_QueueSfx3WithPan(k, 0x6);
-
-  if (sprite_anim_clock[k] == 2) {
-    int j = sprite_head_dir[k];
-    WORD(overlord_gen2[1]) += j ? -4 : 4;
-    if (overlord_gen2[1] == (uint8)(j ? -124 : 124))
-      sprite_anim_clock[k] = 3;
-    overlord_gen1[7] += 3;
-  } else if (sprite_anim_clock[k] == 3) {
-    int j = sprite_head_dir[k] ^ 1;
-    WORD(overlord_gen2[1]) += j ? -4 : 4;
-    if (overlord_gen2[1] == 0)
-      sprite_anim_clock[k] = 0;
-    overlord_gen1[7] -= 3;
-  } else {
-    if (!(overlord_gen2[0] | sprite_delay_aux3[k])) {
-      sprite_head_dir[k] = overlord_gen1[6] & 1;
-      uint8 dir = Sprite_IsRightOfLink(k).a ^ 1;
-      if (dir == sprite_head_dir[k]) {
-        sprite_anim_clock[k] = 2;
-        sound_effect_2 = Sprite_CalculateSfxPan(k) | 0x26;
-      }
-    }
-  }
-}
-
-void HelmasaurKing_CheckMaskDamageFromHammer(int k) {  // 9e8385
-  if (sprite_C[k] >= 3 || !(link_item_in_hand & 10) || (player_oam_y_offset == 0x80))
-    return;
-  SpriteHitBox hb;
-  Player_SetupActionHitBox(&hb);
-  uint8 bak  = sprite_y_lo[k];
-  sprite_y_lo[k] += 8;
-  Sprite_SetupHitBox(k, &hb);
-  sprite_y_lo[k] = bak;
-  if (CheckIfHitBoxesOverlap(&hb)) {
-    sprite_health[k]--;
-    sound_effect_2 = 0x21;
-    ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLink(k, 0x30);
-    link_actual_vel_y = pt.y;
-    link_actual_vel_x = pt.x;
-    link_incapacitated_timer = 8;
-    if (!repulsespark_timer) {
-      repulsespark_x_lo = pt.y;
-      repulsespark_y_lo = pt.x;
-      repulsespark_timer = 5;
-    }
-    SpriteSfx_QueueSfx2WithPan(k, 0x5);
-  }
-}
-
-void HelmasaurKing_AttemptDamage(int k) {  // 9e83eb
-  if (!(frame_counter & 7) &&
-      (uint16)(link_x_coord - cur_sprite_x + 36) < 72 &&
-      (uint16)(link_y_coord - cur_sprite_y + 40) < 64)
-    Sprite_AttemptDamageToLinkPlusRecoil(k);
-}
-
-void HelmasaurKing_ChipAwayAtMask(int k) {  // 9e847e
-  tmp_counter = sprite_C[k] + 7;
-  HelmasaurKing_SpawnMaskDebris(k);
-  SpriteSfx_QueueSfx2WithPan(k, 0x1f);
-}
-
-void HelmasaurKing_ExplodeMask(int k) {  // 9e848c
-  for (int j = 1; j < 16; j++)
-    sprite_state[j] = 0;
-  tmp_counter = 7;
-  do {
-    HelmasaurKing_SpawnMaskDebris(k);
-  } while (!sign8(--tmp_counter));
-  SpriteSfx_QueueSfx2WithPan(k, 0x1f);
-}
-
-void HelmasaurKing_SpawnMaskDebris(int k) {  // 9e84aa
-  static const int8 kHelmasaurKing_Mask_X[10] = {-16, 0, 16, -16, 0, 16, -8, 8, -16, 16};
-  static const int8 kHelmasaurKing_Mask_Y[10] = {24, 27, 24, 24, 27, 24, 27, 27, 24, 24};
-  static const int8 kHelmasaurKing_Mask_Z[10] = {29, 32, 29, 13, 16, 13, 0, 0, 13, 13};
-  static const int8 kHelmasaurKing_Mask_Xvel[10] = {-16, -4, 14, -12, 4, 18, -2, 2, -12, 18};
-  static const int8 kHelmasaurKing_Mask_Yvel[10] = {-8, -4, -6, 4, 2, 7, 6, 8, 4, 7};
-  static const int8 kHelmasaurKing_Mask_Zvel[10] = {32, 40, 36, 37, 39, 34, 30, 33, 37, 34};
-  static const uint8 kHelmasaurKing_Mask_OamFlags[10] = {0, 0, 0x40, 0, 0, 0x40, 0, 0x40, 0, 0x40};
-  static const uint8 kHelmasaurKing_Mask_Gfx[10] = {0, 1, 0, 2, 3, 2, 4, 4, 5, 5};
-  SpriteSpawnInfo info;
-  int j = Sprite_SpawnDynamically(k, 0x92, &info);
-  if (j >= 0) {
-    int i = tmp_counter;
-    Sprite_SetX(j, info.r0_x + kHelmasaurKing_Mask_X[i]);
-    Sprite_SetY(j, info.r2_y + kHelmasaurKing_Mask_Y[i]);
-    sprite_z[j] = kHelmasaurKing_Mask_Z[i];
-    sprite_x_vel[j] = kHelmasaurKing_Mask_Xvel[i];
-    sprite_y_vel[j] = kHelmasaurKing_Mask_Yvel[i];
-    sprite_z_vel[j] = kHelmasaurKing_Mask_Zvel[i];
-    sprite_oam_flags[j] = kHelmasaurKing_Mask_OamFlags[i] | 13;
-    sprite_graphics[j] = kHelmasaurKing_Mask_Gfx[i];
-    sprite_C[j] = 128;
-    sprite_flags2[j] = 0;
-    sprite_delay_aux1[j] = 12;
-    sprite_ignore_projectile[j] = 12;
-    sprite_subtype[j] = tmp_counter;
-  }
-}
-
-void HelmasaurKing_SpitFireball(int k) {  // 9e8517
-  SpriteSpawnInfo info;
-  int j = Sprite_SpawnDynamically(k, 0x70, &info);
-  if (j >= 0) {
-    Sprite_SetSpawnedCoordinates(j, &info);
-    Sprite_SetY(j, info.r2_y + 28);
-    sprite_delay_main[j] = 32;
-    sprite_ignore_projectile[j] = 32;
-  }
-}
-
-void HelmasaurKing_Draw(int k) {  // 9e853b
-  oam_cur_ptr = 0x89c;
-  oam_ext_cur_ptr = 0xa47;
-  PrepOamCoordsRet info;
-  if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
-    return;
-  KingHelmasaur_OperateTail(k, &info);
-  SpriteDraw_KingHelmasaur_Eyes(k, &info);
-  KingHelmasaurMask(k, &info);
-  SpriteDraw_KingHelmasaur_Body(k, &info);
-  SpriteDraw_KingHelmasaur_Legs(k, &info);
-  SpriteDraw_KingHelmasaur_Mouth(k, &info);
-}
-
-void SpriteDraw_KingHelmasaur_Eyes(int k, PrepOamCoordsRet *info) {  // 9e856b
-  static const int8 kHelmasaurKing_DrawB_X[2] = {-3, 11};
-  static const uint8 kHelmasaurKing_DrawB_Char[8] = {0xce, 0xcf, 0xde, 0xde, 0xde, 0xde, 0xcf, 0xce};
-  static const uint8 kHelmasaurKing_DrawB_Flags[2] = {0x3b, 0x7b};
-  oam_cur_ptr += 0x40, oam_ext_cur_ptr += 0x10;
-  OamEnt *oam = GetOamCurPtr();
-  for (int i = 1; i >= 0; i--, oam++) {
-    int j = overlord_x_lo[4] >> 2 & 7;
-    SetOamPlain(oam, info->x + kHelmasaurKing_DrawB_X[i], info->y + 0x14, kHelmasaurKing_DrawB_Char[j], kHelmasaurKing_DrawB_Flags[i], 0);
-  }
-  if (submodule_index)
-    Sprite_CorrectOamEntries(k, 1, 0);
-}
-
-void KingHelmasaurMask(int k, PrepOamCoordsRet *info) {  // 9e8686
-  static const DrawMultipleData kHelmasaurKing_DrawC_Dmd[24] = {
-    {-16, -5, 0x0dae, 2},
-    {  0, -5, 0x0dc0, 2},
-    { 16, -5, 0x4dae, 2},
-    {-16, 11, 0x0dc2, 2},
-    {  0, 11, 0x0dc4, 2},
-    { 16, 11, 0x4dc2, 2},
-    { -8, 27, 0x0dc6, 2},
-    {  8, 27, 0x4dc6, 2},
-    {-16, -5, 0x0dae, 2},
-    {  0, -5, 0x0dc0, 2},
-    { 16, -5, 0x4dae, 2},
-    {-16, 11, 0x0dc8, 2},
-    {  0, 11, 0x0dc4, 2},
-    { 16, 11, 0x4dc2, 2},
-    { -8, 27, 0x0dc6, 2},
-    {  8, 27, 0x4dc6, 2},
-    {-16, -5, 0x0dae, 2},
-    {  0, -5, 0x0dc0, 2},
-    { 16, -5, 0x4dae, 2},
-    {-16, 11, 0x0dc8, 2},
-    {  0, 11, 0x0dc4, 2},
-    { 16, 11, 0x4dc8, 2},
-    { -8, 27, 0x0dc6, 2},
-    {  8, 27, 0x4dc6, 2},
-  };
-  oam_cur_ptr += 8, oam_ext_cur_ptr += 2;
-  if (sprite_C[k] >= 3)
-    return;
-  Sprite_DrawMultiple(k, &kHelmasaurKing_DrawC_Dmd[sprite_C[k] * 8], 8, info);
-  oam_cur_ptr += 0x20, oam_ext_cur_ptr += 8;
-  if (sprite_delay_aux4[k])
-    return;
-  for (int i = 1; i >= 0; i--) {
-    if (ancilla_type[i] == 7 && (ancilla_x_vel[i] | ancilla_y_vel[i])) {
-      KingHelmasaur_CheckBombDamage(k, i);
-    }
-  }
-}
-
-void KingHelmasaur_CheckBombDamage(int k, int j) {  // 9e86e5
-  SpriteHitBox hb;
-  Sprite_SetupHitBox(k, &hb);
-  int x = (ancilla_x_lo[j] | ancilla_x_hi[j] << 8) - 6;
-  int y = (ancilla_y_lo[j] | ancilla_y_hi[j] << 8) - ancilla_z[j];
-  hb.r0_xlo = x, hb.r8_xhi = x >> 8;
-  hb.r1_ylo = y, hb.r9_yhi = y >> 8;
-  hb.r2 = 2;
-  hb.r3 = 15;
-  if (CheckIfHitBoxesOverlap(&hb)) {
-    ancilla_x_vel[j] = -ancilla_x_vel[j];
-    ancilla_y_vel[j] = (int8)-ancilla_y_vel[j] >> 1;
-    sprite_delay_aux4[k] = 32;
-    repulsespark_timer = 5;
-    repulsespark_x_lo = ancilla_x_lo[j];
-    repulsespark_y_lo = ancilla_y_lo[j] - ancilla_z[j];
-    sound_effect_1 = 5;
-  }
-}
-
-void SpriteDraw_KingHelmasaur_Body(int k, PrepOamCoordsRet *info) {  // 9e87e5
-  static const DrawMultipleData kHelmasaurKing_DrawD_Dmd[19] = {
-    {-24, -32, 0x0b80, 2},
-    { -8, -32, 0x0b82, 2},
-    {  8, -32, 0x4b82, 2},
-    { 24, -32, 0x4b80, 2},
-    {-24, -16, 0x0b84, 2},
-    { -8, -16, 0x0b86, 2},
-    {  8, -16, 0x4b86, 2},
-    { 24, -16, 0x4b84, 2},
-    {-24,   0, 0x0b88, 2},
-    { -8,   0, 0x0b8a, 2},
-    {  8,   0, 0x4b8a, 2},
-    { 24,   0, 0x4b88, 2},
-    {-24,  16, 0x0b8c, 2},
-    { -8,  16, 0x0b8e, 2},
-    {  8,  16, 0x4b8e, 2},
-    { 24,  16, 0x4b8c, 2},
-    { -8,  32, 0x0ba0, 2},
-    {  8,  32, 0x4ba0, 2},
-    {  0, -40, 0x0bac, 2},
-  };
-  Sprite_DrawMultiple(k, kHelmasaurKing_DrawD_Dmd, 19, info);
-}
-
-void SpriteDraw_KingHelmasaur_Legs(int k, PrepOamCoordsRet *info) {  // 9e8805
-  static const int8 kHelmasaurKing_DrawE_X[4] = {-28, -28, 28, 28};
-  static const int8 kHelmasaurKing_DrawE_Y[4] = {-28, 4, -28, 4};
-  static const uint8 kHelmasaurKing_DrawE_Char[4] = {0xa2, 0xa6, 0xa2, 0xa6};
-  static const uint8 kHelmasaurKing_DrawE_Flags[4] = {0xb, 0xb, 0x4b, 0x4b};
-
-  oam_cur_ptr += 19 * 4;
-  oam_ext_cur_ptr += 19;
-  OamEnt *oam = GetOamCurPtr();
-  for (int i = 3; i >= 0; i--, oam += 2) {
-    uint8 x = info->x + kHelmasaurKing_DrawE_X[i];
-    uint8 y = info->y + kHelmasaurKing_DrawE_Y[i] + overlord_x_lo[i];
-    uint8 f = kHelmasaurKing_DrawE_Flags[i] ^ info->flags;
-    SetOamPlain(oam + 0, x, y, kHelmasaurKing_DrawE_Char[i], f, 2);
-    SetOamPlain(oam + 1, x, y + 16, kHelmasaurKing_DrawE_Char[i] + 2, f, 2);
-  }
-  tmp_counter = 0xff;
-  if (submodule_index) {
-    Sprite_CorrectOamEntries(k, 7, 2);
-    Sprite_PrepOamCoordOrDoubleRet(k, info);
-  }
-}
-
-void SpriteDraw_KingHelmasaur_Mouth(int k, PrepOamCoordsRet *info) {  // 9e88bc
-  static const uint8 kHelmasaurKing_DrawF_Y[32] = {
-    1,  2,  3,  4,  5,  6,  7, 8, 9, 10, 10, 10, 10, 10, 10, 10,
-    10, 10, 10, 10, 10, 10, 10, 9, 8,  7,  6,  5,  4,  3,  2,  1,
-  };
-  if (!sprite_delay_aux2[k])
-    return;
-  uint8 yd = kHelmasaurKing_DrawF_Y[sprite_delay_aux2[k] >> 2];
-  Oam_AllocateFromRegionB(4);
-  OamEnt *oam = GetOamCurPtr();
-  SetOamPlain(oam, info->x, info->y + yd + 0x13, 0xaa, info->flags ^ 0xb, 2);
-}
-
-void KingHelmasaur_OperateTail(int k, PrepOamCoordsRet *info) {  // 9e8920
-  static const uint8 kHelmasaurKing_DrawA_Mult[32] = {
-    0xff, 0xf0, 0xe0, 0xd0, 0xc0, 0xb0, 0xa0, 0x90, 0x80, 0x70, 0x60, 0x50, 0x40, 0x30, 0x20, 0x10,
-    0xff, 0xf8, 0xf0, 0xe8, 0xe0, 0xd8, 0xd0, 0xc8, 0xbc, 0xb0, 0xa0, 0x90, 0x70, 0x40, 0x20, 0x10,
-  };
-  static const uint8 kHelmasaurKing_DrawA_MultB[16] = {
-    0xff, 0xf0, 0xe0, 0xd0, 0xc0, 0xb0, 0xa0, 0x90, 0x80, 0x70, 0x60, 0x50, 0x40, 0x30, 0x20, 0x10
-  };
-
-  for (int i = 0; i < 16; i++) {
-    int j = i + (sprite_anim_clock[k] ? 16 : 0);
-    uint16 rs = WORD(overlord_gen1[5]) + WORD(overlord_gen2[1]);
-    uint8 f = (rs >> 8) - 1;
-    uint8 r6 = (uint8)(sign8(f) ? -rs : rs) * kHelmasaurKing_DrawA_Mult[j] >> 8;
-    uint16 angle = (rs & 0xff00) | (sign8(f) ? r6 ^ 0xff : r6);
-    uint8 r15 = overlord_gen1[7] * kHelmasaurKing_DrawA_MultB[i] >> 8;
-    overlord_x_lo[i+5] = HelmasaurSin(angle, r15);
-    overlord_y_lo[i+5] = HelmasaurSin(angle + 0x80, r15) - 40;
-  }
-
-  OamEnt *oam = GetOamCurPtr();
-  bool is_hit = false;
-  for (int i = overlord_gen2[3]; i != 16; i++, oam++) {
-    uint8 x = overlord_x_lo[i + 5] + info->x;
-    uint8 y = overlord_y_lo[i + 5] + info->y;
-    oam->x = x;
-    oam->y = y;
-    oam->charnum = (i == overlord_gen2[3]) ? 0xe4 : 0xac;
-    oam->flags = info->flags ^ 0x1b;
-
-    if (!countdown_for_blink && sprite_anim_clock[k]) {
-      if ((uint8)(link_x_coord - BG2HOFS_copy2 - x + 12) < 24 &&
-          (uint8)(link_y_coord - BG2VOFS_copy2 + 8 - y + 8) < 16) {
-        is_hit = true;
-        link_actual_vel_x = 0;
-        link_actual_vel_y = 56;
-      }
-    }
-  }
-
-  if (is_hit && !flag_block_link_menu)
-    Sprite_AttemptDamageToLinkPlusRecoil(k);
-  Sprite_CorrectOamEntries(k, 16, 2);
-  Sprite_PrepOamCoordOrDoubleRet(k, info);
-  tmp_counter = 16;
-}
-
-void Sprite_MadBatterBolt(int k) {  // 9e8a96
-  static const int8 kMadderBolt_X[8] = {0, 4, 8, 12, 12, 4, 8, 0};
-  static const int8 kMadderBolt_Y[8] = {0, 4, 8, 12, 12, 4, 8, 0};
-
-  if (sprite_subtype2[k] & 16)
-    Oam_AllocateFromRegionB(4);
-  SpriteDraw_SingleSmall(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  if (!sprite_ai_state[k]) {
-    Sprite_MoveXY(k);
-    if (!sprite_delay_main[k])
-      sprite_ai_state[k] = 1;
-  } else {
-    if (++sprite_ai_state[k] == 0)
-      sprite_state[k] = 0;
-    int j = ++sprite_subtype2[k];
-    if (!(j & 7))
-      sound_effect_2 = 48;
-    Sprite_SetX(k, link_x_coord + kMadderBolt_X[j >> 2 & 7]);
-    Sprite_SetY(k, link_y_coord + kMadderBolt_Y[j >> 4 & 7]);
-  }
-}
-
-void Sprite_AA_Pikit(int k) {  // 9e8bbf
-  static const uint8 kPikit_Gfx[24] = {
-    2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
-    3, 3, 3, 3, 2, 2, 2, 2,
-  };
-  static const int8 kPikit_XyOffs[72] = {
-     0,  0,  0,  0,  0,  0,  0,  0,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,  0,  0,  0,  0,  0,  0,  0,   0,   0,   0,   0,   0,   0,   0,   0,
-    12, 16, 24, 32, 32, 24, 16, 12,   0,   0,   0,   0,   0,   0,   0,   0,
-     0,  0,  0,  0,  0,  0,  0,  0, -12, -16, -24, -32, -32, -24, -16, -12,
-     0,  0,  0,  0,  0,  0,  0,  0,
-  };
-  static const uint8 kPikit_Tab0[8] = {24, 24, 0, 48, 48, 48, 0, 24};
-  static const uint8 kPikit_Tab1[8] = {0, 24, 24, 24, 0, 48, 48, 48};
-  int j;
-  Pikit_Draw(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  if (Sprite_ReturnIfRecoiling(k))
-    return;
-  Sprite_CheckDamageToAndFromLink(k);
-  switch(sprite_ai_state[k]) {
-  case 0:  // set next vel
-    if (!sprite_delay_main[k]) {
-      int j;
-      sprite_ai_state[k]++;
-      if (++sprite_C[k] == 4) {
-        sprite_C[k] = 0;
-        j = Sprite_DirectionToFaceLink(k, NULL);
-      } else {
-        j = GetRandomNumber() & 3;
-      }
-      sprite_x_vel[k] = kFluteBoyAnimal_Xvel[j];
-      sprite_y_vel[k] = kZazak_Yvel[j];
-      sprite_z_vel[k] = (GetRandomNumber() & 7) + 19;
-    }
-    sprite_graphics[k] = ++sprite_subtype2[k] >> 3 & 1;
-    break;
-  case 1:  // finish jump then attack
-    Sprite_MoveXYZ(k);
-    Sprite_CheckTileCollision(k);
-    sprite_z_vel[k]--;
-    sprite_z_vel[k]--;
-    if (sign8(sprite_z[k])) {
-      sprite_z[k] = 0;
-      sprite_z_vel[k] = 0;
-      PointU8 pt;
-      Sprite_DirectionToFaceLink(k, &pt);
-      if ((uint8)(pt.x + 48) < 96 && (uint8)(pt.y + 48) < 96) {
-        sprite_ai_state[k]++;
-        ProjectSpeedRet pp = Sprite_ProjectSpeedTowardsLink(k, 31);
-        sprite_D[k] = Sprite_ConvertVelocityToAngle(pp.x, pp.y) >> 1;
-        sprite_delay_main[k] = 95;
-        return;
-      }
-      sprite_ai_state[k] = 0;
-      sprite_delay_main[k] = 16;
-    }
-    sprite_graphics[k] = ++sprite_subtype2[k] >> 3 & 1;
-    break;
-  case 2: { // attempt item grab
-    j = sprite_delay_main[k];
-    if (!j) {
-      sprite_ai_state[k] = 0;
-      sprite_delay_main[k] = 16;
-      sprite_A[k] = 0;
-      sprite_B[k] = 0;
-      sprite_G[k] = 0;
-      return;
-    }
-    j >>= 2;
-    sprite_graphics[k] = kPikit_Gfx[j];
-    int8 xo = kPikit_XyOffs[j + kPikit_Tab0[sprite_D[k]]];
-    int8 yo = kPikit_XyOffs[j + kPikit_Tab1[sprite_D[k]]];
-    sprite_A[k] = xo;
-    sprite_B[k] = yo;
-    if (!sprite_G[k] &&
-        (uint16)(cur_sprite_x + xo - link_x_coord + 12) < 24 &&
-        (uint16)(cur_sprite_y + yo - link_y_coord + 12) < 32 &&
-        sprite_delay_main[k] < 46) {
-      sound_effect_1 = Link_CalculateSfxPan() | 0x26;
-      j = (GetRandomNumber() & 3) + 1;
-      sprite_E[k] = sprite_G[k] = j;
-      if (j == 1) {
-        if (link_item_bombs)
-          link_item_bombs--;
-        else
-          sprite_G[k] = 0;
-      } else if (j == 2) {
-        if (link_num_arrows)
-          link_num_arrows--;
-        else
-          sprite_G[k] = 0;
-      } else if (j == 3) {
-        if (link_rupees_goal)
-          link_rupees_goal--;
-        else
-          sprite_G[k] = 0;
-      } else {
-        sprite_subtype[k] = link_shield_type;
-        if (link_shield_type != 0 && link_shield_type != 3)
-          link_shield_type = 0;
-        else
-          sprite_G[k] = 0;
-      }
-    }
-    break;
-  }
-  }
-}
-
-void Sprite_A8_GreenZirro(int k) {  // 9e8dd2
-  static const uint8 kBomber_Gfx[4] = {9, 10, 8, 7};
-
-  sprite_obj_prio[k] = 0x30;
-  if (sprite_A[k]) {
-    switch (sprite_ai_state[k]) {
-    case 0: // bomberpellet falling
-      SpriteDraw_SingleSmall(k);
-      if (Sprite_ReturnIfInactive(k))
-        return;
-      Sprite_MoveXY(k);
-      Sprite_MoveZ(k);
-      sprite_z_vel[k] -= 2;
-      if (sign8(sprite_z[k])) {
-        sprite_z[k] = 0;
-        sprite_ai_state[k]++;
-        sprite_delay_main[k] = 19;
-        sprite_flags2[k]++;
-        SpriteSfx_QueueSfx2WithPan(k, 0xc);
-      }
-      break;
-    case 1: // bomberpellet exploding
-      SpriteDraw_ZirroBomb(k);
-      if (Sprite_ReturnIfInactive(k))
-        return;
-      if (!(frame_counter & 3))
-        sprite_delay_main[k]++;
-      Sprite_CheckDamageToLink(k);
-      break;
-    }
-    return;
-  }
-
-  if (sprite_delay_aux1[k])
-    sprite_graphics[k] = kBomber_Gfx[sprite_D[k]];
-  sprite_obj_prio[k] |= 0x30;
-  Bomber_Draw(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  if (Sprite_ReturnIfRecoiling(k))
-    return;
-  if (sprite_delay_aux1[k] == 8)
-    Zirro_DropBomb(k);
-  Sprite_CheckDamageToAndFromLink(k);
-  if (!(frame_counter & 1)) {
-    int j = sprite_G[k] & 1;
-    sprite_z_vel[k] += j ? -1 : 1;
-    if (sprite_z_vel[k] == (uint8)(j ? -8 : 8))
-      sprite_G[k]++;
-  }
-  Sprite_MoveZ(k);
-  PointU8 pt;
-  Sprite_DirectionToFaceLink(k, &pt);
-  if ((uint8)(pt.x + 40) < 80 && (uint8)(pt.y + 40) < 80 && player_oam_y_offset != 0x80 &&
-      (link_is_running || sign8(button_b_frames - 9))) {
-    ProjectSpeedRet pp = Sprite_ProjectSpeedTowardsLink(k, 0x30);
-    sprite_x_vel[k] = -pp.x;
-    sprite_y_vel[k] = -pp.y;
-    sprite_delay_main[k] = 8;
-    sprite_ai_state[k] = 2;
-  }
-  switch(sprite_ai_state[k]) {
-  case 0:
-    if (!sprite_delay_main[k]) {
-      static const int8 kBomber_Xvel[8] = {16, 12, 0, -12, -16, -12, 0, 12};
-      static const int8 kBomber_Yvel[8] = {0, 12, 16, 12, 0, -12, -16, -12};
-      static const uint8 kBomber_Tab0[4] = {0, 4, 2, 6};
-      int j;
-      sprite_ai_state[k]++;
-      sprite_B[k]++;
-      if (sprite_B[k] == 3) {
-        sprite_B[k] = 0;
-        sprite_delay_main[k] = 48;
-        j = kBomber_Tab0[Sprite_DirectionToFaceLink(k, NULL)];
-      } else {
-        j = GetRandomNumber();
-        sprite_delay_main[k] = j & 0x1f | 0x20;
-        j &= 7;
-      }
-      sprite_x_vel[k] = kBomber_Xvel[j];
-      sprite_y_vel[k] = kBomber_Yvel[j];
-    }
-    goto set_dir;
-  case 1:
-    if (!sprite_delay_main[k]) {
-      sprite_ai_state[k] = 0;
-      sprite_delay_main[k] = 10;
-      if (sprite_type[k] == 0xa8)
-        sprite_delay_aux1[k] = 16;
-    } else {
-      Sprite_MoveXY(k);
-set_dir:
-      sprite_D[k] = Sprite_DirectionToFaceLink(k, NULL);
-      sprite_graphics[k] = sprite_D[k] << 1 | ++sprite_subtype2[k] >> 3 & 1;
-    }
-    break;
-  case 2:
-    if (!sprite_delay_main[k])
-      sprite_ai_state[k] = 0;
-    sprite_subtype2[k] += 2;
-    Sprite_MoveXY(k);
-    goto set_dir;
-  }
-}
-
-void Zirro_DropBomb(int k) {  // 9e8f81
-  static const int8 kBomber_SpawnPellet_X[4] = {14, -6, 4, 4};
-  static const int8 kBomber_SpawnPellet_Y[4] = {7, 7, 12, -4};
-  SpriteSpawnInfo info;
-  int j = Sprite_SpawnDynamically(k, 0xa8, &info);
-  if (j >= 0) {
-    SpriteSfx_QueueSfx2WithPan(k, 0x20);
-    sprite_z[j] = info.r4_z;
-    int i = sprite_D[j];
-    Sprite_SetX(j, info.r0_x + kBomber_SpawnPellet_X[i]);
-    Sprite_SetY(j, info.r2_y + kBomber_SpawnPellet_Y[i]);
-    sprite_x_vel[j] = kFluteBoyAnimal_Xvel[i];
-    sprite_y_vel[j] = kZazak_Yvel[i];
-    sprite_A[j] = 1;
-    sprite_ignore_projectile[j] = 1;
-    sprite_flags4[j] = 9;
-    sprite_flags3[j] = 0x33;
-    sprite_oam_flags[j] = 0x33 & 15;
-  }
-}
-
-void Sprite_StalfosBone(int k) {  // 9e8fdf
-  StalfosBone_Draw(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  Sprite_CheckDamageToLink(k);
-  sprite_subtype2[k]++;
-  Sprite_MoveXY(k);
-  if (!sprite_delay_main[k] && Sprite_CheckTileCollision(k)) {
-    sprite_state[k] = 0;
-    Sprite_PlaceWeaponTink(k);
-  }
-}
-
-void StalfosBone_Draw(int k) {  // 9e9040
-  static const DrawMultipleData kStalfosBone_Dmd[8] = {
-    {-4, -2, 0x802f, 0},
-    { 4,  2, 0x402f, 0},
-    {-4,  2, 0x002f, 0},
-    { 4, -2, 0xc02f, 0},
-    { 2, -4, 0x403f, 0},
-    {-2,  4, 0x803f, 0},
-    {-2, -4, 0x003f, 0},
-    { 2,  4, 0xc03f, 0},
-  };
-  Sprite_DrawMultiple(k, &kStalfosBone_Dmd[(sprite_subtype2[k] >> 2 & 3) * 2], 2, NULL);
-}
-
-void Sprite_A7_Stalfos(int k) {  // 9e906c
-  if (sprite_A[k]) {
-    Sprite_StalfosBone(k);
-    return;
-  }
-  if (!sprite_E[k]) {
-    Stalfos_Skellington(k);
-    return;
-  }
-  if (!sprite_delay_main[k]) {
-    sprite_x_vel[k] = 1;
-    sprite_y_vel[k] = 1;
-    if (Sprite_CheckTileCollision(k)) {
-      sprite_state[k] = 0;
-      return;
-    }
-    sprite_E[k] = 0;
-    SpriteSfx_QueueSfx2WithPan(k, 0x15);
-    Sprite_SpawnPoofGarnish(k);
-    sprite_delay_aux2[k] = 8;
-    sprite_delay_main[k] = 64;
-    sprite_y_vel[k] = 0;
-    sprite_x_vel[k] = 0;
-  }
-  PrepOamCoordsRet info;
-  Sprite_PrepOamCoord(k, &info);
-}
-
-void Stalfos_Skellington(int k) {  // 9e90b5
-  static const uint8 kStalfos_AnimState2[4] = {8, 9, 10, 11};
-  static const uint8 kStalfos_CheckDir[4] = {3, 2, 1, 0};
-  if (sprite_state[k] == 9 &&
-      (uint16)(link_x_coord - cur_sprite_x + 40) < 80 &&
-      (uint16)(link_y_coord - cur_sprite_y + 48) < 80 &&
-      player_oam_y_offset != 0x80 &&
-      !(sprite_z[k] | sprite_pause[k]) &&
-      sprite_floor[k] == link_is_on_lower_level) {
-    uint8 dir = Sprite_DirectionToFaceLink(k, NULL);
-    if (!link_is_running) {
-      if (button_b_frames >= 0x90)
-        goto if_1;
-      if (!sign8(button_b_frames - 9))
-        goto endif_1;
-    }
-    if (dir != kStalfos_CheckDir[link_direction_facing >> 1]) {
-if_1:
-      sprite_D[k] = dir;
-      ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLink(k, 32);
-      sprite_x_vel[k] = -pt.x;
-      sprite_y_vel[k] = -pt.y;
-      sprite_z_vel[k] = 32;
-      SpriteSfx_QueueSfx3WithPan(k, 0x13);
-      sprite_z[k]++;
-    }
-  }
-endif_1:
-  if (sprite_z[k] == 0) {
-    Sprite_Zazak_Main(k);
-    return;
-  }
-  sprite_graphics[k] = kStalfos_AnimState2[sprite_D[k]];
-  Stalfos_Draw(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  if (sprite_F[k])
-    sprite_z_vel[k] = 0;
-  if (Sprite_ReturnIfRecoiling(k))
-    return;
-  Sprite_CheckDamageToAndFromLink(k);
-  uint8 t = Sprite_CheckTileCollision(k);
-  if (t & 3)
-    sprite_x_vel[k] = 0;
-  if (t & 12)
-    sprite_y_vel[k] = 0;
-  Sprite_MoveXYZ(k);
-  sprite_z_vel[k] -= 2;
-  if (sign8(sprite_z[k] - 1)) {
-    sprite_z[k] = 0;
-    Sprite_ZeroVelocity_XY(k);
-    SpriteSfx_QueueSfx2WithPan(k, 0x21);
-    if (sprite_subtype[k]) {
-      sprite_delay_aux3[k] = 16;
-      sprite_subtype2[k] = 0;
-    }
-  }
-}
-
-void Sprite_Zazak_Main(int k) {  // 9e919f
-  static const uint8 kStalfos_AnimState1[8] = {6, 4, 0, 2, 7, 5, 1, 3};
-  static const uint8 kStalfos_Delay[4] = {16, 32, 64, 32};
-
-  static const int8 kZazak_Yvel[4] = {0, 0, 16, -16};
-  if (sprite_B[k]) {
-    FirePhlegm_Draw(k);
-    if (Sprite_ReturnIfInactive(k))
-      return;
-    sprite_graphics[k] = frame_counter >> 1 & 1;
-    Sprite_CheckDamageToLink(k);
-    Sprite_MoveXY(k);
-    if (Sprite_CheckTileCollision(k)) {
-      sprite_state[k] = 0;
-      Sprite_PlaceRupulseSpark_2(k);
-    }
-    return;
-  }
-  int t = sprite_delay_aux3[k];
-  if (t != 0) {
-    sprite_ai_state[k] = 0;
-    sprite_delay_main[k] = 32;
-    Sprite_ZeroVelocity_XY(k);
-    sprite_head_dir[k] = Sprite_DirectionToFaceLink(k, NULL);
-  }
-  if (t == 1) {
-    Stalfos_ThrowBone(k);
-    sprite_subtype2[k] = 1;
-  }
-  sprite_graphics[k] = kStalfos_AnimState1[(sprite_subtype2[k] & 1) * 4 + sprite_D[k]];
-  if (sprite_type[k] == 0xa7)
-    Stalfos_Draw(k);
-  else
-    Zazak_Draw(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  if (Sprite_ReturnIfRecoiling(k))
-    return;
-  Sprite_CheckDamageToAndFromLink(k);
-  Sprite_MoveXY(k);
-  Sprite_CheckTileCollision(k);
-  switch (sprite_ai_state[k]) {
-  case 0:  // walk then track head
-    if (!sprite_delay_main[k]) {
-      sprite_delay_main[k] = kStalfos_Delay[GetRandomNumber() & 3];
-      sprite_ai_state[k] = 1;
-      int j = sprite_head_dir[k];
-      sprite_D[k] = j;
-      sprite_x_vel[k] = kFluteBoyAnimal_Xvel[j];
-      sprite_y_vel[k] = kZazak_Yvel[j];
-    }
-    break;
-  case 1:  // halt and change dir
-    if (sprite_wallcoll[k] != 0) {
-      sprite_delay_main[k] = 16;
-    } else {
-      if (sprite_delay_main[k] != 0) {
-        if (sign8(--sprite_G[k])) {
-          sprite_G[k] = 11;
-          sprite_subtype2[k]++;
-        }
-        return;
-      } else if (sprite_type[k] == 0xa6 &&
-                 sprite_D[k] == Sprite_DirectionToFaceLink(k, NULL) &&
-                 sprite_floor[k] == link_is_on_lower_level) {
-        sprite_ai_state[k] = 2;
-        sprite_delay_main[k] = 48;
-        sprite_delay_aux1[k] = 48;
-        sprite_y_vel[k] = sprite_x_vel[k] = 0;
-        return;
-      }
-      sprite_delay_main[k] = 32;
-    }
-    sprite_head_dir[k] = kZazak_Dir2[sprite_D[k] * 2 + (GetRandomNumber() & 1)];
-    sprite_ai_state[k] = 0;
-    if (++sprite_C[k] == 4) {
-      sprite_C[k] = 0;
-      sprite_head_dir[k] = Sprite_DirectionToFaceLink(k, NULL);
-      sprite_delay_main[k] = 24;
-    }
-    sprite_y_vel[k] = sprite_x_vel[k] = 0;
-    break;
-  case 2:  // shoot
-    if (!sprite_delay_main[k])
-      sprite_ai_state[k] = 0;
-    else if (sprite_delay_main[k] == 24)
-      Sprite_SpawnFirePhlegm(k);
-    break;
-  }
-}
-
-int Sprite_SpawnFirePhlegm(int k) {  // 9e92e4
-  static const int8 kSpawnFirePhlegm_X[4] = {16, -8, 4, 4};
-  static const int8 kSpawnFirePhlegm_Y[4] = {-2, -2, 8, -20};
-  static const int8 kSpawnFirePhlegm_Xvel[4] = {48, -48, 0, 0};
-  static const int8 kSpawnFirePhlegm_Yvel[4] = {0, 0, 48, -48};
-  SpriteSpawnInfo info;
-  int j = Sprite_SpawnDynamically(k, 0xa5, &info);
-  if (j >= 0) {
-    SpriteSfx_QueueSfx3WithPan(k, 0x5);
-    Sprite_SetSpawnedCoordinates(j, &info);
-    int i = sprite_D[k];
-    Sprite_SetX(j, info.r0_x + kSpawnFirePhlegm_X[i]);
-    Sprite_SetY(j, info.r2_y + kSpawnFirePhlegm_Y[i]);
-    sprite_x_vel[j] = kSpawnFirePhlegm_Xvel[i];
-    sprite_y_vel[j] = kSpawnFirePhlegm_Yvel[i];
-    sprite_flags3[j] |= 0x40;
-    sprite_defl_bits[j] = 0x40;
-    sprite_flags2[j] = 0x21;
-    sprite_B[j] = 0x21;
-    sprite_oam_flags[j] = 2;
-    sprite_flags4[j] = 0x14;
-    sprite_ignore_projectile[j] = 20;
-    sprite_bump_damage[j] = 37;
-    if (link_shield_type >= 3)
-      sprite_flags5[j] = 0x20;
-  }
-  return j;
-}
-
-void Stalfos_ThrowBone(int k) {  // 9e9379
-  SpriteSpawnInfo info;
-  int j = Sprite_SpawnDynamically(k, 0xa7, &info);
-  if (j >= 0) {
-    sprite_A[j] = 1;
-    Sprite_SetSpawnedCoordinates(j, &info);
-    Sprite_ApplySpeedTowardsLink(j, 32);
-    sprite_flags2[j] = 0x21;
-    sprite_ignore_projectile[j] = 33;
-    sprite_flags3[j] |= 0x40;
-    sprite_defl_bits[j] = 0x48;
-    sprite_delay_main[j] = 16;
-    sprite_flags4[j] = 0x14;
-    sprite_oam_flags[j] = 7;
-    sprite_bump_damage[j] = 32;
-    SpriteSfx_QueueSfx2WithPan(k, 0x2);
-  }
-}
-
-void FirePhlegm_Draw(int k) {  // 9e9443
-  static const DrawMultipleData kFirePhlegm_Dmd[16] = {
-    { 0,  0, 0x00c3, 0},
-    {-8,  0, 0x00c2, 0},
-    { 0,  0, 0x80c3, 0},
-    {-8,  0, 0x80c2, 0},
-    { 0,  0, 0x40c3, 0},
-    { 8,  0, 0x40c2, 0},
-    { 0,  0, 0xc0c3, 0},
-    { 8,  0, 0xc0c2, 0},
-    { 0,  0, 0x00d4, 0},
-    { 0, -8, 0x00d3, 0},
-    { 0,  0, 0x40d4, 0},
-    { 0, -8, 0x40d3, 0},
-    { 0,  0, 0x80d4, 0},
-    { 0,  8, 0x80d3, 0},
-    { 0,  0, 0xc0d4, 0},
-    { 0,  8, 0xc0d3, 0},
-  };
-  Sprite_DrawMultiple(k, &kFirePhlegm_Dmd[sprite_D[k] * 4 + sprite_graphics[k] * 2], 2, NULL);
-}
-
-void Sprite_A3_KholdstareShell(int k) {  // 9e9460
-  if (Sprite_ReturnIfPaused(k))
-    return;
-  PointU8 pt;
-  Sprite_DirectionToFaceLink(k, &pt);
-  if ((uint8)(pt.x + 32) < 64 && (uint8)(pt.y + 32) < 64) {
-    Sprite_NullifyHookshotDrag();
-    Sprite_RepelDash();
-  }
-  Sprite_CheckDamageFromLink(k);
-  if (sprite_ai_state[k] == 0) {
-    if (sprite_state[k] == 6) {
-      sprite_flags3[k] = 0xc0;
-      sprite_ai_state[k] = 1;
-      sprite_state[k] = 9;
-    } else if (sprite_hit_timer[k] != 0) {
-      dung_floor_x_offs = (sprite_hit_timer[k] & 2) ? -1 : 1;
-      dung_hdr_collision_2_mirror = 1;
-    } else {
-      dung_hdr_collision_2_mirror = 0;
-    }
-  } else if (sprite_ai_state[k]++ != 18) {
-    KholdstareShell_PaletteFiltering();
-  } else {
-    sprite_state[k] = 0;
-    sprite_ai_state[2] = 2;
-    sprite_delay_main[2] = 128;
-  }
-}
-
-void GenerateIceball(int k) {  // 9e94dd
-  if (++sprite_subtype2[k] & 127 | sprite_delay_aux1[k])
-    return;
-  SpriteSpawnInfo info;
-  int j = Sprite_SpawnDynamically(k, 0xa4, &info);
-  if (j >= 0) {
-    Sprite_SetX(j, link_x_coord);
-    Sprite_SetY(j, link_y_coord);
-    sprite_z[j] = -32;
-    sprite_C[j] = -32;
-    SpriteSfx_QueueSfx2WithPan(j, 0x20);
-  }
-}
-
-void Sprite_A2_Kholdstare(int k) {  // 9e9518
-  int j;
-
-  Kholdstare_Draw(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  if (sprite_ai_state[k] < 2) {
-    Kholdstare_SpawnPuffCloudGarnish(k);
-    if (!(frame_counter & 7))
-      sound_effect_1 = 2;
-  }
-  if (Sprite_ReturnIfRecoiling(k))
-    return;
-
-  if (sign8(--sprite_subtype2[k])) {
-    sprite_subtype2[k] = 10;
-    sprite_graphics[k] = sprite_graphics[k] + 1 & 3;
-  }
-
-  if (!(frame_counter & 3)) {
-    ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLink(k, 31);
-    sprite_A[k] = Sprite_ConvertVelocityToAngle(pt.x, pt.y);
-  }
-
-  Sprite_MoveXY(k);
-  switch(sprite_ai_state[k]) {
-  case 0:  // Accelerate
-    Sprite_CheckDamageToAndFromLink(k);
-    if (!sprite_delay_main[k]) {
-      sprite_ai_state[k] = 1;
-      sprite_delay_main[k] = (GetRandomNumber() & 63) + 32;
-      return;
-    }
-    if (sprite_x_vel[k] - sprite_z_vel[k])
-      sprite_x_vel[k] += sign8(sprite_x_vel[k] - sprite_z_vel[k]) ? 1 : -1;
-    if (sprite_y_vel[k] - sprite_z_subpos[k])
-      sprite_y_vel[k] += sign8(sprite_y_vel[k] - sprite_z_subpos[k]) ? 1 : -1;
-check_coll:
-    j = Sprite_CheckTileCollision(k);
-    if (j & 3) {
-      sprite_x_vel[k] = -sprite_x_vel[k];
-      sprite_z_vel[k] = -sprite_z_vel[k];
-    }
-    if (j & 12) {
-      sprite_y_vel[k] = -sprite_y_vel[k];
-      sprite_z_subpos[k] = -sprite_z_subpos[k];
-    }
-    break;
-  case 1:  // Decelerate
-    Sprite_CheckDamageToAndFromLink(k);
-    if (!sprite_delay_main[k]) {
-      sprite_ai_state[k] = 0;
-      sprite_delay_main[k] = (GetRandomNumber() & 63) + 96;
-      j = GetRandomNumber();
-      if (!(j & 0x1c)) {
-        ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLink(k, 24);
-        sprite_z_vel[k] = pt.x;
-        sprite_z_subpos[k] = pt.y;
-      } else {
-        static const int8 kKholdstare_Target_Xvel[4] = {16, 16, -16, -16};
-        static const int8 kKholdstare_Target_Yvel[4] = {-16, 16, 16, -16};
-        sprite_z_vel[k] = kKholdstare_Target_Xvel[j & 3];
-        sprite_z_subpos[k] = kKholdstare_Target_Yvel[j & 3];
-      }
-    } else {
-      if (sprite_x_vel[k])
-        sprite_x_vel[k] += sign8(sprite_x_vel[k]) ? 1 : -1;
-      if (sprite_y_vel[k])
-        sprite_y_vel[k] += sign8(sprite_y_vel[k]) ? 1 : -1;
-      goto check_coll;
-    }
-    break;
-  case 2:  // Triplicate
-    if (sprite_delay_main[k] == 1) {
-      sprite_state[k] = 0;
-      sprite_state[k + 1] = 0;
-      sprite_state[k + 2] = 0;
-      for (int i = 2; i >= 0; i--) {
-        static const int8 kKholdstare_Triplicate_Tab0[3] = {32, -32, 0};
-        static const int8 kKholdstare_Triplicate_Tab1[3] = {-32, -32, 48};
-        SpriteSpawnInfo info;
-        j = Sprite_SpawnDynamicallyEx(k, 0xa2, &info, 4);
-        assert(j >= 0);
-        if (j >= 0) {
-          Sprite_SetSpawnedCoordinates(j, &info);
-          sprite_z_vel[j] = kKholdstare_Triplicate_Tab0[i];
-          sprite_z_subpos[j] = kKholdstare_Triplicate_Tab1[i];
-          sprite_delay_main[j] = 32;
-        }
-      }
-      tmp_counter = 0xff;
-    } else {
-      sprite_hit_timer[k] |= 0xe0;
-    }
-    break;
-  }
-}
-
-void Kholdstare_SpawnPuffCloudGarnish(int k) {  // 9e96a5
-  static const int8 kNebuleGarnish_XY[8] = {-8, -6, -4, -2, 0, 2, 4, 6};
-  if ((k ^ frame_counter) & 3)
-    return;
-  int j = GarnishAllocLow();
-  if (j < 0)
-    return;
-  garnish_type[j] = 7;
-  garnish_active = 7;
-  garnish_countdown[j] = 31;
-  Garnish_SetX(j, cur_sprite_x + kNebuleGarnish_XY[GetRandomNumber() & 7]);
-  Garnish_SetY(j, cur_sprite_y + kNebuleGarnish_XY[GetRandomNumber() & 7] + 16);
-  garnish_floor[j] = 0;
-}
-
-void Sprite_A4_FallingIce(int k) {  // 9e9710
-  if (!sprite_C[k]) {
-    if (Sprite_ReturnIfInactive(k))
-      return;
-    if (sprite_state[2] < 9 && sprite_state[3] < 9 && sprite_state[4] < 9)
-      sprite_state[k] = 0;
-    GenerateIceball(k);
-    return;
-  }
-
-  sprite_ignore_projectile[k] = 1;
-  sprite_obj_prio[k] = 0x30;
-  SpriteDraw_SingleLarge(k);
-  if (!sprite_ai_state[k])
-    sprite_flags3[k] ^= 16;
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  if (sprite_delay_main[k]) {
-    if (sprite_delay_main[k] == 1)
-      sprite_state[k] = 0;
-    sprite_graphics[k] = (sprite_delay_main[k] >> 3) + 2;
-    return;
-  }
-
-  Sprite_MoveXY(k);
-  if (!sprite_ai_state[k] || (Sprite_CheckDamageToLink(k), !Sprite_CheckTileCollision(k))) {
-    uint8 old_z = sprite_z[k];
-    Sprite_MoveZ(k);
-    if (!sign8(sprite_z_vel[k] + 64))
-      sprite_z_vel[k] -= 3;
-    if (!(sign8(old_z ^ sprite_z[k]) && sign8(sprite_z[k])))
-      return;
-    sprite_z[k] = 0;
-    if (!sprite_ai_state[k]) {
-      sprite_state[k] = 0;
-      IceBall_Split(k);
-      return;
-    }
-  }
-  sprite_delay_main[k] = 15;
-  sprite_oam_flags[k] = 4;
-  if (!sound_effect_1) {
-    SpriteSfx_QueueSfx2WithPan(k, 0x1e);
-    sprite_graphics[k] = 3;
-  }
-}
-
-void IceBall_Split(int k) {  // 9e97cf
-  static const int8 kIceBall_Quadruplicate_Xvel[8] = {0, 32, 0, -32, 24, 24, -24, -24};
-  static const int8 kIceBall_Quadruplicate_Yvel[8] = {-32, 0, 32, 0, -24, 24, -24, 24};
-  SpriteSfx_QueueSfx2WithPan(k, 0x1f);
-  int b = GetRandomNumber() & 4;
-  for (int i = 3; i >= 0; i--) {
-    SpriteSpawnInfo info;
-    int j = Sprite_SpawnDynamically(k, 0xa4, &info);
-    if (j >= 0) {
-      Sprite_SetSpawnedCoordinates(j, &info);
-      sprite_ai_state[j] = 1;
-      sprite_graphics[j] = 1;
-      sprite_C[j] = 1;
-      sprite_z_vel[j] = 32;
-      sprite_x_vel[j] = kIceBall_Quadruplicate_Xvel[i + b];
-      sprite_y_vel[j] = kIceBall_Quadruplicate_Yvel[i + b];
-      sprite_flags4[j] = 0x1c;
-    }
-  }
-  tmp_counter = 0xff;
-}
-
-void Sprite_A1_Freezor(int k) {  // 9e981d
-  Freezor_Draw(k);
-  if (sprite_state[k] != 9) {
-    sprite_ai_state[k] = 3;
-    sprite_delay_main[k] = 31;
-    sprite_ignore_projectile[k] = 31;
-    sprite_state[k] = 9;
-    sprite_hit_timer[k] = 0;
-  }
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  if (sprite_ai_state[k] != 3) {
-    if (Sprite_ReturnIfRecoiling(k))
-      return;
-  }
-  switch(sprite_ai_state[k]) {
-  case 0:  // stasis
-    sprite_ignore_projectile[k]++;
-    if ((uint8)(Sprite_IsRightOfLink(k).b + 16) < 32) {
-      sprite_ai_state[k] = 1;
-      sprite_delay_main[k] = 32;
-    }
-    break;
-  case 1: { // awakening
-    sprite_ignore_projectile[k] = sprite_delay_main[k];
-    if (!sprite_delay_main[k]) {
-      sprite_ai_state[k] = 2;
-      uint16 x = Sprite_GetX(k) - 5;
-      uint16 y = Sprite_GetY(k);
-      Dungeon_UpdateTileMapWithCommonTile(x, y, 8);
-      sprite_delay_aux1[k] = 96;
-      sprite_D[k] = 2;
-      sprite_delay_main[k] = 80;
-    } else {
-      sprite_x_vel[k] = (sprite_delay_main[k] & 1) ? -16 : 16;
-      Sprite_MoveX(k);
-    }
-    break;
-  }
-  case 2: { // moving
-    static const int8 kFreezor_Xvel[4] = {8, -8, 0, 0};
-    static const int8 kFreezor_Yvel[4] = {0, 0, 18, -18};
-    static const uint8 kFreezor_Moving_Gfx[4] = {1, 2, 1, 3};
-    static const int8 kFreezor_Sparkle_X[8] = {-4, -2, 0, 2, 4, 6, 8, 10};
-    Sprite_CheckDamageToLink(k);
-    if (Sprite_CheckDamageFromLink(k))
-      sprite_hit_timer[k] = 0;
-    if (sprite_delay_aux1[k] && !((k ^ frame_counter) & 7)) {
-      Sprite_GarnishSpawn_Sparkle(k, kFreezor_Sparkle_X[GetRandomNumber() & 7], -4);
-    }
-    if (!sprite_delay_main[k])
-      sprite_D[k] = Sprite_DirectionToFaceLink(k, NULL);
-    int j = sprite_D[k];
-    sprite_x_vel[k] = kFreezor_Xvel[j];
-    sprite_y_vel[k] = kFreezor_Yvel[j];
-    if (!(sprite_wallcoll[k] & 15))
-      Sprite_MoveXY(k);
-    Sprite_CheckTileCollision(k);
-    sprite_graphics[k] = kFreezor_Moving_Gfx[(k ^ frame_counter) >> 2 & 3];
-    break;
-  }
-  case 3: {  // melting
-    static const uint8 kFreezor_Melting_Gfx[4] = { 6, 5, 4, 7 };
-    if (!sprite_delay_main[k]) {
-      Sprite_ManuallySetDeathFlagUW(k);
-      sprite_state[k] = 0;
-    }
-    sprite_graphics[k] = kFreezor_Melting_Gfx[sprite_delay_main[k] >> 3];
-    break;
-  }
-  }
-}
-
-void Sprite_9E_HauntedGroveOstritch(int k) {  // 9e995b
-  static const uint8 kFluteBoyOstrich_Gfx[4] = {0, 1, 0, 2};
-  FluteBoyOstrich_Draw(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  switch (sprite_ai_state[k]) {
-  case 0:  // wait
-    sprite_graphics[k] = (frame_counter & 0x18) ? 3 : 0;
-    if (byte_7E0FDD) {
-      sprite_ai_state[k] = 1;
-      sprite_y_vel[k] = -8;
-      sprite_x_vel[k] = -16;
-    }
-    break;
-  case 1:  // run away
-    Sprite_MoveXYZ(k);
-    sprite_z_vel[k] -= 2;
-    if (sign8(sprite_z[k])) {
-      sprite_z_vel[k] = 32;
-      sprite_z[k] = 0;
-      sprite_subtype2[k] = 0;
-      sprite_A[k] = 0;
-    }
-    if (!(++sprite_subtype2[k] & 7) && sprite_A[k] != 3)
-      sprite_A[k]++;
-    sprite_graphics[k] = kFluteBoyOstrich_Gfx[sprite_A[k]];
-    break;
-  }
-}
-
-void FluteBoyOstrich_Draw(int k) {  // 9e9a4b
-  static const DrawMultipleData kFluteBoyOstrich_Dmd[16] = {
-    {-4, -8, 0x0080, 2},
-    { 4, -8, 0x0081, 2},
-    {-4,  8, 0x00a3, 2},
-    { 4,  8, 0x00a4, 2},
-    {-4, -8, 0x0080, 2},
-    { 4, -8, 0x0081, 2},
-    {-4,  8, 0x00a0, 2},
-    { 4,  8, 0x00a1, 2},
-    {-4, -8, 0x0080, 2},
-    { 4, -8, 0x0081, 2},
-    {-4,  8, 0x0083, 2},
-    { 4,  8, 0x0084, 2},
-    {-4, -7, 0x0080, 2},
-    { 4, -7, 0x0081, 2},
-    {-4,  9, 0x00a3, 2},
-    { 4,  9, 0x00a4, 2},
-  };
-  PrepOamCoordsRet info;
-  Sprite_DrawMultiple(k, &kFluteBoyOstrich_Dmd[sprite_graphics[k] * 4], 4, &info);
-  SpriteDraw_Shadow_custom(k, &info, 18);
-}
-
-void Sprite_9F_HauntedGroveRabbit(int k) {  // 9e9a6d
-  sprite_oam_flags[k] = sprite_oam_flags[k] & ~0x40 | kFluteBoyAnimal_OamFlags[sprite_D[k]];
-  SpriteDraw_SingleLarge(k);
-  switch (sprite_ai_state[k]) {
-  case 0:  // wait
-    sprite_graphics[k] = 3;
-    if (byte_7E0FDD) {
-      sprite_ai_state[k] = 1;
-      sprite_D[k] ^= 1;
-      sprite_x_vel[k] = kFluteBoyAnimal_Xvel[sprite_D[k]];
-      sprite_y_vel[k] = -8;
-    }
-    break;
-  case 1:  // run
-    Sprite_MoveXYZ(k);
-    sprite_z_vel[k]-=3;
-    if (sign8(sprite_z[k])) {
-      sprite_z_vel[k] = 24;
-      sprite_z[k] = 0;
-      sprite_subtype2[k] = 0;
-      sprite_A[k] = 0;
-    }
-    sprite_subtype2[k]++;
-    if (!(sprite_subtype2[k] & 3) && sprite_A[k] != 2)
-      sprite_A[k]++;
-    sprite_graphics[k] = kFluteBoyAnimal_Gfx[sprite_A[k]];
-    break;
-  }
-}
-
-void Sprite_A0_HauntedGroveBird(int k) {  // 9e9aec
-  if (sprite_graphics[k] == 3)
-    HauntedGroveBird_Blink(k);
-  sprite_oam_flags[k] = sprite_oam_flags[k] & ~0x40 | kFluteBoyAnimal_OamFlags[sprite_D[k]];
-  oam_cur_ptr += 4;
-  oam_ext_cur_ptr++;
-  sprite_flags2[k]--;
-  SpriteDraw_SingleLarge(k);
-  sprite_flags2[k]++;
-  Sprite_MoveXYZ(k);
-  switch (sprite_ai_state[k]) {
-  case 0:  // wait
-    sprite_graphics[k] = (frame_counter & 0x18) ? 0 : 3;
-    if (byte_7E0FDD) {
-      sprite_ai_state[k] = 1;
-      sprite_D[k] ^= 1;
-      sprite_x_vel[k] = kFluteBoyAnimal_Xvel[sprite_D[k]];
-      sprite_delay_main[k] = 32;
-      sprite_z_vel[k] = 16;
-      sprite_y_vel[k] = -8;
-    }
-    break;
-  case 1:  // rising
-    if (!sprite_delay_main[k]) {
-      sprite_z_vel[k] += 2;
-      if (!sign8(sprite_z_vel[k] - 0x10))
-        sprite_ai_state[k] = 2;
-    }
-    sprite_graphics[k] = (++sprite_subtype2[k] >> 1 & 1) + 1;
-    break;
-  case 2:  // falling
-    sprite_graphics[k] = 1;
-    sprite_z_vel[k] -= 1;
-    if (sign8(sprite_z_vel[k] + 15))
-      sprite_ai_state[k] = 1;
-    break;
-  }
-}
-
-void HauntedGroveBird_Blink(int k) {  // 9e9b9c
-  static const int8 kFluteBoyBird_X[2] = {8, 0};
-  PrepOamCoordsRet info;
-  if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
-    return;
-  OamEnt *oam = GetOamCurPtr();
-  int j = sprite_D[k];
-  oam->x = info.x + kFluteBoyBird_X[j];
-  oam->y = info.y;
-  oam->charnum = 0xae;
-  oam->flags = info.flags | kFluteBoyAnimal_OamFlags[j];
-  Sprite_CorrectOamEntries(k, 0, 0);
-}
-
-void Sprite_9C_Zoro(int k) {  // 9e9bc8
-  if (sprite_E[k])
-    Zoro(k);
-  else
-    Babasu(k);
-//
-}
-
-void Zoro(int k) {  // 9e9bd0
-  if (!sprite_C[k]) {
-    sprite_C[k]++;
-    if (Sprite_IsBelowLink(k).a != 0) {
-      sprite_state[k] = 0;
-      return;
-    }
-  }
-  SpriteDraw_SingleSmall(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  Sprite_CheckDamageToAndFromLink(k);
-  sprite_graphics[k] = ++sprite_subtype2[k] >> 1 & 1;
-  sprite_x_vel[k] = kFluteBoyAnimal_Xvel[sprite_subtype2[k] >> 2 & 1];
-  Sprite_MoveXY(k);
-  if (!sprite_delay_main[k] && Sprite_CheckTileCollision(k))
-    sprite_state[k] = 0;
-
-  if (sprite_subtype2[k] & 3)
-    return;
-
-  int j = GarnishAlloc();
-  if (j < 0)
-    return;
-  garnish_type[j] = 6;
-  garnish_active = 6;
-  Garnish_SetX(j, Sprite_GetX(k));
-  Garnish_SetY(j, Sprite_GetY(k) + 16);
-  garnish_countdown[j] = 10;
-  garnish_sprite[j] = k;
-  garnish_floor[j] = sprite_floor[k];
-}
-
-void Babasu(int k) {  // 9e9c6b
-  static const uint8 kBabusu_Gfx[6] = {5, 4, 3, 2, 1, 0};
-  static const uint8 kBabusu_DirGfx[4] = {6, 6, 0, 0};
-  static const int8 kBabusu_XyVel[6] = {32, -32, 0, 0, 32, -32};
-
-  Babusu_Draw(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  switch(sprite_ai_state[k]) {
-  case 0:  // reset
-    sprite_ai_state[k]++;
-    sprite_delay_main[k] = 128;
-    sprite_graphics[k] = 255;
-    break;
-  case 1:  // hiding
-    if (!sprite_delay_main[k]) {
-      sprite_ai_state[k]++;
-      sprite_delay_main[k] = 55;
-    }
-    break;
-  case 2: { // terror sprinkles
-    int j = sprite_delay_main[k], i = sprite_D[k];
-    if (j == 0) {
-      sprite_ai_state[k] = 3;
-      sprite_x_vel[k] = kBabusu_XyVel[i];
-      sprite_y_vel[k] = kBabusu_XyVel[i + 2];
-      sprite_delay_main[k] = 32;
-    }
-    if (j >= 32) {
-      sprite_graphics[k] = kBabusu_Gfx[(j - 32) >> 2] + kBabusu_DirGfx[i];
-    } else {
-      sprite_graphics[k] = 0xff;
-    }
-    break;
-  }
-  case 3: { // scurry across
-    static const uint8 kBabusu_Scurry_Gfx[4] = {18, 14, 12, 16};
-    Sprite_CheckDamageToAndFromLink(k);
-    Sprite_MoveXY(k);
-    sprite_graphics[k] = (frame_counter >> 1 & 1) + kBabusu_Scurry_Gfx[sprite_D[k]];
-    if (!sprite_delay_main[k] && Sprite_CheckTileCollision(k)) {
-      sprite_D[k] ^= 1;
-      sprite_ai_state[k] = 0;
-    }
-    break;
-  }
-  }
-}
-
-void Sprite_9B_Wizzrobe(int k) {  // 9e9d1b
-  int j;
-  if (sprite_C[k]) {
-    Sprite_Wizzbeam(k);
-    return;
-  }
-  if (sprite_ai_state[k] == 0 || sprite_ai_state[k] & 1 && sprite_delay_main[k] & 1) {
-    PrepOamCoordsRet info;
-    Sprite_PrepOamCoord(k, &info);
-  } else {
-    Wizzrobe_Draw(k);
-  }
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  if (Sprite_ReturnIfRecoiling(k))
-    return;
-  sprite_ignore_projectile[k] = 1;
-  switch(sprite_ai_state[k]) {
-  case 0:  // cloaked
-    if (!sprite_delay_main[k]) {
-      sprite_y_vel[k] = sprite_x_vel[k] = 1;
-      if (!Sprite_CheckTileCollision(k)) {
-        static const uint8 kWizzrobe_Cloak_Gfx[4] = {4, 2, 0, 6};
-        sprite_ai_state[k] = 1;
-        sprite_delay_main[k] = 63;
-        sprite_D[k] = j = Sprite_DirectionToFaceLink(k, NULL);
-        sprite_graphics[k] = kWizzrobe_Cloak_Gfx[j];
-      } else {
-        sprite_state[k] = 0;
-      }
-    }
-    break;
-  case 1:  // phasing in
-    if (!sprite_delay_main[k]) {
-      sprite_ai_state[k] = 2;
-      sprite_delay_main[k] = 63;
-    }
-    break;
-  case 2: {  // attack
-    static const uint8 kWizzrobe_Attack_Gfx[8] = {0, 1, 1, 1, 1, 1, 1, 0};
-    static const uint8 kWizzrobe_Attack_DirGfx[4] = {4, 2, 0, 6};
-    sprite_ignore_projectile[k] = 0;
-    Sprite_CheckDamageToAndFromLink(k);
-    j = sprite_delay_main[k];
-    if (!j) {
-      sprite_ai_state[k] = 3;
-      sprite_delay_main[k] = 63;
-      return;
-    }
-    if (j == 32)
-      Wizzrobe_FireBeam(k);
-    sprite_graphics[k] = kWizzrobe_Attack_Gfx[j >> 3] + kWizzrobe_Attack_DirGfx[sprite_D[k]];
-    break;
-  }
-  case 3:  // phasing out
-    if (!sprite_delay_main[k]) {
-      if (sprite_B[k])
-        sprite_state[k] = 0;
-      sprite_ai_state[k] = 0;
-      sprite_delay_main[k] = (GetRandomNumber() & 31) + 32;
-    }
-    break;
-  }
-}
-
-void Wizzrobe_FireBeam(int k) {  // 9e9e15
-  static const int8 kWizzrobe_Beam_XYvel[6] = {32, -32, 0, 0, 32, -32};
-  SpriteSpawnInfo info;
-  int j = Sprite_SpawnDynamically(k, 0x9b, &info);
-  if (j >= 0) {
-    SpriteSfx_QueueSfx3WithPan(k, 0x36);
-    sprite_C[j] = 1;
-    sprite_ignore_projectile[j] = 1;
-    Sprite_SetX(j, info.r0_x + 4);
-    Sprite_SetY(j, info.r2_y);
-    int i = sprite_D[k];
-    sprite_x_vel[j] = kWizzrobe_Beam_XYvel[i];
-    sprite_y_vel[j] = kWizzrobe_Beam_XYvel[i + 2];
-    sprite_defl_bits[j] = 0x48;
-    sprite_oam_flags[j] = 2;
-    sprite_flags5[j] = link_shield_type == 3 ? 0x20 : 0;
-    sprite_flags4[j] = 0x14;
-  }
-}
-
-void Sprite_9A_Kyameron(int k) {  // 9e9e7b
-  PrepOamCoordsRet info;
-  if (!sprite_ai_state[k])
-    Sprite_PrepOamCoord(k, &info);
-  else
-    Kyameron_Draw(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  if (Sprite_ReturnIfRecoiling(k))
-    return;
-  sprite_ignore_projectile[k] = 1;
-  switch(sprite_ai_state[k]) {
-  case 0:  // reset
-    if (!sprite_delay_main[k]) {
-      sprite_ai_state[k] = 1;
-      sprite_delay_main[k] = (GetRandomNumber() & 63) + 96;
-      sprite_x_lo[k] = sprite_A[k];
-      sprite_x_hi[k] = sprite_B[k];
-      sprite_y_lo[k] = sprite_C[k];
-      sprite_y_hi[k] = sprite_head_dir[k];
-      sprite_subtype2[k] = 5;
-      sprite_graphics[k] = 8;
-    }
-    break;
-  case 1:  // puddleup
-    if (!sprite_delay_main[k]) {
-      sprite_delay_main[k] = 31;
-      sprite_ai_state[k] = 2;
-    }
-    if (sign8(--sprite_subtype2[k])) {
-      sprite_subtype2[k] = 5;
-      sprite_graphics[k] = (sprite_graphics[k] + 1 & 3) + 8;
-    }
-    break;
-  case 2: {  // coagulate
-    static const int8 kKyameron_Coagulate_Gfx[8] = {4, 7, 14, 13, 12, 6, 6, 5};
-    static const int8 kKyameron_Xvel[4] = {32, -32, 32, -32};
-    static const int8 kKyameron_Yvel[4] = {32, 32, -32, -32};
-    int j = sprite_delay_main[k];
-    if (j == 0) {
-      sprite_ai_state[k] = 3;
-      j = Sprite_IsBelowLink(k).a * 2 + Sprite_IsRightOfLink(k).a;
-      sprite_x_vel[k] = kKyameron_Xvel[j];
-      sprite_y_vel[k] = kKyameron_Yvel[j];
-    } else {
-      if (j == 7)
-        Sprite_SetY(k, Sprite_GetY(k) - 29);
-      sprite_graphics[k] = kKyameron_Coagulate_Gfx[j >> 2];
-    }
-    break;
-  }
-  case 3: {  // moving
-    sprite_ignore_projectile[k] = 0;
-    if (!Sprite_CheckDamageToAndFromLink(k)) {
-      Sprite_MoveXY(k);
-      int j = Sprite_CheckTileCollision(k);
-      if (j & 3) {
-        sprite_x_vel[k] = -sprite_x_vel[k];
-        sprite_anim_clock[k]++;
-      }
-      if (j & 12) {
-        sprite_y_vel[k] = -sprite_y_vel[k];
-        sprite_anim_clock[k]++;
-      }
-      if (sprite_anim_clock[k] < 3)
-        goto skip_sound;
-    }
-    sprite_ai_state[k] = 4;
-    sprite_delay_main[k] = 15;
-    SpriteSfx_QueueSfx2WithPan(k, 0x28);
-    static const uint8 kKyameron_Moving_Gfx[4] = {3, 2, 1, 0};
-skip_sound:
-    sprite_graphics[k] = kKyameron_Moving_Gfx[++sprite_subtype2[k] >> 3 & 3];
-    if (!((k ^ frame_counter) & 7)) {
-      uint16 x = (GetRandomNumber() & 0xf) - 4;
-      uint16 y = (GetRandomNumber() & 0xf) - 4;
-      Sprite_GarnishSpawn_Sparkle(k, x, y);
-    }
-    break;
-  }
-  case 4:  // disperse
-    if (!sprite_delay_main[k]) {
-      sprite_anim_clock[k] = 0;
-      sprite_ai_state[k] = 0;
-      sprite_z[k] = 0;
-      sprite_delay_main[k] = 64;
-    } else {
-      sprite_graphics[k] = (sprite_delay_main[k] >> 2) + 15;
-    }
-    break;
-  }
-}
-
-void Kyameron_Draw(int k) {  // 9ea158
-  static const uint8 kKyameron_OamFlags[12] = {0x40, 0, 0, 0, 0, 0, 0, 0, 0, 0x40, 0xc0, 0x80};
-  static const DrawMultipleData kKyameron_Dmd[28] = {
-    { 1,   8, 0x00b4, 0},
-    { 7,   8, 0x00b5, 0},
-    { 4,  -3, 0x0086, 0},
-    { 0, -13, 0x80a2, 2},
-    { 2,   8, 0x00b4, 0},
-    { 6,   8, 0x00b5, 0},
-    { 4,  -6, 0x0096, 0},
-    { 0, -20, 0x00a2, 2},
-    { 4,  -1, 0x0096, 0},
-    { 0, -27, 0x00a2, 2},
-    { 0, -27, 0x00a2, 2},
-    { 0, -27, 0x00a2, 2},
-    {-6,  -6, 0x01df, 0},
-    {14,  -6, 0x41df, 0},
-    {-6,  14, 0x81df, 0},
-    {14,  14, 0xc1df, 0},
-    {-6,  -6, 0x0096, 0},
-    {14,  -6, 0x4096, 0},
-    {-6,  14, 0x8096, 0},
-    {14,  14, 0xc096, 0},
-    {-4,  -4, 0x018d, 0},
-    {12,  -4, 0x418d, 0},
-    {-4,  12, 0x818d, 0},
-    {12,  12, 0xc18d, 0},
-    { 0,   0, 0x018d, 0},
-    { 8,   0, 0x418d, 0},
-    { 0,   8, 0x818d, 0},
-    { 8,   8, 0xc18d, 0},
-  };
-  int j = sprite_graphics[k];
-  if (j < 12) {
-    uint8 bak = sprite_oam_flags[k];
-    sprite_oam_flags[k] = sprite_oam_flags[k] & 0x3f | kKyameron_OamFlags[j];
-    SpriteDraw_SingleLarge(k);
-    sprite_oam_flags[k] = bak;
-  } else {
-    Sprite_DrawMultiple(k, &kKyameron_Dmd[(j - 12) * 4], 4, NULL);
-  }
-}
-
-void Sprite_99_Pengator(int k) {  // 9ea196
-  static const uint8 kPengator_Gfx[4] = {5, 0, 10, 15};
-  sprite_graphics[k] = sprite_A[k] + kPengator_Gfx[sprite_D[k]];
-  Pengator_Draw(k);
-  if (sprite_F[k] || sprite_wallcoll[k] & 15) {
-    sprite_ai_state[k] = 0;
-    sprite_x_vel[k] = 0;
-    sprite_y_vel[k] = 0;
-  }
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  if (Sprite_ReturnIfRecoiling(k))
-    return;
-  Sprite_CheckDamageToAndFromLink(k);
-  Sprite_MoveXYZ(k);
-  sprite_z_vel[k] -= 2;
-  if (sign8(sprite_z[k])) {
-    sprite_z_vel[k] = 0;
-    sprite_z[k] = 0;
-  }
-  Sprite_CheckTileCollision(k);
-  switch(sprite_ai_state[k]) {
-  case 0:  // face player
-    sprite_D[k] = Sprite_DirectionToFaceLink(k, NULL);
-    sprite_ai_state[k] = 1;
-    break;
-  case 1:  // speedup
-    if (!((k ^ frame_counter) & 3)) {
-      static const int8 kPengator_XYVel[6] = { 1, -1, 0, 0, 1, -1 };
-      bool flag = false;
-      int j = sprite_D[k];
-      if (sprite_x_vel[k] != (uint8)kFluteBoyAnimal_Xvel[j])
-        sprite_x_vel[k] += kPengator_XYVel[j], flag = true;
-      if (sprite_y_vel[k] != (uint8)kZazak_Yvel[j])
-        sprite_y_vel[k] += kPengator_XYVel[j + 2], flag = true;
-      if (!flag) {
-        sprite_delay_main[k] = 15;
-        sprite_ai_state[k] = 2;
-      }
-    }
-    sprite_A[k] = (frame_counter & 4) >> 2;
-    break;
-  case 2: { // jump
-    static const uint8 kPengator_Jump[4] = {4, 4, 3, 2};
-    if (!sprite_delay_main[k])
-      sprite_ai_state[k]++;
-    else if (sprite_delay_main[k] == 5)
-      sprite_z_vel[k] = 24;
-    sprite_A[k] = kPengator_Jump[sprite_delay_main[k] >> 2];
-    break;
-  }
-  case 3:  // slide and sparkle
-    if (!((k ^ frame_counter) & 7 | sprite_z[k])) {
-      static const int8 kPengator_Garnish_Y[8] = { 8, 10, 12, 14, 12, 12, 12, 12 };
-      static const int8 kPengator_Garnish_X[8] = { 4, 4, 4, 4, 0, 4, 8, 12 };
-      int i = sprite_D[k];
-      int x = kPengator_Garnish_X[(GetRandomNumber() & 3) + (i >= 2) * 4];
-      int y = kPengator_Garnish_Y[(GetRandomNumber() & 3) + (i >= 2) * 4];
-      Sprite_GarnishSpawn_Sparkle_limited(k, x, y);
-    }
-    break;
-  }
-}
-
-void Pengator_Draw(int k) {  // 9ea415
-  static const DrawMultipleData kPengator_Dmd0[40] = {
-    {-1, -8, 0x0082, 2},
-    { 0,  0, 0x0088, 2},
-    {-1, -7, 0x0082, 2},
-    { 0,  0, 0x008a, 2},
-    {-3, -6, 0x0082, 2},
-    { 0,  0, 0x0088, 2},
-    {-6, -4, 0x0082, 2},
-    { 0,  0, 0x008a, 2},
-    {-4,  0, 0x00a2, 2},
-    { 4,  0, 0x00a3, 2},
-    { 1, -8, 0x4082, 2},
-    { 0,  0, 0x4088, 2},
-    { 1, -7, 0x4082, 2},
-    { 0,  0, 0x408a, 2},
-    { 3, -6, 0x4082, 2},
-    { 0,  0, 0x4088, 2},
-    { 6, -4, 0x4082, 2},
-    { 0,  0, 0x408a, 2},
-    { 4,  0, 0x40a2, 2},
-    {-4,  0, 0x40a3, 2},
-    { 0, -7, 0x0080, 2},
-    { 0,  0, 0x0086, 2},
-    { 0, -7, 0x4080, 2},
-    { 0,  0, 0x4086, 2},
-    { 0, -4, 0x0080, 2},
-    { 0,  0, 0x0086, 2},
-    { 0, -1, 0x0080, 2},
-    { 0,  0, 0x0086, 2},
-    {-8,  0, 0x008e, 2},
-    { 8,  0, 0x408e, 2},
-    { 0, -8, 0x0084, 2},
-    { 0,  0, 0x008c, 2},
-    { 0, -8, 0x4084, 2},
-    { 0,  0, 0x408c, 2},
-    { 0, -7, 0x0084, 2},
-    { 0,  0, 0x008c, 2},
-    { 0,  0, 0x408c, 2},
-    { 0, -6, 0x4084, 2},
-    {-8,  0, 0x00a0, 2},
-    { 8,  0, 0x40a0, 2},
-  };
-  static const DrawMultipleData kPengator_Dmd1[4] = {
-    {0, 16, 0x00b5, 0},
-    {8, 16, 0x40b5, 0},
-    {0, -8, 0x00a5, 0},
-    {8, -8, 0x40a5, 0},
-  };
-  PrepOamCoordsRet info;
-  Sprite_DrawMultiple(k, &kPengator_Dmd0[sprite_graphics[k] * 2], 2, &info);
-  int i;
-  if ((i = 0, sprite_graphics[k] == 14) || (i = 1, sprite_graphics[k] == 19)) {
-    oam_cur_ptr += 8, oam_ext_cur_ptr += 2;
-    Sprite_DrawMultiple(k, &kPengator_Dmd1[i * 2], 2, &info);
-  }
-  SpriteDraw_Shadow(k, &info);
-}
-
-void Sprite_LaserBeam(int k) {  // 9ea462
-  SpriteDraw_SingleSmall(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  LaserBeam_BuildUpGarnish(k);
-  Sprite_MoveXY(k);
-  Sprite_CheckDamageToLink_same_layer(k);
-  if (!sprite_delay_main[k] && Sprite_CheckTileCollision(k)) {
-    sprite_state[k] = 0;
-    SpriteSfx_QueueSfx3WithPan(k, 0x26);
-  }
-}
-
-void LaserBeam_BuildUpGarnish(int k) {  // 9ea488
-  int j = GarnishAllocOverwriteOld();
-  garnish_type[j] = 4;
-  garnish_active = 4;
-  Garnish_SetX(j, Sprite_GetX(k));
-  Garnish_SetY(j, Sprite_GetY(k) + 16);
-  garnish_countdown[j] = 16;
-  garnish_oam_flags[j] = sprite_graphics[k];
-  garnish_sprite[j] = k;
-  garnish_floor[j] = sprite_floor[k];
-}
-
-void Sprite_95_LaserEyeLeft(int k) {  // 9ea541
-  static const uint8 kLaserEye_Dirs[4] = {2, 3, 0, 1};
-  if (sprite_A[k]) {
-    Sprite_LaserBeam(k);
-    return;
-  }
-  LaserEye_Draw(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  switch(sprite_ai_state[k]) {
-  case 0:  // monitor firing zone
-    if (sprite_head_dir[k] == 0 && sprite_D[k] != kLaserEye_Dirs[link_direction_facing >> 1]) {
-      sprite_graphics[k] = 0;
-    } else {
-      uint16 j = (sprite_D[k] < 2) ? link_y_coord - cur_sprite_y : link_x_coord - cur_sprite_x;
-      if ((uint16)(j + 16) < 32) {
-        sprite_delay_main[k] = 32;
-        sprite_ai_state[k] = 1;
-      } else {
-        sprite_graphics[k] = 0;
-      }
-    }
-    break;
-  case 1:  // firing beam
-    sprite_graphics[k] = 1;
-    if (!sprite_delay_main[k]) {
-      sprite_ai_state[k] = 0;
-      LaserEye_FireBeam(k);
-      sprite_delay_aux4[k] = 12;
-    }
-    break;
-  }
-}
-
-void LaserEye_FireBeam(int k) {  // 9ea5d8
-  static const int8 kLaserEye_SpawnXY[6] = {12, -4, 4, 4, 12, -4};
-  static const int8 kLaserEye_SpawnXYVel[6] = {112, -112, 0, 0, 112, -112};
-  SpriteSpawnInfo info;
-  int j = Sprite_SpawnDynamically(k, 0x95, &info);
-  if (j >= 0) {
-    int i = sprite_D[k];
-    sprite_graphics[j] = (i & 2) >> 1;
-    Sprite_SetX(j, info.r0_x + kLaserEye_SpawnXY[i]);
-    Sprite_SetY(j, info.r2_y + kLaserEye_SpawnXY[i + 2]);
-    sprite_x_vel[j] = kLaserEye_SpawnXYVel[i];
-    sprite_y_vel[j] = kLaserEye_SpawnXYVel[i + 2];
-    sprite_flags2[j] = 0x20;
-    sprite_A[j] = 0x20;
-    sprite_oam_flags[j] = 5;
-    sprite_defl_bits[j] = 0x48;
-    sprite_ignore_projectile[j] = 0x48;
-    sprite_delay_main[j] = 5;
-    if (link_shield_type == 3)
-      sprite_flags5[j] = 32;
-    SpriteSfx_QueueSfx3WithPan(k, 0x19);
-  }
-}
-
-void LaserEye_Draw(int k) {  // 9ea708
-  static const DrawMultipleData kLaserEye_Dmd[24] = {
-    { 8, -4, 0x40c8, 0},
-    { 8,  4, 0x40d8, 0},
-    { 8, 12, 0xc0c8, 0},
-    { 8, -4, 0x40c9, 0},
-    { 8,  4, 0x40d9, 0},
-    { 8, 12, 0xc0c9, 0},
-    { 0, -4, 0x00c8, 0},
-    { 0,  4, 0x00d8, 0},
-    { 0, 12, 0x80c8, 0},
-    { 0, -4, 0x00c9, 0},
-    { 0,  4, 0x00d9, 0},
-    { 0, 12, 0x80c9, 0},
-    {-4,  8, 0x00d6, 0},
-    { 4,  8, 0x00d7, 0},
-    {12,  8, 0x40d6, 0},
-    {-4,  8, 0x00c6, 0},
-    { 4,  8, 0x00c7, 0},
-    {12,  8, 0x40c6, 0},
-    {-4,  0, 0x80d6, 0},
-    { 4,  0, 0x80d7, 0},
-    {12,  0, 0xc0d6, 0},
-    {-4,  0, 0x80c6, 0},
-    { 4,  0, 0x80c7, 0},
-    {12,  0, 0xc0c6, 0},
-  };
-  if (sprite_head_dir[k])
-    sprite_graphics[k] = (sprite_delay_aux4[k] == 0);
-  sprite_obj_prio[k] = 0x30;
-  Sprite_DrawMultiple(k, &kLaserEye_Dmd[(sprite_graphics[k] + sprite_D[k] * 2) * 3], 3, NULL);
-}
-
-void Sprite_94_Pirogusu(int k) {  // 9ea742
-  static const uint8 kPirogusu_A0[4] = {2, 3, 0, 1};
-  static const uint8 kPirogusu_A1[8] = {9, 11, 5, 7, 5, 11, 7, 9};
-  static const uint8 kPirogusu_A2[8] = {16, 17, 18, 19, 12, 13, 14, 15};
-  static const int8 kPirogusu_XYvel[6] = {0, 0, 4, -4, 0, 0};
-  static const int8 kPirogusu_XYvel2[6] = {2, -2, 0, 0, 2, -2};
-  static const int8 kPirogusu_XYvel3[6] = {24, -24, 0, 0, 24, -24};
-
-  if (sprite_E[k]) {
-    Sprite_94_Tile(k);
-    return;
-  }
-  sprite_obj_prio[k] |= 0x30;
-  Pirogusu_Draw(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  switch(sprite_ai_state[k]) {
-  case 0:  // wriggle in hole
-    if (!sprite_delay_main[k]) {
-      sprite_ai_state[k] = 1;
-      sprite_delay_main[k] = 31;
-    }
-    sprite_ignore_projectile[k] = sprite_delay_main[k];
-    sprite_A[k] = kPirogusu_A0[sprite_D[k]];
-    break;
-  case 1: { // emerge
-    if (!sprite_delay_main[k]) {
-      sprite_ai_state[k] = 2;
-      sprite_delay_main[k] = 32;
-      sprite_ignore_projectile[k] = 0;
-      Sprite_ZeroVelocity_XY(k);
-    } else {
-      sprite_A[k] = kPirogusu_A1[sprite_delay_main[k] >> 3 & 1 | sprite_D[k] << 1];
-      int j = sprite_D[k];
-      sprite_x_vel[k] = kPirogusu_XYvel[j + 2];
-      sprite_y_vel[k] = kPirogusu_XYvel[j];
-      Sprite_MoveXY(k);
-    }
-    break;
-  }
-  case 2: {  // splash into play
-    Sprite_CheckDamageToAndFromLink(k);
-    Sprite_MoveXY(k);
-    int j = sprite_D[k];
-    sprite_x_vel[k] += kPirogusu_XYvel2[j];
-    sprite_y_vel[k] += kPirogusu_XYvel2[j + 2];
-    if (!sprite_delay_main[k]) {
-      Sprite_SpawnSmallSplash(k);
-      sprite_delay_aux1[k] = 16;
-      sprite_ai_state[k] = 3;
-    }
-    sprite_A[k] = kPirogusu_A2[frame_counter >> 2 & 1 | sprite_D[k] << 1];
-    break;
-  }
-  case 3: { // swim
-    if (Sprite_ReturnIfRecoiling(k))
-      return;
-    Sprite_CheckDamageToAndFromLink(k);
-    sprite_A[k] = kPirogusu_A2[frame_counter >> 2 & 1 | sprite_D[k] << 1] + 8;
-    if (!sprite_delay_aux1[k]) {
-      Pirogusu_SpawnSplash(k);
-      Sprite_MoveXY(k);
-      if (Sprite_CheckTileCollision(k) & 15) {
-        static const uint8 kPirogusu_Dir[8] = {2, 3, 2, 3, 0, 1, 0, 1};
-        sprite_D[k] = kPirogusu_Dir[sprite_D[k] << 1 | GetRandomNumber() & 1];
-      }
-      int j = sprite_D[k];
-      sprite_x_vel[k] = kPirogusu_XYvel3[j];
-      sprite_y_vel[k] = kPirogusu_XYvel3[j + 2];
-    }
-    break;
-  }
-  }
-}
-
-void Pirogusu_SpawnSplash(int k) {  // 9ea897
-  static const uint8 kPirogusu_Tab0[4] = {3, 4, 5, 4};
-  if ((k ^ frame_counter) & 3)
-    return;
-  int x = kPirogusu_Tab0[GetRandomNumber() & 3];
-  int y = kPirogusu_Tab0[GetRandomNumber() & 3];
-  int j = GarnishAllocLow();
-  if (j >= 0) {
-    garnish_type[j] = 11;
-    garnish_active = 11;
-    Garnish_SetX(j, Sprite_GetX(k) + x);
-    Garnish_SetY(j, Sprite_GetY(k) + y + 16);
-    garnish_countdown[j] = 15;
-  }
-}
-
-void Pirogusu_Draw(int k) {  // 9ea93b
-  static const uint8 kPirogusu_OamFlags[28] = {
-       0, 0x80, 0x40,    0, 0,    0,    0, 0x80, 0x80, 0xc0, 0x40, 0x40, 0, 0x40, 0x80, 0xc0,
-    0x40, 0xc0,    0, 0x80, 0, 0x40, 0x80, 0xc0, 0x40, 0xc0,    0, 0x80,
-  };
-  static const uint8 kPirogusu_Gfx[28] = {
-    0, 0, 1, 1, 2, 3, 4, 3, 2, 3, 4, 3, 5, 5, 5, 5,
-    7, 7, 7, 7, 6, 6, 6, 6, 8, 8, 8, 8,
-  };
-  int j = sprite_A[k];
-  sprite_oam_flags[k] = sprite_oam_flags[k] & 0x3f | kPirogusu_OamFlags[j];
-  sprite_graphics[k] = kPirogusu_Gfx[j];
-  if (j < 4) {
-    cur_sprite_x += 4, cur_sprite_y += 4;
-    SpriteDraw_SingleSmall(k);
-  } else {
-    SpriteDraw_SingleLarge(k);
-  }
-}
-
-void Sprite_93_Bumper(int k) {  // 9ea982
-  static const int8 kBumper_Vels[4] = { 0, 2, -2, 0 };
-  Bumper_Draw(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  Sprite_CheckTileCollision(k);
-  if (!link_cape_mode && Sprite_CheckDamageToLink_same_layer(k)) {
-    Link_CancelDash();
-    sprite_delay_main[k] = 32;
-    ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLink(k, 0x30);
-    link_actual_vel_y = pt.y + kBumper_Vels[joypad1H_last >> 2 & 3];
-    link_actual_vel_x = pt.x + kBumper_Vels[joypad1H_last & 3];
-    link_incapacitated_timer = 20;
-    Link_ResetSwimmingState();
-    SpriteSfx_QueueSfx3WithPan(k, 0x32);
-  }
-  for (int j = 15; j >= 0; j--) {
-    if ((j ^ frame_counter) & 3 | sprite_z[j])
-      continue;
-    if (sprite_state[j] < 9 || (sprite_flags3[j] | sprite_flags4[j]) & 0x40)
-      continue;
-    int x = Sprite_GetX(j), y = Sprite_GetY(j);
-    if ((uint16)(cur_sprite_x - x + 16) < 32 && (uint16)(cur_sprite_y - y + 16) < 32) {
-      sprite_F[j] = 15;
-      ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLocation(k, x, y, 0x40);
-      sprite_y_recoil[j] = pt.y;
-      sprite_x_recoil[j] = pt.x;
-      sprite_delay_main[k] = 32;
-      SpriteSfx_QueueSfx3WithPan(k, 0x32);
-    }
-  }
-}
-
-void Bumper_Draw(int k) {  // 9eaa8b
-  static const DrawMultipleData kBumper_Dmd[8] = {
-    {-8, -8, 0x00ec, 2},
-    { 8, -8, 0x40ec, 2},
-    {-8,  8, 0x80ec, 2},
-    { 8,  8, 0xc0ec, 2},
-    {-7, -7, 0x00ec, 2},
-    { 7, -7, 0x40ec, 2},
-    {-7,  7, 0x80ec, 2},
-    { 7,  7, 0xc0ec, 2},
-  };
-  Sprite_DrawMultiple(k, &kBumper_Dmd[(sprite_delay_main[k] >> 1 & 1) * 4], 4, NULL);
-}
-
-void Sprite_91_StalfosKnight(int k) {  // 9eaaa7
-  int j;
-  if (!sprite_ai_state[k]) {
-    PrepOamCoordsRet info;
-    Sprite_PrepOamCoord(k, &info);
-  } else {
-    StalfosKnight_Draw(k);
-  }
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  if ((sprite_hit_timer[k] & 127) == 1) {
-    sprite_hit_timer[k] = 0;
-    sprite_ai_state[k] = 6;
-    sprite_delay_main[k] = 255;
-    sprite_x_vel[k] = 0;
-    sprite_y_vel[k] = 0;
-    enemy_damage_data[0x918] = 2;
-  }
-  if (Sprite_ReturnIfRecoiling(k))
-    return;
-  switch(sprite_ai_state[k]) {
-  case 0: { // waiting for player
-    sprite_flags4[k] = 9;
-    sprite_ignore_projectile[k] = 9;
-    uint8 bak0 = sprite_flags2[k];
-    sprite_flags2[k] |= 128;
-    bool flag = Sprite_CheckDamageToLink(k);
-    sprite_flags2[k] = bak0;
-    if (flag) {
-      sprite_z[k] = 144;
-      sprite_ai_state[k] = 1;
-      sprite_head_dir[k] = 2;
-      sprite_graphics[k] = 2;
-      SpriteSfx_QueueSfx2WithPan(k, 0x20);
-    }
-    break;
-  }
-  case 1: { // falling
-    uint8 old_z = sprite_z[k];
-    Sprite_MoveZ(k);
-    if (!sign8(sprite_z_vel[k] + 64))
-      sprite_z_vel[k] -= 3;
-    if (sign8(old_z ^ sprite_z[k]) && sign8(sprite_z[k])) {
-      sprite_ai_state[k] = 2;
-      sprite_ignore_projectile[k] = 0;
-      sprite_z[k] = 0;
-      sprite_z_vel[k] = 0;
-      sprite_delay_main[k] = 63;
-    }
-    break;
-  }
-  case 2: {  //
-    static const uint8 kStalfosKnight_Case2_Gfx[2] = {0, 1};
-    enemy_damage_data[0x918] = 0;
-    Sprite_CheckDamageToAndFromLink(k);
-    if (!sprite_delay_main[k]) {
-      sprite_ai_state[k] = 3;
-      sprite_B[k] = GetRandomNumber() & 63;
-      sprite_delay_main[k] = 127;
-    } else {
-      sprite_C[k] = sprite_graphics[k] = kStalfosKnight_Case2_Gfx[sprite_delay_main[k] >> 5];
-      sprite_head_dir[k] = 2;
-    }
-    break;
-  }
-  case 3:  //
-    Sprite_CheckDamageToAndFromLink(k);
-    if (sprite_delay_main[k] == sprite_B[k]) {
-      sprite_head_dir[k] = Sprite_IsRightOfLink(k).a;
-      sprite_ai_state[k] = 4;
-      sprite_delay_main[k] = 32;
-    } else {
-      static const uint8 kStalfosKnight_Case2_Dir[16] = {0, 0, 0, 2, 1, 1, 1, 2, 0, 0, 0, 2, 1, 1, 1, 2};
-      sprite_head_dir[k] = kStalfosKnight_Case2_Dir[sprite_delay_main[k] >> 3];
-      sprite_C[k] = 0;
-      sprite_graphics[k] = 0;
-    }
-    break;
-  case 4:  //
-    Sprite_CheckDamageToAndFromLink(k);
-    if (!sprite_delay_main[k]) {
-      sprite_ai_state[k] = 5;
-      sprite_delay_main[k] = 255;
-      sprite_delay_aux1[k] = 32;
-    }
-    sprite_C[k] = 1;
-    sprite_graphics[k] = 1;
-    break;
-  case 5:  //
-    Sprite_CheckDamageToAndFromLink(k);
-    if (sprite_delay_aux1[k] == 0) {
-      Sprite_MoveXYZ(k);
-      Sprite_CheckTileCollision(k);
-      if (!sign8(sprite_z_vel[k] + 64))
-        sprite_z_vel[k] -= 2;
-      if (sign8(sprite_z[k] - 1)) {
-        sprite_z[k] = 0;
-        sprite_z_vel[k] = 0;
-        if (!sprite_delay_main[k])
-          goto SetToGround;
-        sprite_delay_aux1[k] = 16;
-      }
-      sprite_graphics[k] = sign8(sprite_z_vel[k] - 24) ? 2 : 0;
-    } else {
-      if (sprite_delay_aux1[k] == 1) {
-        sprite_z_vel[k] = 48;
-        Sprite_ApplySpeedTowardsLink(k, 16);
-        sprite_head_dir[k] = Sprite_IsRightOfLink(k).a;
-        SpriteSfx_QueueSfx3WithPan(k, 0x13);
-      }
-      sprite_C[k] = 1;
-      sprite_graphics[k] = 1;
-    }
-    break;
-  case 6:  //
-    Sprite_MoveXYZ(k);
-    Sprite_CheckTileCollision(k);
-    if (!sign8(sprite_z_vel[k] + 64))
-      sprite_z_vel[k] -= 2;
-    if (sign8(sprite_z[k] - 1)) {
-      sprite_z[k] = 0;
-      sprite_z_vel[k] = 0;
-    }
-    j = sprite_delay_main[k];
-    if (!j) {
-      if (GetRandomNumber() & 1)
-        goto SetToGround;
-      sprite_ai_state[k] = 7;
-      sprite_delay_main[k] = 80;
-    } else {
-      if (j >= 224 && (j & 3) == 0)
-        SpriteSfx_QueueSfx3WithPan(k, 0x14);
-      static const uint8 kStalfosKnight_Case6_C[32] = {
-        0,  4,  8, 12, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
-        14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 14, 12,  8,  4,  0,
-      };
-      sprite_C[k] = kStalfosKnight_Case6_C[j >> 3];
-      sprite_graphics[k] = 3;
-      sprite_head_dir[k] = 2;
-    }
-    break;
-  case 7:  //
-    if (!sprite_delay_main[k]) {
-SetToGround:
-      sprite_ai_state[k] = 2;
-      sprite_ignore_projectile[k] = 0;
-      sprite_z[k] = 0;
-      sprite_z_vel[k] = 0;
-      sprite_delay_main[k] = 63;
-    } else {
-      static const uint8 kStalfosKnight_Case7_Gfx[2] = {1, 4};
-      sprite_graphics[k] = kStalfosKnight_Case7_Gfx[sprite_delay_main[k] >> 2 & 1];
-    }
-    break;
-  }
-}
-
-void StalfosKnight_Draw(int k) {  // 9eae04
-  static const DrawMultipleData kStalfosKnight_Dmd[35] = {
-    {-4, -8, 0x0064, 0},
-    {-4,  0, 0x0061, 2},
-    { 4,  0, 0x0062, 2},
-    {-3, 16, 0x0074, 0},
-    {11, 16, 0x4074, 0},
-    {-4, -7, 0x0064, 0},
-    {-4,  1, 0x0061, 2},
-    { 4,  1, 0x0062, 2},
-    {-3, 16, 0x0065, 0},
-    {11, 16, 0x4065, 0},
-    {-4, -8, 0x0048, 2},
-    { 4, -8, 0x0049, 2},
-    {-4,  8, 0x004b, 2},
-    { 4,  8, 0x004c, 2},
-    { 4,  8, 0x004c, 2},
-    {-4,  8, 0x0068, 2},
-    { 4,  8, 0x0069, 2},
-    { 4,  8, 0x0069, 2},
-    { 4,  8, 0x0069, 2},
-    { 4,  8, 0x0069, 2},
-    {12, -7, 0x4064, 0},
-    {-4,  1, 0x4062, 2},
-    { 4,  1, 0x4061, 2},
-    {-3, 16, 0x0065, 0},
-    {11, 16, 0x4065, 0},
-    {12, -8, 0x4064, 0},
-    {-4,  0, 0x4062, 2},
-    { 4,  0, 0x4061, 2},
-    {-3, 16, 0x0074, 0},
-    {11, 16, 0x4074, 0},
-    {-4, -8, 0x4049, 2},
-    { 4, -8, 0x4048, 2},
-    {-4,  8, 0x404c, 2},
-    { 4,  8, 0x404b, 2},
-    { 4,  8, 0x404b, 2},
-  };
-  PrepOamCoordsRet info;
-  if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
-    return;
-  SpriteDraw_StalfosKnight_Head(k, &info);
-  oam_cur_ptr += 4, oam_ext_cur_ptr += 1;
-  Sprite_DrawMultiple(k, &kStalfosKnight_Dmd[sprite_graphics[k] * 5], 5, &info);
-  oam_cur_ptr -= 4, oam_ext_cur_ptr -= 1;
-  SpriteDraw_Shadow_custom(k, &info, 18);
-}
-
-void SpriteDraw_StalfosKnight_Head(int k, PrepOamCoordsRet *info) {  // 9eae4e
-  static const uint8 kStalfosKnight_DrawHead_Char[4] = {0x66, 0x66, 0x46, 0x46};
-  static const uint8 kStalfosKnight_DrawHead_Flags[4] = {0x40, 0, 0, 0};
-  if (sprite_graphics[k] == 2)
-    return;
-  int i = sprite_head_dir[k];
-  OamEnt *oam = GetOamCurPtr();
-  SetOamHelper0(oam, info->x, info->y + sprite_C[k] - 12,
-                kStalfosKnight_DrawHead_Char[i],
-                info->flags | kStalfosKnight_DrawHead_Flags[i], 2);
-}
-
-void Sprite_90_Wallmaster(int k) {  // 9eaea4
-  sprite_obj_prio[k] |= 0x30;
-  WallMaster_Draw(k);
-  if (sprite_state[k] != 9) {
-    flag_is_link_immobilized = 0;
-    link_disable_sprite_damage = 0;
-  }
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  if (sprite_A[k]) {
-    link_x_coord = Sprite_GetX(k);
-    link_y_coord = Sprite_GetY(k) - sprite_z[k] + 3;
-    flag_is_link_immobilized = 1;
-    link_disable_sprite_damage = 1;
-    link_incapacitated_timer = 0;
-    link_actual_vel_x = link_actual_vel_y = 0;
-    link_y_vel = link_x_vel = 0;
-    if ((uint16)(link_y_coord - BG2VOFS_copy2 - 16) >= 0x100) {
-      flag_is_link_immobilized = 0;
-      link_disable_sprite_damage = 0;
-      WallMaster_SendPlayerToLastEntrance();
-      Link_Initialize();
-      return;
-    }
-  } else {
-    Sprite_CheckDamageFromLink(k);
-  }
-  switch(sprite_ai_state[k]) {
-  case 0: {  // Descend
-    uint8 old_z = sprite_z[k];
-    Sprite_MoveZ(k);
-    if (!sign8(sprite_z_vel[k] + 64))
-      sprite_z_vel[k] -= 3;
-    if (sign8(old_z ^ sprite_z[k]) && sign8(sprite_z[k])) {
-      sprite_ai_state[k] = 1;
-      sprite_z[k] = 0;
-      sprite_z_vel[k] = 0;
-      sprite_delay_main[k] = 63;
-    }
-    break;
-  }
-  case 1:  // Attempt Grab
-    if (!sprite_delay_main[k])
-      sprite_ai_state[k] = 2;
-
-    sprite_graphics[k] = (sprite_delay_main[k] & 0x20) ? 0 : 1;
-    if (Sprite_CheckDamageToLink(k)) {
-      sprite_A[k] = 1;
-      sprite_flags3[k] = 64;
-      SpriteSfx_QueueSfx3WithPan(k, 0x2a);
-    }
-    break;
-  case 2: {  // Ascend
-    uint8 old_z = sprite_z[k];
-    Sprite_MoveZ(k);
-    if (sign8(sprite_z_vel[k] - 64))
-      sprite_z_vel[k] += 2;
-    if (sign8(old_z ^ sprite_z[k]) && !sign8(sprite_z[k])) {
-      sprite_state[k] = 0;
-    }
-    break;
-  }
-  }
-}
-
-void WallMaster_Draw(int k) {  // 9eafe4
-  static const DrawMultipleData kWallMaster_Dmd[8] = {
-    {-4,  0, 0x01a6, 2},
-    {12,  0, 0x01aa, 0},
-    {-4, 16, 0x01ba, 0},
-    { 4,  8, 0x01a8, 2},
-    {-4,  0, 0x01ab, 2},
-    {12,  0, 0x01af, 0},
-    {-4, 16, 0x01bf, 0},
-    { 4,  8, 0x01ad, 2},
-  };
-  Sprite_DrawMultiple(k, &kWallMaster_Dmd[sprite_graphics[k] * 4], 4, NULL);
-  Sprite_DrawLargeShadow2(k);
-}
-
-void Sprite_8F_Blob(int k) {  // 9eb002
-  if (sprite_state[k] == 9 && sprite_E[k]) {
-    sprite_E[k] = 0;
-    sprite_x_vel[k] = 1;
-    uint8 t = Sprite_CheckTileCollision(k);
-    sprite_x_vel[k] = 0;
-    if (t) {
-      sprite_state[k] = 0;
-      return;
-    }
-    SpriteSfx_QueueSfx2WithPan(k, 0x20);
-  }
-  if (sprite_C[k])
-    sprite_obj_prio[k] = 0x30;
-  Zol_Draw(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-
-  if (sprite_ai_state[k] >= 2) {
-    Sprite_CheckDamageFromLink(k);
-  }
-  if (Sprite_ReturnIfRecoiling(k))
-    return;
-  switch(sprite_ai_state[k]) {
-  case 0: { // hiding unseen
-    uint8 bak = sprite_flags4[k];
-    sprite_flags4[k] |= 9;
-    sprite_flags2[k] |= 0x80;
-    uint8 t = Sprite_CheckDamageToLink(k);
-    sprite_flags4[k] = bak;
-    if (t) {
-      sprite_ai_state[k]++;
-      sprite_delay_main[k] = 127;
-      sprite_flags2[k] &= ~0x80;
-      Sprite_SetX(k, link_x_coord);
-      Sprite_SetY(k, link_y_coord + 8);
-      sprite_delay_aux4[k] = 48;
-      sprite_ignore_projectile[k] = 0;
-    }
-    break;
-  }
-  case 1: { // popping out
-    if (!sprite_delay_main[k]) {
-      sprite_ai_state[k]++;
-      sprite_z_vel[k] = 32;
-      Sprite_ApplySpeedTowardsLink(k, 16);
-      SpriteSfx_QueueSfx3WithPan(k, 0x30);
-    } else {
-      static const int8 kZol_PoppingOutGfx[16] = {0, 1, 7, 7, 6, 6, 5, 5, 6, 6, 5, 5, 4, 4, 4, 4};
-      sprite_graphics[k] = kZol_PoppingOutGfx[sprite_delay_main[k] >> 3];
-    }
-    break;
-  }
-  case 2: { // falling
-    if (sprite_delay_main[k] == 0) {
-      Sprite_CheckDamageFromLink(k);
-      Sprite_MoveXY(k);
-      Sprite_CheckTileCollision(k);
-      uint8 oldz = sprite_z[k];
-      Sprite_MoveZ(k);
-      if (!sign8(sprite_z_vel[k] + 64))
-        sprite_z_vel[k] -= 2;
-      if (sign8(sprite_z[k] ^ oldz) && sign8(sprite_z[k])) {
-        sprite_z_vel[k] = 0;
-        sprite_z[k] = 0;
-        sprite_C[k] = 0;
-        sprite_delay_main[k] = 31;
-        sprite_head_dir[k] = 8;
-      }
-    } else if (sprite_delay_main[k] == 1) {
-      sprite_delay_main[k] = 32;
-      sprite_ai_state[k]++;
-      sprite_graphics[k] = 0;
-    } else {
-      static const int8 kZol_FallingXvel[2] = {-8, 8};
-      static const int8 kZol_FallingGfx[2] = {0, 1};
-      sprite_graphics[k] = kZol_FallingGfx[(sprite_delay_main[k] - 1) >> 4];
-      sprite_x_vel[k] = kZol_FallingXvel[frame_counter >> 1 & 1];
-      Sprite_MoveX(k);
-    }
-    break;
-  }
-  case 3:  // active
-    Sprite_CheckDamageToLink(k);
-    if (!sprite_delay_aux1[k]) {
-      Sprite_ApplySpeedTowardsLink(k, 48);
-      sprite_delay_aux1[k] = GetRandomNumber() & 63 | 96;
-      sprite_oam_flags[k] = sprite_oam_flags[k] & 0x3f | (sign8(sprite_x_vel[k]) ? 0x40 : 0);
-    }
-    if (!sprite_delay_aux2[k]) {
-      sprite_subtype2[k]++;
-      if (!(sprite_subtype2[k] & 14 | sprite_wallcoll[k])) {
-        Sprite_MoveXY(k);
-        if (++sprite_G[k] == sprite_head_dir[k]) {
-          sprite_G[k] = 0;
-          sprite_delay_aux2[k] = (GetRandomNumber() & 31) + 64;
-          sprite_head_dir[k] = GetRandomNumber() & 31 | 16;
-        }
-      }
-      Sprite_CheckTileCollision(k);
-      sprite_graphics[k] = (sprite_subtype2[k] & 8) >> 3;
-    } else {
-      sprite_graphics[k] = sprite_delay_aux2[k] & 0x10 ? 1 : 0;
-    }
-    break;
-  }
-}
-
-void Zol_Draw(int k) {  // 9eb1c5
-  PrepOamCoordsRet info;
-  if (!(sprite_oam_flags[k] & 1) && byte_7E0FC6 >= 3)
-    return;
-
-  if (sprite_delay_aux4[k])
-    Oam_AllocateFromRegionB(8);
-
-  if (!sprite_ai_state[k]) {
-    Sprite_PrepOamCoord(k, &info);
-    return;
-  }
-  uint8 gfx = sprite_graphics[k];
-  if (gfx < 4) {
-    static const uint8 kZol_OamFlags[4] = {0, 0, 0x40, 0x40};
-    uint8 bak1 = sprite_oam_flags[k];
-    sprite_oam_flags[k] = bak1 ^ kZol_OamFlags[gfx];
-    sprite_graphics[k] = gfx + ((sprite_oam_flags[k] & 1 ^ 1) << 2);
-    SpriteDraw_SingleLarge(k);
-    sprite_graphics[k] = gfx;
-    sprite_oam_flags[k] = bak1;
-  } else {
-    static const DrawMultipleData kZol_Dmd[8] = {
-      {0, 8, 0x036c, 0},
-      {8, 8, 0x036d, 0},
-      {0, 8, 0x0060, 0},
-      {8, 8, 0x0070, 0},
-      {0, 8, 0x4070, 0},
-      {8, 8, 0x4060, 0},
-      {0, 0, 0x0040, 2},
-      {0, 0, 0x0040, 2},
-    };
-    Sprite_DrawMultiple(k, &kZol_Dmd[(gfx - 4) * 2], 2, NULL);
-  }
-}
-
-void Sprite_8E_Terrorpin(int k) {  // 9eb26f
-  int j;
-  static const int8 kTerrorpin_Xvel[8] = {8, -8, 0, 0, 12, -12, 0, 0};
-  static const int8 kTerrorpin_Yvel[8] = {0, 0, 8, -8, 0, 0, 12, -12};
-  static const uint8 kTerrorpin_Oamflags[2] = {0, 0x40};
-  static const int8 kTerrorpin_Overturned_Xvel[2] = {8, -8};
-  SpriteDraw_SingleLarge(k);
-  Sprite_CheckTileCollision(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  if (Sprite_ReturnIfRecoiling(k))
-    return;
-  if (!sprite_delay_aux2[k])
-    Sprite_CheckDamageFromLink(k);
-  Terrorpin_CheckForHammer(k);
-  Sprite_MoveXYZ(k);
-  switch (sprite_B[k]) {
-  case 0:  // upright
-    if (!sprite_delay_aux4[k]) {
-      sprite_delay_aux4[k] = (GetRandomNumber() & 31) + 32;
-      sprite_D[k] = Sprite_DirectionToFaceLink(k, NULL);
-    }
-    j = sprite_D[k] + sprite_G[k];
-    sprite_x_vel[k] = kTerrorpin_Xvel[j];
-    sprite_y_vel[k] = kTerrorpin_Yvel[j];
-    sprite_z_vel[k] -= 2;
-    if (sign8(sprite_z[k])) {
-      sprite_z[k] = 0;
-      sprite_z_vel[k] = 0;
-    }
-    sprite_graphics[k] = frame_counter >> (sprite_G[k] ? 2 : 3) & 1;
-    sprite_flags3[k] |= 64;
-    sprite_defl_bits[k] = 4;
-    Sprite_CheckDamageToLink(k);
-    break;
-  case 1:  // overturned
-    sprite_flags3[k] &= 191;
-    sprite_defl_bits[k] = 0;
-    if (!sprite_delay_aux4[k]) {
-      sprite_B[k] = 0;
-      sprite_z_vel[k] = 32;
-      sprite_delay_aux4[k] = 64;
-      return;
-    }
-    sprite_z_vel[k] -= 2;
-    if (sign8(sprite_z[k])) {
-      sprite_z[k] = 0;
-      uint8 t = (uint8)-sprite_z_vel[k] >> 1;
-      sprite_z_vel[k] = (t < 9) ? 0 : t;
-      sprite_x_vel[k] = (int8)sprite_x_vel[k] >> 1;
-      if (sprite_x_vel[k] == 0xff)
-        sprite_x_vel[k] = 0;
-      sprite_y_vel[k] = (int8)sprite_y_vel[k] >> 1;
-      if (sprite_y_vel[k] == 0xff)
-        sprite_y_vel[k] = 0;
-    }
-    if (sprite_delay_aux4[k] < 64) {
-      sprite_x_vel[k] = kTerrorpin_Overturned_Xvel[sprite_delay_aux4[k] >> 1 & 1];
-      sprite_subtype2[k]++;
-    }
-    sprite_graphics[k] = 2;
-    sprite_oam_flags[k] = sprite_oam_flags[k] & ~0x40 | kTerrorpin_Oamflags[++sprite_subtype2[k] >> 3 & 1];
-    break;
-  }
-}
-
-void Terrorpin_CheckForHammer(int k) {  // 9eb3a3
-  if (!(sprite_z[k] | sprite_delay_aux2[k]) &&
-      sprite_floor[k] == link_is_on_lower_level &&
-      player_oam_y_offset != 0x80 &&
-      link_item_in_hand & 0xa) {
-    SpriteHitBox hb;
-    Player_SetupActionHitBox(&hb);
-    Terrorpin_SetUpHammerHitBox(k, &hb);
-    if (CheckIfHitBoxesOverlap(&hb)) {
-      sprite_x_vel[k] = -sprite_x_vel[k];
-      sprite_y_vel[k] = -sprite_y_vel[k];
-      sprite_delay_aux2[k] = 32;
-      sprite_z_vel[k] = 32;
-      sprite_G[k] = 4;
-      sprite_B[k] ^= 1;
-      sprite_delay_aux4[k] = sprite_B[k] ? 0xff : 0x40;
-    }
-  }
-  sprite_head_dir[k] = 0;
-}
-
-void Terrorpin_SetUpHammerHitBox(int k, SpriteHitBox *hb) {  // 9eb405
-  int x = Sprite_GetX(k) - 16;
-  int y = Sprite_GetY(k) - 16;
-  hb->r4_spr_xlo = x;
-  hb->r10_spr_xhi = x >> 8;
-  hb->r5_spr_ylo = y;
-  hb->r11_spr_yhi = y >> 8;
-  hb->r6_spr_xsize = hb->r7_spr_ysize = 48;
-}
-
-void Sprite_8C_Arrghus(int k) {  // 9eb433
-  static const uint8 kArrghus_Gfx[9] = {1, 1, 1, 2, 2, 1, 1, 0, 0};
-  sprite_obj_prio[k] |= 0x30;
-  Arrghus_Draw(k);
-  if (sprite_state[k] != 9 || sprite_z[k] < 96) {
-    if (Sprite_ReturnIfInactive(k))
-      return;
-  }
-  Arrghus_HandlePuffs(k);
-  overlord_x_lo[4] = 1;
-  if ((sprite_hit_timer[k] & 127) == 2) {
-    sprite_ai_state[k] = 3;
-    SpriteSfx_QueueSfx3WithPan(k, 0x32);
-    sprite_subtype2[k] = 0;
-    sprite_flags3[k] = 64;
-  }
-  if (Sprite_ReturnIfRecoiling(k))
-    return;
-  Sprite_CheckDamageToLink(k);
-  if (!(sprite_subtype2[k]++ & 3)) {
-    if (++sprite_G[k] == 9)
-      sprite_G[k] = 0;
-    sprite_graphics[k] = kArrghus_Gfx[sprite_G[k]];
-  }
-
-  uint8 a = Sprite_CheckTileCollision(k);
-  if (a) {
-    if (sprite_ai_state[k] == 5) {
-      if (a & 3)
-        sprite_x_vel[k] = -sprite_x_vel[k];
-      else
-        sprite_y_vel[k] = -sprite_y_vel[k];
-    } else {
-      Sprite_ZeroVelocity_XY(k);
-    }
-  }
-
-  switch (sprite_ai_state[k]) {
-  case 0:  // approach speed
-    if (!sprite_delay_main[k]) {
-      sprite_ai_state[k] = 1;
-      sprite_delay_main[k] = 48;
-    }
-    Sprite_MoveXY(k);
-    Sprite_ApproachTargetSpeed(k, sprite_head_dir[k], sprite_D[k]);
-    break;
-  case 1:  // decelerate
-    if (!sprite_delay_main[k]) {
-      sprite_ai_state[k] = 0;
-      if (!Sprite_CheckIfScreenIsClear()) {
-        if (++overlord_x_lo[3] == 4) {
-          overlord_x_lo[3] = 0;
-          sprite_ai_state[k] = 2;
-          sprite_delay_main[k] = 176;
-        } else {
-          sprite_delay_main[k] = (GetRandomNumber() & 63) + 48;
-          ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLink(k, (sprite_delay_main[k] & 3) + 8);
-          sprite_head_dir[k] = pt.x;
-          sprite_D[k] = pt.y;
-        }
-      } else {
-        sprite_ai_state[k] = 3;
-        SpriteSfx_QueueSfx3WithPan(k, 0x32);
-        sprite_subtype2[k] = 0;
-      }
-    } else {
-      Sprite_MoveXY(k);
-      Sprite_ApproachTargetSpeed(k, 0, 0);
-    }
-    break;
-  case 2:  // case2
-    overlord_x_lo[4] = 8;
-    if (sprite_delay_main[k] < 32) {
-      if (sign8(--overlord_x_lo[2])) {
-        overlord_x_lo[2] = 0;
-        sprite_ai_state[k] = 1;
-        sprite_delay_main[k] = 112;
-      }
-    } else if (sprite_delay_main[k] < 96) {
-      overlord_x_lo[2]++;
-    } else if (sprite_delay_main[k] == 96) {
-      SpriteSfx_QueueSfx3WithPan(k, 0x26);
-    } else if ((sprite_delay_main[k] & 0xf) == 0) {
-      SpriteSfx_QueueSfx3WithPan(k, 0x6);
-    }
-    break;
-  case 3:  // jump way up
-    sprite_z_vel[k] = 120;
-    Sprite_MoveZ(k);
-    if (sprite_z[k] >= 224) {
-      sprite_delay_main[k] = 64;
-      sprite_ai_state[k] = 4;
-      sprite_z_vel[k] = 0;
-      sprite_x_lo[k] = link_x_coord;
-      sprite_y_lo[k] = link_y_coord;
-    }
-    break;
-  case 4: {  // swoosh from above
-    if (!(a = sprite_delay_main[k])) {
-      sprite_z_vel[k] = 144;
-      uint8 old_z = sprite_z[k];
-      Sprite_MoveZ(k);
-      if (sign8(a = old_z ^ sprite_z[k]) && sign8(a = sprite_z[k])) {
-        sprite_z[k] = 0;
-        Sprite_SpawnBigSplash(k);
-        sprite_ai_state[k] = 5;
-        sprite_delay_main[k] = 32;
-        SpriteSfx_QueueSfx3WithPan(k, 0x3);
-        sprite_x_vel[k] = 32;
-        sprite_y_vel[k] = 32;
-      }
-    }
-    if (a == 1) {  // wtf
-      SpriteSfx_QueueSfx2WithPan(k, 0x20);
-    }
-    break;
-  }
-  case 5:  // swim frantically
-    if (!sprite_delay_main[k]) {
-      sprite_flags3[k] = 0;
-      Sprite_MoveXY(k);
-      Sprite_CheckDamageFromLink(k);
-      if (!(frame_counter & 7)) {
-        SpriteSfx_QueueSfx2WithPan(k, 0x28);
-        int j = GarnishAllocLimit(sign8(sprite_y_vel[k]) ? 29 : 14);
-        if (j >= 0) {
-          garnish_type[j] = 21;
-          garnish_active = 21;
-          garnish_x_lo[j] = sprite_x_lo[k];
-          garnish_x_hi[j] = sprite_x_hi[k];
-          garnish_y_lo[j] = sprite_y_lo[k] + 24;  // why no carry propagation
-          garnish_y_hi[j] = sprite_y_hi[k];
-          garnish_countdown[j] = 15;
-        }
-      }
-    }
-    break;
-  }
-}
-
-void Arrghus_Draw(int k) {  // 9eb840
-  static const DrawMultipleData kArrghus_Dmd[5] = {
-    {-8, -4, 0x0080, 2},
-    { 8, -4, 0x4080, 2},
-    {-8, 12, 0x00a0, 2},
-    { 8, 12, 0x40a0, 2},
-    { 0, 24, 0x00a8, 2},
-  };
-  Sprite_DrawMultiple(k, kArrghus_Dmd, 5, NULL);
-  OamEnt *oam = GetOamCurPtr();
-  uint8 chr = sprite_graphics[k] * 2;
-  for (int i = 0; i < 4; i++)
-    oam[i].charnum += chr;
-  if (sprite_ai_state[k] == 5)
-    oam[4].y = 0xf0;
-  if (sprite_subtype2[k] & 8)
-    oam[4].flags |= 0x40;
-
-  if (sprite_ai_state[k] != 5) {
-    oam_cur_ptr += 4, oam_ext_cur_ptr += 1;
-    if (sprite_z[k] < 0xa0) {
-      uint8 bak = sprite_oam_flags[k];
-      sprite_oam_flags[k] &= ~1;
-      SpriteDraw_BigShadow(k, 0);
-      sprite_oam_flags[k] = bak;
-    }
-  } else {
-    Sprite_DrawLargeWaterTurbulence(k);
-  }
-
-}
-
-void Arrghus_HandlePuffs(int k) {  // 9eb8b4
-  static const uint16 kArrgi_Tab0[13] = {0, 0x40, 0x80, 0xc0, 0x100, 0x140, 0x180, 0x1c0, 0, 0x66, 0xcc, 0x132, 0x198};
-  static const uint16 kArrgi_Tab1[13] = {0, 0, 0, 0, 0, 0, 0, 0, 0x1ff, 0x1ff, 0x1ff, 0x1ff, 0x1ff};
-  static const uint8 kArrgi_Tab2[13] = {0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0xc, 0xc, 0xc, 0xc, 0xc};
-  static const int8 kArrgi_Tab3[52] = {
-    0, -1, -2, -3, -4, -5, -6, -6, -5, -4, -3, -2, -1,  0, -1, -2,
-    -3, -4, -5, -6, -6, -5, -4, -3, -2, -1,  0, -1, -2, -3, -4, -5,
-    -6, -6, -5, -4, -3, -2, -1,  0, -1, -2, -3, -4, -5, -6, -6, -5,
-    -4, -3, -2, -1,
-  };
-
-  WORD(overlord_x_lo[0]) += overlord_x_lo[4];
-  if (!(frame_counter & 3) && ++sprite_A[k] == 13)
-    sprite_A[k] = 0;
-  if (!(frame_counter & 7) && ++sprite_B[k] == 13)
-    sprite_B[k] = 0;
-  for(int i = 0; i != 13; i++) {
-    uint16 r0 = (WORD(overlord_x_lo[0]) + kArrgi_Tab0[i]) ^ kArrgi_Tab1[i];
-    uint8 r14 = overlord_x_lo[2] + kArrgi_Tab2[i];
-
-    int8 sin_val = ArrgiSin(r0 + 0x00, r14 + kArrgi_Tab3[sprite_A[k] + i]);
-    int8 cos_val = ArrgiSin(r0 + 0x80, r14 + kArrgi_Tab3[sprite_B[k] + i]);
-
-    int tx = Sprite_GetX(k) + sin_val;
-    overlord_x_hi[i] = tx;
-    overlord_y_hi[i] = tx >> 8;
-
-    int ty = Sprite_GetY(k) + cos_val - 0x10;
-    overlord_gen2[i] = ty;
-    overlord_floor[i] = ty >> 8;
-  }
-  tmp_counter = 13;
-}
-
-void Sprite_8D_Arrghi(int k) {  // 9eb8c4
-  static const uint8 kArrgi_Gfx[8] = {0, 1, 2, 2, 2, 2, 2, 1};
-
-  sprite_obj_prio[k] |= 0x30;
-  SpriteDraw_SingleLarge(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  sprite_graphics[k] = kArrgi_Gfx[++sprite_subtype2[k] >> 3 & 7];
-  if (sprite_B[k]) {
-    int j = sprite_B[k] - 1;
-    if (ancilla_type[j]) {
-      sprite_x_lo[k] = ancilla_x_lo[j];
-      sprite_x_hi[k] = ancilla_x_hi[j];
-      sprite_y_lo[k] = ancilla_y_lo[j];
-      sprite_y_hi[k] = ancilla_y_hi[j];
-      sprite_oam_flags[k] = 5;
-      sprite_flags3[k] &= ~0x40;
-      return;
-    }
-    sprite_ai_state[k] = 1;
-    sprite_B[k] = 0;
-    sprite_delay_main[k] = 32;
-  }
-  if (!sprite_delay_main[k])
-    Sprite_CheckDamageToLink(k);
-
-  if (!sprite_ai_state[k]) {
-    sprite_x_lo[k] = overlord_x_lo[k + 7];
-    sprite_x_hi[k] = overlord_y_lo[k + 7];
-    sprite_y_lo[k] = overlord_gen1[k + 7];
-    sprite_y_hi[k] = overlord_gen3[k + 7];
-    return;
-  }
-  Sprite_CheckDamageFromLink(k);
-  if (!((k ^ frame_counter) & 3)) {
-    uint16 x = overlord_y_lo[k + 7] << 8 | overlord_x_lo[k + 7];
-    uint16 y = overlord_gen3[k + 7] << 8 | overlord_gen1[k + 7];
-    ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLocation(k, x, y, 4);
-    sprite_y_vel[k] = pt.y;
-    sprite_x_vel[k] = pt.x;
-    if ((uint8)(sprite_x_lo[k] - overlord_x_lo[k + 7] + 8) < 16 && (uint8)(sprite_y_lo[k] - overlord_gen1[k + 7] + 8) < 16) {
-      sprite_ai_state[k] = 0;
-      sprite_oam_flags[k] = 0xd;
-      sprite_flags3[k] |= 0x40;
-    }
-  }
-  Sprite_MoveXY(k);
-
-}
-
-void Sprite_8B_Gibdo(int k) {  // 9eb9a9
-  Gibdo_Draw(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  if (Sprite_ReturnIfRecoiling(k))
-    return;
-  Sprite_CheckDamageToAndFromLink(k);
-  switch(sprite_ai_state[k]) {
-  case 0: {
-    static const uint8 kGibdo_DirTarget[4] = {2, 6, 4, 0};
-    static const uint8 kGibdo_Gfx[8] = {4, 8, 11, 10, 0, 6, 3, 7};
-    sprite_graphics[k] = kGibdo_Gfx[sprite_D[k]];
-    if (!(frame_counter & 7)) {
-      int j = sprite_A[k];
-      if (sprite_D[k] - kGibdo_DirTarget[j]) {
-        sprite_D[k] += sign8(sprite_D[k] - kGibdo_DirTarget[j]) ? 1 : -1;
-      } else {
-        sprite_delay_main[k] = (GetRandomNumber() & 31) + 48;
-        sprite_ai_state[k] = 1;
-      }
-    }
-    break;
-  }
-  case 1: {
-    static const int8 kGibdo_XyVel[10] = {-16, 0, 0, 0, 16, 0, 0, 0, -16, 0};
-    static const uint8 kGibdo_Gfx2[8] = {9, 2, 0, 4, 11, 3, 1, 5};
-    int j = sprite_D[k];
-    sprite_x_vel[k] = kGibdo_XyVel[j + 2];
-    sprite_y_vel[k] = kGibdo_XyVel[j];
-    Sprite_MoveXY(k);
-    Sprite_CheckTileCollision(k);
-    if ((!sprite_delay_main[k] || sprite_wallcoll[k]) && (j = Sprite_DirectionToFaceLink(k, NULL)) != sprite_A[k]) {
-      sprite_A[k] = j;
-      sprite_ai_state[k] = 0;
-    } else {
-      if (sign8(--sprite_B[k])) {
-        sprite_B[k] = 14;
-        sprite_subtype2[k]++;
-      }
-      sprite_graphics[k] = kGibdo_Gfx2[(sprite_subtype2[k] & 1) << 2 | sprite_A[k]];
-    }
-    break;
-  }
-  }
-}
-
-void Gibdo_Draw(int k) {  // 9ebb20
-  static const DrawMultipleData kGibdo_Dmd[24] = {
-    {0, -9, 0x0080, 2},
-    {0,  0, 0x008a, 2},
-    {0, -8, 0x0080, 2},
-    {0,  1, 0x408a, 2},
-    {0, -9, 0x0082, 2},
-    {0,  0, 0x008c, 2},
-    {0, -8, 0x0082, 2},
-    {0,  0, 0x008e, 2},
-    {0, -9, 0x0084, 2},
-    {0,  0, 0x00a0, 2},
-    {0, -8, 0x0084, 2},
-    {0,  1, 0x40a0, 2},
-    {0, -9, 0x0086, 2},
-    {0,  0, 0x00a2, 2},
-    {0, -9, 0x0088, 2},
-    {0,  0, 0x00a4, 2},
-    {0, -9, 0x4088, 2},
-    {0,  0, 0x40a4, 2},
-    {0, -9, 0x4082, 2},
-    {0,  0, 0x408c, 2},
-    {0, -9, 0x4086, 2},
-    {0,  0, 0x40a2, 2},
-    {0, -8, 0x4082, 2},
-    {0,  1, 0x408e, 2},
-  };
-  PrepOamCoordsRet info;
-  Sprite_DrawMultiple(k, &kGibdo_Dmd[sprite_graphics[k] * 2], 2, &info);
-  if (!sprite_pause[k])
-    SpriteDraw_Shadow(k, &info);
-}
-
-void Sprite_89_MothulaBeam(int k) {  // 9ebb42
-  SpriteDraw_SingleLarge(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  Sprite_CheckDamageToLink(k);
-  if (!(frame_counter & 1))
-    sprite_oam_flags[k] ^= 0x80;
-  Sprite_MoveXY(k);
-  if (!sprite_delay_main[k] && Sprite_CheckTileCollision(k))
-    sprite_state[k] = 0;
-  if ((k ^ frame_counter) & 3)
-    return;
-  for (int i = 14; i >= 0; i--) {
-    if (garnish_type[i] == 0) {
-      garnish_type[i] = 2;
-      garnish_active = 2;
-      garnish_x_lo[i] = sprite_x_lo[k];
-      garnish_x_hi[i] = sprite_x_hi[k];
-      garnish_y_lo[i] = sprite_y_lo[k];
-      garnish_y_hi[i] = sprite_y_hi[k];
-      garnish_countdown[i] = 16;
-      garnish_sprite[i] = k;
-      garnish_floor[i] = sprite_floor[k];
-      break;
-    }
-  }
-}
-
-void Sprite_94_Tile(int k) {  // 9ebbb9
-  sprite_obj_prio[k] = 0x30;
-  FlyingTile_Draw(k);
-  if (Sprite_ReturnIfPaused(k))
-    return;
-  if (sprite_hit_timer[k])
-    goto lbl_a;
-  sprite_ignore_projectile[k] = 1;
-  switch (sprite_ai_state[k]) {
-  case 0:  // erase tilemap
-    Dungeon_UpdateTileMapWithCommonTile(Sprite_GetX(k), (sprite_y_lo[k] + 8) & 0xff | (sprite_y_hi[k] << 8), 6);
-    sprite_ai_state[k] = 1;
-    sprite_delay_main[k] = 128;
-    break;
-  case 1:  // rise up
-    if (!sprite_delay_main[k]) {
-      sprite_ai_state[k] = 2;
-      sprite_delay_main[k] = 16;
-      Sprite_ApplySpeedTowardsLink(k, 32);
-    } else {
-      if (sprite_delay_main[k] >= 0x40) {
-        sprite_z_vel[k] = 4;
-        Sprite_MoveZ(k);
-      }
-lbl_b:
-      sprite_graphics[k] = ++sprite_subtype2[k] >> 2 & 1;
-      if (!((k ^ frame_counter) & 7))
-        SpriteSfx_QueueSfx2WithPan(k, 0x7);
-    }
-    break;
-  case 2:  // towards player
-    sprite_ignore_projectile[k] = 0;
-    if (sprite_delay_main[k] && (sprite_delay_main[k] & 3) == 0)
-      Sprite_ApplySpeedTowardsLink(k, 32);
-    if (!Sprite_CheckDamageToAndFromLink(k)) {
-      Sprite_MoveXY(k);
-      cur_sprite_y -= sprite_z[k];
-      if (!Sprite_CheckTileCollision(k))
-        goto lbl_b;
-    }
-lbl_a:
-    SpriteSfx_QueueSfx2WithPan(k, 0x1f);
-    sprite_state[k] = 6;
-    sprite_delay_main[k] = 31;
-    sprite_type[k] = 0xec;
-    sprite_hit_timer[k] = 0;
-    sprite_C[k] = 0x80;
-    break;
-  }
-}
-
-void FlyingTile_Draw(int k) {  // 9ebcca
-  static const DrawMultipleData kFlyingTile_Dmd[8] = {
-    {0, 0, 0x00d3, 0},
-    {8, 0, 0x40d3, 0},
-    {0, 8, 0x80d3, 0},
-    {8, 8, 0xc0d3, 0},
-    {0, 0, 0x00c3, 0},
-    {8, 0, 0x40c3, 0},
-    {0, 8, 0x80c3, 0},
-    {8, 8, 0xc0c3, 0},
-  };
-  PrepOamCoordsRet info;
-  Sprite_DrawMultiple(k, &kFlyingTile_Dmd[sprite_graphics[k] * 4], 4, &info);
-  SpriteDraw_Shadow(k, &info);
-}
-
-void Sprite_8A_SpikeBlock(int k) {  // 9ebce8
-  if (!sprite_E[k]) {
-    SpriteDraw_SingleLarge(k);
-    if (Sprite_ReturnIfInactive(k))
-      return;
-    Sprite_CheckDamageToAndFromLink(k);
-    Sprite_MoveXY(k);
-    Sprite_CheckTileCollision(k);
-    if (!sprite_delay_main[k] && (!SpikeBlock_CheckStatueCollision(k) || (sprite_wallcoll[k] & 0xf))) {
-      sprite_delay_main[k] = 4;
-      sprite_x_vel[k] = -sprite_x_vel[k];
-      SpriteSfx_QueueSfx2WithPan(k, 0x5);
-    }
-    return;
-  }
-  Oam_AllocateFromRegionB(4);
-  SpriteDraw_SingleLarge(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  Sprite_CheckDamageToAndFromLink(k);
-  if (sprite_ai_state[k] == 0) {
-    Dungeon_UpdateTileMapWithCommonTile(Sprite_GetX(k), Sprite_GetY(k), 0);
-    sprite_ai_state[k] = 1;
-    sprite_delay_main[k] = 64;
-    sprite_delay_aux1[k] = 105;
-  } else if (sprite_delay_main[k] != 0) {
-    if (sprite_delay_main[k] == 1) {
-      sprite_x_lo[k] = sprite_A[k];
-      sprite_y_lo[k] = sprite_B[k];
-    } else {
-      sprite_x_vel[k] = (sprite_delay_main[k] >> 1) & 1 ? -8 : 8;
-      Sprite_MoveX(k);
-      sprite_x_vel[k] = 0;
-    }
-  } else if (sprite_ai_state[k] == 1) {
-    static const int8 kSpikeBlock_XVelTarget[4] = {32, -32, 0, 0};
-    static const int8 kSpikeBlock_YVelTarget[4] = {0, 0, 32, -32};
-    static const int8 kSpikeBlock_XVelDelta[4] = {1, -1, 0, 0};
-    static const int8 kSpikeBlock_YVelDelta[4] = {0, 0, 1, -1};
-
-    int j = sprite_D[k];
-    if (sprite_x_vel[k] != (uint8)kSpikeBlock_XVelTarget[j])
-      sprite_x_vel[k] += kSpikeBlock_XVelDelta[j];
-    if (sprite_y_vel[k] != (uint8)kSpikeBlock_YVelTarget[j])
-      sprite_y_vel[k] += kSpikeBlock_YVelDelta[j];
-    Sprite_MoveXY(k);
-    if (!sprite_delay_aux1[k]) {
-      Sprite_Get16BitCoords(k);
-      if (Sprite_CheckTileCollision(k)) {
-        sprite_ai_state[k] = 2;
-        sprite_delay_aux1[k] = 64;
-      }
-    }
-  } else if (sprite_delay_aux1[k] == 0) {
-    static const int8 kSpikeBlock_XVel[4] = {-16, 16, 0, 0};
-    static const int8 kSpikeBlock_YVel[4] = {0, 0, -16, 16};
-    int j = sprite_D[k];
-    sprite_x_vel[k] = kSpikeBlock_XVel[j];
-    sprite_y_vel[k] = kSpikeBlock_YVel[j];
-    Sprite_MoveXY(k);
-    if (sprite_x_lo[k] == sprite_A[k] && sprite_y_lo[k] == sprite_B[k]) {
-      sprite_state[k] = 0;
-      Dungeon_UpdateTileMapWithCommonTile(Sprite_GetX(k), Sprite_GetY(k), 2);
-    }
-  }
-}
-
-bool SpikeBlock_CheckStatueCollision(int k) {  // 9ebe19
-  for (int j = 15; j >= 0; j--) {
-    if (!((j ^ frame_counter) & 1) && sprite_state[j] && sprite_type[j] == 0x1c) {
-      int x0 = Sprite_GetX(k), y0 = Sprite_GetY(k);
-      int x1 = Sprite_GetX(j), y1 = Sprite_GetY(j);
-      if ((uint16)(x0 - x1 + 16) < 32 && (uint16)(y0 - y1 + 16) < 32)
-        return false;
-    }
-  }
-  return true;
-}
-
-void Sprite_88_Mothula(int k) {  // 9ebe7e
-  if (enhanced_features0 & kFeatures0_MiscBugFixes) {
-    // L4 sword and L3 spin slash can now damage Mothula
-    enemy_damage_data[0x884] = 1;
-    enemy_damage_data[0x885] = 1;
-  }
-  Mothula_Main(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  Mothula_HandleSpikes(k);
-}
-
-void Mothula_Main(int k) {  // 9ebe88
-  int j;
-  Mothula_Draw(k);
-  if (sprite_state[k] == 11)
-    sprite_ai_state[k] = 0;
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  sprite_flags3[k] = 0;
-  if (sprite_delay_aux3[k])
-    sprite_flags3[k] = 64;
-  if ((sprite_F[k] & 127) == 6) {
-    sprite_F[k] = 0;
-    sprite_delay_aux3[k] = 32;
-    sprite_ai_state[k] = 2;
-    sprite_delay_main[k] = 0;
-    sprite_G[k] = 64;
-  }
-  if (Sprite_ReturnIfRecoiling(k))
-    return;
-  switch(sprite_ai_state[k]) {
-  case 0: // Delay
-    if (!sprite_delay_main[k])
-      sprite_ai_state[k] = 1;
-    break;
-  case 1: // Ascend
-    sprite_z_vel[k] = 8;
-    Sprite_MoveZ(k);
-    sprite_z_vel[k] = 0;
-    if (sprite_z[k] >= 24) {
-      sprite_G[k] = 128;
-      sprite_ai_state[k] = 2;
-      sprite_ignore_projectile[k] = 0;
-      sprite_delay_main[k] = 64;
-    }
-    Mothula_FlapWings(k);
-    break;
-  case 2: // FlyAbout
-    if (!sprite_G[k]) {
-      sprite_delay_main[k] = 63;
-      sprite_ai_state[k] = 3;
-      return;
-    }
-    sprite_G[k]--;
-    Mothula_FlapWings(k);
-    j = sprite_A[k] & 1;
-    sprite_z_vel[k] += j ? -1 : 1;
-    if (sprite_z_vel[k] == (uint8)(j ? -16 : 16))
-      sprite_A[k]++;
-    if (!sprite_delay_main[k]) {
-      if (++sprite_C[k] == 7) {
-        sprite_C[k] = 0;
-        Sprite_ApplySpeedTowardsLink(k, 32);
-        sprite_delay_main[k] = 128;
-      } else {
-        static const int8 kMothula_XYvel[10] = {-16, -12, 0, 12, 16, 12, 0, -12, -16, -12};
-        j = GetRandomNumber() & 7;
-        sprite_x_vel[k] = kMothula_XYvel[j + 2];
-        sprite_y_vel[k] = kMothula_XYvel[j];
-        sprite_delay_main[k] = (GetRandomNumber() & 31) + 64;
-      }
-    }
-    if (!sprite_wallcoll[k])
-      Sprite_MoveXY(k);
-    Sprite_MoveZ(k);
-    if (Sprite_CheckTileCollision(k))
-      sprite_delay_main[k] = 0;
-    Sprite_CheckDamageToAndFromLink(k);
-    sprite_subtype2[k] += 2;
-    break;
-  case 3: // FireBeams
-    Sprite_CheckDamageToAndFromLink(k);
-    if (!sprite_delay_main[k]) {
-      sprite_ai_state[k]--;
-      sprite_G[k] = GetRandomNumber() & 31 | 64;
-    } else {
-      if (sprite_delay_main[k] == 0x20)
-        Mothula_SpawnBeams(k);
-      Mothula_FlapWings(k);
-    }
-    break;
-  }
-}
-
-void Mothula_FlapWings(int k) {  // 9ebf9f
-  static const uint8 kMothula_FlapWingsGfx[4] = {0, 1, 2, 1};
-  int j = ++sprite_subtype2[k] >> 2 & 3;
-  if (j == 0)
-    SpriteSfx_QueueSfx3WithPan(k, 0x2);
-  sprite_graphics[k] = kMothula_FlapWingsGfx[j];
-}
-
-void Mothula_SpawnBeams(int k) {  // 9ebfdf
-  static const int8 kMothula_Beam_Xvel[3] = {-16, 0, 16};
-  static const int8 kMothula_Beam_Yvel[3] = {24, 32, 24};
-  SpriteSfx_QueueSfx3WithPan(k, 0x36);
-  for (int i = 2; i >= 0; i--) {
-    SpriteSpawnInfo info;
-    int j = Sprite_SpawnDynamically(k, 0x89, &info);
-    if (j >= 0) {
-      Sprite_SetSpawnedCoordinates(j, &info);
-      sprite_y_lo[j] = info.r2_y - info.r4_z + 3;
-      sprite_delay_main[j] = 16;
-      sprite_ignore_projectile[j] = 16;
-      sprite_x_lo[j] = info.r0_x + kMothula_Beam_Xvel[i];
-      sprite_x_vel[j] = kMothula_Beam_Xvel[i];
-      sprite_y_vel[j] = kMothula_Beam_Yvel[i];
-      sprite_z[j] = 0;
-    }
-  }
-  tmp_counter = 0xff;
-}
-
-void Mothula_HandleSpikes(int k) {  // 9ec088
-  static const uint8 kMothula_Spike_XLo[30] = {
-    0x38, 0x48, 0x58, 0x68, 0x88, 0x98, 0xa8, 0xb8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xb8,
-    0xa8, 0x98, 0x78, 0x68, 0x58, 0x48, 0x38, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28,
-  };
-  static const uint8 kMothula_Spike_YLo[30] = {
-    0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x48, 0x58, 0x68, 0x78, 0x98, 0xa8, 0xb8, 0xc8,
-    0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xb8, 0xa8, 0x98, 0x78, 0x68, 0x58, 0x48,
-  };
-  static const uint8 kMothula_Spike_Dir[30] = {
-    2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 3,
-    3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0,
-  };
-
-  if (--sprite_head_dir[k])
-    return;
-  sprite_head_dir[k] = 0x40;
-  SpriteSpawnInfo info;
-  int j = Sprite_SpawnDynamically(k, 0x8a, &info);
-  if (j < 0)
-    return;
-  int i = GetRandomNumber() & 0x1f;
-  if (i >= 30) i -= 30;
-  sprite_A[j] = sprite_x_lo[j] = kMothula_Spike_XLo[i];
-  sprite_B[j] = sprite_y_lo[j] = kMothula_Spike_YLo[i] - 1;
-  sprite_D[j] = kMothula_Spike_Dir[i];
-  sprite_E[j] = 1;
-  sprite_x_hi[j] = byte_7E0FB0 + 1;
-  sprite_y_hi[j] = byte_7E0FB1 + 1;
-  sprite_x_vel[j] = 1;
-  Sprite_Get16BitCoords(j);
-  Sprite_CheckTileCollision(j);
-  sprite_x_vel[j] = 0;
-  sprite_x_lo[j] = sprite_A[j];
-  sprite_y_lo[j] = sprite_B[j];
-  if (!sprite_wallcoll[j]) {
-    sprite_state[j] = 0;
-    sprite_head_dir[k] = 1;
-  }
-}
-
-void Sprite_86_Kodongo(int k) {  // 9ec103
-  static const int8 kKodondo_Xvel[4] = {1, -1, 0, 0};
-  static const int8 kKodondo_Yvel[4] = {0, 0, 1, -1};
-  static const uint8 kKodondo_Gfx[8] = {2, 2, 0, 5, 3, 3, 0, 5};
-  static const uint8 kKodondo_OamFlags[8] = {0x40, 0, 0, 0, 0x40, 0, 0x40, 0x40};
-  static const uint8 kKodondo_FlameGfx[8] = {2, 2, 0, 5, 4, 4, 1, 6};
-  int j;
-  SpriteDraw_SingleLarge(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  if (Sprite_ReturnIfRecoiling(k))
-    return;
-  Sprite_CheckDamageToAndFromLink(k);
-  sprite_flags[k] = 0;
-  switch(sprite_ai_state[k]) {
-  case 0:  // choose dir
-    sprite_ai_state[k]++;
-    sprite_D[k] = GetRandomNumber() & 3;
-    sprite_flags[k] = 176;
-    for(;;) {
-      j = sprite_D[k];
-      sprite_x_vel[k] = kKodondo_Xvel[j];
-      sprite_y_vel[k] = kKodondo_Yvel[j];
-      if (!Sprite_CheckTileCollision(k))
-        break;
-      sprite_D[k] = (sprite_D[k] + 1) & 3;
-    }
-    Kodongo_SetDirection(k);
-    break;
-  case 1:  // move
-    Sprite_MoveXY(k);
-    if (Sprite_CheckTileCollision(k)) {
-      sprite_D[k] ^= 1;
-      Kodongo_SetDirection(k);
-    }
-    if ((sprite_x_lo[k] & 0x1f) == 4 && (sprite_y_lo[k] & 0x1f) == 0x1b && (GetRandomNumber() & 3) == 0) {
-      sprite_delay_main[k] = 111;
-      sprite_ai_state[k] = 2;
-      sprite_A[k] = 0;
-    }
-    j = ++sprite_subtype2[k] & 4 | sprite_D[k];
-    sprite_graphics[k] = kKodondo_Gfx[j];
-    sprite_oam_flags[k] = sprite_oam_flags[k] & ~0x40 | kKodondo_OamFlags[j];
-    break;
-  case 2:  // breathe flame
-    if (!sprite_delay_main[k])
-      sprite_ai_state[k] = 0;
-    j = (uint8)(sprite_delay_main[k] - 0x20) < 0x30;
-    if (j && (sprite_delay_main[k] & 0xf) == 0)
-      Kodongo_SpawnFire(k);
-    sprite_graphics[k] = kKodondo_FlameGfx[j * 4 + sprite_D[k]];
-    break;
-  }
-}
-
-void Kodongo_SetDirection(int k) {  // 9ec158
-  int j = sprite_D[k];
-  sprite_x_vel[k] = kFluteBoyAnimal_Xvel[j];
-  sprite_y_vel[k] = kZazak_Yvel[j];
-}
-
-void Kodongo_SpawnFire(int k) {  // 9ec223
-  static const int8 kKodondo_Flame_X[4] = {8, -8, 0, 0};
-  static const int8 kKodondo_Flame_Y[4] = {0, 0, 8, -8};
-  static const int8 kKodondo_Flame_Xvel[4] = {24, -24, 0, 0};
-  static const int8 kKodondo_Flame_Yvel[4] = {0, 0, 24, -24};
-  SpriteSpawnInfo info;
-  int j = Sprite_SpawnDynamicallyEx(k, 0x87, &info, 13);
-  if (j >= 0) {
-    int i = sprite_D[k];
-    Sprite_SetX(j, info.r0_x + kKodondo_Flame_X[i]);
-    Sprite_SetY(j, info.r2_y + kKodondo_Flame_Y[i]);
-    sprite_x_vel[j] = kKodondo_Flame_Xvel[i];
-    sprite_y_vel[j] = kKodondo_Flame_Yvel[i];
-    sprite_ignore_projectile[j] = 1;
-  }
-}
-
-void Sprite_87_KodongoFire(int k) {  // 9ec274
-  static const uint8 kFlame_OamFlags[4] = { 0, 0x40, 0xc0, 0x80 };
-  static const int8 kFlame_Gfx[32] = {
-    5, 4, 3, 1, 2, 0, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0,
-    1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0,
-  };
-
-  if (!sprite_delay_main[k]) {
-    SpriteDraw_SingleLarge(k);
-    if (Sprite_ReturnIfInactive(k))
-      return;
-    sprite_oam_flags[k] = sprite_oam_flags[k] & 0x3f | kFlame_OamFlags[frame_counter >> 2 & 3];
-    if (!Sprite_CheckDamageToLink(k)) {
-      Sprite_MoveXY(k);
-      if (!Sprite_CheckTileCollision(k))
-        return;
-    }
-    sprite_delay_main[k] = 127;
-    sprite_oam_flags[k] &= 63;
-    SpriteSfx_QueueSfx2WithPan(k, 0x2a);
-  } else {
-    if (Sprite_CheckDamageFromLink(k) & kCheckDamageFromPlayer_Carry && !--sprite_delay_main[k] || sprite_delay_main[k] == 1)
-      sprite_state[k] = 0;
-    sprite_graphics[k] = kFlame_Gfx[sprite_delay_main[k] >> 3];
-    Flame_Draw(k);
-    Sprite_CheckDamageToLink(k);
-  }
-}
-
-void Flame_Draw(int k) {  // 9ec35c
-  static const DrawMultipleData kFlame_Dmd[12] = {
-    {0,  0, 0x018e, 2},
-    {0,  0, 0x018e, 2},
-    {0,  0, 0x01a0, 2},
-    {0,  0, 0x01a0, 2},
-    {0,  0, 0x418e, 2},
-    {0, 0, 0x418e, 2},
-    { 0,  0, 0x41a0, 2 },
-    { 0,  0, 0x41a0, 2 },
-    { 0,  0, 0x01a2, 2 },
-    { 0,  0, 0x01a2, 2 },
-    { 0, -6, 0x01a4, 0 },
-    { 8, -6, 0x01a5, 0 },
-  };
-  Sprite_DrawMultiple(k, &kFlame_Dmd[sprite_graphics[k] * 2], 2, NULL);
-}
-
-void Sprite_85_YellowStalfos(int k) {  // 9ec37f
-  static const int8 kYellowStalfos_ObjPrio[6] = {0x30, 0, 0, 0, 0x30, 0};
-  static const int8 kYellowStalfos_Gfx[32] = {
-    8, 5, 1, 1, 8, 5, 1, 1, 8, 5, 1, 1, 7, 4, 2, 2,
-    7, 4, 2, 2, 7, 4, 2, 2, 7, 4, 2, 2, 7, 4, 2, 2,
-  };
-  static const int8 kYellowStalfos_HeadX[32] = {
-    -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, 0, 0, 0, 0,
-    0,     0,     0,     0,    -1,     0,     1,     0,    -1,     0,     1,     0, 0, 0, 0, 0,
-  };
-  static const uint8 kYellowStalfos_HeadY[32] = {
-    13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
-    13, 12, 11, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
-  };
-  static const int8 kYellowStalfos_NeutralizedGfx[16] = {1, 1, 1, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 9};
-  static const int8 kYellowStalfos_NeutralizedHeadY[16] = {10, 10, 10, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7};
-  int j;
-
-  if (!sprite_A[k]) {
-    sprite_x_vel[k] = 1;
-    sprite_y_vel[k] = 1;
-    if (Sprite_CheckTileCollision(k)) {
-      sprite_state[k] = 0;
-      return;
-    }
-    sprite_A[k]++;
-    sprite_C[k] = 10;
-    sprite_flags3[k] |= 64;
-    SpriteSfx_QueueSfx2WithPan(k, 0x20);
-  }
-
-  sprite_obj_prio[k] |= kYellowStalfos_ObjPrio[sprite_ai_state[k]];
-  YellowStalfos_Draw(k);  
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  if (link_sword_type >= 3) {
-    if (Sprite_ReturnIfRecoiling(k))
-      return;
-  } else if (sprite_ai_state[k] != 5 && sprite_hit_timer[k]) {
-    sprite_hit_timer[k] = 0;
-    sprite_ai_state[k] = 5;
-    sprite_delay_main[k] = 255;
-  }
-  sprite_ignore_projectile[k] = 1;
-  switch (sprite_ai_state[k]) {
-  case 0: { // descend
-    sprite_head_dir[k] = 2;
-    uint8 bak0 = sprite_z[k];
-    Sprite_MoveZ(k);
-    if (!sign8(sprite_z_vel[k] - 192))
-      sprite_z_vel[k] -= 3;
-    if (!sign8(bak0) && sign8(sprite_z[k])) {
-      sprite_ai_state[k]++;
-      sprite_z[k] = 0;
-      sprite_z_vel[k] = 0;
-      sprite_delay_main[k] = 64;
-      YellowStalfos_Animate(k);
-    }
-    break;
-  }
-  case 1:  // face player
-    sprite_ignore_projectile[k] = 0;
-    Sprite_CheckDamageToAndFromLink(k);
-    sprite_head_dir[k] = sprite_D[k] = Sprite_DirectionToFaceLink(k, NULL);
-    if (!sprite_delay_main[k]) {
-      sprite_ai_state[k]++;
-      sprite_delay_main[k] = 127;
-    }
-    sprite_flags3[k] &= ~0x40;
-    break;
-  case 2:  // pause then detach head
-    sprite_ignore_projectile[k] = 0;
-    Sprite_CheckDamageToAndFromLink(k);
-    j = sprite_delay_main[k];
-    if (!j) {
-      sprite_ai_state[k]++;
-      sprite_delay_main[k] = 64;
-      return;
-    }
-    if (j == 48)
-      YellowStalfos_EmancipateHead(k);
-    sprite_graphics[k] = kYellowStalfos_Gfx[j >> 2 & ~3 | sprite_D[k]];
-    j = sprite_delay_main[k] >> 2;
-    sprite_B[k] = kYellowStalfos_HeadX[j];
-    sprite_C[k] = kYellowStalfos_HeadY[j];
-    sprite_flags3[k] &= ~0x40;
-    break;
-  case 3:  // delay before ascending
-    sprite_ignore_projectile[k] = 0;
-    Sprite_CheckDamageToAndFromLink(k);
-    if (!sprite_delay_main[k])
-      sprite_ai_state[k]++;
-    YellowStalfos_Animate(k);
-    break;
-  case 4:  // ascend
-    sprite_graphics[k] = 0;
-    sprite_head_dir[k] = 2;
-    j = sprite_z[k];
-    Sprite_MoveZ(k);
-    if (sign8(sprite_z_vel[k] - 64))
-      sprite_z_vel[k] += 2;
-    if (sign8(j) && !sign8(sprite_z[k]))
-      sprite_state[k] = 0;
-    break;
-  case 5:  // neutralized
-    sprite_ignore_projectile[k] = 0;
-    Sprite_CheckDamageFromLink(k);
-    j = sprite_delay_main[k];
-    if (!j)
-      sprite_ai_state[k]--;
-    sprite_graphics[k] = kYellowStalfos_NeutralizedGfx[j >> 4];
-    sprite_C[k] = kYellowStalfos_NeutralizedHeadY[j >> 4];
-    break;
-  }
-}
-
-void YellowStalfos_Animate(int k) {  // 9ec509
-  static const uint8 kYellowStalfos_Gfx2[4] = {6, 3, 1, 1};
-  sprite_graphics[k] = kYellowStalfos_Gfx2[sprite_D[k]];
-  sprite_flags3[k] &= ~0x40;
-}
-
-void YellowStalfos_EmancipateHead(int k) {  // 9ec580
-  SpriteSpawnInfo info;
-  int j = Sprite_SpawnDynamically(k, 2, &info);
-  if (j >= 0) {
-    Sprite_SetSpawnedCoordinates(j, &info);
-    sprite_z[j] = 13;
-    Sprite_ApplySpeedTowardsLink(j, 16);
-    sprite_delay_main[j] = 255;
-    sprite_delay_aux1[j] = 32;
-  }
-}
-
-void YellowStalfos_Draw(int k) {  // 9ec655
-  static const DrawMultipleData kYellowStalfos_Dmd[22] = {
-    {0, 0, 0x000a, 2},
-    {0, 0, 0x000a, 2},
-    {0, 0, 0x000c, 2},
-    {0, 0, 0x000c, 2},
-    {0, 0, 0x002c, 2},
-    {0, 0, 0x002c, 2},
-    {5, 5, 0x002e, 0},
-    {0, 0, 0x0024, 2},
-    {4, 1, 0x003e, 0},
-    {0, 0, 0x0024, 2},
-    {0, 0, 0x000e, 2},
-    {0, 0, 0x000e, 2},
-    {3, 5, 0x402e, 0},
-    {0, 0, 0x4024, 2},
-    {4, 1, 0x403e, 0},
-    {0, 0, 0x4024, 2},
-    {0, 0, 0x400e, 2},
-    {0, 0, 0x400e, 2},
-    {0, 0, 0x002a, 2},
-    {0, 0, 0x002a, 2},
-    {0, 0, 0x002a, 2},
-    {0, 0, 0x002a, 2},
-  };
-  oam_cur_ptr += 4, oam_ext_cur_ptr++;
-  PrepOamCoordsRet info;
-  Sprite_DrawMultiple(k, &kYellowStalfos_Dmd[sprite_graphics[k] * 2], 2, &info);
-  oam_cur_ptr -= 4, oam_ext_cur_ptr--;
-  if (!sprite_pause[k]) {
-    YellowStalfos_DrawHead(k, &info);
-    SpriteDraw_Shadow(k, &info);
-  }
-}
-
-void YellowStalfos_DrawHead(int k, PrepOamCoordsRet *info) {  // 9ec69a
-  static const uint8 kYellowStalfos_Head_Char[4] = {2, 2, 0, 4};
-  static const uint8 kYellowStalfos_Head_Flags[4] = {0x40, 0, 0, 0};
-  OamEnt *oam = GetOamCurPtr();
-  if (sprite_graphics[k] == 10 || sprite_B[k] == 0x80)
-    return;
-  int j = sprite_head_dir[k];
-  SetOamHelper0(oam, info->x + (int8)sprite_B[k], info->y - sprite_C[k],
-                kYellowStalfos_Head_Char[j],
-                kYellowStalfos_Head_Flags[j] | info->flags, 2);
-}
-
-void SpritePrep_Eyegore(int k) {  // 9ec700
-  uint8 t = BYTE(dungeon_room_index2);
-  if (t == 12 || t == 27 || t == 75 || t == 107) {
-    sprite_B[k]++;
-    if (sprite_type[k] == 0x83)
-      sprite_defl_bits[k] = 0;
-  }
-}
-
-void Sprite_83_GreenEyegore(int k) {  // 9ec79b
-  static const int8 kGoriya_Xvel[32] = {
-    0,  16, -16, 0, 0,  13, -13, 0, 0,  13, -13, 0, 0, 0, 0, 0,
-    0, -24,  24, 0, 0, -16,  16, 0, 0, -16,  16, 0, 0, 0, 0, 0,
-  };
-  static const int8 kGoriya_Yvel[32] = {
-    0, 0, 0, 0, -16,  -5,  -5, 0, 16, 13, 13, 0, 0, 0, 0, 0,
-    0, 0, 0, 0, -24, -16, -16, 0, 24, 16, 16, 0, 0, 0, 0, 0,
-  };
-  static const uint8 kGoriya_Dir[32] = {
-    0, 0, 1, 0, 3, 3, 3, 0, 2, 2, 2, 0, 0, 0, 0, 0,
-    0, 1, 0, 0, 3, 3, 3, 0, 2, 2, 2, 0, 0, 0, 0, 0,
-  };
-  static const uint8 kGoriya_Gfx[16] = {8, 6, 0, 3, 9, 7, 1, 4, 8, 6, 0, 3, 9, 7, 2, 5};
-
-  if (!sprite_B[k]) {
-    Eyegore_Main(k);
-    return;
-  }
-  Goriya_Draw(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  if (Sprite_ReturnIfRecoiling(k))
-    return;
-  if (sprite_delay_aux1[k] == 8)
-    Sprite_SpawnFirePhlegm(k);
-  if (bitmask_of_dragstate != 0 || !(joypad1H_last & 0xf)) {
-    sprite_A[k] = 0;
-    Sprite_CheckDamageToAndFromLink(k);
-    Sprite_CheckTileCollision(k);
-    return;
-  }
-
-  int j = (joypad1H_last & 0xf) | (sprite_type[k] == 0x84) * 16;
-  sprite_D[k] = kGoriya_Dir[j];
-  sprite_x_vel[k] = kGoriya_Xvel[j];
-  sprite_y_vel[k] = kGoriya_Yvel[j];
-  if (!sprite_wallcoll[k])
-    Sprite_MoveXY(k);
-  Sprite_CheckDamageToAndFromLink(k);
-  Sprite_CheckTileCollision(k);
-  sprite_graphics[k] = kGoriya_Gfx[++sprite_subtype2[k] & 12 | sprite_D[k]];
-  if (sprite_type[k] == 0x84) {
-    PointU8 pt;
-    uint8 dir = Sprite_DirectionToFaceLink(k, &pt);
-    if (((uint8)(pt.x + 8) < 16 || (uint8)(pt.y + 8) < 16) && sprite_D[k] == dir) {
-      if (!(sprite_A[k] & 0x1f))
-        sprite_delay_aux1[k] = 16;
-      sprite_A[k]++;
-      return;
-    }
-  }
-  sprite_A[k] = 0;
-}
-
-void Eyegore_Main(int k) {  // 9ec839
-  static const uint8 kEyeGore_Closing_Gfx[8] = {0, 0, 1, 1, 2, 2, 2, 2};
-  static const uint8 kEyeGore_Opening_Gfx[8] = {2, 2, 2, 2, 1, 1, 0, 0};
-  static const uint8 kEyeGore_Chasing_Gfx[16] = {7, 5, 2, 9, 8, 6, 3, 10, 7, 5, 2, 9, 8, 6, 4, 11};
-  static const uint8 kEyeGore_Opening_Delay[4] = {0x60, 0x80, 0xa0, 0x80};
-  Eyegore_Draw(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  if (Sprite_ReturnIfRecoiling(k))
-    return;
-  Sprite_CheckDamageToAndFromLink(k);
-  sprite_flags3[k] |= 64;
-  sprite_defl_bits[k] |= 4;
-  switch (sprite_ai_state[k]) {
-  case 0:  // wait until player
-    if (!sprite_delay_main[k]) {
-      PointU8 pt;
-      Sprite_DirectionToFaceLink(k, &pt);
-      if ((uint8)(pt.x + 48) < 96 &&
-          (uint8)(pt.y + 48) < 96) {
-        sprite_ai_state[k]++;
-        sprite_delay_main[k] = 63;
-      }
-    }
-    break;
-  case 1:  // openig eye
-    if (!sprite_delay_main[k]) {
-      sprite_D[k] = Sprite_DirectionToFaceLink(k, NULL);
-      sprite_ai_state[k] = 2;
-      sprite_delay_main[k] = kEyeGore_Opening_Delay[GetRandomNumber() & 3];
-    } else {
-      sprite_graphics[k] = kEyeGore_Opening_Gfx[sprite_delay_main[k] >> 3];
-    }
-    break;
-  case 2:  // chase player
-    sprite_flags3[k] &= ~0x40;
-    if (sprite_type[k] != 0x84)
-      sprite_defl_bits[k] &= ~4;
-    if (!sprite_delay_main[k]) {
-      sprite_delay_main[k] = 63;
-      sprite_ai_state[k]++;
-      sprite_graphics[k] = 0;
-    } else {
-      if (!((k ^ frame_counter) & 31))
-        sprite_D[k] = Sprite_DirectionToFaceLink(k, NULL);
-      int j = sprite_D[k];
-      sprite_x_vel[k] = kFluteBoyAnimal_Xvel[j];
-      sprite_y_vel[k] = kZazak_Yvel[j];
-      if (!sprite_wallcoll[k])
-        Sprite_MoveXY(k);
-      Sprite_CheckTileCollision(k);
-      sprite_graphics[k] = kEyeGore_Chasing_Gfx[++sprite_subtype2[k] & 12 | sprite_D[k]];
-    }
-    break;
-  case 3:  // closing eye
-    if (!sprite_delay_main[k]) {
-      sprite_ai_state[k] = 0;
-      sprite_delay_main[k] = 96;
-    } else {
-      sprite_graphics[k] = kEyeGore_Closing_Gfx[sprite_delay_main[k] >> 3];
-    }
-    break;
-  }
-}
-
-void Eyegore_Draw(int k) {  // 9ecacf
-  static const DrawMultipleData kEyeGore_Dmd[48] = {
-    {-4, -4, 0x00a2, 2},
-    { 4, -4, 0x40a2, 2},
-    {-4,  4, 0x009c, 2},
-    { 4,  4, 0x409c, 2},
-    {-4, -4, 0x00a4, 2},
-    { 4, -4, 0x40a4, 2},
-    {-4,  4, 0x009c, 2},
-    { 4,  4, 0x409c, 2},
-    {-4, -4, 0x008c, 2},
-    { 4, -4, 0x408c, 2},
-    {-4,  4, 0x009c, 2},
-    { 4,  4, 0x409c, 2},
-    {-4, -3, 0x008c, 2},
-    {12, -3, 0x408c, 0},
-    {-4, 13, 0x00bc, 0},
-    { 4,  5, 0x408a, 2},
-    {-4, -3, 0x008c, 0},
-    { 4, -3, 0x408c, 2},
-    {-4,  5, 0x008a, 2},
-    {12, 13, 0x40bc, 0},
-    { 0, -4, 0x00aa, 2},
-    { 0,  4, 0x00a6, 2},
-    { 0, -4, 0x00aa, 2},
-    { 0,  4, 0x00a6, 2},
-    { 0, -3, 0x00aa, 2},
-    { 0,  4, 0x00a8, 2},
-    { 0, -3, 0x00aa, 2},
-    { 0,  4, 0x00a8, 2},
-    { 0, -4, 0x40aa, 2},
-    { 0,  4, 0x40a6, 2},
-    { 0, -4, 0x40aa, 2},
-    { 0,  4, 0x40a6, 2},
-    { 0, -3, 0x40aa, 2},
-    { 0,  4, 0x40a8, 2},
-    { 0, -3, 0x40aa, 2},
-    { 0,  4, 0x40a8, 2},
-    {-4, -4, 0x008e, 2},
-    { 4, -4, 0x408e, 2},
-    {-4,  4, 0x009e, 2},
-    { 4,  4, 0x409e, 2},
-    {-4, -3, 0x008e, 2},
-    {12, -3, 0x408e, 0},
-    {-4, 13, 0x00bd, 0},
-    { 4,  5, 0x40a0, 2},
-    {-4, -3, 0x008e, 0},
-    { 4, -3, 0x408e, 2},
-    {-4,  5, 0x00a0, 2},
-    {12, 13, 0x40bd, 0},
-  };
-  PrepOamCoordsRet info;
-  Sprite_DrawMultiple(k, &kEyeGore_Dmd[sprite_graphics[k] * 4], 4, &info);
-  if (!sprite_pause[k])
-    SpriteDraw_Shadow_custom(k, &info, 14);
-}
-
-void SpritePrep_AntifairyCircle(int k) {  // 9ecb0c
-  static const int8 kBubbleGroup_X[3] = {10, 20, 10};
-  static const int8 kBubbleGroup_Y[3] = {-10, 0, 10};
-  static const int8 kBubbleGroup_Xvel[3] = {18, 0, -18};
-  static const int8 kBubbleGroup_Yvel[3] = {0, 18, 0};
-  static const int8 kBubbleGroup_A[3] = {1, 1, 0};
-  static const int8 kBubbleGroup_B[3] = { 0, 1, 1 };
-  Sprite_SetX(k, Sprite_GetX(k) - 10);
-  sprite_y_vel[k] = -18;
-  sprite_x_vel[k] = 0;
-  sprite_A[k] = 0;
-  sprite_B[k] = 0;
-  tmp_counter = 2;
-  do {
-    SpriteSpawnInfo info;
-    int j = Sprite_SpawnDynamically(k, 0x82, &info);
-    if (j >= 0) {
-      int i = tmp_counter;
-      Sprite_SetX(j, info.r0_x + kBubbleGroup_X[i]);
-      Sprite_SetY(j, info.r2_y + kBubbleGroup_Y[i]);
-      sprite_x_vel[j] = kBubbleGroup_Xvel[i];
-      sprite_y_vel[j] = kBubbleGroup_Yvel[i];
-      sprite_A[j] = kBubbleGroup_A[i];
-      sprite_B[j] = kBubbleGroup_B[i];
-    }
-  } while (!sign8(--tmp_counter));
-}
-
-void Sprite_82_AntifairyCircle(int k) {  // 9ecb97
-  static const int8 kBubbleGroup_Vel[2] = {1, -1};
-  static const uint8 kBubbleGroup_VelTarget[2] = {18, (uint8)-18};
-
-  SpriteDraw_Antfairy(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  int j = sprite_A[k] & 1;
-  if ((sprite_x_vel[k] += kBubbleGroup_Vel[j]) == kBubbleGroup_VelTarget[j])
-    sprite_A[k]++;
-
-  j = sprite_B[k] & 1;
-  if ((sprite_y_vel[k] += kBubbleGroup_Vel[j]) == kBubbleGroup_VelTarget[j])
-    sprite_B[k]++;
-
-  Sprite_MoveXY(k);
-  if (sprite_x_vel[k] && sprite_y_vel[k] && Sprite_CheckIfRoomIsClear()) {
-    sprite_type[k] = 0x15;
-    sprite_x_vel[k] = sign8(sprite_x_vel[k]) ? -16 : 16;
-    sprite_y_vel[k] = sign8(sprite_y_vel[k]) ? -16 : 16;
-  }
-  Sprite_CheckDamageToLink(k);
-}
-
-void Sprite_81_Hover(int k) {  // 9ecc02
-  static const int8 kHover_OamFlags[4] = {0x40, 0, 0x40, 0};
-  sprite_obj_prio[k] |= 48;
-  SpriteDraw_SingleLarge(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  if (sprite_F[k])
-    sprite_ai_state[k] = 0;
-  if (Sprite_ReturnIfRecoiling(k))
-    return;
-  Sprite_CheckDamageToAndFromLink(k);
-  if (!sprite_wallcoll[k])
-    Sprite_MoveXY(k);
-  Sprite_CheckTileCollision(k);
-  sprite_graphics[k] = ++sprite_subtype2[k] >> 3 & 2;
-  switch(sprite_ai_state[k]) {
-  case 0:  // stopped
-    if (!sprite_delay_main[k]) {
-      sprite_ai_state[k] = 1;
-      int j = Sprite_IsRightOfLink(k).a + Sprite_IsBelowLink(k).a * 2;
-      sprite_D[k] = j;
-      sprite_oam_flags[k] = sprite_oam_flags[k] & ~0x40 | kHover_OamFlags[j];
-      sprite_delay_main[k] = (GetRandomNumber() & 15) + 12;
-      Sprite_ZeroVelocity_XY(k);
-    }
-    break;
-  case 1: {  // moving
-    static const int8 kHover_AccelX0[4] = {1, -1, 1, -1};
-    static const int8 kHover_AccelY0[4] = {1, 1, -1, -1};
-    static const int8 kHover_AccelX1[4] = {-1, 1, -1, 1};
-    static const int8 kHover_AccelY1[4] = {-1, -1, 1, 1};
-    int j = sprite_D[k];
-    if (sprite_delay_main[k]) {
-      sprite_x_vel[k] += kHover_AccelX0[j];
-      sprite_y_vel[k] += kHover_AccelY0[j];
-      sprite_graphics[k] = sprite_subtype2[k] >> 3 & 1;
-    } else {
-      sprite_x_vel[k] += kHover_AccelX1[j];
-      sprite_y_vel[k] += kHover_AccelY1[j];
-      if (!sprite_y_vel[k]) {
-        sprite_ai_state[k] = 0;
-        sprite_delay_main[k] = 64;
-      }
-    }
-    break;
-  }
-  }
-}
-
-void Sprite_AB_CrystalMaiden(int k) {  // 9ece03
-  cur_sprite_x -= dung_floor_x_offs;
-  cur_sprite_y -= dung_floor_y_offs;
-
-  if (sprite_ai_state[k] >= 3)
-    CrystalMaiden_Draw(k);
-  is_nmi_thread_active = 1;
-  if (!BYTE(intro_did_run_step)) {
-    CrystalMaiden_RunCutscene(k);
-    BYTE(intro_did_run_step) = 1;
-  }
-}
-
-void CrystalMaiden_RunCutscene(int k) {  // 9ece39
-  sprite_E[k]++;
-  poly_b += 6;
-  if (submodule_index)
-    return;
-  switch (sprite_ai_state[k]) {
-  case 0:  // disable subscreen
-    TS_copy = 0;
-    sprite_ai_state[k]++;
-    break;
-  case 1:  // enable subscreen
-    TS_copy = 1;
-    sprite_ai_state[k]++;
-    break;
-  case 2:  // generate sparkles
-    if (poly_config1 < 6) {
-      poly_config1 = 0;
-      sprite_ai_state[k]++;
-    } else {
-      poly_config1 -= 3;
-      if (poly_config1 >= 64)
-        AncillaAdd_SwordChargeSparkle(sprite_A[k]);
-    }
-    break;
-  case 3:  // filter palette
-    sprite_ai_state[k]++;
-  case 4:
-    if (!(sprite_E[k] & 1)) {
-      PaletteFilter_SP5F();
-      if (!BYTE(palette_filter_countdown)) {
-        sprite_ai_state[k]++;
-        flag_is_link_immobilized = 1;
-        link_receiveitem_index = 0;
-        link_pose_for_item = 0;
-        link_animation_steps = 0;
-        link_direction_facing = 0;
-      }
-    }
-    break;
-  case 5: { // show message
-    static const uint16 kCrystalMaiden_Msgs[9] = {0x133, 0x132, 0x137, 0x134, 0x136, 0x132, 0x135, 0x138, 0x13c};
-    int j = BYTE(cur_palace_index_x2) - 10;
-    if (j == 2 && savegame_map_icons_indicator < 7)
-      savegame_map_icons_indicator = 7;
-    if (j == 14 && (link_has_crystals & 0x7f) != 0x7f)
-      j = 16;
-    Sprite_ShowMessageUnconditional(kCrystalMaiden_Msgs[j >> 1]);
-    sprite_ai_state[k]++;
-    if ((link_has_crystals & 0x7f) == 0x7f)
-      savegame_map_icons_indicator = 8;
-    break;
-  }
-  case 6:  // reading comprehension exam
-    Sprite_ShowMessageUnconditional(0x13a);
-    sprite_ai_state[k]++;
-    break;
-  case 7:  // may the way of the hero
-    if (choice_in_multiselect_box) {
-      sprite_ai_state[k] = 5;
-    } else {
-      Sprite_ShowMessageUnconditional(0x139);
-      sprite_ai_state[k]++;
-    }
-    break;
-  case 8:  // initiate dungeon exit
-    TS_copy = 0;
-    PrepareDungeonExitFromBossFight();
-    sprite_state[k] = 0;
-    break;
-  }
-}
-
-void Sprite_7D_BigSpike(int k) {  // 9ecf47
-  static const int8 kSpikeTrap_Xvel[4] = {32, -32, 0, 0};
-  static const int8 kSpikeTrap_Xvel2[4] = {-16, 16, 0, 0};
-  static const int8 kSpikeTrap_Yvel[4] = {0, 0, 32, -32};
-  static const int8 kSpikeTrap_Yvel2[4] = {0, 0, -16, 16};
-  static const uint8 kSpikeTrap_Delay[4] = {0x40, 0x40, 0x38, 0x38};
-  int j;
-
-  SpikeTrap_Draw(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  Sprite_CheckDamageToAndFromLink(k);
-  if (sprite_ai_state[k] == 0) {
-    PointU8 pt;
-    sprite_D[k] = j = Sprite_DirectionToFaceLink(k, &pt);
-    if ((uint8)(pt.x + 16) < 32 || (uint8)(pt.y + 16) < 32) {
-      sprite_delay_main[k] = kSpikeTrap_Delay[j];
-      sprite_ai_state[k] = 1;
-      sprite_x_vel[k] = kSpikeTrap_Xvel[j];
-      sprite_y_vel[k] = kSpikeTrap_Yvel[j];
-    }
-  } else if (sprite_ai_state[k] == 1) {
-    if (Sprite_CheckTileCollision(k) || !sprite_delay_main[k]) {
-      sprite_ai_state[k] = 2;
-      sprite_delay_main[k] = 96;
-    }
-    Sprite_MoveXY(k);
-  } else {
-    if (!sprite_delay_main[k]) {
-      j = sprite_D[k];
-      sprite_x_vel[k] = kSpikeTrap_Xvel2[j];
-      sprite_y_vel[k] = kSpikeTrap_Yvel2[j];
-      Sprite_MoveXY(k);
-      if (sprite_x_lo[k] == sprite_A[k] && sprite_y_lo[k] == sprite_C[k])
-        sprite_ai_state[k] = 0;
-    }
-  }
-}
-
-void SpikeTrap_Draw(int k) {  // 9ecfff
-  static const DrawMultipleData kSpikeTrap_Dmd[4] = {
-    {-8, -8, 0x00c4, 2},
-    { 8, -8, 0x40c4, 2},
-    {-8,  8, 0x80c4, 2},
-    { 8,  8, 0xc0c4, 2},
-  };
-  Sprite_DrawMultiple(k, kSpikeTrap_Dmd, 4, NULL);
-}
-
-void Sprite_7E_Firebar_Clockwise(int k) {  // 9ed01a
-  static const int8 kGuruguruBar_incr[4] = {-2, 2, -1, 1};
-  Firebar_Main(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  sprite_subtype2[k]++;
-  int j = (sprite_type[k] - 0x7e) + (BYTE(cur_palace_index_x2) == 18) * 2;
-
-  int t = sprite_A[k] | sprite_B[k] << 8;
-  t = (t + kGuruguruBar_incr[j]) & 0x1ff;
-  sprite_A[k] = t;
-  sprite_B[k] = t >> 8;
-}
-
-void Firebar_Main(int k) {  // 9ed049
-  PrepOamCoordsRet info;
-  if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
-    return;
-  OamEnt *oam = GetOamCurPtr();
-  byte_7E0FB6 = info.flags;
-  BYTE(dungmap_var7) = info.x;
-  HIBYTE(dungmap_var7) = info.y;
-  int angle = sprite_A[k] | sprite_B[k] << 8;
-  int8 sinval = GuruguruBarSin(angle, 0x40);
-  int8 cosval = GuruguruBarSin((angle + 0x80) & 0x1ff, 0x40);
-  uint8 flags = (sprite_subtype2[k] << 4 & 0xc0) | info.flags;
-  for (int i = 3; i >= 0; i--, oam++) {
-    SetOamPlain(oam, info.x + sinval * (i + 1) / 4, info.y + cosval * (i + 1) / 4, 0x28, flags, 2);
-  }
-  Sprite_CorrectOamEntries(k, 3, 0xff);
-  if (!((k ^ frame_counter) & 3 | submodule_index | flag_unk1)) {
-    OamEnt *oam = GetOamCurPtr();
-    for (int i = 0; i < 4; i++, oam++) {
-      if (bytewise_extended_oam[oam - oam_buf] & 1)
-        continue;
-      if ((uint8)(oam->x + BG2HOFS_copy2 - link_x_coord + 12) < 24 &&
-          oam->y < 0xf0 &&
-          (uint8)(oam->y + BG2VOFS_copy2 - link_y_coord + 4) < 16)
-        Sprite_AttemptDamageToLinkPlusRecoil(k);
-    }
-  }
-}
-
-void Sprite_80_Firesnake(int k) {  // 9ed1d1
-  static const uint8 kWinder_OamFlags[4] = {0, 0x40, 0x80, 0xc0};
-  static const int8 kWinder_Xvel[4] = {24, -24, 0, 0};
-  static const int8 kWinder_Yvel[4] = {0, 0, 24, -24};
-  SpriteDraw_SingleLarge(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  if (Sprite_ReturnIfRecoiling(k))
-    return;
-  sprite_oam_flags[k] = sprite_oam_flags[k] & 0x3f | kWinder_OamFlags[frame_counter >> 2 & 3];
-  if (sprite_A[k]) {
-    sprite_ignore_projectile[k] = sprite_delay_main[k];
-    if (sprite_delay_main[k] == 0)
-      sprite_state[k] = 0;
-    return;
-  }
-  Sprite_CheckDamageToAndFromLink(k);
-  Firesnake_SpawnFireball(k);
-  if (!sprite_wallcoll[k])
-    Sprite_MoveXY(k);
-  if (Sprite_CheckTileCollision(k))
-    sprite_D[k] = kZazak_Dir2[sprite_D[k] * 2 + (GetRandomNumber() & 1)];
-  int j = sprite_D[k];
-  sprite_x_vel[k] = kWinder_Xvel[j];
-  sprite_y_vel[k] = kWinder_Yvel[j];
-}
-
-void Firesnake_SpawnFireball(int j) {  // 9ed239
-  if ((j ^ frame_counter) & 7)
-    return;
-  int k = GarnishAlloc();
-  garnish_type[k] = 1;
-  garnish_active = 1;
-  garnish_x_lo[k] = sprite_x_lo[j];
-  garnish_x_hi[k] = sprite_x_hi[j];
-  int y = Sprite_GetY(j) + 16;
-  garnish_y_lo[k] = y;
-  garnish_y_hi[k] = y >> 8;
-  garnish_countdown[k] = 32;
-  garnish_sprite[k] = j;
-  garnish_floor[k] = sprite_floor[j];
-}
-
-void Sprite_7C_GreenStalfos(int k) {  // 9ed299
-  static const uint8 kGreenStalfos_Dir[4] = {4, 6, 0, 2};
-  static const uint8 kGreenStalfos_OamFlags[4] = {0x40, 0, 0, 0};
-  static const uint8 kGreenStalfos_Gfx[4] = {0, 0, 1, 2};
-  int j = sprite_D[k];
-  sprite_oam_flags[k] = sprite_oam_flags[k] & ~0x40 | kGreenStalfos_OamFlags[j];
-  sprite_graphics[k] = kGreenStalfos_Gfx[j];
-  SpriteDraw_SingleLarge(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  if (Sprite_ReturnIfRecoiling(k))
-    return;
-  Sprite_CheckDamageToAndFromLink(k);
-  j = Sprite_DirectionToFaceLink(k, NULL);
-  if (kGreenStalfos_Dir[j] != link_direction_facing) {
-    sprite_A[k] = 0;
-    if (!((k ^ frame_counter) & 7)) {
-      uint8 vel = sprite_B[k];
-      if (vel != 4)
-        sprite_B[k]++;
-      Sprite_ApplySpeedTowardsLink(k, vel);
-      sprite_D[k] = Sprite_IsRightOfLink(k).a;
-    }
-  } else {
-    sprite_A[k] = 1;
-    if (!((k ^ frame_counter) & 15)) {
-      uint8 vel = sprite_B[k];
-      if (vel)
-        sprite_B[k]--;
-      Sprite_ApplySpeedTowardsLink(k, vel);
-      sprite_D[k] = Sprite_IsRightOfLink(k).a;
-    }
-  }
-  Sprite_MoveXY(k);
-}
-
-void Sprite_7A_Agahnim(int k) {  // 9ed330
-  int j;
-  uint8 t;
-  static const uint8 kAgahnim_StartState[2] = {1, 6};
-  static const uint8 kAgahnim_Gfx0[5] = {12, 13, 14, 15, 16};
-  static const int8 kAgahnim_Tab5[2] = {32, -32};
-  static const uint8 kAgahnim_Tab6[2] = {9, 11};
-  static const uint8 kAgahnim_Dir[25] = {
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 0, 1, 1, 4,
-    4, 0, 2, 2, 4, 4, 3, 2, 2,
-  };
-  static const uint8 kAgahnim_Gfx1[6] = {2, 10, 8, 0, 4, 6};
-  static const uint8 kAgahnim_Tab0[16] = {0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0};
-  static const uint8 kAgahnim_Tab1[16] = {0, 0, 0, 0, 0, 0, 0, 6, 5, 4, 3, 2, 1, 0, 0, 0};
-  static const uint8 kAgahnim_Tab2[6] = {30, 24, 12, 0, 6, 18};
-  static const uint8 kAgahnim_Gfx2[5] = {16, 15, 14, 13, 12};
-  static const uint8 kAgahnim_Tab3[16] = {0x38, 0x38, 0x38, 0x58, 0x78, 0x98, 0xb8, 0xb8, 0xb8, 0x98, 0x58, 0x58, 0x60, 0x90, 0x98, 0x78};
-  static const uint8 kAgahnim_Tab4[16] = {0xb8, 0x78, 0x58, 0x48, 0x48, 0x48, 0x58, 0x78, 0xb8, 0xb8, 0xb8, 0x90, 0x70, 0x70, 0x90, 0xa0};
-  static const uint8 kAgahnim_Gfx3[7] = {0, 8, 10, 2, 2, 6, 4};
-  Agahnim_Draw(k);
-  if (sprite_pause[k]) {
-    sprite_delay_main[k] = 32;
-    sprite_graphics[k] = 0;
-    sprite_D[k] = 3;
-  }
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  if (Sprite_ReturnIfRecoiling(k))
-    return;
-  sprite_ignore_projectile[k] = 1;
-  switch (sprite_ai_state[k]) {
-  case 0:
-    sprite_ai_state[k] = kAgahnim_StartState[is_in_dark_world];
-    break;
-  case 1:
-    if (!sprite_delay_main[k]) {
-      dialogue_message_index = 0x13f;
-      Sprite_ShowMessageMinimal();
-      sprite_ai_state[k] = 3;
-      sprite_delay_main[k] = 32;
-    }
-    break;
-  case 2:
-    byte_7E0FF8 = 0;
-    if (!sprite_delay_main[k]) {
-      sprite_ai_state[k]++;
-      sprite_delay_main[k] = 255;
-    } else {
-      sprite_graphics[k] = kAgahnim_Gfx0[sprite_delay_main[k] >> 3];
-    }
-    break;
-  case 3:
-    j = sprite_delay_main[k];
-    if (j == 192)
-      SpriteSfx_QueueSfx3WithPan(k, 0x27);
-    if (j >= 239 || j < 16) {
-      AgahnimWarpShadowFilter(is_in_dark_world ? k : 2);
-    } else {
-      if (!k) {
-        Sprite_CheckDamageToAndFromLink(k);
-        sprite_ignore_projectile[k] = 0;
-      }
-    }
-    if (!sprite_delay_main[k]) {
-      sprite_ai_state[k]++;
-      sprite_delay_main[k] = 39;
-      return;
-    }
-    if (sprite_delay_main[k] >= 128) {
-      Sprite_ApplySpeedTowardsLink(k, 2);
-      sprite_D[k] = kAgahnim_Dir[((int8)sprite_y_vel[k] + 2) * 5 + 2 + (int8)sprite_x_vel[k]];
-      Sprite_ApplySpeedTowardsLink(k, 32);
-      if (sprite_subtype[k] == 4)
-        sprite_D[k] = 3;
-    } else if (sprite_delay_main[k] == 112) {
-      Agahnim_PerformAttack(k);
-    }
-    j = sprite_delay_main[k] >> 4;
-    sprite_A[k] = kAgahnim_Tab0[j];
-    t = kAgahnim_Tab1[j];
-    sprite_head_dir[k] = t ? t + kAgahnim_Tab2[sprite_D[k]] : t ;
-    sprite_graphics[k] = kAgahnim_Gfx1[sprite_D[k]] + sprite_A[k];
-    break;
-  case 4:
-    sprite_ignore_projectile[k] = sprite_delay_main[k];
-    if (!sprite_delay_main[k]) {
-      sprite_ai_state[k]++;
-      j = sprite_subtype[k] == 4 ? 4 : GetRandomNumber() & 0xf;
-      sprite_C[k] = kAgahnim_Tab3[j];
-      sprite_E[k] = kAgahnim_Tab4[j];
-      sprite_G[k] = 8;
-    } else {
-      sprite_graphics[k] = kAgahnim_Gfx2[sprite_delay_main[k] >> 3];
-    }
-    break;
-  case 5: {
-    if ((uint16)(sprite_x_lo[k] - sprite_C[k] + 7) < 14 &&
-        (uint16)(sprite_y_lo[k] - sprite_E[k] + 7) < 14) {
-      sprite_x_lo[k] = sprite_C[k];
-      sprite_y_lo[k] = sprite_E[k];
-      sprite_ai_state[k] = 2;
-      sprite_delay_main[k] = 39;
-      return;
-    }
-    int x = sprite_x_hi[k] << 8 | sprite_C[k];
-    int y = sprite_y_hi[k] << 8 | sprite_E[k];
-    ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLocation(k, x, y, sprite_G[k]);
-    sprite_y_vel[k] = pt.y;
-    sprite_x_vel[k] = pt.x;
-    if (sprite_G[k] < 64)
-      sprite_G[k]++;
-    Sprite_MoveXY(k);
-    break;
-  }
-  case 6:
-    if (!sprite_delay_main[k]) {
-      dialogue_message_index = 0x141;
-      Sprite_ShowMessageMinimal();
-      sprite_ai_state[k]++;
-      sprite_delay_main[k] = 80;
-    }
-    break;
-  case 7:
-    if (sprite_anim_clock[k]) {
-      if (!sprite_delay_main[k]) {
-        sprite_ai_state[k] = 3;
-        sprite_delay_main[k] = 32;
-      } else {
-        sprite_x_vel[k] = kAgahnim_Tab5[k - 1];
-        sprite_y_vel[k] += 2;
-        Sprite_MoveXY(k);
-        j = Sprite_Agahnim_ApplyMotionBlur(k);
-        if (j >= 0)
-          sprite_oam_flags[j] = 4;
-      }
-    } else {
-      if (!sprite_delay_main[k]) {
-        sprite_ai_state[k] = 3;
-        sprite_delay_main[k] = 32;
-      } else if (sprite_delay_main[k] == 64) {
-        sound_effect_2 = 0x28;
-        tmp_counter = 1;
-        do {
-          SpriteSpawnInfo info;
-          j = Sprite_SpawnDynamicallyEx(k, 0x7A, &info, 2);
-          Sprite_SetSpawnedCoordinates(j, &info);
-          sprite_flags3[j] = kAgahnim_Tab6[j - 1];
-          sprite_anim_clock[j] = sprite_oam_flags[j] = sprite_flags3[j] & 15;
-          sprite_ai_state[j] = sprite_ai_state[k];
-          sprite_delay_main[j] = 32;
-        } while (!sign8(--tmp_counter));
-      }
-    }
-    break;
-  case 8:
-    flag_block_link_menu = 2;
-    sprite_head_dir[k] = 0;
-    if (sprite_delay_main[k] >= 64) {
-      sprite_hit_timer[k] |= 0xe0;
-    } else {
-      if (sprite_delay_main[k] == 1) {
-        Sprite_SpawnPhantomGanon(k);
-        music_control = 0x1d;
-      }
-      sprite_hit_timer[k] = 0;
-      sprite_graphics[k] = 17;
-    }
-    break;
-  case 9: {
-    sprite_head_dir[k] = 0;
-    int x = Sprite_GetX(0), y = Sprite_GetY(0);
-    if ((uint16)(cur_sprite_x - x + 4) < 8 &&
-        (uint16)(cur_sprite_y - y + 4) < 8)
-      sprite_state[k] = 0;
-    ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLocation(k, x, y, 0x20);
-    sprite_y_vel[k] = pt.y;
-    sprite_x_vel[k] = pt.x;
-    Sprite_MoveXY(k);
-    Sprite_Agahnim_ApplyMotionBlur(k);
-    break;
-  }
-  case 10:
-    if (!sprite_delay_main[k]) {
-      sprite_state[k] = 0;
-      PrepareDungeonExitFromBossFight();
-    }
-    if (sprite_delay_main[k] < 16) {
-      CGADSUB_copy = 0x7f;
-      TM_copy = 6;
-      TS_copy = 0x10;
-      PaletteFilter_SP5F();
-    }
-    if (sprite_z_vel[k] != 0xff)
-      sprite_z_vel[k]++;
-    j = sprite_z_subpos[k] + sprite_z_vel[k];
-    sprite_z_subpos[k] = j;
-    if (j & 0x100 && ++sprite_subtype2[k] == 7) {
-      sprite_subtype2[k] = 0;
-      SpriteSfx_QueueSfx2WithPan(k, 0x4);
-    }
-    sprite_graphics[k] = kAgahnim_Gfx3[sprite_subtype2[k]];
-    break;
-  }
-}
-
-void Agahnim_PerformAttack(int k) {  // 9ed67a
-  static const int8 kAgahnim_X0[6] = {0, 10, 8, 0, -10, -10};
-  static const int8 kAgahnim_Y0[6] = {-9, -2, -2, -9, -2, -2};
-
-  if (!k) {
-    sprite_subtype[k]++;
-    if (is_in_dark_world)
-      sprite_subtype[k] &= 3;
-  }
-  if (sprite_subtype[k] == 5) {
-    sprite_subtype[k] = 0;
-    SpriteSfx_QueueSfx3WithPan(k, 0x26);
-    for (int i = 0; i < 4; i++)
-      Sprite_SpawnLightning(k);
-  } else {
-    SpriteSpawnInfo info;
-    int j = Sprite_SpawnDynamically(k, 0x7B, &info);
-    if (j >= 0) {
-      SpriteSfx_QueueSfx3WithPan(k, 0x29);
-      int i = sprite_D[k];
-      Sprite_SetX(j, info.r0_x + kAgahnim_X0[i]);
-      Sprite_SetY(j, info.r2_y + kAgahnim_Y0[i]);
-      sprite_ignore_projectile[j] = sprite_y_hi[j];
-      sprite_x_vel[j] = sprite_x_vel[k];
-      sprite_y_vel[j] = sprite_y_vel[k];
-      if (sprite_subtype[k] >= 2 && !(GetRandomNumber() & 1)) {
-        sprite_B[j] = 1;
-        sprite_delay_main[j] = 32;
-      }
-    }
-  }
-}
-
-void Agahnim_Draw(int k) {  // 9ed978
-  static const int8 kAgahnim_Draw_X0[72] = {
-    -8, 8, -8, 8, -8, 8, -8, 8, -8, 8, -8, 8, -8, 8, -8, 8,
-    -8, 8, -8, 8, -8, 8, -8, 8, -8, 8, -8, 8, -8, 8, -8, 8,
-    -8, 8, -8, 8, -8, 8, -8, 8, -8, 8, -8, 8, -8, 8, -8, 8,
-    -8, 8, -8, 8, -6, 6, -6, 6, -8, 8, -8, 8, -6, 6, -6, 6,
-    0, 8,  0, 8, -8, 8, -8, 8,
-  };
-  static const int8 kAgahnim_Draw_Y0[72] = {
-    -8, -8, 8, 8, -8, -8, 8, 8, -8, -8, 8, 8, -8, -8, 8, 8,
-    -8, -8, 8, 8, -8, -8, 8, 8, -8, -8, 8, 8, -8, -8, 8, 8,
-    -8, -8, 8, 8, -8, -8, 8, 8, -8, -8, 8, 8, -8, -8, 8, 8,
-    -8, -8, 8, 8, -6, -6, 6, 6, -8, -8, 8, 8, -6, -6, 6, 6,
-    0,  0, 8, 8,  8,  8, 8, 8,
-  };
-  static const uint8 kAgahnim_Draw_Char0[72] = {
-    0x82, 0x82, 0xa2, 0xa2, 0x80, 0x80, 0xa0, 0xa0, 0x84, 0x84, 0xa4, 0xa4, 0x86, 0x86, 0xa6, 0xa6,
-    0x88, 0x8a, 0xa8, 0xaa, 0x8c, 0x8e, 0xac, 0xae, 0xc4, 0xc2, 0xe4, 0xe6, 0xc0, 0xc2, 0xe0, 0xe2,
-    0x8a, 0x88, 0xaa, 0xa8, 0x8e, 0x8c, 0xae, 0xac, 0xc2, 0xc4, 0xe6, 0xe4, 0xc2, 0xc0, 0xe2, 0xe0,
-    0xec, 0xec, 0xec, 0xec, 0xec, 0xec, 0xec, 0xec, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
-    0xdf, 0xdf, 0xdf, 0xdf, 0x40, 0x42, 0x40, 0x42,
-  };
-  static const uint8 kAgahnim_Draw_Flags0[72] = {
-    0, 0x40,    0, 0x40,    0, 0x40,    0, 0x40,    0, 0x40,    0, 0x40,    0, 0x40,    0, 0x40,
-    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
-    0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
-    0, 0x40, 0x80, 0xc0,    0, 0x40, 0x80, 0xc0,    0, 0x40, 0x80, 0xc0,    0, 0x40, 0x80, 0xc0,
-    0, 0x40, 0x80, 0xc0,    0,    0,    0,    0,
-  };
-  static const int8 kAgahnim_Draw_X1[72] = {
-    -7, 15, -11, 11, -11, 11,  -8,   8,  -4,   4,   0,   0, -10,  -1, -14,  -5,
-    -14, -5, -12, -7, -10, -7, -10, -10,  16,   8,  12,   4,  12,   4,  10,   6,
-    9,  7,   8,  8,  -6, -6, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10,
-    14, 14,  10, 10,  10, 10,  10,  10,  10,  10,  10,  10,  -7,  15, -11,  11,
-    -11, 11,  -8,  8,  -4,  4,   0,   0,
-  };
-  static const int8 kAgahnim_Draw_Y1[72] = {
-    -5, -5, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -3,  9, -7,  5,
-    -7,  5, -5,  3, -3,  3, -2, -2, -3,  9, -7,  5, -7,  5, -5,  3,
-    -3,  3, -2, -2, -3,  9, -7,  5, -7,  5, -5,  3, -3,  3, -2, -2,
-    -3,  9, -7,  5, -7,  5, -5,  3, -3,  3, -2, -2, -5, -5, -9, -9,
-    -9, -9, -9, -9, -9, -9, -9, -9,
-  };
-  static const uint8 kAgahnim_Draw_Char1[36] = {
-    0xce, 0xcc, 0xc6, 0xc6, 0xc6, 0xc6, 0xce, 0xcc, 0xc6, 0xc6, 0xc6, 0xc6, 0xce, 0xcc, 0xc6, 0xc6,
-    0xc6, 0xc6, 0xce, 0xcc, 0xc6, 0xc6, 0xc6, 0xc6, 0xce, 0xcc, 0xc6, 0xc6, 0xc6, 0xc6, 0xce, 0xcc,
-    0xc6, 0xc6, 0xc6, 0xc6,
-  };
-  static const uint8 kAgahnim_Draw_Big1[36] = {
-    0, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 0, 2, 2, 2,
-    2, 2, 0, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 0, 2,
-    2, 2, 2, 2,
-  };
-  PrepOamCoordsRet info;
-  if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
-    return;
-  OamEnt *oam = GetOamCurPtr();
-  int g = sprite_graphics[k];
-  for (int i = 3; i >= 0; i--, oam++) {
-    int j = g * 4 + i;
-    SetOamPlain(oam, info.x + kAgahnim_Draw_X0[j], info.y + kAgahnim_Draw_Y0[j],
-                 kAgahnim_Draw_Char0[j], info.flags | kAgahnim_Draw_Flags0[j],
-                 (j >= 0x40 && j < 0x44) ? 0 : 2);
-  }
-  if (g < 12)
-    SpriteDraw_Shadow_custom(k, &info, 18);
-  if (submodule_index)
-    Sprite_CorrectOamEntries(k, 3, 0xff);
-
-  if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
-    return;
-
-  if (sprite_D[k])
-    Oam_AllocateFromRegionC(8);
-  else
-    Oam_AllocateFromRegionB(8);
-  oam = GetOamCurPtr();
-
-  if (!sprite_head_dir[k])
-    return;
-  g = sprite_head_dir[k] - 1;
-  uint8 flags = (((frame_counter >> 1) & 2) + 2) + 0x31;
-  for (int i = 1; i >= 0; i--, oam++) {
-    SetOamPlain(oam, info.x + kAgahnim_Draw_X1[g * 2 + i], info.y + kAgahnim_Draw_Y1[g * 2 + i],
-                 kAgahnim_Draw_Char1[g], flags, kAgahnim_Draw_Big1[g]);
-  }
-}
-
-void Sprite_7B_AgahnimBalls(int k) {  // 9eda42
-  if (sprite_B[k]) {
-    if (sprite_delay_main[k])
-      Sprite_ApplySpeedTowardsLink(k, 32);
-    sprite_oam_flags[k] = 5;
-  } else {
-    sprite_oam_flags[k] = (frame_counter >> 1 & 2) + 3;
-  }
-
-  if (sprite_ai_state[k]) {
-    static const uint8 kEnergyBall_Gfx[16] = {2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 0, 0, 0, 0};
-    if (sprite_graphics[k] != 2)
-      SpriteDraw_SingleLarge(k);
-    else
-      SpriteDraw_SingleSmall(k);
-    if (Sprite_ReturnIfInactive(k))
-      return;
-    sprite_ignore_projectile[k] = sprite_delay_main[k];
-    if (!sprite_delay_main[k]) {
-      sprite_state[k] = 0;
-    } else if (sprite_delay_main[k] == 6) {
-      sprite_x_vel[k] = sprite_y_vel[k] = 64;
-      Sprite_MoveXY(k);
-    }
-    sprite_graphics[k] = kEnergyBall_Gfx[sprite_delay_main[k]];
-    return;
-  }
-  if (sprite_B[k])
-    SeekerEnergyBall_Draw(k);
-  else
-    SpriteDraw_SingleLarge(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  sprite_subtype2[k]++;
-  Sprite_MoveXY(k);
-  if (Sprite_CheckTileCollision(k)) {
-    sprite_state[k] = 0;
-    if (sprite_B[k]) {
-      SpriteSfx_QueueSfx3WithPan(k, 0x36);
-      CreateSixBlueBalls(k);
-      return;
-    }
-  }
-
-  if (sprite_A[k] && !sprite_ignore_projectile[0]) {
-    SpriteHitBox hb;
-    hb.r0_xlo = sprite_x_lo[k];
-    hb.r8_xhi = sprite_x_hi[k];
-    hb.r2 = hb.r3 = 15;
-    hb.r1_ylo = sprite_y_lo[k];
-    hb.r9_yhi = sprite_y_hi[k];
-    Sprite_SetupHitBox(0, &hb);
-    if (CheckIfHitBoxesOverlap(&hb)) {
-      Sprite_GiveDamage(0, 16, 0xa0);
-      sprite_state[k] = 0;
-      sprite_x_recoil[0] = sprite_x_vel[k];
-      sprite_y_recoil[0] = sprite_y_vel[k];
-    }
-  } else {
-    Sprite_CheckDamageToLink(k);
-    if (Sprite_CheckDamageFromLink(k) & kCheckDamageFromPlayer_Carry) {
-      if (sprite_B[k]) {
-        sprite_state[k] = 0;
-        SpriteSfx_QueueSfx3WithPan(k, 0x36);
-        CreateSixBlueBalls(k);
-        return;
-      }
-      SpriteSfx_QueueSfx2WithPan(k, 0x5);
-      SpriteSfx_QueueSfx3WithPan(k, 0x29);
-      Sprite_ApplySpeedTowardsLink(k, 0x30);
-      sprite_x_vel[k] = -sprite_x_vel[k];
-      sprite_y_vel[k] = -sprite_y_vel[k];
-      sprite_A[k]++;
-    }
-  }
-  if ((k ^ frame_counter) & 3 | sprite_B[k])
-    return;
-  SpriteSpawnInfo info;
-  int j = Sprite_SpawnDynamically(k, 0x7B, &info);
-  if (j < 0)
-    return;
-  Sprite_SetSpawnedCoordinates(j, &info);
-  sprite_delay_main[j] = 15;
-  sprite_ai_state[j] = 15;
-  sprite_B[j] = sprite_B[k];
-}
-
-void CreateSixBlueBalls(int k) {  // 9edb96
-  static const int8 kEnergyBall_SplitXVel[6] = {0, 24, 24, 0, -24, -24};
-  static const int8 kEnergyBall_SplitYVel[6] = {-32, -16, 16, 32, 16, -16};
-  SpriteSfx_QueueSfx3WithPan(k, 0x36);
-  tmp_counter = 5;
-  do {
-    SpriteSpawnInfo info;
-    int j = Sprite_SpawnDynamically(k, 0x55, &info);
-    if (j >= 0) {
-      Sprite_SetX(j, info.r0_x + 4);
-      Sprite_SetY(j, info.r2_y + 4);
-      sprite_flags3[j] = sprite_flags3[j] & ~1 | 0x40;
-      sprite_oam_flags[j] = 4;
-      sprite_delay_aux1[j] = 4;
-      sprite_flags4[j] = 20;
-      sprite_C[j] = 20;
-      sprite_E[j] = 20;
-      sprite_x_vel[j] = kEnergyBall_SplitXVel[tmp_counter];
-      sprite_y_vel[j] = kEnergyBall_SplitYVel[tmp_counter];
-    }
-  } while (!sign8(--tmp_counter));
-  tmp_counter = 0;
-}
-
-void SeekerEnergyBall_Draw(int k) {  // 9edc3e
-  static const DrawMultipleData kEnergyBall_Dmd[8] = {
-    { 4, -3, 0x00ce, 0},
-    {11,  4, 0x00ce, 0},
-    { 4, 11, 0x00ce, 0},
-    {-3,  4, 0x00ce, 0},
-    {-1, -1, 0x00ce, 0},
-    { 9, -1, 0x00ce, 0},
-    {-1,  9, 0x00ce, 0},
-    { 9,  9, 0x00ce, 0},
-  };
-  Sprite_DrawMultiple(k, &kEnergyBall_Dmd[(sprite_subtype2[k] >> 2 & 1) * 4], 4, NULL);
-}
-
-void Sprite_79_Bee(int k) {  // 9edc5b
-  switch (sprite_ai_state[k]) {
-  case 0:
-    Bee_DormantHive(k);
-    break;
-  case 1:
-    Bee_Main(k);
-    break;
-  case 2:
-    Bee_PutInBottle(k);
-    break;
-  }
-}
-
-void Bee_DormantHive(int k) {  // 9edc68
-  if (sprite_E[k])
-    return;
-  sprite_state[k] = 0;
-  for (int i = 11; i >= 0; i--)
-    SpawnBeeFromHive(k);
-}
-
-void SpawnBeeFromHive(int k) {  // 9edc8f
-  SpriteSpawnInfo info;
-  int j = Sprite_SpawnDynamically(k, 0x79, &info);
-  if (j >= 0) {
-    Sprite_SetSpawnedCoordinates(j, &info);
-    InitializeSpawnedBee(j);
-  }
-}
-
-void InitializeSpawnedBee(int k) {  // 9edc9b
-  sprite_ai_state[k] = 1;
-  sprite_A[k] = sprite_delay_main[k] = kSpawnBee_InitDelay[k & 3];
-  sprite_delay_aux4[k] = 96;
-  sprite_x_vel[k] = kSpawnBee_InitVel[GetRandomNumber() & 7];
-  sprite_y_vel[k] = kSpawnBee_InitVel[GetRandomNumber() & 7];
-}
-
-int ReleaseBeeFromBottle(int x_value) {  // 9edccf
-  static const int8 kSpawnBee_XY[8] = {8, 2, -2, -8, 10, 5, -5, -10};
-
-  SpriteSpawnInfo info;
-  int j = Sprite_SpawnDynamically(x_value, 0xb2, &info);
-  if (j >= 0) {
-    sprite_floor[j] = link_is_on_lower_level;
-    Sprite_SetX(j, link_x_coord + 8);
-    Sprite_SetY(j, link_y_coord + 16);
-    if (link_bottle_info[link_item_bottle_index - 1] == 8)
-      sprite_head_dir[j] = 1;
-    InitializeSpawnedBee(j);
-    sprite_x_vel[j] = kSpawnBee_XY[GetRandomNumber() & 7];
-    sprite_y_vel[j] = kSpawnBee_XY[GetRandomNumber() & 7];
-    sprite_delay_main[j] = 64;
-    sprite_A[j] = 64;
-  }
-  return j;
-}
-
-void Bee_Main(int k) {  // 9edd45
-  Bee_HandleZ(k);
-  SpriteDraw_SingleSmall(k);
-  Bee_HandleInteractions(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  if (Sprite_ReturnIfRecoiling(k))
-    return;
-  if (sprite_head_dir[k])
-    Sprite_SpawnSparkleGarnish(k);
-  Bee_Bzzt(k);
-  Sprite_MoveXY(k);
-  sprite_graphics[k] = (k ^ frame_counter) >> 1 & 1;
-  if (!sprite_delay_aux4[k]) {
-    Sprite_CheckDamageToLink(k);
-    if (Sprite_CheckDamageFromLink(k) & kCheckDamageFromPlayer_Ne) {
-      Sprite_ShowMessageUnconditional(0xc8);
-      sprite_ai_state[k] = 2; // put in bottle
-      return;
-    }
-  }
-
-  if (!frame_counter && sprite_A[k] != 16)
-    sprite_A[k] -= 8;
-
-  if (sprite_delay_main[k] == 0) {
-    uint16 x = link_x_coord + (GetRandomNumber() & 3) * 5;
-    uint16 y = link_y_coord + (GetRandomNumber() & 3) * 5;
-    ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLocation(k, x, y, 20);
-    sprite_y_vel[k] = pt.y;
-    sprite_x_vel[k] = pt.x;
-    sprite_oam_flags[k] = sprite_oam_flags[k] & ~0x40 | (sign8(pt.x) ? 0 : 0x40);
-    sprite_delay_main[k] = k + sprite_A[k];
-  }
-}
-
-int Sprite_Find_EmptyBottle() {  // 9ede2e
-  for (int i = 0; i != 4; i++)
-    if (link_bottle_info[i] == 2)
-      return i;
-  return -1;
-}
-
-void Bee_HandleInteractions(int k) {  // 9ede44
-  if (submodule_index == 2 && (dialogue_message_index == 0xc8 || dialogue_message_index == 0xca))
-    sprite_delay_aux4[k] = 40;
-}
-
-void Sprite_B2_PlayerBee(int k) {  // 9ede63
-  static const uint8 kGoodBee_Tab0[2] = {0xa, 0x14};
-
-  switch (sprite_ai_state[k]) {
-  case 0:  // wait
-    if (!sprite_E[k]) {
-      sprite_state[k] = 0;
-      uint8 or_bottle = link_bottle_info[0] | link_bottle_info[1] | link_bottle_info[2] | link_bottle_info[3];
-      if (!(or_bottle & 8))
-        GoldBee_SpawnSelf(k);
-    }
-    break;
-  case 1: {// activated
-    sprite_ignore_projectile[k] = 1;
-    Bee_HandleZ(k);
-    SpriteDraw_SingleSmall(k);
-    Bee_HandleInteractions(k);
-    if (Sprite_ReturnIfInactive(k))
-      return;
-    Bee_Bzzt(k);
-    Sprite_MoveXY(k);
-    sprite_graphics[k] = (k ^ frame_counter) >> 1 & 1;
-    if (sprite_head_dir[k])
-      Sprite_SpawnSparkleGarnish(k);
-    if (sprite_B[k] >= kGoodBee_Tab0[sprite_head_dir[k]]) {
-      sprite_defl_bits[k] = 64;
-      return;
-    }
-    if (sprite_delay_aux4[k])
-      return;
-    if (Sprite_CheckDamageFromLink(k) & kCheckDamageFromPlayer_Ne) {
-      Sprite_ShowMessageUnconditional(0xc8);
-      sprite_ai_state[k]++;
-      return;
-    }
-    if ((k ^ frame_counter) & 3)
-      return;
-    Point16U pt2;
-    if (!PlayerBee_FindTarget(k, &pt2)) {
-      pt2.x = link_x_coord + (GetRandomNumber() & 3) * 5;
-      pt2.y = link_y_coord + (GetRandomNumber() & 3) * 5;
-    }
-    if ((k ^ frame_counter) & 7)
-      return;
-    ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLocation(k, pt2.x, pt2.y, 32);
-    sprite_x_vel[k] = pt.x;
-    sprite_y_vel[k] = pt.y;
-    sprite_oam_flags[k] = sprite_oam_flags[k] & ~0x40 | (sign8(pt.x) ? 0 : 0x40);
-    break;
-  }
-  case 2:  // bottle
-    Bee_PutInBottle(k);
-    break;
-  }
-}
-
-void GoldBee_SpawnSelf(int k) {  // 9ede90
-  SpriteSpawnInfo info;
-  int j = Sprite_SpawnDynamically(k, 0x79, &info);
-  if (j >= 0) {
-    Sprite_SetSpawnedCoordinates(j, &info);
-    sprite_ai_state[j] = 1;
-    sprite_delay_main[j] = 64;
-    sprite_A[j] = 64;
-    sprite_delay_aux4[j] = 96;
-    sprite_head_dir[j] = 1;
-    sprite_x_vel[j] = kSpawnBee_InitVel[GetRandomNumber() & 7];
-    sprite_y_vel[j] = kSpawnBee_InitVel[GetRandomNumber() & 7];
-  }
-}
-
-void Bee_HandleZ(int k) {  // 9edf8a
-  sprite_z[k] = 16;
-  if (sprite_head_dir[k])
-    sprite_oam_flags[k] = (sprite_oam_flags[k] & 0xf1) | (((frame_counter >> 4 & 3) + 1) << 1);
-}
-
-bool PlayerBee_FindTarget(int k, Point16U *pt) {  // 9edfab
-  int n = 16;
-  int j = k * 4 & 0xf;
-  do {
-    if (j == k || sprite_state[j] < 9 || sprite_pause[j])
-      continue;
-    if (!(sprite_flags2[j] & 0x80)) {
-      if (sprite_floor[k] != sprite_floor[j] || sprite_flags4[j] & 0x40 || sprite_ignore_projectile[j])
-        continue;
-    } else {
-      if (!sprite_head_dir[k] || !(sprite_bump_damage[j] & 0x40))
-        continue;
-    }
-    PlayerBee_HoneInOnTarget(j, k);
-    pt->x = Sprite_GetX(j) + (GetRandomNumber() & 3) * 5;
-    pt->y = Sprite_GetY(j) + (GetRandomNumber() & 3) * 5;
-    return true;
-  } while (j = (j - 1) & 0xf, --n);
-  return false;
-}
-
-void Bee_Bzzt(int k) {  // 9ee02e
-  if (!((k ^ frame_counter) & 31))
-    SpriteSfx_QueueSfx3WithPan(k, 0x2c);
-}
-
-void Sprite_B3_PedestalPlaque(int k) {  // 9ee044
-  PrepOamCoordsRet info;
-  Sprite_PrepOamCoord(k, &info);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  if (!flag_is_link_immobilized && Sprite_CheckIfLinkIsBusy())
-    return;
-
-  link_position_mode &= ~0x20;
-  if (BYTE(overworld_screen_index) != 48) {
-    if (link_direction_facing || !Sprite_CheckDamageToLink_same_layer(k))
-      return;
-    if (hud_cur_item != kHudItem_BookMudora || !(filtered_joypad_H & 0x40)) {
-      if (!(filtered_joypad_L & 0x80))
-        return;
-      Sprite_ShowMessageUnconditional(0xb6);
-    } else {
-      player_handler_timer = 0;
-      link_position_mode = 32;
-      sound_effect_1 = 0;
-      Sprite_ShowMessageUnconditional(0xb7);
-    }
-  } else {
-    if (link_direction_facing || !Sprite_CheckDamageToLink_same_layer(k))
-      return;
-    if (hud_cur_item != kHudItem_BookMudora || !(filtered_joypad_H & 0x40)) {
-      if (!(filtered_joypad_L & 0x80))
-        return;
-      Sprite_ShowMessageUnconditional(0xbc);
-    } else {
-      player_handler_timer = 0;
-      link_position_mode = 32;
-      sound_effect_1 = 0;
-      button_b_frames = 1;
-      link_delay_timer_spin_attack = 0;
-      link_player_handler_state = kPlayerState_OpeningDesertPalace;
-      Sprite_ShowMessageUnconditional(0xbd);
-    }
-  }
-}
-
-void Sprite_B4_PurpleChest(int k) {  // 9ee0dd
-  SpriteDraw_SingleLarge(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  if (!sprite_ai_state[k]) {
-    if (Sprite_ShowMessageOnContact(k, 0x116) & 0x100 && follower_indicator == 0)
-      sprite_ai_state[k] = 1;
-  } else {
-    sprite_state[k] = 0;
-    follower_indicator = 12;
-    LoadFollowerGraphics();
-    Sprite_BecomeFollower(k);
-  }
-}
-
-void Sprite_B5_BombShop(int k) {  // 9ee111
-  switch (sprite_subtype2[k]) {
-  case 0: Sprite_BombShop_Clerk(k); break;
-  case 1: Sprite_BombShop_Bomb(k); break;
-  case 2: Sprite_BombShop_SuperBomb(k); break;
-  case 3: Sprite_BombShop_Huff(k); break;
-  }
-}
-
-void Sprite_BombShop_Clerk(int k) {  // 9ee134
-  static const uint8 kBombShopGuy_Gfx[8] = {0, 1, 0, 1, 0, 1, 0, 1};
-  static const uint8 kBombShopGuy_Delay[8] = {255, 32, 255, 24, 15, 24, 255, 15};
-
-  BombShopEntity_Draw(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  if (!sprite_delay_main[k]) {
-    int j = sprite_E[k];
-    sprite_E[k] = j + 1 & 7;
-    sprite_delay_main[k] = kBombShopGuy_Delay[j];
-    sprite_graphics[k] = kBombShopGuy_Gfx[j];
-    if (sprite_graphics[k] == 0) {
-      SpriteSfx_QueueSfx3WithPan(k, 0x11);
-      BombShop_ClerkExhalation(k);
-    } else {
-      SpriteSfx_QueueSfx3WithPan(k, 0x12);
-    }
-  }
-  bool flag = ((link_has_crystals & 5) == 5 && sram_progress_indicator_3 & 32);
-  Sprite_ShowSolicitedMessage(k, flag ? 0x118 : 0x117);
-  Sprite_BehaveAsBarrier(k);
-}
-
-void Sprite_BombShop_Bomb(int k) {  // 9ee190
-  BombShopEntity_Draw(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  Sprite_BehaveAsBarrier(k);
-  if (!ShopItem_CheckForAPress(k))
-    return;
-
-  if (link_item_bombs != kMaxBombsForLevel[link_bomb_upgrades]) {
-    if (!ShopItem_HandleCost(100)) {
-      Sprite_ShowMessageUnconditional(0x17c);
-      ShopItem_PlayBeep(k);
-    } else {
-      link_bomb_filler = 27;
-      sprite_state[k] = 0;
-      Sprite_ShowMessageUnconditional(0x119);
-      ShopItem_HandleReceipt(k, 0x28);
-    }
-  } else {
-    Sprite_ShowMessageUnconditional(0x16e);
-    ShopItem_PlayBeep(k);
-  }
-
-}
-
-void Sprite_BombShop_SuperBomb(int k) {  // 9ee1df
-  BombShopEntity_Draw(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  Sprite_BehaveAsBarrier(k);
-  if (ShopItem_CheckForAPress(k)) {
-    if (!ShopItem_HandleCost(100)) {
-      Sprite_ShowMessageUnconditional(0x17c);
-      ShopItem_PlayBeep(k);
-    } else {
-      follower_indicator = 13;
-      LoadFollowerGraphics();
-      Sprite_BecomeFollower(k);
-      sprite_state[k] = 0;
-      Sprite_ShowMessageUnconditional(0x11a);
-    }
-  }
-}
-
-void Sprite_BombShop_Huff(int k) {  // 9ee21a
-  static const uint8 kSnoutPutt_Dmd[4] = {4, 0x44, 0xc4, 0x84};
-  Oam_AllocateFromRegionC(4);
-  SpriteDraw_SingleSmall(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  sprite_oam_flags[k] &= 0x30;
-  sprite_oam_flags[k] |= kSnoutPutt_Dmd[frame_counter >> 2 & 3];
-  sprite_z_vel[k]++;
-  Sprite_MoveZ(k);
-  if (!sprite_delay_main[k])
-    sprite_state[k] = 0;
-  sprite_graphics[k] = sprite_delay_main[k] >> 3 & 3;
-}
-
-void BombShop_ClerkExhalation(int k) {  // 9ee256
-  SpriteSpawnInfo info;
-  int j = Sprite_SpawnDynamically(k, 0xb5, &info);
-  if (j >= 0) {
-    Sprite_SetX(j, info.r0_x + 4);
-    Sprite_SetY(j, info.r2_y + 16);
-    sprite_subtype2[j] = 3;
-    sprite_ignore_projectile[j] = 3;
-    sprite_z[j] = 4;
-    sprite_z_vel[j] = -12;
-    sprite_delay_main[j] = 23;
-    sprite_flags3[j] &= ~0x11;
-  }
-}
-
-void BombShopEntity_Draw(int k) {  // 9ee2c6
-  static const DrawMultipleData kBombShopEntity_Dmd[6] = {
-    {0, 0, 0x0a48, 2},
-    {0, 0, 0x0a4c, 2},
-    {0, 0, 0x04c2, 2},
-    {0, 0, 0x04c2, 2},
-    {0, 0, 0x084e, 2},
-    {0, 0, 0x084e, 2},
-  };
-  PrepOamCoordsRet info;
-  Sprite_DrawMultiplePlayerDeferred(k, &kBombShopEntity_Dmd[sprite_subtype2[k] * 2 + sprite_graphics[k]], 1, &info);
-  SpriteDraw_Shadow(k, &info);
-
-}
-
-void Sprite_B6_Kiki(int k) {  // 9ee2ef
-  switch(sprite_subtype2[k]) {
-  case 0: Kiki_LyingInwait(k); break;
-  case 1: Kiki_OfferEntranceService(k); break;
-  case 2: Kiki_OfferInitialService(k); break;
-  case 3: Kiki_Flee(k); break;
-  }
-}
-
-void Kiki_Flee(int k) {  // 9ee2fe
-  bool flag = Kiki_Draw(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  if (!sprite_z[k] &&
-      (uint16)(cur_sprite_x - 0xc98) < 0xd0 &&
-      (uint16)(cur_sprite_y - 0x6a5) < 0xd0)
-    flag = true;
-
-  if (flag)
-    sprite_state[k] = 0;
-  sprite_z_vel[k]-=2;
-  Sprite_MoveXYZ(k);
-  if (sign8(sprite_z[k])) {
-    sprite_z[k] = 0;
-    sprite_z_vel[k] = GetRandomNumber() & 15 | 16;
-  }
-  ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLocation(k, 0xcf5, 0x6fe, 16);
-  sprite_x_vel[k] = pt.x << 1;
-  sprite_y_vel[k] = pt.y << 1;
-  tagalong_event_flags &= ~3;
-  if (sign8(pt.x)) pt.x = -pt.x;
-  if (sign8(pt.y)) pt.y = -pt.y;
-  sprite_D[k] = (pt.x >= pt.y) ? (sprite_x_vel[k] >> 7) ^ 3 : (sprite_y_vel[k] >> 7) ^ 1;
-  sprite_graphics[k] = frame_counter >> 3 & 1;
-}
-
-void Kiki_OfferInitialService(int k) {  // 9ee3af
-  if (!sign8(sprite_ai_state[k] - 2))
-    Kiki_Draw(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  Sprite_MoveXYZ(k);
-  sprite_z_vel[k]--;
-  if (sign8(sprite_z[k])) {
-    sprite_z_vel[k] = 0;
-    sprite_z[k] = 0;
-  }
-  sprite_graphics[k] = frame_counter >> 3 & 1;
-  switch(sprite_ai_state[k]) {
-  case 0:
-    Sprite_ShowMessageUnconditional(0x11e);
-    sprite_ai_state[k]++;
-    break;
-  case 1:
-    if (!choice_in_multiselect_box && ShopItem_HandleCost(10)) {
-      Sprite_ShowMessageUnconditional(0x11f);
-      tagalong_event_flags |= 3;
-      sprite_state[k] = 0;
-    } else {
-      Sprite_ShowMessageUnconditional(0x120);
-      tagalong_event_flags &= ~3;
-      follower_indicator = 0;
-      sprite_ai_state[k]++;
-      flag_is_link_immobilized++;
-    }
-    break;
-  case 2: {
-    sprite_ai_state[k]++;
-    ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLocation(k, 0xc45, 0x6fe, 9);
-    sprite_y_vel[k] = pt.y;
-    sprite_x_vel[k] = pt.x;
-    sprite_D[k] = (pt.x >> 7) ^ 3;
-    sprite_delay_main[k] = 32;
-    break;
-  }
-  case 3:
-    if (!sprite_delay_main[k]) {
-      sprite_ai_state[k]++;
-      sprite_z_vel[k] = 16;
-      sprite_delay_main[k] = 16;
-    }
-    break;
-  case 4:
-    if (!sprite_delay_main[k] && !sprite_z[k]) {
-      sprite_state[k] = 0;
-      flag_is_link_immobilized = 0;
-    }
-    break;
-  }
-}
-
-void Kiki_OfferEntranceService(int k) {  // 9ee4c9
-  int j, t;
-  Kiki_Draw(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  Sprite_MoveXYZ(k);
-  sprite_z_vel[k]--;
-  if (sign8(sprite_z[k])) {
-    sprite_z_vel[k] = 0;
-    sprite_z[k] = 0;
-  }
-  switch(sprite_ai_state[k]) {
-  case 0:  //
-    Sprite_ShowMessageUnconditional(0x11b);
-    sprite_ai_state[k]++;
-    break;
-  case 1:  //
-    if (choice_in_multiselect_box || !ShopItem_HandleCost(100)) {
-      Sprite_ShowMessageUnconditional(0x11c);
-      sprite_subtype2[k] = 3;
-    } else {
-      Sprite_ShowMessageUnconditional(0x11d);
-      flag_is_link_immobilized++;
-      sprite_ai_state[k]++;
-      sprite_D[k] = 0;
-    }
-    break;
-  case 2:  //
-  case 4:  //
-  case 6: { //
-    static const uint16 kKiki_Leave_X[3] = {0xf4f, 0xf70, 0xf5d};
-    static const uint16 kKiki_Leave_Y[3] = { 0x661, 0x64c, 0x624 };
-
-    sprite_graphics[k] = frame_counter >> 3 & 1;
-    j = (sprite_ai_state[k] >> 1) - 1;
-    if ((uint8)(kKiki_Leave_X[j] - sprite_x_lo[k] + 2) < 4 &&
-        (uint8)(kKiki_Leave_Y[j] - sprite_y_lo[k] + 2) < 4) {
-      sprite_ai_state[k]++;
-      sprite_x_vel[k] = sprite_y_vel[k] = 0;
-      sprite_delay_aux1[k] = 32;
-      SpriteSfx_QueueSfx2WithPan(k, 0x21);
-      return;
-    }
-    ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLocation(k, kKiki_Leave_X[j], kKiki_Leave_Y[j], 9);
-    sprite_x_vel[k] = pt.x;
-    sprite_y_vel[k] = pt.y;
-    break;
-  }
-  case 3:  //
-  case 5:  //
-    if (!sprite_delay_aux1[k]) {
-      static const uint8 kKiki_Zvel[2] = {32, 28};
-      sprite_z_vel[k] = kKiki_Zvel[sprite_ai_state[k]++ >> 1 & 1];
-      SpriteSfx_QueueSfx2WithPan(k, 0x20);
-      sprite_D[k] = sprite_ai_state[k] >> 1 & 1 | 4;
-    } else {
-      sprite_D[k] = sprite_ai_state[k] >> 1 & 1 | 6;
-      sprite_graphics[k] = frame_counter >> 3 & 1;
-    }
-    break;
-  case 7: { //
-    static const uint8 kKiki_Tab7[3] = {2, 1, 0xff};
-    static const uint8 kKiki_Delay7[2] = {82, 0};
-    static const int8 kKiki_Xvel7[4] = {0, 0, -9, 9};
-    static const int8 kKiki_Yvel7[4] = {-9, 9, 0, 0};
-    sprite_graphics[k] = frame_counter >> 3 & 1;
-    if (sprite_z[k] || sprite_delay_main[k])
-      return;
-    j = sprite_A[k]++;
-    t = kKiki_Tab7[j];
-    if (!sign8(t)) {
-      sprite_D[k] = t;
-      sprite_delay_main[k] = kKiki_Delay7[j];
-      sprite_x_vel[k] = kKiki_Xvel7[t];
-      sprite_y_vel[k] = kKiki_Yvel7[t];
-    } else {
-      sprite_ai_state[k]++;
-      sprite_x_vel[k] = sprite_y_vel[k] = 0;
-      trigger_special_entrance = 1;
-      subsubmodule_index = 0;
-      overworld_entrance_sequence_counter = 0;
-      sprite_D[k] = 0;
-      flag_is_link_immobilized = 0;
-    }
-    break;
-  }
-  case 8:  //
-    sprite_D[k] = 8;
-    sprite_graphics[k] = 0;
-    sprite_z_vel[k] = (GetRandomNumber() & 15) + 16;
-    sprite_ai_state[k]++;
-    break;
-  case 9:  //
-    if (sign8(sprite_z_vel[k]) && !sprite_z[k]) {
-      sprite_ai_state[k]++;
-      SpriteSfx_QueueSfx3WithPan(k, 0x25);
-    }
-    break;
-  case 10:  //
-    break;
-  }
-}
-
-bool Kiki_Draw(int k) {  // 9ee859
-  static const DrawMultipleData kKiki_Dmd1[32] = {
-    { 0, -6, 0x0020, 2},
-    { 0,  0, 0x0022, 2},
-    { 0, -6, 0x0020, 2},
-    { 0,  0, 0x4022, 2},
-    { 0, -6, 0x0020, 2},
-    { 0,  0, 0x0022, 2},
-    { 0, -6, 0x0020, 2},
-    { 0,  0, 0x4022, 2},
-    {-1, -6, 0x0020, 2},
-    { 0,  0, 0x0022, 2},
-    {-1, -6, 0x0020, 2},
-    { 0,  0, 0x0022, 2},
-    { 1, -6, 0x4020, 2},
-    { 0,  0, 0x4022, 2},
-    { 1, -6, 0x4020, 2},
-    { 0,  0, 0x4022, 2},
-    { 0, -6, 0x01ce, 2},
-    { 0,  0, 0x01ee, 2},
-    { 0, -6, 0x01ce, 2},
-    { 0,  0, 0x01ee, 2},
-    { 0, -6, 0x41ce, 2},
-    { 0,  0, 0x41ee, 2},
-    { 0, -6, 0x41ce, 2},
-    { 0,  0, 0x41ee, 2},
-    {-1, -6, 0x01ce, 2},
-    { 0,  0, 0x01ec, 2},
-    {-1, -6, 0x41ce, 2},
-    { 0,  0, 0x01ec, 2},
-    { 1, -6, 0x41ce, 2},
-    { 0,  0, 0x41ec, 2},
-    { 1, -6, 0x01ce, 2},
-    { 0,  0, 0x41ec, 2},
-  };
-  static const DrawMultipleData kKiki_Dmd2[12] = {
-    {0, -6, 0x01ca, 0},
-    {8, -6, 0x41ca, 0},
-    {0,  2, 0x01da, 0},
-    {8,  2, 0x41da, 0},
-    {0, 10, 0x01cb, 0},
-    {8, 10, 0x41cb, 0},
-    {0, -6, 0x01db, 0},
-    {8, -6, 0x41db, 0},
-    {0,  2, 0x01cc, 0},
-    {8,  2, 0x41cc, 0},
-    {0, 10, 0x01dc, 0},
-    {8, 10, 0x41dd, 0},
-  };
-  static const uint8 kKikiDma[32] = {
-    0x20, 0xc0, 0x20, 0xc0, 0, 0xa0, 0, 0xa0, 0x40, 0x80, 0x40, 0x60, 0x40, 0x80, 0x40, 0x60,
-    0, 0, 0xfa, 0xff, 0x20, 0, 0, 2, 0, 0, 0, 0, 0x22, 0, 0, 2  // zelda bug: OOB read
-  };
-  PrepOamCoordsRet info;
-  if (sprite_D[k] < 8) {
-    int j = sprite_D[k] * 2 + sprite_graphics[k];
-    BYTE(dma_var6) = kKikiDma[j * 2 + 0];
-    BYTE(dma_var7) = kKikiDma[j * 2 + 1];
-    Sprite_DrawMultiple(k, &kKiki_Dmd1[j * 2], 2, &info);
-    if (!sprite_pause[k])
-      SpriteDraw_Shadow(k, &info);
-  } else {
-    Sprite_DrawMultiple(k, &kKiki_Dmd2[sprite_graphics[k] * 6], 6, &info);
-    if (!sprite_pause[k])
-      SpriteDraw_Shadow(k, &info);
-  }
-
-  return ((info.x | info.y) & 0xff00) != 0;
-}
-
-void Sprite_B7_BlindMaiden(int k) {  // 9ee8b6
-  CrystalMaiden_Draw(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  Sprite_TrackBodyToHead(k);
-  sprite_head_dir[k] = Sprite_DirectionToFaceLink(k, NULL) ^ 3;
-  if (!sprite_ai_state[k]) {
-    if (Sprite_ShowMessageOnContact(k, 0x122) & 0x100)
-      sprite_ai_state[k] = 1;
-  } else {
-    sprite_state[k] = 0;
-    follower_indicator = 6;
-    LoadFollowerGraphics();
-    Sprite_BecomeFollower(k);
-  }
-}
-
-void OldMan_RevertToSprite(int k) {  // 9ee938
-  SpriteSpawnInfo info;
-  int j = Sprite_SpawnDynamically(k, 0xAD, &info);
-  sprite_D[j] = sprite_head_dir[j] = tagalong_layerbits[k] & 3;
-  Sprite_SetY(j, (tagalong_y_lo[k] | tagalong_y_hi[k] << 8) + 2);
-  Sprite_SetX(j, (tagalong_x_lo[k] | tagalong_x_hi[k] << 8) + 2);
-  sprite_floor[j] = link_is_on_lower_level;
-  sprite_ignore_projectile[j] = 1;
-  sprite_subtype2[j] = 1;
-  OldMan_EnableCutscene();
-  follower_indicator = 0;
-  link_speed_setting = 0;
-}
-
-void OldMan_EnableCutscene() {  // 9ee989
-  flag_is_link_immobilized = 1;
-  link_disable_sprite_damage = 1;
-}
-
-void Sprite_AD_OldMan(int k) {  // 9ee992
-  static const uint16 kOldMountainManMsgs[3] = {0x9e, 0x9f, 0xa0};
-  int j;
-  OldMountainMan_Draw(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  switch(sprite_subtype2[k]) {
-  case 0: // lost
-    switch (sprite_ai_state[k]) {
-    case 0: // supplicate
-      Sprite_TrackBodyToHead(k);
-      sprite_head_dir[k] = Sprite_DirectionToFaceLink(k, NULL) ^ 3;
-      j = Sprite_ShowMessageOnContact(k, 0x9c);
-      if (j & 0x100) {
-        sprite_D[k] = sprite_head_dir[k] = j;
-        sprite_ai_state[k] = 1;
-      }
-      break;
-    case 1: // switch to tagalong
-      follower_indicator = 4;
-      Sprite_BecomeFollower(k);
-      which_starting_point = 5;
-      sprite_state[k] = 0;
-      CacheCameraProperties();
-      break;
-    }
-    break;
-  case 1: // entering domicile
-    Sprite_MoveXY(k);
-    switch(sprite_ai_state[k]) {
-    case 0:  // grant mirror
-      sprite_ai_state[k]++;
-      item_receipt_method = 0;
-      Link_ReceiveItem(0x1a, 0);
-      which_starting_point = 1;
-      OldMan_EnableCutscene();
-      sprite_delay_main[k] = 48;
-      sprite_x_vel[k] = 8;
-      sprite_y_vel[k] = 4;
-      sprite_D[k] = sprite_head_dir[k] = 3;
-      break;
-    case 1:  // shuffle away
-      OldMan_EnableCutscene();
-      if (!sprite_delay_main[k])
-        sprite_ai_state[k]++;
-      sprite_graphics[k] = (k ^ frame_counter) >> 3 & 1;
-      break;
-    case 2: { // approach door
-      sprite_head_dir[k] = 0;
-      sprite_D[k] = 0;
-      j = byte_7E0FDE;
-      int x = overlord_x_lo[j] | overlord_x_hi[j] << 8;
-      int y = overlord_y_lo[j] | overlord_y_hi[j] << 8;
-      if (y >= Sprite_GetY(k)) {
-        sprite_ai_state[k]++;
-        sprite_y_vel[k] = sprite_x_vel[k] = 0;
-      } else {
-        ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLocation(k, x, y, 8);
-        sprite_y_vel[k] = pt.y;
-        sprite_x_vel[k] = pt.x;
-        sprite_graphics[k] = (k ^ frame_counter) >> 3 & 1;
-        OldMan_EnableCutscene();
-      }
-      break;
-    }
-    case 3:  // made it inside
-      sprite_state[k] = 0;
-      flag_is_link_immobilized = 0;
-      link_disable_sprite_damage = 0;
-      break;
-    }
-    break;
-  case 2: // sitting at home
-    Sprite_BehaveAsBarrier(k);
-    if (sprite_ai_state[k]) {
-      link_hearts_filler = 160;
-      sprite_ai_state[k] = 0;
-    }
-    j = sram_progress_indicator >= 3 ? 2 : link_item_moon_pearl;
-    if (Sprite_ShowSolicitedMessage(k, kOldMountainManMsgs[j]) & 0x100)
-      sprite_ai_state[k]++;
-
-    break;
-  }
-}
-
-void Sprite_B8_DialogueTester(int k) {  // 9eeae7
-  assert(0);
-}
-
-void Sprite_B9_BullyAndPinkBall(int k) {  // 9eeb33
-  switch(sprite_subtype2[k]) {
-  case 0: Sprite_PinkBall(k); return;
-  case 1: PinkBall_Distress(k); return;
-  case 2: Sprite_Bully(k); return;
-  }
-}
-
-void Sprite_PinkBall(int k) {  // 9eeb40
-  Oam_AllocateDeferToPlayer(k);
-  SpriteDraw_SingleLarge(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  PinkBall_HandleMessage(k);
-  sprite_oam_flags[k] = sprite_oam_flags[k] & ~0x80 | sprite_head_dir[k];
-  Sprite_MoveXYZ(k);
-  int t = Sprite_CheckTileCollision(k);
-  if (t) {
-    if (!(t & 3)) {
-      sprite_y_vel[k] = -sprite_y_vel[k];
-      if (sprite_E[k])
-        goto play_sound;
-    }
-    sprite_x_vel[k] = -sprite_x_vel[k];
-    if (sprite_E[k]) {
-play_sound:
-      BallGuy_PlayBounceNoise(k);
-    }
-  }
-
-  sprite_z_vel[k]--;
-  if (sign8(sprite_z[k])) {
-    sprite_z[k] = 0;
-    sprite_z_vel[k] = (uint8)-sprite_z_vel[k] >> 2;
-    if (sprite_z_vel[k] & 0xfc)
-      BallGuy_PlayBounceNoise(k);
-    PinkBall_HandleDeceleration(k);
-  }
-  if (!sprite_E[k]) {
-    if (!sprite_head_dir[k]) {
-      PinkBall_Distress(k);
-      sprite_graphics[k] = (k ^ frame_counter) >> 3 & 1;
-      if (!((k ^ frame_counter) & 0x3f)) {
-        uint16 x = (link_x_coord & 0xff00) | GetRandomNumber();
-        uint16 y = (link_y_coord & 0xff00) | GetRandomNumber();
-        ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLocation(k, x, y, 8);
-        sprite_B[k] = pt.x;
-        sprite_A[k] = pt.y;
-        if (pt.y) {
-          sprite_oam_flags[k] |= 64;
-          sprite_oam_flags[k] ^= sprite_x_vel[k] >> 1 & 64;
-        }
-      }
-      sprite_x_vel[k] = sprite_B[k];
-      sprite_y_vel[k] = sprite_A[k];
-    } else {
-      PinkBall_Distress(k);
-      if (k ^ frame_counter) {
-        sprite_graphics[k] = (k ^ frame_counter) >> 2 & 1;
-        sprite_x_vel[k] = 0;
-        sprite_y_vel[k] = 0;
-      } else {
-        sprite_head_dir[k] = 0;
-      }
-    }
-  } else {
-    if ((sprite_x_vel[k] | sprite_y_vel[k]) == 0) {
-      sprite_E[k] = 0;
-    } else {
-      sprite_graphics[k] = (k ^ frame_counter) >> 2 & 1;
-      sprite_head_dir[k] = (k ^ frame_counter) << 2 & 128;
-    }
-  }
-}
-
-void PinkBall_HandleDeceleration(int k) {  // 9eec4d
-  if (sprite_x_vel[k])
-    sprite_x_vel[k] += sign8(sprite_x_vel[k]) ? 2 : -2;
-  if (sprite_y_vel[k])
-    sprite_y_vel[k] += sign8(sprite_y_vel[k]) ? 2 : -2;
-}
-
-void PinkBall_Distress(int k) {  // 9eec74
-  PrepOamCoordsRet info;
-  if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
-    return;
-  Sprite_DrawDistress_custom(info.x, info.y, frame_counter);
-}
-
-void Sprite_Bully(int k) {  // 9eec7c
-  Bully_Draw(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  Bully_HandleMessage(k);
-  Sprite_MoveXYZ(k);
-  int t = Sprite_CheckTileCollision(k);
-  if (t) {
-    if (!(t & 3))
-      sprite_y_vel[k] = -sprite_y_vel[k];
-    else
-      sprite_x_vel[k] = -sprite_x_vel[k];
-  }
-  switch(sprite_ai_state[k]) {
-  case 0: { // chase
-    sprite_graphics[k] = (k ^ frame_counter) >> 3 & 1;
-    int j = sprite_head_dir[k];
-    if (!((k ^ frame_counter) & 0x1f)) {
-      ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLocation(k, Sprite_GetX(j), Sprite_GetY(j), 14);
-      sprite_y_vel[k] = pt.y;
-      sprite_x_vel[k] = pt.x;
-      if (pt.x)
-        sprite_D[k] = sprite_x_vel[k] >> 7;
-    }
-    if (!sprite_z[j]) {
-      if ((uint8)(sprite_x_lo[k] - sprite_x_lo[j] + 8) < 16 &&
-          (uint8)(sprite_y_lo[k] - sprite_y_lo[j] + 8) < 16) {
-        sprite_ai_state[k]++;
-        BallGuy_PlayBounceNoise(k);
-      }
-    }
-    break;
-  }
-  case 1: { // kick ball
-    sprite_ai_state[k] = 2;
-    int j = sprite_head_dir[k];
-    sprite_x_vel[j] = sprite_x_vel[k] << 1;
-    sprite_y_vel[j] = sprite_y_vel[k] << 1;
-    sprite_x_vel[k] = 0;
-    sprite_y_vel[k] = 0;
-    sprite_z_vel[j] = GetRandomNumber() & 31;
-    sprite_delay_main[k] = 96;
-    sprite_graphics[k] = 1;
-    sprite_E[j] = 1;
-    break;
-  }
-  case 2:  // waiting
-    if (!sprite_delay_main[k])
-      sprite_ai_state[k] = 0;
-    break;
-  }
-}
-
-void Bully_Draw(int k) {  // 9eed9e
-  static const DrawMultipleData kBully_Dmd[8] = {
-    {0, -7, 0x46e0, 2},
-    {0,  0, 0x46e2, 2},
-    {0, -7, 0x46e0, 2},
-    {0,  0, 0x46c4, 2},
-    {0, -7, 0x06e0, 2},
-    {0,  0, 0x06e2, 2},
-    {0, -7, 0x06e0, 2},
-    {0,  0, 0x06c4, 2},
-  };
-  PrepOamCoordsRet info;
-  Sprite_DrawMultiplePlayerDeferred(k, &kBully_Dmd[sprite_D[k] * 4 + sprite_graphics[k] * 2], 2, &info);
-  SpriteDraw_Shadow(k, &info);
-
-}
-
-void BallGuy_PlayBounceNoise(int k) {  // 9eedc2
-  SpriteSfx_QueueSfx3WithPan(k, 0x32);
-}
-
-void SpawnBully(int k) {  // 9eedc9
-  SpriteSpawnInfo info;
-  int j = Sprite_SpawnDynamically(k, 0xB9, &info);
-  if (j >= 0) {
-    Sprite_SetSpawnedCoordinates(j, &info);
-    sprite_subtype2[j] = 2;
-    sprite_head_dir[j] = k;
-    sprite_ignore_projectile[j] = 1;
-  }
-}
-
-void PinkBall_HandleMessage(int k) {  // 9eede8
-  if (sprite_delay_aux4[k])
-    return;
-  int msg = link_item_moon_pearl & 1 ? 0x15c : 0x15b;
-  if (Sprite_ShowMessageOnContact(k, msg) & 0x100) {
-    sprite_x_vel[k] ^= 255;
-    sprite_y_vel[k] ^= 255;
-    if (sprite_E[k])
-      BallGuy_PlayBounceNoise(k);
-    sprite_delay_aux4[k] = 64;
-  }
-}
-
-void Bully_HandleMessage(int k) {  // 9eee25
-  if (sprite_delay_aux4[k])
-    return;
-  int msg = link_item_moon_pearl & 1 ? 0x15e : 0x15d;
-  if (Sprite_ShowMessageOnContact(k, msg) & 0x100) {
-    sprite_x_vel[k] ^= 255;
-    sprite_y_vel[k] ^= 255;
-    sprite_delay_aux4[k] = 64;
-  }
-}
-
-void Sprite_BA_Whirlpool(int k) {  // 9eee5a
-  static const uint8 kWhirlpool_OamFlags[4] = {0, 0x40, 0xc0, 0x80};
-
-  if (BYTE(overworld_screen_index) == 0x1b) {
-    PrepOamCoordsRet info;
-    Sprite_PrepOamCoord(k, &info);
-    if (Sprite_ReturnIfInactive(k))
-      return;
-    uint16 x = cur_sprite_x - link_x_coord + 0x40;
-    uint16 y = cur_sprite_y - link_y_coord + 0xf;
-    if (x < 0x51 && y < 0x12) {
-      submodule_index = 35;
-      link_triggered_by_whirlpool_sprite = 1;
-      subsubmodule_index = 0;
-      link_actual_vel_y = 0;
-      link_actual_vel_x = 0;
-      link_player_handler_state = 20;
-      last_light_vs_dark_world = overworld_screen_index & 0x40;
-    }
-  } else {
-    sprite_oam_flags[k] = (sprite_oam_flags[k] & 0x3f) | kWhirlpool_OamFlags[frame_counter >> 3 & 3];
-    Oam_AllocateFromRegionB(4);
-    cur_sprite_x -= 5;
-    SpriteDraw_SingleLarge(k);
-    if (Sprite_ReturnIfInactive(k))
-      return;
-    if (Sprite_CheckDamageToLink_same_layer(k)) {
-      if (sprite_A[k] == 0) {
-        submodule_index = 46;
-        subsubmodule_index = 0;
-      }
-    } else {
-      sprite_A[k] = 0;
-    }
-  }
-}
-
-void Sprite_BB_Shopkeeper(int k) {  // 9eeeef
-  switch (sprite_subtype2[k]) {
-  case 0: Shopkeeper_StandardClerk(k); break;
-  case 1: ChestGameGuy(k); break;
-  case 2: NiceThiefWithGift(k); break;
-  case 3: MiniChestGameGuy(k); break;
-  case 4: LostWoodsChestGameGuy(k); break;
-  case 5:
-  case 6: NiceThiefUnderRock(k); break;
-  case 7: ShopItem_RedPotion150(k); break;
-  case 8: ShopItem_FighterShield(k); break;
-  case 9: ShopItem_FireShield(k); break;
-  case 10: ShopItem_Heart(k); break;
-  case 11: ShopItem_Arrows(k); break;
-  case 12: ShopItem_Bombs(k); break;
-  case 13: ShopItem_Bee(k); break;
-  }
-}
-
-void Shopkeeper_StandardClerk(int k) {  // 9eef12
-  if (is_in_dark_world) {
-    Oam_AllocateDeferToPlayer(k);
-    SpriteDraw_SingleLarge(k);
-    if (Sprite_ReturnIfInactive(k))
-      return;
-    sprite_oam_flags[k] = (sprite_oam_flags[k] & 63) | (frame_counter << 3 & 64);
-  } else {
-    sprite_oam_flags[k] = 7;
-    Shopkeeper_Draw(k);
-    if (Sprite_ReturnIfInactive(k))
-      return;
-    sprite_graphics[k] = frame_counter >> 4 & 1;
-  }
-  Sprite_BehaveAsBarrier(k);
-  int msg = is_in_dark_world == 0 ? 0x165 : 0x15f;
-  Sprite_ShowSolicitedMessage(k, msg);
-  if (sprite_ai_state[k] == 0 && (uint16)(cur_sprite_y + 0x60) >= link_y_coord) {
-    Sprite_ShowMessageUnconditional(msg);
-    sprite_ai_state[k] = 1;
-  }
-}
-
-void ChestGameGuy(int k) {  // 9eef90
-  Oam_AllocateDeferToPlayer(k);
-  SpriteDraw_SingleLarge(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  Sprite_BehaveAsBarrier(k);
-  sprite_oam_flags[k] = (sprite_oam_flags[k] & 63) | (frame_counter << 3 & 64);
-  switch (sprite_ai_state[k]) {
-  case 0:
-    if ((uint8)(minigame_credits - 1) >= 2 && Sprite_ShowSolicitedMessage(k, 0x160) & 0x100)
-      sprite_ai_state[k] = 1;
-    break;
-  case 1:
-    if (choice_in_multiselect_box == 0 && ShopItem_HandleCost(30)) {
-      minigame_credits = 2;
-      Sprite_ShowMessageUnconditional(0x164);
-      sprite_ai_state[k] = 2;
-    } else {
-      Sprite_ShowMessageUnconditional(0x161);
-      sprite_ai_state[k] = 0;
-    }
-    break;
-  case 2:
-    if (minigame_credits == 0)
-      Sprite_ShowSolicitedMessage(k, 0x163);
-    else
-      Sprite_ShowSolicitedMessage(k, 0x17f);
-    break;
-  }
-}
-
-void NiceThief_Animate(int k) {  // 9ef017
-  if (!(frame_counter & 3)) {
-    sprite_graphics[k] = 2;
-    uint8 dir = Sprite_DirectionToFaceLink(k, NULL);
-    sprite_head_dir[k] = (dir == 3) ? 2 : dir;
-  }
-  Oam_AllocateDeferToPlayer(k);
-  Thief_Draw(k);
-}
-
-void NiceThiefWithGift(int k) {  // 9ef038
-  NiceThief_Animate(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  Sprite_BehaveAsBarrier(k);
-  switch (sprite_ai_state[k]) {
-  case 0:
-    if (Sprite_ShowSolicitedMessage(k, 0x176) & 0x100)
-      sprite_ai_state[k] = 1;
-    break;
-  case 1:
-    if (!(dung_savegame_state_bits & 0x4000)) {
-      dung_savegame_state_bits |= 0x4000;
-      sprite_ai_state[k] = 2;
-      ShopItem_HandleReceipt(k, 0x46);
-    } else {
-      sprite_ai_state[k] = 0;
-    }
-    break;
-  case 2:
-    sprite_ai_state[k] = 0;
-    break;
-  }
-}
-
-void MiniChestGameGuy(int k) {  // 9ef078
-  sprite_D[k] = Sprite_DirectionToFaceLink(k, NULL) ^ 3;
-  sprite_graphics[k] = 0;
-  MazeGameGuy_Draw(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  Sprite_BehaveAsBarrier(k);
-  switch (sprite_ai_state[k]) {
-  case 0:
-    if ((uint8)(minigame_credits - 1) >= 2 && Sprite_ShowSolicitedMessage(k, 0x17e) & 0x100)
-      sprite_ai_state[k] = 1;
-    break;
-  case 1:
-    if (choice_in_multiselect_box == 0 && ShopItem_HandleCost(20)) {
-      minigame_credits = 1;
-      Sprite_ShowMessageUnconditional(0x17f);
-      sprite_ai_state[k] = 2;
-    } else {
-      Sprite_ShowMessageUnconditional(0x180);
-      sprite_ai_state[k] = 0;
-    }
-    break;
-  case 2:
-    Sprite_ShowSolicitedMessage(k, (minigame_credits == 0) ? 0x163 : 0x17f);
-    break;
-  }
-
-}
-
-void LostWoodsChestGameGuy(int k) {  // 9ef0f3
-  NiceThief_Animate(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  Sprite_BehaveAsBarrier(k);
-  switch (sprite_ai_state[k]) {
-  case 0:
-    if ((uint8)(minigame_credits - 1) >= 2 && Sprite_ShowSolicitedMessage(k, 0x181) & 0x100)
-      sprite_ai_state[k] = 1;
-    break;
-  case 1:
-    if (choice_in_multiselect_box == 0 && ShopItem_HandleCost(100)) {
-      minigame_credits = 1;
-      Sprite_ShowMessageUnconditional(0x17f);
-      sprite_ai_state[k] = 2;
-    } else {
-      Sprite_ShowMessageUnconditional(0x180);
-      sprite_ai_state[k] = 0;
-    }
-    break;
-  case 2:
-    Sprite_ShowSolicitedMessage(k, (minigame_credits == 0) ? 0x163 : 0x17f);
-    break;
-  }
-}
-
-void NiceThiefUnderRock(int k) {  // 9ef14f
-  NiceThief_Animate(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  Sprite_BehaveAsBarrier(k);
-  Sprite_ShowSolicitedMessage(k, sprite_subtype2[k] == 5 ? 0x177 : 0x178);
-}
-
-void ShopItem_RedPotion150(int k) {  // 9ef16e
-  SpriteDraw_ShopItem(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  Sprite_BehaveAsBarrier(k);
-  if (ShopItem_CheckForAPress(k)) {
-    if (Sprite_Find_EmptyBottle() < 0) {
-      Sprite_ShowMessageUnconditional(0x16d);
-      ShopItem_PlayBeep(k);
-    } else if (ShopItem_HandleCost(150)) {
-      sprite_state[k] = 0;
-      ShopItem_HandleReceipt(k, 0x2e);
-    } else {
-      Sprite_ShowMessageUnconditional(0x17c);
-      ShopItem_PlayBeep(k);
-    }
-  }
-}
-
-void ShopKeeper_SpawnShopItem(int k, int pos, int what) {  // 9ef1b3
-  static const int8 kShopKeeper_ItemX[3] = {-44, 8, 60};
-  SpriteSpawnInfo info;
-  int j = Sprite_SpawnDynamicallyEx(k, 0xbb, &info, 12);
-  assert(j >= 0);
-  sprite_ignore_projectile[j] = sprite_subtype2[j] = what;
-  Sprite_SetX(j, info.r0_x + kShopKeeper_ItemX[pos]);
-  Sprite_SetY(j, info.r2_y + 0x27);
-  sprite_flags2[j] |= 4;
-}
-
-void ShopItem_FighterShield(int k) {  // 9ef1f2
-  SpriteDraw_ShopItem(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  Sprite_BehaveAsBarrier(k);
-  ShopItem_MakeShieldsDeflect(k);
-  if (ShopItem_CheckForAPress(k)) {
-    if (link_shield_type) {
-      Sprite_ShowMessageUnconditional(0x166);
-      ShopItem_PlayBeep(k);
-      return;
-    }
-    if (!ShopItem_HandleCost(50)) {
-      Sprite_ShowMessageUnconditional(0x17c);
-      ShopItem_PlayBeep(k);
-      return;
-    }
-    sprite_state[k] = 0;
-    ShopItem_HandleReceipt(k, 4);
-  }
-  sprite_flags4[k] = 0x1c;
-}
-
-void ShopItem_FireShield(int k) {  // 9ef230
-  SpriteDraw_ShopItem(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  Sprite_BehaveAsBarrier(k);
-  ShopItem_MakeShieldsDeflect(k);
-  if (ShopItem_CheckForAPress(k)) {
-    if (link_shield_type >= 2) {
-      Sprite_ShowMessageUnconditional(0x166);
-      ShopItem_PlayBeep(k);
-      return;
-    }
-    if (!ShopItem_HandleCost(500)) {
-      Sprite_ShowMessageUnconditional(0x17c);
-      ShopItem_PlayBeep(k);
-      return;
-    }
-    sprite_state[k] = 0;
-    ShopItem_HandleReceipt(k, 5);
-  }
-  sprite_flags4[k] = 0x1c;
-}
-
-void ShopItem_MakeShieldsDeflect(int k) {  // 9ef261
-  sprite_ignore_projectile[k] = 0;
-  sprite_flags[k] = 8;
-  sprite_defl_bits[k] = 4;
-  sprite_flags4[k] = 0x1c;
-  Sprite_CheckDamageFromLink(k);
-  sprite_flags4[k] = 0xa;
-}
-
-void ShopItem_Heart(int k) {  // 9ef27d
-  SpriteDraw_ShopItem(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  Sprite_BehaveAsBarrier(k);
-  if (ShopItem_CheckForAPress(k)) {
-    if (link_health_current == link_health_capacity) {
-      ShopItem_PlayBeep(k);
-    } else if (ShopItem_HandleCost(10)) {
-      sprite_state[k] = 0;
-      ShopItem_HandleReceipt(k, 0x42);
-    } else {
-      Sprite_ShowMessageUnconditional(0x17c);
-      ShopItem_PlayBeep(k);
-    }
-  }
-}
-
-void ShopItem_Arrows(int k) {  // 9ef2af
-  SpriteDraw_ShopItem(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  Sprite_BehaveAsBarrier(k);
-  if (ShopItem_CheckForAPress(k)) {
-    if (link_num_arrows == kMaxArrowsForLevel[link_arrow_upgrades]) {
-      Sprite_ShowSolicitedMessage(k, 0x16e);
-      ShopItem_PlayBeep(k);
-    } else if (ShopItem_HandleCost(30)) {
-      sprite_state[k] = 0;
-      ShopItem_HandleReceipt(k, 0x44);
-    } else {
-      Sprite_ShowMessageUnconditional(0x17c);
-      ShopItem_PlayBeep(k);
-    }
-  }
-}
-
-void ShopItem_Bombs(int k) {  // 9ef2f0
-  SpriteDraw_ShopItem(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  Sprite_BehaveAsBarrier(k);
-  if (ShopItem_CheckForAPress(k)) {
-    if (link_item_bombs == kMaxBombsForLevel[link_bomb_upgrades]) {
-      Sprite_ShowSolicitedMessage(k, 0x16e);
-      ShopItem_PlayBeep(k);
-    } else if (ShopItem_HandleCost(50)) {
-      sprite_state[k] = 0;
-      ShopItem_HandleReceipt(k, 0x31);
-    } else {
-      Sprite_ShowMessageUnconditional(0x17c);
-      ShopItem_PlayBeep(k);
-    }
-  }
-}
-
-void ShopItem_Bee(int k) {  // 9ef322
-  SpriteDraw_ShopItem(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  Sprite_BehaveAsBarrier(k);
-  if (ShopItem_CheckForAPress(k)) {
-    if (Sprite_Find_EmptyBottle() < 0) {
-      Sprite_ShowSolicitedMessage(k, 0x16d);
-      ShopItem_PlayBeep(k);
-    } else if (ShopItem_HandleCost(10)) {
-      sprite_state[k] = 0;
-      ShopItem_HandleReceipt(k, 0xe);
-    } else {
-      Sprite_ShowMessageUnconditional(0x17c);
-      ShopItem_PlayBeep(k);
-    }
-  }
-}
-
-void ShopItem_HandleReceipt(int k, uint8 item) {  // 9ef366
-  static const uint16 kShopKeeper_GiveItemMsgs[7] = {0x168, 0x167, 0x167, 0x16c, 0x169, 0x16a, 0x16b};
-  item_receipt_method = 0;
-  Link_ReceiveItem(item, 0);
-  int j = sprite_subtype2[k];
-  if (j >= 7) {
-    Sprite_ShowMessageUnconditional(kShopKeeper_GiveItemMsgs[j - 7]);
-    ShopKeeper_RapidTerminateReceiveItem();
-  }
-}
-
-void ShopItem_PlayBeep(int k) {  // 9ef38a
-  SpriteSfx_QueueSfx2WithPan(k, 0x3c);
-}
-
-bool ShopItem_CheckForAPress(int k) {  // 9ef391
-  if (!(filtered_joypad_L & 0x80))
-    return false;
-  return Sprite_CheckDamageToLink_same_layer(k);
-}
-
-bool ShopItem_HandleCost(int amt) {  // 9ef39e
-  if (amt > link_rupees_goal)
-    return false;
-  link_rupees_goal -= amt;
-  return true;
-}
-
-void SpriteDraw_ShopItem(int k) {  // 9ef4ce
-  static const DrawMultipleData kShopKeeper_ItemWithPrice_Dmd[35] = {
-    {-4, 16, 0x0231, 0},
-    { 4, 16, 0x0213, 0},
-    {12, 16, 0x0230, 0},
-    { 0,  0, 0x02c0, 2},
-    { 0, 11, 0x036c, 2},
-    { 0, 16, 0x0213, 0},
-    { 0, 16, 0x0213, 0},
-    { 8, 16, 0x0230, 0},
-    { 0,  0, 0x04ce, 2},
-    { 4, 12, 0x0338, 0},
-    {-4, 16, 0x0213, 0},
-    { 4, 16, 0x0230, 0},
-    {12, 16, 0x0230, 0},
-    { 0,  0, 0x08cc, 2},
-    { 4, 12, 0x0338, 0},
-    { 0, 16, 0x0231, 0},
-    { 0, 16, 0x0231, 0},
-    { 8, 16, 0x0230, 0},
-    { 4,  8, 0x0329, 0},
-    { 4, 11, 0x0338, 0},
-    {-4, 16, 0x0203, 0},
-    {-4, 16, 0x0203, 0},
-    { 4, 16, 0x0230, 0},
-    { 0,  0, 0x04c4, 2},
-    { 0, 11, 0x0338, 0},
-    { 0, 16, 0x0213, 0},
-    { 0, 16, 0x0213, 0},
-    { 8, 16, 0x0230, 0},
-    { 0,  0, 0x04e8, 2},
-    { 0, 11, 0x036c, 2},
-    { 0, 16, 0x0231, 0},
-    { 0, 16, 0x0231, 0},
-    { 8, 16, 0x0230, 0},
-    { 4,  8, 0x0ff4, 0},
-    { 4, 11, 0x0338, 0},
-  };
-  Sprite_DrawMultiplePlayerDeferred(k, &kShopKeeper_ItemWithPrice_Dmd[(sprite_subtype2[k] - 7) * 5], 5, NULL);
-}
-
-void Sprite_AC_Apple(int k) {  // 9ef515
-  if (sprite_ai_state[k]) {
-    Sprite_Apple(k);
-    return;
-  }
-  if (sprite_E[k] == 0) {
-    sprite_state[k] = 0;
-    int n = (GetRandomNumber() & 3) + 2;
-    do {
-      SpawnApple(k);
-    } while (--n >= 0);
-  }
-}
-
-void SpawnApple(int k) {  // 9ef535
-  SpriteSpawnInfo info;
-  int j = Sprite_SpawnDynamically(k, 0xac, &info);
-  if (j < 0)
-    return;
-  Sprite_SetSpawnedCoordinates(j, &info);
-  sprite_ai_state[j] = 1;
-  sprite_A[j] = 255;
-  sprite_z[j] = 8;
-  sprite_z_vel[j] = 22;
-  uint16 x = info.r0_x & ~0xff | GetRandomNumber();
-  uint16 y = info.r2_y & ~0xff | GetRandomNumber();
-  ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLocation(k, x, y, 10);
-  sprite_x_vel[j] = pt.x;
-  sprite_y_vel[j] = pt.y;
-}
-
-void Sprite_Apple(int k) {  // 9ef57c
-  if (sprite_A[k] >= 16 || frame_counter & 2)
-    SpriteDraw_SingleLarge(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  if (sprite_A[k] == 0) {
-    sprite_state[k] = 0;
-    return;
-  }
-  Sprite_MoveXYZ(k);
-  if (Sprite_CheckDamageToLink(k)) {
-    SpriteSfx_QueueSfx3WithPan(k, 0xb);
-    link_hearts_filler += 8;
-    sprite_state[k] = 0;
-    return;
-  }
-  if (!(frame_counter & 1))
-    sprite_A[k]--;
-
-  if (!sign8(sprite_z[k] - 1)) {
-    sprite_z_vel[k] -= 1;
-    return;
-  }
-  sprite_z[k] = 0;
-  uint8 a = sign8(sprite_z_vel[k]) ? sprite_z_vel[k] : 0;
-  sprite_z_vel[k] = (uint8)(-a) >> 1;
-  if (sprite_x_vel[k])
-    sprite_x_vel[k] += sign8(sprite_x_vel[k]) ? 1 : -1;
-  if (sprite_y_vel[k])
-    sprite_y_vel[k] += sign8(sprite_y_vel[k]) ? 1 : -1;
-}
-
-void Sprite_BC_Drunkard(int k) {  // 9ef603
-  DrinkingGuy_Draw(k);
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  Sprite_BehaveAsBarrier(k);
-  if (!GetRandomNumber())
-    sprite_delay_main[k] = 32;
-  sprite_graphics[k] = sprite_delay_main[k] ? 1 : 0;
-  if (Sprite_ShowSolicitedMessage(k, 0x175) & 0x100)
-    sprite_graphics[k] = 0;
-}
-
-void SomariaPlatform_LocatePath(int k) {  // 9ef640
-  for (;;) {
-    uint8 tiletype = SomariaPlatformAndPipe_CheckTile(k);
-    sprite_E[k] = tiletype;
-    if (tiletype >= 0xb0 && tiletype < 0xbf)
-      break;
-    Sprite_SetX(k, Sprite_GetX(k) + 8);
-    Sprite_SetY(k, Sprite_GetY(k) + 8);
-  }
-  sprite_x_lo[k] = (sprite_x_lo[k] & ~7) + 4;
-  sprite_y_lo[k] = (sprite_y_lo[k] & ~7) + 4;
-  sprite_head_dir[k] = sprite_D[k];
-  SomariaPlatformAndPipe_HandleMovement(k);
-  sprite_ignore_projectile[k]++;
-  player_on_somaria_platform = 0;
-  sprite_delay_aux4[k] = 14;
-  sprite_graphics[k]++;
-}
-
-void Sprite_ED_SomariaPlatform(int k) {  // 9ef6d4
-  switch(sprite_graphics[k]) {
-  case 0: {
-    SomariaPlatform_LocatePath(k);
-    int j = Sprite_SpawnSuperficialBombBlast(k);
-    if (j >= 0) {
-      Sprite_SetX(j, Sprite_GetX(j) - 8);
-      Sprite_SetY(j, Sprite_GetY(j) - 8);
-    }
-    break;
-  }
-  case 1:
-    SomariaPlatform_Draw(k);
-    if (Sprite_ReturnIfInactive(k))
-      return;
-    if (!(drag_player_x | drag_player_y) && sign8(player_near_pit_state - 2) && Sprite_CheckDamageToLink_ignore_layer(k)) {
-      sprite_C[k] = 1;
-      Link_CancelDash();
-      if (link_player_handler_state != kPlayerState_Hookshot && link_player_handler_state != kPlayerState_SpinAttacking) {
-        if (sprite_ai_state[k]) {
-          SomariaPlatformAndPipe_HandleMovement(k);
-          return;
-        }
-        sprite_A[k]++;
-        player_on_somaria_platform = 2;
-        if (!(sprite_A[k] & 7)) {
-          uint8 a = SomariaPlatformAndPipe_CheckTile(k);
-          if (a != sprite_E[k]) {
-            sprite_E[k] = a;
-            sprite_head_dir[k] = sprite_D[k];
-            SomariaPlatformAndPipe_HandleMovement(k);
-            SomariaPlatform_HandleDrag(k);
-          }
-        }
-        if (BYTE(dungeon_room_index) != 36) {
-          static const int8 kSomariaPlatform_DragX[8] = {0, 0, -1, 1, -1, 1, 1, -1};
-          static const int8 kSomariaPlatform_DragY[8] = {-1, 1, 0, 0, -1, 1, -1, 1};
-          int j = sprite_D[k];
-          drag_player_x += kSomariaPlatform_DragX[j];
-          drag_player_y += kSomariaPlatform_DragY[j];
-          Sprite_MoveXY(k);
-          SomariaPlatform_DragLink(k);
-        } else {
-          player_on_somaria_platform = 1;
-        }
-        return;
-      }
-    }
-    if (sprite_C[k]) {
-      player_on_somaria_platform = 0;
-      sprite_C[k] = 0;
-    }
-    break;
-  }
-}
-
-void SomariaPlatformAndPipe_HandleMovement(int k) {  // 9ef7af
-  static const int8 kSomariaPlatform_Xvel[8] = {0, 0, -16, 16, -16, 16, 16, -16};
-  static const int8 kSomariaPlatform_Yvel[8] = {-16, 16, 0, 0, -16, 16, -16, 16};
-  SomariaPlatform_HandleJunctions(k);
-  int j = sprite_D[k];
-  sprite_x_vel[k] = kSomariaPlatform_Xvel[j];
-  sprite_y_vel[k] = kSomariaPlatform_Yvel[j];
-}
-
-uint8 SomariaPlatformAndPipe_CheckTile(int k) {  // 9ef7c2
-  uint16 x = Sprite_GetX(k), y = Sprite_GetY(k);
-  return GetTileAttribute(0, &x, y);
-}
-
-void SomariaPlatform_Draw(int k) {  // 9ef860
-  static const DrawMultipleData kSomariaPlatform_Dmd[16] = {
-    {-16, -16, 0x00ac, 2},
-    {  0, -16, 0x40ac, 2},
-    {-16,   0, 0x80ac, 2},
-    {  0,   0, 0xc0ac, 2},
-    {-13, -13, 0x00ac, 2},
-    { -3, -13, 0x40ac, 2},
-    {-13,  -3, 0x80ac, 2},
-    { -3,  -3, 0xc0ac, 2},
-    {-10, -10, 0x00ac, 2},
-    { -6, -10, 0x40ac, 2},
-    {-10,  -6, 0x80ac, 2},
-    { -6,  -6, 0xc0ac, 2},
-    { -8,  -8, 0x00ac, 2},
-    { -8,  -8, 0x40ac, 2},
-    { -8,  -8, 0x80ac, 2},
-    { -8,  -8, 0xc0ac, 2},
-  };
-  Oam_AllocateFromRegionB(0x10);
-  Sprite_DrawMultiple(k, &kSomariaPlatform_Dmd[sprite_delay_aux4[k] & 12], 4, NULL);
-}
-
-void SomariaPlatform_HandleJunctions(int k) {  // 9ef87d
-  switch (sprite_E[k]) {
-  case 0xb2:
-  case 0xb5:  // ZigZagRisingSlope
-    sprite_D[k] ^= 3;
-    break;
-  case 0xb3:
-  case 0xb4:  // ZigZagFallingSlope
-    sprite_D[k] ^= 2;
-    break;
-  case 0xb6: { // TransitTile
-    static const uint8 kSomariaPlatform_TransitDir[4] = {4, 8, 1, 2};
-    sprite_ai_state[k] = 1;
-    if (!link_auxiliary_state && joypad1H_last & kSomariaPlatform_TransitDir[sprite_D[k]]) {
-      sprite_ai_state[k] = 0;
-      sprite_D[k] ^= 1;
-    }
-    link_visibility_status = 0;
-    player_on_somaria_platform = 1;
-    break;
-  }
-  case 0xb7: {  // Tjunc_NoUp
-    static const uint8 kSomariaPlatform_Keys1[4] = {3, 7, 6, 5};
-    uint8 t = joypad1H_last & kSomariaPlatform_Keys1[sprite_D[k]];
-    if (t & 8) {
-      sprite_D[k] = 0;
-    } else if (t & 4) {
-      sprite_D[k] = 1;
-    } else if (t & 2) {
-      sprite_D[k] = 2;
-    } else if (t & 1) {
-      sprite_D[k] = 3;
-    } else if (sprite_D[k] == 0) {
-      sprite_D[k] = 2;
-    }
-    sprite_ai_state[k] = 0;
-    break;
-  }
-  case 0xb8: {  // Tjunc_NoDown
-    static const uint8 kSomariaPlatform_Keys2[4] = {11, 3, 10, 9};
-    uint8 t = joypad1H_last & kSomariaPlatform_Keys2[sprite_D[k]];
-    if (t & 8) {
-      sprite_D[k] = 0;
-    } else if (t & 4) {
-      sprite_D[k] = 1;
-    } else if (t & 2) {
-      sprite_D[k] = 2;
-    } else if (t & 1) {
-      sprite_D[k] = 3;
-    } else if (sprite_D[k] == 1) {
-      sprite_D[k] = 2;
-    }
-    sprite_ai_state[k] = 0;
-    break;
-  }
-  case 0xb9: {  // Tjunc_NoLeft
-    static const uint8 kSomariaPlatform_Keys3[4] = {9, 5, 12, 13};
-    uint8 t = joypad1H_last & kSomariaPlatform_Keys3[sprite_D[k]];
-    if (t & 8) {
-      sprite_D[k] = 0;
-    } else if (t & 4) {
-      sprite_D[k] = 1;
-    } else if (t & 2) {
-      sprite_D[k] = 2;
-    } else if (t & 1) {
-      sprite_D[k] = 3;
-    } else if (sprite_D[k] == 2) {
-      sprite_D[k] = 0;
-    }
-    sprite_ai_state[k] = 0;
-    break;
-  }
-  case 0xba: {  // Tjunc_NoRight
-    static const uint8 kSomariaPlatform_Keys4[4] = {0xa, 6, 0xe, 0xc};
-    uint8 t = joypad1H_last & kSomariaPlatform_Keys4[sprite_D[k]];
-    if (t & 8) {
-      sprite_D[k] = 0;
-    } else if (t & 4) {
-      sprite_D[k] = 1;
-    } else if (t & 2) {
-      sprite_D[k] = 2;
-    } else if (t & 1) {
-      sprite_D[k] = 3;
-    } else if (sprite_D[k] == 3) {
-      sprite_D[k] = 0;
-    }
-    sprite_ai_state[k] = 0;
-    break;
-  }
-  case 0xbb: {  // TransitTileNoBack
-    static const uint8 kSomariaPlatform_Keys5[4] = {0xb, 7, 0xe, 0xd};
-    uint8 t = joypad1H_last & kSomariaPlatform_Keys5[sprite_D[k]];
-    if (t & 8) {
-      sprite_D[k] = 0;
-    } else if (t & 4) {
-      sprite_D[k] = 1;
-    } else if (t & 2) {
-      sprite_D[k] = 2;
-    } else if (t & 1) {
-      sprite_D[k] = 3;
-    }
-    break;
-  }
-  case 0xbc: {  // TransitTileQuestion
-    static const uint8 kSomariaPlatform_Keys6[4] = {0xc, 0xc, 3, 3};
-    sprite_ai_state[k] = 1;
-    uint8 t = joypad1H_last & kSomariaPlatform_Keys6[sprite_D[k]];
-    if (t) {
-      if (t & 8) {
-        sprite_D[k] = 0;
-      } else if (t & 4) {
-        sprite_D[k] = 1;
-      } else if (t & 2) {
-        sprite_D[k] = 2;
-      } else {
-        sprite_D[k] = 3;
-      }
-      sprite_ai_state[k] = 0;
-    }
-    player_on_somaria_platform = 1;
-    break;
-  }
-  case 0xbe:  // endpoint
-    sprite_ai_state[k] = 0;
-    sprite_D[k] ^= 1;
-    link_visibility_status = 0;
-    player_on_somaria_platform = 1;
-    break;
-  }
-}
-
-void SomariaPlatform_HandleDragX(int k) {  // 9ef8ad
-  if ((sprite_D[k] ^ sprite_head_dir[k]) & 2) {
-    uint8 x = (sprite_x_lo[k] & ~7) + 4;
-    uint8 t = x - sprite_x_lo[k];
-    if (!t)
-      return;
-    drag_player_x = (int8)t;
-    sprite_x_lo[k] = x;
-  }
-}
-
-void SomariaPlatform_HandleDragY(int k) {  // 9ef8d7
-  if ((sprite_D[k] ^ sprite_head_dir[k]) & 2) {
-    uint8 y = (sprite_y_lo[k] & ~7) + 4;
-    uint8 t = y - sprite_y_lo[k];
-    if (!t)
-      return;
-    drag_player_y = (int8)t;
-    sprite_y_lo[k] = y;
-  }
-}
-
-void SomariaPlatform_HandleDrag(int k) {  // 9ef901
-  SomariaPlatform_HandleDragX(k);
-  SomariaPlatform_HandleDragY(k);
-}
-
-void SomariaPlatform_DragLink(int k) {  // 9efb49
-  uint16 x = cur_sprite_x - 8 - link_x_coord;
-  if (x)
-    drag_player_x += sign16(x) ? -1 : 1;
-  uint16 y = cur_sprite_y - 16 - link_y_coord;
-  if (y)
-    drag_player_y += sign16(y) ? -1 : 1;
-}
-
-void Sprite_AE_Pipe_Down(int k) {  // 9efb7e
-  static const uint8 kPipe_Dirs[4] = {8, 4, 2, 1};
-
-  uint8 t;
-  if (Sprite_ReturnIfInactive(k))
-    return;
-  switch(sprite_graphics[k]) {
-  case 0:  // locate transit tile
-    alt_sprite_spawned_flag[0] = 255;
-    sprite_D[k] = sprite_type[k] - 0xae;
-    SomariaPlatform_LocatePath(k);
-    break;
-  case 1:  // locate endpoint
-    t = SomariaPlatformAndPipe_CheckTile(k);
-    if (t == 0xbe) {
-      sprite_graphics[k]++;
-      t = (sprite_D[k] ^= 1);
-    }
-    sprite_E[k] = t;
-    sprite_head_dir[k] = sprite_D[k];
-    SomariaPlatformAndPipe_HandleMovement(k);
-    Sprite_MoveXY(k);
-    break;
-  case 2:  // wait for player
-    if (alt_sprite_spawned_flag[0] == 255 && Sprite_CheckDamageToLink_ignore_layer(k)) {
-      if (!Pipe_ValidateEntry()) {
-        sprite_graphics[k]++;
-        sprite_delay_aux1[k] = 4;
-        Link_ResetProperties_A();
-        flag_is_link_immobilized = 1;
-        link_disable_sprite_damage = 1;
-        alt_sprite_spawned_flag[0] = k;
-      } else {
-        Sprite_HaltAllMovement();
-      }
-    }
-    break;
-  case 3:  // draw player in
-    if (!sprite_delay_aux1[k]) {
-      sprite_graphics[k]++;
-      link_visibility_status = 12;
-    } else {
-      flag_is_link_immobilized = 1;
-      link_disable_sprite_damage = 1;
-      Pipe_HandlePlayerMovement(kPipe_Dirs[sprite_D[k]]);
-    }
-    break;
-  case 4: {  // draw player along
-    sprite_subtype2[k] = 3;
-    link_x_coord_safe_return_lo = link_x_coord;
-    link_x_coord_safe_return_hi = link_x_coord >> 8;
-    link_y_coord_safe_return_lo = link_y_coord;
-    link_y_coord_safe_return_hi = link_y_coord >> 8;
-    do {
-      if (!(++sprite_A[k] & 7)) {
-        uint8 t = SomariaPlatformAndPipe_CheckTile(k);
-        if (t >= 0xb2 && t < 0xb6)
-          SpriteSfx_QueueSfx2WithPan(k, 0xb);
-        if (t != sprite_E[k]) {
-          sprite_E[k] = t;
-          if (t == 0xbe) {
-            sprite_graphics[k]++;
-            sprite_delay_aux1[k] = 24;
-          }
-          sprite_head_dir[k] = sprite_D[k];
-          SomariaPlatformAndPipe_HandleMovement(k);
-          SomariaPlatform_HandleDrag(k);
-        }
-      }
-      Sprite_MoveXY(k);
-      uint16 x = Sprite_GetX(k) - 8;
-      uint16 y = Sprite_GetY(k) - 14;
-      if (x != link_x_coord)
-        link_x_coord += (x < link_x_coord) ? -1 : 1;
-      if (y != link_y_coord)
-        link_y_coord += (y < link_y_coord) ? -1 : 1;
-    } while (--sprite_subtype2[k]);
-    link_x_vel = link_x_coord - link_x_coord_safe_return_lo;
-    link_y_vel = link_y_coord - link_y_coord_safe_return_lo;
-    link_direction_last = kPipe_Dirs[sprite_D[k]];
-    Link_HandleMovingAnimation_FullLongEntry();
-    HandleIndoorCameraAndDoors();
-    Link_CancelDash();
-    break;
-  }
-  case 5:  //
-    if (!sprite_delay_aux1[k]) {
-      flag_is_link_immobilized = 0;
-      player_on_somaria_platform = 0;
-      link_disable_sprite_damage = 0;
-      link_visibility_status = 0;
-      link_x_vel = link_y_vel = 0;
-      alt_sprite_spawned_flag[0] = 255;
-      sprite_graphics[k] = 2;
-    } else {
-      Pipe_HandlePlayerMovement(kPipe_Dirs[sprite_D[k] ^ 1]);
-    }
-    break;
-  }
-}
-
-void Pipe_HandlePlayerMovement(uint8 dir) {  // 9efcff
-  link_direction_last = link_direction = dir;
-  Link_HandleVelocity();
-  Link_HandleMovingAnimation_FullLongEntry();
-  HandleIndoorCameraAndDoors();
-}
-
-void Faerie_HandleMovement(int k) {  // 9efd1c
-  sprite_graphics[k] = frame_counter >> 3 & 1;
-  if (player_is_indoors && !sprite_delay_aux1[k]) {
-    if (Sprite_CheckTileCollision(k) & 3) {
-      sprite_x_vel[k] = -sprite_x_vel[k];
-      sprite_D[k] = -sprite_D[k];
-      sprite_delay_aux1[k] = 32;
-    }
-    if (sprite_wallcoll[k] & 12) {
-      sprite_y_vel[k] = -sprite_y_vel[k];
-      sprite_A[k] = -sprite_A[k];
-      sprite_delay_aux1[k] = 32;
-    }
-  }
-  if (sprite_x_vel[k]) {
-    if (sign8(sprite_x_vel[k]))
-      sprite_oam_flags[k] &= ~0x40;
-    else
-      sprite_oam_flags[k] |= 0x40;
-  }
-  Sprite_MoveXY(k);
-  if (!(frame_counter & 63)) {
-    uint16 x = (link_x_coord & ~0xff) + GetRandomNumber();
-    uint16 y = (link_y_coord & ~0xff) + GetRandomNumber();
-    ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLocation(k, x, y, 16);
-    sprite_A[k] = pt.y;
-    sprite_D[k] = pt.x;
-  }
-  if (!(frame_counter & 15)) {
-    sprite_y_vel[k] = ((int8)sprite_A[k] + (int8)sprite_y_vel[k]) >> 1;
-    sprite_x_vel[k] = ((int8)sprite_D[k] + (int8)sprite_x_vel[k]) >> 1;
-  }
-  Sprite_MoveZ(k);
-  sprite_z_vel[k] += (GetRandomNumber() & 1) ? -1 : 1;
-  if (sprite_z[k] < 8) {
-    sprite_z[k] = 8;
-    sprite_z_vel[k] = 5;
-  } else if (sprite_z[k] >= 24) {
-    sprite_z[k] = 24;
-    sprite_z_vel[k] = -5;
-  }
-}
-
--- a/sprite_main.h
+++ /dev/null
@@ -1,953 +1,0 @@
-#pragma once
-#include "types.h"
-#include "sprite.h"
-
-void Sprite_PullSwitch_bounce(int k);
-void GiantMoldorm_DrawSegment_AB(int k, int lookback);
-void GiantMoldorm_DrawSegment_C_OrTail(int k, int lookback);
-void Chicken_IncrSubtype2(int k, int j);
-bool Octoballoon_Find();
-bool FluteBoy_CheckIfPlayerClose(int k);
-void FortuneTeller_LightOrDarkWorld(int k, bool dark_world);
-int GarnishAllocForce();
-int GarnishAlloc();
-int GarnishAllocLow();
-int GarnishAllocLimit(int k);
-int GarnishAllocOverwriteOldLow();
-int GarnishAllocOverwriteOld();
-void Garnish_SetX(int k, uint16 x);
-void Garnish_SetY(int k, uint16 y);
-void Sprite_WishPond3(int k);
-int Sprite_SpawnSmallSplash(int k);
-void HeartUpgrade_CheckIfAlreadyObtained(int k);
-void Sprite_EE_MovableMantle(int k);
-void Sprite_GoodOrBadArcheryTarget(int k);
-void ChainBallTrooper_Draw(int k);
-void Sprite_6B_CannonTrooper(int k);
-void Bee_PutInBottle(int k);
-void Sprite_Wizzbeam(int k);
-void Kiki_LyingInwait(int k);
-int ChainChomp_OneMult(uint8 a, uint8 b);
-void Sprite_CC(int k);
-void Sprite_CD(int k);
-void SpritePrep_IncrXYLow8(int k);
-void SpritePrep_FakeSword(int k);
-void SpritePrep_MedallionTable(int k);
-void Hobo_Draw(int k);
-bool Landmine_CheckDetonationFromHammer(int k);
-void Sprite_DrawLargeWaterTurbulence(int k);
-void Sprite_SpawnSparkleGarnish(int k);
-void Sprite_70_KingHelmasaurFireball(int k);
-void Sprite_66_WallCannonVerticalLeft(int k);
-void Sprite_65_ArcheryGame(int k);
-void ArcheryGame_Host(int k);
-void ArcheryGameGuy_ShowMsg(int k, int msg);
-void ArcheryGame_Host_ProctorGame(int k);
-void ArcheryGame_DrawPrize(int k);
-void Sprite_63_DebirandoPit(int k);
-void DebirandoPit_Draw(int k);
-void Sprite_64_Debirando(int k);
-void Debirando_Draw(int k);
-void Sprite_62_MasterSword(int k);
-void MasterSword_Main(int k);
-void Sprite_MasterSword_LightFountain(int k);
-void Sprite_MasterSword_LightWell(int k);
-void SpriteDraw_LightFountain(int k);
-void MasterSword_SpawnLightWell(int k);
-void MasterSword_SpawnLightFountain(int k);
-void Sprite_MasterSword_LightBeam(int k);
-void MasterSword_SpawnReplacementLightBeam(int k);
-void MasterSword_SpawnLightBeam(int k, uint8 ain, uint8 yin);
-void MasterSword_SpawnPendantProp(int k, uint8 ain);
-void Sprite_MasterSword_Prop(int k);
-void MasterSword_Draw(int k);
-void Sprite_5D_Roller_VerticalDownFirst(int k);
-void SpikeRoller_Draw(int k);
-void Sprite_61_Beamos(int k);
-void Beamos_FireLaser(int k);
-void Beamos_Draw(int k);
-void SpriteDraw_Beamos_Eyeball(int k, PrepOamCoordsRet *info);
-void Sprite_Beamos_Laser(int k);
-void BeamosLaser_Draw(int k);
-void Sprite_Beamos_LaserHit(int k);
-void Sprite_5B_Spark_Clockwise(int k);
-void Sprite_59_LostWoodsBird(int k);
-void Sprite_5A_LostWoodsSquirrel(int k);
-void Sprite_58_Crab(int k);
-void Crab_Draw(int k);
-void Sprite_57_DesertStatue(int k);
-void DesertBarrier_Draw(int k);
-void Sprite_55_Zora(int k);
-void Sprite_Fireball(int k);
-void Sprite_Zora_Main(int k);
-void Zora_Draw(int k);
-void Sprite_52_KingZora(int k);
-void Sprite_SpawnBigSplash(int k);
-void ZoraKing_Draw(int k);
-void Sprite_56_WalkingZora(int k);
-void WalkingZora_AdjustShadow(int k);
-void WalkingZora_Draw(int k);
-void WalkingZora_DrawWaterRipples(int k);
-void SpriteDraw_WaterRipple_WithOamAdjust(int k);
-void SpriteDraw_WaterRipple(int k);
-void Sprite_53_ArmosKnight(int k);
-void ArmosKnight_Draw(int k);
-void Sprite_54_Lanmolas(int k);
-void Lanmola_Draw(int k);
-void Sprite_6D_Rat(int k);
-void Sprite_6E_Rope(int k);
-void Sprite_6F_Keese(int k);
-void Sprite_Cannonball(int k);
-void Sprite_SpawnPoofGarnish(int j);
-void Sprite_6C_MirrorPortal(int k);
-void Sprite_6A_BallNChain(int k);
-void BallNChain_Animate(int k);
-void SpriteDraw_GuardHead(int k, PrepOamCoordsRet *info, int spr_offs);
-void SpriteDraw_BNCBody(int k, PrepOamCoordsRet *info, int spr_offs);
-void SpriteDraw_BNCFlail(int k, PrepOamCoordsRet *info);
-void Sprite_50_Cannonball(int k);
-void SpriteDraw_BigCannonball(int k);
-void Sprite_51_ArmosStatue(int k);
-void Armos_Draw(int k);
-void Sprite_4E_Popo(int k);
-void Bot_Draw(int k);
-void Sprite_4C_Geldman(int k);
-void GerudoMan_Draw(int k);
-void Sprite_4D_Toppo(int k);
-void Toppo_VerifyTile(int k);
-void Toppo_Draw(int k);
-void Sprite_4B_GreenKnifeGuard(int k);
-void GreenKnifeGuard_Moving(int k);
-void Recruit_Draw(int k);
-void Sprite_4A_BombGuard(int k);
-void SpriteBomb_CheckDamageToSprite(int k, int j);
-void SpriteBomb_ExplosionIncoming(int k);
-void BombGuard(int k);
-void BombGuard_CreateBomb(int k);
-void BombTrooper_Draw(int k);
-void SpriteDraw_BombGuard_Arm(int k, PrepOamCoordsRet *info);
-void SpriteDraw_SpriteBombExplosion(int k);
-void Sprite_41_BlueGuard(int k);
-void Probe(int k);
-void Guard_Main(int k);
-void Guard_SetGlanceTo12(int k);
-void Guard_ShootProbeAndStuff(int k);
-void Guard_TickAndUpdateBody(int k);
-void Guard_SetTimerAndAssertTileHitBox(int k, uint8 a);
-void Soldier_Func12(int k);
-void Guard_ApplySpeedInDirection(int k);
-void Sprite_Guard_SendOutProbe(int k);
-void Sprite_SpawnProbeAlways(int k, uint8 r15);
-void Guard_HandleAllAnimation(int k);
-void Guard_AnimateHead(int k, int oam_offs, const PrepOamCoordsRet *poc);
-void Guard_AnimateBody(int k, int oam_idx, const PrepOamCoordsRet *poc);
-void Guard_AnimateWeapon(int k, const PrepOamCoordsRet *poc);
-void Sprite_45_HogSpearMan(int k);
-void BoltGuard_TriggerChaseTheme(int k);
-void Sprite_44_BluesainBolt(int k);
-void PsychoTrooper_Draw(int k);
-void SpriteDraw_GuardSpear(int k, PrepOamCoordsRet *info, int spr_offs);
-void Sprite_48_RedJavelinGuard(int k);
-void Sprite_46_BlueArcher(int k);
-void SoldierThrowing_Common(int k);
-void Guard_LaunchProjectile(int k);
-void BushJavelinSoldier_Draw(int k);
-void JavelinTrooper_Draw(int k);
-void Sprite_49_RedBushGuard(int k);
-void Sprite_47_GreenBushGuard(int k);
-void Sprite_BushGuard_Main(int k);
-void BushGuard_SpawnFoliage(int k);
-void BushSoldierCommon_Draw(int k);
-void ArcherSoldier_Draw(int k);
-void SpriteDraw_Archer_Weapon(int k, int spr_offs, PrepOamCoordsRet *info);
-void TutorialSoldier_Draw(int k);
-void PullSwitch_FacingUp(int k);
-void PullSwitch_HandleUpPulling(int k);
-void BadPullDownSwitch_Draw(int k);
-void BadPullUpSwitch_Draw(int k);
-void PullSwitch_FacingDown(int k);
-void GoodPullSwitch_Draw(int k);
-void PullSwitch_HandleDownPulling(int k);
-void Priest_SpawnMantle(int k);
-void Sprite_SanctuaryMantle(int k);
-void SageMantle_Draw(int k);
-void Sprite_Priest(int k);
-void Priest_Dying(int k);
-void Priest_RunRescueCutscene(int k);
-void Priest_Chillin(int k);
-void Sprite_Uncle(int k);
-void Uncle_AtHouse(int k);
-void Uncle_InPassage(int k);
-void Sprite_QuarrelBros(int k);
-void QuarrelBros_Draw(int k);
-void Sprite_YoungSnitchLady(int k);
-void YoungSnitchLady_Draw(int k);
-void Sprite_InnKeeper(int k);
-void InnKeeper_Draw(int k);
-void Sprite_Witch(int k);
-void Witch_AcceptShroom(int k);
-void Witch_Draw(int k);
-void SpritePrep_Snitches(int k);
-void Sprite_OldSnitchLady(int k);
-void SpritePrep_RunningMan(int k);
-void Sprite_RunningMan(int k);
-void RunningMan_Draw(int k);
-void Sprite_BottleVendor(int k);
-uint8 BottleVendor_Draw(int k);
-void Priest_SpawnRescuedPrincess();
-void Sprite_76_Zelda(int k);
-void Zelda_InCell(int k);
-void Zelda_EnteringSanctuary(int k);
-void Zelda_AtSanctuary(int k);
-void SpritePrep_Mushroom(int k);
-void Sprite_E7_Mushroom(int k);
-void Sprite_E8_FakeSword(int k);
-void FakeSword_Draw(int k);
-void SpritePrep_HeartContainer(int k);
-void Sprite_HeartContainer(int k);
-void Sprite_HeartPiece(int k);
-void HeartUpgrade_SetObtainedFlag(int k);
-void Sprite_Aginah(int k);
-void Sprite_Sahasrahla(int k);
-void Sasha_Idle(int k);
-void Elder_Draw(int k);
-void Sprite_DustCloud(int k);
-int Sprite_SpawnDustCloud(int k);
-void MedallionTablet_Main(int k);
-void BombosTablet(int k);
-void EtherTablet(int k);
-void ElderWife_Draw(int k);
-void SpritePrep_PotionShop(int k);
-void MagicShopAssistant_SpawnPowder(int k);
-void MagicShopAssistant_SpawnGreenCauldron(int k);
-void MagicShopAssistant_SpawnBlueCauldron(int k);
-void MagicShopAssistant_SpawnRedCauldron(int k);
-void Sprite_E9_PotionShop(int k);
-void Sprite_BagOfPowder(int k);
-void MagicPowderItem_Draw(int k);
-void Sprite_GreenCauldron(int k);
-void GreenPotionItem_Draw(int k);
-void Sprite_BlueCauldron(int k);
-void BluePotionItem_Draw(int k);
-void Sprite_RedCauldron(int k);
-void PotionCauldron_GoBeep(int k);
-void RedPotionItem_Draw(int k);
-bool PotionCauldron_CheckBottles();
-void Sprite_MagicShopAssistant_Main(int k);
-void Shopkeeper_Draw(int k);
-void Sprite_DashItem(int k);
-void Sprite_BonkKey(int k);
-void Sprite_BookOfMudora(int k);
-void Sprite_LumberjackTree(int k);
-void DashTreeTop_Draw(int k);
-int LumberjackTree_SpawnLeaves(int k);
-void Sprite_TroughBoy(int k);
-void TroughBoy_Draw(int k);
-void BottleMerchant_DetectFish(int k);
-void BottleMerchant_BuyFish(int k);
-void SpritePrep_ThrowableScenery(int k);
-void SpriteModule_Initialize(int k);
-void SpritePrep_Mantle(int k);
-void SpritePrep_Switch(int k);
-void SpritePrep_SwitchFacingUp(int k);
-void SpritePrep_Snitch_bounce_1(int k);
-void SpritePrep_DoNothingA(int k);
-void SpritePrep_Rat(int k);
-void SpritePrep_Keese(int k);
-void SpritePrep_Rope(int k);
-void SpritePrep_Swamola(int k);
-void SpritePrep_Blind(int k);
-void SpritePrep_Ganon(int k);
-void SpritePrep_Pokey(int k);
-void SpritePrep_MiniVitreous(int k);
-void SpritePrep_Gibo(int k);
-void SpritePrep_Octoballoon(int k);
-void SpritePrep_AgahnimsBarrier(int k);
-void SpritePrep_Catfish(int k);
-void SpritePrep_CutsceneAgahnim(int k);
-void SpritePrep_Vitreous(int k);
-void SpritePrep_Raven(int k);
-void SpritePrep_Vulture(int k);
-void SpritePrep_Poe(int k);
-void SpritePrep_DoNothingC(int k);
-void SpritePrep_BlindMaiden(int k);
-void SpritePrep_MiniMoldorm_bounce(int k);
-void SpritePrep_Bomber(int k);
-void SpritePrep_BombShoppe(int k);
-void SpritePrep_BullyAndVictim(int k);
-void SpritePrep_PurpleChest(int k);
-void SpritePrep_Smithy(int k);
-void SpritePrep_Babasu(int k);
-void SpritePrep_Zoro(int k);
-void SpritePrep_LaserEye_bounce(int k);
-void SpritePrep_Popo(int k);
-void SpritePrep_Popo2(int k);
-void SpritePrep_Statue(int k);
-void SpritePrep_Bari(int k);
-void SpritePrep_GreenStalfos(int k);
-void SpritePrep_WaterLever(int k);
-void SpritePrep_FireDebirando(int k);
-void SpritePrep_DebirandoPit(int k);
-void SpritePrep_WeakGuard(int k);
-void SpritePrep_WallCannon(int k);
-void SpritePrep_ArrowGame_bounce(int k);
-void SpritePrep_IgnoreProjectiles(int k);
-void SpritePrep_HauntedGroveAnimal(int k);
-void SpritePrep_HauntedGroveOstritch(int k);
-void SpritePrep_DiggingGameGuy_bounce(int k);
-void SpritePrep_ThievesTownGrate(int k);
-void SpritePrep_RupeePull(int k);
-void SpritePrep_Shopkeeper(int k);
-void SpritePrep_Storyteller(int k);
-void SpritePrep_Adults(int k);
-void SpritePrep_Whirlpool(int k);
-void SpritePrep_Sage(int k);
-void SpritePrep_BonkItem(int k);
-void SpritePrep_Kiki(int k);
-void SpritePrep_Locksmith(int k);
-void SpritePrep_SickKid(int k);
-void SpritePrep_Tektite(int k);
-void SpritePrep_Chainchomp_bounce(int k);
-void SpritePrep_BigFairy(int k);
-void SpritePrep_MrsSahasrahla(int k);
-void SpritePrep_MagicBat(int k);
-void SpritePrep_FortuneTeller(int k);
-void SpritePrep_FairyPond(int k);
-void SpritePrep_Hobo(int k);
-void SpritePrep_MasterSword(int k);
-void SpritePrep_Roller_HorizontalRightFirst(int k);
-void SpritePrep_RollerLeftRight(int k);
-void SpritePrep_Roller_VerticalDownFirst(int k);
-void SpritePrep_RollerUpDown(int k);
-void SpritePrep_Kodongo(int k);
-void SpritePrep_Spark(int k);
-void SpritePrep_LostWoodsBird(int k);
-void SpritePrep_LostWoodsSquirrel(int k);
-void SpritePrep_Antifairy(int k);
-void SpritePrep_FallingIce(int k);
-void SpritePrep_KingZora(int k);
-bool Sprite_ReturnIfBossFinished(int k);
-void SpritePrep_ArmosKnight(int k);
-void SpritePrep_DesertStatue(int k);
-void SpritePrep_DoNothingD(int k);
-void SpritePrep_Octorok(int k);
-void SpritePrep_Moldorm(int k);
-void SpritePrep_Lanmolas(int k);
-void SpritePrep_BigSpike(int k);
-void SpritePrep_SwimmingZora(int k);
-void SpritePrep_Geldman(int k);
-void SpritePrep_Kyameron(int k);
-void SpritePrep_WalkingZora(int k);
-void SpritePrep_StandardGuard(int k);
-void SpritePrep_TrooperAndArcherSoldier(int k);
-void SpritePrep_TalkingTree(int k);
-void SpritePrep_CrystalSwitch(int k);
-void SpritePrep_FluteKid(int k);
-void SpritePrep_MoveDown_8px(int k);
-void SpritePrep_Zazakku(int k);
-void SpritePrep_PedestalPlaque(int k);
-void SpritePrep_Stalfos(int k);
-void SpritePrep_KholdstareShell(int k);
-void SpritePrep_Kholdstare(int k);
-void SpritePrep_Bumper(int k);
-void SpritePrep_MoveDown_8px_Right8px(int k);
-void SpritePrep_HardhatBeetle(int k);
-void SpritePrep_MiniHelmasaur(int k);
-void SpritePrep_Fairy(int k);
-void SpritePrep_Absorbable(int k);
-void SpritePrep_OverworldBonkItem(int k);
-void SpritePrep_ShieldPickup(int k);
-void SpritePrep_NiceBee(int k);
-void SpritePrep_Agahnim(int k);
-void SpritePrep_DoNothingG(int k);
-void SpritePrep_FireBar(int k);
-void SpritePrep_Trinexx(int k);
-void SpritePrep_HelmasaurKing(int k);
-void SpritePrep_Spike(int k);
-void SpritePrep_RockStal(int k);
-void SpritePrep_Blob(int k);
-void SpritePrep_Arrghus(int k);
-void SpritePrep_Arrghi(int k);
-void SpritePrep_Mothula(int k);
-void SpritePrep_DoNothingH(int k);
-void SpritePrep_BigKey(int k);
-void SpritePrep_BigKey_load_graphics(int k);
-void SpritePrep_SmallKey(int k);
-void SpritePrep_KeySetItemDrop(int k);
-void SpriteActive_Main(int k);
-void Sprite_09_GiantMoldorm(int k);
-void Sprite_01_Vulture_bounce(int k);
-void Sprite_27_Deadrock(int k);
-void Sprite_20_Sluggula(int k);
-void Sluggula_DropBomb(int k);
-void Sprite_19_Poe(int k);
-void Poe_Draw(int k);
-void Sprite_18_MiniMoldorm(int k);
-void Sprite_12_Moblin(int k);
-void Moblin_MaterializeSpear(int k);
-void Moblin_Draw(int k);
-void Sprite_0E_Snapdragon(int k);
-void SnapDragon_Draw(int k);
-void Sprite_22_Ropa(int k);
-void Ropa_Draw(int k);
-void Sprite_11_Hinox(int k);
-void Hinox_ThrowBomb(int k);
-void Hinox_FaceLink(int k);
-void Hinox_SetDirection(int k, uint8 dir);
-void Hinox_Draw(int k);
-void Sprite_23_RedBari(int k);
-void RedBari_Split(int k);
-void RedBari_Draw(int k);
-void Sprite_13_MiniHelmasaur(int k);
-void Sprite_26_HardhatBeetle(int k);
-void HelmasaurHardHatBeetleCommon(int k);
-void HardHatBeetle_Draw(int k);
-void Sprite_15_Antifairy(int k);
-void Sprite_0B_Cucco(int k);
-void Cucco_Calm(int k);
-void Chicken_Hopping(int k);
-void Cucco_Flee(int k);
-void Cucco_DrawPANIC(int k);
-void Cucco_Carried(int k);
-uint8 Cucco_DoMovement_XY(int k);
-void Cucco_SummonAvenger(int k);
-void BawkBawk(int k);
-void Sprite_17_Hoarder(int k);
-void Sprite_Hoarder_Covered(int k);
-void Sprite_Hoarder_Frantic(int k);
-void CoveredRupeeCrab_Draw(int k);
-void Sprite_EC_ThrownItem(int k);
-void SpriteDraw_ThrownItem_Gigantic(int k);
-void ThrowableScenery_ScatterIntoDebris(int k);
-void Sprite_TransmuteToBomb(int k);
-void Sprite_28_DarkWorldHintNPC(int k);
-void DarkWorldHintNPC_Idle(int k);
-void DarkWorldHintNPC_RestoreHealth(int k);
-bool DarkWorldHintNPC_HandlePayment();
-void StoryTeller_1_Draw(int k);
-void Sprite_2E_FluteKid(int k);
-void FluteKid_Human(int k);
-void Sprite_FluteKid_Stumpy(int k);
-void Sprite_FluteKid_Quaver(int k);
-void FluteKid_SpawnQuaver(int k);
-void Sprite_1A_Smithy(int k);
-void Smithy_Homecoming(int k);
-void Smithy_Frog(int k);
-void ReturningSmithy_Draw(int k);
-void SmithyFrog_Draw(int k);
-void Smithy_Main(int k);
-bool Smithy_ListenForHammer(int k);
-int Smithy_SpawnDwarfPal(int k);
-void Smithy_Draw(int k);
-void Smithy_Spark(int k);
-void Smithy_SpawnSpark(int k);
-void SmithySpark_Draw(int k);
-void Sprite_1B_Arrow(int k);
-void EnemyArrow_Draw(int k);
-void Sprite_1E_CrystalSwitch(int k);
-void Sprite_1F_SickKid(int k);
-void Sprite_21_WaterSwitch(int k);
-void PushSwitch_Draw(int k);
-void Sprite_39_Locksmith(int k);
-void MiddleAgedMan_Draw(int k);
-void Sprite_2B_Hobo(int k);
-void Sprite_Hobo_Bum(int k);
-void SpritePrep_Hobo_SpawnSmoke(int k);
-void Sprite_Hobo_Bubble(int k);
-int Hobo_SpawnBubble(int k);
-void Sprite_Hobo_Fire(int k);
-void SpritePrep_Hobo_SpawnFire(int k);
-void Sprite_Hobo_Smoke(int k);
-void Hobo_SpawnSmoke(int k);
-void Sprite_73_UncleAndPriest(int k);
-void SpritePrep_UncleAndPriest_bounce(int k);
-void SpritePrep_OldMan_bounce(int k);
-void Sprite_TutorialGuardOrBarrier(int k);
-void Sprite_F2_MedallionTablet(int k);
-void Sprite_33_RupeePull(int k);
-void Sprite_14_ThievesTownGrate(int k);
-void SpritePrep_Snitch_bounce_2(int k);
-void SpritePrep_Snitch_bounce_3(int k);
-void Sprite_37_Waterfall(int k);
-void Sprite_38_EyeStatue(int k);
-void Sprite_3A_MagicBat(int k);
-void SpritePrep_Zelda_bounce(int k);
-void Sprite_78_MrsSahasrahla(int k);
-void Sprite_16_Elder_bounce(int k);
-void SpritePrep_HeartPiece(int k);
-void Sprite_2D_TelepathicTile(int k);
-void Sprite_25_TalkingTree(int k);
-void Sprite_1C_Statue(int k);
-bool Statue_CheckForSwitch(int k);
-void MovableStatue_Draw(int k);
-void Statue_BlockSprites(int k);
-void Sprite_1D_FluteQuest(int k);
-void Sprite_72_FairyPond(int k);
-void Sprite_WishPond2(int k);
-void Sprite_HappinessPond(int k);
-void WishPond2_Draw(int k);
-void FaerieQueen_Draw(int k);
-void Sprite_71_Leever(int k);
-void Leever_Draw(int k);
-void Sprite_D8_Heart(int k);
-void Sprite_E3_Fairy(int k);
-void Fairy_CheckIfTouchable(int k);
-void Sprite_E4_SmallKey(int k);
-void Sprite_D9_GreenRupee(int k);
-void Sprite_Absorbable_Main(int k);
-void Sprite_08_Octorok(int k);
-void Octorok_FireLoogie(int k);
-void Octorock_Draw(int k);
-void Sprite_0C_OctorokStone(int k);
-void SpriteDraw_OctorokStoneCrumbling(int k);
-void Sprite_0F_Octoballoon(int k);
-void Octoballoon_RecoilLink(int k);
-void Octoballoon_Draw(int k);
-void Octoballoon_FormBabby(int k);
-void Sprite_10_OctoballoonBaby(int k);
-void Sprite_0D_Buzzblob(int k);
-void Buzzblob_SelectNewDirection(int k);
-void BuzzBlob_Draw(int k);
-void Sprite_02_StalfosHead(int k);
-bool Pipe_ValidateEntry();
-void Ancilla_TerminateSparkleObjects();
-int Sprite_SpawnSuperficialBombBlast(int k);
-void Sprite_SpawnDummyDeathAnimation(int k);
-void Sprite_MagicBat_SpawnLightning(int k);
-void Fireball_SpawnTrailGarnish(int k);
-void GarnishSpawn_PyramidDebris(int8 x, int8 y, int8 xvel, int8 yvel);
-void Snitch_SpawnGuard(int k);
-void Babusu_Draw(int k);
-void Wizzrobe_Draw(int k);
-void Wizzbeam_Draw(int k);
-void Freezor_Draw(int k);
-void Zazak_Draw(int k);
-void Stalfos_Draw(int k);
-bool Probe_CheckTileSolidity(int k);
-void Sprite_HumanMulti_1(int k);
-void Sprite_BlindsHutGuy(int k);
-void Sprite_ThiefHideoutGuy(int k);
-void Sprite_FluteDad(int k);
-void FluteBoyFather_Draw(int k);
-void BlindHideoutGuy_Draw(int k);
-void Sprite_SweepingLady(int k);
-void SweepingLady_Draw(int k);
-void Sprite_Lumberjacks(int k);
-bool Lumberjack_CheckProximity(int k, int j);
-void Lumberjacks_Draw(int k);
-void Sprite_FortuneTeller(int k);
-void FortuneTeller_PerformPseudoScience(int k);
-void FortuneTeller_Draw(int k);
-void Smithy_SpawnDumbBarrierSprite(int k);
-void Sprite_MazeGameLady(int k);
-void Sprite_MazeGameGuy(int k);
-void MazeGameGuy_Draw(int k);
-void CrystalMaiden_Draw(int k);
-void Priest_Draw(int k);
-uint8 FluteBoy_Draw(int k);
-void FluteAardvark_Draw(int k);
-void DustCloud_Draw(int k);
-void MedallionTablet_Draw(int k);
-void Uncle_Draw(int k);
-void BugNetKid_Draw(int k);
-void Bomber_Draw(int k);
-void SpriteDraw_ZirroBomb(int k);
-void PlayerBee_HoneInOnTarget(int j, int k);
-void Pikit_Draw(int k);
-void SpriteDraw_Pikit_Tongue(int k, PrepOamCoordsRet *info);
-void SpriteDraw_Pikit_Loot(int k, PrepOamCoordsRet *info);
-void Kholdstare_Draw(int k);
-int Sprite_SpawnFireball(int k);
-void ArcheryGameGuy_Draw(int k);
-void ShopKeeper_RapidTerminateReceiveItem();
-void Sprite_InitializeSecondaryItemMinigame(int what);
-void Waterfall(int k);
-void Sprite_BatCrash(int k);
-void Sprite_SpawnBatCrashCutscene();
-void BatCrash_DrawHardcodedGarbage(int k);
-void BatCrash_SpawnDebris(int k);
-void RetreatBat_Draw(int k);
-void DrinkingGuy_Draw(int k);
-void Lady_Draw(int k);
-void Lanmola_SpawnShrapnel(int k);
-void Sprite_Cukeman(int k);
-void Cukeman_Draw(int k);
-void RunningBoy_SpawnDustGarnish(int k);
-void MovableMantle_Draw(int k);
-void Mothula_Draw(int k);
-void BottleMerchant_BuyBee(int k);
-void Sprite_ChickenLady(int k);
-void Overworld_DrawWoodenDoor(uint16 pos, bool unlocked);
-void Sprite_D4_Landmine(int k);
-void Landmine_Draw(int k);
-void Sprite_D3_Stal(int k);
-void Stal_Draw(int k);
-void Sprite_D2_FloppingFish(int k);
-void Fish_Draw(int k);
-void ChimneySmoke_Draw(int k);
-void Sprite_D1_BunnyBeam(int k);
-void Sprite_Chimney(int k);
-void Sprite_BunnyBeam(int k);
-void Sprite_D0_Lynel(int k);
-void Lynel_Draw(int k);
-void Sprite_SpawnPhantomGanon(int k);
-void Sprite_PhantomGanon(int k);
-void GanonBat_Draw(int k);
-void PhantomGanon_Draw(int k);
-void SwishEvery16Frames(int k);
-void Sprite_GanonTrident(int k);
-void Sprite_FireBat_Trailer(int k);
-void Sprite_SpiralFireBat(int k);
-void FireBat_Move(int k);
-void Sprite_FireBat_Launched(int k);
-void GetPositionRelativeToTheGreatOverlordGanon(int k);
-void FireBat_Animate(int k);
-void FireBat_Draw(int k);
-bool Ganon_AttemptTridentCatch(uint16 x, uint16 y);
-void Ganon_HandleFireBatCircle(int k);
-void Ganon_SpawnSpiralBat(int k);
-void Sprite_D6_Ganon(int k);
-void Ganon_EnableInvincibility(int k);
-void Ganon_SpawnFallingTilesOverlord(int k);
-void Ganon_Func1(int k, int t);
-void Ganon_Phase1_AnimateTridentSpin(int k);
-void Ganon_HandleAnimation_Idle(int k);
-void Ganon_SelectWarpLocation(int k, int a);
-void Ganon_ShakeHead(int k);
-void Ganon_Draw(int k);
-void Trident_Draw(int k);
-void SpritePrep_Swamola_InitializeSegments(int k);
-void Sprite_CF_Swamola(int k);
-ProjectSpeedRet Swamola_ProjectVelocityTowardsTarget(int k);
-void Swamola_SpawnRipples(int k);
-void Sprite_Swamola_Ripples(int k);
-void SwamolaRipples_Draw(int k);
-void Swamola_Draw(int k);
-void SpritePrep_Blind_PrepareBattle(int k);
-void BlindLaser_SpawnTrailGarnish(int j);
-void Sprite_Blind_Head(int k);
-void Blind_SpawnHead(int k);
-void Sprite_CE_Blind(int k);
-void Sprite_BlindLaser(int k);
-void Sprite_Blind_Blind_Blind(int k);
-void Blind_FireballFlurry(int k, uint8 a);
-int Blind_SpitFireball(int k, uint8 a);
-int SpawnBossPoof(int k);
-void Blind_Decelerate_X(int k);
-void Blind_Decelerate_Y(int k);
-void Blind_CheckBumpDamage(int k);
-void Blind_Animate(int k);
-void Blind_AnimateRobes(int k);
-void Blind_SpawnLaser(int k);
-void Blind_Draw(int k);
-void TrinexxComponents_Initialize(int k);
-void Trinexx_RestoreXY(int k);
-void Trinexx_CachePosition(int k);
-void Sprite_Trinexx_FinalPhase(int k);
-void Sprite_TrinexxD_Draw(int k);
-void Sprite_Trinexx_CheckDamageToFlashingSegment(int k);
-void Sprite_CB_TrinexxRockHead(int k);
-void Trinexx_WagTail(int k);
-void Trinexx_HandleShellCollision(int k);
-void SpriteDraw_TrinexxRockHead(int k, PrepOamCoordsRet *info);
-void SpriteDraw_TrinexxRockHeadAndBody(int k);
-void Sprite_Sidenexx(int k);
-void Sidenexx_ExhaleDanger(int k);
-void Sidenexx_Explode(int k);
-void TrinexxHead_Draw(int k);
-void Sprite_CC_CD_Common(int k);
-void Sprite_CD_SpawnGarnish(int k);
-void Sprite_TrinexxFire_AddFireGarnish(int k);
-int Garnish_FlameTrail(int k, bool is_low);
-void Sprite_CA_ChainChomp(int k);
-void ChainChomp_MoveChain(int k);
-void ChainChomp_HandleLeash(int k);
-void ChainChomp_Draw(int k);
-void Sprite_C9_Tektite(int k);
-void Sprite_Tektite(int k);
-void Tektite_Draw(int k);
-void Sprite_C8_BigFairy(int k);
-void Sprite_FairyCloud(int k);
-void Sprite_BigFairy(int k);
-void BigFaerie_Draw(int k);
-void FaerieCloud_Draw(int k);
-void Sprite_C7_Pokey(int k);
-void Hokbok_Draw(int k);
-void Sprite_C5_Medusa(int k);
-void Sprite_C6_4WayShooter(int k);
-void Sprite_C4_Thief(int k);
-uint8 Thief_ScanForBooty(int k);
-void Thief_TargetBooty(int k, int j);
-void Thief_GrabBooty(int k, int j);
-void Thief_CheckCollisionWithLink(int k);
-void Thief_SpillItems(int k);
-void Thief_Draw(int k);
-void Sprite_C3_Gibo(int k);
-void Gibo_Draw(int k);
-void Sprite_C2_Boulder(int k);
-void Boulder_OutdoorsMain(int k);
-void Boulder_Draw(int k);
-void SpriteDraw_BigShadow(int k, int anim);
-void Sprite_DrawLargeShadow2(int k);
-void CutsceneAgahnim_SpawnZeldaOnAltar(int k);
-void Sprite_C1_CutsceneAgahnim(int k);
-void CutsceneAgahnim_Agahnim(int k);
-int Sprite_Agahnim_ApplyMotionBlur(int k);
-void ChattyAgahnim_Draw(int k, PrepOamCoordsRet *info);
-void SpriteDraw_CutsceneAgahnimSpell(int k, PrepOamCoordsRet *info);
-void Sprite_CutsceneAgahnim_Zelda(int k);
-void AltarZelda_DrawBody(int k, PrepOamCoordsRet *info);
-void SpriteDraw_AltarZeldaWarp(int k);
-void Sprite_InitializedSegmented(int k);
-void GiantMoldorm_Draw(int k);
-void GiantMoldorm_IncrementalSegmentExplosion(int k);
-void SpriteDraw_Moldorm_Head(int k);
-void SpriteDraw_Moldorm_SegmentC(int k);
-void Moldorm_HandleTail(int k);
-void SpriteDraw_Moldorm_Tail(int k);
-void SpriteDraw_Moldorm_Eyeballs(int k, PrepOamCoordsRet *info);
-void Sprite_ScheduleBossForDeath(int k);
-void Sprite_MakeBossExplosion(int k);
-void Sprite_MakeBossDeathExplosion_NoSound(int k);
-void Vulture_Draw(int k);
-void Sprite_Raven(int k);
-void Vitreous_SpawnSmallerEyes(int k);
-void Sprite_C0_Catfish(int k);
-void Sprite_Catfish_QuakeMedallion(int k);
-void Catfish_BigFish(int k);
-int Sprite_SpawnBomb(int k);
-void Catfish_RegurgitateMedallion(int k);
-void Sprite_Zora_RegurgitateFlippers(int k);
-void Catfish_SpawnPlop(int k);
-int Sprite_SpawnWaterSplash(int k);
-void GreatCatfish_Draw(int k);
-void Sprite_Catfish_SplashOfWater(int k);
-void Sprite_BF_Lightning(int k);
-void Lightning_SpawnGarnish(int k);
-void Sprite_BD_Vitreous(int k);
-void Vitreous_Animate(int k, uint8 a);
-void Vitreous_SetMinionsForth(int k);
-void Sprite_SpawnLightning(int k);
-void Vitreous_Draw(int k);
-void Sprite_BE_VitreousEye(int k);
-void HelmasaurFireball_TriSplit(int k);
-void HelmasaurFireball_QuadSplit(int k);
-void Sprite_ArmosCrusher(int k);
-void Sprite_EvilBarrier(int k);
-void EvilBarrier_Draw(int k);
-void SpriteDraw_Antfairy(int k);
-void Toppo_Flustered(int k);
-void Goriya_Draw(int k);
-void Moldorm_Draw(int k);
-void TalkingTree_Mouth(int k);
-void TalkingTree_SpawnBomb(int k);
-void TalkingTree_Draw(int k);
-void TalkingTree_Eye(int k);
-void SpritePrep_TalkingTree_SpawnEyeball(int k, int dir);
-void RupeePull_SpawnPrize(int k);
-void Sprite_D5_DigGameGuy(int k);
-void DiggingGameGuy_Draw(int k);
-void OldMountainMan_Draw(int k);
-void HelmasaurKing_Initialize(int k);
-void HelmasaurKing_Reinitialize(int k);
-void Sprite_92_HelmasaurKing(int k);
-void HelmasaurKing_HandleMovement(int k);
-bool HelmasaurKing_MaybeFireball(int k);
-void HelmasaurKing_SwingTail(int k);
-void HelmasaurKing_CheckMaskDamageFromHammer(int k);
-void HelmasaurKing_AttemptDamage(int k);
-void HelmasaurKing_ChipAwayAtMask(int k);
-void HelmasaurKing_ExplodeMask(int k);
-void HelmasaurKing_SpawnMaskDebris(int k);
-void HelmasaurKing_SpitFireball(int k);
-void HelmasaurKing_Draw(int k);
-void SpriteDraw_KingHelmasaur_Eyes(int k, PrepOamCoordsRet *info);
-void KingHelmasaurMask(int k, PrepOamCoordsRet *info);
-void KingHelmasaur_CheckBombDamage(int k, int j);
-void SpriteDraw_KingHelmasaur_Body(int k, PrepOamCoordsRet *info);
-void SpriteDraw_KingHelmasaur_Legs(int k, PrepOamCoordsRet *info);
-void SpriteDraw_KingHelmasaur_Mouth(int k, PrepOamCoordsRet *info);
-void KingHelmasaur_OperateTail(int k, PrepOamCoordsRet *info);
-void Sprite_MadBatterBolt(int k);
-void Sprite_AA_Pikit(int k);
-void Sprite_A8_GreenZirro(int k);
-void Zirro_DropBomb(int k);
-void Sprite_StalfosBone(int k);
-void StalfosBone_Draw(int k);
-void Sprite_A7_Stalfos(int k);
-void Stalfos_Skellington(int k);
-void Sprite_Zazak_Main(int k);
-int Sprite_SpawnFirePhlegm(int k);
-void Stalfos_ThrowBone(int k);
-void FirePhlegm_Draw(int k);
-void Sprite_A3_KholdstareShell(int k);
-void GenerateIceball(int k);
-void Sprite_A2_Kholdstare(int k);
-void Kholdstare_SpawnPuffCloudGarnish(int k);
-void Sprite_A4_FallingIce(int k);
-void IceBall_Split(int k);
-void Sprite_A1_Freezor(int k);
-void Sprite_9E_HauntedGroveOstritch(int k);
-void FluteBoyOstrich_Draw(int k);
-void Sprite_9F_HauntedGroveRabbit(int k);
-void Sprite_A0_HauntedGroveBird(int k);
-void HauntedGroveBird_Blink(int k);
-void Sprite_9C_Zoro(int k);
-void Zoro(int k);
-void Babasu(int k);
-void Sprite_9B_Wizzrobe(int k);
-void Wizzrobe_FireBeam(int k);
-void Sprite_9A_Kyameron(int k);
-void Kyameron_Draw(int k);
-void Sprite_99_Pengator(int k);
-void Pengator_Draw(int k);
-void Sprite_LaserBeam(int k);
-void LaserBeam_BuildUpGarnish(int k);
-void Sprite_95_LaserEyeLeft(int k);
-void LaserEye_FireBeam(int k);
-void LaserEye_Draw(int k);
-void Sprite_94_Pirogusu(int k);
-void Pirogusu_SpawnSplash(int k);
-void Pirogusu_Draw(int k);
-void Sprite_93_Bumper(int k);
-void Bumper_Draw(int k);
-void Sprite_91_StalfosKnight(int k);
-void StalfosKnight_Draw(int k);
-void SpriteDraw_StalfosKnight_Head(int k, PrepOamCoordsRet *info);
-void Sprite_90_Wallmaster(int k);
-void WallMaster_Draw(int k);
-void Sprite_8F_Blob(int k);
-void Zol_Draw(int k);
-void Sprite_8E_Terrorpin(int k);
-void Terrorpin_CheckForHammer(int k);
-void Terrorpin_SetUpHammerHitBox(int k, SpriteHitBox *hb);
-void Sprite_8C_Arrghus(int k);
-void Arrghus_Draw(int k);
-void Arrghus_HandlePuffs(int k);
-void Sprite_8D_Arrghi(int k);
-void Sprite_8B_Gibdo(int k);
-void Gibdo_Draw(int k);
-void Sprite_89_MothulaBeam(int k);
-void Sprite_94_Tile(int k);
-void FlyingTile_Draw(int k);
-void Sprite_8A_SpikeBlock(int k);
-bool SpikeBlock_CheckStatueCollision(int k);
-void Sprite_88_Mothula(int k);
-void Mothula_Main(int k);
-void Mothula_FlapWings(int k);
-void Mothula_SpawnBeams(int k);
-void Mothula_HandleSpikes(int k);
-void Sprite_86_Kodongo(int k);
-void Kodongo_SetDirection(int k);
-void Kodongo_SpawnFire(int k);
-void Sprite_87_KodongoFire(int k);
-void Flame_Draw(int k);
-void Sprite_85_YellowStalfos(int k);
-void YellowStalfos_Animate(int k);
-void YellowStalfos_EmancipateHead(int k);
-void YellowStalfos_Draw(int k);
-void YellowStalfos_DrawHead(int k, PrepOamCoordsRet *info);
-void SpritePrep_Eyegore(int k);
-void Sprite_83_GreenEyegore(int k);
-void Eyegore_Main(int k);
-void Eyegore_Draw(int k);
-void SpritePrep_AntifairyCircle(int k);
-void Sprite_82_AntifairyCircle(int k);
-void Sprite_81_Hover(int k);
-void Sprite_AB_CrystalMaiden(int k);
-void CrystalMaiden_RunCutscene(int k);
-void Sprite_7D_BigSpike(int k);
-void SpikeTrap_Draw(int k);
-void Sprite_7E_Firebar_Clockwise(int k);
-void Firebar_Main(int k);
-void Sprite_80_Firesnake(int k);
-void Firesnake_SpawnFireball(int j);
-void Sprite_7C_GreenStalfos(int k);
-void Sprite_7A_Agahnim(int k);
-void Agahnim_PerformAttack(int k);
-void Agahnim_Draw(int k);
-void Sprite_7B_AgahnimBalls(int k);
-void CreateSixBlueBalls(int k);
-void SeekerEnergyBall_Draw(int k);
-void Sprite_79_Bee(int k);
-void Bee_DormantHive(int k);
-void SpawnBeeFromHive(int k);
-void InitializeSpawnedBee(int k);
-int ReleaseBeeFromBottle(int x_value);
-void Bee_Main(int k);
-int Sprite_Find_EmptyBottle();
-void Bee_HandleInteractions(int k);
-void Sprite_B2_PlayerBee(int k);
-void GoldBee_SpawnSelf(int k);
-void Bee_HandleZ(int k);
-bool PlayerBee_FindTarget(int k, Point16U *pt);
-void Bee_Bzzt(int k);
-void Sprite_B3_PedestalPlaque(int k);
-void Sprite_B4_PurpleChest(int k);
-void Sprite_B5_BombShop(int k);
-void Sprite_BombShop_Clerk(int k);
-void Sprite_BombShop_Bomb(int k);
-void Sprite_BombShop_SuperBomb(int k);
-void Sprite_BombShop_Huff(int k);
-void BombShop_ClerkExhalation(int k);
-void BombShopEntity_Draw(int k);
-void Sprite_B6_Kiki(int k);
-void Kiki_Flee(int k);
-void Kiki_OfferInitialService(int k);
-void Kiki_OfferEntranceService(int k);
-bool Kiki_Draw(int k);
-void Sprite_B7_BlindMaiden(int k);
-void OldMan_RevertToSprite(int k);
-void OldMan_EnableCutscene();
-void Sprite_AD_OldMan(int k);
-void Sprite_B8_DialogueTester(int k);
-void Sprite_B9_BullyAndPinkBall(int k);
-void Sprite_PinkBall(int k);
-void PinkBall_HandleDeceleration(int k);
-void PinkBall_Distress(int k);
-void Sprite_Bully(int k);
-void Bully_Draw(int k);
-void BallGuy_PlayBounceNoise(int k);
-void SpawnBully(int k);
-void PinkBall_HandleMessage(int k);
-void Bully_HandleMessage(int k);
-void Sprite_BA_Whirlpool(int k);
-void Sprite_BB_Shopkeeper(int k);
-void Shopkeeper_StandardClerk(int k);
-void ChestGameGuy(int k);
-void NiceThief_Animate(int k);
-void NiceThiefWithGift(int k);
-void MiniChestGameGuy(int k);
-void LostWoodsChestGameGuy(int k);
-void NiceThiefUnderRock(int k);
-void ShopItem_RedPotion150(int k);
-void ShopKeeper_SpawnShopItem(int k, int pos, int what);
-void ShopItem_FighterShield(int k);
-void ShopItem_FireShield(int k);
-void ShopItem_MakeShieldsDeflect(int k);
-void ShopItem_Heart(int k);
-void ShopItem_Arrows(int k);
-void ShopItem_Bombs(int k);
-void ShopItem_Bee(int k);
-void ShopItem_HandleReceipt(int k, uint8 item);
-void ShopItem_PlayBeep(int k);
-bool ShopItem_CheckForAPress(int k);
-bool ShopItem_HandleCost(int amt);
-void SpriteDraw_ShopItem(int k);
-void Sprite_AC_Apple(int k);
-void SpawnApple(int k);
-void Sprite_Apple(int k);
-void Sprite_BC_Drunkard(int k);
-void SomariaPlatform_LocatePath(int k);
-void Sprite_ED_SomariaPlatform(int k);
-void SomariaPlatformAndPipe_HandleMovement(int k);
-uint8 SomariaPlatformAndPipe_CheckTile(int k);
-void SomariaPlatform_Draw(int k);
-void SomariaPlatform_HandleJunctions(int k);
-void SomariaPlatform_HandleDragX(int k);
-void SomariaPlatform_HandleDragY(int k);
-void SomariaPlatform_HandleDrag(int k);
-void SomariaPlatform_DragLink(int k);
-void Sprite_AE_Pipe_Down(int k);
-void Pipe_HandlePlayerMovement(uint8 dir);
-void Faerie_HandleMovement(int k);
--- /dev/null
+++ b/src/ancilla.c
@@ -1,0 +1,7156 @@
+#include "ancilla.h"
+#include "variables.h"
+#include "sprite.h"
+#include "hud.h"
+#include "load_gfx.h"
+#include "tagalong.h"
+#include "overworld.h"
+#include "tile_detect.h"
+#include "player.h"
+#include "misc.h"
+#include "dungeon.h"
+#include "sprite_main.h"
+#include "assets.h"
+
+static const uint8 kAncilla_Pflags[68] = {
+  0,    8,  0xc, 0x10, 0x10,    4, 0x10, 0x18,    8,    8,    8,    0, 0x14, 0, 0x10, 0x28,
+  0x18, 0x10, 0x10, 0x10, 0x10,  0xc,    8,    8, 0x50,    0, 0x10,    8, 0x40, 0,  0xc, 0x24,
+  0x10,  0xc,    8, 0x10, 0x10,    4,  0xc, 0x1c,    0, 0x10, 0x14, 0x14, 0x10, 8, 0x20, 0x10,
+  0x10, 0x10,    4,    0, 0x80, 0x10,    4, 0x30, 0x14, 0x10,    0, 0x10,    0, 0,    8,    0,
+  0x10,    8, 0x78, 0x80,
+};
+static const int8 kFireRod_Xvel2[12] = {0, 0, -40, 40, 0, 0, -48, 48, 0, 0, -64, 64};
+static const int8 kFireRod_Yvel2[12] = {-40, 40, 0, 0, -48, 48, 0, 0, -64, 64, 0, 0};
+static const uint8 kTagalongLayerBits[4] = {0x20, 0x10, 0x30, 0x20};
+static const uint8 kBombos_Sfx[8] = {0x80, 0x80, 0x80, 0, 0, 0x40, 0x40, 0x40};
+const uint8 kBomb_Tab0[11] = {0xA0, 6, 4, 4, 4, 4, 4, 6, 6, 6, 6};
+
+#define swordbeam_temp_x (*(uint16*)(g_ram+0x1580E))
+#define swordbeam_temp_y (*(uint16*)(g_ram+0x15810))
+#define swordbeam_arr ((uint8*)(g_ram+0x15800))
+#define swordbeam_var1 (*(uint8*)(g_ram+0x15804))
+#define swordbeam_var2 (*(uint8*)(g_ram+0x15808))
+static const int8 kAncilla_TileColl_Attrs[256] = {
+  0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0,
+  1, 1, 1, 1, 0, 0, 0, 0, 2, 2, 2, 2, 0, 3, 3, 3,
+  0, 0, 0, 0, 0, 0, 1, 1, 4, 4, 4, 4, 4, 4, 4, 4,
+  1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 3, 3, 3,
+  0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+};
+static const uint8 kAncilla_TileColl0_Attrs[256] = {
+  0, 1, 0, 3, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0,
+  1, 1, 1, 1, 0, 0, 0, 0, 2, 2, 2, 2, 0, 3, 3, 3,
+  0, 0, 0, 0, 0, 0, 1, 1, 4, 4, 4, 4, 4, 4, 4, 4,
+  1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 3, 3, 3,
+  0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4,
+  0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0,
+  0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+};
+static const uint8 kBomb_Draw_Tab0[12] = {0, 1, 2, 3, 2, 3, 4, 5, 6, 7, 8, 9};
+static const uint8 kBomb_Draw_Tab2[11] = {1, 4, 4, 4, 4, 4, 5, 4, 6, 6, 6};
+
+static const uint8 kMagicPowder_Tab0[40] = {
+  13, 14, 15, 0,  1,  2,  3, 4, 5, 6, 10, 11, 12, 0, 1, 2,
+  3,  4,  5, 6, 16, 17, 18, 0, 1, 2,  3,  4,  5, 6, 7, 8,
+  9,  0,  1, 2,  3,  4,  5, 6,
+};
+#define ether_arr1 ((uint8*)(g_ram+0x15800))
+#define ether_var2 (*(uint8*)(g_ram+0x15808))
+#define ether_y2 (*(uint16*)(g_ram+0x1580A))
+#define ether_y_adjusted (*(uint16*)(g_ram+0x1580C))
+#define ether_x2 (*(uint16*)(g_ram+0x1580E))
+#define ether_y3 (*(uint16*)(g_ram+0x15810))
+#define ether_var1 (*(uint8*)(g_ram+0x15812))
+#define ether_y (*(uint16*)(g_ram+0x15813))
+#define ether_x (*(uint16*)(g_ram+0x15815))
+static const uint8 kEther_BlitzOrb_Char[8] = {0x48, 0x48, 0x4a, 0x4a, 0x4c, 0x4c, 0x4e, 0x4e};
+static const uint8 kEther_BlitzOrb_Flags[8] = {0x3c, 0x7c, 0x3c, 0x7c, 0x3c, 0x7c, 0x3c, 0x7c};
+static const uint8 kEther_BlitzSegment_Char[4] = {0x40, 0x42, 0x44, 0x46};
+#define bombos_arr1 ((uint8*)(g_ram+0x15800))
+#define bombos_arr2 ((uint8*)(g_ram+0x15810))
+static const uint8 kBombosBlasts_Tab[72] = {
+  0xb6, 0x5d, 0xa1, 0x30, 0x69, 0xb5, 0xa3, 0x24, 0x96, 0xac, 0x73, 0x5f, 0x92, 0x48, 0x52, 0x81,
+  0x39, 0x95, 0x7f, 0x20, 0x88, 0x5d, 0x34, 0x98, 0xbc, 0xd2, 0x51, 0x77, 0xa2, 0x47, 0x94, 0xb2,
+  0x34, 0xda, 0x30, 0x62, 0x9f, 0x76, 0x51, 0x46, 0x98, 0x5c, 0x9b, 0x61, 0x58, 0x95, 0x4c, 0xba,
+  0x7e, 0xcb, 0x12, 0xd0, 0x70, 0xa6, 0x46, 0xbf, 0x40, 0x50, 0x7e, 0x8c, 0x2d, 0x61, 0xac, 0x88,
+  0x20, 0x6a, 0x72, 0x5f, 0xd2, 0x28, 0x52, 0x80,
+};
+static const uint8 kQuake_Tab1[5] = {0x17, 0x16, 0x17, 0x16, 0x10};
+static const uint8 kQuakeDrawGroundBolts_Char[15] = { 0x40, 0x42, 0x44, 0x46, 0x48, 0x4a, 0x4c, 0x4e, 0x60, 0x62, 0x64, 0x66, 0x68, 0x6a, 0x63 };
+typedef struct QuakeItem {
+  int8 x, y;
+  uint8 f;
+} QuakeItem;
+static const QuakeItem kQuakeItems[] = {
+  {0, -16, 0x00},
+  {0, -16, 0x01},
+  {0, -16, 0x02},
+  {0, -16, 0x03},
+  {0, -16, 0x43},
+  {0, -16, 0x42},
+  {0, -16, 0x41},
+  {0, -16, 0x40},
+  {0, -16, 0x40}, {14, -8, 0x84},
+  {29, -8, 0x44}, {13, -7, 0x84},
+  {31, -7, 0x44}, {47, -4, 0x84},
+  {49, -11, 0x06}, {63, -5, 0x44}, {47, -4, 0x84},
+  {36, -17, 0x08}, {49, -11, 0x06}, {63, -5, 0x44}, {78, 4, 0x08},
+  {22, -31, 0x08}, {36, -17, 0x08}, {78, 4, 0x08}, {93, 20, 0x08},
+  {7, -46, 0x08}, {23, -45, 0x48}, {22, -31, 0x08}, {93, 20, 0x08}, {93, 36, 0x48},
+  {-7, -61, 0x08}, {37, -59, 0x48}, {7, -46, 0x08}, {23, -45, 0x48}, {93, 36, 0x48}, {93, 52, 0x08},
+  {-22, -75, 0x08}, {47, -74, 0x01}, {-8, -61, 0x08}, {36, -60, 0x48}, {93, 52, 0x08}, {108, 67, 0x08},
+  {-37, -90, 0x08}, {-22, -75, 0x08}, {47, -74, 0x01}, {59, -62, 0x81}, {108, 67, 0x08}, {121, 80, 0x08},
+  {-44, -104, 0xc9}, {-37, -90, 0x08}, {73, -74, 0x48}, {59, -62, 0x81}, {121, 80, 0x08},
+  {-44, -120, 0x09}, {-44, -104, 0xc9}, {87, -89, 0x48}, {73, -74, 0x48},
+  {-44, -120, 0x09}, {102, -104, 0x48}, {87, -89, 0x48},
+  {102, -104, 0x48}, {87, -89, 0x48},
+  {112, -116, 0x48}, {102, -104, 0x48},
+  {112, -116, 0x48},
+  {-13, -16, 0x00},
+  {-13, -16, 0x01},
+  {-13, -16, 0x02},
+  {-13, -16, 0x03},
+  {-11, -16, 0x43},
+  {-11, -16, 0x42},
+  {-11, -16, 0x41},
+  {-11, -16, 0x40}, {-24, -10, 0x04},
+  {-38, -18, 0x08}, {-24, -10, 0x04}, {-40, -7, 0xc4},
+  {-45, -33, 0xc9}, {-38, -18, 0x08}, {-57, -7, 0x04}, {-40, -7, 0xc4},
+  {-48, -45, 0x07}, {-45, -33, 0xc9}, {-57, -7, 0x04}, {-71, 2, 0x48},
+  {-48, -45, 0x06}, {-71, 2, 0x48}, {-70, 18, 0x08},
+  {-48, -45, 0x05}, {-70, 18, 0x08}, {-56, 33, 0x08},
+  {-48, -45, 0x07}, {-54, 34, 0x08}, {-54, 49, 0x88},
+  {-48, -45, 0x06}, {-54, 49, 0x88}, {-69, 64, 0x88},
+  {-48, -45, 0x07}, {-69, 64, 0x88}, {-85, 73, 0xc4},
+  {-48, -45, 0x05}, {-101, 73, 0x04}, {-85, 73, 0xc4},
+  {-60, -53, 0x08}, {-48, -45, 0x06}, {-101, 73, 0x04}, {-116, 77, 0xc4},
+  {-75, -67, 0x08}, {-60, -53, 0x08}, {-128, 76, 0x04}, {-116, 77, 0xc4},
+  {-90, -82, 0x08}, {-75, -67, 0x08}, {-128, 76, 0x04},
+  {-105, -97, 0x08}, {-90, -82, 0x08},
+  {-120, -111, 0x08}, {-105, -97, 0x08},
+  {-120, -111, 0x08},
+  {0, -5, 0x0a},
+  {0, -5, 0x0b},
+  {2, -3, 0x0c},
+  {1, -3, 0x0d},
+  {0, -3, 0x8d},
+  {1, -3, 0x8c},
+  {1, -3, 0x8b},
+  {1, -3, 0x8a}, {-6, 12, 0x89},
+  {-6, 12, 0x89}, {-10, 28, 0xc9},
+  {-10, 28, 0x49}, {-8, 44, 0x89},
+  {-8, 44, 0x89}, {-10, 56, 0x02},
+  {-10, 56, 0x02}, {-23, 70, 0x48}, {5, 70, 0x08},
+  {-23, 70, 0x48}, {5, 70, 0x08}, {-38, 85, 0x48}, {19, 85, 0x08},
+  {-38, 85, 0x48}, {19, 85, 0x08}, {-52, 99, 0x48}, {33, 101, 0x08},
+  {-52, 99, 0x48}, {33, 101, 0x08}, {-66, 113, 0x48}, {47, 115, 0x08},
+  {-66, 113, 0x48}, {47, 115, 0x08},
+};
+static const uint8 kQuakeItemPos[] = {
+  0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 17, 21, 25, 30,
+  36, 42, 48, 53, 57, 60, 62, 64, 65, 66, 67, 68, 69, 70, 71, 72, 74, 77, 81, 85, 88, 91, 94, 97, 100, 103, 107, 111, 114, 116, 118, 119, 120, 121, 122, 123, 124, 125, 126, 128, 130, 132, 134, 137, 141, 145, 149, 151
+};
+static const QuakeItem kQuakeItems2[] = {
+  {-96, 112, 0x20},
+  {-96, 112, 0x21},
+  {-96, 112, 0x66},
+  {-96, 112, 0x22},
+  {-96, 112, 0x23},
+  {-96, 112, 0x63},
+  {-96, 112, 0x62},
+  {-96, 112, 0x26},
+  {-96, 112, 0x27}, {-86, 124, 0x28},
+  {-86, 124, 0x28}, {-72, -117, 0x28},
+  {-72, -117, 0x28}, {-59, -102, 0xa1},
+  {-59, -102, 0xa1}, {-44, -116, 0x68},
+  {-44, -116, 0x68}, {-29, 126, 0x68},
+  {-29, 126, 0x68},
+  {-19, 125, 0xc5},
+  {-112, 96, 0x2a},
+  {-112, 96, 0x2b},
+  {-112, 96, 0x2c},
+  {-112, 96, 0x2d},
+  {-119, 82, 0x29}, {-112, 96, 0x2a},
+  {-123, 66, 0xe9}, {-119, 82, 0x29},
+  {-121, 50, 0x29}, {-123, 66, 0xe9},
+  {126, 34, 0x28}, {-115, 34, 0x68}, {-121, 50, 0x29},
+  {-106, 18, 0xa9}, {111, 19, 0x28}, {126, 34, 0x28}, {-115, 34, 0x68},
+  {-100, 2, 0x68}, {102, 4, 0xe9}, {-106, 18, 0xa9}, {111, 19, 0x28},
+  {-91, -14, 0xa9}, {95, -11, 0x28}, {-100, 2, 0x68}, {102, 4, 0xe9},
+  {96, 112, 0x60},
+  {96, 112, 0x61},
+  {96, 112, 0x26},
+  {96, 112, 0x62},
+  {96, 112, 0x63},
+  {96, 112, 0x23},
+  {96, 112, 0x22},
+  {96, 112, 0x66},
+  {85, 111, 0xe8}, {96, 112, 0x67},
+  {70, 104, 0x24}, {85, 111, 0xe8},
+  {70, 104, 0x24}, {54, 108, 0xe4},
+  {40, 100, 0x28}, {38, 107, 0x24}, {54, 108, 0xe4},
+  {25, 85, 0x28}, {40, 100, 0x28}, {38, 107, 0x24}, {22, 110, 0xe4},
+  {11, 70, 0x28}, {25, 85, 0x28}, {7, 108, 0x24}, {22, 110, 0xe4},
+  {11, 70, 0x28}, {7, 108, 0x24},
+  {112, 112, 0x2a},
+  {112, 112, 0x2b},
+  {112, 112, 0x2c},
+  {112, 112, 0x2d},
+  {112, 112, 0x2a}, {108, 125, 0x29},
+  {108, 125, 0x29}, {114, -116, 0x28},
+  {114, -116, 0x28}, {124, -100, 0x29},
+  {124, -100, 0x29}, {123, -84, 0xe9},
+  {123, -84, 0xe9}, {117, -74, 0xe4}, {-124, -69, 0x28},
+  {117, -74, 0xe4}, {-124, -69, 0x28}, {103, -67, 0x68}, {-110, -54, 0x28},
+  {103, -67, 0x68}, {-110, -54, 0x28}, {95, -52, 0x69}, {-102, -39, 0x29},
+  {95, -52, 0x69}, {-102, -39, 0x29}, {96, -36, 0xe9}, {-102, -24, 0xe9},
+  {96, -36, 0xe9}, {-102, -24, 0xe9},
+  {-123, -14, 0x29}, {-115, -14, 0x2e}, {49, -12, 0x28},
+};
+static const uint8 kQuakeItemPos2[] = {
+  0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 18, 19, 20, 21, 22, 23, 24, 26, 28, 30, 33, 37, 41, 45, 46, 47, 48, 49, 50, 51, 52, 53, 55, 57, 59, 62, 66, 70, 72, 73, 74, 75, 76, 78, 80, 82, 84, 87, 91, 95, 99, 101, 104
+};
+static const uint8 kReceiveItem_Tab4[3] = {9, 5, 5};
+static const uint8 kReceiveItem_Tab5[3] = {0x24, 0x25, 0x26};
+static const uint8 kReceiveItem_Tab0[3] = {5, 1, 4};
+static const int16 kReceiveItemMsgs[76] = {
+  -1, 0x70, 0x77, 0x52,   -1, 0x78,  0x78, 0x62, 0x61, 0x66, 0x69, 0x53, 0x52, 0x56,   -1,  0x64,
+  0x63, 0x65, 0x51, 0x54, 0x67, 0x68,  0x6b, 0x77, 0x79, 0x55, 0x6e, 0x58, 0x6d, 0x5d, 0x57,  0x5e,
+  -1, 0x74, 0x75, 0x76,   -1, 0x5f, 0x158,   -1, 0x6a, 0x5c, 0x8f, 0x71, 0x72, 0x73, 0x71,  0x72,
+  0x73, 0x6a, 0x6c, 0x60,   -1,   -1,    -1, 0x59, 0x84, 0x5a,   -1,   -1,   -1,   -1,   -1, 0x159,
+  -1,   -1,   -1,   -1,   -1,   -1,    -1,   -1,   -1, 0xdb, 0x67, 0x7c,
+};
+static const int16 kReceiveItemMsgs2[2] = {0x5b, 0x83};
+static const int16 kReceiveItemMsgs3[4] = {-1, 0x155, 0x156, 0x157};
+static const uint8 kTravelBird_DmaStuffs[4] = {0, 0x20, 0x40, 0xe0};
+static const int8 kTravelBird_Draw_X[3] = {0, -9, -9};
+static const int8 kTravelBird_Draw_Y[3] = {0, 12, 20};
+static const uint8 kTravelBird_Draw_Char[3] = {0xe, 0, 2};
+static const uint8 kTravelBird_Draw_Flags[3] = {0x22, 0x2e, 0x2e};
+static const int8 kSomarianBlock_Coll_X[12] = {0, 0, -8, 8, 0, 0, 0, 0, 8, -8, -8, 8};
+static const int8 kSomarianBlock_Coll_Y[12] = {-8, 8, 0, 0, 0, 0, 0, 0, -8, 8, -8, 8};
+static HandlerFuncK *const kAncilla_Funcs[67] = {
+  &Ancilla01_SomariaBullet,
+  &Ancilla02_FireRodShot,
+  &Ancilla_Empty,
+  &Ancilla04_BeamHit,
+  &Ancilla05_Boomerang,
+  &Ancilla06_WallHit,
+  &Ancilla07_Bomb,
+  &Ancilla08_DoorDebris,
+  &Ancilla09_Arrow,
+  &Ancilla0A_ArrowInTheWall,
+  &Ancilla0B_IceRodShot,
+  &Ancilla_SwordBeam,
+  &Ancilla0D_SpinAttackFullChargeSpark,
+  &Ancilla33_BlastWallExplosion,
+  &Ancilla33_BlastWallExplosion,
+  &Ancilla33_BlastWallExplosion,
+  &Ancilla11_IceRodWallHit,
+  &Ancilla33_BlastWallExplosion,
+  &Ancilla13_IceRodSparkle,
+  &Ancilla_Unused_14,
+  &Ancilla15_JumpSplash,
+  &Ancilla16_HitStars,
+  &Ancilla17_ShovelDirt,
+  &Ancilla18_EtherSpell,
+  &Ancilla19_BombosSpell,
+  &Ancilla1A_PowderDust,
+  &Ancilla_SwordWallHit,
+  &Ancilla1C_QuakeSpell,
+  &Ancilla1D_ScreenShake,
+  &Ancilla1E_DashDust,
+  &Ancilla1F_Hookshot,
+  &Ancilla20_Blanket,
+  &Ancilla21_Snore,
+  &Ancilla22_ItemReceipt,
+  &Ancilla23_LinkPoof,
+  &Ancilla24_Gravestone,
+  &Ancilla_Unused_25,
+  &Ancilla26_SwordSwingSparkle,
+  &Ancilla27_Duck,
+  &Ancilla28_WishPondItem,
+  &Ancilla29_MilestoneItemReceipt,
+  &Ancilla2A_SpinAttackSparkleA,
+  &Ancilla2B_SpinAttackSparkleB,
+  &Ancilla2C_SomariaBlock,
+  &Ancilla2D_SomariaBlockFizz,
+  &Ancilla2E_SomariaBlockFission,
+  &Ancilla2F_LampFlame,
+  &Ancilla30_ByrnaWindupSpark,
+  &Ancilla31_ByrnaSpark,
+  &Ancilla32_BlastWallFireball,
+  &Ancilla33_BlastWallExplosion,
+  &Ancilla34_SkullWoodsFire,
+  &Ancilla35_MasterSwordReceipt,
+  &Ancilla36_Flute,
+  &Ancilla37_WeathervaneExplosion,
+  &Ancilla38_CutsceneDuck,
+  &Ancilla39_SomariaPlatformPoof,
+  &Ancilla3A_BigBombExplosion,
+  &Ancilla3B_SwordUpSparkle,
+  &Ancilla3C_SpinAttackChargeSparkle,
+  &Ancilla3D_ItemSplash,
+  &Ancilla_RisingCrystal,
+  &Ancilla3F_BushPoof,
+  &Ancilla40_DwarfPoof,
+  &Ancilla41_WaterfallSplash,
+  &Ancilla42_HappinessPondRupees,
+  &Ancilla43_GanonsTowerCutscene,
+};
+uint16 Ancilla_GetX(int k) {
+  return ancilla_x_lo[k] | ancilla_x_hi[k] << 8;
+}
+
+uint16 Ancilla_GetY(int k) {
+  return ancilla_y_lo[k] | ancilla_y_hi[k] << 8;
+}
+
+void Ancilla_SetX(int k, uint16 x) {
+  ancilla_x_lo[k] = x;
+  ancilla_x_hi[k] = x >> 8;
+}
+
+void Ancilla_SetY(int k, uint16 y) {
+  ancilla_y_lo[k] = y;
+  ancilla_y_hi[k] = y >> 8;
+}
+
+int Ancilla_AllocHigh() {
+  for (int k = 9; k >= 0; k--) {
+    if (ancilla_type[k] == 0)
+      return k;
+  }
+  return -1;
+}
+
+static void Ancilla_SetOam(OamEnt *oam, uint16 x, uint16 y, uint8 charnum, uint8 flags, uint8 big) {
+  uint8 yval = 0xf0;
+  int xt = enhanced_features0 & kFeatures0_ExtendScreen64 ? 0x40 : 0;
+  if ((uint16)(x + xt) < 256 + xt * 2 && y < 256) {
+    big |= (x >> 8) & 1;
+    oam->x = x;
+    if (y < 0xf0)
+      yval = y;
+  }
+  oam->y = yval;
+  oam->charnum = charnum;
+  oam->flags = flags;
+  bytewise_extended_oam[oam - oam_buf] = big;
+}
+
+static void Ancilla_SetOam_Safe(OamEnt *oam, uint16 x, uint16 y, uint8 charnum, uint8 flags, uint8 big) {
+  uint8 yval = 0xf0;
+  oam->x = x;
+  int xt = enhanced_features0 & kFeatures0_ExtendScreen64 ? 0x48 : 0;
+  if ((uint16)(x + 0x80) < (0x180 + xt)) {
+    big |= (x >> 8) & 1;
+    if ((uint16)(y + 0x10) < 0x100)
+      yval = y;
+  }
+  oam->y = yval;
+  oam->charnum = charnum;
+  oam->flags = flags;
+  bytewise_extended_oam[oam - oam_buf] = big;
+}
+
+void Ancilla_Empty(int k) {
+}
+
+void Ancilla_Unused_14(int k) {
+  assert(0);
+}
+
+void Ancilla_Unused_25(int k) {
+  assert(0);
+}
+
+void SpinSpark_Draw(int k, int offs) {
+  static const uint8 kInitialSpinSpark_Char[32] = {
+    0x92, 0xff, 0xff, 0xff, 0x8c, 0x8c, 0x8c, 0x8c, 0xd6, 0xd6, 0xd6, 0xd6, 0x93, 0x93, 0x93, 0x93,
+    0xd6, 0xd6, 0xd6, 0xd6, 0xd7, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x22, 0xff, 0xff, 0xff,  // wtf oob
+  };
+  static const uint8 kInitialSpinSpark_Flags[29] = {
+    0x22, 0xff, 0xff, 0xff, 0x22, 0x62, 0xa2, 0xe2, 0x24, 0x64, 0xa4, 0xe4, 0x22, 0x62, 0xa2, 0xe2,
+    0x22, 0x62, 0xa2, 0xe2, 0x22, 0xff, 0xff, 0xff, 0x22, 0xff, 0xff, 0xff,
+    0xfc,
+  };
+  static const int8 kInitialSpinSpark_Y[29] = {
+    -4,  0, 0, 0, -8, -8, 0, 0, -8, -8, 0, 0, -8, -8, 0, 0,
+    -8, -8, 0, 0, -4,  0, 0, 0, -4,  0, 0, 0,
+    -4,
+  };
+  static const int16 kInitialSpinSpark_X[29] = {
+    -4, 0,  0, 0, -8, 0, -8, 0, -8, 0, -8, 0, -8, 0, -8, 0,
+    -8, 0, -8, 0, -4, 0,  0, 0, -4, 0,  0, 0,
+    0x11a5
+  };
+  Point16U info;
+  Ancilla_PrepOamCoord(k, &info);
+  OamEnt *oam = GetOamCurPtr();
+  int t = (ancilla_item_to_link[k] + offs) * 4;
+  assert(t < 32);
+  for(int i = 0; i < 4; i++, t++) {
+    if (kInitialSpinSpark_Char[t] != 0xff) {
+      Ancilla_SetOam(oam, info.x + kInitialSpinSpark_X[t], info.y + kInitialSpinSpark_Y[t],
+                     kInitialSpinSpark_Char[t], kInitialSpinSpark_Flags[t] & ~0x30 | HIBYTE(oam_priority_value), 0);
+      oam++;
+    }
+  }
+}
+
+bool SomarianBlock_CheckEmpty(OamEnt *oam) {
+  for (int i = 0; i != 4; i++) {
+    if (oam[i].y == 0xf0)
+      continue;
+    for (i = 0; i < 4; i++)
+      if (!(bytewise_extended_oam[oam + i - oam_buf] & 1))
+        return false;
+    break;
+  }
+  return true;
+}
+
+void AddDashingDustEx(uint8 a, uint8 y, uint8 flag) {
+  static const int8 kAddDashingDust_X[4] = {4, 4, 6, 0};
+  static const int8 kAddDashingDust_Y[4] = {20, 4, 16, 16};
+  int k = Ancilla_AddAncilla(a, y);
+  if (k >= 0) {
+    ancilla_step[k] = flag;
+    ancilla_item_to_link[k] = 0;
+    ancilla_timer[k] = 3;
+    int j = link_direction_facing >> 1;
+    ancilla_dir[k] = j;
+    if (!flag) {
+      Ancilla_SetXY(k, link_x_coord, link_y_coord + 20);
+    } else {
+      Ancilla_SetXY(k, link_x_coord + kAddDashingDust_X[j], link_y_coord + kAddDashingDust_Y[j]);
+    }
+  }
+}
+
+void AddBirdCommon(int k) {
+  ancilla_y_vel[k] = 0;
+  ancilla_item_to_link[k] = 0;
+  ancilla_aux_timer[k] = 1;
+  ancilla_x_vel[k] = 56;
+  ancilla_arr3[k] = 3;
+  ancilla_K[k] = 0;
+  ancilla_G[k] = 0;
+
+  int xt = (enhanced_features0 & kFeatures0_ExtendScreen64) ? 0x40 : 0;
+  Ancilla_SetXY(k, BG2HOFS_copy2 - 16 - xt, link_y_coord - 8);
+}
+
+ProjectSpeedRet Bomb_ProjectSpeedTowardsPlayer(int k, uint16 x, uint16 y, uint8 vel) {  // 84eb63
+  uint16 old_x = Sprite_GetX(0), old_y = Sprite_GetY(0), old_z = sprite_z[0];
+  Sprite_SetX(0, x);
+  Sprite_SetY(0, y);
+  sprite_z[0] = 0;
+  ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLink(0, vel);
+  sprite_z[0] = old_z;
+  Sprite_SetX(0, old_x);
+  Sprite_SetY(0, old_y);
+  return pt;
+}
+
+void Boomerang_CheatWhenNoOnesLooking(int k, ProjectSpeedRet *pt) {  // 86809f
+  uint16 x = link_x_coord - Ancilla_GetX(k) + 0xf0;
+  uint16 y = link_y_coord - Ancilla_GetY(k) + 0xf0;
+  if (x >= 0x1e0) {
+    pt->x = sign16(x - 0x1e0) ? 0x90 : 0x70;
+  } else if (y >= 0x1e0) {
+    pt->y = sign16(y - 0x1e0) ? 0x90 : 0x70;
+  }
+}
+
+void Medallion_CheckSpriteDamage(int k) {  // 86ec5c
+  tmp_counter = ancilla_type[k];
+  for (int j = 15; j >= 0; j--) {
+    if (sprite_state[j] >= 9 && !(sprite_ignore_projectile[j] | sprite_pause[j])) {
+      Ancilla_CheckDamageToSprite_aggressive(j, tmp_counter);
+    }
+  }
+}
+
+void Ancilla_CheckDamageToSprite(int k, uint8 type) {  // 86ecb7
+  if (!sign8(sprite_hit_timer[k]))
+    Ancilla_CheckDamageToSprite_aggressive(k, type);
+}
+
+void Ancilla_CheckDamageToSprite_aggressive(int k, uint8 type) {  // 86ecbd
+  static const uint8 kAncilla_Damage[57] = {
+    6, 1, 11, 0, 0, 0, 0, 8,  0,  6, 0, 12,  1, 0, 0,  0,
+    0, 1,  0, 0, 0, 0, 0, 0, 14, 13, 0,  0, 15, 0, 0,  7,
+    1, 1,  1, 1, 1, 1, 1, 1,  1,  1, 1,  1,  1, 1, 1, 11,
+    0, 1,  1, 1, 1, 1, 1, 1,  1,
+  };
+  uint8 dmg = kAncilla_Damage[type];
+  if (dmg == 6 && link_item_bow >= 3) {
+    if (sprite_type[k] == 0xd7)
+      sprite_delay_aux4[k] = 32;
+    dmg = 9;
+  }
+  Ancilla_CheckDamageToSprite_preset(k, dmg);
+}
+
+void CallForDuckIndoors() {  // 87a45f
+  Ancilla_Sfx2_Near(0x13);
+  AncillaAdd_Duck_take_off(0x27, 4);
+}
+
+void Ancilla_Sfx1_Pan(int k, uint8 v) {  // 888020
+  byte_7E0CF8 = v;
+  sound_effect_ambient = v | Ancilla_CalculateSfxPan(k);
+}
+
+void Ancilla_Sfx2_Pan(int k, uint8 v) {  // 888027
+  byte_7E0CF8 = v;
+  sound_effect_1 = v | Ancilla_CalculateSfxPan(k);
+}
+
+void Ancilla_Sfx3_Pan(int k, uint8 v) {  // 88802e
+  byte_7E0CF8 = v;
+  sound_effect_2 = v | Ancilla_CalculateSfxPan(k);
+}
+
+void AncillaAdd_FireRodShot(uint8 type, uint8 y) {  // 8880b3
+  static const int8 kFireRod_X[4] = {0, 0, -8, 16};
+  static const int8 kFireRod_Y[4] = {-8, 16, 3, 3};
+  static const int8 kFireRod_Xvel[4] = {0, 0, -64, 64};
+  static const int8 kFireRod_Yvel[4] = {-64, 64, 0, 0};
+
+  y = 1;
+  int j= Ancilla_AllocInit(type, 1);
+  if (j < 0) {
+    if (type != 1)
+      Refund_Magic(0);
+    return;
+  }
+
+  if (type != 1)
+    Ancilla_Sfx2_Near(0xe);
+
+  ancilla_type[j] = type;
+  ancilla_numspr[j] = kAncilla_Pflags[type];
+  ancilla_timer[j] = 3;
+  ancilla_step[j] = 0;
+  ancilla_item_to_link[j] = 0;
+  ancilla_objprio[j] = 0;
+  ancilla_U[j] = 0;
+  int i = link_direction_facing >> 1;
+  ancilla_dir[j] = i;
+
+  if (Ancilla_CheckInitialTile_A(j) < 0) {
+    Ancilla_SetXY(j, link_x_coord + kFireRod_X[i], link_y_coord + kFireRod_Y[i]);
+    if (type != 1) {
+      ancilla_x_vel[j] = kFireRod_Xvel[i];
+      ancilla_y_vel[j] = kFireRod_Yvel[i];
+    } else {
+      i += (link_sword_type - 2) * 4;
+      ancilla_x_vel[j] = kFireRod_Xvel2[i];
+      ancilla_y_vel[j] = kFireRod_Yvel2[i];
+    }
+    ancilla_floor[j] = link_is_on_lower_level;
+    ancilla_floor2[j] = link_is_on_lower_level_mirror;
+  } else {
+    if (type == 1) {
+      ancilla_type[j] = 4;
+      ancilla_timer[j] = 7;
+      ancilla_numspr[j] = 16;
+    } else {
+      ancilla_step[j] = 1;
+      ancilla_timer[j] = 31;
+      ancilla_numspr[j] = 8;
+      j = link_direction_facing >> 1; // wtf
+      Ancilla_Sfx2_Pan(j, 0x2a);
+    }
+  }
+}
+
+void SomariaBlock_SpawnBullets(int k) {  // 8881a7
+  static const int8 kSpawnCentrifugalQuad_X[4] = {-8, -8, -9, -4};
+  static const int8 kSpawnCentrifugalQuad_Y[4] = {-15, -4, -8, -8};
+
+  uint8 z = (ancilla_z[k] == 0xff) ? 0 : ancilla_z[k];
+  uint16 x = Ancilla_GetX(k);
+  uint16 y = Ancilla_GetY(k) - z;
+
+  for (int i = 3; i >= 0; i--) {
+    int j = Ancilla_AllocInit(1, 4);
+    if (j >= 0) {
+      ancilla_type[j] = 0x1;
+      ancilla_numspr[j] = kAncilla_Pflags[0x1];
+      ancilla_step[j] = 4;
+      ancilla_item_to_link[j] = 0;
+      ancilla_objprio[j] = 0;
+      ancilla_dir[j] = i;
+      Ancilla_SetXY(j, x + kSpawnCentrifugalQuad_X[i], y + kSpawnCentrifugalQuad_Y[i]);
+      Ancilla_TerminateIfOffscreen(j);
+      ancilla_x_vel[j] = kFireRod_Xvel2[i];
+      ancilla_y_vel[j] = kFireRod_Yvel2[i];
+      ancilla_floor[j] = ancilla_floor[k];
+      ancilla_floor2[j] = link_is_on_lower_level_mirror;
+    }
+  }
+  tmp_counter = 0xff;
+}
+
+void Ancilla_Main() {  // 888242
+  Ancilla_WeaponTink();
+  Ancilla_ExecuteAll();
+}
+
+ProjectSpeedRet Ancilla_ProjectReflexiveSpeedOntoSprite(int k, uint16 x, uint16 y, uint8 vel) {  // 88824d
+  uint16 old_x = link_x_coord, old_y = link_y_coord;
+  link_x_coord = x;
+  link_y_coord = y;
+  ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLink(k, vel);
+  link_x_coord = old_x;
+  link_y_coord = old_y;
+  return pt;
+}
+
+void Bomb_CheckSpriteDamage(int k) {  // 888287
+  for (int j = 15; j >= 0; j--) {
+    if ((j ^ frame_counter) & 3 | sprite_hit_timer[j] | sprite_ignore_projectile[j])
+      continue;
+    if (sprite_floor[j] != ancilla_floor[k] || sprite_state[j] < 9)
+      continue;
+    SpriteHitBox hb;
+    int ax = Ancilla_GetX(k) - 24;
+    int ay = Ancilla_GetY(k) - 24 - ancilla_z[k];
+    hb.r0_xlo = ax;
+    hb.r8_xhi = ax >> 8;
+    hb.r1_ylo = ay;
+    hb.r9_yhi = ay >> 8;
+    hb.r2 = 48;
+    hb.r3 = 48;
+    Sprite_SetupHitBox(j, &hb);
+    if (!CheckIfHitBoxesOverlap(&hb))
+      continue;
+    if (sprite_type[j] == 0x92 && sprite_C[j] >= 3)
+      continue;
+    Ancilla_CheckDamageToSprite(j, ancilla_type[k]);
+    ProjectSpeedRet pt = Ancilla_ProjectReflexiveSpeedOntoSprite(j, Ancilla_GetX(k), Ancilla_GetY(k), 64);
+    sprite_x_recoil[j] = -pt.x;
+    sprite_y_recoil[j] = -pt.y;
+  }
+}
+
+void Ancilla_ExecuteAll() {  // 88832b
+  for (int i = 9; i >= 0; i--) {
+    cur_object_index = i;
+    if (ancilla_type[i])
+      Ancilla_ExecuteOne(ancilla_type[i], i);
+  }
+}
+
+void Ancilla_ExecuteOne(uint8 type, int k) {  // 88833c
+  if (k < 6) {
+    ancilla_oam_idx[k] = Ancilla_AllocateOamFromRegion_A_or_D_or_F(k, ancilla_numspr[k]);
+  }
+
+  if (submodule_index == 0 && ancilla_timer[k] != 0)
+    ancilla_timer[k]--;
+
+  kAncilla_Funcs[type - 1](k);
+}
+
+void Ancilla13_IceRodSparkle(int k) {  // 888435
+  static const uint8 kIceShotSparkle_X[16] = {2, 7, 6, 1, 1, 7, 7, 1, 0, 7, 8, 1, 4, 9, 4, 0xff};
+  static const uint8 kIceShotSparkle_Y[16] = {2, 3, 8, 7, 1, 1, 7, 7, 1, 0, 7, 8, 0xff, 4, 9, 4};
+  static const uint8 kIceShotSparkle_Char[16] = {0x83, 0x83, 0x83, 0x83, 0xb6, 0x80, 0xb6, 0x80, 0xb7, 0xb6, 0xb7, 0xb6, 0xb7, 0xb6, 0xb7, 0xb6};
+
+  if (!ancilla_timer[k])
+    ancilla_type[k] = 0;
+  if (!submodule_index) {
+    Ancilla_MoveX(k);
+    Ancilla_MoveY(k);
+  }
+  AncillaOamInfo info;
+  if (Ancilla_ReturnIfOutsideBounds(k, &info))
+    return;
+
+  int j;
+  for (j = 4; j >= 0 && ancilla_type[j] != 0xb; j--) {}
+  if (j >= 0 && ancilla_objprio[j])
+    info.flags = 0x30;
+
+  if (sort_sprites_setting) {
+    if (ancilla_floor[k])
+      Oam_AllocateFromRegionE(0x10);
+    else
+      Oam_AllocateFromRegionD(0x10);
+  } else {
+    Oam_AllocateFromRegionA(0x10);
+  }
+
+  OamEnt *oam = GetOamCurPtr();
+  j = ancilla_timer[k] & 0x1c;
+  for (int i = 3; i >= 0; i--, oam++)
+    SetOamPlain(oam, info.x + kIceShotSparkle_X[i + j], info.y + kIceShotSparkle_Y[i + j], kIceShotSparkle_Char[i + j], info.flags | 4, 0);
+}
+
+void AncillaAdd_IceRodSparkle(int k) {  // 8884c8
+  static const int8 kIceShotSparkle_Xvel[4] = {0, 0, -4, 4};
+  static const int8 kIceShotSparkle_Yvel[4] = {-4, 4, 0, 0};
+
+  if (submodule_index || !sign8(--ancilla_arr4[k]))
+    return;
+
+  ancilla_arr4[k] = 5;
+  int j = Ancilla_AllocHigh();
+  if (j >= 0) {
+    ancilla_type[j] = 0x13;
+    ancilla_timer[j] = 15;
+
+    int i = ancilla_dir[k];
+    ancilla_x_vel[j] = kIceShotSparkle_Xvel[i];
+    ancilla_y_vel[j] = kIceShotSparkle_Yvel[i];
+
+    ancilla_x_lo[j] = ancilla_x_lo[k];
+    ancilla_y_lo[j] = ancilla_y_lo[k];
+    ancilla_floor[j] = ancilla_floor[k];
+    ancilla_numspr[j] = 0;
+  }
+
+}
+
+void Ancilla01_SomariaBullet(int k) {  // 88851b
+  static const uint8 kSomarianBlast_Mask[6] = {7, 3, 1, 0, 0, 0};
+
+  if (!submodule_index) {
+    if (!(frame_counter & kSomarianBlast_Mask[ancilla_step[k]])) {
+      Ancilla_MoveX(k);
+      Ancilla_MoveY(k);
+    }
+    if (ancilla_timer[k] == 0) {
+      ancilla_timer[k] = 3;
+      uint8 a = ancilla_step[k] + 1;
+      if (a >= 6)
+        a = 4;
+      ancilla_step[k] = a;
+    }
+    if (Ancilla_CheckSpriteCollision(k) >= 0 || Ancilla_CheckTileCollision_staggered(k)) {
+      ancilla_type[k] = 4;
+      ancilla_timer[k] = 7;
+      ancilla_numspr[k] = 16;
+    }
+  }
+  SomarianBlast_Draw(k);
+}
+
+bool Ancilla_ReturnIfOutsideBounds(int k, AncillaOamInfo *info) {  // 88862a
+  static const uint8 kAncilla_FloorFlags[2] = {0x20, 0x10};
+  info->flags = kAncilla_FloorFlags[ancilla_floor[k]];
+  if ((info->x = ancilla_x_lo[k] - BG2HOFS_copy2) >= 0xf4 ||
+      (info->y = ancilla_y_lo[k] - BG2VOFS_copy2) >= 0xf0) {
+    ancilla_type[k] = 0;
+    return true;
+  }
+  return false;
+}
+
+void SomarianBlast_Draw(int k) {  // 888650
+  static const uint8 kSomarianBlast_Flags[2] = {2, 6};
+  AncillaOamInfo info;
+  if (Ancilla_ReturnIfOutsideBounds(k, &info))
+    return;
+  info.flags |= kSomarianBlast_Flags[ancilla_item_to_link[k]];
+  if (ancilla_objprio[k])
+    info.flags |= 0x30;
+  static const int8 kSomarianBlast_Draw_X0[24] = {
+    0, 0, 0, 0, 4, 4, 0, 0, 0, 0, 4, 4, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0,
+  };
+  static const int8 kSomarianBlast_Draw_X1[24] = {
+    8, 8, 8, 8, 4, 4, 8, 8, 8, 8, 4, 4, 0, 0, 0, 0,
+    8, 8, 0, 0, 0, 0, 8, 8,
+  };
+  static const uint8 kSomarianBlast_Draw_Y0[24] = {
+    0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    4, 4, 0, 0, 0, 0, 4, 4,
+  };
+  static const uint8 kSomarianBlast_Draw_Y1[24] = {
+    0, 0,    0, 0, 8, 8, 0x80, 0, 0, 0, 8, 8, 0x80, 8, 8, 8,
+    4, 4, 0x80, 8, 8, 8,    4, 4,
+  };
+  static const uint8 kSomarianBlast_Draw_Flags0[24] = {
+    0xc0, 0xc0, 0xc0, 0xc0, 0x80, 0xc0, 0x40, 0x40, 0x40, 0x40, 0, 0x40, 0x40, 0x40, 0x40, 0x40,
+    0x40, 0xc0,    0,    0,    0,    0,    0, 0x80,
+  };
+  static const uint8 kSomarianBlast_Draw_Flags1[24] = {
+    0x80, 0x80, 0x80, 0x80, 0x80, 0xc0, 0,    0, 0, 0, 0, 0x40, 0xc0, 0xc0, 0xc0, 0xc0,
+    0x40, 0xc0, 0x80, 0x80, 0x80, 0x80, 0, 0x80,
+  };
+  static const uint8 kSomarianBlast_Draw_Char0[24] = {
+    0x50, 0x50, 0x44, 0x44, 0x52, 0x52, 0x50, 0x50, 0x44, 0x44, 0x51, 0x51, 0x43, 0x43, 0x42, 0x42,
+    0x41, 0x41, 0x43, 0x43, 0x42, 0x42, 0x40, 0x40,
+  };
+  static const uint8 kSomarianBlast_Draw_Char1[24] = {
+    0x50, 0x50, 0x44, 0x44, 0x51, 0x51, 0x50, 0x50, 0x44, 0x44, 0x52, 0x52, 0x43, 0x43, 0x42, 0x42,
+    0x40, 0x40, 0x43, 0x43, 0x42, 0x42, 0x41, 0x41,
+  };
+  OamEnt *oam = GetOamCurPtr();
+  int j = ancilla_dir[k] * 6 + ancilla_step[k];
+  SetOamPlain(oam + 0, info.x + kSomarianBlast_Draw_X0[j], sign8(kSomarianBlast_Draw_Y0[j]) ? 0xf0 : info.y + kSomarianBlast_Draw_Y0[j],
+              0x82 + kSomarianBlast_Draw_Char0[j], info.flags | kSomarianBlast_Draw_Flags0[j], 0);
+  SetOamPlain(oam + 1, info.x + kSomarianBlast_Draw_X1[j], sign8(kSomarianBlast_Draw_Y1[j]) ? 0xf0 : info.y + kSomarianBlast_Draw_Y1[j],
+              0x82 + kSomarianBlast_Draw_Char1[j], info.flags | kSomarianBlast_Draw_Flags1[j], 0);
+}
+
+void Ancilla02_FireRodShot(int k) {  // 8886d2
+  if (ancilla_step[k] == 0) {
+    if (!submodule_index) {
+      ancilla_L[k] = 0;
+      Ancilla_MoveX(k);
+      Ancilla_MoveY(k);
+      uint8 coll = Ancilla_CheckSpriteCollision(k) >= 0;
+      if (!coll) {
+        ancilla_dir[k] |= 8;
+        coll = Ancilla_CheckTileCollision(k);
+        ancilla_L[k] = ancilla_tile_attr[k];
+        if (!coll) {
+          ancilla_dir[k] |= 12;
+          uint8 bak = ancilla_U[k];
+          coll = Ancilla_CheckTileCollision(k);
+          ancilla_U[k] = bak;
+        }
+      }
+      if (coll) {
+        ancilla_step[k]++;
+        ancilla_timer[k] = 31;
+        ancilla_numspr[k] = 8;
+        Ancilla_Sfx2_Pan(k, 0x2a);
+      }
+      ancilla_item_to_link[k]++;
+      ancilla_dir[k] &= ~0xC;
+      if (((byte_7E0333 = ancilla_L[k]) & 0xf0) == 0xc0 || ((byte_7E0333 = ancilla_tile_attr[k]) & 0xf0) == 0xc0)
+        Dungeon_LightTorch();
+    }
+    FireShot_Draw(k);
+  } else {
+    AncillaOamInfo info;
+    Ancilla_CheckBasicSpriteCollision(k);
+    if (Ancilla_ReturnIfOutsideBounds(k, &info))
+      return;
+    OamEnt *oam = GetOamCurPtr();
+    if (!ancilla_timer[k]) {
+      uint8 old_type = ancilla_type[k];
+      ancilla_type[k] = 0;
+      if (old_type != 0x2f && BYTE(overworld_screen_index) == 64 && ancilla_tile_attr[k] == 0x43)
+        FireRodShot_BecomeSkullWoodsFire(k);
+      return;
+    }
+    int j = ancilla_timer[k] >> 3;
+    if (j != 0) {
+      static const uint8 kFireShot_Draw_Char[3] = {0xa2, 0xa0, 0x8e};
+      SetOamPlain(oam, info.x, info.y, kFireShot_Draw_Char[j - 1], info.flags | 2, 2);
+    } else {
+      SetOamPlain(oam + 0, info.x + 0, info.y - 3, 0xa4, info.flags | 2, 0);
+      SetOamPlain(oam + 1, info.x + 8, info.y - 3, 0xa5, info.flags | 2, 0);
+    }
+  }
+}
+
+void FireShot_Draw(int k) {  // 88877c
+  static const uint8 kFireShot_Draw_X2[16] = {7, 0, 8, 0, 8, 4, 0, 0, 2, 8, 0, 0, 1, 4, 9, 0};
+  static const uint8 kFireShot_Draw_Y2[16] = {1, 4, 9, 0, 7, 0, 8, 0, 8, 4, 0, 0, 2, 8, 0, 0};
+  static const uint8 kFireShot_Draw_Char2[3] = {0x8d, 0x9d, 0x9c};
+  AncillaOamInfo info;
+  if (Ancilla_ReturnIfOutsideBounds(k, &info))
+    return;
+  if (ancilla_objprio[k])
+    info.flags |= 0x30;
+
+  OamEnt *oam = GetOamCurPtr();
+  int j = ancilla_item_to_link[k] & 0xc;
+  for (int i = 2; i >= 0; i--, oam++)
+    SetOamPlain(oam, info.x + kFireShot_Draw_X2[j + i], info.y + kFireShot_Draw_Y2[j + i], kFireShot_Draw_Char2[i], info.flags | 2, 0);
+}
+
+uint8 Ancilla_CheckTileCollision_staggered(int k) {  // 88897b
+  if ((frame_counter ^ k) & 1)
+    return Ancilla_CheckTileCollision(k);
+  return 0;
+}
+
+uint8 Ancilla_CheckTileCollision(int k) {  // 888981
+  if (!player_is_indoors && ancilla_objprio[k]) {
+    ancilla_tile_attr[k] = 0;
+    return 0;
+  }
+  if (!dung_hdr_collision)
+    return Ancilla_CheckTileCollisionOneFloor(k);
+  uint16 x = 0, y = 0;
+  if (dung_hdr_collision < 3) {
+    x = BG1HOFS_copy2 - BG2HOFS_copy2;
+    y = BG1VOFS_copy2 - BG2VOFS_copy2;
+  }
+  uint16 oldx = Ancilla_GetX(k), oldy = Ancilla_GetY(k);
+  Ancilla_SetX(k, oldx + x);
+  Ancilla_SetY(k, oldy + y);
+  ancilla_floor[k] = 1;
+  uint8 b = Ancilla_CheckTileCollisionOneFloor(k);
+  ancilla_floor[k] = 0;
+  Ancilla_SetX(k, oldx);
+  Ancilla_SetY(k, oldy);
+  return (b << 1) | (uint8)Ancilla_CheckTileCollisionOneFloor(k);
+}
+
+bool Ancilla_CheckTileCollisionOneFloor(int k) {  // 888a03
+  static const int8 kAncilla_CheckTileColl0_X[20] = {
+    8, 8, 0, 16, 4, 4, 0, 16, 4, 4, 4, 12, 12, 12, 4, 12, 0, 0, 0, 0,
+  };
+  static const int8 kAncilla_CheckTileColl0_Y[20] = {
+    0, 16, 5, 5, 0, 16, 4, 4, 4, 12, 5, 5, 4, 12, 12, 12, 0, 0, 0, 0,
+  };
+  uint16 x = Ancilla_GetX(k) + kAncilla_CheckTileColl0_X[ancilla_dir[k]];
+  uint16 y = Ancilla_GetY(k) + kAncilla_CheckTileColl0_Y[ancilla_dir[k]];
+  return Ancilla_CheckTileCollision_targeted(k, x, y);
+}
+
+bool Ancilla_CheckTileCollision_targeted(int k, uint16 x, uint16 y) {  // 888a26
+  if ((uint16)(y - BG2VOFS_copy2) >= 224 || (uint16)(x - BG2HOFS_copy2) >= 256)
+    return 0;
+  uint8 tile_attr;
+  if (!player_is_indoors) {
+    x >>= 3;
+    tile_attr = Overworld_GetTileAttributeAtLocation(x, y);
+  } else {
+    tile_attr = GetTileAttribute(ancilla_floor[k], &x, y);
+  }
+
+  ancilla_tile_attr[k] = tile_attr;
+  if (tile_attr == 3 && ancilla_floor2[k])
+    return 0;
+
+  uint8 t = kAncilla_TileColl0_Attrs[tile_attr];
+
+  if (ancilla_type[k] == 2 && (tile_attr & 0xf0) == 0xc0)
+    t = 0;
+
+  if (!ancilla_objprio[k]) {
+    if (t == 0)
+      return false;
+    if (t == 1)
+      goto return_true_set_alert;
+    if (t == 2)
+      return Entity_CheckSlopedTileCollision(x, y);
+    if (t == 3) {
+      if (ancilla_floor2[k])
+        goto return_true_set_alert;
+      return 0;
+    }
+  }
+  if (sign8(--ancilla_U[k])) {
+    ancilla_U[k] = 0;
+    if (t == 4) {
+      ancilla_U[k] = 6;
+      ancilla_objprio[k] ^= 1;
+    }
+  }
+  return 0;
+
+return_true_set_alert:
+  sprite_alert_flag = 3;
+  return 1;
+}
+
+bool Ancilla_CheckTileCollision_Class2(int k) {  // 888bcf
+  if (!dung_hdr_collision)
+    return Ancilla_CheckTileCollision_Class2_Inner(k);
+  uint16 x = 0, y = 0;
+  if (dung_hdr_collision < 3) {
+    x = BG1HOFS_copy2 - BG2HOFS_copy2;
+    y = BG1VOFS_copy2 - BG2VOFS_copy2;
+  }
+  uint16 oldx = Ancilla_GetX(k), oldy = Ancilla_GetY(k);
+  Ancilla_SetX(k, oldx + x);
+  Ancilla_SetY(k, oldy + y);
+  ancilla_floor[k] = 1;
+  bool b = Ancilla_CheckTileCollision_Class2_Inner(k);
+  ancilla_floor[k] = 0;
+  Ancilla_SetX(k, oldx);
+  Ancilla_SetY(k, oldy);
+  return (b | Ancilla_CheckTileCollision_Class2_Inner(k)) != 0;
+}
+
+bool Ancilla_CheckTileCollision_Class2_Inner(int k) {  // 888c43
+  static const int8 kAncilla_CheckTileColl_Y[4] = {-8, 8, 0, 0};
+  static const int8 kAncilla_CheckTileColl_X[4] = {0, 0, -8, 8};
+
+  uint16 x = Ancilla_GetX(k) + kAncilla_CheckTileColl_X[ancilla_dir[k]];
+  uint16 y = Ancilla_GetY(k) + kAncilla_CheckTileColl_Y[ancilla_dir[k]];
+
+  if ((uint16)(y - BG2VOFS_copy2) >= 224 || (uint16)(x - BG2HOFS_copy2) >= 256)
+    return false;
+  uint8 tile_attr;
+  if (!player_is_indoors) {
+    x >>= 3;
+    tile_attr = Overworld_GetTileAttributeAtLocation(x, y);
+  } else {
+    tile_attr = GetTileAttribute(ancilla_floor[k], &x, y);
+  }
+
+  ancilla_tile_attr[k] = tile_attr;
+  if (tile_attr == 3 && ancilla_floor2[k])
+    return false;
+
+  uint8 t = kAncilla_TileColl_Attrs[tile_attr];
+  if (t == 0)
+    return false;
+  if (t == 2)
+    return Entity_CheckSlopedTileCollision(x, y);
+  if (t == 4) {
+    if (ancilla_floor2[k])
+      return true;
+    ancilla_objprio[k] = 1;
+    return false;
+  }
+  if (t == 3)
+    return ancilla_floor2[k] != 0;
+  return true;
+}
+
+void Ancilla04_BeamHit(int k) {  // 888d19
+  static const int8 kBeamHit_X[16] = {-12, 20, -12, 20, -8, 16, -8, 16, -4, 12, -4, 12, 0, 8, 0, 8};
+  static const int8 kBeamHit_Y[16] = {-12, -12, 20, 20, -8, -8, 16, 16, -4, -4, 12, 12, 0, 0, 8, 8};
+  static const uint8 kBeamHit_Char[16] = {0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x54, 0x54, 0x54, 0x54};
+  static const uint8 kBeamHit_Flags[16] = {0x40, 0, 0xc0, 0x80, 0x40, 0, 0xc0, 0x80, 0x40, 0, 0xc0, 0x80, 0, 0x40, 0x80, 0xc0};
+  AncillaOamInfo info;
+  if (Ancilla_ReturnIfOutsideBounds(k, &info))
+    return;
+  if (!ancilla_timer[k]) {
+    ancilla_type[k] = 0;
+    return;
+  }
+  OamEnt *oam = GetOamCurPtr();
+  int j = ancilla_timer[k] >> 1;
+  uint16 ancilla_x = Ancilla_GetX(k);
+  uint16 ancilla_y = Ancilla_GetY(k);
+  uint8 r7 = ancilla_x - BG2HOFS_copy2;
+  uint8 r6 = ancilla_y - BG2VOFS_copy2;
+  for (int i = 3; i >= 0; i--, oam++) {
+    int m = j * 4 + i;
+    uint8 x = info.x + kBeamHit_X[m];
+    uint8 y = info.y + kBeamHit_Y[m];
+    uint16 x_adj = (uint16)(ancilla_x + (int8)(x - r7) - BG2HOFS_copy2);
+    uint16 y_adj = (uint16)(ancilla_y + (int8)(y - r6) - BG2VOFS_copy2 + 0x10);
+    SetOamPlain(oam, x, (y_adj >= 0x100) ? 0xf0 : y,
+                kBeamHit_Char[m] + 0x82, kBeamHit_Flags[m] | 2 | info.flags, (x_adj >= 0x100) ? 1 : 0);
+  }
+}
+
+int Ancilla_CheckSpriteCollision(int k) {  // 888d68
+  for (int j = 15; j >= 0; j--) {
+    if (ancilla_type[k] == 9 || ancilla_type[k] == 0x1f || ((j ^ frame_counter) & 3 | sprite_pause[j]) == 0) {
+      if ((sprite_state[j] >= 9 && (sprite_defl_bits[j] & 2 || !ancilla_objprio[k])) && ancilla_floor[k] == sprite_floor[j]) {
+        if (Ancilla_CheckSpriteCollision_Single(k, j))
+          return j;
+      }
+    }
+  }
+  return -1;
+}
+
+bool Ancilla_CheckSpriteCollision_Single(int k, int j) {  // 888dae
+  int i;
+  SpriteHitBox hb;
+  Ancilla_SetupHitBox(k, &hb);
+
+  Sprite_SetupHitBox(j, &hb);
+  if (!CheckIfHitBoxesOverlap(&hb))
+    return false;
+
+  bool return_value = true;
+  if (sprite_flags[j] & 8 && ancilla_type[k] == 9) {
+    if (sprite_type[j] != 0x1b) {
+      Sprite_CreateDeflectedArrow(k);
+      return false;
+    }
+    if (link_item_bow < 3) {
+      Sprite_CreateDeflectedArrow(k);
+    } else {
+      return_value = false;
+    }
+  }
+
+  if (sprite_defl_bits[j] & 0x10) {
+    static const uint8 kAncilla_CheckSpriteColl_Dir[4] = {2, 3, 0, 1};
+    ancilla_dir[k] &= 3;
+    if (ancilla_dir[k] == kAncilla_CheckSpriteColl_Dir[ancilla_dir[k]])
+      goto return_true_set_alert;
+  }
+
+  if (ancilla_type[k] == 5 || ancilla_type[k] == 0x1f) {
+    if (ancilla_type[k] == 0x1f && sprite_type[j] == 0x8d)
+      goto skip;
+    if (sprite_hit_timer[j])
+      goto return_true_set_alert;
+    if (sprite_defl_bits[j] & 2) {
+skip:
+      sprite_B[j] = k + 1;
+      sprite_unk2[j] = ancilla_type[k];
+      goto return_true_set_alert;
+    }
+  }
+
+  if (!sprite_ignore_projectile[j]) {
+    static const int8 kAncilla_CheckSpriteColl_RecoilX[4] = {0, 0, -64, 64};
+    static const int8 kAncilla_CheckSpriteColl_RecoilY[4] = {-64, 64, 0, 0};
+    if (sprite_type[j] == 0x92 && sprite_C[j] < 3)
+      goto return_true_set_alert;
+    i = ancilla_dir[k] & 3;
+    sprite_x_recoil[j] = kAncilla_CheckSpriteColl_RecoilX[i];
+    sprite_y_recoil[j] = kAncilla_CheckSpriteColl_RecoilY[i];
+    byte_7E0FB6 = k;
+    Ancilla_CheckDamageToSprite(j, ancilla_type[k]);
+return_true_set_alert:
+    sprite_unk2[j] = ancilla_type[k];
+    sprite_alert_flag = 3;
+    return return_value;
+  }
+  return false;
+}
+
+void Ancilla_SetupHitBox(int k, SpriteHitBox *hb) {  // 888ead
+  static const int8 kAncilla_HitBox_X[12] = {4, 4, 4, 4, 3, 3, 2, 11, -16, -16, -1, -8};
+  static const int8 kAncilla_HitBox_Y[12] = {4, 4, 4, 4, 2, 11, 3, 3, -1, -8, -16, -16};
+  static const uint8 kAncilla_HitBox_W[12] = {8, 8, 8, 8, 1, 1, 1, 1, 32, 32, 8, 8};
+  static const uint8 kAncilla_HitBox_H[12] = {8, 8, 8, 8, 1, 1, 1, 1, 8, 8, 32, 32};
+  int j = ancilla_dir[k];
+  if (ancilla_type[k] == 0xc)
+    j |= 8;
+  int x = Ancilla_GetX(k) + kAncilla_HitBox_X[j];
+  hb->r0_xlo = x;
+  hb->r8_xhi = x >> 8;
+  int y = Ancilla_GetY(k) + kAncilla_HitBox_Y[j];
+  hb->r1_ylo = y;
+  hb->r9_yhi = y >> 8;
+  hb->r2 = kAncilla_HitBox_W[j];
+  hb->r3 = kAncilla_HitBox_H[j];
+}
+
+ProjectSpeedRet Ancilla_ProjectSpeedTowardsPlayer(int k, uint8 vel) {  // 888eed
+  if (vel == 0) {
+    ProjectSpeedRet rv = { 0, 0, 0, 0 };
+    return rv;
+  }
+  PairU8 below = Ancilla_IsBelowLink(k);
+  uint8 r12 = sign8(below.b) ? -below.b : below.b;
+
+  PairU8 right = Ancilla_IsRightOfLink(k);
+  uint8 r13 = sign8(right.b) ? -right.b : right.b;
+  uint8 t;
+  bool swapped = false;
+  if (r13 < r12) {
+    swapped = true;
+    t = r12, r12 = r13, r13 = t;
+  }
+  uint8 xvel = vel, yvel = 0;
+  t = 0;
+  do {
+    t += r12;
+    if (t >= r13)
+      t -= r13, yvel++;
+  } while (--vel);
+  if (swapped)
+    t = xvel, xvel = yvel, yvel = t;
+  ProjectSpeedRet rv = {
+    (uint8)(right.a ? -xvel : xvel),
+    (uint8)(below.a ? -yvel : yvel),
+    right.b,
+    below.b
+  };
+  return rv;
+}
+
+PairU8 Ancilla_IsRightOfLink(int k) {  // 888f5c
+  uint16 x = link_x_coord - Ancilla_GetX(k);
+  PairU8 rv = { (uint8)(sign16(x) ? 1 : 0), (uint8)x };
+  return rv;
+}
+
+PairU8 Ancilla_IsBelowLink(int k) {  // 888f6f
+  int y = link_y_coord - Ancilla_GetY(k);
+  PairU8 rv = { (uint8)(sign16(y) ? 1 : 0), (uint8)y };
+  return rv;
+}
+
+void Ancilla_WeaponTink() {  // 888f89
+  if (!repulsespark_timer)
+    return;
+  sprite_alert_flag = 2;
+  if (sign8(--repulsespark_anim_delay)) {
+    repulsespark_timer--;
+    repulsespark_anim_delay = 1;
+  }
+
+  if (sort_sprites_setting) {
+    if (repulsespark_floor_status)
+      Oam_AllocateFromRegionF(0x10);
+    else
+      Oam_AllocateFromRegionD(0x10);
+  } else {
+    Oam_AllocateFromRegionA(0x10);
+  }
+
+  uint8 x = repulsespark_x_lo - BG2HOFS_copy2;
+  uint8 y = repulsespark_y_lo - BG2VOFS_copy2;
+
+  if (x >= 0xf8 || y >= 0xf0) {
+    repulsespark_timer = 0;
+    return;
+  }
+
+  OamEnt *oam = GetOamCurPtr();
+  static const uint8 kRepulseSpark_Flags[4] = {0x22, 0x12, 0x22, 0x22};
+  uint8 flags = kRepulseSpark_Flags[repulsespark_floor_status];
+  if (repulsespark_timer >= 3) {
+    SetOamPlain(oam, x, y, (repulsespark_timer < 9) ? 0x92 : 0x80, flags, 0);
+    return;
+  }
+  static const uint8 kRepulseSpark_Char[3] = { 0x93, 0x82, 0x81 };
+  uint8 c = kRepulseSpark_Char[repulsespark_timer];
+  SetOamPlain(oam + 0, x - 4, y - 4, c, flags | 0x00, 0);
+  SetOamPlain(oam + 1, x + 4, y - 4, c, flags | 0x40, 0);
+  SetOamPlain(oam + 2, x - 4, y + 4, c, flags | 0x80, 0);
+  SetOamPlain(oam + 3, x + 4, y + 4, c, flags | 0xc0, 0);
+}
+
+void Ancilla_MoveX(int k) {  // 889080
+  uint32 t = ancilla_x_subpixel[k] + (ancilla_x_lo[k] << 8) + (ancilla_x_hi[k] << 16) + ((int8)ancilla_x_vel[k] << 4);
+  ancilla_x_subpixel[k] = t, ancilla_x_lo[k] = t >> 8, ancilla_x_hi[k] = t >> 16;
+}
+
+void Ancilla_MoveY(int k) {  // 88908b
+  uint32 t = ancilla_y_subpixel[k] + (ancilla_y_lo[k] << 8) + (ancilla_y_hi[k] << 16) + ((int8)ancilla_y_vel[k] << 4);
+  ancilla_y_subpixel[k] = t, ancilla_y_lo[k] = t >> 8, ancilla_y_hi[k] = t >> 16;
+}
+
+void Ancilla_MoveZ(int k) {  // 8890b7
+  uint32 t = ancilla_z_subpixel[k] + (ancilla_z[k] << 8) + ((int8)ancilla_z_vel[k] << 4);
+  ancilla_z_subpixel[k] = t, ancilla_z[k] = t >> 8;
+}
+
+void Ancilla05_Boomerang(int k) {  // 8890fc
+  int hit_spr;
+  static const int8 kBoomerang_X0[8] = {0, 0, -8, 8, 8, 8, -8, -8};
+  static const int8 kBoomerang_Y0[8] = {-16, 6, 0, 0, -8, 8, -8, 8};
+
+  for (int j = 4; j >= 0; j--) {
+    if (ancilla_type[j] == 0x22)
+      goto exit_and_draw;
+  }
+  if (submodule_index)
+    goto exit_and_draw;
+
+  if (!(frame_counter & 7))
+    Ancilla_Sfx2_Pan(k, 0x9);
+
+  if (!ancilla_aux_timer[k]) {
+    if (button_b_frames < 9 && player_handler_timer == 0) {
+      if (link_is_bunny_mirror || link_auxiliary_state || link_item_in_hand == 0 && (enhanced_features0 & kFeatures0_MiscBugFixes)) {
+        Boomerang_Terminate(k);
+        return;
+      }
+      goto exit_and_draw;
+    }
+    int j = ancilla_arr23[k] >> 1;
+    Ancilla_SetXY(k, link_x_coord + kBoomerang_X0[j], link_y_coord + 8 + kBoomerang_Y0[j]);
+    ancilla_aux_timer[k]++;
+  }
+  // endif_2
+  if (ancilla_G[k] && !(frame_counter & 1))
+    AncillaAdd_SwordChargeSparkle(k);
+
+  if (ancilla_item_to_link[k]) {
+    if (ancilla_K[k])
+      ancilla_K[k]++;
+    WORD(ancilla_A[k]) = link_y_coord;
+    link_y_coord += 8;
+    ProjectSpeedRet pt = Ancilla_ProjectSpeedTowardsPlayer(k, ancilla_H[k]);
+    Boomerang_CheatWhenNoOnesLooking(k, &pt);
+    ancilla_x_vel[k] = pt.x;
+    ancilla_y_vel[k] = pt.y;
+    link_y_coord = WORD(ancilla_A[k]);
+  }
+
+  if (ancilla_y_vel[k])
+    ancilla_y_vel[k] += ancilla_K[k];
+  Ancilla_MoveY(k);
+
+  if (ancilla_x_vel[k])
+    ancilla_x_vel[k] += ancilla_K[k];
+  Ancilla_MoveX(k);
+  hit_spr = Ancilla_CheckSpriteCollision(k);
+
+  if (!ancilla_item_to_link[k]) {
+    if (hit_spr >= 0) {
+      ancilla_item_to_link[k] ^= 1;
+    } else if (Ancilla_CheckTileCollision(k)) {
+      AncillaAdd_BoomerangWallClink(k);
+      Ancilla_Sfx2_Pan(k, (ancilla_tile_attr[k] == 0xf0) ? 6 : 5);
+      ancilla_item_to_link[k] ^= 1;
+    } else if (Boomerang_ScreenEdge(k) || --ancilla_step[k] == 0) {
+      ancilla_item_to_link[k] ^= 1;
+    } else {
+      if (ancilla_step[k] < 5)
+        ancilla_K[k]--;
+    }
+  } else {
+    uint8 bak0 = ancilla_objprio[k];
+    uint8 bak1 = ancilla_floor[k];
+    ancilla_floor[k] = 0;
+    Ancilla_CheckTileCollision(k);
+    ancilla_floor[k] = bak1;
+    ancilla_objprio[k] = bak0;
+    Boomerang_StopOffScreen(k);
+  }
+
+exit_and_draw:
+  Boomerang_Draw(k);
+}
+
+bool Boomerang_ScreenEdge(int k) {  // 88924b
+  uint16 x = Ancilla_GetX(k), y = Ancilla_GetY(k);
+  if (hookshot_effect_index & 3) {
+    uint16 t = x + (hookshot_effect_index & 1 ? 16 : 0) - BG2HOFS_copy2;
+    if (t >= 0x100)
+      return true;
+  }
+  if (hookshot_effect_index & 12) {
+    uint16 t = y + (hookshot_effect_index & 4 ? 16 : 0) - BG2VOFS_copy2;
+    if (t >= 0xe2)
+      return true;
+  }
+  return false;
+}
+
+void Boomerang_StopOffScreen(int k) {  // 8892ab
+  uint16 x = Ancilla_GetX(k) + 8, y = Ancilla_GetY(k) + 8;
+  if (x >= link_x_coord && x < (uint16)(link_x_coord + 16) &&
+      y >= link_y_coord && y < (uint16)(link_y_coord + 24))
+    Boomerang_Terminate(k);
+}
+
+void Boomerang_Terminate(int k) {  // 8892f5
+  ancilla_type[k] = 0;
+  flag_for_boomerang_in_place = 0;
+  if (link_item_in_hand & 0x80) {
+    link_item_in_hand = 0;
+    button_mask_b_y &= ~0x40;
+    if (!(button_mask_b_y & 0x80))
+      link_cant_change_direction &= ~1;
+  }
+}
+
+void Boomerang_Draw(int k) {  // 889338
+  static const uint8 kBoomerang_Flags[8] = {0xa4, 0xe4, 0x64, 0x24, 0xa2, 0xe2, 0x62, 0x22};
+  static const int8 kBoomerang_Draw_XY[8] = {2, -2, 2, 2, -2, 2, -2, -2};
+  static const uint16 kBoomerang_Draw_OamIdx[2] = {0x180, 0xd0};
+  static const uint8 kBoomerang_Draw_Tab0[2] = {3, 2};
+  Point16U info;
+  Ancilla_PrepOamCoord(k, &info);
+
+  if (ancilla_item_to_link[k]) {
+    ancilla_floor[k] = link_is_on_lower_level;
+    oam_priority_value = kTagalongLayerBits[link_is_on_lower_level] << 8;
+  }
+
+  if (ancilla_objprio[k])
+    oam_priority_value = 0x3000;
+
+  if (!submodule_index && ancilla_aux_timer[k] && sign8(--ancilla_arr3[k])) {
+    ancilla_arr3[k] = kBoomerang_Draw_Tab0[ancilla_G[k]];
+    ancilla_arr1[k] = (ancilla_arr1[k] + (ancilla_S[k] ? -1 : 1)) & 3;
+  }
+
+  int j = ancilla_arr1[k];
+  uint16 x = info.x + kBoomerang_Draw_XY[j * 2 + 1];
+  uint16 y = info.y + kBoomerang_Draw_XY[j * 2 + 0];
+  if (!ancilla_aux_timer[k]) {
+    int i = kBoomerang_Draw_OamIdx[sort_sprites_setting];
+    oam_ext_cur_ptr = (i >> 2) + 0xa20;
+    oam_cur_ptr = i + 0x800;
+  }
+  Ancilla_SetOam_Safe(GetOamCurPtr(), x, y, 0x26, kBoomerang_Flags[ancilla_G[k] * 4 + j] & ~0x30 | HIBYTE(oam_priority_value), 2);
+}
+
+void Ancilla06_WallHit(int k) {  // 8893e8
+  if (sign8(--ancilla_arr3[k])) {
+    uint8 t = ancilla_item_to_link[k] + 1;
+    if (t == 5) {
+      ancilla_type[k] = 0;
+      return;
+    }
+    ancilla_item_to_link[k] = t;
+    ancilla_arr3[k] = 1;
+  }
+  WallHit_Draw(k);
+}
+
+void Ancilla_SwordWallHit(int k) {  // 8893ff
+  sprite_alert_flag = 3;
+  if (sign8(--ancilla_aux_timer[k])) {
+    uint8 t = ancilla_item_to_link[k] + 1;
+    if (t == 8) {
+      ancilla_type[k] = 0;
+      return;
+    }
+    ancilla_item_to_link[k] = t;
+    ancilla_aux_timer[k] = 1;
+  }
+  WallHit_Draw(k);
+}
+
+void WallHit_Draw(int k) {  // 8894df
+  static const int8 kWallHit_X[32] = {
+    -4, 0,  0, 0, -4, 0, 0, 0, -8, 0, -8, 0, -8, 0, -8, 0,
+    -8, 0, -8, 0, -4, 0, 0, 0, -4, 0,  0, 0, -8, 0,  0, 0,
+  };
+  static const int8 kWallHit_Y[32] = {
+    -4,  0, 0, 0, -4, 0, 0, 0, -8, -8, 0, 0, -8, -8, 0, 0,
+    -8, -8, 0, 0, -4, 0, 0, 0, -4,  0, 0, 0, -8,  0, 0, 0,
+  };
+  static const uint8 kWallHit_Char[32] = {
+    0x80,    0,    0,    0, 0x92, 0, 0, 0, 0x81, 0x81, 0x81, 0x81, 0x82, 0x82, 0x82, 0x82,
+    0x93, 0x93, 0x93, 0x93, 0x92, 0, 0, 0, 0xb9,    0,    0,    0, 0x90, 0x90,    0,    0,
+  };
+  static const uint8 kWallHit_Flags[32] = {
+    0x32,    0,    0,    0, 0x32, 0, 0, 0, 0x32, 0x72, 0xb2, 0xf2, 0x32, 0x72, 0xb2, 0xf2,
+    0x32, 0x72, 0xb2, 0xf2, 0x32, 0, 0, 0, 0x72,    0,    0,    0, 0x32, 0xf2,    0,    0,
+  };
+  Point16U info;
+  Ancilla_PrepOamCoord(k, &info);
+
+  int t = ancilla_item_to_link[k] * 4;
+
+  OamEnt *oam = GetOamCurPtr();
+  for (int n = 3; n >= 0; n--, t++) {
+    if (kWallHit_Char[t] != 0) {
+      Ancilla_SetOam(oam, info.x + kWallHit_X[t], info.y + kWallHit_Y[t], kWallHit_Char[t],
+                     kWallHit_Flags[t] & ~0x30 | HIBYTE(oam_priority_value), 0);
+      oam++;
+    }
+    oam = Ancilla_AllocateOamFromCustomRegion(oam);
+  }
+
+}
+
+void Ancilla07_Bomb(int k) {  // 88955a
+  if (submodule_index) {
+    if (submodule_index == 8 || submodule_index == 16) {
+      Ancilla_HandleLiftLogic(k);
+    } else if (k + 1 == flag_is_ancilla_to_pick_up && ancilla_K[k] != 0) {
+      if (ancilla_K[k] != 3) {
+        Ancilla_LatchLinkCoordinates(k, 3);
+        Ancilla_LatchAltitudeAboveLink(k);
+        ancilla_K[k] = 3;
+      }
+      Ancilla_LatchCarriedPosition(k);
+    }
+    Bomb_Draw(k);
+    return;
+  }
+  Ancilla_HandleLiftLogic(k);
+
+  uint16 old_y = Ancilla_LatchYCoordToZ(k);
+  uint8 s1a = ancilla_dir[k];
+  uint8 s1b = ancilla_objprio[k];
+  ancilla_objprio[k] = 0;
+  bool flag = Ancilla_CheckTileCollision_Class2(k);
+
+  if (player_is_indoors && ancilla_L[k] && ancilla_tile_attr[k] == 0x1c)
+    ancilla_T[k] = 1;
+
+label1:
+  if (flag && (!(link_state_bits & 0x80) || link_picking_throw_state)) {
+    if (!s1b && !ancilla_arr4[k]) {
+      ancilla_arr4[k] = 1;
+      int qq = (ancilla_dir[k] == 1) ? 16 : 4;
+      if (ancilla_y_vel[k])
+        ancilla_y_vel[k] = sign8(ancilla_y_vel[k]) ? qq : -qq;
+      if (ancilla_x_vel[k])
+        ancilla_x_vel[k] = sign8(ancilla_x_vel[k]) ? 4 : -4;
+      if (ancilla_dir[k] == 1 && ancilla_z[k]) {
+        ancilla_y_vel[k] = -4;
+        ancilla_L[k] = 2;
+      }
+    }
+  } else if (!((k + 1 == flag_is_ancilla_to_pick_up) && (link_state_bits & 0x80)) && (ancilla_z[k] == 0 || ancilla_z[k] == 0xff)) {
+    ancilla_dir[k] = 16;
+    uint8 bak0 = ancilla_objprio[k];
+    Ancilla_CheckTileCollision(k);
+    ancilla_objprio[k] = bak0;
+    uint8 a = ancilla_tile_attr[k];
+    if (a == 0x26) {
+      flag = true;
+      goto label1;
+    } else if (a == 0xc || a == 0x1c) {
+      if (dung_hdr_collision != 3) {
+        if (ancilla_floor[k] == 0 && ancilla_z[k] != 0 && ancilla_z[k] != 0xff)
+          ancilla_floor[k] = 1;
+      } else {
+        old_y = Ancilla_GetY(k) + dung_floor_y_vel;
+        Ancilla_SetX(k, Ancilla_GetX(k) + dung_floor_x_vel);
+      }
+    } else if (a == 0x20 || (a & 0xf0) == 0xb0 && a != 0xb6 && a != 0xbc) {
+      if (!(link_state_bits & 0x80)) {
+        if (k + 1 == flag_is_ancilla_to_pick_up)
+          flag_is_ancilla_to_pick_up = 0;
+        if (!ancilla_timer[k]) {
+          ancilla_type[k] = 0;
+          return;
+        }
+      }
+    } else if (a == 8) {
+      if (k + 1 == flag_is_ancilla_to_pick_up)
+        flag_is_ancilla_to_pick_up = 0;
+      if (ancilla_timer[k] == 0) {
+        Ancilla_SetY(k, Ancilla_GetY(k) - 24);
+        Ancilla_TransmuteToSplash(k);
+        return;
+      }
+    } else if (a == 0x68 || a == 0x69 || a == 0x6a || a == 0x6b) {
+      Ancilla_ApplyConveyor(k);
+      old_y = Ancilla_GetY(k);
+    } else {
+      ancilla_timer[k] = ancilla_L[k] ? 0 : 2;
+    }
+  }
+  // endif_3
+
+  Ancilla_SetY(k, old_y);
+  ancilla_dir[k] = s1a;
+  ancilla_objprio[k] |= s1b;
+  Bomb_CheckSpriteAndPlayerDamage(k);
+  if (!--ancilla_arr3[k]) {
+    if (++ancilla_item_to_link[k] == 1) {
+      Ancilla_Sfx2_Pan(k, 0xc);
+      if (k + 1 == flag_is_ancilla_to_pick_up) {
+        flag_is_ancilla_to_pick_up = 0;
+        if (link_state_bits & 0x80) {
+          link_state_bits = 0;
+          link_cant_change_direction = 0;
+        }
+      }
+    }
+
+    if (ancilla_item_to_link[k] == 11) {
+      // transmute to door debris?
+      ancilla_type[k] = ancilla_step[k] ? 8 : 0;
+      return;
+    }
+    ancilla_arr3[k] = kBomb_Tab0[ancilla_item_to_link[k]];
+  }
+
+  if (ancilla_item_to_link[k] == 7 && ancilla_arr3[k] == 2) {
+    // check whether the bomb causes any door debris, the bomb
+    // will transmute to debris later on.
+    door_debris_x[k] = 0;
+    Bomb_CheckForDestructibles(Ancilla_GetX(k), Ancilla_GetY(k), k);
+    if (door_debris_x[k])
+      ancilla_step[k] = 1;
+  }
+  Bomb_Draw(k);
+}
+
+void Ancilla_ApplyConveyor(int k) {  // 8897be
+  static const int8 kAncilla_Belt_Xvel[4] = {0, 0, -8, 8};
+  static const int8 kAncilla_Belt_Yvel[4] = {-8, 8, 0, 0};
+  int j = ancilla_tile_attr[k] - 0x68;
+  ancilla_y_vel[k] = kAncilla_Belt_Yvel[j];
+  ancilla_x_vel[k] = kAncilla_Belt_Xvel[j];
+  Ancilla_MoveY(k);
+  Ancilla_MoveX(k);
+}
+
+void Bomb_CheckSpriteAndPlayerDamage(int k) {  // 889815
+  static const uint8 kBomb_Dmg_Speed[16] = {32, 32, 32, 32, 32, 32, 28, 28, 28, 28, 28, 28, 24, 24, 24, 24};
+  static const uint8 kBomb_Dmg_Zvel[16] = {16, 16, 16, 16, 16, 16, 12, 12, 12, 12, 8, 8, 8, 8, 8, 8};
+  static const uint8 kBomb_Dmg_Delay[16] = {32, 32, 32, 32, 32, 32, 24, 24, 24, 24, 24, 24, 16, 16, 16, 16};
+  static const uint8 kBomb_Dmg_ToLink[3] = {8, 4, 2};
+
+  if (ancilla_item_to_link[k] == 0 || ancilla_item_to_link[k] >= 9)
+    return;
+  Bomb_CheckSpriteDamage(k);
+  if (link_disable_sprite_damage) {
+    if (k + 1 == flag_is_ancilla_to_pick_up && link_state_bits & 0x80) {
+      link_state_bits &= ~0x80;
+      link_cant_change_direction = 0;
+    }
+    return;
+  }
+
+  if (link_auxiliary_state || link_incapacitated_timer || ancilla_floor[k] != link_is_on_lower_level)
+    return;
+
+  SpriteHitBox hb;
+  hb.r0_xlo = link_x_coord;
+  hb.r8_xhi = link_x_coord >> 8;
+  hb.r1_ylo = link_y_coord;
+  hb.r9_yhi = link_y_coord >> 8;
+  hb.r2 = 0x10;
+  hb.r3 = 0x18;
+
+  int ax = Ancilla_GetX(k) - 16, ay = Ancilla_GetY(k) - 16;
+  hb.r6_spr_xsize = 32;
+  hb.r7_spr_ysize = 32;
+  hb.r4_spr_xlo = ax;
+  hb.r10_spr_xhi = ax >> 8;
+  hb.r5_spr_ylo = ay;
+  hb.r11_spr_yhi = ay >> 8;
+
+  if (!CheckIfHitBoxesOverlap(&hb))
+    return;
+
+  int x = Ancilla_GetX(k) - 8, y = Ancilla_GetY(k) - 12;
+
+  int j = Bomb_GetDisplacementFromLink(k);
+  ProjectSpeedRet pt = Bomb_ProjectSpeedTowardsPlayer(k, x, y, kBomb_Dmg_Speed[j]);
+  if (countdown_for_blink || flag_block_link_menu == 2)
+    return;
+  link_actual_vel_x = pt.x;
+  link_actual_vel_y = pt.y;
+
+  link_actual_vel_z_copy = link_actual_vel_z = kBomb_Dmg_Zvel[j];
+  link_incapacitated_timer = kBomb_Dmg_Delay[j];
+  link_auxiliary_state = 1;
+  countdown_for_blink = 58;
+  if (!(dung_savegame_state_bits & 0x8000))
+    link_give_damage = kBomb_Dmg_ToLink[link_armor];
+
+}
+
+void Ancilla_HandleLiftLogic(int k) {  // 889976
+  static const uint8 kAncilla_Liftable_Delay[3] = {16, 8, 9};
+
+  if (ancilla_R[k]) {
+label_6:
+    if (ancilla_item_to_link[k])
+      return;
+    if (ancilla_K[k] == 3) {
+      ancilla_z_vel[k] -= 2;
+      Ancilla_MoveZ(k);
+      if (ancilla_z[k] && ancilla_z[k] < 252)
+        return;
+      ancilla_z[k] = 0;
+      if (++ancilla_R[k] != 3) {
+        ancilla_z_vel[k] = 24;
+        return;
+      }
+      ancilla_K[k] = 0;
+    }
+    ancilla_R[k] = 0;
+    link_speed_setting = 0;
+    return;
+  }
+  if (!ancilla_L[k]) {
+    if (!flag_is_ancilla_to_pick_up) {
+clear_pickup_item:
+      flag_is_ancilla_to_pick_up = 0;
+      CheckPlayerCollOut coll;
+      if (ancilla_item_to_link[k] || link_state_bits || !Ancilla_CheckLinkCollision(k, 0, &coll) || ancilla_floor[k] != link_is_on_lower_level)
+        return;
+      if (coll.r8 >= 16 || coll.r10 >= 12) {
+        int j = (coll.r8 >= coll.r10) ? (sign8(coll.r4) ? 1 : 0) : (sign8(coll.r6) ? 3 : 2);
+        if (j * 2 != link_direction_facing)
+          return;
+      }
+      flag_is_ancilla_to_pick_up = k + 1;
+      ancilla_K[k] = 0;
+      ancilla_aux_timer[k] = kAncilla_Liftable_Delay[0];
+      ancilla_L[k] = 0;
+      ancilla_z[k] = 0;
+      return;
+    }
+
+    if (flag_is_ancilla_to_pick_up != k + 1)
+      return;
+    if (!link_disable_sprite_damage && link_incapacitated_timer || byte_7E03FD || link_auxiliary_state == 1) {
+      ancilla_R[k] = 1;
+      ancilla_z_vel[k] = 0;
+      flag_is_ancilla_to_pick_up = 0;
+      ancilla_arr4[k] = 0;
+      goto label_6;
+    }
+    if (!(link_state_bits & 0x80))
+      goto clear_pickup_item;
+    int j = ancilla_K[k];
+    if (link_picking_throw_state != 2 && flag_is_ancilla_to_pick_up != 0 && j != 3) {
+      if (j == 0 && ancilla_aux_timer[k] == 16)
+        Ancilla_Sfx2_Pan(k, 0x1d);
+      if (sign8(--ancilla_aux_timer[k])) {
+        ancilla_K[k] = ++j;
+        ancilla_aux_timer[k] = j == 3 ? -2 : kAncilla_Liftable_Delay[j];
+        if (j == 3) {
+          Ancilla_LatchAltitudeAboveLink(k);
+          return;
+        }
+      }
+      Ancilla_LatchLinkCoordinates(k, j);
+      return;
+    }
+    if (j != 3)
+      return;
+
+    if (link_picking_throw_state != 2 && (submodule_index != 0 || !((filtered_joypad_L | filtered_joypad_H) & 0x80))) {
+      if (ancilla_item_to_link[k])
+        return;
+      if (player_near_pit_state >= 2) {
+        link_speed_setting = 0;
+        if (k + 1 == flag_is_ancilla_to_pick_up) {
+          flag_is_ancilla_to_pick_up = 0;
+          ancilla_type[k] = 0;
+        }
+        return;
+      }
+      if (!(link_is_in_deep_water | link_is_bunny_mirror)) {
+        Ancilla_LatchCarriedPosition(k);
+        return;
+      }
+      link_state_bits = 0;
+    }
+    static const int8 kAncilla_Liftable_Yvel[4] = {-32, 32, 0, 0};
+    static const int8 kAncilla_Liftable_Xvel[4] = {0, 0, -32, 32};
+    j = link_direction_facing >> 1;
+    ancilla_dir[k] = j;
+    ancilla_z_vel[k] = 24;
+    ancilla_y_vel[k] = kAncilla_Liftable_Yvel[j];
+    ancilla_x_vel[k] = kAncilla_Liftable_Xvel[j];
+    link_picking_throw_state = 2;
+    ancilla_L[k] = 1;
+    flag_is_ancilla_to_pick_up = 0;
+    ancilla_arr4[k] = 0;
+    ancilla_K[k] = 0;
+    ancilla_objprio[k] = 0;
+    Ancilla_Sfx3_Pan(k, 0x13);
+  }
+  // endif_1
+  if (!ancilla_item_to_link[k]) {
+    ancilla_z_vel[k] -= 2;
+    Ancilla_MoveY(k);
+    Ancilla_MoveX(k);
+    uint8 old_z = ancilla_z[k];
+    Ancilla_MoveZ(k);
+    if (ancilla_arr4[k] && ancilla_dir[k] == 1 && !sign8(ancilla_z[k]))
+      Ancilla_SetY(k, Ancilla_GetY(k) + (int8)(ancilla_z[k] - old_z));
+    if (!sign8(ancilla_z[k]) || ancilla_z[k] == 0xff)
+      return;
+    ancilla_z[k] = 0;
+    Ancilla_Sfx2_Pan(k, 0x21);
+    if (++ancilla_L[k] != 3) {
+      ancilla_y_vel[k] = (int8)ancilla_y_vel[k] / 2;
+      ancilla_x_vel[k] = (int8)ancilla_x_vel[k] / 2;
+      ancilla_z_vel[k] = 16;
+      ancilla_arr4[k] = 0;
+    } else {
+      ancilla_z[k] = 0;
+      ancilla_L[k] = 0;
+      ancilla_arr4[k] = 0;
+      link_speed_setting = 0;
+      ancilla_y_vel[k] = 0;
+      ancilla_x_vel[k] = 0;
+      ancilla_z_vel[k] = 0;
+      if (ancilla_T[k]) {
+        ancilla_floor[k] = ancilla_T[k];
+        ancilla_T[k] = 0;
+      }
+    }
+  }
+}
+
+void Ancilla_LatchAltitudeAboveLink(int k) {  // 889a4f
+  ancilla_z[k] = 17;
+  Ancilla_SetY(k, Ancilla_GetY(k) + 17);
+  ancilla_objprio[k] = 0;
+}
+
+void Ancilla_LatchLinkCoordinates(int k, int j) {  // 889a6a
+  static const int8 kAncilla_Func3_X[12] = {8, 8, -4, 20, 8, 8, 8, 8, 8, 8, 8, 8};
+  static const int8 kAncilla_Func3_Y[12] = {16, 8, 4, 4, 8, 2, -1, -1, 2, 2, -1, -1};
+  j = j * 4 + (link_direction_facing >> 1);
+  Ancilla_SetXY(k,
+      link_x_coord + kAncilla_Func3_X[j],
+      link_y_coord + kAncilla_Func3_Y[j]);
+}
+
+void Ancilla_LatchCarriedPosition(int k) {  // 889bef
+  static const int8 kAncilla_Func2_Y[6] = {-2, -1, 0, -2, -1, 0};
+  link_speed_setting = 12;
+  ancilla_floor[k] = link_is_on_lower_level;
+  ancilla_floor2[k] = link_is_on_lower_level_mirror;
+  uint16 z = link_z_coord;
+  if (z == 0xffff)
+    z = 0;
+  Ancilla_SetXY(k,
+    link_x_coord + 8,
+    link_y_coord - z + 18 + kAncilla_Func2_Y[link_animation_steps]);
+}
+
+uint16 Ancilla_LatchYCoordToZ(int k) {  // 889c7f
+  uint16 y = Ancilla_GetY(k);
+  int8 z = ancilla_z[k];
+  if (ancilla_dir[k] == 1 && z != -1)
+    Ancilla_SetY(k, y - z);
+  return y;
+}
+
+int Bomb_GetDisplacementFromLink(int k) {  // 889cce
+  int x = Ancilla_GetX(k), y = Ancilla_GetY(k);
+  return ((abs16(link_x_coord + 8 - x) + abs16(link_y_coord + 12 - y)) & 0xfc) >> 2;
+}
+
+void Bomb_Draw(int k) {  // 889e9e
+  Point16U pt;
+  Ancilla_PrepAdjustedOamCoord(k, &pt);
+
+  int z = (int8)ancilla_z[k];
+  if (z != 0 && z != -1 && ancilla_K[k] != 3 && ancilla_objprio[k])
+    oam_priority_value = 0x3000;
+  pt.y -= z;
+  int j = kBomb_Draw_Tab0[ancilla_item_to_link[k]] * 6;
+
+  uint8 r11 = 2;
+  if (ancilla_item_to_link[k] == 0) {
+    r11 = (ancilla_arr3[k] < 0x20) ? ancilla_arr3[k] & 0xe : 4;
+  }
+
+  if (ancilla_item_to_link[k] == 0) {
+    if (ancilla_L[k] == 0 && (sprite_type[0] == 0x92 || k + 1 == flag_is_ancilla_to_pick_up ) && (!(link_state_bits & 0x80) || ancilla_K[k] != 3 && link_direction_facing == 0)) {
+      Ancilla_AllocateOamFromRegion_B_or_E(12);
+    } else if (sort_sprites_setting && ancilla_floor[k] && (ancilla_L[k] || k + 1 == flag_is_ancilla_to_pick_up && (link_state_bits & 0x80))) {
+      oam_cur_ptr = 0x800 + 0x34 * 4;
+      oam_ext_cur_ptr = 0xa20 + 0x34;
+    }
+  }
+
+  OamEnt *oam = GetOamCurPtr(), *oam_org = oam;
+  uint8 numframes = kBomb_Draw_Tab2[ancilla_item_to_link[k]];
+
+  oam += (ancilla_item_to_link[k] == 0 && (ancilla_tile_attr[k] == 9 || ancilla_tile_attr[k] == 0x40)) ? 2 : 0;
+
+  AncillaDraw_Explosion(oam, j, 0, numframes, r11, pt.x, pt.y);
+  oam += numframes;
+
+  uint8 r10;
+  if (!Bomb_CheckUndersideSpriteStatus(k, &pt, &r10)) {
+    if (oam != oam_org + 1)
+      oam = oam_org;
+    AncillaDraw_Shadow(oam, r10, pt.x, pt.y, HIBYTE(oam_priority_value));
+  }
+}
+
+void Ancilla08_DoorDebris(int k) {  // 889fb6
+  DoorDebris_Draw(k);
+  if (sign8(--ancilla_arr26[k])) {
+    ancilla_arr26[k] = 7;
+    if (++ancilla_arr25[k] == 4)
+      ancilla_type[k] = 0;
+  }
+}
+
+void DoorDebris_Draw(int k) {  // 88a091
+  static const uint16 kDoorDebris_XY[64] = {
+     4,  7,  3, 17,  8,  8,  7, 17, 11,  7, 10, 16, 16,  7, 17, 17,
+    20,  7, 21, 17, 16,  8, 17, 17, 13,  7, 14, 16,  8,  7,  7, 17,
+     7,  4, 17,  3,  8,  8, 17,  7,  7, 11, 16, 10,  7, 16, 17, 17,
+     7, 20, 17, 21,  8, 16, 17, 17,  7, 13, 16, 14,  7,  8, 17,  7,
+  };
+  static const uint16 kDoorDebris_CharFlags[32] = {
+    0x205e, 0xe05e, 0xa05e, 0x605e, 0x204f, 0x204f, 0x204f, 0x204f, 0x605e, 0x605e, 0x205e, 0xe05e, 0x604f, 0x604f, 0x604f, 0x604f,
+    0x205e, 0xe05e, 0xa05e, 0x605e, 0x204f, 0xe04f, 0x204f, 0x204f, 0x605e, 0x605e, 0x205e, 0xe05e, 0x604f, 0x604f, 0x604f, 0x604f,
+  };
+  Point16U pt;
+  Ancilla_PrepAdjustedOamCoord(k, &pt);
+  OamEnt *oam = GetOamCurPtr();
+  int y = door_debris_y[k] - BG2VOFS_copy2;
+  int x = door_debris_x[k] - BG2HOFS_copy2;
+  int j = ancilla_arr25[k] + door_debris_direction[k] * 4;
+
+  for (int i = 0; i != 2; i++) {
+    int t = j * 2 + i;
+    //kDoorDebris_XY
+    uint16 d = kDoorDebris_CharFlags[t];
+    Ancilla_SetOam(oam, x + kDoorDebris_XY[t * 2 + 1], y + kDoorDebris_XY[t * 2 + 0],
+                   d, (d >> 8) & 0xc0 | HIBYTE(oam_priority_value), 0);
+    oam = Ancilla_AllocateOamFromCustomRegion(oam + 1);
+  }
+}
+
+void Ancilla09_Arrow(int k) {  // 88a131
+  static const int8 kArrow_Y[4] = {-4, 2, 0, 0};
+  static const int8 kArrow_X[4] = {0, 0, -4, 4};
+  int j;
+
+  if (submodule_index != 0) {
+    Arrow_Draw(k);
+    return;
+  }
+
+  if (!sign8(--ancilla_item_to_link[k])) {
+    if (ancilla_item_to_link[k] >= 4)
+      return;
+  } else {
+    ancilla_item_to_link[k] = 0xff;
+  }
+  Ancilla_MoveY(k);
+  Ancilla_MoveX(k);
+  if (link_item_bow & 4 && !(frame_counter & 1))
+    AncillaAdd_SilverArrowSparkle(k);
+  ancilla_S[k] = 255;
+  if ((j = Ancilla_CheckSpriteCollision(k)) >= 0) {
+    ancilla_x_vel[k] = ancilla_x_lo[k] - sprite_x_lo[j];
+    ancilla_y_vel[k] = ancilla_y_lo[k] - sprite_y_lo[j] + sprite_z[j];
+    ancilla_S[k] = j;
+    if (sprite_type[j] == 0x65) {
+      if (sprite_A[j] == 1) {
+        sound_effect_2 = 0x2d;
+        sprite_delay_aux2[j] = 0x80;
+        sprite_delay_aux4[0] = 128;
+        if (byte_7E0B88 < 9)
+          byte_7E0B88++;
+        sprite_B[j] = byte_7E0B88;
+        sprite_G[j] += 1;
+      } else {
+        sprite_delay_aux3[j] = 4;
+        byte_7E0B88 = 0;
+      }
+    } else {
+      byte_7E0B88 = 0;
+    }
+  } else if ((j = Ancilla_CheckTileCollision(k)) != 0) {
+    ancilla_H[k] = j >> 1;
+    j = ancilla_dir[k] & 3;
+    Ancilla_SetX(k, Ancilla_GetX(k) + kArrow_X[j]);
+    Ancilla_SetY(k, Ancilla_GetY(k) + kArrow_Y[j]);
+    byte_7E0B88 = 0;
+  } else {
+    Arrow_Draw(k);
+    return;
+  }
+  if (sprite_type[j] != 0x1b)
+    Ancilla_Sfx2_Pan(k, 8);
+  ancilla_item_to_link[k] = 0;
+  ancilla_type[k] = 10;
+  ancilla_aux_timer[k] = 1;
+  if (ancilla_H[k]) {
+    ancilla_x_lo[k] += BG1HOFS_copy2 - BG2HOFS_copy2;
+    ancilla_y_lo[k] += BG1VOFS_copy2 - BG2VOFS_copy2;
+  }
+  Arrow_Draw(k);
+}
+
+void Arrow_Draw(int k) {  // 88a36e
+  static const uint8 kArrow_Draw_Char[48] = {
+    0x2b, 0x2a, 0x2a, 0x2b, 0x3d, 0x3a, 0x3a, 0x3d, 0x2b, 0xff, 0x2b, 0xff, 0x3d, 0xff, 0x3d, 0xff,
+    0x3c, 0x2c, 0x3c, 0x2a, 0x3c, 0x2c, 0x3c, 0x2a, 0x2c, 0x3c, 0x2a, 0x3c, 0x2c, 0x3c, 0x2a, 0x3c,
+    0x3b, 0x2d, 0x3b, 0x3a, 0x3b, 0x2d, 0x3b, 0x3a, 0x2d, 0x3b, 0x3a, 0x3b, 0x2d, 0x3b, 0x3a, 0x3b,
+  };
+  static const uint8 kArrow_Draw_Flags[48] = {
+    0xa4, 0xa4, 0x24, 0x24, 0x64, 0x64, 0x24, 0x24, 0xa4, 0xff, 0x24, 0xff, 0x64, 0xff, 0x24, 0xff,
+    0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xe4, 0xa4, 0xa4, 0x24, 0x24, 0x24, 0x24, 0x64, 0x24, 0x24, 0x24,
+    0x64, 0x64, 0x64, 0xe4, 0x64, 0xe4, 0x64, 0xe4, 0x24, 0x24, 0x24, 0xa4, 0xa4, 0x24, 0x24, 0xa4,
+  };
+  static const int8 kArrow_Draw_Y[48] = {
+    0,  8, 0, 8, 0, 0, 0, 0,  0,  0, 0, 0, 0, 0, 0, 0,
+    0,  8, 0, 8, 0, 8, 0, 8,  0,  8, 0, 8, 0, 8, 0, 8,
+    -1, -1, 0, 0, 0, 1, 0, 0, -1, -1, 0, 0, 1, 0, 0, 0,
+  };
+  static const int8 kArrow_Draw_X[48] = {
+    0, 0, 0, 0,  0,  8, 0, 8, 0, 0, 0, 0,  0,  0, 0, 0,
+    1, 1, 0, 0, -1, -2, 0, 0, 1, 1, 0, 0, -2, -1, 0, 0,
+    0, 8, 0, 8,  0,  8, 0, 8, 0, 8, 0, 8,  0,  8, 0, 8,
+  };
+  Point16U pt;
+  Ancilla_PrepAdjustedOamCoord(k, &pt);
+  if (ancilla_objprio[k])
+    HIBYTE(oam_priority_value) = 0x30;
+  uint16 x = pt.x, y = pt.y;
+  if (ancilla_H[k] != 0) {
+    x += BG2VOFS_copy2 - BG1VOFS_copy2;
+    y += BG2HOFS_copy2 - BG1HOFS_copy2;
+  }
+  uint8 r7 = ancilla_item_to_link[k];
+  int j = ancilla_dir[k] & ~4;
+  if (ancilla_type[k] == 0xa) {
+    j = j * 4 + 8 + ((r7 & 8) ? 1 : (r7 & 3));
+  } else if (!sign8(r7)) {
+    j |= 4;
+  }
+
+  j *= 2;
+
+  OamEnt *oam = GetOamCurPtr(), *oam_org = oam;
+  uint8 flags = (link_item_bow & 4) ? 2 : 4;
+  for (int i = 0; i != 2; i++, j++) {
+    if (kArrow_Draw_Char[j] != 0xff) {
+      Ancilla_SetOam(oam, x + kArrow_Draw_X[j], y + kArrow_Draw_Y[j],
+                     kArrow_Draw_Char[j], kArrow_Draw_Flags[j] & ~0x3E | flags | HIBYTE(oam_priority_value), 0);
+      oam++;
+    }
+  }
+
+  if (oam_org[0].y == 0xf0 && oam_org[1].y == 0xf0)
+    ancilla_type[k] = 0;
+}
+
+void Ancilla0A_ArrowInTheWall(int k) {  // 88a45b
+  int j = ancilla_S[k];
+  if (!sign8(j)) {
+    if (sprite_state[j] < 9 || sign8(sprite_z[j]) || sprite_ignore_projectile[j] || sprite_defl_bits[j] & 2) {
+      ancilla_type[k] = 0;
+      return;
+    }
+    Ancilla_SetX(k, Sprite_GetX(j) + (int8)ancilla_x_vel[k]);
+    Ancilla_SetY(k, Sprite_GetY(j) + (int8)ancilla_y_vel[k] - sprite_z[j]);
+  }
+  if (submodule_index == 0 && --ancilla_aux_timer[k] == 0) {
+    ancilla_aux_timer[k] = 2;
+    if (++ancilla_item_to_link[k] == 9) {
+      ancilla_type[k] = 0;
+      return;
+    } else if (ancilla_item_to_link[k] & 8) {
+      ancilla_aux_timer[k] = 0x80;
+    }
+  }
+  Arrow_Draw(k);
+}
+
+void Ancilla0B_IceRodShot(int k) {  // 88a4dd
+  if (submodule_index == 0) {
+    if (sign8(--ancilla_aux_timer[k])) {
+      if (++ancilla_item_to_link[k] & ~1) {
+        ancilla_step[k] = 1;
+        ancilla_item_to_link[k] = ancilla_item_to_link[k] & 7 | 4;
+      }
+      ancilla_aux_timer[k] = 3;
+    }
+    if (ancilla_step[k]) {
+      AncillaOamInfo info;
+      if (Ancilla_ReturnIfOutsideBounds(k, &info))
+        return;
+      Ancilla_MoveY(k);
+      Ancilla_MoveX(k);
+      if (Ancilla_CheckSpriteCollision(k) >= 0 || Ancilla_CheckTileCollision(k)) {
+        ancilla_type[k] = 0x11;
+        ancilla_numspr[k] = kAncilla_Pflags[0x11];
+        ancilla_item_to_link[k] = 0;
+        ancilla_aux_timer[k] = 4;
+      }
+    }
+  }
+  AncillaAdd_IceRodSparkle(k);
+}
+
+void Ancilla11_IceRodWallHit(int k) {  // 88a536
+  if (sign8(--ancilla_aux_timer[k])) {
+    ancilla_aux_timer[k] = 7;
+    if (++ancilla_item_to_link[k] == 2) {
+      ancilla_type[k] = 0;
+      return;
+    }
+  }
+  IceShotSpread_Draw(k);
+}
+
+void IceShotSpread_Draw(int k) {  // 88a571
+  static const uint8 kIceShotSpread_CharFlags[16] = {0xcf, 0x24, 0xcf, 0x24, 0xcf, 0x24, 0xcf, 0x24, 0xdf, 0x24, 0xdf, 0x24, 0xdf, 0x24, 0xdf, 0x24};
+  static const uint8 kIceShotSpread_XY[16] = {0, 0, 0, 8, 8, 0, 8, 8, 0xf8, 0xf8, 0xf8, 0x10, 0x10, 0xf8, 0x10, 0x10};
+
+  Point16U info;
+  Ancilla_PrepOamCoord(k, &info);
+
+  Ancilla_AllocateOamFromRegion_A_or_D_or_F(k, ancilla_numspr[k]);
+  OamEnt *oam = GetOamCurPtr();
+  int j = ancilla_item_to_link[k] * 4;
+  for (int i = 0; i != 4; i++, j++) {
+    uint16 y = info.y + (int8)kIceShotSpread_XY[j * 2 + 0];
+    uint16 x = info.x + (int8)kIceShotSpread_XY[j * 2 + 1];
+    uint8 yv = 0xf0;
+    if (x < 256 && y < 256) {
+      oam->x = x;
+      if (y < 224)
+        yv = y;
+    }
+    oam->y = yv;
+    oam->charnum = kIceShotSpread_CharFlags[j * 2 + 0];
+    oam->flags = kIceShotSpread_CharFlags[j * 2 + 1] & ~0x30 | HIBYTE(oam_priority_value);
+    bytewise_extended_oam[oam - oam_buf] = 0;
+    oam = Ancilla_AllocateOamFromCustomRegion(oam + 1);
+  }
+  oam = GetOamCurPtr();
+  if (oam[0].y == 0xf0 && oam[1].y == 0xf0)
+    ancilla_type[k] = 0;
+}
+
+void Ancilla33_BlastWallExplosion(int k) {  // 88a60e
+  if (submodule_index == 0) {
+    if (blastwall_var5[k]) {
+      if (--blastwall_var6[k] == 0) {
+        if (++blastwall_var5[k] != 0 && blastwall_var5[k] < 9) {
+          AncillaAdd_BlastWallFireball(0x32, 10, k * 4);
+        }
+        if (blastwall_var5[k] == 11) {
+          blastwall_var5[k] = 0;
+          blastwall_var6[k] = 0;
+        } else {
+          blastwall_var6[k] = 3;
+        }
+      }
+    } else if ((k ^= 1), blastwall_var5[k] == 6 && blastwall_var6[k] == 2 && (uint8)(ancilla_item_to_link[0] + 1) < 7) {
+      ancilla_item_to_link[0]++;
+      blastwall_var5[k] = 1;
+      blastwall_var6[k] = 3;
+      for (int i = 3; i >= 0; i--) {
+        int8 arr[2] = { 0, 0 };
+        int j = blastwall_var7 < 4 ? 1 : 0;
+        arr[j] = (i & 2) ? -13 : 13;
+        j = k * 4 + i;
+        blastwall_var10[j] += arr[0];
+        blastwall_var11[j] += arr[1];
+        uint16 x = blastwall_var11[j] - BG2HOFS_copy2;
+        if (x < 256)
+          sound_effect_1 = kBombos_Sfx[x >> 5] | 0xc;
+      }
+    }
+  }
+
+  if (blastwall_var5[ancilla_K[0]]) {
+    int i = (ancilla_K[0] == 1) ? 7 : 3;
+    do {
+      AncillaDraw_BlastWallBlast(ancilla_K[0], blastwall_var11[i], blastwall_var10[i]);
+    } while ((--i & 3) != 3);
+  }
+  if (ancilla_item_to_link[0] == 6) {
+    if (blastwall_var5[0] == 0 && blastwall_var5[1] == 0) {
+      ancilla_type[0] = 0;
+      ancilla_type[1] = 0;
+      flag_custom_spell_anim_active = 0;
+    }
+  }
+}
+
+void AncillaDraw_BlastWallBlast(int k, int x, int y) {  // 88a756
+  oam_priority_value = 0x3000;
+  if (sort_sprites_setting)
+    Oam_AllocateFromRegionD(0x18);
+  else
+    Oam_AllocateFromRegionA(0x18);
+  OamEnt *oam = GetOamCurPtr();
+  int i = blastwall_var5[k];
+  AncillaDraw_Explosion(oam, kBomb_Draw_Tab0[i] * 6, 0, kBomb_Draw_Tab2[i], 0x32,
+      x - BG2HOFS_copy2, y - BG2VOFS_copy2);
+}
+
+OamEnt *AncillaDraw_Explosion(OamEnt *oam, int frame, int idx, int idx_end, uint8 r11, int x, int y) {  // 88a7ab
+  static const int8 kBomb_DrawExplosion_XY[108] = {
+     -8,  -8,   0,   0,   0,   0,   0,   0,   0,   0,   0,  0,  -8,  -8,  -8,  0,
+      0,  -8,   0,   0,   0,   0,   0,   0, -16, -16, -16,  0,   0, -16,   0,  0,
+      0,   0,   0,   0, -16, -16, -16,   0,   0, -16,   0,  0,   0,   0,   0,  0,
+     -8,  -8, -21, -22, -21,   8,   9, -22,   9,   8,   0,  0,  -6, -15,   0, -1,
+    -16,  -2,  -8,  -7,   0,   0,   0,   0,  -9,  -4, -21, -5, -12, -18, -11,  7,
+      0, -15,   4,  -2,  -9,  -4, -22,  -5, -13, -20, -11,  8,   1, -16,   5, -2,
+    -20,   4, -12, -19,  -9,  16,  -5,  -2,   2,  -9,  10,  6,
+  };
+  static const uint8 kBomb_DrawExplosion_CharFlags[108] = {
+    0x6e, 0x26, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x8c, 0x22, 0x8c, 0x62,
+    0x8c, 0xa2, 0x8c, 0xe2, 0xff, 0xff, 0xff, 0xff, 0x84, 0x22, 0x84, 0x62, 0x84, 0xa2, 0x84, 0xe2,
+    0xff, 0xff, 0xff, 0xff, 0x88, 0x22, 0x88, 0x62, 0x88, 0xa2, 0x88, 0xe2, 0xff, 0xff, 0xff, 0xff,
+    0x86, 0x22, 0x88, 0x22, 0x88, 0x62, 0x88, 0xa2, 0x88, 0xe2, 0xff, 0xff, 0x86, 0x22, 0x86, 0x62,
+    0x86, 0xe2, 0x86, 0xe2, 0xff, 0xff, 0xff, 0xff, 0x86, 0xe2, 0x86, 0x22, 0x86, 0x22, 0x86, 0x62,
+    0x86, 0xa2, 0x86, 0xa2, 0x8a, 0xa2, 0x8a, 0x62, 0x8a, 0x22, 0x8a, 0x62, 0x8a, 0x62, 0x8a, 0xe2,
+    0x9b, 0x22, 0x9b, 0xa2, 0x9b, 0x62, 0x9b, 0xe2, 0x9b, 0xa2, 0x9b, 0x22,
+  };
+  static const uint8 kBomb_DrawExplosion_Ext[54] = {
+    2, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 2, 2, 2, 2,
+    1, 1, 2, 2, 2, 2, 1, 1, 2, 2, 2, 2, 2, 1, 2, 2,
+    2, 2, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+    0, 0, 0, 0, 0, 0,
+  };
+  int base_frame = frame;
+  do {
+    if (kBomb_DrawExplosion_CharFlags[frame * 2] != 0xff) {
+      int i = idx + base_frame;
+      Ancilla_SetOam_Safe(oam, x + kBomb_DrawExplosion_XY[i * 2 + 1], y + kBomb_DrawExplosion_XY[i * 2 + 0],
+                          kBomb_DrawExplosion_CharFlags[frame * 2],
+                          kBomb_DrawExplosion_CharFlags[frame * 2 + 1] & ~0x3E | HIBYTE(oam_priority_value) | r11,
+                          kBomb_DrawExplosion_Ext[frame]);
+      oam++;
+    }
+  } while (frame++, ++idx != idx_end);
+  return oam;
+}
+
+void Ancilla15_JumpSplash(int k) {  // 88a80f
+  static const uint8 kAncilla_JumpSplash_Char[2] = {0xac, 0xae};
+
+  if (!submodule_index) {
+    if (sign8(--ancilla_aux_timer[k])) {
+      ancilla_aux_timer[k] = 0;
+      ancilla_item_to_link[k] = 1;
+    }
+    if (ancilla_item_to_link[k]) {
+      ancilla_x_vel[k] = ancilla_y_vel[k] = ancilla_y_vel[k] - 4;
+      if (ancilla_y_vel[k] < 232) {
+        ancilla_type[k] = 0;
+        if ((link_is_bunny_mirror || link_player_handler_state == kPlayerState_Swimming) && link_is_in_deep_water)
+          CheckAbilityToSwim();
+        return;
+      }
+      Ancilla_MoveX(k);
+      Ancilla_MoveY(k);
+    }
+  }
+  Point16U pt;
+  Ancilla_PrepOamCoord(k, &pt);
+  OamEnt *oam = GetOamCurPtr();
+  int ax = Ancilla_GetX(k);
+  int x8 = link_x_coord * 2 - ax - BG2HOFS_copy2;
+  int x6 = ax + 12 - BG2HOFS_copy2;
+  int j = ancilla_item_to_link[k];
+  uint8 flags = 0;
+  for (int i = 0; i < 2; i++) {
+    Ancilla_SetOam(oam, pt.x, pt.y, kAncilla_JumpSplash_Char[j], 0x24 | flags, 2);
+    oam = Ancilla_AllocateOamFromCustomRegion(oam + 1);
+    pt.x = x8;
+    flags = 0x40;
+  }
+  Ancilla_SetOam(oam, x6, pt.y, 0xc0, 0x24, ((j == 1) ? 1 : 2));
+}
+
+void Ancilla16_HitStars(int k) {  // 88a8e5
+  static const uint8 kAncilla_HitStars_Char[2] = {0x90, 0x91};
+
+  if (!sign8(--ancilla_arr3[k]))
+    return;
+
+  ancilla_arr3[k] = 0;
+  if (!submodule_index) {
+    if (sign8(--ancilla_aux_timer[k])) {
+      ancilla_aux_timer[k] = 0;
+      ancilla_item_to_link[k] = 1;
+    }
+    if (ancilla_item_to_link[k]) {
+      ancilla_x_vel[k] = (ancilla_y_vel[k] -= 4);
+      if (ancilla_y_vel[k] < 232) {
+        ancilla_type[k] = 0;
+        return;
+      }
+      Ancilla_MoveY(k);
+      Ancilla_MoveX(k);
+    }
+  }
+  Point16U info;
+  Ancilla_PrepOamCoord(k, &info);
+
+  uint16 ax = Ancilla_GetX(k);
+  uint16 tt = ancilla_B[k] << 8 | ancilla_A[k];
+
+  uint16 r8 = 2 * tt - ax - 8 - BG2HOFS_copy2;
+
+  if (ancilla_step[k] == 2)
+    Ancilla_AllocateOamFromRegion_B_or_E(8);
+
+  OamEnt *oam = GetOamCurPtr();
+  uint16 x = info.x, y = info.y;
+  uint8 flags = 0;
+  for (int i = 1; i >= 0; i--) {
+    Ancilla_SetOam(oam, x, y,
+                   kAncilla_HitStars_Char[ancilla_item_to_link[k]],
+                   HIBYTE(oam_priority_value) | 4 | flags, 0);
+    flags = 0x40;
+    BYTE(x) = r8;
+    oam = HitStars_UpdateOamBufferPosition(oam + 1);
+  }
+}
+
+void Ancilla17_ShovelDirt(int k) {  // 88a9a9
+  static const int8 kShovelDirt_XY[8] = {18, -13, -9, 4, 18, 13, -9, -11};
+  static const int8 kShovelDirt_Char[2] = {0x40, 0x50};
+  Point16U pt;
+  Ancilla_PrepOamCoord(k, &pt);
+  OamEnt *oam = GetOamCurPtr();
+  if (!ancilla_timer[k]) {
+    ancilla_timer[k] = 8;
+    if (++ancilla_item_to_link[k] == 2) {
+      ancilla_type[k] = 0;
+      return;
+    }
+  }
+  int b = ancilla_item_to_link[k];
+  int j = b + ((link_direction_facing == 4) ? 0 : 2);
+  pt.x += kShovelDirt_XY[j * 2 + 1];
+  pt.y += kShovelDirt_XY[j * 2 + 0];
+  for (int i = 0; i < 2; i++) {
+    Ancilla_SetOam(oam, pt.x + i * 8, pt.y, kShovelDirt_Char[b] + i, 4 | HIBYTE(oam_priority_value), 0);
+    oam = Ancilla_AllocateOamFromCustomRegion(oam + 1);
+  }
+}
+
+void Ancilla32_BlastWallFireball(int k) {  // 88aa35
+  static const uint8 kBlastWallFireball_Char[3] = {0x9d, 0x9c, 0x8d};
+
+  if (!submodule_index) {
+    ancilla_item_to_link[k] += 2;
+    ancilla_y_vel[k] += ancilla_item_to_link[k];
+    Ancilla_MoveY(k);
+    Ancilla_MoveX(k);
+    if (sign8(--blastwall_var12[k])) {
+      ancilla_type[k] = 0;
+      return;
+    }
+  }
+
+  if (sort_sprites_setting)
+    Oam_AllocateFromRegionD(4);
+  else
+    Oam_AllocateFromRegionA(4);
+
+  Point16U pt;
+  Ancilla_PrepOamCoord(k, &pt);
+  Ancilla_SetOam(GetOamCurPtr(), pt.x, pt.y, kBlastWallFireball_Char[blastwall_var12[k] & 8 ? 0 : blastwall_var12[k] & 4 ? 1 : 2], 0x22, 0);
+}
+
+void Ancilla18_EtherSpell(int k) {  // 88aaa0
+  if (submodule_index)
+    return;
+
+  if (ancilla_step[k] != 0) {
+    uint8 flag;
+
+    if (step_counter_for_spin_attack == 0) {
+      flag = (++ancilla_arr4[k] & 4) == 0;
+    } else {
+      flag = step_counter_for_spin_attack == 11;
+    }
+    if (flag) {
+      Palette_ElectroThemedGear();
+      Filter_Majorly_Whiten_Bg();
+    } else {
+      LoadActualGearPalettes();
+      Palette_Restore_BG_From_Flash();
+    }
+  }
+
+  if (ancilla_step[k] == 2) {
+    if (sign8(--ancilla_aux_timer[k])) {
+      ancilla_aux_timer[k] = 2;
+      if (++ancilla_item_to_link[k] == 2) {
+        ancilla_item_to_link[k]--;
+        ancilla_x_vel[k] = 16;
+        ancilla_step[k] = 3;
+      }
+    }
+    ancilla_x_vel[k] += 1;
+    EtherSpell_HandleRadialSpin(k);
+    return;
+  } else {
+    if (sign8(--ancilla_aux_timer[k])) {
+      ancilla_aux_timer[k] = 2;
+      ancilla_item_to_link[k] ^= 1;
+    }
+    if (ancilla_step[k] == 0) {
+      EtherSpell_HandleLightningStroke(k);
+    } else if (ancilla_step[k] == 1) {
+      EtherSpell_HandleOrbPulse(k);
+    } else if (ancilla_step[k] == 3) {
+      EtherSpell_HandleRadialSpin(k);
+    } else if (ancilla_step[k] == 4) {
+      if (!--ether_var1)
+        ancilla_step[k] = 5;
+      EtherSpell_HandleRadialSpin(k);
+    } else {
+      uint8 vel = ancilla_x_vel[k] + 0x10;
+      if (sign8(vel)) vel = 0x7f;
+      ancilla_x_vel[k] = vel;
+      EtherSpell_HandleRadialSpin(k);
+    }
+  }
+}
+
+void EtherSpell_HandleLightningStroke(int k) {  // 88ab63
+  Ancilla_MoveY(k);
+  uint16 y = Ancilla_GetY(k);
+
+  if (BYTE(ether_y_adjusted) != (y & 0xf0)) {
+    BYTE(ether_y_adjusted) = y & 0xf0;
+    ancilla_arr25[k]++;
+  }
+  if (y < 0xe000 && ether_y2 < 0xe000 && ether_y2 <= y) {
+    ancilla_step[k] = 1;
+  }
+  AncillaDraw_EtherBlitz(k);
+}
+
+void EtherSpell_HandleOrbPulse(int k) {  // 88aba7
+  if (!sign8(ancilla_arr25[k])) {
+    if (!sign8(--ancilla_arr3[k])) {
+      AncillaDraw_EtherBlitz(k);
+      return;
+    }
+    ancilla_arr3[k] = 3;
+    if (!sign8(--ancilla_arr25[k])) {
+      AncillaDraw_EtherBlitz(k);
+      return;
+    }
+    ancilla_arr3[k] = 9;
+  }
+  if (sign8(--ancilla_arr3[k])) {
+    ancilla_step[k] = 2;
+    ancilla_y_vel[k] = 0;
+    ancilla_x_vel[k] = 16;
+    ancilla_item_to_link[k] = 0;
+    ancilla_aux_timer[k] = 2;
+    if (step_counter_for_spin_attack)
+      Medallion_CheckSpriteDamage(k);
+  }
+  AncillaDraw_EtherOrb(k, GetOamCurPtr());
+}
+
+void EtherSpell_HandleRadialSpin(int k) {  // 88abef
+  if (ancilla_step[k] == 4) {
+    if ((frame_counter & 7) == 0)
+      sound_effect_2 = 0x2a;
+    else if ((frame_counter & 7) == 4)
+      sound_effect_2 = 0xaa;
+    else if ((frame_counter & 7) == 7)
+      sound_effect_2 = 0x6a;
+  } else {
+    ancilla_x_lo[k] = ether_var2;
+    ancilla_x_hi[k] = 0;
+    Ancilla_MoveX(k);
+    ether_var2 = ancilla_x_lo[k];
+    if (ether_var2 == 0x40)
+      ancilla_step[k] = 4;
+  }
+
+  uint8 sb = ancilla_step[k];
+  uint8 sa = ancilla_item_to_link[k];
+  OamEnt *oam = GetOamCurPtr();
+  for (int i = 7; i >= 0; i--) {
+    if (sb != 2 && sb != 5) {
+      ether_arr1[i] = (ether_arr1[i] + 1) & 0x3f;
+    }
+    AncillaRadialProjection arp = Ancilla_GetRadialProjection(ether_arr1[i], ether_var2);
+    if (sb != 2)
+      oam = AncillaDraw_EtherBlitzBall(oam, &arp, sa);
+    else
+      oam = AncillaDraw_EtherBlitzSegment(oam, &arp, sa, i);
+  }
+  if (ether_var2 < 0xf0) {
+    OamEnt *oam = GetOamCurPtr();
+    for (int i = 0; i != 8; i++) {
+      if (oam[i].y != 0xf0)
+        return;
+    }
+  }
+  ancilla_type[k] = 0;
+  load_chr_halfslot_even_odd = 1;
+  byte_7E0324 = 0;
+  state_for_spin_attack = 0;
+  step_counter_for_spin_attack = 0;
+  link_cant_change_direction = 0;
+  flag_unk1 = 0;
+
+  if (BYTE(overworld_screen_index) == 0x70 && !(save_ow_event_info[0x70] & 0x20) && Ancilla_CheckForEntranceTrigger(2)) {
+    trigger_special_entrance = 3;
+    subsubmodule_index = 0;
+    BYTE(R16) = 0;
+  }
+
+  if (link_player_handler_state != kPlayerState_ReceivingEther) {
+    link_player_handler_state = kPlayerState_Ground;
+    link_delay_timer_spin_attack = 0;
+    button_mask_b_y = button_b_frames ? (joypad1H_last & 0x80) : 0;
+  }
+  link_speed_setting = 0;
+  byte_7E0325 = 0;
+  LoadActualGearPalettes();
+  Palette_Restore_BG_And_HUD();
+}
+
+OamEnt *AncillaDraw_EtherBlitzBall(OamEnt *oam, const AncillaRadialProjection *arp, int s) {  // 88aced
+  static const uint8 kEther_BlitzBall_Char[2] = {0x68, 0x6a};
+  int x = (arp->r6 ? -arp->r4 : arp->r4) + ether_x2 - 8 - BG2HOFS_copy2;
+  int y = (arp->r2 ? -arp->r0 : arp->r0) + ether_y3 - 8 - BG2VOFS_copy2;
+  Ancilla_SetOam(oam, x, y, kEther_BlitzBall_Char[s], 0x3c, 2);
+  return Ancilla_AllocateOamFromCustomRegion(oam + 1);
+}
+
+OamEnt *AncillaDraw_EtherBlitzSegment(OamEnt *oam, const AncillaRadialProjection *arp, int s, int k) {  // 88adc9
+  static const int8 kEther_SpllittingBlitzSegment_X[16] = {-8, -16, -24, -16, -8, 0, 8, -16, -8, -16, -24, -16, -8, 0, 8, 0};
+  static const int8 kEther_SpllittingBlitzSegment_Y[16] = {8, 0, -8, -16, -24, -16, -8, -16, 8, 0, -8, -16, -24, -16, -8, 0};
+  static const uint8 kEther_SpllittingBlitzSegment_Char[32] = {
+    0x40, 0x42, 0x66, 0x64, 0x62, 0x60, 0x64, 0x66, 0x42, 0x40, 0x66, 0x64, 0x60, 0x62, 0x64, 0x66,
+    0x68, 0x42, 0x68, 0x64, 0x68, 0x60, 0x68, 0x64, 0x68, 0x40, 0x68, 0x66, 0x68, 0x62, 0x68, 0x64,
+  };
+  static const uint8 kEther_SpllittingBlitzSegment_Flags[32] = {
+    0x3c, 0x3c, 0xfc, 0xfc, 0x3c, 0x3c, 0xbc, 0xbc, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x7c, 0x7c,
+    0x3c, 0x7c, 0x3c, 0x3c, 0x3c, 0xbc, 0x3c, 0x7c, 0x3c, 0x7c, 0x3c, 0xfc, 0x3c, 0xbc, 0x3c, 0xbc,
+  };
+  int x = (arp->r6 ? -arp->r4 : arp->r4);
+  int y = (arp->r2 ? -arp->r0 : arp->r0);
+  int t = s * 8 + k;
+  Ancilla_SetOam(oam, x + ether_x2 - 8 - BG2HOFS_copy2, y + ether_y3 - 8 - BG2VOFS_copy2,
+                 kEther_SpllittingBlitzSegment_Char[t * 2], kEther_SpllittingBlitzSegment_Flags[t * 2], 2);
+  Ancilla_SetOam(oam + 1,
+      x + ether_x2 + kEther_SpllittingBlitzSegment_X[t] - BG2HOFS_copy2,
+      y + ether_y3 + kEther_SpllittingBlitzSegment_Y[t] - BG2VOFS_copy2,
+      kEther_SpllittingBlitzSegment_Char[t * 2 + 1],
+      kEther_SpllittingBlitzSegment_Flags[t * 2 + 1], 2);
+  return Ancilla_AllocateOamFromCustomRegion(oam + 2);
+}
+
+void AncillaDraw_EtherBlitz(int k) {  // 88ae87
+  Point16U info;
+  Ancilla_PrepOamCoord(k, &info);
+  OamEnt *oam = GetOamCurPtr();
+  int t = ancilla_item_to_link[k];
+  int i = ancilla_arr25[k];
+  int m = 0;
+  do {
+    Ancilla_SetOam(oam, info.x, info.y,
+                   kEther_BlitzSegment_Char[t * 2 + m],
+                   kEther_BlitzOrb_Flags[0] | HIBYTE(oam_priority_value), 2);
+    info.y -= 16;
+    oam++;
+    m ^= 1;
+  } while (--i >= 0);
+  if (ancilla_step[k] == 1)
+    AncillaDraw_EtherOrb(k, oam);
+}
+
+void AncillaDraw_EtherOrb(int k, OamEnt *oam) {  // 88aedd
+  uint16 y = ether_y - 1 - BG2VOFS_copy2;
+  uint16 x = ether_x - 8 - BG2HOFS_copy2;
+  int t = ancilla_item_to_link[k] * 4;
+
+  for (int i = 0; i < 4; i++) {
+    Ancilla_SetOam(oam, x, y, kEther_BlitzOrb_Char[t + i], kEther_BlitzOrb_Flags[t + i], 2);
+    oam++;
+    oam = Ancilla_AllocateOamFromCustomRegion(oam);
+    x += 16;
+    if (i == 1)
+      x -= 32, y += 16;
+  }
+}
+
+void AncillaAdd_BombosSpell(uint8 a, uint8 y) {  // 88af66
+  int k = AncillaAdd_AddAncilla_Bank08(a, y);
+  if (k < 0)
+    return;
+  for (int i = 0; i < 10; i++) {
+    bombos_arr2[i] = 0;
+    bombos_arr1[i] = 3;
+  }
+  for (int i = 0; i < 8; i++) {
+    bombos_arr3[i] = 0;
+    bombos_arr4[i] = 3;
+  }
+  bombos_var4 = 0;
+  bombos_var2 = 0;
+  bombos_var3 = 0x80;
+  bombos_arr7[0] = 0x10;
+  load_chr_halfslot_even_odd = 11;
+  flag_custom_spell_anim_active = 1;
+  ancilla_step[k] = 0;
+  ancilla_item_to_link[k] = 0;
+  Ancilla_Sfx2_Near(0x2a);
+
+  uint8 t = kGeneratedBombosArr[frame_counter];
+  t = (t < 0xe0) ? t : t & 0x7f;
+  bombos_x_coord[0] = link_x_coord & ~0xff | t;
+  bombos_y_coord[0] = link_y_coord & ~0xff | t;
+
+  static const int16 kBombos_YDelta[4] = {16, 24, -128, -16};
+  static const int16 kBombos_XDelta[4] = {-16, -128, 0, 128};
+
+  for (int i = 0; i < 1 ; i++) {
+    bombos_x_coord2[i] = link_x_coord + kBombos_XDelta[i];
+    bombos_y_coord2[i] = link_y_coord + kBombos_YDelta[i];
+    bombos_var1 = 16;
+    AncillaRadialProjection arp = Ancilla_GetRadialProjection(bombos_arr7[i], 16);
+    int x = (arp.r6 ? -arp.r4 : arp.r4) + bombos_x_coord2[i];
+    int y = (arp.r2 ? -arp.r0 : arp.r0) + bombos_y_coord2[i];
+    bombos_x_lo[i] = (uint8)x;
+    bombos_x_hi[i] = x >> 8;
+    bombos_y_lo[i] = (uint8)y;
+    bombos_y_hi[i] = y >> 8;
+  }
+}
+
+void Ancilla19_BombosSpell(int k) {  // 88b0ce
+  if (bombos_var4 == 0) {
+    if (submodule_index == 0) {
+      BombosSpell_ControlFireColumns(k);
+      return;
+    }
+    for (int i = 9; i >= 0; i--)
+      AncillaDraw_BombosFireColumn(i);
+  } else if (bombos_var4 != 2) {
+    if (submodule_index == 0) {
+      BombosSpell_FinishFireColumns(k);
+      return;
+    }
+    for (int i = 9; i >= 0; i--)
+      AncillaDraw_BombosFireColumn(i);
+  } else {
+    if (submodule_index == 0) {
+      BombosSpell_ControlBlasting(k);
+      return;
+    }
+    int i = ancilla_step[k];
+    do {
+      AncillaDraw_BombosBlast(i);
+    } while (--i >= 0);
+  }
+}
+
+void BombosSpell_ControlFireColumns(int k) {  // 88b10a
+  uint8 sa = ancilla_item_to_link[k];
+  uint8 sb = ancilla_step[k];
+
+  int j, i = sb;
+  do {
+    if (bombos_arr2[i] == 13)
+      continue;
+
+    if (sign8(--bombos_arr1[i])) {
+      bombos_arr1[i] = 3;
+      if (++bombos_arr2[i] == 13)
+        continue;
+
+      if (bombos_arr2[i] == 2) {
+        if (sa)
+          continue;
+
+        // pushed x
+        if (sb == 9) {
+          for (j = 9; j >= 0; j--) {
+            if (bombos_arr2[j] == 13) {
+              bombos_arr2[j] = 0;
+              goto exit_loop;
+            }
+          }
+        }
+        sb = j = (sb + 1) != 10 ? sb + 1 : 9;
+exit_loop:
+        bombos_var1 = (bombos_var1 + 3 >= 207) ? 207 : bombos_var1 + 3;
+        bombos_arr7[0] += 6;
+        AncillaRadialProjection arp = Ancilla_GetRadialProjection(bombos_arr7[0] & 0x3f, bombos_var1);
+        int x = (arp.r6 ? -arp.r4 : arp.r4) + bombos_x_coord2[0];
+        int y = (arp.r2 ? -arp.r0 : arp.r0) + bombos_y_coord2[0];
+        bombos_x_lo[j] = (uint8)x;
+        bombos_x_hi[j] = x >> 8;
+        bombos_y_lo[j] = (uint8)y;
+        bombos_y_hi[j] = y >> 8;
+
+        uint16 t = x - BG2HOFS_copy2 + 8;
+        if (t < 256)
+          sound_effect_1 = kBombos_Sfx[t >> 5] | 0x2a;
+      }
+    }
+    AncillaDraw_BombosFireColumn(i);
+
+  } while (--i >= 0);
+  if (bombos_arr7[0] >= 0x80)
+    bombos_var4 = 1;
+  ancilla_step[k] = sb;
+}
+
+void BombosSpell_FinishFireColumns(int kk) {  // 88b236
+  int k = ancilla_step[kk];
+  do {
+    if (sign8(--bombos_arr1[k])) {
+      bombos_arr1[k] = 3;
+      if (++bombos_arr2[k] >= 13)
+        bombos_arr2[k] = 13;
+    }
+    AncillaDraw_BombosFireColumn(k);
+  } while (--k >= 0);
+  for (int k = 9; k >= 0; k--) {
+    if (bombos_arr2[k] != 13)
+      return;
+  }
+  bombos_var4 = 2;
+  Medallion_CheckSpriteDamage(kk);
+  ancilla_step[kk] = 0;
+}
+
+void AncillaDraw_BombosFireColumn(int kk) {  // 88b373
+  static const int8 kBombosSpell_FireColumn_X[39] = {
+     0, -1, -1,  0, 0, -1,  0, 0, -1, 0, 0, -1, 0, 0, -1, 0,
+     0,  0,  0,  0, 0,  0,  0, 0,  0, 0, 0,  0, 0, 0,  0, 0,
+    -1,  1, -1, -1, 2, -1, -1,
+  };
+  static const int8 kBombosSpell_FireColumn_Y[39] = {
+     0,  -1, -1,  0,  -4, -1,   0,  -8, -1,   0, -12, -1,   0, -16,  -1,   0,
+    -4, -20,  0, -8, -24,  0, -12, -28,  0, -16, -32,  0, -16, -32, -18, -34,
+    -1, -35, -1, -1, -36, -1,  -1,
+  };
+  static const uint8 kBombosSpell_FireColumn_Flags[39] = {
+    0x3c, 0xff, 0xff, 0x3c, 0x3c, 0xff, 0x3c, 0x3c, 0xff, 0x7c, 0x7c, 0xff, 0x3c, 0x7c, 0xff, 0x3c,
+    0x3c, 0x3c, 0xbc, 0x3c, 0x3c, 0x7c, 0x3c, 0x3c, 0x3c, 0x3c, 0x7c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c,
+    0xff, 0x3c, 0xff, 0xff, 0x3c, 0xff, 0xff,
+  };
+  static const uint8 kBombosSpell_FireColumn_Char[39] = {
+    0x40, 0xff, 0xff, 0x42, 0x44, 0xff, 0x42, 0x44, 0xff, 0x42, 0x44, 0xff, 0x42, 0x44, 0xff, 0x40,
+    0x46, 0x44, 0x4a, 0x4a, 0x48, 0x4c, 0x4c, 0x4a, 0x4e, 0x4c, 0x4a, 0x4e, 0x6a, 0x4c, 0x4e, 0x68,
+    0xff, 0x6a, 0xff, 0xff, 0x4e, 0xff, 0xff,
+  };
+  Ancilla_AllocateOamFromRegion_A_or_D_or_F(kk, 0x10);
+  OamEnt *oam = GetOamCurPtr();
+  for (int i = 0; i < 1; i++) {
+    int k = bombos_arr2[kk];
+    if (k == 13)
+      continue;
+    k = k * 3 + 2;
+    for (int j = 0; j < 3; j++, k--) {
+      if (kBombosSpell_FireColumn_Char[k] != 0xff) {
+        uint16 x = bombos_x_lo[kk] | bombos_x_hi[kk] << 8;
+        uint16 y = bombos_y_lo[kk] | bombos_y_hi[kk] << 8;
+        y += kBombosSpell_FireColumn_Y[k] - BG2VOFS_copy2;
+        x += kBombosSpell_FireColumn_X[k] - BG2HOFS_copy2;
+        Ancilla_SetOam(oam, x, y,
+                       kBombosSpell_FireColumn_Char[k],
+                       kBombosSpell_FireColumn_Flags[k], 2);
+        oam++;
+      }
+      oam = Ancilla_AllocateOamFromCustomRegion(oam);
+    }
+  }
+}
+
+void BombosSpell_ControlBlasting(int kk) {  // 88b40d
+  int k = ancilla_step[kk], sb = k;
+  for (; k >= 0; k--) {
+    if (bombos_arr3[k] != 8 && sign8(--bombos_arr4[k])) {
+      bombos_arr4[k] = 3;
+      if (++bombos_arr3[k] == 1 && !bombos_var2) {
+        int j = sb;
+        if (j != 15) {
+          j = ++sb;
+        } else {
+          for (; j >= 0 && bombos_arr3[j] != 8; j--) {}
+        }
+        bombos_arr3[j] = 0;
+        bombos_arr4[j] = 3;
+
+        uint16 y = kBombosBlasts_Tab[frame_counter & 0x3f];
+        uint16 x = kBombosBlasts_Tab[(frame_counter & 0x3f) + 3];
+        bombos_y_coord[j] = y + BG2VOFS_copy2;
+        bombos_x_coord[j] = x + BG2HOFS_copy2;
+
+        sound_effect_1 = 0xc | kBombos_Sfx[bombos_x_coord[j] >> 5 & 7];
+      }
+    }
+    AncillaDraw_BombosBlast(k);
+  }
+
+  for (int j = 15; j >= 0; j--) {
+    if (bombos_arr3[j] != 8) {
+      ancilla_step[kk] = sb;
+      goto getout;
+    }
+  }
+  ancilla_type[kk] = 0;
+  load_chr_halfslot_even_odd = 1;
+  byte_7E0324 = 0;
+  state_for_spin_attack = 0;
+  step_counter_for_spin_attack = 0;
+  link_cant_change_direction = 0;
+  flag_unk1 = 0;
+  if (link_player_handler_state != kPlayerState_ReceivingBombos) {
+    link_player_handler_state = kPlayerState_Ground;
+    link_delay_timer_spin_attack = 0;
+    button_mask_b_y = button_b_frames ? (joypad1H_last & 0x80) : 0;
+  }
+  link_speed_setting = 0;
+  byte_7E0325 = 0;
+getout:
+  if (--bombos_var3 == 0)
+    bombos_var2 = bombos_var3 = 1;
+}
+
+void AncillaDraw_BombosBlast(int k) {  // 88b5e1
+  static const int8 kBombosSpell_DrawBlast_X[32] = {
+     -8, -1,  -1, -1, -12, -4, -12, -4, -16, 0, -16, 0, -16, 0, -16, 0,
+    -17,  1, -17,  1, -19,  3, -19,  3, -19, 3, -19, 3, -19, 3, -19, 3,
+  };
+  static const int8 kBombosSpell_DrawBlast_Y[32] = {
+     -8,  -1, -1, -1, -12, -12, -4, -4, -16, -16, 0, 0, -16, -16, 0, 0,
+    -17, -17,  1,  1, -19, -19,  3,  3, -19, -19, 3, 3, -19, -19, 3, 3,
+  };
+  static const uint8 kBombosSpell_DrawBlast_Flags[32] = {
+    0x3c, 0xff, 0xff, 0xff, 0x3c, 0x7c, 0xbc, 0xfc, 0x3c, 0x7c, 0xbc, 0xfc, 0x3c, 0x7c, 0xbc, 0xfc,
+    0x3c, 0x7c, 0xbc, 0xfc, 0x3c, 0x7c, 0xbc, 0xfc, 0x3c, 0x7c, 0xbc, 0xfc, 0x3c, 0x7c, 0xbc, 0xfc,
+  };
+  static const uint8 kBombosSpell_DrawBlast_Char[32] = {
+    0x60, 0xff, 0xff, 0xff, 0x62, 0x62, 0x62, 0x62, 0x64, 0x64, 0x64, 0x64, 0x66, 0x66, 0x66, 0x66,
+    0x68, 0x68, 0x68, 0x68, 0x68, 0x68, 0x68, 0x68, 0x6a, 0x6a, 0x6a, 0x6a, 0x4e, 0x4e, 0x4e, 0x4e,
+  };
+  uint16 x = bombos_x_coord[k];
+  uint16 y = bombos_y_coord[k];
+  if (bombos_arr3[k] == 8)
+    return;
+
+  Ancilla_AllocateOamFromRegion_A_or_D_or_F(k, 0x10);
+  OamEnt *oam = GetOamCurPtr();
+
+  int t = bombos_arr3[k] * 4 + 3;
+  for (int j = 0; j < 4; j++, t--) {
+    if (kBombosSpell_DrawBlast_Char[t] != 0xff) {
+      Ancilla_SetOam(oam,
+        x + kBombosSpell_DrawBlast_X[t] - BG2HOFS_copy2,
+        y + kBombosSpell_DrawBlast_Y[t] - BG2VOFS_copy2,
+        kBombosSpell_DrawBlast_Char[t],
+        kBombosSpell_DrawBlast_Flags[t], 2);
+      oam++;
+    }
+    oam = Ancilla_AllocateOamFromCustomRegion(oam);
+  }
+
+}
+
+void Ancilla1C_QuakeSpell(int k) {  // 88b66a
+  if (submodule_index != 0) {
+    if (quake_arr2[4] != kQuake_Tab1[4])
+      AncillaDraw_QuakeInitialBolts(k);
+    return;
+  }
+  if (ancilla_step[k] != 2) {
+    QuakeSpell_ShakeScreen(k);
+    QuakeSpell_ControlBolts(k);
+    QuakeSpell_SpreadBolts(k);
+    return;
+  }
+  Medallion_CheckSpriteDamage(k);
+  Prepare_ApplyRumbleToSprites();
+  ancilla_type[k] = 0;
+  link_player_handler_state = 0;
+  load_chr_halfslot_even_odd = 1;
+  byte_7E0324 = 0;
+  state_for_spin_attack = 0;
+  step_counter_for_spin_attack = 0;
+  link_cant_change_direction = 0;
+  link_delay_timer_spin_attack = 0;
+  flag_unk1 = 0;
+  bg1_x_offset = 0;
+  bg1_y_offset = 0;
+  if (BYTE(overworld_screen_index) == 0x47 && !(save_ow_event_info[0x47] & 0x20) && Ancilla_CheckForEntranceTrigger(3)) {
+    trigger_special_entrance = 4;
+    subsubmodule_index = 0;
+    BYTE(R16) = 0;
+  }
+  button_mask_b_y = button_b_frames ? (joypad1H_last & 0x80) : 0;
+  link_speed_setting = 0;
+  byte_7E0325 = 0;
+}
+
+void QuakeSpell_ShakeScreen(int k) {  // 88b6f7
+  bg1_y_offset = quake_var3;
+  quake_var3 = -quake_var3;
+  link_y_vel += bg1_y_offset;
+}
+
+void QuakeSpell_ControlBolts(int k) {  // 88b718
+  quake_var4 = ancilla_step[k];
+  int j = quake_var5;
+  do {
+    if (quake_arr2[j] == kQuake_Tab1[j])
+      continue;
+
+    if (sign8(--quake_arr1[j])) {
+      quake_arr1[j] = 1;
+      if (++quake_arr2[j] == kQuake_Tab1[j])
+        continue;
+
+      if (j == 0 && quake_arr2[j] == 2) {
+        Ancilla_Sfx2_Near(0xc);
+        quake_var5 = 1;
+      } else if (j == 1 && quake_arr2[j] == 2) {
+        quake_var5 = 4;
+      } else if (j == 4 && quake_arr2[j] == 7) {
+        quake_var4 = 1;
+      }
+    }
+    AncillaDraw_QuakeInitialBolts(j);
+  } while (--j >= 0);
+  ancilla_step[k] = quake_var4;
+}
+
+void AncillaDraw_QuakeInitialBolts(int k) {  // 88b793
+  static const uint8 kQuakeDrawGroundBolts_Tab[5] = {0, 0x18, 0, 0x18, 0x2f};
+
+  int t = quake_arr2[k] + kQuakeDrawGroundBolts_Tab[k];
+  OamEnt *oam = GetOamCurPtr();
+  int idx = kQuakeItemPos[t], num = kQuakeItemPos[t + 1] - idx;
+  const QuakeItem *p = &kQuakeItems[idx], *pend = p + num;
+  do {
+    uint16 x = p->x + quake_var2 - BG2HOFS_copy2;
+    uint16 y = p->y + quake_var1 - BG2VOFS_copy2;
+
+    uint8 xval = oam->x, yval = 0xf0;
+    if (x < 256 && y < 256) {
+      xval = x;
+      if (y < 0xf0)
+        yval = y;
+    }
+    SetOamPlain(oam, xval, yval, kQuakeDrawGroundBolts_Char[p->f & 0x0f], p->f & 0xc0 | 0x3c, 2);
+    oam++, oam_cur_ptr += 4, oam_ext_cur_ptr += 1;
+  } while (++p != pend);
+}
+
+void QuakeSpell_SpreadBolts(int k) {  // 88b84f
+  if (ancilla_step[k] != 1)
+    return;
+  if (ancilla_timer[k] == 0) {
+    ancilla_timer[k] = 2;
+    if (++ancilla_item_to_link[k] == 55) {
+      ancilla_step[k] = 2;
+      return;
+    }
+  }
+  int t = ancilla_item_to_link[k];
+  int idx = kQuakeItemPos2[t], num = kQuakeItemPos2[t + 1] - idx;
+  const QuakeItem *p = &kQuakeItems2[idx], *pend = p + num;
+  OamEnt *oam = GetOamCurPtr();
+  do {
+    SetOamPlain(oam, p->x, p->y, kQuakeDrawGroundBolts_Char[p->f & 0x0f], p->f & 0xc0 | 0x3c, p->f >> 4 & 3);
+    oam_cur_ptr += 4, oam_ext_cur_ptr += 1;
+    oam = Ancilla_AllocateOamFromCustomRegion(oam + 1);
+  } while (++p != pend);
+}
+
+void Ancilla1A_PowderDust(int k) {  // 88bab0
+  if (submodule_index == 0) {
+    Powder_ApplyDamageToSprites(k);
+    if (sign8(--ancilla_aux_timer[k])) {
+      ancilla_aux_timer[k] = 1;
+      int j = ancilla_dir[k];
+      if (ancilla_item_to_link[k] == 9) {
+        ancilla_type[k] = 0;
+        byte_7E0333 = 0;
+        return;
+      }
+      ancilla_arr25[k] = kMagicPowder_Tab0[++ancilla_item_to_link[k] + j * 10];
+    }
+  }
+  Ancilla_AllocateOamFromRegion_B_or_E(ancilla_numspr[k]);
+  Ancilla_MagicPowder_Draw(k);
+}
+
+void Ancilla_MagicPowder_Draw(int k) {  // 88baeb
+  static const int8 kMagicPowder_DrawX[76] = {
+    -5, -12,  2,  -9, -7, -10, -6, -2, -6, -12,  1, -6,  -6, -12,   1,  -6,
+    -6, -12,  1,  -6, -6, -12,  1, -6, -6, -12,  1, -6, -17, -23, -14, -19,
+    -11, -18, -9, -13, -4, -13, -1, -8, -3,  -9,  0, -5,  -3, -10,  -1,  -5,
+    -4, -13, -1,  -8, -3,  -9,  0, -5, -3, -10, -1, -5,  -3, -13,  -1,  -8,
+    9,  15,  6,  11,  3,  10,  1,  5, -4,   5, -7,  0,
+  };
+  static const int8 kMagicPowder_DrawY[76] = {
+    -20, -15, -13,  -7, -18, -13, -13, -13, -20, -13, -13,  -8, -20, -13, -13,  -8,
+    -19, -12, -12,  -7, -18, -11, -11,  -6, -17, -10, -10,  -5, -16, -14, -12,  -9,
+    -17, -14, -12,  -8, -18, -14, -13,  -6, -33, -31, -29, -26, -28, -25, -23, -19,
+    -22, -18, -17, -10,  -2,   0,   2,   5,  -9,  -6,  -4,   0, -16, -12, -11,  -4,
+    -16, -14, -12,  -9, -17, -14, -12,  -8, -18, -14, -13,  -6,
+  };
+  static const uint8 kMagicPowder_Draw_Char[19] = {
+    9, 10, 10, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+  };
+  static const uint8 kMagicPowder_Draw_Flags[76] = {
+    0x68, 0x24, 0xa2, 0x28, 0x68, 0xe2, 0x28, 0xa4, 0x68, 0xe2, 0xa4, 0x28, 0x22, 0xa4, 0xe8, 0x62,
+    0x24, 0xa8, 0xe2, 0x64, 0x28, 0xa2, 0xe4, 0x68, 0x22, 0xa4, 0xe8, 0x62, 0xe2, 0xa4, 0xe8, 0x64,
+    0xe8, 0xa8, 0xe4, 0x62, 0xe4, 0xa8, 0xe2, 0x68, 0xe2, 0xa4, 0xe8, 0x64, 0xe8, 0xa8, 0xe4, 0x62,
+    0xe4, 0xa8, 0xe2, 0x68, 0xe2, 0xa4, 0xe8, 0x64, 0xe8, 0xa8, 0xe4, 0x62, 0xe4, 0xa8, 0xe2, 0x68,
+    0xe2, 0xa4, 0xe8, 0x64, 0xe8, 0xa8, 0xe4, 0x62, 0xe4, 0xa8, 0xe2, 0x68,
+  };
+  Point16U info;
+  Ancilla_PrepOamCoord(k, &info);
+  OamEnt *oam = GetOamCurPtr();
+  int b = ancilla_arr25[k];
+  for (int i = 0; i < 4; i++, oam++) {
+    Ancilla_SetOam(oam, info.x + kMagicPowder_DrawX[b * 4 + i], info.y + kMagicPowder_DrawY[b * 4 + i],
+                   kMagicPowder_Draw_Char[b], kMagicPowder_Draw_Flags[b * 4 + i] & ~0x30 | HIBYTE(oam_priority_value), 0);
+  }
+}
+
+void Powder_ApplyDamageToSprites(int k) {  // 88bb58
+  uint8 a;
+  for (int j = 15; j >= 0; j--) {
+    if ((frame_counter ^ j) & 3 || sprite_state[j] != 9 || sprite_bump_damage[j] & 0x20)
+      continue;
+    SpriteHitBox hb;
+    Ancilla_SetupBasicHitBox(k, &hb);
+    Sprite_SetupHitBox(j, &hb);
+    if (!CheckIfHitBoxesOverlap(&hb))
+      continue;
+
+    if ((a = sprite_type[j]) != 0xb || (a = player_is_indoors) == 0 || (a = dungeon_room_index2 - 1) != 0) {
+      if (a != 0xd) {
+        Ancilla_CheckDamageToSprite_preset(j, 10);
+        continue;
+      }
+      if (sprite_head_dir[j] != 0)
+        continue;
+    }
+    sprite_head_dir[j] = 1;
+    Sprite_SpawnPoofGarnish(j);
+  }
+}
+
+void Ancilla1D_ScreenShake(int k) {  // 88bbbc
+  if (submodule_index == 0) {
+    if (sign8(--ancilla_item_to_link[k])) {
+      bg1_x_offset = 0;
+      bg1_y_offset = 0;
+      ancilla_type[k] = 0;
+      return;
+    }
+    int offs = DashTremor_TwiddleOffset(k);
+    int j = ancilla_dir[k];
+    if (j == 0) {
+      bg1_x_offset = offs;
+      link_x_vel += offs;
+    } else {
+      bg1_y_offset = offs;
+      link_y_vel += offs;
+    }
+  }
+  sprite_alert_flag = 3;
+}
+
+void Ancilla1E_DashDust(int k) {  // 88bc92
+  if (ancilla_step[k]) {
+    DashDust_Motive(k);
+    return;
+  }
+  if (!ancilla_timer[k]) {
+    ancilla_timer[k] = 3;
+    if (++ancilla_item_to_link[k] == 5)
+      return;
+    if (ancilla_item_to_link[k] == 6) {
+      ancilla_type[k] = 0;
+      return;
+    }
+  }
+  if (ancilla_item_to_link[k] == 5)
+    return;
+
+  Point16U info;
+  Ancilla_PrepOamCoord(k, &info);
+  OamEnt *oam = GetOamCurPtr();
+
+  static const int8 kDashDust_Draw_X1[4] = {0, 0, 4, -4};
+  static const int16 kDashDust_Draw_X[30] = {
+    10,  5, -1,  0, 10, 5, 0,  5, -1,  0, -1, -1,  9, -1, -1, 10,
+    5, -1,  0, 10,  5, 0, 5, -1,  0, -1, -1,  9, -1, -1,
+  };
+  static const int16 kDashDust_Draw_Y[30] = {
+    -2,  0, -1, -3, -2,  0, -3,  0, -1, -3, -1, -1, -2, -1, -1, -2,
+    0, -1, -3, -2,  0, -3,  0, -1, -3, -1, -1, -2, -1, -1,
+  };
+  static const uint8 kDashDust_Draw_Char[30] = {
+    0xcf, 0xa9, 0xff, 0xa9, 0xdf, 0xcf, 0xcf, 0xdf, 0xff, 0xdf, 0xff, 0xff, 0xa9, 0xff, 0xff, 0xcf,
+    0xcf, 0xff, 0xcf, 0xdf, 0xcf, 0xcf, 0xdf, 0xff, 0xdf, 0xff, 0xff, 0xcf, 0xff, 0xff,
+  };
+  int r12 = kDashDust_Draw_X1[link_direction_facing >> 1];
+  int t = 3 * (ancilla_item_to_link[k] + (draw_water_ripples_or_grass == 1 ? 5 : 0));
+
+  for (int n = 2; n >= 0; n--, t++) {
+    if (kDashDust_Draw_Char[t] != 0xff) {
+      Ancilla_SetOam(oam, info.x + r12 + kDashDust_Draw_X[t], info.y + kDashDust_Draw_Y[t], kDashDust_Draw_Char[t], 4 | HIBYTE(oam_priority_value), 0);
+      oam++;
+    }
+  }
+}
+
+void Ancilla1F_Hookshot(int k) {  // 88bd74
+  if (submodule_index != 0)
+    goto do_draw;
+
+  if (!ancilla_timer[k]) {
+    ancilla_timer[k] = 7;
+    Ancilla_Sfx2_Pan(k, 0xa);
+  }
+
+  if (related_to_hookshot)
+    goto do_draw;
+  Ancilla_MoveY(k);
+  Ancilla_MoveX(k);
+  if (ancilla_step[k]) {
+    if (sign8(--ancilla_item_to_link[k])) {
+      ancilla_type[k] = 0;
+      return;
+    }
+    goto do_draw;
+  }
+
+  if (++ancilla_item_to_link[k] == 32) {
+    ancilla_step[k] = 1;
+    ancilla_x_vel[k] = -ancilla_x_vel[k];
+    ancilla_y_vel[k] = -ancilla_y_vel[k];
+  }
+
+  if (Hookshot_ShouldIEvenBotherWithTiles(k))
+    goto do_draw;
+
+  if (!ancilla_L[k] && !ancilla_step[k] && Ancilla_CheckSpriteCollision(k) >= 0 && !ancilla_step[k]) {
+    ancilla_step[k] = 1;
+    ancilla_y_vel[k] = -ancilla_y_vel[k];
+    ancilla_x_vel[k] = -ancilla_x_vel[k];
+  }
+
+  Hookshot_CheckTileCollision(k);
+
+  uint8 r0;
+
+  r0 = 0;
+
+  if (player_is_indoors) {
+    if (!(ancilla_dir[k] & 2)) {
+      r0 = (tiledetect_vertical_ledge | (tiledetect_vertical_ledge >> 4)) & 3;
+    } else {
+      r0 = detection_of_ledge_tiles_horiz_uphoriz & 3;
+    }
+    if (r0 == 0)
+      goto endif_7;
+  } else {
+    if (!((detection_of_ledge_tiles_horiz_uphoriz & 3 | tiledetect_vertical_ledge | detection_of_unknown_tile_types) & 0x33))
+      goto endif_7;
+  }
+  if (sign8(--ancilla_G[k])) {
+    if (ancilla_K[k] && ((r0 & 3) || ancilla_K[k] != BYTE(index_of_interacting_tile))) {
+      ancilla_G[k] = 2;
+      if (sign8(--ancilla_L[k]))
+        ancilla_L[k] = 0;
+    } else {
+      ancilla_L[k]++;
+      ancilla_K[k] = index_of_interacting_tile;
+      ancilla_G[k] = 1;
+    }
+  }
+endif_7:
+  if (ancilla_L[k])
+    goto do_draw;
+  if (!sign8(ancilla_G[k])) {
+    ancilla_G[k]--;
+    goto do_draw;
+  }
+
+  if ((R14 >> 4 | R14 | tiledetect_stair_tile | R12) & 3 && !ancilla_step[k]) {
+    ancilla_step[k] = 1;
+    ancilla_y_vel[k] = -ancilla_y_vel[k];
+    ancilla_x_vel[k] = -ancilla_x_vel[k];
+    if (!(tiledetect_misc_tiles & 3)) {
+      AncillaAdd_HookshotWallClink(k, 6, 1);
+      Ancilla_Sfx2_Pan(k, (tiledetect_misc_tiles & 0x30) ? 6 : 5);
+    }
+  }
+
+  if (tiledetect_misc_tiles & 3) {
+    if (ancilla_item_to_link[k] < 4) {
+      ancilla_type[k] = 0;
+      return;
+    }
+    related_to_hookshot = 1;
+    hookshot_effect_index = k;
+  }
+
+  static const int8 kHookShot_Move_X[4] = {0, 0, 8, -8};
+  static const int8 kHookShot_Move_Y[4] = {8, -9, 0, 0};
+  static const uint8 kHookShot_Draw_Flags[12] = {0, 0, 0xff, 0x80, 0x80, 0xff, 0x40, 0xff, 0x40, 0, 0xff, 0};
+  static const uint8 kHookShot_Draw_Char[12] = {9, 0xa, 0xff, 9, 0xa, 0xff, 9, 0xff, 0xa, 9, 0xff, 0xa};
+
+  Point16U info;
+do_draw:
+  Ancilla_PrepOamCoord(k, &info);
+  if (ancilla_L[k])
+    oam_priority_value = 0x3000;
+  OamEnt *oam = GetOamCurPtr();
+
+  int j = ancilla_dir[k] * 3;
+  int x = info.x, y = info.y;
+  for (int i = 2; i >= 0; i--, j++) {
+    if (kHookShot_Draw_Char[j] != 0xff) {
+      Ancilla_SetOam(oam, x, y, kHookShot_Draw_Char[j], kHookShot_Draw_Flags[j] | 2 | HIBYTE(oam_priority_value), 0);
+      oam++;
+    }
+    if (i == 1)
+      x -= 8, y += 8;
+    else
+      x += 8;
+  }
+
+  int r10 = 0;
+  int n = ancilla_item_to_link[k] >> 1;
+  if (n >= 7) {
+    r10 = n - 7;
+    n = 6;
+  }
+  if (n == 0)
+    return;
+  if (ancilla_dir[k] & 1)
+    r10 = -r10;
+  x = info.x, y = info.y;
+  j = ancilla_dir[k];
+  if (kHookShot_Move_Y[j] == 0)
+    y += 4;
+  if (kHookShot_Move_X[j] == 0)
+    x += 4;
+  do {
+    if (kHookShot_Move_Y[j])
+      y += kHookShot_Move_Y[j] + r10;
+    if (kHookShot_Move_X[j])
+      x += kHookShot_Move_X[j] + r10;
+    if (!Hookshot_CheckProximityToLink(x, y)) {
+      Ancilla_SetOam(oam, x, y, 0x19, (frame_counter & 2) << 6 | 2 | HIBYTE(oam_priority_value), 0);
+      oam++;
+    }
+  } while (--n >= 0);
+}
+
+void Ancilla20_Blanket(int k) {  // 88c013
+  static const uint8 kBedSpread_Char[8] = {0xa, 0xa, 0xa, 0xa, 0xc, 0xc, 0xa, 0xa};
+  static const uint8 kBedSpread_Flags[8] = {0, 0x60, 0xa0, 0xe0, 0, 0x60, 0xa0, 0xe0};
+  Point16U pt;
+  Ancilla_PrepOamCoord(k, &pt);
+
+  if (!link_pose_during_opening) {
+    Oam_AllocateFromRegionB(0x10);
+  } else {
+    Oam_AllocateFromRegionA(0x10);
+  }
+
+  OamEnt *oam = GetOamCurPtr();
+  int j = link_pose_during_opening ? 4 : 0;
+  uint16 x = pt.x, y = pt.y;
+  for (int i = 3; i >= 0; i--, j++, oam++) {
+    Ancilla_SetOam(oam, x, y, kBedSpread_Char[j], kBedSpread_Flags[j] | 0xd | HIBYTE(oam_priority_value), 2);
+    x += 16;
+    if (i == 2)
+      x -= 32, y += 8;
+  }
+}
+
+void Ancilla21_Snore(int k) {  // 88c094
+  static const uint8 kBedSpread_Dma[3] = {0x44, 0x43, 0x42};
+  if (sign8(--ancilla_aux_timer[k])) {
+    if (ancilla_item_to_link[k] != 2)
+      ancilla_item_to_link[k]++;
+    ancilla_aux_timer[k] = 7;
+  }
+  ancilla_x_vel[k] += ancilla_step[k];
+  if (abs8(ancilla_x_vel[k]) >= 8)
+    ancilla_step[k] = -ancilla_step[k];
+  Ancilla_MoveY(k);
+  Ancilla_MoveX(k);
+  if (Ancilla_GetY(k) <= (uint16)(link_y_coord - 24))
+    ancilla_type[k] = 0;
+  link_dma_var5 = kBedSpread_Dma[ancilla_item_to_link[k]];
+  Point16U pt;
+  Ancilla_PrepOamCoord(k, &pt);
+  Ancilla_SetOam(GetOamCurPtr(), pt.x, pt.y, 9, 0x24, 0);
+}
+
+void Ancilla3B_SwordUpSparkle(int k) {  // 88c167
+  static const int8 kAncilla_VictorySparkle_X[16] = {16, 0, 0, 0, 8, 16, 8, 16, 9, 15, 0, 0, 12, 0, 0, 0};
+  static const int8 kAncilla_VictorySparkle_Y[16] = {-7, 0, 0, 0, -11, -11, -3, -3, -7, -7, 0, 0, -7, 0, 0, 0};
+  static const uint8 kAncilla_VictorySparkle_Char[16] = {0x92, 0xff, 0xff, 0xff, 0x93, 0x93, 0x93, 0x93, 0xf9, 0xf9, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff};
+  static const uint8 kAncilla_VictorySparkle_Flags[16] = {0, 0xff, 0xff, 0xff, 0, 0x40, 0x80, 0xc0, 0, 0x40, 0xff, 0xff, 0, 0xff, 0xff, 0xff};
+
+  if (ancilla_aux_timer[k]) {
+    ancilla_aux_timer[k]--;
+    return;
+  }
+
+  if (sign8(--ancilla_arr3[k])) {
+    ancilla_arr3[k] = 1;
+    if (++ancilla_item_to_link[k] == 4) {
+      ancilla_type[k] = 0;
+      ancilla_aux_timer[k]--;
+      return;
+    }
+  }
+  Point16U pt;
+  Ancilla_PrepOamCoord(k, &pt);
+  OamEnt *oam = GetOamCurPtr();
+  int j = ancilla_item_to_link[k] * 4;
+  for (int i = 0; i < 4; i++, j++) {
+    if (kAncilla_VictorySparkle_Char[j] != 0xff) {
+      Ancilla_SetOam(oam,
+                     link_x_coord + kAncilla_VictorySparkle_X[j] - BG2HOFS_copy2,
+                     link_y_coord + kAncilla_VictorySparkle_Y[j] - BG2VOFS_copy2,
+                     kAncilla_VictorySparkle_Char[j],
+                     kAncilla_VictorySparkle_Flags[j] | 4 | HIBYTE(oam_priority_value), 0);
+      oam++;
+    }
+  }
+}
+
+void Ancilla3C_SpinAttackChargeSparkle(int k) {  // 88c1ea
+  static const uint8 kSwordChargeSpark_Char[3] = {0xb7, 0x80, 0x83};
+  static const uint8 kSwordChargeSpark_Flags[3] = {4, 4, 0x84};
+
+  if (!submodule_index && !ancilla_timer[k]) {
+    ancilla_timer[k] = 4;
+    if (++ancilla_item_to_link[k] == 3) {
+      ancilla_type[k] = 0;
+      return;
+    }
+  }
+  ancilla_oam_idx[k] = Ancilla_AllocateOamFromRegion_A_or_D_or_F(k, 4);
+  Point16U info;
+  Ancilla_PrepOamCoord(k, &info);
+  int j = ancilla_item_to_link[k];
+  Ancilla_SetOam(GetOamCurPtr(), info.x, info.y,
+                 kSwordChargeSpark_Char[j], kSwordChargeSpark_Flags[j] | HIBYTE(oam_priority_value), 0);
+}
+
+void Ancilla35_MasterSwordReceipt(int k) {  // 88c25f
+  static const int8 kSwordCeremony_X[8] = {-1, 8, -1, 8, 0, 7, 0, 7};
+  static const int8 kSwordCeremony_Y[8] = {1, 1, 9, 9, 1, 1, 9, 9};
+  static const uint8 kSwordCeremony_Char[8] = {0x86, 0x86, 0x96, 0x96, 0x87, 0x87, 0x97, 0x97};
+  static const uint8 kSwordCeremony_Flags[8] = {1, 0x41, 1, 0x41, 1, 0x41, 1, 0x41};
+
+  if (!ancilla_timer[k]) {
+    ancilla_type[k] = 0;
+    return;
+  }
+  if (sign8(--ancilla_aux_timer[k])) {
+    ancilla_item_to_link[k] = (ancilla_item_to_link[k] == 2) ? 0 : ancilla_item_to_link[k] + 1;
+  }
+
+  Point16U pt;
+  Ancilla_PrepOamCoord(k, &pt);
+  OamEnt *oam = GetOamCurPtr();
+  int j = (ancilla_item_to_link[k] - 1) * 4;
+  if (j < 0)
+    return;
+
+  for (int i = 0; i < 4; i++, j++, oam++) {
+    Ancilla_SetOam(oam, pt.x + kSwordCeremony_X[j], pt.y + kSwordCeremony_Y[j],
+                   kSwordCeremony_Char[j], kSwordCeremony_Flags[j] & ~0x30 | 4 | HIBYTE(oam_priority_value), 0);
+  }
+}
+
+void Ancilla22_ItemReceipt(int k) {  // 88c38a
+  uint8 a;
+
+  if (flag_is_link_immobilized == 2)
+    goto endif_1;
+  if (submodule_index != 0 && submodule_index != 43 && submodule_index != 9) {
+    if (submodule_index == 2)
+      ancilla_timer[k] = 16;
+    goto endif_1;
+  }
+  flag_unk1++;
+
+  if (ancilla_step[k] != 0 && ancilla_step[k] != 3) {
+    if (sign8(--ancilla_aux_timer[k]))
+      goto endif_11;
+
+    if (ancilla_aux_timer[k] == 0)
+      goto endif_6;
+
+    if (ancilla_aux_timer[k] == 40 && ancilla_step[k] != 2) {
+      if (Ancilla_AddRupees(k) || ancilla_item_to_link[k] != 0x17)
+        Ancilla_Sfx3_Near(0xf);
+    }
+    goto label_b;
+  }
+
+  if (ancilla_item_to_link[k] == 1 && ancilla_step[k] != 2) {
+    if (ancilla_timer[k] == 0)
+      goto label_a;
+    if (ancilla_timer[k] != 17)
+      goto endif_1;
+    word_7E02CD = 0xDF3;
+    follower_indicator = 0xe;
+    goto endif_6;
+  }
+
+  a = --ancilla_aux_timer[k];
+  if (a == 0)
+    goto label_a;
+  if (a == 1) {
+    if (ancilla_item_to_link[k] != 0x37 && ancilla_item_to_link[k] != 0x38 && ancilla_item_to_link[k] != 0x39 || zelda_read_apui00() == 0)
+      goto endif_6;
+    ancilla_aux_timer[k]++;
+  }
+  goto endif_1;
+
+label_a:
+  if (ancilla_item_to_link[k] == 1 && !ancilla_step[k]) {
+    sound_effect_ambient = 5;
+    music_control = 2;
+  }
+  link_player_handler_state = link_is_in_deep_water ? kPlayerState_Swimming : 0;
+  link_receiveitem_index = 0;
+  link_pose_for_item = 0;
+  link_disable_sprite_damage = 0;
+  Ancilla_AddRupees(k);
+endif_11:
+  item_receipt_method = 0;
+  a = ancilla_item_to_link[k];
+  if (a == 23 && link_heart_pieces == 0) {
+    Link_ReceiveItem(0x26, 0);
+    ancilla_type[k] = 0;
+    flag_unk1 = 0;
+    return;
+  }
+
+  if (a == 0x26 || a == 0x3f) {
+    if (link_health_capacity != 0xa0) {
+      link_health_capacity += 8;
+      link_hearts_filler += link_health_capacity - link_health_current;
+      Ancilla_Sfx3_Near(0xd);
+    }
+  } else if (a == 0x3e) {
+    flag_is_link_immobilized = 0;
+    if (link_health_capacity != 0xa0) {
+      link_health_capacity += 8;
+      link_hearts_filler += 8;
+      Ancilla_Sfx3_Near(0xd);
+    }
+  } else if (a == 0x42) {
+    link_hearts_filler += 8;
+  } else if (a == 0x45) {
+    link_magic_filler += 16;
+  } else if (a == 0x22 || a == 0x23) {
+    Palette_Load_LinkArmorAndGloves();
+  }
+
+  ancilla_type[k] = 0;
+  flag_unk1 = 0;
+  a = ancilla_item_to_link[k];
+  if (ancilla_step[k] == 3 && a != 0x10 && a != 0x26 && a != 0xf && a != 0x20) {
+    PrepareDungeonExitFromBossFight();
+  }
+
+  if (ancilla_step[k] != 2)
+    flag_is_link_immobilized = 0;
+  return;
+
+endif_6:
+  if (player_is_indoors) {
+    int room = dungeon_room_index;
+    if (room == 0xff || room == 0x10f || room == 0x110 || room == 0x112 || room == 0x11f)
+      goto label_b;
+  }
+  int msg;
+  msg = -1;
+  if (ancilla_item_to_link[k] == 0x38 || ancilla_item_to_link[k] == 0x39) {
+    if ((link_which_pendants & 7) == 7)
+      msg = kReceiveItemMsgs2[ancilla_item_to_link[k] - 0x38];
+    else
+      msg = kReceiveItemMsgs[ancilla_item_to_link[k]];
+  } else if (ancilla_step[k] != 2) {
+    if (ancilla_item_to_link[k] == 0x17)
+      msg = kReceiveItemMsgs3[link_heart_pieces];
+    else
+      msg = kReceiveItemMsgs[ancilla_item_to_link[k]];
+  }
+  if (msg != -1) {
+    dialogue_message_index = msg;
+    if (msg == 0x70)
+      sound_effect_ambient = 9;
+    Main_ShowTextMessage();
+  }
+  goto endif_1;
+
+label_b:
+  if (ancilla_aux_timer[k] >= 24) {
+    a = ancilla_y_vel[k] - 1;
+    if (a >= 248)
+      ancilla_y_vel[k] = a;
+    Ancilla_MoveY(k);
+  }
+endif_1:
+
+  if (ancilla_item_to_link[k] == 0x20) {
+    ancilla_z[k] = 0;
+    AncillaAdd_OccasionalSparkle(k);
+    if (zelda_read_apui00() == 0) {
+      music_control = 0x1a;
+      ItemReceipt_TransmuteToRisingCrystal(k);
+      return;
+    }
+  } else if (ancilla_item_to_link[k] == 0x1) {
+    ancilla_arr4[k] = kReceiveItem_Tab0[0];
+    if (ancilla_step[k] != 2) {
+      if (ancilla_timer[k] < 16) {
+        a = 0;
+      } else {
+        if (!sign8(--ancilla_arr3[k]))
+          goto skipit;
+        ancilla_arr3[k] = 2;
+        a = ancilla_arr1[k] + 1;
+        if (a == 3)
+          a = 0;
+      }
+      ancilla_arr1[k] = a;
+      ancilla_arr4[k] = kReceiveItem_Tab0[a];
+skipit:;
+    }
+  }
+
+  if ((ancilla_item_to_link[k] == 0x34 || ancilla_item_to_link[k] == 0x35 || ancilla_item_to_link[k] == 0x36) && sign8(--ancilla_arr3[k])) {
+    a = ancilla_arr1[k] + 1;
+    if (a == 3)
+      a = 0;
+    ancilla_arr1[k] = a;
+    ancilla_arr3[k] = kReceiveItem_Tab4[a];
+    WriteTo4BPPBuffer_at_7F4000(kReceiveItem_Tab5[a]);
+  }
+  Point16U pt;
+  Ancilla_PrepAdjustedOamCoord(k, &pt);
+  Ancilla_ReceiveItem_Draw(k, pt.x, pt.y);
+}
+
+OamEnt *Ancilla_ReceiveItem_Draw(int k, int x, int y) {  // 88c690
+  OamEnt *oam = GetOamCurPtr();
+  int j = ancilla_item_to_link[k];
+  oam->charnum = 0x24;
+  uint8 a = kWishPond2_OamFlags[j];
+  if (sign8(a))
+    a = ancilla_arr4[k];
+  Ancilla_SetOam(oam, x, y, 0x24, a * 2 | 0x30, kReceiveItem_Tab1[j]);
+  oam++;
+  if (kReceiveItem_Tab1[j] == 0) {
+    Ancilla_SetOam(oam, x, y + 8, 0x34, a * 2 | 0x30, 0);
+    oam++;
+  }
+  return oam;
+}
+
+void Ancilla28_WishPondItem(int k) {  // 88c6f2
+  Ancilla_AllocateOamFromRegion_A_or_D_or_F(k, 0x10);
+
+  if (submodule_index == 0 && ancilla_timer[k] == 0) {
+    link_picking_throw_state = 2;
+    link_state_bits = 0;
+    ancilla_z_vel[k] -= 2;
+    Ancilla_MoveZ(k);
+    Ancilla_MoveY(k);
+    Ancilla_MoveX(k);
+    if (sign8(ancilla_z[k]) && ancilla_z[k] < 228) {
+      ancilla_z[k] = 228;
+      Ancilla_SetXY(k,
+          Ancilla_GetX(k) + (kGeneratedWishPondItem[ancilla_item_to_link[k]] ? 8 : 4), // wtf
+          Ancilla_GetY(k) + 18);
+      Ancilla_TransmuteToSplash(k);
+      return;
+    }
+  }
+  WishPondItem_Draw(k);
+}
+
+void WishPondItem_Draw(int k) {  // 88c760
+  Point16U pt;
+  Ancilla_PrepAdjustedOamCoord(k, &pt);
+
+  if (ancilla_item_to_link[k] == 1)
+    ancilla_arr4[k] = 5;
+
+  OamEnt *oam = Ancilla_ReceiveItem_Draw(k, pt.x, pt.y - (int8)ancilla_z[k]);
+
+  if (link_picking_throw_state != 2 || !sign8(ancilla_z_vel[k]) && ancilla_z_vel[k] >= 2)
+    return;
+
+  uint8 xx = kGeneratedWishPondItem[ancilla_item_to_link[k]];
+  AncillaDraw_Shadow(oam,
+    (xx == 2) ? 1 : 2,
+    pt.x - (xx == 2 ? 0 : 4),
+    pt.y + 40, HIBYTE(oam_priority_value));
+}
+
+void Ancilla42_HappinessPondRupees(int k) {  // 88c7de
+  link_picking_throw_state = 2;
+  link_state_bits = 0;
+  for (int i = 9; i >= 0; i--) {
+    if (happiness_pond_arr1[i]) {
+      HapinessPondRupees_ExecuteRupee(k, i);
+      if (happiness_pond_step[i] == 2)
+        happiness_pond_arr1[i] = 0;
+    }
+  }
+  for (int i = 9; i >= 0; i--) {
+    if (happiness_pond_arr1[i])
+      return;
+  }
+  ancilla_type[k] = 0;
+}
+
+void HapinessPondRupees_ExecuteRupee(int k, int i) {  // 88c819
+  Ancilla_AllocateOamFromRegion_A_or_D_or_F(k, 0x10);
+  HapinessPondRupees_GetState(k, i);
+
+  if (ancilla_step[k]) {
+    if (!submodule_index && !ancilla_timer[k]) {
+      ancilla_timer[k] = 6;
+      if (++ancilla_item_to_link[k] == 5) {
+        ancilla_step[k]++;
+      } else {
+        ObjectSplash_Draw(k);
+      }
+    } else {
+      ObjectSplash_Draw(k);
+    }
+  } else if (submodule_index == 0 && ancilla_timer[k] == 0) {
+    ancilla_z_vel[k] -= 2;
+    Ancilla_MoveY(k);
+    Ancilla_MoveX(k);
+    Ancilla_MoveZ(k);
+    if (!sign8(ancilla_z[k]) || ancilla_z[k] >= 0xe4)
+      goto else_label;
+    ancilla_z[k] = 0xe4;
+    Ancilla_SetXY(k, Ancilla_GetX(k) - 4, Ancilla_GetY(k) + 30);
+    ancilla_item_to_link[k] = 0;
+    ancilla_timer[k] = 6;
+    Ancilla_Sfx2_Pan(k, 0x28);
+    ancilla_step[k]++;
+    ObjectSplash_Draw(k);
+  } else {
+else_label:
+    ancilla_arr4[k] = 2;
+    ancilla_floor[k] = 0;
+    WishPondItem_Draw(k);
+  }
+  HapinessPondRupees_SaveState(i, k);
+}
+
+void HapinessPondRupees_GetState(int j, int k) {  // 88c8be
+  ancilla_y_lo[j] = happiness_pond_y_lo[k];
+  ancilla_y_hi[j] = happiness_pond_y_hi[k];
+  ancilla_x_lo[j] = happiness_pond_x_lo[k];
+  ancilla_x_hi[j] = happiness_pond_x_hi[k];
+  ancilla_z[j] = happiness_pond_z[k];
+  ancilla_y_vel[j] = happiness_pond_y_vel[k];
+  ancilla_x_vel[j] = happiness_pond_x_vel[k];
+  ancilla_z_vel[j] = happiness_pond_z_vel[k];
+  ancilla_y_subpixel[j] = happiness_pond_y_subpixel[k];
+  ancilla_x_subpixel[j] = happiness_pond_x_subpixel[k];
+  ancilla_z_subpixel[j] = happiness_pond_z_subpixel[k];
+  ancilla_item_to_link[j] = happiness_pond_item_to_link[k];
+  ancilla_step[j] = happiness_pond_step[k];
+  ancilla_timer[j] = happiness_pond_timer[k] ? happiness_pond_timer[k] - 1 : 0;
+}
+
+void HapinessPondRupees_SaveState(int k, int j) {  // 88c924
+  happiness_pond_y_lo[k] = ancilla_y_lo[j];
+  happiness_pond_y_hi[k] = ancilla_y_hi[j];
+  happiness_pond_x_lo[k] = ancilla_x_lo[j];
+  happiness_pond_x_hi[k] = ancilla_x_hi[j];
+  happiness_pond_z[k] = ancilla_z[j];
+  happiness_pond_y_vel[k] = ancilla_y_vel[j];
+  happiness_pond_x_vel[k] = ancilla_x_vel[j];
+  happiness_pond_z_vel[k] = ancilla_z_vel[j];
+  happiness_pond_y_subpixel[k] = ancilla_y_subpixel[j];
+  happiness_pond_x_subpixel[k] = ancilla_x_subpixel[j];
+  happiness_pond_z_subpixel[k] = ancilla_z_subpixel[j];
+  happiness_pond_item_to_link[k] = ancilla_item_to_link[j];
+  happiness_pond_timer[k] = ancilla_timer[j];
+  happiness_pond_step[k] = ancilla_step[j];
+}
+
+void Ancilla_TransmuteToSplash(int k) {  // 88c9cd
+  ancilla_type[k] = 0x3d;
+  ancilla_item_to_link[k] = 0;
+  ancilla_timer[k] = 6;
+  Ancilla_SetXY(k, Ancilla_GetX(k) - 8, Ancilla_GetY(k) + 12);
+  Ancilla_Sfx2_Pan(k, 0x28);
+  Ancilla3D_ItemSplash(k);
+}
+
+void Ancilla3D_ItemSplash(int k) {  // 88ca01
+  Ancilla_AllocateOamFromRegion_A_or_D_or_F(k, 8);
+  if (!submodule_index && !ancilla_timer[k]) {
+    ancilla_timer[k] = 6;
+    if (++ancilla_item_to_link[k] == 5) {
+      ancilla_type[k] = 0;
+      return;
+    }
+  }
+  ObjectSplash_Draw(k);
+}
+
+void ObjectSplash_Draw(int k) {  // 88ca22
+  static const int8 kObjectSplash_Draw_X[10] = {0, 0, 0, 0, 11, -3, 15, -7, 15, -7};
+  static const int8 kObjectSplash_Draw_Y[10] = {0, 0, -6, 0, -13, -8, -17, -4, -17, -4};
+  static const uint8 kObjectSplash_Draw_Char[10] = {0xc0, 0xff, 0xe7, 0xff, 0xaf, 0xbf, 0x80, 0x80, 0x83, 0x83};
+  static const uint8 kObjectSplash_Draw_Flags[10] = {0, 0xff, 0, 0xff, 0x40, 0, 0x40, 0, 0xc0, 0x80};
+  static const uint8 kObjectSplash_Draw_Ext[10] = {2, 0, 2, 0, 0, 0, 0, 0, 0, 0};
+  Point16U pt;
+  Ancilla_PrepOamCoord(k, &pt);
+  OamEnt *oam = GetOamCurPtr();
+  int j = ancilla_item_to_link[k] * 2;
+  for (int i = 0; i != 2; i++, j++) {
+    if (kObjectSplash_Draw_Char[j] != 0xff) {
+      Ancilla_SetOam(oam, pt.x + kObjectSplash_Draw_X[j], pt.y + kObjectSplash_Draw_Y[j],
+                     kObjectSplash_Draw_Char[j], kObjectSplash_Draw_Flags[j] | 0x24, 
+                     kObjectSplash_Draw_Ext[j]);
+      oam++;
+    }
+  }
+}
+
+void Ancilla29_MilestoneItemReceipt(int k) {  // 88ca8c
+  if (ancilla_item_to_link[k] != 0x10 && ancilla_item_to_link[k] != 0x0f) {
+    if (dung_savegame_state_bits & 0x4000) {
+      ancilla_type[k] = 0;
+      return;
+    }
+
+    if (!(dung_savegame_state_bits & 0x8000))
+      return;
+
+    if (byte_7E04C2 != 0) {
+      if (byte_7E04C2 == 1) {
+        if (ancilla_item_to_link[k] == 0x20) {
+          sound_effect_ambient = 0x0f;
+          DecodeAnimatedSpriteTile_variable(0x28);
+        } else {
+          DecodeAnimatedSpriteTile_variable(0x23);
+        }
+      }
+      byte_7E04C2--;
+      return;
+    }
+    if (!ancilla_arr3[k] && ancilla_item_to_link[k] == 0x20) {
+      ancilla_arr3[k] = 1;
+      palette_sp6r_indoors = 4;
+      overworld_palette_aux_or_main = 0x200;
+      Palette_Load_SpriteEnvironment_Dungeon();
+      flag_update_cgram_in_nmi++;
+    }
+  } else {
+    if (ancilla_G[k]) {
+      ancilla_G[k]--;
+      return;
+    }
+  }
+
+  if (ancilla_item_to_link[k] == 0x20)
+    AncillaAdd_OccasionalSparkle(k);
+
+  if (submodule_index == 0) {
+    CheckPlayerCollOut coll_out;
+    if (ancilla_z[k] < 24 && Ancilla_CheckLinkCollision(k, 2, &coll_out) && related_to_hookshot == 0 && link_auxiliary_state == 0) {
+      ancilla_type[k] = 0;
+      if (link_player_handler_state == kPlayerState_ReceivingEther || link_player_handler_state == kPlayerState_ReceivingBombos) {
+        flag_custom_spell_anim_active = 0;
+        link_force_hold_sword_up = 0;
+        link_player_handler_state = 0;
+      }
+      item_receipt_method = 3;
+      Link_ReceiveItem(ancilla_item_to_link[k], 0);
+      return;
+    }
+
+    if (ancilla_step[k] != 2) {
+      if (ancilla_step[k] != 0) {
+        ancilla_z_vel[k]--;
+      }
+      Ancilla_MoveZ(k);
+      if (ancilla_z[k] >= 0xf8) {
+        ancilla_step[k]++;
+        ancilla_z_vel[k] = 0x18;
+        ancilla_z[k] = 0;
+      }
+    }
+  }
+
+  Point16U pt;
+  Ancilla_PrepAdjustedOamCoord(k, &pt);
+  OamEnt *oam = Ancilla_ReceiveItem_Draw(k, pt.x, pt.y - ancilla_z[k]);
+
+  if (sign8(--ancilla_aux_timer[k])) {
+    ancilla_aux_timer[k] = 9;
+    if (++ancilla_L[k] == 3)
+      ancilla_L[k] = 0;
+  }
+
+  int t;
+  if (ancilla_z[k] == 0) {
+    t = (dungeon_room_index == 6) ? ancilla_L[k] + 4 : 0;
+  } else {
+    t = ancilla_z[k] < 0x20 ? 1 : 2;
+  }
+  AncillaDraw_Shadow(oam, t, pt.x, pt.y + 12, 0x20);
+}
+
+void ItemReceipt_TransmuteToRisingCrystal(int k) {  // 88cbe4
+  ancilla_type[k] = 0x3e;
+  ancilla_y_vel[k] = 0;
+  ancilla_x_vel[k] = 0;
+  ancilla_y_subpixel[k] = 0;
+  Ancilla_RisingCrystal(k);
+}
+
+void Ancilla_RisingCrystal(int k) {  // 88cbf2
+  ancilla_z[k] = 0;
+  AncillaAdd_OccasionalSparkle(k);
+  uint8 yy = ancilla_y_vel[k] - 1;
+  if (yy < 0xf0)
+    yy = 0xf0;
+  ancilla_y_vel[k] = yy;
+  Ancilla_MoveY(k);
+
+  uint16 y = Ancilla_GetY(k) - BG2VOFS_copy;
+  if (y < 0x49) {
+    Ancilla_SetY(k, 0x49 + BG2VOFS_copy);
+    if (!submodule_index) {
+      link_has_crystals |= kDungeonCrystalPendantBit[BYTE(cur_palace_index_x2) >> 1];
+      submodule_index = 0x18;
+      subsubmodule_index = 0;
+      memset(aux_palette_buffer + 0x20, 0, sizeof(uint16) * 0x60);
+      palette_filter_countdown = 0;
+      darkening_or_lightening_screen = 0;
+    }
+  }
+
+  Point16U pt;
+  Ancilla_PrepAdjustedOamCoord(k, &pt);
+  Ancilla_ReceiveItem_Draw(k, pt.x, pt.y);
+}
+
+void AncillaAdd_OccasionalSparkle(int k) {  // 88cc93
+  if (!(frame_counter & 7))
+    AncillaAdd_SwordChargeSparkle(k);
+}
+
+void Ancilla43_GanonsTowerCutscene(int k) {  // 88cca0
+  OamEnt *oam = GetOamCurPtr();
+  if (!ancilla_step[k]) {
+    uint8 yy = ancilla_y_vel[k] - 1;
+    ancilla_y_vel[k] = (yy < 0xf0) ? 0xf0 : yy;
+    Ancilla_MoveY(k);
+    uint16 x = Ancilla_GetX(k), y = Ancilla_GetY(k);
+    if ((uint16)(y - BG2VOFS_copy) >= 0x38)
+      goto lbl_else;
+    breaktowerseal_y = 0x38 + 8 + BG2VOFS_copy;
+    breaktowerseal_x = x + 8;
+    Ancilla_SetY(k, 0x38 + BG2VOFS_copy);
+    ancilla_step[k]++;
+    sound_effect_ambient = 5;
+    music_control = 0xf1;
+    dialogue_message_index = 0x13b;
+    Main_ShowTextMessage();
+    goto label_a;
+  }
+lbl_else:
+  if (ancilla_step[k] == 1 && submodule_index == 0) {
+    ancilla_x_vel[k] = 16;
+    uint8 bak0 = ancilla_x_lo[k];
+    uint8 bak1 = ancilla_x_hi[k];
+    ancilla_x_lo[k] = breaktowerseal_var4;
+    ancilla_x_hi[k] = 0;
+    Ancilla_MoveX(k);
+    breaktowerseal_var4 = ancilla_x_lo[k];
+    ancilla_x_lo[k] = bak0;
+    ancilla_x_hi[k] = bak1;
+    if (breaktowerseal_var4 >= 48) {
+      breaktowerseal_var4 = 48;
+      ancilla_step[k]++;
+    }
+  }
+  if (submodule_index)
+    goto label_b;
+  if (ancilla_step[k] == 0)
+    goto label_a;
+  if (ancilla_step[k] == 1)
+    goto label_b;
+  if (ancilla_step[k] == 2) {
+    if (--breaktowerseal_var5 == 0) {
+      trigger_special_entrance = 5;
+      subsubmodule_index = 0;
+      BYTE(R16) = 0;
+      ancilla_step[k]++;
+    }
+  } else {
+    ancilla_x_vel[k] = 48;
+    uint8 bak0 = ancilla_x_lo[k];
+    uint8 bak1 = ancilla_x_hi[k];
+    ancilla_x_lo[k] = breaktowerseal_var4;
+    ancilla_x_hi[k] = 0;
+    Ancilla_MoveX(k);
+    breaktowerseal_var4 = ancilla_x_lo[k];
+    ancilla_x_lo[k] = bak0;
+    ancilla_x_hi[k] = bak1;
+    if (breaktowerseal_var4 >= 240) {
+      palette_sp6r_indoors = 0;
+      overworld_palette_aux_or_main = 0x200;
+      Palette_Load_SpriteEnvironment_Dungeon();
+      flag_update_cgram_in_nmi++;
+      ancilla_type[k] = 0;
+      return;
+    }
+  }
+  uint8 astep;
+label_b:
+
+
+  astep = ancilla_step[k];
+  if (astep != 0)
+    oam = GTCutscene_SparkleALot(oam);
+
+  for (int j = 6; j >= 0; j--) {
+    if (submodule_index == 0 && astep != 1 && !(frame_counter & 1))
+      breaktowerseal_var3[j] = breaktowerseal_var3[j] + 1 & 63;
+    AncillaRadialProjection arp = Ancilla_GetRadialProjection(breaktowerseal_var3[j], breaktowerseal_var4);
+    int x = (arp.r6 ? -arp.r4 : arp.r4) + breaktowerseal_x - 8 - BG2HOFS_copy;
+    int y = (arp.r2 ? -arp.r0 : arp.r0) + breaktowerseal_y - 8 - BG2VOFS_copy;
+
+    breaktowerseal_base_sparkle_x_lo[j] = x;
+    breaktowerseal_base_sparkle_x_hi[j] = x >> 8;
+
+    breaktowerseal_base_sparkle_y_lo[j] = y;
+    breaktowerseal_base_sparkle_y_hi[j] = y >> 8;
+
+    AncillaDraw_GTCutsceneCrystal(oam, x, y);
+    oam++;
+  }
+  Point16U info;
+label_a:
+  Ancilla_PrepAdjustedOamCoord(k, &info);
+
+  breaktowerseal_base_sparkle_x_lo[7] = info.x;
+  breaktowerseal_base_sparkle_x_hi[7] = info.x >> 8;
+  breaktowerseal_base_sparkle_y_lo[7] = info.y;
+  breaktowerseal_base_sparkle_y_hi[7] = info.y >> 8;
+
+  AncillaDraw_GTCutsceneCrystal(oam, info.x, info.y);
+
+  if (!ancilla_step[k])
+    AncillaAdd_OccasionalSparkle(k);
+  else if (!submodule_index)
+    GTCutscene_ActivateSparkle();
+}
+
+void AncillaDraw_GTCutsceneCrystal(OamEnt *oam, int x, int y) {  // 88ceaa
+  Ancilla_SetOam_Safe(oam, x, y, 0x24, 0x3c, 2);
+}
+
+void GTCutscene_ActivateSparkle() {  // 88cec7
+  for (int k = 0x17; k >= 0; k--) {
+    if (breaktowerseal_sparkle_var1[k] == 0xff) {
+      breaktowerseal_sparkle_var1[k] = 0;
+      breaktowerseal_sparkle_var2[k] = 4;
+      int r = GetRandomNumber();
+      int x = breaktowerseal_base_sparkle_x_hi[k & 7] << 8 | breaktowerseal_base_sparkle_x_lo[k & 7];
+      int y = breaktowerseal_base_sparkle_y_hi[k & 7] << 8 | breaktowerseal_base_sparkle_y_lo[k & 7];
+      x += r >> 4;
+      y += r & 0xf;
+      breaktowerseal_sparkle_x_lo[k] = x;
+      breaktowerseal_sparkle_x_hi[k] = x >> 8;
+      breaktowerseal_sparkle_y_lo[k] = y;
+      breaktowerseal_sparkle_y_hi[k] = y >> 8;
+      return;
+    }
+  }
+}
+
+OamEnt *GTCutscene_SparkleALot(OamEnt *oam) {  // 88cf35
+  static const uint8 kSwordChargeSpark_Char[3] = {0xb7, 0x80, 0x83};
+  static const uint8 kSwordChargeSpark_Flags[3] = {4, 4, 0x84};
+  for (int k = 0x17; k >= 0; k--) {
+    if (breaktowerseal_sparkle_var1[k] == 0xff)
+      continue;
+
+    if (sign8(--breaktowerseal_sparkle_var2[k])) {
+      breaktowerseal_sparkle_var2[k] = 4;
+      if (++breaktowerseal_sparkle_var1[k] == 3) {
+        breaktowerseal_sparkle_var1[k] = 0xff;
+        continue;
+      }
+    }
+
+    int x = breaktowerseal_sparkle_x_hi[k] << 8 | breaktowerseal_sparkle_x_lo[k];
+    int y = breaktowerseal_sparkle_y_hi[k] << 8 | breaktowerseal_sparkle_y_lo[k];
+    int j = breaktowerseal_sparkle_var1[k];
+    Ancilla_SetOam(oam, x, y, kSwordChargeSpark_Char[j], kSwordChargeSpark_Flags[j] | 0x30, 0);
+    oam++;
+  }
+  return oam;
+}
+
+void Ancilla36_Flute(int k) {  // 88cfaa
+  static const uint8 kFlute_Vels[4] = {0x18, 0x10, 0xa, 0};
+
+  if (!submodule_index) {
+    if (ancilla_step[k] != 3) {
+      ancilla_z_vel[k] -= 2;
+      Ancilla_MoveX(k);
+      Ancilla_MoveZ(k);
+      if (sign8(ancilla_z[k]) || ancilla_z[k] >= 0xf0) {
+        ancilla_z_vel[k] = kFlute_Vels[++ancilla_step[k]];
+        ancilla_z[k] = 0;
+      }
+    } else {
+      CheckPlayerCollOut coll_out;
+      if (Ancilla_CheckLinkCollision(k, 2, &coll_out) && !related_to_hookshot && link_auxiliary_state == 0) {
+        ancilla_type[k] = 0;
+        item_receipt_method = 0;
+        Link_ReceiveItem(0x14, 0);
+        return;
+      }
+    }
+  }
+
+  Point16U pt;
+  Ancilla_PrepAdjustedOamCoord(k, &pt);
+  OamEnt *oam = GetOamCurPtr();
+  Ancilla_SetOam(oam, pt.x, pt.y - (int8)ancilla_z[k], 0x24, HIBYTE(oam_priority_value) | 4, 2);
+  if (oam->y == 0xf0)
+    ancilla_type[k] = 0;
+}
+
+void Ancilla37_WeathervaneExplosion(int k) {  // 88d03d
+  if (--weathervane_var2)
+    return;
+  weathervane_var2 = 1;
+  if (!weathervane_var1) {
+    weathervane_var1 = 1;
+    music_control = 0xf3;
+  }
+  if (--ancilla_G[k])
+    return;
+  ancilla_G[k] = 1;
+  if (!ancilla_arr3[k]) {
+    ancilla_arr3[k] += 1;
+    Ancilla_Sfx2_Near(0xc);
+  }
+  if (!ancilla_step[k] && sign8(--ancilla_aux_timer[k])) {
+    ancilla_step[k] = 1;
+    Overworld_AlterWeathervane();
+    AncillaAdd_CutsceneDuck(0x38, 0);
+  }
+  weathervane_var13 = k;
+  weathervane_var14 = 0;
+  for (int i = 11; i >= 0; i--) {
+    if (weathervane_arr12[i] == 0xff)
+      continue;
+    if (sign8(--weathervane_arr11[i])) {
+      weathervane_arr11[i] = 1;
+      weathervane_arr12[i] ^= 1;
+    }
+
+    ancilla_item_to_link[k] = weathervane_arr12[i];
+    ancilla_y_lo[k] = weathervane_arr6[i];
+    ancilla_y_hi[k] = weathervane_arr7[i];
+    ancilla_x_lo[k] = weathervane_arr8[i];
+    ancilla_x_hi[k] = weathervane_arr9[i];
+    ancilla_z[k] = weathervane_arr10[i];
+    ancilla_y_vel[k] = weathervane_arr3[i];
+    ancilla_x_vel[k] = weathervane_arr4[i];
+    weathervane_arr5[i] = ancilla_z_vel[k] = weathervane_arr5[i] - 1;
+
+    Ancilla_MoveY(k);
+    Ancilla_MoveX(k);
+    Ancilla_MoveZ(k);
+
+    uint8 c = (ancilla_z[k] < 0xf0) ? 0 : 0xff;
+    AncillaDraw_WeathervaneExplosionWoodDebris(k);
+    if (sign8(c))
+      weathervane_arr12[i] = c;
+    weathervane_arr6[i] = ancilla_y_lo[k];
+    weathervane_arr7[i] = ancilla_y_hi[k];
+    weathervane_arr8[i] = ancilla_x_lo[k];
+    weathervane_arr9[i] = ancilla_x_hi[k];
+    weathervane_arr10[i] = ancilla_z[k];
+  }
+  for (int i = 11; i >= 0; i--) {
+    if (weathervane_arr12[i] != 0xff)
+      return;
+  }
+  ancilla_type[k] = 0;
+}
+
+void AncillaDraw_WeathervaneExplosionWoodDebris(int k) {  // 88d188
+  static const uint8 kWeathervane_Explode_Char[2] = {0x4e, 0x4f};
+  Point16U pt;
+  Ancilla_PrepOamCoord(k, &pt);
+  pt.y -= (int8)ancilla_z[k];
+  int i = ancilla_item_to_link[k];
+  if (sign8(i))
+    return;
+  Ancilla_SetOam(GetOamCurPtr() + (weathervane_var14 >> 2), pt.x, pt.y, kWeathervane_Explode_Char[i], 0x3c, 0);
+  weathervane_var14 += 4;
+}
+
+void Ancilla38_CutsceneDuck(int k) {  // 88d1d8
+  static const uint8 kTravelBirdIntro_Tab0[2] = {0x40, 0};
+  static const uint8 kTravelBirdIntro_Tab1[2] = {28, 60};
+
+  if (!(frame_counter & 31))
+    Ancilla_Sfx3_Pan(k, 0x1e);
+
+  if (sign8(--ancilla_arr3[k])) {
+    ancilla_arr3[k] = 3;
+    ancilla_K[k] ^= 1;
+  }
+
+  if (!--ancilla_aux_timer[k]) {
+    ancilla_aux_timer[k] = 1;
+    if (!ancilla_L[k]) {
+      if (!sign8(--ancilla_item_to_link[k])) {
+        ancilla_z_vel[k] += ancilla_step[k] ? 1 : -1;
+        if (abs8(ancilla_z_vel[k]) >= 12)
+          ancilla_step[k] ^= 1;
+        goto after_stuff;
+      }
+      ancilla_item_to_link[k] = 0;
+      ancilla_step[k] = 0;
+      ancilla_x_vel[k] = kTravelBirdIntro_Tab1[0];
+      ancilla_z_vel[k] = -16;
+      ancilla_L[k]++;
+      ancilla_step[k] = 3;
+    }
+    ancilla_x_vel[k] += (ancilla_step[k] & 1) == 0 ? 1 : -1;
+    uint8 absx = abs8(ancilla_x_vel[k]);
+    if (absx == 0 && ++ancilla_L[k] == 7)
+      ancilla_S[k] = 1;
+    if (absx >= kTravelBirdIntro_Tab1[ancilla_S[k]]) {
+      ancilla_step[k] ^= 3;
+    }
+    ancilla_dir[k] = sign8(ancilla_x_vel[k]) ? 2 : 3;
+    uint8 t = (uint8)(kTravelBirdIntro_Tab1[ancilla_S[k]] - absx) >> 1;
+    ancilla_z_vel[k] = (ancilla_step[k] & 2) ? -t : t;
+  }
+after_stuff:
+  Ancilla_MoveX(k);
+  Ancilla_MoveZ(k);
+  BYTE(flag_travel_bird) = kTravelBird_DmaStuffs[ancilla_K[k] + 1];
+  Point16U info;
+  Ancilla_PrepOamCoord(k, &info);
+  OamEnt *oam = GetOamCurPtr();
+  Ancilla_SetOam(oam, info.x + kTravelBird_Draw_X[0], info.y + (int8)ancilla_z[k] + kTravelBird_Draw_Y[0],
+                 kTravelBird_Draw_Char[0],
+                 kTravelBird_Draw_Flags[0] | 0x30 | kTravelBirdIntro_Tab0[ancilla_dir[k] & 1], 2);
+  oam++;
+  AncillaDraw_Shadow(oam, 1, info.x, info.y + 48, 0x30);
+  if (!sign16(info.x) && info.x >= 248) {
+    ancilla_type[k] = 0;
+    submodule_index = 0;
+    link_item_flute = 3;
+  }
+}
+
+void Ancilla23_LinkPoof(int k) {  // 88d3bc
+  if (sign8(--ancilla_aux_timer[k])) {
+    ancilla_aux_timer[k] = 7;
+    if (++ancilla_item_to_link[k] == 3) {
+      ancilla_type[k] = 0;
+      link_is_transforming = 0;
+      link_cant_change_direction = 0;
+      if (!ancilla_step[k]) {
+        link_animation_steps = 0;
+        link_visibility_status = 0;
+        link_is_bunny = link_is_bunny_mirror = BYTE(overworld_screen_index) & 0x40 ? 1 : 0;
+        if (link_is_bunny)
+          LoadGearPalettes_bunny();
+        else
+          LoadActualGearPalettes();
+      }
+      return;
+    }
+  }
+  MorphPoof_Draw(k);
+}
+
+void MorphPoof_Draw(int k) {  // 88d3fd
+  static const int8 kMorphPoof_X[12] = {0, 0, 0, 0, 0, 8, 0, 8, -4, 12, -4, 12};
+  static const int8 kMorphPoof_Y[12] = {0, 0, 0, 0, 0, 0, 8, 8, -4, -4, 12, 12};
+  static const uint8 kMorphPoof_Flags[12] = {0, 0xff, 0xff, 0xff, 0x40, 0, 0xc0, 0x80, 0, 0x40, 0x80, 0xc0};
+  static const uint8 kMorphPoof_Char[3] = {0x86, 0xa9, 0x9b};
+  static const uint8 kMorphPoof_Ext[3] = {2, 0, 0};
+  if (sort_sprites_setting && ancilla_floor[k] && (!flag_for_boomerang_in_place || !(frame_counter & 1))) {
+    oam_cur_ptr = 0x8d0;
+    oam_ext_cur_ptr = 0xa20 + (0xd0 >> 2);
+  }
+  Point16U info;
+  Ancilla_PrepOamCoord(k, &info);
+  OamEnt *oam = GetOamCurPtr();
+  int j = ancilla_item_to_link[k];
+  uint8 ext = kMorphPoof_Ext[j];
+  uint8 chr = kMorphPoof_Char[j];
+  for (int i = 0; i < 4; i++, oam++) {
+    Ancilla_SetOam(oam, info.x + kMorphPoof_X[j * 4 + i], info.y + kMorphPoof_Y[j * 4 + i], chr,
+                   kMorphPoof_Flags[j * 4 + i] | 4 | HIBYTE(oam_priority_value), ext);
+    if (ext == 2)
+      break;
+  }
+}
+
+void Ancilla40_DwarfPoof(int k) {  // 88d49a
+  if (sign8(--ancilla_aux_timer[k])) {
+    ancilla_aux_timer[k] = 7;
+    if (++ancilla_item_to_link[k] == 3) {
+      ancilla_type[k] = 0;
+      tagalong_var5 = 0;
+      return;
+    }
+  }
+  MorphPoof_Draw(k);
+}
+
+void Ancilla3F_BushPoof(int k) {  // 88d519
+  static const int8 kBushPoof_Draw_X[16] = {0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, -2, 10, -2, 10};
+  static const int8 kBushPoof_Draw_Y[16] = {0, 0, 8, 8, 0, 0, 8, 8, 0, 0, 8, 8, -2, -2, 10, 10};
+  static const uint8 kBushPoof_Draw_Char[16] = {0x86, 0x87, 0x96, 0x97, 0xa9, 0xa9, 0xa9, 0xa9, 0x8a, 0x8b, 0x9a, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b};
+  static const uint8 kBushPoof_Draw_Flags[16] = {0, 0, 0, 0, 0, 0x40, 0x80, 0xc0, 0, 0, 0, 0, 0xc0, 0x80, 0x40, 0};
+
+  if (ancilla_timer[k] == 0) {
+    ancilla_timer[k] = 7;
+    if (++ancilla_item_to_link[k] == 4) {
+      ancilla_type[k] = 0;
+      return;
+    }
+  }
+  Oam_AllocateFromRegionC(0x10);
+  Point16U pt;
+  Ancilla_PrepOamCoord(k, &pt);
+  OamEnt *oam = GetOamCurPtr();
+
+  int j = ancilla_item_to_link[k] * 4;
+  for (int i = 0; i < 4; i++, j++, oam++) {
+    Ancilla_SetOam(oam, pt.x + kBushPoof_Draw_X[j], pt.y + kBushPoof_Draw_Y[j],
+                   kBushPoof_Draw_Char[j], kBushPoof_Draw_Flags[j] | 4 | HIBYTE(oam_priority_value), 0);
+  }
+}
+
+void Ancilla26_SwordSwingSparkle(int k) {  // 88d65a
+  static const int8 kSwordSwingSparkle_X[48] = {
+    5,  10, -1,  5, 10, -4,  5, 10,  -4,  -4, -1,  -1,   0,   5,  -1,   0,
+    5,  14,  0,  5, 14, 14, -1, -1, -23, -27, -1, -23, -27, -22, -23, -27,
+    -22, -22, -1, -1, 32, 35, -1, 32,  35,  30, 32,  35,  30,  30,  -1,  -1,
+  };
+  static const int8 kSwordSwingSparkle_Y[48] = {
+    -22, -18, -1, -22, -18, -17, -22, -18, -17, -17, -1, -1, 35, 40, -1, 35,
+    40,  37, 35,  40,  37,  37,  -1,  -1,   2,   7, -1,  2,  7, 19,  2,  7,
+    19,  19, -1,  -1,   2,   7,  -1,   2,   7,  19,  2,  7, 19, 19, -1, -1,
+  };
+  static const uint8 kSwordSwingSparkle_Char[48] = {
+    0xb7, 0xb7, 0xff, 0x80, 0x80, 0xb7, 0x83, 0x83, 0x80, 0x83, 0xff, 0xff, 0xb7, 0xb7, 0xff, 0x80,
+    0x80, 0xb7, 0x83, 0x83, 0x80, 0x83, 0xff, 0xff, 0xb7, 0xb7, 0xff, 0x80, 0x80, 0xb7, 0x83, 0x83,
+    0x80, 0x83, 0xff, 0xff, 0xb7, 0xb7, 0xff, 0x80, 0x80, 0xb7, 0x83, 0x83, 0x80, 0x83, 0xff, 0xff,
+  };
+  static const uint8 kSwordSwingSparkle_Flags[48] = {
+    0,    0, 0xff,    0, 0,    0, 0x80, 0x80, 0, 0x80, 0xff, 0xff, 0,    0, 0xff,    0,
+    0,    0, 0x80, 0x80, 0, 0x80, 0xff, 0xff, 0,    0, 0xff,    0, 0,    0, 0x80, 0x80,
+    0, 0x80, 0xff, 0xff, 0,    0, 0xff,    0, 0,    0, 0x80, 0x80, 0, 0x80, 0xff, 0xff,
+  };
+  if (sign8(--ancilla_aux_timer[k])) {
+    ancilla_aux_timer[k] = 0;
+    if (++ancilla_item_to_link[k] == 4) {
+      ancilla_type[k] = 0;
+      return;
+    }
+  }
+  Ancilla_SetXY(k, link_x_coord, link_y_coord);
+
+  Point16U info;
+  Ancilla_PrepOamCoord(k, &info);
+
+  k = ancilla_item_to_link[k] * 3 + ancilla_dir[k] * 12;
+
+  OamEnt *oam = GetOamCurPtr();
+  for (int n = 2; n >= 0; n--, k++, oam++) {
+    uint8 chr = kSwordSwingSparkle_Char[k];
+    if (chr == 0xff)
+      continue;
+    Ancilla_SetOam(oam, info.x + kSwordSwingSparkle_X[k], info.y + kSwordSwingSparkle_Y[k],
+                   chr, kSwordSwingSparkle_Flags[k] | 0x4 | (oam_priority_value >> 8), 0);
+  }
+}
+
+void Ancilla2A_SpinAttackSparkleA(int k) {  // 88d7b2
+  static const uint8 kInitialSpinSpark_Timer[6] = {4, 2, 3, 3, 2, 1};
+  if (!submodule_index && sign8(--ancilla_aux_timer[k])) {
+    ancilla_aux_timer[k] = 0;
+    if (!ancilla_timer[k]) {
+      int j = ++ancilla_item_to_link[k];
+      ancilla_timer[k] = kInitialSpinSpark_Timer[j];
+      if (j == 5) {
+        if (ancilla_step[k])
+          AddSwordBeam(j);
+        else
+          SpinAttackSparkleA_TransmuteToNextSpark(k);
+        return;
+      }
+    }
+  }
+  if (!ancilla_item_to_link[k])
+    return;
+  SpinSpark_Draw(k, -1);
+}
+
+void SpinAttackSparkleA_TransmuteToNextSpark(int k) {  // 88d86d
+  static const uint8 kTransmuteSpinSpark_Arr[16] = {0x21, 0x20, 0x1f, 0x1e, 3, 2, 1, 0, 0x12, 0x11, 0x10, 0xf, 0x31, 0x30, 0x2f, 0x2e};
+  static const int8 kTransmuteSpinSpark_X[4] = {-3, 21, 25, -8};
+  static const int8 kTransmuteSpinSpark_Y[4] = {28, -2, 24, 6};
+
+  ancilla_type[k] = 0x2b;
+  int j = link_direction_facing * 2;
+  swordbeam_arr[0] = kTransmuteSpinSpark_Arr[j + 0];
+  swordbeam_arr[1] = kTransmuteSpinSpark_Arr[j + 1];
+  swordbeam_arr[2] = kTransmuteSpinSpark_Arr[j + 2];
+  swordbeam_arr[3] = swordbeam_var1 = kTransmuteSpinSpark_Arr[j + 3];
+  ancilla_aux_timer[k] = 2;
+  ancilla_item_to_link[k] = 0x4c;
+  ancilla_arr3[k] = 8;
+  ancilla_step[k] = 0;
+  ancilla_L[k] = 0;
+  ancilla_arr1[k] = 255;
+  swordbeam_var2 = 20;
+
+  swordbeam_temp_x = link_x_coord + 8;
+  swordbeam_temp_y = link_y_coord + 12;
+
+  j = link_direction_facing>>1;
+  Ancilla_SetXY(k,
+      link_x_coord + kTransmuteSpinSpark_X[j],
+      link_y_coord + kTransmuteSpinSpark_Y[j]);
+  Ancilla2B_SpinAttackSparkleB(k);
+}
+
+void Ancilla2B_SpinAttackSparkleB(int k) {  // 88d8fd
+  static const uint8 kSpinSpark_Char[4] = {0xd7, 0xb7, 0x80, 0x83};
+
+  if (ancilla_L[k]) {
+    SpinAttackSparkleB_Closer(k);
+    return;
+  }
+  uint8 flags = 2;
+  if (!submodule_index) {
+    uint8 t = (ancilla_item_to_link[k] -= 3);
+    if (t < 13) {
+      ancilla_aux_timer[k] = 1;
+      ancilla_L[k] = 1;
+      ancilla_item_to_link[k] = 0;
+      SpinAttackSparkleB_Closer(k);
+      return;
+    }
+    ancilla_step[k] = (t < 0x42) ? 3 : (t == 0x46) ? 1 : (t == 0x43) ? 2 : 0;
+    if (sign8(--ancilla_aux_timer[k])) {
+      flags = 4;
+      ancilla_aux_timer[k] = 2;
+    }
+  }
+  OamEnt *oam = GetOamCurPtr(), *oam_org = oam;
+  int i = ancilla_step[k];
+  do {
+    if (submodule_index == 0)
+      swordbeam_arr[i] = (swordbeam_arr[i] + 4) & 0x3f;
+    Point16U pt = Sparkle_PrepOamFromRadial(Ancilla_GetRadialProjection(swordbeam_arr[i], swordbeam_var2));
+    Ancilla_SetOam(oam, pt.x, pt.y, kSpinSpark_Char[i], flags | HIBYTE(oam_priority_value), 0);
+  } while (oam++, --i >= 0);
+
+  if (submodule_index == 0) {
+    if (!sign8(--ancilla_arr3[k]))
+      goto endif_2;
+
+    ancilla_arr3[k] = 0;
+    ancilla_arr1[k] = (ancilla_arr1[k] + 1) & 3;
+    if (ancilla_arr1[k] == 3)
+      swordbeam_var1 = (swordbeam_var1 + 9) & 0x3f;
+  }
+
+  uint8 t;
+
+  t = ancilla_arr1[k];
+  if (t != 3) {
+    static const uint8 kSpinSpark_Char2[3] = {0xb7, 0x80, 0x83};
+    Point16U pt = Sparkle_PrepOamFromRadial(Ancilla_GetRadialProjection(swordbeam_var1, swordbeam_var2));
+    Ancilla_SetOam(oam, pt.x, pt.y, kSpinSpark_Char2[t], 4 | HIBYTE(oam_priority_value), 0);
+  }
+endif_2:
+  if (ancilla_item_to_link[k] == 7)
+    bytewise_extended_oam[oam_org - oam_buf + 3] = 1;
+}
+
+Point16U Sparkle_PrepOamFromRadial(AncillaRadialProjection p) {  // 88da17
+  Point16U pt;
+  pt.y = (p.r2 ? -p.r0 : p.r0) + swordbeam_temp_y - 4 - BG2VOFS_copy2;
+  pt.x = (p.r6 ? -p.r4 : p.r4) + swordbeam_temp_x - 4 - BG2HOFS_copy2;
+  return pt;
+}
+
+void SpinAttackSparkleB_Closer(int k) {  // 88da4c
+  if (sign8(--ancilla_aux_timer[k])) {
+    ancilla_aux_timer[k] = 1;
+    if (++ancilla_item_to_link[k] == 3)
+      ancilla_type[k] = 0;
+  }
+  SpinSpark_Draw(k, 4);
+}
+
+void Ancilla30_ByrnaWindupSpark(int k) {  // 88db24
+  static const int8 kInitialCaneSpark_X[16] = {3, 1, 0, 0, 13, 16, 12, 12, 24, 7, -4, -10, -8, 9, 22, 26};
+  static const int8 kInitialCaneSpark_Y[16] = {5, 0, -3, -6, -8, -3, 12, 28, 5, 0, 8, 16, 5, 0, 8, 16};
+  static const int8 kInitialCaneSpark_Draw_X[16] = {-4, 0, 0, 0, -8, 0, -8, 0, -8, 0, -8, 0, -8, 0, -8, 0};
+  static const int8 kInitialCaneSpark_Draw_Y[16] = {-4, 0, 0, 0, -8, -8, 0, 0, -8, -8, 0, 0, -8, -8, 0, 0};
+  static const uint8 kInitialCaneSpark_Draw_Char[16] = {0x92, 0xff, 0xff, 0xff, 0x8c, 0x8c, 0x8c, 0x8c, 0xd6, 0xd6, 0xd6, 0xd6, 0x93, 0x93, 0x93, 0x93};
+  static const uint8 kInitialCaneSpark_Draw_Flags[16] = {0x22, 0xff, 0xff, 0xff, 0x22, 0x62, 0xa2, 0xe2, 0x24, 0x64, 0xa4, 0xe4, 0x22, 0x62, 0xa2, 0xe2};
+
+  if (!submodule_index && sign8(--ancilla_aux_timer[k])) {
+    ancilla_aux_timer[k] = 1;
+    if (++ancilla_item_to_link[k] == 17) {
+      ByrnaWindupSpark_TransmuteToNormal(k);
+      return;
+    }
+  }
+  if (!ancilla_item_to_link[k])
+    return;
+
+  int j = player_handler_timer;
+  if (j == 2) {
+    uint8 a = ancilla_arr3[k] - 1;
+    if (sign8(a))
+      a = 0, j = 3;
+    ancilla_arr3[k] = a;
+  }
+  j += link_direction_facing * 2;
+  Ancilla_SetXY(k, link_x_coord + kInitialCaneSpark_X[j], link_y_coord + kInitialCaneSpark_Y[j]);
+  Point16U pt;
+  Ancilla_PrepOamCoord(k, &pt);
+
+  uint8 a = (ancilla_item_to_link[k] - 1) & 0xf;
+  j = 0;
+  if (a != 0)
+    j = 4 * ((a != 15) ? (a & 1) + 1 : 3);
+
+  OamEnt *oam = GetOamCurPtr();
+  for (int i = 0; i < 4; i++, j++) {
+    if (kInitialCaneSpark_Draw_Char[j] != 255) {
+      Ancilla_SetOam(oam, pt.x + kInitialCaneSpark_Draw_X[j], pt.y + kInitialCaneSpark_Draw_Y[j],
+                     kInitialCaneSpark_Draw_Char[j],
+                     kInitialCaneSpark_Draw_Flags[j] & ~0x30 | HIBYTE(oam_priority_value), 0);
+      oam++;
+    }
+  }
+}
+
+void ByrnaWindupSpark_TransmuteToNormal(int k) {  // 88dc21
+  static const uint8 kCaneSpark_Transmute_Tab[16] = {0x34, 0x33, 0x32, 0x31, 0x16, 0x15, 0x14, 0x13, 0x2a, 0x29, 0x28, 0x27, 0x10, 0xf, 0xe, 0xd};
+
+  ancilla_type[k] = 0x31;
+  int j = link_direction_facing << 1;
+  swordbeam_arr[0] = kCaneSpark_Transmute_Tab[j + 0];
+  swordbeam_arr[1] = kCaneSpark_Transmute_Tab[j + 1];
+  swordbeam_arr[2] = kCaneSpark_Transmute_Tab[j + 2];
+  swordbeam_arr[3] = kCaneSpark_Transmute_Tab[j + 3];
+  ancilla_aux_timer[k] = 0x17;
+  ancilla_G[k] = 0;
+  ancilla_item_to_link[k] = 0;
+  ancilla_arr3[k] = 8;
+  ancilla_step[k] = 0;
+  ancilla_L[k] = 0;
+  ancilla_arr1[k] = 2;
+  ancilla_timer[k] = 21;
+  swordbeam_var2 = 20;
+  Ancilla_Sfx3_Near(0x30);
+  Ancilla31_ByrnaSpark(k);
+}
+
+void Ancilla31_ByrnaSpark(int k) {  // 88dc70
+  static const uint8 kCaneSpark_Magic[3] = {4, 2, 1};
+
+  uint8 flags = 2;
+  if (submodule_index == 0) {
+    if (current_item_y != 13) {
+kill_me:
+      link_disable_sprite_damage = 0;
+      ancilla_type[k] = 0;
+      link_give_damage = 0;
+      return;
+    }
+    link_disable_sprite_damage = 1;
+    if (!--ancilla_aux_timer[k]) {
+      ancilla_aux_timer[k] = 1;
+      uint8 r0 = kCaneSpark_Magic[link_magic_consumption];
+      if (!link_magic_power || (uint8)(r0 = link_magic_power - r0) >= 0x80)
+        goto kill_me;
+
+      if (sign8(--ancilla_G[k])) {
+        ancilla_G[k] = 0x17;
+        link_magic_power = r0;
+      }
+      if (filtered_joypad_H & 0x40)
+        goto kill_me;
+    }
+    if (ancilla_step[k] != 3) {
+      uint8 a = ++ancilla_item_to_link[k];
+      ancilla_step[k] = (a >= 4) ? 3 : (a == 2) ? 1 : (a == 3) ? 2 : 0;
+    }
+    if (sign8(--ancilla_arr1[k])) {
+      ancilla_arr1[k] = 2;
+      flags = 4;
+    }
+  }
+
+  int z = (int8)link_z_coord;
+  if (z == -1)
+    z = 0;
+  swordbeam_temp_y = link_y_coord + 12 - z;
+  swordbeam_temp_x = link_x_coord + 8;
+  if (!ancilla_timer[k]) {
+    ancilla_timer[k] = 21;
+    Ancilla_Sfx3_Near(0x30);
+  }
+  OamEnt *oam = GetOamCurPtr();
+  int i = ancilla_step[k];
+  do {
+    static const uint8 kCaneSpark_Char[4] = {0xd7, 0xb7, 0x80, 0x83};
+    if (!submodule_index)
+      swordbeam_arr[i] = (swordbeam_arr[i] + 3) & 0x3f;
+    Point16U pt = Sparkle_PrepOamFromRadial(Ancilla_GetRadialProjection(swordbeam_arr[i], swordbeam_var2));
+    Ancilla_SetOam(oam, pt.x, pt.y, kCaneSpark_Char[i], flags | HIBYTE(oam_priority_value), 0);
+    Ancilla_SetXY(k, pt.x + BG2HOFS_copy2, pt.y + BG2VOFS_copy2);
+    ancilla_dir[k] = 0;
+    Ancilla_CheckSpriteCollision(k);
+  } while (oam++, --i >= 0);
+}
+
+void Ancilla_SwordBeam(int k) {  // 88ddc5
+  uint8 flags = 2;
+
+  if (!submodule_index) {
+    Ancilla_SetXY(k, swordbeam_temp_x, swordbeam_temp_y);
+    Ancilla_MoveX(k);
+    Ancilla_MoveY(k);
+    swordbeam_temp_x = Ancilla_GetX(k);
+    swordbeam_temp_y = Ancilla_GetY(k);
+
+    if ((ancilla_G[k]++ & 0xf) == 0) {
+      sound_effect_2 = Ancilla_CalculateSfxPan(k) | 1;
+    }
+
+    if (Ancilla_CheckSpriteCollision(k) >= 0 || Ancilla_CheckTileCollision(k)) {
+      static const int8 kSwordBeam_Yvel2[4] = {0, 0, -6, -6};
+      static const int8 kSwordBeam_Xvel2[4] = {-8, -10, 0, 0};
+      int j = ancilla_dir[k];
+      Ancilla_SetXY(k,
+          Ancilla_GetX(k) + kSwordBeam_Xvel2[j],
+          Ancilla_GetY(k) + kSwordBeam_Yvel2[j]);
+      ancilla_type[k] = 4;
+      ancilla_timer[k] = 7;
+      ancilla_numspr[k] = 0x10;
+      return;
+    }
+    if (sign8(--ancilla_aux_timer[k])) {
+      flags = 4;
+      ancilla_aux_timer[k] = 2;
+    }
+  }
+
+  OamEnt *oam = GetOamCurPtr();
+  uint8 s = ancilla_S[k];
+  for (int i = 3; i >= 0; i--, oam++) {
+    static const uint8 kSwordBeam_Char[4] = {0xd7, 0xb7, 0x80, 0x83};
+    if (submodule_index == 0)
+      swordbeam_arr[i] = (swordbeam_arr[i] + s) & 0x3f;
+    Point16U pt = Sparkle_PrepOamFromRadial(Ancilla_GetRadialProjection(swordbeam_arr[i], swordbeam_var2));
+    Ancilla_SetOam(oam, pt.x, pt.y, kSwordBeam_Char[i], flags | HIBYTE(oam_priority_value), 0);
+  }
+
+  if (submodule_index == 0) {
+    if (!sign8(--ancilla_arr3[k]))
+      goto endif_2;
+
+    ancilla_arr3[k] = 0;
+    ancilla_arr1[k] = (ancilla_arr1[k] + 1) & 3;
+    if (ancilla_arr1[k] == 3)
+      swordbeam_var1 = (swordbeam_var1 + s) & 0x3f;
+  }
+
+  uint8 t;
+
+  t = ancilla_arr1[k];
+  if (t != 3) {
+    static const uint8 kSwordBeam_Char2[3] = {0xb7, 0x80, 0x83};
+    Point16U pt = Sparkle_PrepOamFromRadial(Ancilla_GetRadialProjection(swordbeam_var1, swordbeam_var2));
+    Ancilla_SetOam(oam, pt.x, pt.y, kSwordBeam_Char2[t], 4 | HIBYTE(oam_priority_value), 0);
+  }
+endif_2:
+  oam -= 4;
+  for (int i = 0; i < 4; i++) {
+    if (oam[i].y != 0xf0)
+      return;
+  }
+  ancilla_type[k] = 0;
+}
+
+void Ancilla0D_SpinAttackFullChargeSpark(int k) {  // 88ddca
+  static const int8 kSwordFullChargeSpark_Y[4] = {-8, 27, 12, 12};
+  static const int8 kSwordFullChargeSpark_X[4] = {4, 4, -13, 20};
+  static const uint8 kSwordFullChargeSpark_Flags[4] = {0x20, 0x10, 0x30, 0x20};
+
+  ancilla_oam_idx[k] = Ancilla_AllocateOamFromRegion_A_or_D_or_F(k, 4);
+
+  if (!ancilla_timer[k]) {
+    ancilla_type[k] = 0;
+    return;
+  }
+
+  int j = link_direction_facing >> 1;
+
+  uint16 x = link_x_coord + kSwordFullChargeSpark_X[j] - BG2HOFS_copy2;
+  uint16 y = link_y_coord + kSwordFullChargeSpark_Y[j] - BG2VOFS_copy2;
+
+  oam_priority_value = kSwordFullChargeSpark_Flags[ancilla_floor[k]] << 8;
+  OamEnt *oam = GetOamCurPtr();
+  Ancilla_SetOam(oam, x, y, 0xd7, HIBYTE(oam_priority_value) | 2, 0);
+}
+
+void Ancilla27_Duck(int k) {  // 88dde8
+  CheckPlayerCollOut coll;
+  int j;
+
+  if (submodule_index)
+    goto endif_1;
+
+  if (ancilla_timer[k]) {
+    int xt = (enhanced_features0 & kFeatures0_ExtendScreen64) ? 0x40 : 0;
+    Ancilla_SetXY(k, BG2HOFS_copy2 - 16 - xt, link_y_coord - 8);
+    return;
+  }
+
+  if (sign8(--ancilla_G[k])) {
+    ancilla_G[k] = 0x28;
+    Ancilla_Sfx3_Pan(k, 0x1e);
+  }
+
+  if (ancilla_L[k] || ancilla_step[k] && (flag_unk1++, true)) {
+    ancilla_z_vel[k]--;
+    Ancilla_MoveZ(k);
+  }
+  Ancilla_MoveX(k);
+
+
+  if (ancilla_L[k]) {
+    uint16 x = Ancilla_GetX(k);
+    if (ancilla_step[k])
+      flag_unk1++;
+    if (!sign16(x) && x >= link_x_coord) {
+      if (ancilla_step[k]) {
+        ancilla_step[k] = 0;
+        link_visibility_status = 0;
+        tagalong_var5 = 0;
+        link_pose_for_item = 0;
+        ancilla_y_vel[k] = 0;
+        flag_is_link_immobilized = 0;
+        link_disable_sprite_damage = 0;
+        byte_7E03FD = 0;
+        countdown_for_blink = 144;
+        if (!((follower_indicator == 12 || follower_indicator == 13) && follower_dropped)) {
+          Follower_Initialize();
+        }
+      }
+    } else if ((uint16)(link_x_coord - x) < 48) {
+      j = 3;
+      goto endif_5;
+    }
+    goto endif_1;
+  }
+
+  if (!Ancilla_CheckLinkCollision(k, 1, &coll) || main_module_index == 15)
+    goto endif_1;
+
+  if (!player_is_indoors) {
+    if (link_player_handler_state == 8 || link_player_handler_state == 9 || link_player_handler_state == 10 ||
+        player_near_pit_state == 2 ||
+        (link_pose_for_item | related_to_hookshot | link_force_hold_sword_up | link_disable_sprite_damage) ||
+        (link_state_bits & 0x80))
+      goto endif_1;
+    for (int i = 4; i >= 0; i--) {
+      uint8 a = ancilla_type[i];
+      if (a == 0x2a || a == 0x1f || a == 0x30 || a == 0x31 || a == 0x41)
+        ancilla_type[i] = 0;
+    }
+    if (follower_indicator == 9) {
+      follower_indicator = 0;
+      tagalong_var5 = 0;
+    }
+  }
+  link_state_bits = 0;
+  link_picking_throw_state = 0;
+
+  bg1_x_offset = 0;
+  bg1_y_offset = 0;
+  Link_ResetProperties_A();
+  link_is_in_deep_water = 0;
+  link_need_for_pullforrupees_sprite = 0;
+  link_visibility_status = 12;
+  link_player_handler_state = 0;
+  link_pose_for_item = 1;
+  flag_is_link_immobilized = 1;
+  link_disable_sprite_damage = 1;
+  tagalong_var5 = 1;
+  ancilla_step[k] = 2;
+  flag_unk1++;
+  link_give_damage = 0;
+  if (player_is_indoors)
+    byte_7E03FD = player_is_indoors;
+endif_1:
+  if (sign8(--ancilla_arr3[k])) {
+    ancilla_arr3[k] = 3;
+    if (++ancilla_K[k] == 3)
+      ancilla_K[k] = 0;
+  }
+  j = ancilla_K[k];
+endif_5:
+  BYTE(flag_travel_bird) = kTravelBird_DmaStuffs[j];
+
+  Point16U info;
+  Ancilla_PrepOamCoord(k, &info);
+
+  OamEnt *oam = GetOamCurPtr();
+  int z = ancilla_z[k] ? ancilla_z[k] | ~0xff : 0;
+  int i = 0, n = ancilla_step[k] + 1;
+  do {
+    Ancilla_SetOam(oam, info.x + (int8)kTravelBird_Draw_X[i], info.y + z + (int8)kTravelBird_Draw_Y[i],
+                   kTravelBird_Draw_Char[i], kTravelBird_Draw_Flags[i] | 0x30, 2);
+    oam++;
+  } while (++i != n);
+
+  AncillaDraw_Shadow(oam, 1, info.x, info.y + 28, 0x30);
+  oam += 2;
+  if (ancilla_step[k])
+    AncillaDraw_Shadow(oam, 1, info.x - 7, info.y + 28, 0x30);
+
+  if (!sign16(info.x) && info.x >= 0x130) {
+    ancilla_type[k] = 0;
+    if (!ancilla_L[k] && ancilla_step[k]) {
+      submodule_index = 10;
+      saved_module_for_menu = main_module_index;
+      main_module_index = 14;
+    }
+  }
+}
+
+int AncillaAdd_SomariaBlock(uint8 type, uint8 y) {  // 88e078
+  int k = AncillaAdd_AddAncilla_Bank08(type, y);
+  if (k < 0)
+    return k;
+  for (int j = 4; j >= 0; j--) {
+    if (j == k || ancilla_type[j] != 0x2c)
+      continue;
+    if (j == flag_is_ancilla_to_pick_up - 1)
+      flag_is_ancilla_to_pick_up = 0;
+    AncillaAdd_ExplodingSomariaBlock(j);
+    ancilla_type[k] = 0;
+    dung_flag_somaria_block_switch = 0;
+    if (link_speed_setting == 0x12) {
+      bitmask_of_dragstate = 0;
+      link_speed_setting = 0;
+    }
+    return k;
+  }
+
+  Ancilla_Sfx3_Near(0x2a);
+  ancilla_step[k] = 0;
+  ancilla_y_vel[k] = 0;
+  ancilla_x_vel[k] = 0;
+  ancilla_item_to_link[k] = 0;
+  ancilla_aux_timer[k] = 0;
+  ancilla_arr3[k] = 0;
+  ancilla_arr1[k] = 0;
+  ancilla_H[k] = 0;
+  ancilla_G[k] = 12;
+  ancilla_timer[k] = 18;
+  ancilla_L[k] = 0;
+  ancilla_z[k] = 0;
+  ancilla_K[k] = 0;
+  ancilla_R[k] = 0;
+  ancilla_arr4[k] = 0;
+  ancilla_S[k] = 9;
+  ancilla_T[k] = 0;
+  ancilla_dir[k] = link_direction_facing >> 1;
+  if (Ancilla_CheckInitialTileCollision_Class2(k)) {
+    Ancilla_SetX(k, link_x_coord + 8);
+    Ancilla_SetY(k, link_y_coord + 16);
+  } else {
+    static const int8 kCaneOfSomaria_Y[4] = { -8, 31, 17, 17 };
+    static const int8 kCaneOfSomaria_X[4] = { 8, 8, -8, 23 };
+    int j = link_direction_facing >> 1;
+    Ancilla_SetX(k, link_x_coord + kCaneOfSomaria_X[j]);
+    Ancilla_SetY(k, link_y_coord + kCaneOfSomaria_Y[j]);
+    SomariaBlock_CheckForTransitTile(k);
+  }
+  return k;
+}
+
+void SomariaBlock_CheckForTransitTile(int k) {  // 88e191
+  static const int8 kSomariaTransitLine_X[12] = { -8, 0, 8, -8, 0, 8, -16, -16, -16, 16, 16, 16 };
+  static const int8 kSomariaTransitLine_Y[12] = { -16, -16, -16, 16, 16, 16, -8, 0, 8, -8, 0, 8 };
+  if (!dung_unk6)
+    return;
+  for (int j = 11; j >= 0; j--) {
+    uint16 x = Ancilla_GetX(k) + kSomariaTransitLine_X[j];
+    uint16 y = Ancilla_GetY(k) + kSomariaTransitLine_Y[j];
+    uint8 bak = ancilla_objprio[k];
+    Ancilla_CheckTileCollision_targeted(k, x, y);
+    ancilla_objprio[k] = bak;
+    if (ancilla_tile_attr[k] == 0xb6 || ancilla_tile_attr[k] == 0xbc) {
+      Ancilla_SetX(k, x);
+      Ancilla_SetY(k, y);
+      AncillaAdd_SomariaPlatformPoof(k);
+      return;
+    }
+  }
+}
+
+int Ancilla_CheckBasicSpriteCollision(int k) {  // 88e1f9
+  for (int j = 15; j >= 0; j--) {
+    if (((j ^ frame_counter) & 3 | sprite_pause[j] | sprite_hit_timer[j]) != 0)
+      continue;
+    if (sprite_state[j] < 9 || !(sprite_defl_bits[j] & 2) && ancilla_objprio[k])
+      continue;
+    if (ancilla_floor[k] != sprite_floor[j])
+      continue;
+    if (ancilla_type[k] == 0x2c && (sprite_type[j] == 0x1e || sprite_type[j] == 0x90))
+      continue;
+    if (Ancilla_CheckBasicSpriteCollision_Single(k, j))
+      return j;
+  }
+  return -1;
+}
+
+bool Ancilla_CheckBasicSpriteCollision_Single(int k, int j) {  // 88e23d
+  SpriteHitBox hb;
+  Ancilla_SetupBasicHitBox(k, &hb);
+  Sprite_SetupHitBox(j, &hb);
+  if (!CheckIfHitBoxesOverlap(&hb))
+    return false;
+  if (sprite_type[j] == 0x92 && sprite_C[j] < 3)
+    return true;
+  if (sprite_type[j] == 0x80 && sprite_delay_aux4[j] == 0) {
+    sprite_delay_aux4[j] = 24;
+    sprite_D[j] ^= 1;
+  }
+  if (sprite_ignore_projectile[j])
+    return false;
+
+  int x = Ancilla_GetX(k) - 8, y = Ancilla_GetY(k) - 8 - ancilla_z[k];
+  ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLocation(j, x, y, 80);
+  sprite_y_recoil[j] = ~pt.y;
+  sprite_x_recoil[j] = ~pt.x;
+  Ancilla_CheckDamageToSprite(j, ancilla_type[k]);
+  return true;
+}
+
+void Ancilla_SetupBasicHitBox(int k, SpriteHitBox *hb) {  // 88e2ca
+  int x = Ancilla_GetX(k) - 8;
+  hb->r0_xlo = x;
+  hb->r8_xhi = x >> 8;
+  int y = Ancilla_GetY(k) - 8 - ancilla_z[k];
+  hb->r1_ylo = y;
+  hb->r9_yhi = y >> 8;
+  hb->r2 = 15;
+  hb->r3 = 15;
+}
+
+void Ancilla2C_SomariaBlock(int k) {  // 88e365
+  if (!sign8(--ancilla_G[k]))
+    return;
+  ancilla_G[k] = 0;
+
+  if (ancilla_H[k])
+    goto label_1;
+  if (submodule_index == 0 || submodule_index == 8 || submodule_index == 16) {
+    Ancilla_HandleLiftLogic(k);
+  } else if (k + 1 == flag_is_ancilla_to_pick_up && ancilla_K[k] != 0) {
+    if (ancilla_K[k] != 3) {
+      Ancilla_LatchLinkCoordinates(k, 3);
+      Ancilla_LatchAltitudeAboveLink(k);
+      ancilla_K[k] = 3;
+    }
+    Ancilla_LatchCarriedPosition(k);
+  }
+  if (player_is_indoors) {
+    if (!ancilla_K[k] && !(link_state_bits & 0x80) && (ancilla_z[k] == 0 || ancilla_z[k] == 0xff)) {
+      if (dung_unk6) {
+        int j = frame_counter & 3;
+        do {
+          uint8 bak = ancilla_objprio[k];
+          uint16 x = Ancilla_GetX(k) + kSomarianBlock_Coll_X[j];
+          uint16 y = Ancilla_GetY(k) + kSomarianBlock_Coll_Y[j];
+          Ancilla_CheckTileCollision_targeted(k, x, y);
+          ancilla_objprio[k] = bak;
+          if (ancilla_tile_attr[k] == 0xb6 || ancilla_tile_attr[k] == 0xbc) {
+            Ancilla_SetXY(k, x, y);
+            AncillaAdd_SomariaPlatformPoof(k);
+            if (k + 1 == flag_is_ancilla_to_pick_up)
+              flag_is_ancilla_to_pick_up = 0;
+            return;
+          }
+        } while ((j += 4) < 12);
+      } else {
+        if (!SomariaBlock_CheckForSwitch(k) && (ancilla_z[k] == 0 || ancilla_z[k] == 0xff))
+          dung_flag_somaria_block_switch++;
+      }
+    } else {
+label_1:
+      if (flag_is_ancilla_to_pick_up == k + 1)
+        dung_flag_somaria_block_switch = 0;
+    }
+  }
+
+  uint16 old_y = Ancilla_LatchYCoordToZ(k);
+  uint8 s1a = ancilla_dir[k];
+  uint8 s1b = ancilla_objprio[k];
+  ancilla_objprio[k] = 0;
+  bool flag = Ancilla_CheckTileCollision_Class2(k);
+
+  if (player_is_indoors && ancilla_L[k] && ancilla_tile_attr[k] == 0x1c)
+    ancilla_T[k] = 1;
+
+label1:
+  if (flag && (!(link_state_bits & 0x80) || link_picking_throw_state)) {
+    if (!s1b && !ancilla_arr4[k] && ancilla_z[k]) {
+      ancilla_arr4[k] = 1;
+      int qq = (ancilla_dir[k] == 1) ? 16 : 4;
+      if (ancilla_y_vel[k])
+        ancilla_y_vel[k] = sign8(ancilla_y_vel[k]) ? qq : -qq;
+      if (ancilla_x_vel[k])
+        ancilla_x_vel[k] = sign8(ancilla_x_vel[k]) ? 4 : -4;
+      if (ancilla_dir[k] == 1 && ancilla_z[k]) {
+        ancilla_y_vel[k] = -4;
+        ancilla_L[k] = 2;
+      }
+    }
+  } else if (!(link_state_bits & 0x80) && (ancilla_z[k] == 0 || ancilla_z[k] == 0xff)) {
+    ancilla_dir[k] = 16;
+    uint8 bak0 = ancilla_objprio[k];
+    Ancilla_CheckTileCollision(k);
+    ancilla_objprio[k] = bak0;
+    uint8 a = ancilla_tile_attr[k];
+    if (a == 0x26) {
+      flag = true;
+      goto label1;
+    } else if (a == 0xc || a == 0x1c) {
+      if (dung_hdr_collision != 3) {
+        if (ancilla_floor[k] == 0 && ancilla_z[k] != 0 && ancilla_z[k] != 0xff)
+          ancilla_floor[k] = 1;
+      } else {
+        old_y = Ancilla_GetY(k) + dung_floor_y_vel;
+        Ancilla_SetX(k, Ancilla_GetX(k) + dung_floor_x_vel);
+      }
+    } else if (a == 0x20 || (a & 0xf0) == 0xb0 && a != 0xb6 && a != 0xbc) {
+      if (!(link_state_bits & 0x80)) {
+        if (k + 1 == flag_is_ancilla_to_pick_up)
+          flag_is_ancilla_to_pick_up = 0;
+        if (!ancilla_timer[k]) {
+          if (link_speed_setting == 18) {
+            link_speed_setting = 0;
+            bitmask_of_dragstate = 0;
+          }
+          ancilla_type[k] = 0;
+          return;
+        }
+      }
+    } else if (a == 8) {
+      if (k + 1 == flag_is_ancilla_to_pick_up)
+        flag_is_ancilla_to_pick_up = 0;
+      if (ancilla_timer[k] == 0) {
+        Ancilla_SetY(k, Ancilla_GetY(k) - 24);
+        Ancilla_TransmuteToSplash(k);
+        return;
+      }
+    } else if (a == 0x68 || a == 0x69 || a == 0x6a || a == 0x6b) {
+      Ancilla_ApplyConveyor(k);
+      old_y = Ancilla_GetY(k);
+    } else {
+      ancilla_timer[k] = (ancilla_L[k] | ancilla_H[k]) ? 0 : 2;
+    }
+  }
+  // endif_3
+  s1b |= ancilla_objprio[k];
+
+  if (!(link_state_bits & 0x80) && !--ancilla_S[k]) {
+    ancilla_S[k] = 1;
+    ancilla_objprio[k] = 0;
+    if (Ancilla_CheckBasicSpriteCollision(k) >= 0) {
+      ancilla_S[k] = 7;
+      if (++ancilla_step[k] == 5) {
+        SomariaBlock_FizzleAway(k);
+        return;
+      }
+    }
+  }
+  Ancilla_SetY(k, old_y);
+  ancilla_dir[k] = s1a;
+  ancilla_objprio[k] = s1b;
+
+  AncillaDraw_SomariaBlock(k);
+}
+
+void AncillaDraw_SomariaBlock(int k) {  // 88e61b
+  static const int8 kSomarianBlock_Draw_X[12] = {-8, 0, -8, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+  static const int8 kSomarianBlock_Draw_Y[12] = {-8, -8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+  static const uint8 kSomarianBlock_Draw_Flags[12] = {0, 0x40, 0x80, 0xc0, 0, 0x40, 0x80, 0xc0, 0, 0x40, 0x80, 0xc0};
+
+  if (k + 1 == flag_is_ancilla_to_pick_up && link_state_bits & 0x80 && ancilla_K[k] != 3 && link_direction_facing == 0) {
+    Ancilla_AllocateOamFromRegion_B_or_E(ancilla_numspr[k]);
+  } else if (sort_sprites_setting && ancilla_floor[k] && (ancilla_L[k] || k + 1 == flag_is_ancilla_to_pick_up && (link_state_bits & 0x80))) {
+    oam_cur_ptr = 0x8d0;
+    oam_ext_cur_ptr = 0xa20 + 0x34;
+  }
+
+  Point16U pt;
+  Ancilla_PrepAdjustedOamCoord(k, &pt);
+  OamEnt *oam = GetOamCurPtr(), *oam_org = oam;
+  int z = (int8)ancilla_z[k];
+  if (z != 0 && z != -1 && ancilla_K[k] != 3 && ancilla_objprio[k])
+    oam_priority_value = 0x3000;
+  pt.y -= z;
+  int j = ancilla_arr1[k] * 4;
+  int r8 = 0;
+  do {
+    Ancilla_SetOam_Safe(oam, pt.x + kSomarianBlock_Draw_X[j], pt.y + kSomarianBlock_Draw_Y[j], 0xe9,
+                        kSomarianBlock_Draw_Flags[j] & ~0x30 | 2 | HIBYTE(oam_priority_value), 0);
+    oam++;
+  } while (j++, ++r8 & 3);
+
+  if (SomarianBlock_CheckEmpty(oam_org)) {
+    dung_flag_somaria_block_switch = 0;
+    ancilla_type[k] = 0;
+    if (k + 1 == flag_is_ancilla_to_pick_up) {
+      flag_is_ancilla_to_pick_up = 0;
+      if (link_state_bits & 128)
+        link_state_bits = 0;
+    }
+  }
+}
+
+bool SomariaBlock_CheckForSwitch(int k) {  // 88e75c
+  static const int8 kSomarianBlock_CheckCover_X[4] = {0, 0, -4, 4};
+  static const int8 kSomarianBlock_CheckCover_Y[4] = {-4, 4, 0, 0};
+  dung_flag_somaria_block_switch = 0;
+  ancilla_arr24[k] = 0;
+  for (int j = 3; j >= 0; j--) {
+    uint16 y = Ancilla_GetY(k) + kSomarianBlock_CheckCover_Y[j];
+    uint16 x = Ancilla_GetX(k) + kSomarianBlock_CheckCover_X[j];
+    uint8 bak = ancilla_objprio[k];
+    Ancilla_CheckTileCollision_targeted(k, x, y);
+    ancilla_objprio[k] = bak;
+    uint8 a = ancilla_tile_attr[k];
+    if (a == 0x23 || a == 0x24 || a == 0x25 || a == 0x3b)
+      ancilla_arr24[k]++;
+  }
+  return ancilla_arr24[k] != 4;
+}
+
+void SomariaBlock_FizzleAway(int k) {  // 88e9b2
+  if (link_speed_setting == 18) {
+    bitmask_of_dragstate = 0;
+    link_speed_setting = 0;
+  }
+  dung_flag_somaria_block_switch = 0;
+  ancilla_type[k] = 0x2d;
+  ancilla_aux_timer[k] = 0;
+  ancilla_step[k] = 0;
+  ancilla_item_to_link[k] = 0;
+  ancilla_arr3[k] = 0;
+  ancilla_arr1[k] = 0;
+  ancilla_R[k] = 0;
+  if (k + 1 == flag_is_ancilla_to_pick_up) {
+    flag_is_ancilla_to_pick_up = 0;
+    link_state_bits &= 0x80;
+  }
+  Ancilla2D_SomariaBlockFizz(k);
+}
+
+void Ancilla2D_SomariaBlockFizz(int k) {  // 88e9e8
+  static const int8 kSomariaBlockFizzle_X[6] = {-4, -1, -8, 0, -6, -2};
+  static const int8 kSomariaBlockFizzle_Y[6] = {-4, -1, -4, -4, -4, -4};
+  static const uint8 kSomariaBlockFizzle_Char[6] = {0x92, 0xff, 0xf9, 0xf9, 0xf9, 0xf9};
+  static const uint8 kSomariaBlockFizzle_Flags[6] = {6, 0xff, 0x86, 0xc6, 0x86, 0xc6};
+  if (sign8(--ancilla_aux_timer[k])) {
+    ancilla_aux_timer[k] = 3;
+    if (++ancilla_item_to_link[k] == 3) {
+      ancilla_type[k] = 0;
+      return;
+    }
+  }
+  Point16U pt;
+  Ancilla_PrepAdjustedOamCoord(k, &pt);
+  OamEnt *oam = GetOamCurPtr();
+  uint8 z = ancilla_z[k];
+  if (z == 0xff)
+    z = 0;
+  int x = pt.x, y = pt.y - (int8)z;
+  int j = ancilla_item_to_link[k] * 2;
+  for (int i = 0; i < 2; i++, j++, oam++) {
+    if (kSomariaBlockFizzle_Char[j] != 0xff) {
+      Ancilla_SetOam(oam, x + kSomariaBlockFizzle_X[j], y + kSomariaBlockFizzle_Y[j],
+                     kSomariaBlockFizzle_Char[j],
+                     kSomariaBlockFizzle_Flags[j] & ~0x30 | HIBYTE(oam_priority_value), 0);
+    }
+  }
+}
+
+void Ancilla39_SomariaPlatformPoof(int k) {  // 88ea83
+  static const uint8 kSomarianPlatformPoof_Tab0[4] = {1, 0, 3, 2};
+  if (!sign8(--ancilla_aux_timer[k]))
+    return;
+  ancilla_type[k] = 0;
+  SpriteSpawnInfo info;
+  int x = Ancilla_GetX(k) & ~7 | 4, y = Ancilla_GetY(k) & ~7 | 4;
+  uint8 floor = ancilla_floor[k];
+  int j = Sprite_SpawnDynamically(k, 0xed, &info);  // wtf
+  if (j >= 0) {
+    player_on_somaria_platform = 0;
+    Sprite_SetX(j, x);
+    Sprite_SetY(j, y);
+
+    int pos = ((x & 0x1f8) >> 3) + ((y & 0x1f8) << 3) + (floor >= 1 ? 0x1000 : 0);
+
+    int t = 0;
+    if ((dung_bg2_attr_table[pos + XY(0, -1)] & 0xf0) != 0xb0) {
+      t += 1;
+      if ((dung_bg2_attr_table[pos + XY(0, 1)] & 0xf0) != 0xb0) {
+        t += 1;
+        if ((dung_bg2_attr_table[pos + XY(-1, 0)] & 0xf0) != 0xb0) {
+          t += 1;
+        }
+      }
+    }
+    sprite_D[j] = kSomarianPlatformPoof_Tab0[t];
+    sprite_floor[j] = 0;
+  } else {
+    AncillaDraw_SomariaBlock(k);
+  }
+}
+
+void Ancilla2E_SomariaBlockFission(int k) {  // 88eb3e
+  static const int8 kSomarianBlockDivide_X[16] = {-8, 0, -8, 0, -10, -10, 2, 2, -8, 0, -8, 0, -12, -12, 4, 4};
+  static const int8 kSomarianBlockDivide_Y[16] = {-10, -10, 2, 2, -8, 0, -8, 0, -12, -12, 4, 4, -8, 0, -8, 0};
+  static const uint8 kSomarianBlockDivide_Char[16] = {0xc6, 0xc6, 0xc6, 0xc6, 0xc4, 0xc4, 0xc4, 0xc4, 0xd2, 0xd2, 0xd2, 0xd2, 0xc5, 0xc5, 0xc5, 0xc5};
+  static const uint8 kSomarianBlockDivide_Flags[16] = {0xc6, 0x86, 0x46, 6, 0x46, 0xc6, 6, 0x86, 0xc6, 0x86, 0x46, 6, 0x46, 0xc6, 6, 0x86};
+
+  if (sign8(--ancilla_aux_timer[k])) {
+    ancilla_aux_timer[k] = 3;
+    if (++ancilla_item_to_link[k] == 2) {
+      ancilla_type[k] = 0;
+      SomariaBlock_SpawnBullets(k);
+      return;
+    }
+  }
+  Point16U pt;
+  Ancilla_PrepAdjustedOamCoord(k, &pt);
+  OamEnt *oam = GetOamCurPtr();
+
+  int8 z = ancilla_z[k] + (ancilla_K[k] == 3 && BYTE(link_z_coord) != 0xff ? BYTE(link_z_coord) : 0);
+  int j = ancilla_item_to_link[k] * 8;
+  for (int i = 0; i != 8; i++, j++, oam++) {
+    Ancilla_SetOam(oam, pt.x + kSomarianBlockDivide_X[j], pt.y + kSomarianBlockDivide_Y[j] - z,
+                   kSomarianBlockDivide_Char[j], kSomarianBlockDivide_Flags[j] & ~0x30 | HIBYTE(oam_priority_value), 0);
+  }
+}
+
+void Ancilla2F_LampFlame(int k) {  // 88ec13
+  static const uint8 kLampFlame_Draw_Char[12] = {0x9c, 0x9c, 0xff, 0xff, 0xa4, 0xa5, 0xb2, 0xb3, 0xe3, 0xf3, 0xff, 0xff};
+  static const int8 kLampFlame_Draw_Y[12] = {-3, 0, 0, 0, 0, 0, 8, 8, 0, 8, 0, 0};
+  static const int8 kLampFlame_Draw_X[12] = {4, 10, 0, 0, 1, 9, 2, 7, 4, 4, 0, 0};
+
+  Point16U pt;
+  Ancilla_PrepAdjustedOamCoord(k, &pt);
+  OamEnt *oam = GetOamCurPtr();
+  if (!ancilla_timer[k]) {
+    ancilla_type[k] = 0;
+    return;
+  }
+  int j = (ancilla_timer[k] & 0xf8) >> 1;
+  do {
+    if (kLampFlame_Draw_Char[j] != 0xff) {
+      Ancilla_SetOam(oam, pt.x + kLampFlame_Draw_X[j], pt.y + kLampFlame_Draw_Y[j], kLampFlame_Draw_Char[j], HIBYTE(oam_priority_value) | 2, 0);
+      oam++;
+    }
+  } while (++j & 3);
+}
+
+void Ancilla41_WaterfallSplash(int k) {  // 88ecaf
+  if (!Ancilla_CheckForEntranceTrigger(player_is_indoors ? 0 : 1)) {
+    ancilla_type[k] = 0;
+    return;
+  }
+
+  if (!submodule_index && !(frame_counter & 7))
+    Ancilla_Sfx2_Near(0x1c);
+
+  draw_water_ripples_or_grass = 1;
+  if (!sign8(link_animation_steps - 6))
+    link_animation_steps -= 6;
+
+  if (!ancilla_timer[k]) {
+    ancilla_timer[k] = 2;
+    ancilla_item_to_link[k] = (ancilla_item_to_link[k] + 1) & 3;
+  }
+
+  if (player_is_indoors && BYTE(link_y_coord) < 0x38) {
+    Ancilla_SetY(k, 0xd38);
+  } else {
+    Ancilla_SetY(k, link_y_coord);
+  }
+  Ancilla_SetX(k, link_x_coord);
+
+  static const int8 kWaterfallSplash_X[8] = {0, 0, -4, 4, -7, 7, -9, 17};
+  static const int8 kWaterfallSplash_Y[8] = {-4, 0, -5, -5, -3, -3, 12, 12};
+  static const uint8 kWaterfallSplash_Char[8] = {0xc0, 0xff, 0xac, 0xac, 0xae, 0xae, 0xbf, 0xbf};
+  static const uint8 kWaterfallSplash_Flags[8] = {0x84, 0xff, 0x84, 0xc4, 0x84, 0xc4, 0x84, 0xc4};
+  static const uint8 kWaterfallSplash_Ext[8] = {2, 0xff, 2, 2, 2, 2, 0, 0};
+
+  Point16U pt;
+  Ancilla_PrepAdjustedOamCoord(k, &pt);
+  OamEnt *oam = GetOamCurPtr();
+
+  uint8 z = link_z_coord;
+  pt.y -= (sign8(z) ? 0 : z);
+
+  int j = ancilla_item_to_link[k] * 2;
+  for (int i = 0; i != 2; i++, j++, oam++) {
+    if (kWaterfallSplash_Char[j] != 0xff) {
+      Ancilla_SetOam(oam, pt.x + kWaterfallSplash_X[j], pt.y + kWaterfallSplash_Y[j], kWaterfallSplash_Char[j],
+                     kWaterfallSplash_Flags[j] | 0x30, kWaterfallSplash_Ext[j]);
+    }
+  }
+}
+
+void Ancilla24_Gravestone(int k) {  // 88ee01
+  static const uint8 kAncilla_Gravestone_Char[4] = {0xc8, 0xc8, 0xd8, 0xd8};
+  static const uint8 kAncilla_Gravestone_Flags[4] = {0, 0x40, 0, 0x40};
+  Point16U pt;
+  Ancilla_PrepAdjustedOamCoord(k, &pt);
+  Oam_AllocateFromRegionB(16);
+  OamEnt *oam = GetOamCurPtr();
+  uint16 x = pt.x, y = pt.y;
+  for (int i = 0; i < 4; i++, oam++) {
+    Ancilla_SetOam(oam, x, y, kAncilla_Gravestone_Char[i], kAncilla_Gravestone_Flags[i] | 0x3d, 2);
+    x += 16;
+    if (i == 1)
+      x -= 32, y += 8;
+  }
+}
+
+void Ancilla34_SkullWoodsFire(int k) {  // 88ef9a
+  static const int8 kSkullWoodsFire_Draw_Y[4] = {0, 0, 0, -3};
+  static const uint8 kSkullWoodsFire_Draw_Char[4] = {0x8e, 0xa0, 0xa2, 0xa4};
+  static const uint8 kSkullWoodsFire_Draw_Ext[4] = {2, 2, 2, 0};
+  static const int8 kSkullWoodsFire_Draw2_X[24] = {
+    -13, -21, -10, -1,  -1,  -1, -16, -27, -4, -16, -6, -25, -16, -27, -4, -16,
+    -6, -25, -13, -5, -27, -11, -22,  -3,
+  };
+  static const int8 kSkullWoodsFire_Draw2_Y[24] = {
+    -31, -24, -22,  -1,  -1,  -1, -37, -32, -32, -23, -16, -14, -37, -32, -32, -23,
+    -16, -14, -35, -29, -28, -20, -13, -11,
+  };
+  static const uint8 kSkullWoodsFire_Draw2_Char[24] = {
+    0x86, 0x86, 0x86, 0xff, 0xff, 0xff, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x8a, 0x8a, 0x8a, 0x8a,
+    0x8a, 0x8a, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b,
+  };
+  static const uint8 kSkullWoodsFire_Draw2_Flags[24] = {
+    0, 0,    0,    0,    0,    0,    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0x80, 0x40, 0x40, 0x80, 0x40, 0,
+  };
+  static const uint8 kSkullWoodsFire_Draw2_Ext[24] = {
+    2, 2, 2, 2, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+    2, 2, 0, 0, 0, 0, 0, 0,
+  };
+  if (skullwoodsfire_var4 && ancilla_item_to_link[k] != 4 && sign8(--ancilla_aux_timer[k])) {
+    ancilla_aux_timer[k] = 5;
+    ancilla_item_to_link[k]++;
+  }
+  OamEnt *oam = GetOamCurPtr();
+  for(int k = 3; k >= 0; k--) {
+    if (sign8(--skullwoodsfire_var5[k])) {
+      skullwoodsfire_var5[k] = 5;
+      if (skullwoodsfire_var0[k] == 128)
+        goto endif_2;
+      if (++skullwoodsfire_var0[k] != 0) {
+        if (skullwoodsfire_var0[k] != 4)
+          goto endif_2;
+        skullwoodsfire_var0[k] = 0;
+      }
+      skullwoodsfire_var9 -= 8;
+      if (skullwoodsfire_var9 < 200 && skullwoodsfire_var4 != 1) {
+        skullwoodsfire_var4 = 1;
+        sound_effect_1 = kBombos_Sfx[(uint8)(0x98 - BG2HOFS_copy2) >> 5] | 0xc;
+      }
+      if (skullwoodsfire_var9 < 168)
+        skullwoodsfire_var0[k] = 128;
+      skullwoodsfire_x_arr[k] = skullwoodsfire_var11;
+      skullwoodsfire_y_arr[k] = skullwoodsfire_var9;
+      if (sound_effect_1 == 0)
+        sound_effect_1 = kBombos_Sfx[(uint8)(skullwoodsfire_var11 - BG2HOFS_copy2) >> 5] | 0x2a;
+    }
+endif_2:
+    if (!sign8(skullwoodsfire_var0[k])) {
+      int j = skullwoodsfire_var0[k];
+      uint16 x = skullwoodsfire_x_arr[k] - BG2HOFS_copy2;
+      uint16 y = skullwoodsfire_y_arr[k] - BG2VOFS_copy2 + kSkullWoodsFire_Draw_Y[j];
+      Ancilla_SetOam(oam, x, y, kSkullWoodsFire_Draw_Char[j], 0x32, kSkullWoodsFire_Draw_Ext[j]);
+      oam++;
+      if (kSkullWoodsFire_Draw_Ext[j] != 2) {
+        Ancilla_SetOam(oam, x + 8, y, kSkullWoodsFire_Draw_Char[j] + 1, 0x32, kSkullWoodsFire_Draw_Ext[j]);
+        oam++;
+      }
+    }
+  }
+
+  for (int i = 3; sign8(skullwoodsfire_var0[i]); ) {
+    if (--i < 0) {
+      ancilla_type[k] = 0;
+      return;
+    }
+  }
+
+  if (skullwoodsfire_var4 == 0 || ancilla_item_to_link[k] == 4)
+    return;
+
+  int j = ancilla_item_to_link[k] * 6;
+  for (int i = 0; i < 6; i++, j++) {
+    if (kSkullWoodsFire_Draw2_Char[j] != 0xff) {
+      Ancilla_SetOam(oam,
+          168 - BG2HOFS_copy2 + kSkullWoodsFire_Draw2_X[j],
+          200 - BG2VOFS_copy2 + kSkullWoodsFire_Draw2_Y[j],
+          kSkullWoodsFire_Draw2_Char[j],
+          kSkullWoodsFire_Draw2_Flags[j] | 0x32, kSkullWoodsFire_Draw2_Ext[j]);
+      oam++;
+    }
+  }
+}
+
+void Ancilla3A_BigBombExplosion(int k) {  // 88f18d
+  static const int8 kSuperBombExplode_X[9] = {0, -16, 0, 16, -24, 24, -16, 0, 16};
+  static const int8 kSuperBombExplode_Y[9] = {0, -16, -24, -16, 0, 0, 16, 24, 16};
+
+  if (!submodule_index && !--ancilla_arr3[k]) {
+    if (++ancilla_item_to_link[k] == 2)
+      Ancilla_Sfx2_Pan(k, 0xc);
+    if (ancilla_item_to_link[k] == 11) {
+      ancilla_type[k] = 0;
+      return;
+    }
+    ancilla_arr3[k] = kBomb_Tab0[ancilla_item_to_link[k]];
+  }
+  oam_priority_value = 0x3000;
+  uint8 numframes = kBomb_Draw_Tab2[ancilla_item_to_link[k]];
+  int j = kBomb_Draw_Tab0[ancilla_item_to_link[k]] * 6;
+  ancilla_step[k] = j * 2;
+
+  int yy = 0;
+  for (int i = 8; i >= 0; i--) {
+    uint16 x = Ancilla_GetX(k) + kSuperBombExplode_X[i] - BG2HOFS_copy2;
+    uint16 y = Ancilla_GetY(k) + kSuperBombExplode_Y[i] - BG2VOFS_copy2;
+    if (x < 256 && y < 256) {
+      Ancilla_AllocateOamFromRegion_A_or_D_or_F((uint8)(j * 2), 0x18); // wtf
+      OamEnt *oam = GetOamCurPtr() + yy;
+      yy += AncillaDraw_Explosion(oam, j, 0, numframes, 0x32, x, y) - oam;
+
+    }
+  }
+  if (ancilla_item_to_link[k] == 3 && ancilla_arr3[k] == 1) {
+    // Changed so this is reset elsewhere. Some code depends on the value 13.
+    uint8 old = (enhanced_features0 & kFeatures0_MiscBugFixes) ? follower_indicator : 0;
+    follower_indicator = 13;
+    Bomb_CheckForDestructibles(Ancilla_GetX(k), Ancilla_GetY(k), 0); // r14?
+    follower_indicator = old;
+  }
+}
+
+void RevivalFairy_Main() {  // 88f283
+  static const uint8 kAncilla_RevivalFaerie_Tab0[2] = {0, 0x90};
+  static const uint8 kAncilla_RevivalFaerie_Tab1[5] = {0x4b, 0x4d, 0x49, 0x47, 0x49};
+
+  int k = 0;
+  switch (ancilla_step[k]) {
+  case 0:
+    if (!--ancilla_arr3[k]) {
+      ancilla_arr3[k] = kAncilla_RevivalFaerie_Tab0[++ancilla_step[k]];
+      ancilla_K[k] = 0;
+      ancilla_z_vel[k] = 0;
+    } else {
+      Ancilla_MoveZ(k);
+    }
+    break;
+  case 1:
+    if (!--ancilla_arr3[k]) {
+      ancilla_step[k]++;
+      ancilla_z_vel[k] = 0;
+      ancilla_x_vel[k] = 0;
+    } else {
+      if (ancilla_arr3[k] == 0x4f || ancilla_arr3[k] == 0x8f) {
+        ancilla_L[k]++;
+        Ancilla_Sfx2_Pan(k, 0x31);
+      }
+      if (ancilla_L[k] != 0 && sign8(--ancilla_G[k])) {
+        ancilla_G[k] = 5;
+        if (++ancilla_item_to_link[k] == 3) {
+          ancilla_item_to_link[k] = 0;
+          ancilla_L[k] = 0;
+        }
+      }
+      ancilla_z_vel[k] += ancilla_K[k] ? 1 : -1;
+      if (abs8(ancilla_z_vel[k]) == 8)
+        ancilla_K[k] ^= 1;
+      Ancilla_MoveZ(k);
+    }
+    break;
+  case 2:
+    if (ancilla_z_vel[k] < 24)
+      ancilla_z_vel[k] += 1;
+    if (ancilla_x_vel[k] < 16)
+      ancilla_x_vel[k] += 1;
+    Ancilla_MoveX(k);
+    Ancilla_MoveZ(k);
+    break;
+  case 3:
+    goto skip_draw;
+  }
+
+  {
+    Oam_AllocateFromRegionC(12);
+    Point16U pt;
+    Ancilla_PrepOamCoord(k, &pt);
+    OamEnt *oam = GetOamCurPtr();
+    int t = (ancilla_step[k] == 1 && ancilla_L[k]) ? ancilla_item_to_link[k] + 1 : 0;
+    if (t != 0)
+      t += 1;
+    else
+      t = (frame_counter >> 2) & 1;
+    Ancilla_SetOam(oam, pt.x, pt.y - (int8)ancilla_z[k], kAncilla_RevivalFaerie_Tab1[t], 0x74, 2);
+    if (oam->y == 0xf0) {
+      ancilla_step[k] = 3;
+      submodule_index++;
+      TM_copy = mapbak_TM;
+    }
+  }
+skip_draw:
+  RevivalFairy_Dust();
+  RevivalFairy_MonitorHP();
+}
+
+void RevivalFairy_Dust() {  // 88f3cf
+  int k = 2;
+  if (ancilla_step[0] == 0 || ancilla_step[k] == 2 || !sign8(--ancilla_arr3[k]))
+    return;
+  ancilla_arr3[k] = 0;
+  if (!sort_sprites_setting)
+    Oam_AllocateFromRegionA(16);
+  else
+    Oam_AllocateFromRegionD(16);
+  if (sign8(--ancilla_aux_timer[k])) {
+    ancilla_aux_timer[k] = 3;
+    if (ancilla_item_to_link[k] == 9) {
+      ancilla_arr3[k] = 32;
+      ancilla_step[k]++;
+      ancilla_item_to_link[k] = 2;
+      return;
+    }
+    ancilla_arr25[k] = kMagicPowder_Tab0[30 + ++ancilla_item_to_link[k]];
+  }
+  Ancilla_MagicPowder_Draw(k);
+}
+
+void RevivalFairy_MonitorHP() {  // 88f430
+  if ((link_health_current == link_health_capacity || link_health_current == 0x38) && !is_doing_heart_animation) {
+    if (link_is_in_deep_water) {
+      link_some_direction_bits = 4;
+      link_player_handler_state = kPlayerState_Swimming;
+    } else if (link_is_bunny) {
+      link_player_handler_state = kPlayerState_PermaBunny;
+      link_is_bunny_mirror = 1;
+      //bugfix: dying as permabunny doesn't restore link palette during death animation
+      if (enhanced_features0 & kFeatures0_MiscBugFixes)
+        LoadGearPalettes_bunny();
+    } else {
+      link_player_handler_state = kPlayerState_Ground;
+    }
+    link_auxiliary_state = 0;
+    player_unk1 = 0;
+    link_var30d = 0;
+    some_animation_timer_steps = 0;
+    BYTE(link_z_coord) = 0;
+    link_incapacitated_timer = 0;
+    for(int i = 0; i < 5; i++)
+      ancilla_type[i] = 0;
+    return;
+  }
+  int k = 1;
+  if (!ancilla_step[k]) {
+    if (!--ancilla_arr3[k]) {
+      ancilla_arr3[k]++;
+      ancilla_z_vel[k] = 4;
+      Ancilla_MoveZ(k);
+      if (ancilla_z[k] >= 16) {
+        ancilla_step[k]++;
+        ancilla_z_vel[k] = 2;
+      }
+    }
+  } else {
+    if (sign8(--ancilla_K[k])) {
+      ancilla_K[k] = 32;
+      ancilla_z_vel[k] = -ancilla_z_vel[k];
+    }
+    Ancilla_MoveZ(k);
+  }
+  BYTE(link_z_coord) = ancilla_z[k];
+}
+
+void GameOverText_Draw() {  // 88f5c4
+  static const uint8 kGameOverText_Chars[16] = {0x40, 0x50, 0x41, 0x51, 0x42, 0x52, 0x43, 0x53, 0x44, 0x54, 0x45, 0x55, 0x43, 0x53, 0x46, 0x56};
+  oam_cur_ptr = 0x800;
+  oam_ext_cur_ptr = 0xa20;
+  OamEnt *oam = GetOamCurPtr();
+  int k = flag_for_boomerang_in_place;
+  do {
+    Ancilla_SetOam(oam + 0, Ancilla_GetX(k), 0x57, kGameOverText_Chars[k * 2 + 0], 0x3c, 0);
+    Ancilla_SetOam(oam + 1, Ancilla_GetX(k), 0x5f, kGameOverText_Chars[k * 2 + 1], 0x3c, 0);
+  } while (oam += 2, --k >= 0);
+}
+
+int AncillaAdd_AddAncilla_Bank08(uint8 type, uint8 y) {  // 88f631
+  int k = Ancilla_AllocInit(type, y);
+  if (k >= 0) {
+    ancilla_type[k] = type;
+    ancilla_numspr[k] = kAncilla_Pflags[type];
+    ancilla_floor[k] = link_is_on_lower_level;
+    ancilla_floor2[k] = link_is_on_lower_level_mirror;
+    ancilla_y_vel[k] = 0;
+    ancilla_x_vel[k] = 0;
+    ancilla_objprio[k] = 0;
+    ancilla_U[k] = 0;
+  }
+  return k;
+}
+
+void Ancilla_PrepOamCoord(int k, Point16U *info) {  // 88f671
+  oam_priority_value = kTagalongLayerBits[ancilla_floor[k]] << 8;
+  info->x = Ancilla_GetX(k) - BG2HOFS_copy2;
+  info->y = Ancilla_GetY(k) - BG2VOFS_copy2;
+}
+
+void Ancilla_PrepAdjustedOamCoord(int k, Point16U *info) {  // 88f6a4
+  oam_priority_value = kTagalongLayerBits[ancilla_floor[k]] << 8;
+  info->x = Ancilla_GetX(k) - BG2HOFS_copy;
+  info->y = Ancilla_GetY(k) - BG2VOFS_copy;
+}
+
+bool Ancilla_CheckLinkCollision(int k, int j, CheckPlayerCollOut *out) {  // 88f76b
+  static const int16 kAncilla_Coll_Yoffs[5] = {0, 8, 8, 8, 0};
+  static const int16 kAncilla_Coll_Xoffs[5] = {0, 8, 8, 8, 0};
+  static const int16 kAncilla_Coll_H[5] = {20, 20, 8, 28, 14};
+  static const int16 kAncilla_Coll_W[5] = {20, 3, 8, 24, 14};
+  static const int16 kAncilla_Coll_LinkYoffs[5] = {12, 12, 12, 12, 12};
+  static const int16 kAncilla_Coll_LinkXoffs[5] = {8, 8, 8, 12, 8};
+  uint16 x = Ancilla_GetX(k), y = Ancilla_GetY(k);
+  y += kAncilla_Coll_Yoffs[j] + (int8)ancilla_z[k];
+  x += kAncilla_Coll_Xoffs[j];
+  out->r4 = link_y_coord + kAncilla_Coll_LinkYoffs[j] - y;
+  out->r8 = abs16(out->r4);
+  out->r6 = link_x_coord + kAncilla_Coll_LinkXoffs[j] - x;
+  out->r10 = abs16(out->r6);
+  return out->r8 < kAncilla_Coll_H[j] && out->r10 < kAncilla_Coll_W[j];
+}
+
+bool Hookshot_CheckProximityToLink(int x, int y) {  // 88f7dc
+  return abs16(link_y_coord - BG2VOFS_copy2 + 12 - y - 4) < 12 &&
+         abs16(link_x_coord - BG2HOFS_copy2 +  8 - x - 4) < 12;
+}
+
+bool Ancilla_CheckForEntranceTrigger(int what) {  // 88f844
+  static const uint16 kEntranceTrigger_BaseY[4] = {0xd40, 0x210, 0xcfc, 0x100};
+  static const uint16 kEntranceTrigger_BaseX[4] = {0xd80, 0xe68, 0x130, 0xf10};
+  static const uint8 kEntranceTrigger_SizeY[4] = {11, 32, 16, 12};
+  static const uint8 kEntranceTrigger_SizeX[4] = {16, 16, 16, 16};
+  return
+    abs16(link_y_coord + 12 - kEntranceTrigger_BaseY[what]) < kEntranceTrigger_SizeY[what] &&
+    abs16(link_x_coord + 8 - kEntranceTrigger_BaseX[what]) < kEntranceTrigger_SizeX[what];
+}
+
+void AncillaDraw_Shadow(OamEnt *oam, int k, int x, int y, uint8 pal) {  // 88f897
+  static const uint8 kAncilla_DrawShadow_Char[14] = {0x6c, 0x6c, 0x28, 0x28, 0x38, 0xff, 0xc8, 0xc8, 0xd8, 0xd8, 0xd9, 0xd9, 0xda, 0xda};
+  static const uint8 kAncilla_DrawShadow_Flags[14] = {0x28, 0x68, 0x28, 0x68, 0x28, 0xff, 0x22, 0x22, 0x24, 0x64, 0x24, 0x64, 0x24, 0x64};
+
+  if (k == 2)
+    x += 4;
+  Ancilla_SetOam_Safe(oam, x, y,
+                      kAncilla_DrawShadow_Char[k * 2],
+                      kAncilla_DrawShadow_Flags[k * 2] & ~0x30 | pal, 0);
+  uint8 ch = kAncilla_DrawShadow_Char[k * 2 + 1];
+  if (ch != 0xff) {
+    x += 8;
+    Ancilla_SetOam_Safe(oam + 1, x, y, ch, kAncilla_DrawShadow_Flags[k * 2 + 1] & ~0x30 | pal, 0);
+  }
+}
+
+void Ancilla_AllocateOamFromRegion_B_or_E(uint8 size) {  // 88f90a
+  if (!sort_sprites_setting)
+    Oam_AllocateFromRegionB(size);
+  else
+    Oam_AllocateFromRegionE(size);
+}
+
+OamEnt *Ancilla_AllocateOamFromCustomRegion(OamEnt *oam) {  // 88f9ba
+  int a = (uint8 *)oam - g_ram;
+  if (sort_sprites_setting) {
+    if (a < 0x900) {
+      if (a < 0x8e0)
+        return oam;
+      a = 0x820;
+    } else {
+      if (a < 0x9d0)
+        return oam;
+      a = 0x940;
+    }
+  } else {
+    if (a < 0x990)
+      return oam;
+    a = 0x820;
+  }
+  oam_cur_ptr = a;
+  oam_ext_cur_ptr = ((a - 0x800) >> 2) + 0xa20;
+  return GetOamCurPtr();
+}
+
+OamEnt *HitStars_UpdateOamBufferPosition(OamEnt *oam) {  // 88fa00
+  int a = (uint8 *)oam - g_ram;
+  if (!sort_sprites_setting && a >= 0x9d0) {
+    oam_cur_ptr = 0x820;
+    oam_ext_cur_ptr = 0xa20 + (0x20 >> 2);
+    oam = GetOamCurPtr();
+  }
+  return oam;
+}
+
+bool Hookshot_ShouldIEvenBotherWithTiles(int k) {  // 88fa2d
+  uint16 x = Ancilla_GetX(k), y = Ancilla_GetY(k);
+  if (!player_is_indoors) {
+    if (!(ancilla_dir[k] & 2)) {
+      uint16 t = y - kOverworld_OffsetBaseY[BYTE(current_area_of_player) >> 1];
+      return (t < 4) || (t >= overworld_right_bottom_bound_for_scroll);
+    } else {
+      uint16 t = x - kOverworld_OffsetBaseX[BYTE(current_area_of_player) >> 1];
+      return (t < 6) || (t >= overworld_right_bottom_bound_for_scroll);
+    }
+  }
+  if (!(ancilla_dir[k] & 2)) {
+    return (y & 0x1ff) < 4 || (y & 0x1ff) >= 0x1e8 || (y & 0x200) != (link_y_coord & 0x200);
+  } else {
+    return (x & 0x1ff) < 4 || (x & 0x1ff) >= 0x1f0 || (x & 0x200) != (link_x_coord & 0x200);
+  }
+}
+
+AncillaRadialProjection Ancilla_GetRadialProjection(uint8 a, uint8 r8) {  // 88fadd
+  static const uint8 kRadialProjection_Tab0[64] = {
+    255, 254, 251, 244, 236, 225, 212, 197, 181, 162, 142, 120,  97,  74,  49,  25,
+      0,  25,  49,  74,  97, 120, 142, 162, 181, 197, 212, 225, 236, 244, 251, 254,
+    255, 254, 251, 244, 236, 225, 212, 197, 181, 162, 142, 120,  97,  74,  49,  25,
+      0,  25,  49,  74,  97, 120, 142, 162, 181, 197, 212, 225, 236, 244, 251, 254,
+  };
+  static const uint8 kRadialProjection_Tab2[64] = {
+      0,  25,  49,  74,  97, 120, 142, 162, 181, 197, 212, 225, 236, 244, 251, 254,
+    255, 254, 251, 244, 236, 225, 212, 197, 181, 162, 142, 120,  97,  74,  49,  25,
+      0,  25,  49,  74,  97, 120, 142, 162, 181, 197, 212, 225, 236, 244, 251, 254,
+    255, 254, 251, 244, 236, 225, 212, 197, 181, 162, 142, 120,  97,  74,  49,  25,
+  };
+  static const uint8 kRadialProjection_Tab1[64] = {
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  };
+  static const uint8 kRadialProjection_Tab3[64] = {
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  };
+  AncillaRadialProjection rv;
+  int p0 = kRadialProjection_Tab0[a] * r8;
+  int p1 = kRadialProjection_Tab2[a] * r8;
+  rv.r0 = (p0 >> 8) + (p0 >> 7 & 1);
+  rv.r2 = kRadialProjection_Tab1[a];
+  rv.r4 = (p1 >> 8) + (p1 >> 7 & 1);
+  rv.r6 = kRadialProjection_Tab3[a];
+  return rv;
+}
+
+int Ancilla_AllocateOamFromRegion_A_or_D_or_F(int k, uint8 size) {  // 88fb2b
+  if (sort_sprites_setting) {
+    if (ancilla_floor[k])
+      return Oam_AllocateFromRegionF(size);
+    else
+      return Oam_AllocateFromRegionD(size);
+  } else {
+    return Oam_AllocateFromRegionA(size);
+  }
+}
+
+void Ancilla_AddHitStars(uint8 a, uint8 y) {  // 898024
+  static const int8 kShovelHitStars_XY[12] = {21, -11, 21, 11, 3, -6, 21, 5, 16, -14, 16, 14};
+  static const int8 kShovelHitStars_X2[6] = {-3, 19, 2, 13, -6, 22};
+  int k = Ancilla_AddAncilla(a, y);
+  if (k >= 0) {
+    ancilla_item_to_link[k] = 0;
+    ancilla_aux_timer[k] = 2;
+    ancilla_arr3[k] = 1;
+    ancilla_y_vel[k] = 0;
+    ancilla_x_vel[k] = 0;
+    int j = a;
+    if (link_item_in_hand) {
+      j = (link_direction_facing >> 1) + 2;
+    } else if (link_position_mode) {
+      j = link_direction_facing != 4 ? 1 : 0;
+    }
+    ancilla_step[k] = j;
+    int t = link_x_coord + kShovelHitStars_X2[j];
+    ancilla_A[k] = t;
+    ancilla_B[k] = t >> 8;
+    Ancilla_SetXY(k, link_x_coord + kShovelHitStars_XY[j * 2 + 1], link_y_coord + kShovelHitStars_XY[j * 2 + 0]);
+  }
+}
+
+void AncillaAdd_Blanket(uint8 a) {  // 898091
+  int k = 0;
+  ancilla_type[k] = a;
+  ancilla_numspr[k] = kAncilla_Pflags[a];
+  ancilla_floor[k] = link_is_on_lower_level;
+  ancilla_floor2[k] = link_is_on_lower_level_mirror;
+  ancilla_objprio[k] = 0;
+  Ancilla_SetXY(k, 0x938, 0x2162);
+}
+
+void AncillaAdd_Snoring(uint8 a, uint8 y) {  // 8980c8
+  int k = Ancilla_AddAncilla(a, y);
+  if (k >= 0) {
+    ancilla_item_to_link[k] = 0;
+    ancilla_y_vel[k] = -8;
+    ancilla_aux_timer[k] = 7;
+    ancilla_x_vel[k] = 8;
+    ancilla_step[k] = 255;
+    Ancilla_SetXY(k, link_x_coord + 16, link_y_coord + 4);
+  }
+}
+
+void AncillaAdd_Bomb(uint8 a, uint8 y) {  // 89811f
+  static const int8 kBomb_Place_X0[4] = {8, 8, 0, 16};
+  static const int8 kBomb_Place_Y0[4] = {0, 24, 12, 12};
+  static const int8 kBomb_Place_X1[4] = {8, 8, -6, 22};
+  static const int8 kBomb_Place_Y1[4] = {4, 28, 12, 12};
+
+  int k = Ancilla_AddAncilla(a, y);
+  if (k < 0)
+    return;
+  if (link_item_bombs == 0) {
+    ancilla_type[k] = 0;
+    return;
+  }
+
+  if (--link_item_bombs == 0)
+    Hud_RefreshIcon();
+
+  ancilla_R[k] = 0;
+  ancilla_step[k] = 0;
+  ancilla_item_to_link[k] = 0;
+  ancilla_L[k] = 0;
+  ancilla_arr3[k] = kBomb_Tab0[0];
+
+  // These are not used directly by bombs, but used by door debris
+  ancilla_arr25[k] = 0;
+  ancilla_arr26[k] = 7;
+
+  ancilla_z[k] = 0;
+  ancilla_timer[k] = 8;
+  ancilla_dir[k] = link_direction_facing >> 1;
+  ancilla_T[k] = 0;
+  ancilla_arr23[k] = 0;
+  ancilla_arr22[k] = 0;
+  if (Ancilla_CheckInitialTileCollision_Class2(k)) {
+    int j = link_direction_facing >> 1;
+    Ancilla_SetXY(k, link_x_coord + kBomb_Place_X0[j], link_y_coord + kBomb_Place_Y0[j]);
+  } else {
+    int j = link_direction_facing >> 1;
+    Ancilla_SetXY(k, link_x_coord + kBomb_Place_X1[j], link_y_coord + kBomb_Place_Y1[j]);
+  }
+  sound_effect_1 = Link_CalculateSfxPan() | 0xb;
+}
+
+uint8 AncillaAdd_Boomerang(uint8 a, uint8 y) {  // 89820f
+  static const uint8 kBoomerang_Tab0[4] = {0x20, 0x18, 0x30, 0x28};
+  static const uint8 kBoomerang_Tab1[2] = {0x20, 0x60};
+  static const uint8 kBoomerang_Tab2[2] = {3, 2};
+  static const uint8 kBoomerang_Tab3[4] = {8, 4, 2, 1};
+  static const uint8 kBoomerang_Tab4[8] = {8, 4, 2, 1, 9, 5, 10, 6};
+  static const uint8 kBoomerang_Tab5[8] = {2, 3, 3, 2, 2, 3, 3, 3};
+  static const int8 kBoomerang_Tab6[8] = {-10, -8, -9, -9, -10, -8, -9, -9};
+  static const int8 kBoomerang_Tab7[8] = {-10, 11, 8, -8, -10, 11, 8, -8};
+  static const int8 kBoomerang_Tab8[8] = {-16, 6, 0, 0, -8, 8, -8, 8};
+  static const int8 kBoomerang_Tab9[8] = {0, 0, -8, 8, 8, 8, -8, -8};
+
+  int k = Ancilla_AddAncilla(a, y);
+  if (k < 0)
+    return 0;
+  ancilla_aux_timer[k] = 0;
+  ancilla_item_to_link[k] = 0;
+  ancilla_K[k] = 0;
+  ancilla_z[k] = 0;
+  ancilla_L[k] = ancilla_numspr[k];
+  flag_for_boomerang_in_place = 1;
+  int j = link_item_boomerang - 1;
+  ancilla_G[k] = j;
+  ancilla_step[k] = kBoomerang_Tab1[j];
+  ancilla_arr3[k] = kBoomerang_Tab2[j];
+
+  int s = ancilla_G[k] * 2 + ((joypad1H_last & 0xc) && (joypad1H_last & 3) ? 1 : 0);
+  uint8 r0 = kBoomerang_Tab0[s];
+  ancilla_H[k] = r0;
+
+  uint8 r1 = (joypad1H_last & 0xf) ? (joypad1H_last & 0xf) : kBoomerang_Tab3[link_direction_facing >> 1];
+  hookshot_effect_index = 0;
+
+  if (r1 & 0xc) {
+    ancilla_y_vel[k] = r1 & 8 ? -r0 : r0;
+    int i = sign8(ancilla_y_vel[k]) ? 0 : 1;
+    ancilla_dir[k] = i;
+    hookshot_effect_index = kBoomerang_Tab3[i];
+  }
+  ancilla_S[k] = 0;
+
+  if (r1 & 3) {
+    if (!(r1 & 2))
+      ancilla_S[k] = 1;
+    ancilla_x_vel[k] = (r1 & 2) ? -r0 : r0;
+    int i = sign8(ancilla_x_vel[k]) ? 2 : 3;
+    ancilla_dir[k] = i;
+    hookshot_effect_index |= kBoomerang_Tab3[i];
+  }
+
+  j = FindInByteArray(kBoomerang_Tab4, r1, 8);
+  if (j < 0)
+    j = 0;
+  ancilla_arr1[k] = kBoomerang_Tab5[j];
+  ancilla_arr23[k] = j << 1;
+  if (button_b_frames >= 9) {
+    ancilla_aux_timer[k]++;
+  } else {
+    if (s || !(joypad1H_last & 0xf))
+      j = link_direction_facing >> 1;
+  }
+  s = Ancilla_CheckInitialTile_A(k);
+  if (s < 0) {
+    if (ancilla_aux_timer[k]) {
+      Ancilla_SetXY(k, link_x_coord + kBoomerang_Tab9[j], link_y_coord + 8 + kBoomerang_Tab8[j]);
+    } else {
+      Ancilla_SetXY(k, link_x_coord + kBoomerang_Tab7[j], link_y_coord + 8 + kBoomerang_Tab6[j]);
+    }
+  } else {
+    ancilla_type[k] = 0;
+    flag_for_boomerang_in_place = 0;
+    if (ancilla_tile_attr[k] != 0xf0) {
+      sound_effect_1 = Ancilla_CalculateSfxPan(k) | 5;
+    } else {
+      sound_effect_1 = Ancilla_CalculateSfxPan(k) | 6;
+    }
+    AncillaAdd_BoomerangWallClink(k);
+  }
+  return s;
+}
+
+void AncillaAdd_TossedPondItem(uint8 a, uint8 xin, uint8 yin) {  // 898a32
+  static const uint8 kWishPondItem_X[76] = {
+    4, 4, 4, 4,  4, 0, 0, 4, 4, 4, 4, 4, 5, 0, 0, 0,
+    0, 0, 0, 4,  0, 4, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 11, 0, 0, 0, 2, 0, 5, 0, 0, 0, 0, 0,
+    0, 0, 0, 0,  4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 4, 4,  0, 4, 0, 0, 0, 4, 0, 0,
+  };
+  static const int8 kWishPondItem_Y[76] = {
+    -13, -13, -13, -13, -13, -12, -12, -13, -13, -12, -12, -12, -10, -12, -12, -12,
+    -12, -12, -12, -12, -12, -12, -12, -12, -12, -12, -12, -12, -12, -12, -12, -12,
+    -12, -12, -12, -13, -12, -12, -12, -12, -12, -12, -10, -12, -12, -12, -12, -12,
+    -12, -12, -12, -12, -12, -12, -12, -12, -12, -12, -12, -12, -12, -12, -12, -12,
+    -12, -12, -12, -12, -12, -12, -12, -12, -12, -13, -12, -12,
+  };
+
+  link_receiveitem_index = xin;
+  int k = Ancilla_AddAncilla(a, yin);
+  if (k >= 0) {
+    sound_effect_2 = Link_CalculateSfxPan() | 0x13;
+    uint8 sb = kReceiveItemGfx[xin];
+
+    if (sb != 0xff) {
+      if (sb == 0x20)
+        DecompressShieldGraphics();
+      DecodeAnimatedSpriteTile_variable(sb);
+    } else {
+      DecodeAnimatedSpriteTile_variable(0);
+    }
+    if (sb == 6)
+      DecompressSwordGraphics();
+
+    link_state_bits = 0x80;
+    link_picking_throw_state = 0;
+    link_direction_facing = 0;
+    link_animation_steps = 0;
+    ancilla_z_vel[k] = 20;
+    ancilla_y_vel[k] = -40;
+    ancilla_x_vel[k] = 0;
+    ancilla_z[k] = 0;
+    ancilla_timer[k] = 16;
+    ancilla_item_to_link[k] = link_receiveitem_index;
+    Ancilla_SetXY(k,
+      link_x_coord + kWishPondItem_X[link_receiveitem_index],
+      link_y_coord + kWishPondItem_Y[link_receiveitem_index]);
+  }
+}
+
+void AddHappinessPondRupees(uint8 arg) {  // 898ae0
+  int k = Ancilla_AddAncilla(0x42, 9);
+  if (k < 0)
+    return;
+  sound_effect_2 = Link_CalculateSfxPan() | 0x13;
+  uint8 sb = kReceiveItemGfx[0x35];
+  DecodeAnimatedSpriteTile_variable(sb);
+  link_state_bits = 0x80;
+  link_picking_throw_state = 0;
+  link_direction_facing = 0;
+  link_animation_steps = 0;
+
+  memset(happiness_pond_arr1, 0, 10);
+
+  static const int8 kHappinessPond_Start[4] = {0, 4, 4, 9};
+  static const int8 kHappinessPond_End[4] = {-1, 0, -1, -1};
+  static const int8 kHappinessPond_Xvel[10] = {0, -12, -6, 6, 12, -9, -5, 0, 5, 9};
+  static const int8 kHappinessPond_Yvel[10] = {-40, -40, -40, -40, -40, -32, -32, -32, -32, -32};
+  static const int8 kHappinessPond_Zvel[10] = {20, 20, 20, 20, 20, 16, 16, 16, 16, 16};
+
+  int j = kHappinessPond_Start[arg], j_end = kHappinessPond_End[arg];
+  k = 9;
+  do {
+    happiness_pond_arr1[k] = 1;
+    happiness_pond_z_vel[k] = kHappinessPond_Zvel[j];
+    happiness_pond_y_vel[k] = kHappinessPond_Yvel[j];
+    happiness_pond_x_vel[k] = kHappinessPond_Xvel[j];
+    happiness_pond_z[k] = 0;
+    happiness_pond_step[k] = 0;
+    happiness_pond_timer[k] = 16;
+    happiness_pond_item_to_link[k] = 53;
+    int x = link_x_coord + 4;
+    int y = link_y_coord - 12;
+    happiness_pond_x_lo[k] = x;
+    happiness_pond_x_hi[k] = x >> 8;
+    happiness_pond_y_lo[k] = y;
+    happiness_pond_y_hi[k] = y >> 8;
+  } while (--k, --j != j_end);
+}
+
+int AncillaAdd_FallingPrize(uint8 a, uint8 item_idx, uint8 yv) {  // 898bc1
+  static const int8 kFallingItem_Type[7] = {0x10, 0x37, 0x39, 0x38, 0x26, 0xf, 0x20};
+  static const int8 kFallingItem_G[7] = {0x40, 0, 0, 0, 0, -1, 0};
+  static const int16 kFallingItem_X[7] = {0x78, 0x78, 0x78, 0x78, 0x78, 0x80, 0x78};
+  static const int16 kFallingItem_Y[7] = {0x48, 0x78, 0x78, 0x78, 0x78, 0x68, 0x78};
+  static const uint8 kFallingItem_Z[7] = {0x60, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80};
+  link_receiveitem_index = item_idx;
+  int k = Ancilla_AddAncilla(a, yv);
+  if (k < 0)
+    return k;
+  uint8 item_type = kFallingItem_Type[item_idx];
+  ancilla_item_to_link[k] = item_type;
+  if (item_type == 0x10 || item_type == 0xf)
+    DecodeAnimatedSpriteTile_variable(kReceiveItemGfx[item_type]);
+
+  ancilla_z_vel[k] = -48;
+  ancilla_y_vel[k] = 0;
+  ancilla_x_vel[k] = 0;
+  ancilla_step[k] = 0;
+  ancilla_z[k] = kFallingItem_Z[item_idx];
+  ancilla_aux_timer[k] = 9;
+  ancilla_arr3[k] = 0;
+  ancilla_L[k] = 0;
+  ancilla_G[k] = kFallingItem_G[item_idx];
+  link_receiveitem_index = item_type;
+
+  int x, y;
+  if (item_idx != 0 && item_idx != 5) {
+    if (BYTE(cur_palace_index_x2) == 20) {
+      x = (link_x_coord & 0xff00) | 0x100;
+      y = (link_y_coord & 0xff00) | 0x100;
+    } else {
+      x = kFallingItem_X[item_idx] + BG2HOFS_copy2;
+      y = kFallingItem_Y[item_idx] + BG2VOFS_copy2;
+    }
+  } else {
+    x = link_x_coord;
+    y = kFallingItem_Y[item_idx] + BG2VOFS_copy2;
+  }
+  Ancilla_SetXY(k, x, y);
+  return k;
+}
+
+void AncillaAdd_ChargedSpinAttackSparkle() {  // 898cb1
+  for (int k = 9; k >= 0; k--) {
+    if (ancilla_type[k] == 0 || ancilla_type[k] == 0x3c) {
+      ancilla_type[k] = 13;
+      ancilla_floor[k] = link_is_on_lower_level;
+      ancilla_timer[k] = 6;
+      break;
+    }
+  }
+}
+
+void AncillaAdd_ExplodingWeatherVane(uint8 a, uint8 y) {  // 898d11
+  static const int8 kWeathervane_Tab4[12] = {8, 10, 9, 4, 11, 12, -10, -8, 4, -6, -10, -4};
+  static const int8 kWeathervane_Tab5[12] = {20, 22, 20, 20, 22, 20, 20, 22, 20, 22, 20, 20};
+  static const uint8 kWeathervane_Tab6[12] = {0xb0, 0xa3, 0xa0, 0xa2, 0xa0, 0xa8, 0xa0, 0xa0, 0xa8, 0xa1, 0xb0, 0xa0};
+  static const uint8 kWeathervane_Tab8[12] = {0, 2, 4, 6, 3, 8, 14, 8, 12, 7, 10, 8};
+  static const uint8 kWeathervane_Tab10[12] = {48, 18, 32, 20, 22, 24, 32, 20, 24, 22, 20, 32};
+
+  int k = Ancilla_AddAncilla(a, y);
+  if (k < 0)
+    return;
+
+  ancilla_aux_timer[k] = 10;
+  ancilla_G[k] = 128;
+  ancilla_step[k] = 0;
+  ancilla_arr3[k] = 0;
+  sound_effect_1 = 0;
+  music_control = 0xf2;
+  sound_effect_ambient = 0x17;
+
+  weathervane_var1 = 0;
+  weathervane_var2 = 0x280;
+
+  for (int i = 11; i >= 0; i--) {
+    weathervane_arr3[i] = 0;
+    weathervane_arr4[i] = kWeathervane_Tab4[i];
+    weathervane_arr5[i] = kWeathervane_Tab5[i];
+    weathervane_arr6[i] = kWeathervane_Tab6[i];
+    weathervane_arr7[i] = 7;
+    weathervane_arr8[i] = kWeathervane_Tab8[i];
+    weathervane_arr9[i] = 2;
+    weathervane_arr10[i] = kWeathervane_Tab10[i];
+    weathervane_arr11[i] = 1;
+    weathervane_arr12[i] = i & 1;
+  }
+}
+
+void AncillaAdd_CutsceneDuck(uint8 a, uint8 y) {  // 898d90
+  if (AncillaAdd_CheckForPresence(a))
+    return;
+  int k = Ancilla_AddAncilla(a, y);
+  if (k >= 0) {
+    ancilla_dir[k] = 2;
+    ancilla_arr3[k] = 3;
+    ancilla_step[k] = 0;
+    ancilla_aux_timer[k] = 32;
+    ancilla_item_to_link[k] = 116;
+    ancilla_z_vel[k] = 0;
+    ancilla_L[k] = 0;
+    ancilla_z[k] = 0;
+    ancilla_S[k] = 0;
+    Ancilla_SetXY(k, 0x200, 0x788);
+  }
+}
+
+void AncillaAdd_SomariaPlatformPoof(int k) {  // 898dd2
+  ancilla_type[k] = 0x39;
+  ancilla_aux_timer[k] = 7;
+  for (int j = 15; j >= 0; j--) {
+    if (sprite_type[j] == 0xed) {
+      sprite_state[j] = 0;
+      player_on_somaria_platform = 0;
+    }
+  }
+  Player_TileDetectNearby();
+}
+
+int AncillaAdd_SuperBombExplosion(uint8 a, uint8 y) {  // 898df9
+  int k = Ancilla_AddAncilla(a, y);
+  if (k >= 0) {
+    ancilla_R[k] = 0;
+    ancilla_step[k] = 0;
+    ancilla_arr25[k] = 0;
+    ancilla_L[k] = 0;
+    ancilla_arr3[k] = kBomb_Tab0[1];
+    ancilla_item_to_link[k] = 1;
+    int j = WORD(tagalong_var2);
+    int y = tagalong_y_lo[j] | tagalong_y_hi[j] << 8;
+    int x = tagalong_x_lo[j] | tagalong_x_hi[j] << 8;
+    Ancilla_SetXY(k, x + 8, y + 16);
+  }
+  return k;
+}
+
+void ConfigureRevivalAncillae() {  // 898e4e
+  link_dma_var5 = 80;
+  int k = 0;
+
+  ancilla_arr3[k] = 64;
+  ancilla_step[k] = 0;
+  ancilla_z_vel[k] = 8;
+  ancilla_L[k] = 0;
+  ancilla_G[k] = 5;
+  ancilla_item_to_link[k] = 0;
+  ancilla_K[k] = 0;
+  Ancilla_SetXY(k, link_x_coord, link_y_coord);
+  ancilla_z[k] = 0;
+  k += 1;
+
+  ancilla_z[k] = 0;
+  ancilla_arr3[k] = 240;
+  ancilla_step[k] = 0;
+  ancilla_K[k] = 0;
+  k += 1;
+
+  ancilla_item_to_link[k] = 2;
+  ancilla_aux_timer[k] = 3;
+  ancilla_arr3[k] = 8;
+  ancilla_step[k] = 0;
+  ancilla_dir[k] = 3;
+  ancilla_arr25[k] = kMagicPowder_Tab0[30 + ancilla_item_to_link[k]];
+
+  Ancilla_SetXY(k, link_x_coord + 20, link_y_coord + 2);
+}
+
+void AncillaAdd_LampFlame(uint8 a, uint8 y) {  // 898f1c
+  static const int8 kLampFlame_X[4] = {0, 0, -20, 18};
+  static const int8 kLampFlame_Y[4] = {-16, 24, 4, 4};
+  int k = Ancilla_AddAncilla(a, y);
+  if (k >= 0) {
+    ancilla_item_to_link[k] = 0;
+    ancilla_aux_timer[k] = 0;
+    ancilla_timer[k] = 23;
+    int j = link_direction_facing >> 1;
+    ancilla_dir[k] = j;
+    Ancilla_SetXY(k, link_x_coord + kLampFlame_X[j], link_y_coord + kLampFlame_Y[j]);
+    sound_effect_1 = Ancilla_CalculateSfxPan(k) | 42;
+  }
+}
+
+void AncillaAdd_MSCutscene(uint8 a, uint8 y) {  // 898f7c
+  int k = Ancilla_AddAncilla(a, y);
+  if (k >= 0) {
+    ancilla_item_to_link[k] = 0;
+    ancilla_aux_timer[k] = 2;
+    ancilla_timer[k] = 64;
+    Ancilla_SetXY(k, link_x_coord + 8, link_y_coord - 8);
+  }
+}
+
+void AncillaAdd_DashDust(uint8 a, uint8 y) {  // 898fba
+  AddDashingDustEx(a, y, 1);
+}
+
+void AncillaAdd_DashDust_charging(uint8 a, uint8 y) {  // 898fc1
+  AddDashingDustEx(a, y, 0);
+}
+
+void AncillaAdd_BlastWallFireball(uint8 a, uint8 y, int r4) {  // 899031
+  static const int8 kBlastWall_XY[32] = {
+    -64, 0, -22,  42, -38,  38, -42,  22, 0,  64,  22,  42,  38,  38,  42,  22,
+    64, 0,  22, -42,  38, -38,  42, -22, 0, -64, -22, -42, -38, -38, -42, -22,
+  };
+  for (int k = 10; k != 4; k--) {
+    if (ancilla_type[k] == 0) {
+      ancilla_type[k] = 0x32;
+      ancilla_floor[k] = link_is_on_lower_level;
+      blastwall_var12[k] = 16;
+      int j = frame_counter & 15;
+      ancilla_y_vel[k] = kBlastWall_XY[j * 2 + 0];
+      ancilla_x_vel[k] = kBlastWall_XY[j * 2 + 1];
+      Ancilla_SetXY(k, blastwall_var11[r4] + 16, blastwall_var10[r4] + 8);
+      return;
+    }
+  }
+
+}
+
+int AncillaAdd_Arrow(uint8 a, uint8 ax, uint8 ay, uint16 xcoord, uint16 ycoord) {  // 8990a4
+  static const int8 kShootBow_X[4] = {4, 4, 0, 4};
+  static const int8 kShootBow_Y[4] = {-4, 3, 4, 4};
+  static const int8 kShootBow_Xvel[4] = {0, 0, -48, 48};
+  static const int8 kShootBow_Yvel[4] = {-48, 48, 0, 0};
+
+  scratch_0 = ycoord;
+  scratch_1 = xcoord;
+  BYTE(index_of_interacting_tile) = ax;
+
+  if (AncillaAdd_CheckForPresence(a))
+    return -1;
+
+  int k = AncillaAdd_ArrowFindSlot(a, ay);
+
+  if (k >= 0) {
+    sound_effect_1 = Link_CalculateSfxPan() | 7;
+    ancilla_H[k] = 0;
+    ancilla_item_to_link[k] = 8;
+    int j = ax >> 1;
+    ancilla_dir[k] = j | 4;
+    ancilla_y_vel[k] = kShootBow_Yvel[j];
+    ancilla_x_vel[k] = kShootBow_Xvel[j];
+    Ancilla_SetXY(k, xcoord + kShootBow_X[j], ycoord + 8 +  kShootBow_Y[j]);
+  }
+  return k;
+}
+
+void AncillaAdd_BunnyPoof(uint8 a, uint8 y) {  // 899102
+  int k = Ancilla_AddAncilla(a, y);
+  if (k >= 0) {
+    link_visibility_status = 0xc;
+    ancilla_step[k] = 0;
+    if (!link_is_bunny_mirror)
+      sound_effect_1 = Link_CalculateSfxPan() | 0x14;
+    else
+      sound_effect_1 = Link_CalculateSfxPan() | 0x15;
+
+    ancilla_item_to_link[k] = 0;
+    ancilla_aux_timer[k] = 7;
+    Ancilla_SetXY(k, link_x_coord, link_y_coord + 4);
+  }
+}
+
+void AncillaAdd_CapePoof(uint8 a, uint8 y) {  // 89912c
+  int k = Ancilla_AddAncilla(a, y);
+  if (k >= 0) {
+    ancilla_step[k] = 1;
+    link_is_transforming = 1;
+    link_cant_change_direction |= 1;
+    link_direction = 0;
+    link_direction_last = 0;
+    ancilla_item_to_link[k] = 0;
+    ancilla_aux_timer[k] = 7;
+    Ancilla_SetXY(k, link_x_coord, link_y_coord + 4);
+  }
+}
+
+void AncillaAdd_DwarfPoof(uint8 ain, uint8 yin) {  // 89915f
+  int k = Ancilla_AddAncilla(ain, yin);
+  if (k < 0)
+    return;
+  if (follower_indicator == 8)
+    sound_effect_1 = Link_CalculateSfxPan() | 0x14;
+  else
+    sound_effect_1 = Link_CalculateSfxPan() | 0x15;
+
+  ancilla_item_to_link[k] = 0;
+  ancilla_step[k] = 0;
+  ancilla_aux_timer[k] = 7;
+  tagalong_var5 = 1;
+  int j = tagalong_var2;
+  int x = tagalong_x_lo[j] | tagalong_x_hi[j] << 8;
+  int y = tagalong_y_lo[j] | tagalong_y_hi[j] << 8;
+  Ancilla_SetXY(k, x, y + 4);
+}
+
+void AncillaAdd_BushPoof(uint16 x, uint16 y) {  // 8991c3
+  if (!(link_item_in_hand & 0x40))
+    return;
+  int k = Ancilla_AddAncilla(0x3f, 4);
+  if (k >= 0) {
+    ancilla_item_to_link[k] = 0;
+    ancilla_timer[k] = 7;
+    sound_effect_1 = Link_CalculateSfxPan() | 21;
+    Ancilla_SetXY(k, x, y - 2);
+  }
+}
+
+void AncillaAdd_EtherSpell(uint8 a, uint8 y) {  // 8991fc
+  int k = Ancilla_AddAncilla(a, y);
+  if (k >= 0) {
+    ancilla_item_to_link[k] = 0;
+    ancilla_arr25[k] = 0;
+    ancilla_step[k] = 0;
+    flag_custom_spell_anim_active = 1;
+    ancilla_aux_timer[k] = 2;
+    ancilla_arr3[k] = 3;
+    ancilla_y_vel[k] = 127;
+    ether_var2 = 40;
+    load_chr_halfslot_even_odd = 9;
+    ether_var1 = 0x40;
+    sound_effect_2 = Link_CalculateSfxPan() | 0x26;
+    for(int i = 0; i < 8; i++)
+      ether_arr1[i] = i * 8;
+    ether_y = link_y_coord;
+    uint16 y = BG2VOFS_copy2 - 16;
+    ether_y_adjusted = y & 0xf0;
+    ether_x = link_x_coord;
+    ether_x2 = ether_x + 8;
+    ether_y2 = link_y_coord - 16;
+    ether_y3 = ether_y2 + 0x24;
+    Ancilla_SetXY(k, link_x_coord, y);
+  }
+}
+
+void AncillaAdd_VictorySpin() {  // 8992ac
+  if ((link_sword_type + 1 & 0xfe) != 0) {
+    int k = Ancilla_AddAncilla(0x3b, 0);
+    if (k >= 0) {
+      ancilla_item_to_link[k] = 0;
+      ancilla_arr3[k] = 1;
+      ancilla_aux_timer[k] = 34;
+    }
+  }
+}
+
+void AncillaAdd_MagicPowder(uint8 a, uint8 y) {  // 8992f0
+  static const int8 kMagicPower_X[4] = {-2, -2, -12, 12};
+  static const int8 kMagicPower_Y[4] = {0, 20, 16, 16};
+  static const int8 kMagicPower_X1[4] = {10, 10, -8, 28};
+  static const int8 kMagicPower_Y1[4] = {1, 40, 22, 22};
+
+  int k = Ancilla_AddAncilla(a, y);
+  if (k >= 0) {
+    ancilla_item_to_link[k] = 0;
+    ancilla_z[k] = 0;
+    ancilla_aux_timer[k] = 1;
+    link_dma_var5 = 80;
+    int j = link_direction_facing >> 1;
+    ancilla_dir[k] = j;
+    ancilla_arr25[k] = kMagicPowder_Tab0[j * 10];
+    Ancilla_SetXY(k, link_x_coord + kMagicPower_X[j], link_y_coord + kMagicPower_Y[j]);
+    Ancilla_CheckTileCollision(k);
+    byte_7E0333 = ancilla_tile_attr[k];
+    if (current_item_active == 9) {
+      ancilla_type[k] = 0;
+      return;
+    }
+    sound_effect_1 = Link_CalculateSfxPan() | 0xd;
+    Ancilla_SetXY(k, link_x_coord + kMagicPower_X1[j], link_y_coord + kMagicPower_Y1[j]);
+  }
+}
+
+void AncillaAdd_WallTapSpark(uint8 a, uint8 y) {  // 899395
+  static const int8 kWallTapSpark_X[4] = {11, 10, -12, 29};
+  static const int8 kWallTapSpark_Y[4] = {-4, 32, 17, 17};
+  int k = Ancilla_AddAncilla(a, y);
+  if (k >= 0) {
+    ancilla_item_to_link[k] = 5;
+    ancilla_aux_timer[k] = 1;
+    int i = link_direction_facing >> 1;
+    Ancilla_SetXY(k, link_x_coord + kWallTapSpark_X[i], link_y_coord + kWallTapSpark_Y[i]);
+  }
+}
+
+void AncillaAdd_SwordSwingSparkle(uint8 a, uint8 y) {  // 8993c2
+  int k = Ancilla_AddAncilla(a, y);
+  if (k >= 0) {
+    ancilla_item_to_link[k] = 0;
+    ancilla_aux_timer[k] = 1;
+    ancilla_dir[k] = link_direction_facing >> 1;
+    Ancilla_SetXY(k, link_x_coord, link_y_coord);
+  }
+}
+
+void AncillaAdd_DashTremor(uint8 a, uint8 y) {  // 8993f3
+  static const uint8 kAddDashTremor_Dir[4] = {2, 2, 0, 0};
+  static const uint8 kAddDashTremor_Tab[2] = {0x80, 0x78};
+  if (AncillaAdd_CheckForPresence(a))
+    return;
+  int k = Ancilla_AddAncilla(a, y);
+  if (k >= 0) {
+    ancilla_item_to_link[k] = 16;
+    ancilla_L[k] = 0;
+    int j = link_direction_facing >> 1;
+    ancilla_dir[k] = j = kAddDashTremor_Dir[j];
+    uint8 y = link_y_coord - BG2VOFS_copy2;
+    uint8 x = link_x_coord - BG2HOFS_copy2;
+    Ancilla_SetY(k, (j ? y : x) < kAddDashTremor_Tab[j >> 1] ? 3 : -3);
+  }
+}
+
+void AncillaAdd_BoomerangWallClink(int k) {  // 899478
+  static const int8 kBoomerangWallHit_X[8] = {8, 8, 0, 10, 12, 8, 4, 0};
+  static const int8 kBoomerangWallHit_Y[8] = {0, 8, 8, 8, 4, 8, 12, 8};
+  static const uint8 kBoomerangWallHit_Tab0[16] = {0, 6, 4, 0, 2, 10, 12, 0, 0, 8, 14, 0, 0, 0, 0, 0};
+  boomerang_temp_x = Ancilla_GetX(k);
+  boomerang_temp_y = Ancilla_GetY(k);
+  k = Ancilla_AddAncilla(6, 1);
+  if (k >= 0) {
+    ancilla_item_to_link[k] = 0;
+    ancilla_arr3[k] = 1;
+    int j = kBoomerangWallHit_Tab0[hookshot_effect_index] >> 1;
+    Ancilla_SetXY(k, boomerang_temp_x + kBoomerangWallHit_X[j], boomerang_temp_y + kBoomerangWallHit_Y[j]);
+  }
+}
+
+void AncillaAdd_HookshotWallClink(int kin, uint8 a, uint8 y) {  // 8994c6
+  static const int8 kHookshotWallHit_X[8] = {8, 8, 0, 10, 12, 8, 4, 0};
+  static const int8 kHookshotWallHit_Y[8] = {0, 8, 8, 8, 4, 8, 12, 8};
+  int k = Ancilla_AddAncilla(a, y);
+  if (k >= 0) {
+    ancilla_item_to_link[k] = 0;
+    ancilla_arr3[k] = 1;
+    int j = ancilla_dir[kin];
+    Ancilla_SetXY(k, Ancilla_GetX(kin) + kHookshotWallHit_X[j], Ancilla_GetY(kin) + kHookshotWallHit_Y[j]);
+  }
+}
+
+void AncillaAdd_Duck_take_off(uint8 a, uint8 y) {  // 8994fe
+  if (AncillaAdd_CheckForPresence(a))
+    return;
+  int k = Ancilla_AddAncilla(a, y);
+  if (k >= 0) {
+    ancilla_timer[k] = 0x78;
+    ancilla_L[k] = 0;
+    ancilla_z_vel[k] = 0;
+    ancilla_z[k] = 0;
+    ancilla_step[k] = 0;
+    AddBirdCommon(k);
+  }
+}
+
+void AddBirdTravelSomething(uint8 a, uint8 y) {  // 89951d
+  if (AncillaAdd_CheckForPresence(a))
+    return;
+  int k = Ancilla_AddAncilla(a, y);
+  if (k >= 0) {
+    link_player_handler_state = 0;
+    link_speed_setting = 0;
+    button_mask_b_y &= ~0x81;
+    button_b_frames = 0;
+    link_delay_timer_spin_attack = 0;
+    link_cant_change_direction &= ~1;
+    ancilla_L[k] = 1;
+
+    if (enhanced_features0 & kFeatures0_ExtendScreen64) {
+      // todo: tune these better so the angle of attack is better
+      ancilla_z_vel[k] = 58;
+      ancilla_z[k] = -105;
+    } else {
+      ancilla_z_vel[k] = 40;
+      ancilla_z[k] = -51;
+    }
+    ancilla_step[k] = 2;
+    AddBirdCommon(k);
+  }
+}
+
+void AncillaAdd_QuakeSpell(uint8 a, uint8 y) {  // 899589
+  int k = Ancilla_AddAncilla(a, y);
+  if (k >= 0) {
+    ancilla_step[k] = 0;
+    ancilla_item_to_link[k] = 0;
+    load_chr_halfslot_even_odd = 13;
+    sound_effect_1 = 0x35;
+    for(int i = 0; i < 5; i++)
+      quake_arr2[i] = 0;
+    quake_var5 = 0;
+    for(int i = 0; i < 5; i++)
+      quake_arr1[i] = 1;
+    flag_custom_spell_anim_active = 1;
+    ancilla_timer[k] = 2;
+    quake_var1 = link_y_coord + 26;
+    quake_var2 = link_x_coord + 8;
+    quake_var3 = 3;
+  }
+}
+
+void AncillaAdd_SpinAttackInitSpark(uint8 a, uint8 x, uint8 y) {  // 89960b
+  static const int8 kSpinAttackStartSparkle_Y[4] = {32, -8, 10, 20};
+  static const int8 kSpinAttackStartSparkle_X[4] = {10, 7, 28, -10};
+
+  int k = Ancilla_AddAncilla(a, y);
+  for (int i = 4; i >= 0; i--) {
+    if (ancilla_type[i] == 0x31)
+      ancilla_type[i] = 0;
+  }
+  ancilla_item_to_link[k] = 0;
+  ancilla_step[k] = x;
+  ancilla_timer[k] = 4;
+  ancilla_aux_timer[k] = 3;
+  int j = link_direction_facing >> 1;
+  Ancilla_SetXY(k,
+      link_x_coord + kSpinAttackStartSparkle_X[j],
+      link_y_coord + kSpinAttackStartSparkle_Y[j]);
+}
+
+void AncillaAdd_BlastWall() {  // 899692
+  static const int8 kBlastWall_Tab3[4] = {-16, 16, 0, 0};
+  static const int8 kBlastWall_Tab4[4] = {0, 0, -16, 16};
+  static const int8 kBlastWall_Tab5[16] = {-8, 0, -8, 16, 16, 0, 16, 16, 0, -8, 16, -8, 0, 16, 16, 16};
+
+  ancilla_type[0] = 0x33;
+  ancilla_type[1] = 0x33;
+  ancilla_type[2] = 0;
+  ancilla_type[3] = 0;
+  ancilla_type[4] = 0;
+  ancilla_type[5] = 0;
+
+  ancilla_item_to_link[0] = 0;
+  flag_is_ancilla_to_pick_up = 0;
+  link_state_bits = 0;
+  link_cant_change_direction = 0;
+  ancilla_K[0] = 0;
+  ancilla_floor[0] = link_is_on_lower_level;
+  ancilla_floor[1] = link_is_on_lower_level;
+  ancilla_floor2[0] = link_is_on_lower_level_mirror;
+  blastwall_var1 = 0;
+  blastwall_var6[1] = 0;
+  blastwall_var5[1] = 0;
+  blastwall_var4 = 0;
+  blastwall_var5[0] = 1;
+  flag_custom_spell_anim_active = 1;
+  blastwall_var6[0] = 3;
+  int j = blastwall_var7;
+  blastwall_var8 += kBlastWall_Tab3[j];
+  blastwall_var9 += kBlastWall_Tab4[j];
+  j = (j < 4) ? 4 : 0;
+  for (int k = 3; k >= 0; k--, j++) {
+    blastwall_var10[k] = blastwall_var8 + kBlastWall_Tab5[j * 2 + 0];
+    blastwall_var11[k] = blastwall_var9 + kBlastWall_Tab5[j * 2 + 1];
+    uint16 x = blastwall_var11[k] - BG2HOFS_copy2;
+    if (x < 256)
+      sound_effect_1 = kBombos_Sfx[x >> 5] | 0xc;
+  }
+  // In dark world forest castle hole outside door
+
+}
+
+void AncillaAdd_SwordChargeSparkle(int k) {  // 899757
+  int j;
+  for (j = 9; ancilla_type[j] != 0; ) {
+    if (--j < 0)
+      return;
+  }
+  ancilla_type[j] = 60;
+  ancilla_floor[j] = link_is_on_lower_level;
+  ancilla_item_to_link[j] = 0;
+  ancilla_timer[j] = 4;
+
+  uint8 rand = GetRandomNumber();
+
+  uint8 z = ancilla_z[k];
+  if (z >= 0xF8)
+    z = 0;
+  Ancilla_SetXY(j, Ancilla_GetX(k) + 2 + (rand >> 5), Ancilla_GetY(k) - 2 - z + (rand & 0xf));
+}
+
+void AncillaAdd_SilverArrowSparkle(int kin) {  // 8997de
+  static const int8 kSilverArrowSparkle_X[4] = {-4, -4, 0, 2};
+  static const int8 kSilverArrowSparkle_Y[4] = {0, 2, -4, -4};
+  int k = Ancilla_AllocHigh();
+  if (k >= 0) {
+    ancilla_type[k] = 0x3c;
+    ancilla_item_to_link[k] = 0;
+    ancilla_timer[k] = 4;
+    ancilla_floor[k] = link_is_on_lower_level;
+    int m = GetRandomNumber();
+    int j = ancilla_dir[kin] & 3;
+    Ancilla_SetXY(k,
+      Ancilla_GetX(kin) + kSilverArrowSparkle_X[j] + (m >> 4 & 7),
+      Ancilla_GetY(kin) + kSilverArrowSparkle_Y[j] + (m & 7));
+  }
+}
+
+void AncillaAdd_IceRodShot(uint8 a, uint8 y) {  // 899863
+  static const int8 kIceRod_X[4] = {0, 0, -20, 20};
+  static const int8 kIceRod_Y[4] = {-16, 24, 8, 8};
+  static const int8 kIceRod_Xvel[4] = {0, 0, -48, 48};
+  static const int8 kIceRod_Yvel[4] = {-48, 48, 0, 0};
+
+  int k = Ancilla_AddAncilla(a, y);
+  if (k < 0) {
+    Refund_Magic(0);
+    return;
+  }
+  sound_effect_1 = Link_CalculateSfxPan() | 15;
+  ancilla_step[k] = 0;
+  ancilla_arr25[k] = 0;
+  ancilla_item_to_link[k] = 255;
+  ancilla_L[k] = 1;
+  ancilla_aux_timer[k] = 3;
+  ancilla_arr3[k] = 6;
+  int j = link_direction_facing >> 1;
+  ancilla_dir[k] = j;
+  ancilla_y_vel[k] = kIceRod_Yvel[j];
+  ancilla_x_vel[k] = kIceRod_Xvel[j];
+
+  if (Ancilla_CheckInitialTile_A(k) < 0) {
+    uint16 x = link_x_coord + kIceRod_X[j];
+    uint16 y = link_y_coord + kIceRod_Y[j];
+
+    if (((x - BG2HOFS_copy2) | (y - BG2VOFS_copy2)) & 0xff00) {
+      ancilla_type[k] = 0;
+      return;
+    }
+    Ancilla_SetXY(k, x, y);
+  } else {
+    ancilla_type[k] = 0x11;
+    ancilla_numspr[k] = kAncilla_Pflags[0x11];
+    ancilla_item_to_link[k] = 0;
+    ancilla_aux_timer[k] = 4;
+  }
+}
+
+bool AncillaAdd_Splash(uint8 a, uint8 y) {  // 8998fc
+  int k = Ancilla_AddAncilla(a, y);
+  if (k >= 0) {
+    sound_effect_1 = Link_CalculateSfxPan() | 0x24;
+    ancilla_item_to_link[k] = 0;
+    ancilla_aux_timer[k] = 2;
+    if (player_is_indoors && !link_is_in_deep_water)
+      link_is_on_lower_level = 0;
+    Ancilla_SetXY(k, link_x_coord - 11, link_y_coord + 8);
+  }
+  return k < 0;
+}
+
+void AncillaAdd_GraveStone(uint8 ain, uint8 yin) {  // 8999e9
+  static const uint16 kMoveGravestone_Y[8] = {0x550, 0x540, 0x530, 0x520, 0x500, 0x4e0, 0x4c0, 0x4b0};
+  static const uint16 kMoveGravestone_X[15] = {0x8b0, 0x8f0, 0x910, 0x950, 0x970, 0x9a0, 0x850, 0x870, 0x8b0, 0x8f0, 0x920, 0x950, 0x880, 0x990, 0x840};
+  static const uint16 kMoveGravestone_Y1[15] = {0x540, 0x530, 0x530, 0x530, 0x520, 0x520, 0x510, 0x510, 0x4f0, 0x4f0, 0x4f0, 0x4f0, 0x4d0, 0x4b0, 0x4a0};
+  static const uint16 kMoveGravestone_X1[15] = {0x8b0, 0x8f0, 0x910, 0x950, 0x970, 0x9a0, 0x850, 0x870, 0x8b0, 0x8f0, 0x920, 0x950, 0x880, 0x990, 0x840};
+  static const uint16 kMoveGravestone_Pos[15] = {0xa16, 0x99e, 0x9a2, 0x9aa, 0x92e, 0x934, 0x88a, 0x88e, 0x796, 0x79e, 0x7a4, 0x7aa, 0x690, 0x5b2, 0x508};
+  static const uint8 kMoveGravestone_Ctr[15] = {0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x38, 0x58};
+  static const uint8 kMoveGravestone_Idx[9] = {0, 1, 4, 6, 8, 12, 13, 14, 15};
+
+  int k = Ancilla_AddAncilla(ain, yin);
+  if (k < 0)
+    return;
+  int t = ((link_y_coord & 0xf) < 7 ? link_y_coord : link_y_coord + 16) & ~0xf;
+
+  int i = 7;
+  while (kMoveGravestone_Y[i] != t) {
+    if (--i < 0) {
+      ancilla_type[k] = 0;
+      return;
+    }
+  }
+
+  int j = kMoveGravestone_Idx[i];
+  int end = kMoveGravestone_Idx[i + 1];
+  do {
+    int x = kMoveGravestone_X[j];
+    if (x < link_x_coord && (uint16)(x + 15) >= link_x_coord) {
+      if (j == 13 ? !link_is_running : link_is_running)
+        break;
+
+      int pos = kMoveGravestone_Pos[j];
+      big_rock_starting_address = pos;
+      door_open_closed_counter = kMoveGravestone_Ctr[j];
+      if (door_open_closed_counter == 0x58) {
+        sound_effect_2 = Link_CalculateSfxPan() | 0x1b;
+      } else if (door_open_closed_counter == 0x38) {
+        save_ow_event_info[BYTE(overworld_screen_index)] |= 0x20;
+        sound_effect_2 = Link_CalculateSfxPan() | 0x1b;
+      }
+
+      ((uint8 *)door_debris_y)[k] = (pos - 0x80);
+      ((uint8 *)door_debris_x)[k] = (pos - 0x80) >> 8;
+
+      Overworld_DoMapUpdate32x32_B();
+
+      if ((sound_effect_2 & 0x3f) != 0x1b)
+        sound_effect_1 = Link_CalculateSfxPan() | 0x22;
+
+      int yy = kMoveGravestone_Y1[j];
+      int xx = kMoveGravestone_X1[j];
+      bitmask_of_dragstate = 4;
+      link_something_with_hookshot = 1;
+      ancilla_A[k] = (yy - 18);
+      ancilla_B[k] = (yy - 18) >> 8;
+      Ancilla_SetXY(k, xx, yy - 2);
+      return;
+    }
+  } while (++j != end);
+  ancilla_type[k] = 0;
+}
+
+void AncillaAdd_WaterfallSplash() {  // 899b68
+  if (AncillaAdd_CheckForPresence(0x41))
+    return;
+  int k = Ancilla_AddAncilla(0x41, 4);
+  if (k >= 0) {
+    ancilla_timer[k] = 2;
+    ancilla_item_to_link[k] = 0;
+  }
+}
+
+void AncillaAdd_GTCutscene() {  // 899b83
+  if (link_state_bits & 0x80 | link_auxiliary_state ||
+     (link_has_crystals & 0x7f) != 0x7f ||
+      save_ow_event_info[0x43] & 0x20)
+    return;
+
+  Ancilla_TerminateSparkleObjects();
+
+  if (AncillaAdd_CheckForPresence(0x43))
+    return;
+
+  int k = Ancilla_AddAncilla(0x43, 4);
+  if (k < 0)
+    return;
+
+  for (int i = 15; i >= 0; i--) {
+    if (sprite_type[i] == 0x37)
+      sprite_state[i] = 0;
+  }
+
+  for (int i = 0x17; i >= 0; i--)
+    breaktowerseal_sparkle_var1[i] = 0xff;
+  DecodeAnimatedSpriteTile_variable(0x28);
+  palette_sp6r_indoors = 4;
+  overworld_palette_aux_or_main = 0x200;
+  Palette_Load_SpriteEnvironment_Dungeon();
+  flag_update_cgram_in_nmi++;
+  flag_is_link_immobilized = 1;
+  ancilla_y_subpixel[k] = 0;
+  ancilla_x_subpixel[k] = 0;
+  ancilla_step[k] = 0;
+  breaktowerseal_var5 = 240;
+  breaktowerseal_var4 = 0;
+
+  breaktowerseal_var3[0] = 0;
+
+  breaktowerseal_var3[1] = 10;
+  breaktowerseal_var3[2] = 22;
+  breaktowerseal_var3[3] = 32;
+  breaktowerseal_var3[4] = 42;
+  breaktowerseal_var3[5] = 54;
+
+  Ancilla_SetXY(k, link_x_coord, link_y_coord - 16);
+}
+
+int AncillaAdd_DoorDebris() {  // 899c38
+  int k = Ancilla_AddAncilla(8, 1);
+  if (k >= 0) {
+    ancilla_arr25[k] = 0;
+    ancilla_arr26[k] = 7;
+  }
+  return k;
+}
+
+void FireRodShot_BecomeSkullWoodsFire(int k) {  // 899c4f
+  if (player_is_indoors || !(BYTE(overworld_screen_index) & 0x40))
+    return;
+
+  ancilla_type[0] = 0x34;
+  ancilla_type[1] = 0;
+  ancilla_type[2] = 0;
+  ancilla_type[3] = 0;
+  ancilla_type[4] = 0;
+  ancilla_type[5] = 0;
+  flag_for_boomerang_in_place = 0;
+  ancilla_numspr[0] = kAncilla_Pflags[0x34];
+  skullwoodsfire_var0[0] = 253;
+  skullwoodsfire_var0[1] = 254;
+  skullwoodsfire_var0[2] = 255;
+  skullwoodsfire_var0[3] = 0;
+  skullwoodsfire_var4 = 0;
+  skullwoodsfire_var5[0] = 5;
+  skullwoodsfire_var5[1] = 5;
+  skullwoodsfire_var5[2] = 5;
+  skullwoodsfire_var5[3] = 5;
+  ancilla_aux_timer[0] = 5;
+  skullwoodsfire_var9 = 0x100;
+  skullwoodsfire_var10 = 0x100;
+  skullwoodsfire_var11 = 0x98;
+  skullwoodsfire_var12 = 0x98;
+
+  trigger_special_entrance = 2;
+  subsubmodule_index = 0;
+  BYTE(R16) = 0;
+  ancilla_floor[0] = link_is_on_lower_level;
+  ancilla_floor2[0] = link_is_on_lower_level_mirror;
+  ancilla_item_to_link[0] = 0;
+  ancilla_step[0] = 0;
+
+}
+
+int Ancilla_AddAncilla(uint8 a, uint8 y) {  // 899ce2
+  int k = Ancilla_AllocInit(a, y);
+  if (k >= 0) {
+    ancilla_type[k] = a;
+    ancilla_floor[k] = link_is_on_lower_level;
+    ancilla_floor2[k] = link_is_on_lower_level_mirror;
+    ancilla_y_vel[k] = 0;
+    ancilla_x_vel[k] = 0;
+    ancilla_objprio[k] = 0;
+    ancilla_U[k] = 0;
+    ancilla_numspr[k] = kAncilla_Pflags[a];
+  }
+  return k;
+}
+
+bool AncillaAdd_CheckForPresence(uint8 a) {  // 899d20
+  for (int k = 5; k >= 0; k--) {
+    if (ancilla_type[k] == a)
+      return true;
+  }
+  return false;
+}
+
+int AncillaAdd_ArrowFindSlot(uint8 type, uint8 ay) {  // 899d36
+  int k, n = 0;
+  for (k = 4; k >= 0; k--) {
+    if (ancilla_type[k] == 10)
+      n++;
+  }
+  if (n != ay + 1) {
+    for (k = 4; k >= 0; k--) {
+      if (ancilla_type[k] == 0)
+        break;
+    }
+  } else {
+    do {
+      if (sign8(--ancilla_alloc_rotate))
+        ancilla_alloc_rotate = 4;
+      k = ancilla_alloc_rotate;
+    } while (ancilla_type[k] != 10);
+  }
+  if (k >= 0) {
+    ancilla_type[k] = type;
+    ancilla_floor[k] = link_is_on_lower_level;
+    ancilla_floor2[k] = link_is_on_lower_level_mirror;
+    ancilla_y_vel[k] = 0;
+    ancilla_x_vel[k] = 0;
+    ancilla_objprio[k] = 0;
+    ancilla_U[k] = 0;
+    ancilla_numspr[k] = kAncilla_Pflags[type];
+  }
+  return k;
+}
+
+int Ancilla_CheckInitialTile_A(int k) {  // 899dd3
+  static const int8 kAncilla_Yoffs_Hb[12] = {8, 0, -8, 8, 16, 24, 8, 8, 8, 8, 8, 8};
+  static const int8 kAncilla_Xoffs_Hb[12] = {0, 0, 0, 0, 0, 0, 0, -8, -16, 0, 8, 16};
+  int j = ancilla_dir[k] * 3;
+  int i;
+  for (i = 2; i >= 0; i--, j++) {
+    uint16 x = link_x_coord + kAncilla_Xoffs_Hb[j];
+    uint16 y = link_y_coord + kAncilla_Yoffs_Hb[j];
+    Ancilla_SetXY(k, x, y);
+    if (Ancilla_CheckTileCollision(k))
+      break;
+  }
+  return i;
+}
+
+bool Ancilla_CheckInitialTileCollision_Class2(int k) {  // 899e44
+  static const int16 kAncilla_InitialTileColl_Y[9] = {15, 16, 28, 24, 12, 12, 12, 12, 8};
+  static const int16 kAncilla_InitialTileColl_X[9] = {8, 8, 8, 8, -1, 0, 17, 16, 0x4b8b}; // wtf
+  int j = ancilla_dir[k] * 2;
+  for (int n = 2; n >= 0; n--, j++) {
+    Ancilla_SetXY(k, link_x_coord + kAncilla_InitialTileColl_X[j],
+                     link_y_coord + kAncilla_InitialTileColl_Y[j]);
+    if (Ancilla_CheckTileCollision_Class2(k))
+      return true;
+  }
+  return false;
+}
+
+uint8 Ancilla_TerminateSelectInteractives(uint8 y) {  // 89ac6b
+  int i = 5;
+
+  do {
+    if (ancilla_type[i] == 0x3e) {
+      y = i;
+    }
+    else if (ancilla_type[i] == 0x2c) {
+      dung_flag_somaria_block_switch = 0;
+      if (bitmask_of_dragstate & 0x80) {
+        bitmask_of_dragstate = 0;
+        link_speed_setting = 0;
+      }
+    }
+
+    if (sign8(link_state_bits)) {
+      if (i + 1 != flag_is_ancilla_to_pick_up)
+        ancilla_type[i] = 0;
+    }
+    else {
+      if (i + 1 == flag_is_ancilla_to_pick_up)
+        flag_is_ancilla_to_pick_up = 0;
+      ancilla_type[i] = 0;
+    }
+  } while (--i >= 0);
+
+  if (link_position_mode & 0x10) {
+    link_incapacitated_timer = 0;
+    link_position_mode = 0;
+  }
+  flute_countdown = 0;
+  tagalong_event_flags = 0;
+  byte_7E02F3 = 0;
+  flag_for_boomerang_in_place = 0;
+  is_archer_or_shovel_game = 0;
+  link_disable_sprite_damage = 0;
+  byte_7E03FD = 0;
+  link_electrocute_on_touch = 0;
+  if (link_player_handler_state == 19) {
+    link_player_handler_state = 0;
+    button_mask_b_y &= ~0x40;
+    link_cant_change_direction &= ~1;
+    link_position_mode &= ~4;
+    related_to_hookshot = 0;
+  }
+  return y;
+}
+
+void Ancilla_SetXY(int k, uint16 x, uint16 y) {  // 89ad06
+  Ancilla_SetX(k, x);
+  Ancilla_SetY(k, y);
+}
+
+void AncillaAdd_ExplodingSomariaBlock(int k) {  // 89ad30
+  ancilla_type[k] = 0x2e;
+  ancilla_numspr[k] = kAncilla_Pflags[0x2e];
+  ancilla_aux_timer[k] = 3;
+  ancilla_step[k] = 0;
+  ancilla_item_to_link[k] = 0;
+  ancilla_arr3[k] = 0;
+  ancilla_arr1[k] = 0;
+  ancilla_R[k] = 0;
+  ancilla_objprio[k] = 0;
+  dung_flag_somaria_block_switch = 0;
+  sound_effect_2 = Ancilla_CalculateSfxPan(k) | 1;
+}
+
+bool Ancilla_AddRupees(int k) {  // 89ad6c
+  static const uint8 kGiveRupeeGift_Tab[5] = {1, 5, 20, 100, 50};
+  uint8 a = ancilla_item_to_link[k];
+  if (a == 0x34 || a == 0x35 || a == 0x36) {
+    link_rupees_goal += kGiveRupeeGift_Tab[a - 0x34];
+  } else if (a == 0x40 || a == 0x41) {
+    link_rupees_goal += kGiveRupeeGift_Tab[a - 0x40 + 3];
+  } else if (a == 0x46) {
+    link_rupees_goal += 300;
+  } else if (a == 0x47) {
+    link_rupees_goal += 20;
+  } else {
+    return false;
+  }
+  return true;
+}
+
+void DashDust_Motive(int k) {  // 89adf4
+  static const uint8 kMotiveDashDust_Draw_Char[3] = {0xa9, 0xcf, 0xdf};
+  if (!ancilla_timer[k]) {
+    ancilla_timer[k] = 3;
+    if (++ancilla_item_to_link[k] == 3) {
+      ancilla_type[k] = 0;
+      return;
+    }
+  }
+  if (link_direction_facing == 2)
+    Oam_AllocateFromRegionB(4);
+  Point16U info;
+  Ancilla_PrepOamCoord(k, &info);
+  Ancilla_SetOam(GetOamCurPtr(), info.x, info.y,
+                 kMotiveDashDust_Draw_Char[ancilla_item_to_link[k]], 4 | HIBYTE(oam_priority_value), 0);
+}
+
+uint8 Ancilla_CalculateSfxPan(int k) {  // 8dbb5e
+  return CalculateSfxPan(Ancilla_GetX(k));
+}
+
+int Ancilla_AllocInit(uint8 type, uint8 limit) {  // 8ff577
+  // snes bug: R14 is used in tile detection already
+  // unless this is here it the memcmp will fail when entering/leaving a water through steps quickly
+  if (g_ram[kRam_BugsFixed] >= kBugFix_PolyRenderer)
+    BYTE(R14) = limit + 1;
+
+  int n = 0;
+  for (int i = 0; i < 5; i++) {
+    if (ancilla_type[i] == type)
+      n++;
+  }
+  if (limit + 1 == n)
+    return -1;
+
+  // Try to reuse an empty ancilla slot
+  for (int j = (type == 7 || type == 8) ? limit : 4; j >= 0; j--) {
+    if (ancilla_type[j] == 0)
+      return j;
+  }
+  int k = ancilla_alloc_rotate;
+  do {
+    if (--k < 0)
+      k = limit;
+    uint8 old_type = ancilla_type[k];
+    // reuse slots for sparkles or arrows in wall
+    if (old_type == 0x3c || old_type == 0x13 || old_type == 0xa) {
+      ancilla_alloc_rotate = k;
+      return k;
+    }
+  } while (k != 0);
+  ancilla_alloc_rotate = 0;
+  return -1;
+}
+
+void AddSwordBeam(uint8 y) {  // 8ff67b
+  static const int8 kSwordBeam_X[4] = {-8, -10, -22, 4};
+  static const int8 kSwordBeam_Y[4] = {-24, 8, -6, -6};
+  static const int8 kSwordBeam_S[4] = {-8, -8, -8, 8};
+  static const uint8 kSwordBeam_Tab[16] = {0x21, 0x1d, 0x19, 0x15, 3, 0x3e, 0x3a, 0x36, 0x12, 0xe, 0xa, 6, 0x31, 0x2d, 0x29, 0x25};
+  static const int8 kSwordBeam_Yvel[4] = {-64, 64, 0, 0};
+  static const int8 kSwordBeam_Xvel[4] = {0, 0, -64, 64};
+
+  int k = Ancilla_AddAncilla(0xc, y);
+  if (k < 0)
+    return;
+  int j = link_direction_facing * 2;
+  swordbeam_arr[0] = kSwordBeam_Tab[j + 0];
+  swordbeam_arr[1] = kSwordBeam_Tab[j + 1];
+  swordbeam_arr[2] = kSwordBeam_Tab[j + 2];
+  swordbeam_arr[3] = swordbeam_var1 = kSwordBeam_Tab[j + 3];
+  ancilla_aux_timer[k] = 2;
+  ancilla_item_to_link[k] = 0x4c;
+  ancilla_arr3[k] = 8;
+  ancilla_step[k] = 0;
+  ancilla_L[k] = 0;
+  ancilla_G[k] = 0;
+  ancilla_arr1[k] = 0;
+  swordbeam_var2 = 14;
+  j = link_direction_facing >> 1;
+  ancilla_dir[k] = j;
+  ancilla_y_vel[k] = kSwordBeam_Yvel[j];
+  ancilla_x_vel[k] = kSwordBeam_Xvel[j];
+  ancilla_S[k] = kSwordBeam_S[j];
+
+  swordbeam_temp_y = link_y_coord + 12;
+  swordbeam_temp_x = link_x_coord + 8;
+
+  if (Ancilla_CheckInitialTile_A(k) >= 0) {
+    Ancilla_SetXY(k, swordbeam_temp_x + kSwordBeam_X[j], swordbeam_temp_y + kSwordBeam_Y[j]);
+    sound_effect_2 = 1 | Ancilla_CalculateSfxPan(k);
+    ancilla_type[k] = 4;
+    ancilla_timer[k] = 7;
+    ancilla_numspr[k] = 16;
+  }
+}
+
+void AncillaSpawn_SwordChargeSparkle() {  // 8ff979
+  static const uint8 kSwordChargeSparkle_A[4] = {0, 0, 7, 7};
+  static const uint8 kSwordChargeSparkle_B[4] = {0x70, 0x70, 0, 0};
+  static const uint8 kSwordChargeSparkle_X[4] = {0, 3, 4, 5};
+  static const uint8 kSwordChargeSparkle_Y[4] = {5, 12, 8, 8};
+  int k = Ancilla_AllocHigh();
+  if (k < 0)
+    return;
+  ancilla_type[k] = 0x3c;
+  ancilla_item_to_link[k] = 0;
+  ancilla_timer[k] = 4;
+  ancilla_floor[k] = link_is_on_lower_level;
+  int j = link_direction_facing >> 1;
+  int8 x = 0, y = 0;
+  uint8 m0 = kSwordChargeSparkle_A[j];
+  if (!m0) {
+    y = link_spin_attack_step_counter >> 2;
+    if (j == 0)
+      y = -y;
+  }
+  uint8 m1 = kSwordChargeSparkle_B[j];
+  if (!m1) {
+    x = link_spin_attack_step_counter >> 2;
+    if (j == 2)
+      x = -x;
+  }
+  uint8 r = GetRandomNumber();
+  Ancilla_SetXY(k,
+    link_x_coord + x + kSwordChargeSparkle_X[j] + ((r & m1) >> 4),
+    link_y_coord + y + kSwordChargeSparkle_Y[j] + (r & m0));
+}
+
+int DashTremor_TwiddleOffset(int k) {  // 8ffafe
+  int j = ancilla_dir[k];
+  uint16 y = -Ancilla_GetY(k);
+  Ancilla_SetY(k, y);
+  if (player_is_indoors)
+    return y;
+  if (j == 2) {
+    uint16 start = ow_scroll_vars0.ystart + 1;
+    uint16 end = ow_scroll_vars0.yend - 1;
+    uint16 a = y + BG2VOFS_copy2;
+    return (a <= start || a >= end) ? 0 : y;
+  } else {
+    uint16 start = ow_scroll_vars0.xstart + 1;
+    uint16 end = ow_scroll_vars0.xend - 1;
+    uint16 a = y + BG2HOFS_copy2;
+    return (a <= start || a >= end) ? 0 : y;
+  }
+}
+
+void Ancilla_TerminateIfOffscreen(int j) {  // 8ffd52
+  int xt = (enhanced_features0 & kFeatures0_ExtendScreen64) ? 0x40 : 0;
+  uint16 x = Ancilla_GetX(j) - BG2HOFS_copy2 + xt;
+  uint16 y = Ancilla_GetY(j) - BG2VOFS_copy2;
+  if (x >= 244 + xt * 2 || y >= 240)
+    ancilla_type[j] = 0;
+}
+
+bool Bomb_CheckUndersideSpriteStatus(int k, Point16U *out_pt, uint8 *out_r10) {  // 8ffdcf
+  if (ancilla_item_to_link[k] != 0)
+    return true;
+
+  uint8 r10 = 0;
+  if (ancilla_tile_attr[k] == 9) {
+    if (sign8(--ancilla_arr22[k])) {
+      ancilla_arr22[k] = 3;
+      if (++ancilla_arr23[k] == 3)
+        ancilla_arr23[k] = 0;
+    }
+    r10 = ancilla_arr23[k] + 4;
+    if ((sound_effect_1 & 0x3f) == 0xb || (sound_effect_1 & 0x3f) == 0x21)
+      sound_effect_1 = Ancilla_CalculateSfxPan(k) | 0x28;
+  } else if (ancilla_tile_attr[k] == 0x40) {
+    r10 = 3;
+  }
+
+  if (ancilla_z[k] >= 2 && ancilla_z[k] < 252)
+    r10 = 2;
+  if (k + 1 == flag_is_ancilla_to_pick_up && (link_state_bits & 0x80))
+    return true;
+  int z = (int8)ancilla_z[k];
+  out_pt->y += z + 2;
+  out_pt->x += -8;
+  *out_r10 = r10;
+  return false;
+}
+
+void Sprite_CreateDeflectedArrow(int k) {  // 9d8040
+  ancilla_type[k] = 0;
+  SpriteSpawnInfo info;
+  int j = Sprite_SpawnDynamically(k, 0x1b, &info);
+  if (j >= 0) {
+    sprite_x_lo[j] = ancilla_x_lo[k];
+    sprite_x_hi[j] = ancilla_x_hi[k];
+    sprite_y_lo[j] = ancilla_y_lo[k];
+    sprite_y_hi[j] = ancilla_y_hi[k];
+    sprite_state[j] = 6;
+    sprite_delay_main[j] = 31;
+    sprite_x_vel[j] = ancilla_x_vel[k];
+    sprite_y_vel[j] = ancilla_y_vel[k];
+    sprite_floor[j] = link_is_on_lower_level;
+    Sprite_PlaceWeaponTink(j);
+  }
+}
+
--- /dev/null
+++ b/src/ancilla.h
@@ -1,0 +1,273 @@
+#pragma once
+#include "types.h"
+#include "zelda_rtl.h"
+#include "sprite.h"
+
+typedef struct CheckPlayerCollOut {
+  uint16 r4, r6;
+  uint16 r8, r10;
+} CheckPlayerCollOut;
+
+typedef struct AncillaOamInfo {
+  uint8 x;
+  uint8 y;
+  uint8 flags;
+} AncillaOamInfo;
+
+typedef struct AncillaRadialProjection {
+  uint8 r0, r2, r4, r6;
+} AncillaRadialProjection;
+
+uint16 Ancilla_GetX(int k);
+uint16 Ancilla_GetY(int k);
+void Ancilla_SetX(int k, uint16 x);
+void Ancilla_SetY(int k, uint16 y);
+int Ancilla_AllocHigh();
+void Ancilla_Empty(int k);
+void Ancilla_Unused_14(int k);
+void Ancilla_Unused_25(int k);
+void SpinSpark_Draw(int k, int offs);
+bool SomarianBlock_CheckEmpty(OamEnt *oam);
+void AddDashingDustEx(uint8 a, uint8 y, uint8 flag);
+void AddBirdCommon(int k);
+ProjectSpeedRet Bomb_ProjectSpeedTowardsPlayer(int k, uint16 x, uint16 y, uint8 vel);
+void Boomerang_CheatWhenNoOnesLooking(int k, ProjectSpeedRet *pt);
+void Medallion_CheckSpriteDamage(int k);
+void Ancilla_CheckDamageToSprite(int k, uint8 type);
+void Ancilla_CheckDamageToSprite_aggressive(int k, uint8 type);
+void CallForDuckIndoors();
+void Ancilla_Sfx1_Pan(int k, uint8 v);
+void Ancilla_Sfx2_Pan(int k, uint8 v);
+void Ancilla_Sfx3_Pan(int k, uint8 v);
+void AncillaAdd_FireRodShot(uint8 type, uint8 y);
+void SomariaBlock_SpawnBullets(int k);
+void Ancilla_Main();
+ProjectSpeedRet Ancilla_ProjectReflexiveSpeedOntoSprite(int k, uint16 x, uint16 y, uint8 vel);
+void Bomb_CheckSpriteDamage(int k);
+void Ancilla_ExecuteAll();
+void Ancilla_ExecuteOne(uint8 type, int k);
+void Ancilla13_IceRodSparkle(int k);
+void AncillaAdd_IceRodSparkle(int k);
+void Ancilla01_SomariaBullet(int k);
+bool Ancilla_ReturnIfOutsideBounds(int k, AncillaOamInfo *info);
+void SomarianBlast_Draw(int k);
+void Ancilla02_FireRodShot(int k);
+void FireShot_Draw(int k);
+uint8 Ancilla_CheckTileCollision_staggered(int k);
+uint8 Ancilla_CheckTileCollision(int k);
+bool Ancilla_CheckTileCollisionOneFloor(int k);
+bool Ancilla_CheckTileCollision_targeted(int k, uint16 x, uint16 y);
+bool Ancilla_CheckTileCollision_Class2(int k);
+bool Ancilla_CheckTileCollision_Class2_Inner(int k);
+void Ancilla04_BeamHit(int k);
+int Ancilla_CheckSpriteCollision(int k);
+bool Ancilla_CheckSpriteCollision_Single(int k, int j);
+void Ancilla_SetupHitBox(int k, SpriteHitBox *hb);
+ProjectSpeedRet Ancilla_ProjectSpeedTowardsPlayer(int k, uint8 vel);
+PairU8 Ancilla_IsRightOfLink(int k);
+PairU8 Ancilla_IsBelowLink(int k);
+void Ancilla_WeaponTink();
+void Ancilla_MoveX(int k);
+void Ancilla_MoveY(int k);
+void Ancilla_MoveZ(int k);
+void Ancilla05_Boomerang(int k);
+bool Boomerang_ScreenEdge(int k);
+void Boomerang_StopOffScreen(int k);
+void Boomerang_Terminate(int k);
+void Boomerang_Draw(int k);
+void Ancilla06_WallHit(int k);
+void Ancilla_SwordWallHit(int k);
+void WallHit_Draw(int k);
+void Ancilla07_Bomb(int k);
+void Ancilla_ApplyConveyor(int k);
+void Bomb_CheckSpriteAndPlayerDamage(int k);
+void Ancilla_HandleLiftLogic(int k);
+void Ancilla_LatchAltitudeAboveLink(int k);
+void Ancilla_LatchLinkCoordinates(int k, int j);
+void Ancilla_LatchCarriedPosition(int k);
+uint16 Ancilla_LatchYCoordToZ(int k);
+int Bomb_GetDisplacementFromLink(int k);
+void Bomb_Draw(int k);
+void Ancilla08_DoorDebris(int k);
+void DoorDebris_Draw(int k);
+void Ancilla09_Arrow(int k);
+void Arrow_Draw(int k);
+void Ancilla0A_ArrowInTheWall(int k);
+void Ancilla0B_IceRodShot(int k);
+void Ancilla11_IceRodWallHit(int k);
+void IceShotSpread_Draw(int k);
+void Ancilla33_BlastWallExplosion(int k);
+void AncillaDraw_BlastWallBlast(int k, int x, int y);
+OamEnt *AncillaDraw_Explosion(OamEnt *oam, int frame, int idx, int idx_end, uint8 r11, int x, int y);
+void Ancilla15_JumpSplash(int k);
+void Ancilla16_HitStars(int k);
+void Ancilla17_ShovelDirt(int k);
+void Ancilla32_BlastWallFireball(int k);
+void Ancilla18_EtherSpell(int k);
+void EtherSpell_HandleLightningStroke(int k);
+void EtherSpell_HandleOrbPulse(int k);
+void EtherSpell_HandleRadialSpin(int k);
+OamEnt *AncillaDraw_EtherBlitzBall(OamEnt *oam, const AncillaRadialProjection *arp, int s);
+OamEnt *AncillaDraw_EtherBlitzSegment(OamEnt *oam, const AncillaRadialProjection *arp, int s, int k);
+void AncillaDraw_EtherBlitz(int k);
+void AncillaDraw_EtherOrb(int k, OamEnt *oam);
+void AncillaAdd_BombosSpell(uint8 a, uint8 y);
+void Ancilla19_BombosSpell(int k);
+void BombosSpell_ControlFireColumns(int k);
+void BombosSpell_FinishFireColumns(int kk);
+void AncillaDraw_BombosFireColumn(int kk);
+void BombosSpell_ControlBlasting(int kk);
+void AncillaDraw_BombosBlast(int k);
+void Ancilla1C_QuakeSpell(int k);
+void QuakeSpell_ShakeScreen(int k);
+void QuakeSpell_ControlBolts(int k);
+void AncillaDraw_QuakeInitialBolts(int k);
+void QuakeSpell_SpreadBolts(int k);
+void Ancilla1A_PowderDust(int k);
+void Ancilla_MagicPowder_Draw(int k);
+void Powder_ApplyDamageToSprites(int k);
+void Ancilla1D_ScreenShake(int k);
+void Ancilla1E_DashDust(int k);
+void Ancilla1F_Hookshot(int k);
+void Ancilla20_Blanket(int k);
+void Ancilla21_Snore(int k);
+void Ancilla3B_SwordUpSparkle(int k);
+void Ancilla3C_SpinAttackChargeSparkle(int k);
+void Ancilla35_MasterSwordReceipt(int k);
+void Ancilla22_ItemReceipt(int k);
+OamEnt *Ancilla_ReceiveItem_Draw(int k, int x, int y);
+void Ancilla28_WishPondItem(int k);
+void WishPondItem_Draw(int k);
+void Ancilla42_HappinessPondRupees(int k);
+void HapinessPondRupees_ExecuteRupee(int k, int i);
+void HapinessPondRupees_GetState(int j, int k);
+void HapinessPondRupees_SaveState(int k, int j);
+void Ancilla_TransmuteToSplash(int k);
+void Ancilla3D_ItemSplash(int k);
+void ObjectSplash_Draw(int k);
+void Ancilla29_MilestoneItemReceipt(int k);
+void ItemReceipt_TransmuteToRisingCrystal(int k);
+void Ancilla_RisingCrystal(int k);
+void AncillaAdd_OccasionalSparkle(int k);
+void Ancilla43_GanonsTowerCutscene(int k);
+void AncillaDraw_GTCutsceneCrystal(OamEnt *oam, int x, int y);
+void GTCutscene_ActivateSparkle();
+OamEnt *GTCutscene_SparkleALot(OamEnt *oam);
+void Ancilla36_Flute(int k);
+void Ancilla37_WeathervaneExplosion(int k);
+void AncillaDraw_WeathervaneExplosionWoodDebris(int k);
+void Ancilla38_CutsceneDuck(int k);
+void Ancilla23_LinkPoof(int k);
+void MorphPoof_Draw(int k);
+void Ancilla40_DwarfPoof(int k);
+void Ancilla3F_BushPoof(int k);
+void Ancilla26_SwordSwingSparkle(int k);
+void Ancilla2A_SpinAttackSparkleA(int k);
+void SpinAttackSparkleA_TransmuteToNextSpark(int k);
+void Ancilla2B_SpinAttackSparkleB(int k);
+Point16U Sparkle_PrepOamFromRadial(AncillaRadialProjection p);
+void SpinAttackSparkleB_Closer(int k);
+void Ancilla30_ByrnaWindupSpark(int k);
+void ByrnaWindupSpark_TransmuteToNormal(int k);
+void Ancilla31_ByrnaSpark(int k);
+void Ancilla_SwordBeam(int k);
+void Ancilla0D_SpinAttackFullChargeSpark(int k);
+void Ancilla27_Duck(int k);
+int AncillaAdd_SomariaBlock(uint8 type, uint8 y);
+void SomariaBlock_CheckForTransitTile(int k);
+int Ancilla_CheckBasicSpriteCollision(int k);
+bool Ancilla_CheckBasicSpriteCollision_Single(int k, int j);
+void Ancilla_SetupBasicHitBox(int k, SpriteHitBox *hb);
+void Ancilla2C_SomariaBlock(int k);
+void AncillaDraw_SomariaBlock(int k);
+bool SomariaBlock_CheckForSwitch(int k);
+void SomariaBlock_FizzleAway(int k);
+void Ancilla2D_SomariaBlockFizz(int k);
+void Ancilla39_SomariaPlatformPoof(int k);
+void Ancilla2E_SomariaBlockFission(int k);
+void Ancilla2F_LampFlame(int k);
+void Ancilla41_WaterfallSplash(int k);
+void Ancilla24_Gravestone(int k);
+void Ancilla34_SkullWoodsFire(int k);
+void Ancilla3A_BigBombExplosion(int k);
+void RevivalFairy_Main();
+void RevivalFairy_Dust();
+void RevivalFairy_MonitorHP();
+void GameOverText_Draw();
+int AncillaAdd_AddAncilla_Bank08(uint8 type, uint8 y);
+void Ancilla_PrepOamCoord(int k, Point16U *info);
+void Ancilla_PrepAdjustedOamCoord(int k, Point16U *info);
+bool Ancilla_CheckLinkCollision(int k, int j, CheckPlayerCollOut *out);
+bool Hookshot_CheckProximityToLink(int x, int y);
+bool Ancilla_CheckForEntranceTrigger(int what);
+void AncillaDraw_Shadow(OamEnt *oam, int k, int x, int y, uint8 pal);
+void Ancilla_AllocateOamFromRegion_B_or_E(uint8 size);
+OamEnt *Ancilla_AllocateOamFromCustomRegion(OamEnt *oam);
+OamEnt *HitStars_UpdateOamBufferPosition(OamEnt *oam);
+bool Hookshot_ShouldIEvenBotherWithTiles(int k);
+AncillaRadialProjection Ancilla_GetRadialProjection(uint8 a, uint8 r8);
+int Ancilla_AllocateOamFromRegion_A_or_D_or_F(int k, uint8 size);
+void Ancilla_AddHitStars(uint8 a, uint8 y);
+void AncillaAdd_Blanket(uint8 a);
+void AncillaAdd_Snoring(uint8 a, uint8 y);
+void AncillaAdd_Bomb(uint8 a, uint8 y);
+uint8 AncillaAdd_Boomerang(uint8 a, uint8 y);
+void AncillaAdd_TossedPondItem(uint8 a, uint8 xin, uint8 yin);
+void AddHappinessPondRupees(uint8 arg);
+int AncillaAdd_FallingPrize(uint8 a, uint8 item_idx, uint8 yv);
+void AncillaAdd_ChargedSpinAttackSparkle();
+void AncillaAdd_ExplodingWeatherVane(uint8 a, uint8 y);
+void AncillaAdd_CutsceneDuck(uint8 a, uint8 y);
+void AncillaAdd_SomariaPlatformPoof(int k);
+int AncillaAdd_SuperBombExplosion(uint8 a, uint8 y);
+void ConfigureRevivalAncillae();
+void AncillaAdd_LampFlame(uint8 a, uint8 y);
+void AncillaAdd_MSCutscene(uint8 a, uint8 y);
+void AncillaAdd_DashDust(uint8 a, uint8 y);
+void AncillaAdd_DashDust_charging(uint8 a, uint8 y);
+void AncillaAdd_BlastWallFireball(uint8 a, uint8 y, int r4);
+int AncillaAdd_Arrow(uint8 a, uint8 ax, uint8 ay, uint16 xcoord, uint16 ycoord);
+void AncillaAdd_BunnyPoof(uint8 a, uint8 y);
+void AncillaAdd_CapePoof(uint8 a, uint8 y);
+void AncillaAdd_DwarfPoof(uint8 ain, uint8 yin);
+void AncillaAdd_BushPoof(uint16 x, uint16 y);
+void AncillaAdd_EtherSpell(uint8 a, uint8 y);
+void AncillaAdd_VictorySpin();
+void AncillaAdd_MagicPowder(uint8 a, uint8 y);
+void AncillaAdd_WallTapSpark(uint8 a, uint8 y);
+void AncillaAdd_SwordSwingSparkle(uint8 a, uint8 y);
+void AncillaAdd_DashTremor(uint8 a, uint8 y);
+void AncillaAdd_BoomerangWallClink(int k);
+void AncillaAdd_HookshotWallClink(int kin, uint8 a, uint8 y);
+void AncillaAdd_Duck_take_off(uint8 a, uint8 y);
+void AddBirdTravelSomething(uint8 a, uint8 y);
+void AncillaAdd_QuakeSpell(uint8 a, uint8 y);
+void AncillaAdd_SpinAttackInitSpark(uint8 a, uint8 x, uint8 y);
+void AncillaAdd_BlastWall();
+void AncillaAdd_SwordChargeSparkle(int k);
+void AncillaAdd_SilverArrowSparkle(int kin);
+void AncillaAdd_IceRodShot(uint8 a, uint8 y);
+bool AncillaAdd_Splash(uint8 a, uint8 y);
+void AncillaAdd_GraveStone(uint8 ain, uint8 yin);
+void AncillaAdd_WaterfallSplash();
+void AncillaAdd_GTCutscene();
+int AncillaAdd_DoorDebris();
+void FireRodShot_BecomeSkullWoodsFire(int k);
+int Ancilla_AddAncilla(uint8 a, uint8 y);
+bool AncillaAdd_CheckForPresence(uint8 a);
+int AncillaAdd_ArrowFindSlot(uint8 type, uint8 ay);
+int Ancilla_CheckInitialTile_A(int k);
+bool Ancilla_CheckInitialTileCollision_Class2(int k);
+uint8 Ancilla_TerminateSelectInteractives(uint8 y);
+void Ancilla_SetXY(int k, uint16 x, uint16 y);
+void AncillaAdd_ExplodingSomariaBlock(int k);
+bool Ancilla_AddRupees(int k);
+void DashDust_Motive(int k);
+uint8 Ancilla_CalculateSfxPan(int k);
+int Ancilla_AllocInit(uint8 type, uint8 y);
+void AddSwordBeam(uint8 y);
+void AncillaSpawn_SwordChargeSparkle();
+int DashTremor_TwiddleOffset(int k);
+void Ancilla_TerminateIfOffscreen(int j);
+bool Bomb_CheckUndersideSpriteStatus(int k, Point16U *out_pt, uint8 *out_r10);
+void Sprite_CreateDeflectedArrow(int k);
--- /dev/null
+++ b/src/assets.h
@@ -1,0 +1,332 @@
+#pragma once
+#include "types.h"
+
+enum {
+  kNumberOfAssets = 165
+};
+extern const uint8 *g_asset_ptrs[kNumberOfAssets];
+extern uint32 g_asset_sizes[kNumberOfAssets];
+extern MemBlk FindInAssetArray(int asset, int idx);
+
+#define kSoundBank_intro ((uint8*)g_asset_ptrs[0])
+#define kSoundBank_intro_SIZE (g_asset_sizes[0])
+#define kSoundBank_indoor ((uint8*)g_asset_ptrs[1])
+#define kSoundBank_indoor_SIZE (g_asset_sizes[1])
+#define kSoundBank_ending ((uint8*)g_asset_ptrs[2])
+#define kSoundBank_ending_SIZE (g_asset_sizes[2])
+#define kDungeonRoom ((uint8*)g_asset_ptrs[3])
+#define kDungeonRoom_SIZE (g_asset_sizes[3])
+#define kDungeonRoomOffs ((uint16*)g_asset_ptrs[4])
+#define kDungeonRoomOffs_SIZE (g_asset_sizes[4])
+#define kDungeonRoomDoorOffs ((uint16*)g_asset_ptrs[5])
+#define kDungeonRoomDoorOffs_SIZE (g_asset_sizes[5])
+#define kDungeonRoomHeaders ((uint8*)g_asset_ptrs[6])
+#define kDungeonRoomHeaders_SIZE (g_asset_sizes[6])
+#define kDungeonRoomHeadersOffs ((uint16*)g_asset_ptrs[7])
+#define kDungeonRoomHeadersOffs_SIZE (g_asset_sizes[7])
+#define kDungeonRoomChests ((uint8*)g_asset_ptrs[8])
+#define kDungeonRoomChests_SIZE (g_asset_sizes[8])
+#define kDungeonRoomTeleMsg ((uint16*)g_asset_ptrs[9])
+#define kDungeonRoomTeleMsg_SIZE (g_asset_sizes[9])
+#define kDungeonPitsHurtPlayer ((uint16*)g_asset_ptrs[10])
+#define kDungeonPitsHurtPlayer_SIZE (g_asset_sizes[10])
+#define kEntranceData_rooms ((uint16*)g_asset_ptrs[11])
+#define kEntranceData_rooms_SIZE (g_asset_sizes[11])
+#define kEntranceData_relativeCoords ((uint8*)g_asset_ptrs[12])
+#define kEntranceData_relativeCoords_SIZE (g_asset_sizes[12])
+#define kEntranceData_scrollX ((uint16*)g_asset_ptrs[13])
+#define kEntranceData_scrollX_SIZE (g_asset_sizes[13])
+#define kEntranceData_scrollY ((uint16*)g_asset_ptrs[14])
+#define kEntranceData_scrollY_SIZE (g_asset_sizes[14])
+#define kEntranceData_playerX ((uint16*)g_asset_ptrs[15])
+#define kEntranceData_playerX_SIZE (g_asset_sizes[15])
+#define kEntranceData_playerY ((uint16*)g_asset_ptrs[16])
+#define kEntranceData_playerY_SIZE (g_asset_sizes[16])
+#define kEntranceData_cameraX ((uint16*)g_asset_ptrs[17])
+#define kEntranceData_cameraX_SIZE (g_asset_sizes[17])
+#define kEntranceData_cameraY ((uint16*)g_asset_ptrs[18])
+#define kEntranceData_cameraY_SIZE (g_asset_sizes[18])
+#define kEntranceData_blockset ((uint8*)g_asset_ptrs[19])
+#define kEntranceData_blockset_SIZE (g_asset_sizes[19])
+#define kEntranceData_floor ((int8*)g_asset_ptrs[20])
+#define kEntranceData_floor_SIZE (g_asset_sizes[20])
+#define kEntranceData_palace ((int8*)g_asset_ptrs[21])
+#define kEntranceData_palace_SIZE (g_asset_sizes[21])
+#define kEntranceData_doorwayOrientation ((uint8*)g_asset_ptrs[22])
+#define kEntranceData_doorwayOrientation_SIZE (g_asset_sizes[22])
+#define kEntranceData_startingBg ((uint8*)g_asset_ptrs[23])
+#define kEntranceData_startingBg_SIZE (g_asset_sizes[23])
+#define kEntranceData_quadrant1 ((uint8*)g_asset_ptrs[24])
+#define kEntranceData_quadrant1_SIZE (g_asset_sizes[24])
+#define kEntranceData_quadrant2 ((uint8*)g_asset_ptrs[25])
+#define kEntranceData_quadrant2_SIZE (g_asset_sizes[25])
+#define kEntranceData_doorSettings ((uint16*)g_asset_ptrs[26])
+#define kEntranceData_doorSettings_SIZE (g_asset_sizes[26])
+#define kEntranceData_musicTrack ((uint8*)g_asset_ptrs[27])
+#define kEntranceData_musicTrack_SIZE (g_asset_sizes[27])
+#define kStartingPoint_rooms ((uint16*)g_asset_ptrs[28])
+#define kStartingPoint_rooms_SIZE (g_asset_sizes[28])
+#define kStartingPoint_relativeCoords ((uint8*)g_asset_ptrs[29])
+#define kStartingPoint_relativeCoords_SIZE (g_asset_sizes[29])
+#define kStartingPoint_scrollX ((uint16*)g_asset_ptrs[30])
+#define kStartingPoint_scrollX_SIZE (g_asset_sizes[30])
+#define kStartingPoint_scrollY ((uint16*)g_asset_ptrs[31])
+#define kStartingPoint_scrollY_SIZE (g_asset_sizes[31])
+#define kStartingPoint_playerX ((uint16*)g_asset_ptrs[32])
+#define kStartingPoint_playerX_SIZE (g_asset_sizes[32])
+#define kStartingPoint_playerY ((uint16*)g_asset_ptrs[33])
+#define kStartingPoint_playerY_SIZE (g_asset_sizes[33])
+#define kStartingPoint_cameraX ((uint16*)g_asset_ptrs[34])
+#define kStartingPoint_cameraX_SIZE (g_asset_sizes[34])
+#define kStartingPoint_cameraY ((uint16*)g_asset_ptrs[35])
+#define kStartingPoint_cameraY_SIZE (g_asset_sizes[35])
+#define kStartingPoint_blockset ((uint8*)g_asset_ptrs[36])
+#define kStartingPoint_blockset_SIZE (g_asset_sizes[36])
+#define kStartingPoint_floor ((int8*)g_asset_ptrs[37])
+#define kStartingPoint_floor_SIZE (g_asset_sizes[37])
+#define kStartingPoint_palace ((int8*)g_asset_ptrs[38])
+#define kStartingPoint_palace_SIZE (g_asset_sizes[38])
+#define kStartingPoint_doorwayOrientation ((uint8*)g_asset_ptrs[39])
+#define kStartingPoint_doorwayOrientation_SIZE (g_asset_sizes[39])
+#define kStartingPoint_startingBg ((uint8*)g_asset_ptrs[40])
+#define kStartingPoint_startingBg_SIZE (g_asset_sizes[40])
+#define kStartingPoint_quadrant1 ((uint8*)g_asset_ptrs[41])
+#define kStartingPoint_quadrant1_SIZE (g_asset_sizes[41])
+#define kStartingPoint_quadrant2 ((uint8*)g_asset_ptrs[42])
+#define kStartingPoint_quadrant2_SIZE (g_asset_sizes[42])
+#define kStartingPoint_doorSettings ((uint16*)g_asset_ptrs[43])
+#define kStartingPoint_doorSettings_SIZE (g_asset_sizes[43])
+#define kStartingPoint_entrance ((uint8*)g_asset_ptrs[44])
+#define kStartingPoint_entrance_SIZE (g_asset_sizes[44])
+#define kStartingPoint_musicTrack ((uint8*)g_asset_ptrs[45])
+#define kStartingPoint_musicTrack_SIZE (g_asset_sizes[45])
+#define kDungeonRoomDefault ((uint8*)g_asset_ptrs[46])
+#define kDungeonRoomDefault_SIZE (g_asset_sizes[46])
+#define kDungeonRoomDefaultOffs ((uint16*)g_asset_ptrs[47])
+#define kDungeonRoomDefaultOffs_SIZE (g_asset_sizes[47])
+#define kDungeonRoomOverlay ((uint8*)g_asset_ptrs[48])
+#define kDungeonRoomOverlay_SIZE (g_asset_sizes[48])
+#define kDungeonRoomOverlayOffs ((uint16*)g_asset_ptrs[49])
+#define kDungeonRoomOverlayOffs_SIZE (g_asset_sizes[49])
+#define kDungeonSecrets ((uint8*)g_asset_ptrs[50])
+#define kDungeonSecrets_SIZE (g_asset_sizes[50])
+#define kDungAttrsForTile_Offs ((uint16*)g_asset_ptrs[51])
+#define kDungAttrsForTile_Offs_SIZE (g_asset_sizes[51])
+#define kDungAttrsForTile ((uint8*)g_asset_ptrs[52])
+#define kDungAttrsForTile_SIZE (g_asset_sizes[52])
+#define kMovableBlockDataInit ((uint16*)g_asset_ptrs[53])
+#define kMovableBlockDataInit_SIZE (g_asset_sizes[53])
+#define kTorchDataInit ((uint16*)g_asset_ptrs[54])
+#define kTorchDataInit_SIZE (g_asset_sizes[54])
+#define kTorchDataJunk ((uint16*)g_asset_ptrs[55])
+#define kTorchDataJunk_SIZE (g_asset_sizes[55])
+#define kEnemyDamageData ((uint8*)g_asset_ptrs[56])
+#define kEnemyDamageData_SIZE (g_asset_sizes[56])
+#define kLinkGraphics ((uint8*)g_asset_ptrs[57])
+#define kLinkGraphics_SIZE (g_asset_sizes[57])
+#define kDungeonSprites ((uint8*)g_asset_ptrs[58])
+#define kDungeonSprites_SIZE (g_asset_sizes[58])
+#define kDungeonSpriteOffs ((uint16*)g_asset_ptrs[59])
+#define kDungeonSpriteOffs_SIZE (g_asset_sizes[59])
+#define kMap32ToMap16_0 ((uint8*)g_asset_ptrs[60])
+#define kMap32ToMap16_0_SIZE (g_asset_sizes[60])
+#define kMap32ToMap16_1 ((uint8*)g_asset_ptrs[61])
+#define kMap32ToMap16_1_SIZE (g_asset_sizes[61])
+#define kMap32ToMap16_2 ((uint8*)g_asset_ptrs[62])
+#define kMap32ToMap16_2_SIZE (g_asset_sizes[62])
+#define kMap32ToMap16_3 ((uint8*)g_asset_ptrs[63])
+#define kMap32ToMap16_3_SIZE (g_asset_sizes[63])
+#define kSprGfx(idx) FindInAssetArray(64, idx)
+#define kBgGfx(idx) FindInAssetArray(65, idx)
+#define kOverworldMapGfx ((uint8*)g_asset_ptrs[66])
+#define kOverworldMapGfx_SIZE (g_asset_sizes[66])
+#define kLightOverworldTilemap ((uint8*)g_asset_ptrs[67])
+#define kLightOverworldTilemap_SIZE (g_asset_sizes[67])
+#define kDarkOverworldTilemap ((uint8*)g_asset_ptrs[68])
+#define kDarkOverworldTilemap_SIZE (g_asset_sizes[68])
+#define kPredefinedTileData ((uint16*)g_asset_ptrs[69])
+#define kPredefinedTileData_SIZE (g_asset_sizes[69])
+#define kMap16ToMap8 ((uint16*)g_asset_ptrs[70])
+#define kMap16ToMap8_SIZE (g_asset_sizes[70])
+#define kGeneratedWishPondItem ((uint8*)g_asset_ptrs[71])
+#define kGeneratedWishPondItem_SIZE (g_asset_sizes[71])
+#define kGeneratedBombosArr ((uint8*)g_asset_ptrs[72])
+#define kGeneratedBombosArr_SIZE (g_asset_sizes[72])
+#define kGeneratedEndSequence15 ((uint8*)g_asset_ptrs[73])
+#define kGeneratedEndSequence15_SIZE (g_asset_sizes[73])
+#define kEnding_Credits_Text ((uint8*)g_asset_ptrs[74])
+#define kEnding_Credits_Text_SIZE (g_asset_sizes[74])
+#define kEnding_Credits_Offs ((uint16*)g_asset_ptrs[75])
+#define kEnding_Credits_Offs_SIZE (g_asset_sizes[75])
+#define kEnding_MapData ((uint16*)g_asset_ptrs[76])
+#define kEnding_MapData_SIZE (g_asset_sizes[76])
+#define kEnding0_Offs ((uint16*)g_asset_ptrs[77])
+#define kEnding0_Offs_SIZE (g_asset_sizes[77])
+#define kEnding0_Data ((uint8*)g_asset_ptrs[78])
+#define kEnding0_Data_SIZE (g_asset_sizes[78])
+#define kPalette_DungBgMain ((uint16*)g_asset_ptrs[79])
+#define kPalette_DungBgMain_SIZE (g_asset_sizes[79])
+#define kPalette_MainSpr ((uint16*)g_asset_ptrs[80])
+#define kPalette_MainSpr_SIZE (g_asset_sizes[80])
+#define kPalette_ArmorAndGloves ((uint16*)g_asset_ptrs[81])
+#define kPalette_ArmorAndGloves_SIZE (g_asset_sizes[81])
+#define kPalette_Sword ((uint16*)g_asset_ptrs[82])
+#define kPalette_Sword_SIZE (g_asset_sizes[82])
+#define kPalette_Shield ((uint16*)g_asset_ptrs[83])
+#define kPalette_Shield_SIZE (g_asset_sizes[83])
+#define kPalette_SpriteAux3 ((uint16*)g_asset_ptrs[84])
+#define kPalette_SpriteAux3_SIZE (g_asset_sizes[84])
+#define kPalette_MiscSprite_Indoors ((uint16*)g_asset_ptrs[85])
+#define kPalette_MiscSprite_Indoors_SIZE (g_asset_sizes[85])
+#define kPalette_SpriteAux1 ((uint16*)g_asset_ptrs[86])
+#define kPalette_SpriteAux1_SIZE (g_asset_sizes[86])
+#define kPalette_OverworldBgMain ((uint16*)g_asset_ptrs[87])
+#define kPalette_OverworldBgMain_SIZE (g_asset_sizes[87])
+#define kPalette_OverworldBgAux12 ((uint16*)g_asset_ptrs[88])
+#define kPalette_OverworldBgAux12_SIZE (g_asset_sizes[88])
+#define kPalette_OverworldBgAux3 ((uint16*)g_asset_ptrs[89])
+#define kPalette_OverworldBgAux3_SIZE (g_asset_sizes[89])
+#define kPalette_PalaceMapBg ((uint16*)g_asset_ptrs[90])
+#define kPalette_PalaceMapBg_SIZE (g_asset_sizes[90])
+#define kPalette_PalaceMapSpr ((uint16*)g_asset_ptrs[91])
+#define kPalette_PalaceMapSpr_SIZE (g_asset_sizes[91])
+#define kHudPalData ((uint16*)g_asset_ptrs[92])
+#define kHudPalData_SIZE (g_asset_sizes[92])
+#define kOverworldMapPaletteData ((uint16*)g_asset_ptrs[93])
+#define kOverworldMapPaletteData_SIZE (g_asset_sizes[93])
+#define kDialogue(idx) FindInAssetArray(94, idx)
+#define kDialogueFont(idx) FindInAssetArray(95, idx)
+#define kDialogueMap(idx) FindInAssetArray(96, idx)
+#define kDungMap_FloorLayout(idx) FindInAssetArray(97, idx)
+#define kDungMap_Tiles(idx) FindInAssetArray(98, idx)
+#define kBgTilemap_0 ((uint8*)g_asset_ptrs[99])
+#define kBgTilemap_0_SIZE (g_asset_sizes[99])
+#define kBgTilemap_1 ((uint8*)g_asset_ptrs[100])
+#define kBgTilemap_1_SIZE (g_asset_sizes[100])
+#define kBgTilemap_2 ((uint8*)g_asset_ptrs[101])
+#define kBgTilemap_2_SIZE (g_asset_sizes[101])
+#define kBgTilemap_3 ((uint8*)g_asset_ptrs[102])
+#define kBgTilemap_3_SIZE (g_asset_sizes[102])
+#define kBgTilemap_4 ((uint8*)g_asset_ptrs[103])
+#define kBgTilemap_4_SIZE (g_asset_sizes[103])
+#define kBgTilemap_5 ((uint8*)g_asset_ptrs[104])
+#define kBgTilemap_5_SIZE (g_asset_sizes[104])
+#define kOverworld_Hibytes_Comp(idx) FindInAssetArray(105, idx)
+#define kOverworld_Lobytes_Comp(idx) FindInAssetArray(106, idx)
+#define kOverworldMapIsSmall ((uint8*)g_asset_ptrs[107])
+#define kOverworldMapIsSmall_SIZE (g_asset_sizes[107])
+#define kOverworldAuxTileThemeIndexes ((uint8*)g_asset_ptrs[108])
+#define kOverworldAuxTileThemeIndexes_SIZE (g_asset_sizes[108])
+#define kOverworldBgPalettes ((uint8*)g_asset_ptrs[109])
+#define kOverworldBgPalettes_SIZE (g_asset_sizes[109])
+#define kOverworld_SignText ((uint16*)g_asset_ptrs[110])
+#define kOverworld_SignText_SIZE (g_asset_sizes[110])
+#define kOwMusicSets ((uint8*)g_asset_ptrs[111])
+#define kOwMusicSets_SIZE (g_asset_sizes[111])
+#define kOwMusicSets2 ((uint8*)g_asset_ptrs[112])
+#define kOwMusicSets2_SIZE (g_asset_sizes[112])
+#define kBirdTravel_ScreenIndex ((uint16*)g_asset_ptrs[113])
+#define kBirdTravel_ScreenIndex_SIZE (g_asset_sizes[113])
+#define kBirdTravel_Map16LoadSrcOff ((uint16*)g_asset_ptrs[114])
+#define kBirdTravel_Map16LoadSrcOff_SIZE (g_asset_sizes[114])
+#define kBirdTravel_ScrollX ((uint16*)g_asset_ptrs[115])
+#define kBirdTravel_ScrollX_SIZE (g_asset_sizes[115])
+#define kBirdTravel_ScrollY ((uint16*)g_asset_ptrs[116])
+#define kBirdTravel_ScrollY_SIZE (g_asset_sizes[116])
+#define kBirdTravel_LinkXCoord ((uint16*)g_asset_ptrs[117])
+#define kBirdTravel_LinkXCoord_SIZE (g_asset_sizes[117])
+#define kBirdTravel_LinkYCoord ((uint16*)g_asset_ptrs[118])
+#define kBirdTravel_LinkYCoord_SIZE (g_asset_sizes[118])
+#define kBirdTravel_CameraXScroll ((uint16*)g_asset_ptrs[119])
+#define kBirdTravel_CameraXScroll_SIZE (g_asset_sizes[119])
+#define kBirdTravel_CameraYScroll ((uint16*)g_asset_ptrs[120])
+#define kBirdTravel_CameraYScroll_SIZE (g_asset_sizes[120])
+#define kBirdTravel_Unk1 ((int8*)g_asset_ptrs[121])
+#define kBirdTravel_Unk1_SIZE (g_asset_sizes[121])
+#define kBirdTravel_Unk3 ((int8*)g_asset_ptrs[122])
+#define kBirdTravel_Unk3_SIZE (g_asset_sizes[122])
+#define kWhirlpoolAreas ((uint16*)g_asset_ptrs[123])
+#define kWhirlpoolAreas_SIZE (g_asset_sizes[123])
+#define kOverworld_Entrance_Area ((uint16*)g_asset_ptrs[124])
+#define kOverworld_Entrance_Area_SIZE (g_asset_sizes[124])
+#define kOverworld_Entrance_Pos ((uint16*)g_asset_ptrs[125])
+#define kOverworld_Entrance_Pos_SIZE (g_asset_sizes[125])
+#define kOverworld_Entrance_Id ((uint8*)g_asset_ptrs[126])
+#define kOverworld_Entrance_Id_SIZE (g_asset_sizes[126])
+#define kFallHole_Area ((uint16*)g_asset_ptrs[127])
+#define kFallHole_Area_SIZE (g_asset_sizes[127])
+#define kFallHole_Pos ((uint16*)g_asset_ptrs[128])
+#define kFallHole_Pos_SIZE (g_asset_sizes[128])
+#define kFallHole_Entrances ((uint8*)g_asset_ptrs[129])
+#define kFallHole_Entrances_SIZE (g_asset_sizes[129])
+#define kExitData_ScreenIndex ((uint8*)g_asset_ptrs[130])
+#define kExitData_ScreenIndex_SIZE (g_asset_sizes[130])
+#define kExitDataRooms ((uint16*)g_asset_ptrs[131])
+#define kExitDataRooms_SIZE (g_asset_sizes[131])
+#define kExitData_Map16LoadSrcOff ((uint16*)g_asset_ptrs[132])
+#define kExitData_Map16LoadSrcOff_SIZE (g_asset_sizes[132])
+#define kExitData_ScrollX ((uint16*)g_asset_ptrs[133])
+#define kExitData_ScrollX_SIZE (g_asset_sizes[133])
+#define kExitData_ScrollY ((uint16*)g_asset_ptrs[134])
+#define kExitData_ScrollY_SIZE (g_asset_sizes[134])
+#define kExitData_XCoord ((uint16*)g_asset_ptrs[135])
+#define kExitData_XCoord_SIZE (g_asset_sizes[135])
+#define kExitData_YCoord ((uint16*)g_asset_ptrs[136])
+#define kExitData_YCoord_SIZE (g_asset_sizes[136])
+#define kExitData_CameraXScroll ((uint16*)g_asset_ptrs[137])
+#define kExitData_CameraXScroll_SIZE (g_asset_sizes[137])
+#define kExitData_CameraYScroll ((uint16*)g_asset_ptrs[138])
+#define kExitData_CameraYScroll_SIZE (g_asset_sizes[138])
+#define kExitData_NormalDoor ((uint16*)g_asset_ptrs[139])
+#define kExitData_NormalDoor_SIZE (g_asset_sizes[139])
+#define kExitData_FancyDoor ((uint16*)g_asset_ptrs[140])
+#define kExitData_FancyDoor_SIZE (g_asset_sizes[140])
+#define kExitData_Unk1 ((int8*)g_asset_ptrs[141])
+#define kExitData_Unk1_SIZE (g_asset_sizes[141])
+#define kExitData_Unk3 ((int8*)g_asset_ptrs[142])
+#define kExitData_Unk3_SIZE (g_asset_sizes[142])
+#define kSpExit_Top ((uint16*)g_asset_ptrs[143])
+#define kSpExit_Top_SIZE (g_asset_sizes[143])
+#define kSpExit_Bottom ((uint16*)g_asset_ptrs[144])
+#define kSpExit_Bottom_SIZE (g_asset_sizes[144])
+#define kSpExit_Left ((uint16*)g_asset_ptrs[145])
+#define kSpExit_Left_SIZE (g_asset_sizes[145])
+#define kSpExit_Right ((uint16*)g_asset_ptrs[146])
+#define kSpExit_Right_SIZE (g_asset_sizes[146])
+#define kSpExit_Tab4 ((int16*)g_asset_ptrs[147])
+#define kSpExit_Tab4_SIZE (g_asset_sizes[147])
+#define kSpExit_Tab5 ((int16*)g_asset_ptrs[148])
+#define kSpExit_Tab5_SIZE (g_asset_sizes[148])
+#define kSpExit_Tab6 ((int16*)g_asset_ptrs[149])
+#define kSpExit_Tab6_SIZE (g_asset_sizes[149])
+#define kSpExit_Tab7 ((int16*)g_asset_ptrs[150])
+#define kSpExit_Tab7_SIZE (g_asset_sizes[150])
+#define kSpExit_LeftEdgeOfMap ((uint16*)g_asset_ptrs[151])
+#define kSpExit_LeftEdgeOfMap_SIZE (g_asset_sizes[151])
+#define kSpExit_Dir ((uint8*)g_asset_ptrs[152])
+#define kSpExit_Dir_SIZE (g_asset_sizes[152])
+#define kSpExit_SprGfx ((uint8*)g_asset_ptrs[153])
+#define kSpExit_SprGfx_SIZE (g_asset_sizes[153])
+#define kSpExit_AuxGfx ((uint8*)g_asset_ptrs[154])
+#define kSpExit_AuxGfx_SIZE (g_asset_sizes[154])
+#define kSpExit_PalBg ((uint8*)g_asset_ptrs[155])
+#define kSpExit_PalBg_SIZE (g_asset_sizes[155])
+#define kSpExit_PalSpr ((uint8*)g_asset_ptrs[156])
+#define kSpExit_PalSpr_SIZE (g_asset_sizes[156])
+#define kOverworldSecrets_Offs ((uint16*)g_asset_ptrs[157])
+#define kOverworldSecrets_Offs_SIZE (g_asset_sizes[157])
+#define kOverworldSecrets ((uint8*)g_asset_ptrs[158])
+#define kOverworldSecrets_SIZE (g_asset_sizes[158])
+#define kOverworldSpriteOffs ((uint16*)g_asset_ptrs[159])
+#define kOverworldSpriteOffs_SIZE (g_asset_sizes[159])
+#define kOverworldSprites ((uint8*)g_asset_ptrs[160])
+#define kOverworldSprites_SIZE (g_asset_sizes[160])
+#define kOverworldSpriteGfx ((uint8*)g_asset_ptrs[161])
+#define kOverworldSpriteGfx_SIZE (g_asset_sizes[161])
+#define kOverworldSpritePalettes ((uint8*)g_asset_ptrs[162])
+#define kOverworldSpritePalettes_SIZE (g_asset_sizes[162])
+#define kMap8DataToTileAttr ((uint8*)g_asset_ptrs[163])
+#define kMap8DataToTileAttr_SIZE (g_asset_sizes[163])
+#define kSomeTileAttr ((uint8*)g_asset_ptrs[164])
+#define kSomeTileAttr_SIZE (g_asset_sizes[164])
+#define kAssets_Sig 90, 101, 108, 100, 97, 51, 95, 118, 48, 32, 32, 32, 32, 32, 10, 0, 27, 174, 233, 45, 74, 174, 252, 50, 49, 27, 153, 197, 27, 43, 216, 197, 132, 101, 173, 169, 36, 108, 15, 155, 176, 169, 57, 131, 174, 101, 51, 207
--- /dev/null
+++ b/src/attract.c
@@ -1,0 +1,1063 @@
+#include "zelda_rtl.h"
+#include "variables.h"
+#include "snes/snes_regs.h"
+#include "load_gfx.h"
+#include "dungeon.h"
+#include "sprite.h"
+#include "ending.h"
+#include "messaging.h"
+#include "attract.h"
+#include "sprite_main.h"
+
+const uint16 kMapMode_Zooms1[240] = {
+  375, 374, 373, 373, 372, 371, 371, 370, 369, 369, 368, 367, 367, 366, 365, 365,
+  364, 363, 363, 361, 361, 360, 359, 359, 358, 357, 357, 356, 355, 355, 354, 354,
+  353, 352, 352, 351, 351, 350, 349, 349, 348, 348, 347, 346, 346, 345, 345, 344,
+  343, 343, 342, 342, 341, 341, 340, 339, 339, 338, 338, 337, 337, 336, 335, 335,
+  334, 334, 333, 333, 332, 332, 331, 331, 330, 330, 328, 327, 327, 326, 326, 325,
+  325, 324, 324, 323, 323, 322, 322, 321, 321, 320, 320, 319, 319, 318, 318, 317,
+  317, 316, 316, 315, 315, 314, 314, 313, 313, 312, 312, 311, 311, 310, 310, 309,
+  309, 309, 308, 308, 307, 307, 306, 306, 305, 305, 304, 304, 303, 303, 303, 302,
+  302, 301, 301, 300, 300, 299, 299, 299, 298, 298, 297, 297, 295, 295, 294, 294,
+  294, 293, 293, 292, 292, 292, 291, 291, 290, 290, 289, 289, 289, 288, 288, 287,
+  287, 287, 286, 286, 285, 285, 285, 284, 284, 283, 283, 283, 282, 282, 281, 281,
+  281, 280, 280, 279, 279, 279, 278, 278, 278, 277, 277, 276, 276, 276, 275, 275,
+  275, 274, 274, 273, 273, 273, 272, 272, 272, 271, 271, 271, 270, 270, 269, 269,
+  269, 268, 268, 268, 267, 267, 267, 266, 266, 266, 265, 265, 265, 264, 264, 264,
+  263, 263, 262, 262, 262, 261, 261, 261, 260, 260, 260, 259, 259, 259, 258, 258,
+};
+const uint16 kMapMode_Zooms2[240] = {
+  136, 136, 135, 135, 135, 135, 135, 134, 134, 134, 133, 133, 133, 133, 132, 132,
+  132, 132, 132, 131, 131, 131, 130, 130, 130, 130, 130, 129, 129, 129, 129, 129,
+  128, 128, 128, 127, 127, 127, 127, 127, 126, 126, 126, 126, 126, 125, 125, 125,
+  124, 124, 124, 124, 124, 124, 123, 123, 123, 123, 123, 122, 122, 122, 121, 121,
+  121, 121, 121, 121, 120, 120, 120, 120, 120, 120, 119, 119, 119, 118, 118, 118,
+  118, 118, 118, 117, 117, 117, 117, 117, 117, 116, 116, 116, 116, 115, 115, 115,
+  115, 115, 115, 114, 114, 114, 114, 114, 114, 113, 113, 113, 113, 112, 112, 112,
+  112, 112, 112, 112, 111, 111, 111, 111, 111, 111, 110, 110, 110, 110, 110, 109,
+  109, 109, 109, 109, 109, 108, 108, 108, 108, 108, 108, 108, 107, 107, 107, 107,
+  107, 106, 106, 106, 106, 106, 106, 106, 105, 105, 105, 105, 105, 105, 105, 104,
+  104, 104, 104, 104, 103, 103, 103, 103, 103, 103, 103, 103, 102, 102, 102, 102,
+  102, 102, 102, 101, 101, 101, 101, 101, 101, 100, 100, 100, 100, 100, 100, 100,
+  100,  99,  99,  99,  99,  99,  99,  99,  99,  98,  98,  98,  98,  98,  97,  97,
+  97,  97,  97,  97,  97,  97,  97,  96,  96,  96,  96,  96,  96,  96,  96,  96,
+  95, 95, 95, 95, 95, 95, 95, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+};
+static const uint8 kAttract_Legendgraphics_0[157+1] = {
+  0x61, 0x65, 0x40, 0x28,    0, 0x35, 0x61, 0x85, 0x40, 0x28, 0x10, 0x35, 0x61, 0xa5,    0, 0x29,
+     1, 0x35,    2, 0x35,    1, 0x35,    2, 0x35,    1, 0x35,    2, 0x35,    1, 0x35,    2, 0x35,
+     1, 0x35,    3, 0x31,    3, 0x71,    2, 0x35,    1, 0x35,    2, 0x35,    1, 0x35,    2, 0x35,
+     1, 0x35,    2, 0x35,    1, 0x35,    2, 0x35,    1, 0x35, 0x61, 0xc5,    0, 0x29, 0x11, 0x35,
+  0x12, 0x35, 0x11, 0x35, 0x12, 0x35, 0x11, 0x35, 0x12, 0x35, 0x11, 0x35, 0x12, 0x35, 0x11, 0x35,
+  0x13, 0x35, 0x13, 0x75, 0x12, 0x35, 0x11, 0x35, 0x12, 0x35, 0x11, 0x35, 0x12, 0x35, 0x11, 0x35,
+  0x12, 0x35, 0x11, 0x35, 0x12, 0x35, 0x11, 0x35, 0x61, 0xe5,    0, 0x29, 0x20, 0x35, 0x21, 0x35,
+  0x20, 0x35, 0x21, 0x35, 0x20, 0x35, 0x21, 0x35, 0x20, 0x35, 0x21, 0x35, 0x20, 0x35, 0x21, 0x35,
+  0x20, 0x35, 0x21, 0x35, 0x20, 0x35, 0x21, 0x35, 0x20, 0x35, 0x21, 0x35, 0x20, 0x35, 0x21, 0x35,
+  0x20, 0x35, 0x21, 0x35, 0x20, 0x35, 0x62,    5, 0x40, 0x28,    0, 0xb5, 0xff, 0x61,
+};
+static const uint8 kAttract_Legendgraphics_1[237+1] = {
+  0x61, 0x65, 0x40, 0x28,    0, 0x35, 0x61, 0x85,    0, 0x13, 0x10, 0x35, 0x4e, 0x75, 0x6e, 0x35,
+  0x10, 0x35, 0x4e, 0x35, 0x10, 0x35, 0x4c, 0x35, 0x10, 0x35, 0x4e, 0x75, 0x49, 0x35, 0x61, 0x8f,
+  0x40,    8, 0x10, 0x35, 0x61, 0x94,    0,  0xb, 0x4e, 0x75, 0x6e, 0x35, 0x10, 0x35, 0x4e, 0x35,
+  0x10, 0x35, 0x4c, 0x35, 0x61, 0xa5,    0, 0x29, 0x5f, 0x75, 0x5e, 0x75, 0x7e, 0x35, 0x7f, 0x35,
+  0x5e, 0x35, 0x5f, 0x35, 0x4d, 0x35, 0x5f, 0x75, 0x5e, 0x75, 0x4a, 0x35, 0x4b, 0x35, 0x10, 0x35,
+  0x49, 0x75, 0x10, 0x35, 0x5f, 0x75, 0x5e, 0x75, 0x7e, 0x35, 0x7f, 0x35, 0x5e, 0x35, 0x5f, 0x35,
+  0x4d, 0x35, 0x61, 0xc5,    0, 0x29, 0x50, 0x35, 0x51, 0x35, 0x52, 0x35, 0x53, 0x35, 0x54, 0x35,
+  0x55, 0x35, 0x56, 0x35, 0x57, 0x35, 0x58, 0x35, 0x59, 0x35, 0x5a, 0x35, 0x5b, 0x35, 0x5c, 0x35,
+  0x5d, 0x35, 0x50, 0x35, 0x51, 0x35, 0x52, 0x35, 0x53, 0x35, 0x54, 0x35, 0x55, 0x35, 0x56, 0x35,
+  0x61, 0xe5,    0, 0x29, 0x60, 0x35, 0x61, 0x35, 0x62, 0x35, 0x63, 0x35, 0x64, 0x35, 0x65, 0x35,
+  0x66, 0x35, 0x67, 0x35, 0x68, 0x35, 0x69, 0x35, 0x6a, 0x35, 0x6b, 0x35, 0x6c, 0x35, 0x6d, 0x35,
+  0x60, 0x35, 0x61, 0x35, 0x62, 0x35, 0x63, 0x35, 0x64, 0x35, 0x65, 0x35, 0x66, 0x35, 0x62,    5,
+     0, 0x29, 0x70, 0x35, 0x71, 0x35, 0x72, 0x35, 0x73, 0x35, 0x74, 0x35, 0x75, 0x35, 0x76, 0x35,
+  0x77, 0x35, 0x78, 0x35, 0x79, 0x35, 0x7a, 0x35, 0x7b, 0x35, 0x7c, 0x35, 0x7d, 0x35, 0x70, 0x35,
+  0x71, 0x35, 0x72, 0x35, 0x73, 0x35, 0x74, 0x35, 0x75, 0x35, 0x76, 0x35, 0xff, 0x61,
+};
+static const uint8 kAttract_Legendgraphics_2[199+1] = {
+  0x61, 0x65, 0x40, 0x28,    0, 0x35, 0x61, 0x85, 0x40, 0x28, 0x10, 0x35, 0x61, 0xa5,    0, 0x1d,
+  0x22, 0x35, 0x23, 0x35, 0x10, 0x35, 0x22, 0x35, 0x23, 0x35, 0x10, 0x35, 0x22, 0x35, 0x23, 0x35,
+  0x10, 0x35, 0x22, 0x35, 0x23, 0x35, 0x10, 0x35, 0x10, 0x75, 0x23, 0x75, 0x22, 0x75, 0x61, 0xb4,
+  0x40,    6, 0x10, 0x35, 0x61, 0xb8,    0,    3, 0x23, 0x75, 0x22, 0x75, 0x61, 0xc5,    0, 0x29,
+     4, 0x35,    5, 0x35,    6, 0x35,    4, 0x35,    5, 0x35,    6, 0x35,    4, 0x35,    5, 0x35,
+     6, 0x35,    4, 0x35,    5, 0x35,    6, 0x35,    6, 0x75,    5, 0x75,    4, 0x75, 0x10, 0x75,
+  0x23, 0x75, 0x22, 0x75,    6, 0x75,    5, 0x75,    4, 0x75, 0x61, 0xe5,    0, 0x29, 0x14, 0x35,
+  0x15, 0x35, 0x16, 0x35, 0x14, 0x35, 0x15, 0x35, 0x16, 0x35, 0x14, 0x35, 0x15, 0x35, 0x16, 0x35,
+  0x14, 0x35, 0x15, 0x35, 0x16, 0x35, 0x16, 0x75, 0x15, 0x75, 0x14, 0x75,    6, 0x75,    5, 0x75,
+     4, 0x75, 0x16, 0x75, 0x15, 0x75, 0x14, 0x75, 0x62,    5,    0, 0x29, 0x24, 0x35, 0x25, 0x35,
+  0x26, 0x35, 0x24, 0x35, 0x25, 0x35, 0x26, 0x35, 0x24, 0x35, 0x25, 0x35, 0x26, 0x35, 0x24, 0x35,
+  0x25, 0x35, 0x26, 0x35, 0x26, 0x75, 0x25, 0x75, 0x24, 0x75, 0x26, 0x75, 0x25, 0x75, 0x24, 0x75,
+  0x26, 0x75, 0x25, 0x75, 0x24, 0x75, 0xff, 0x61,
+};
+static const uint8 kAttract_Legendgraphics_3[265+1] = {
+  0x61, 0x65,    0, 0x29,    0, 0x35,    0, 0x35, 0x1b, 0x35, 0x30, 0x35, 0x31, 0x35, 0x32, 0x35,
+     0, 0x35,    0, 0x35,    0, 0x35, 0x33, 0x35, 0x41, 0x35, 0x41, 0x75, 0x33, 0x75,    0, 0x75,
+     0, 0x75,    0, 0x75, 0x32, 0x75, 0x31, 0x75, 0x30, 0x75, 0x1b, 0x75,    0, 0x75, 0x61, 0x85,
+  0x40, 0x1e, 0x10, 0x35, 0x61, 0x86,    0,    9, 0x34, 0x35,  0xb, 0x35, 0x40, 0x35, 0x41, 0x35,
+  0x42, 0x35, 0x61, 0x95,    0,    9, 0x42, 0x75, 0x41, 0x75, 0x40, 0x75,  0xb, 0x75, 0x34, 0x75,
+  0x61, 0xa5,    0, 0x29, 0x43, 0x35, 0x44, 0x35,    7, 0x35,    8, 0x35,    9, 0x35,  0xa, 0x35,
+  0x10, 0x35,  0xc, 0x35,  0xd, 0x35,  0xe, 0x35,  0xf, 0x35,  0xf, 0x75,  0xe, 0x75,  0xd, 0x75,
+   0xc, 0x75, 0x10, 0x75,  0xa, 0x75,    9, 0x75,    8, 0x75,    7, 0x75, 0x44, 0x75, 0x61, 0xc5,
+     0, 0x29, 0x35, 0x35, 0x36, 0x35, 0x17, 0x35, 0x18, 0x35, 0x19, 0x35, 0x1a, 0x35, 0x10, 0x35,
+  0x1c, 0x35, 0x1d, 0x35, 0x1e, 0x35, 0x1f, 0x35, 0x1f, 0x75, 0x1e, 0x75, 0x1d, 0x75, 0x1c, 0x75,
+  0x10, 0x75, 0x1a, 0x75, 0x19, 0x75, 0x18, 0x75, 0x17, 0x75, 0x36, 0x75, 0x61, 0xe5,    0, 0x29,
+  0x45, 0x35, 0x46, 0x35, 0x27, 0x35, 0x28, 0x35, 0x29, 0x35, 0x2a, 0x35, 0x2b, 0x35, 0x2c, 0x35,
+  0x2d, 0x35, 0x2e, 0x35, 0x2f, 0x35, 0x2f, 0x75, 0x2e, 0x75, 0x2d, 0x75, 0x2c, 0x75, 0x2b, 0x75,
+  0x2a, 0x75, 0x29, 0x75, 0x28, 0x75, 0x27, 0x75, 0x46, 0x75, 0x62,    5,    0, 0x29, 0x47, 0x35,
+  0x48, 0x35, 0x37, 0x35, 0x38, 0x35, 0x39, 0x35, 0x3a, 0x35, 0x3b, 0x35, 0x3c, 0x35, 0x3d, 0x35,
+  0x3e, 0x35, 0x3f, 0x35, 0x3f, 0x75, 0x3e, 0x75, 0x3d, 0x75, 0x3c, 0x75, 0x3b, 0x75, 0x3a, 0x75,
+  0x39, 0x75, 0x38, 0x75, 0x37, 0x75, 0x48, 0x75, 0xff, 0x0
+};
+void Attract_DrawSpriteSet2(const AttractOamInfo *p, int n) {
+  OamEnt *oam = &oam_buf[attract_oam_idx + 64];
+  attract_oam_idx += n;
+  for (; n--; oam++)
+    SetOamPlain(oam, attract_x_base + p[n].x, attract_y_base + p[n].y, p[n].c, p[n].f, p[n].e);
+}
+
+void Attract_ZeldaPrison_Case0() {
+  static const AttractOamInfo kZeldaPrison_Oams0[] = {
+    { 5, 25, 0x6c, 0x38, 2},
+    {11, 25, 0x6c, 0x38, 2},
+    { 0,  0, 0x84, 0x3b, 2},
+    {16,  0, 0x84, 0x7b, 2},
+    { 0, 16, 0xa4, 0x3b, 2},
+    {16, 16, 0xa4, 0x7b, 2},
+  };
+  if (!attract_var4)
+    attract_var5++;
+  if (frame_counter & 1)
+    attract_vram_dst--;
+  attract_x_base = 0x58;
+  attract_y_base = attract_var9;
+  Attract_DrawSpriteSet2(kZeldaPrison_Oams0, 6);
+  attract_var7 = 0xf8d9;
+}
+
+void Attract_ZeldaPrison_Case1() {
+  int k;
+  static const AttractOamInfo kZeldaPrison_Oams1[] = {
+    { 5, 25, 0x6c, 0x38, 2},
+    {11, 25, 0x6c, 0x38, 2},
+    { 0,  0, 0x84, 0x3b, 2},
+    {16,  0, 0x84, 0x7b, 2},
+    { 0, 16, 0xa4, 0x3b, 2},
+    {16, 16, 0xa4, 0x7b, 2},
+
+    { 5, 25, 0x6c, 0x38, 2},
+    {11, 25, 0x6c, 0x38, 2},
+    { 0,  0, 0xc4, 0x3b, 2},
+    {16,  0, 0xc2, 0x3b, 2},
+    { 0, 16, 0xe4, 0x3b, 2},
+    {16, 16, 0xe6, 0x3b, 2},
+
+    { 5, 25, 0x6c, 0x38, 2},
+    {11, 25, 0x6c, 0x38, 2},
+    { 0,  0, 0x88, 0x3b, 2},
+    {16,  0, 0x8a, 0x3b, 2},
+    { 0, 16, 0xa8, 0x3b, 2},
+    {16, 16, 0xaa, 0x3b, 2},
+
+    { 5, 25, 0x6c, 0x38, 2},
+    {11, 25, 0x6c, 0x38, 2},
+    { 0,  0, 0x82, 0x3b, 2},
+    {16,  0, 0x82, 0x7b, 2},
+    { 0, 16, 0xa2, 0x3b, 2},
+    {16, 16, 0xa2, 0x7b, 2},
+
+    { 5, 25, 0x6c, 0x38, 2},
+    {11, 25, 0x6c, 0x38, 2},
+    { 0,  0, 0x80, 0x3b, 2},
+    {16,  0, 0x80, 0x7b, 2},
+    { 0, 16, 0xa0, 0x3b, 2},
+    {16, 16, 0xa0, 0x7b, 2},
+  };
+  if (attract_var10 < 0x80 && (Attract_ShowTimedTextMessage(), oam_priority_value != 0)) {
+    k = 4;
+  } else if (attract_var9 != 0x6e) {
+    attract_var9--;
+    k = 0;
+  } else {
+    if (attract_var10 < 31 && !(attract_var10 & 1))
+      INIDISP_copy--;
+    if (!--attract_var10) {
+      attract_sequence++;
+      attract_state -= 2;
+      return;
+    }
+
+    k = attract_var10 >= 0xc0 ? 0 :
+      attract_var10 >= 0xb8 ? 1 :
+      attract_var10 >= 0xb0 ? 2 :
+      attract_var10 >= 0xa0 ? 3 : 4;
+  }
+  if (frame_counter & 1)
+    attract_vram_dst--;
+  attract_x_base = 0x58;
+  attract_y_base = attract_var9;
+  Attract_DrawSpriteSet2(&kZeldaPrison_Oams1[k * 6], 6);
+}
+
+void Attract_ZeldaPrison_DrawA() {
+  OamEnt *oam = &oam_buf[64 + attract_oam_idx];
+  uint8 ext = attract_x_base_hi ? 3 : 2;
+  int j = (attract_var1 >> 3) & 1;
+  SetOamPlain(oam + 0, attract_x_base, attract_y_base + j, 6, 0x3d, ext);
+  SetOamPlain(oam + 1, attract_x_base, attract_y_base + 10, j ? 10 : 8, 0x3d, ext);
+  attract_oam_idx += 2;
+}
+
+void Attract_MaidenWarp_Case0() {
+  if (attract_var11)
+    attract_var5++;
+}
+
+void Attract_MaidenWarp_Case1() {
+  static const AttractOamInfo kZeldaPrison_MaidenWarpCase1_Oam[] = {
+    { 0,  0, 0xce, 0x35, 0},
+    {28,  0, 0xce, 0x35, 0},
+    {-2,  3, 0x26, 0x75, 0},
+    {30,  3, 0x26, 0x35, 0},
+    {-2, 11, 0x36, 0x75, 0},
+    {30, 11, 0x36, 0x35, 0},
+    { 0, 16, 0x26, 0x75, 0},
+    {28, 16, 0x26, 0x35, 0},
+    { 0, 24, 0x36, 0x75, 0},
+    {28, 24, 0x36, 0x35, 0},
+    { 2, 16, 0x20, 0x35, 2},
+    {18, 16, 0x20, 0x75, 2},
+    { 2, 32, 0x20, 0xb5, 2},
+    {18, 32, 0x20, 0xf5, 2},
+    { 0,  0, 0xce, 0x37, 0},
+    {28,  0, 0xce, 0x37, 0},
+    {-2,  3, 0x26, 0x77, 0},
+    {30,  3, 0x26, 0x37, 0},
+    {-2, 11, 0x36, 0x77, 0},
+    {30, 11, 0x36, 0x37, 0},
+    { 0, 16, 0x26, 0x77, 0},
+    {28, 16, 0x26, 0x37, 0},
+    { 0, 24, 0x36, 0x77, 0},
+    {28, 24, 0x36, 0x37, 0},
+    { 2, 16, 0x22, 0x37, 2},
+    {18, 16, 0x22, 0x77, 2},
+    { 2, 32, 0x22, 0xb7, 2},
+    {18, 32, 0x22, 0xf7, 2},
+  };
+  int k = frame_counter >> 2 & 1;
+  static const uint8 kAttract_MaidenWarp_Case1_Num[8] = { 2, 2, 2, 6, 6, 10, 10, 14 };
+  attract_x_base = 110;
+  attract_y_base = 72;
+  Attract_DrawSpriteSet2(kZeldaPrison_MaidenWarpCase1_Oam + k * 14, kAttract_MaidenWarp_Case1_Num[attract_var21 >> 1 & 7]);
+
+  if (!attract_var21 && attract_var20 == 0x70)
+    sound_effect_2 = 0x27;
+
+  if (attract_var21 == 15) {
+    attract_var5++;
+  } else {
+    if (attract_var21 == 6) {
+      intro_times_pal_flash = 0x90;
+      sound_effect_2 = 0x2b;
+    }
+    if (attract_var20)
+      attract_var20--;
+    else
+      attract_var21++;
+  }
+}
+
+void Attract_MaidenWarp_Case2() {
+  static const uint8 kMaidenWarp_Case2_Num[8] = { 4, 4, 8, 8, 12, 12, 14, 14 };
+  static const AttractOamInfo kAttract_MaidenWarpCase2_Oam[] = {
+    { 0,  0, 0xce, 0x35, 0},
+    {28,  0, 0xce, 0x35, 0},
+    {-2,  3, 0x26, 0x75, 0},
+    {30,  3, 0x26, 0x35, 0},
+    {-2, 11, 0x36, 0x75, 0},
+    {30, 11, 0x36, 0x35, 0},
+    { 0, 16, 0x26, 0x75, 0},
+    {28, 16, 0x26, 0x35, 0},
+    { 0, 24, 0x36, 0x75, 0},
+    {28, 24, 0x36, 0x35, 0},
+    { 2, 16, 0x20, 0x35, 2},
+    {18, 16, 0x20, 0x75, 2},
+    { 2, 32, 0x20, 0xb5, 2},
+    {18, 32, 0x20, 0xf5, 2},
+    { 0,  0, 0xce, 0x37, 0},
+    {28,  0, 0xce, 0x37, 0},
+    {-2,  3, 0x26, 0x77, 0},
+    {30,  3, 0x26, 0x37, 0},
+    {-2, 11, 0x36, 0x77, 0},
+    {30, 11, 0x36, 0x37, 0},
+    { 0, 16, 0x26, 0x77, 0},
+    {28, 16, 0x26, 0x37, 0},
+    { 0, 24, 0x36, 0x77, 0},
+    {28, 24, 0x36, 0x37, 0},
+    { 2, 16, 0x22, 0x37, 2},
+    {18, 16, 0x22, 0x77, 2},
+    { 2, 32, 0x22, 0xb7, 2},
+    {18, 32, 0x22, 0xf7, 2},
+  };
+  attract_x_base = 110;
+  attract_y_base = 72;
+  int k = frame_counter >> 2 & 1;
+  int n = kMaidenWarp_Case2_Num[attract_var21 >> 1 & 7];
+  Attract_DrawSpriteSet2(kAttract_MaidenWarpCase2_Oam + k * 14 + (14 - n), n);
+  if (attract_var21 == 0) {
+    if (!--attract_var19)
+      attract_var5++;
+  } else {
+    attract_var21--;
+  }
+}
+
+void Attract_MaidenWarp_Case3() {
+  static const AttractOamInfo kAttract_MaidenWarpCase3_Oam[] = {
+    { 0,  0, 0xc6, 0x3d, 2},
+    { 0,  0, 0x24, 0x35, 2},
+    {16,  0, 0x24, 0x75, 2},
+  };
+  static const uint8 kMaidenWarp_Case3_Xbase[2] = { 0x78, 0x70 };
+
+  if (attract_var21 == 6) {
+    attract_var15++;
+    sound_effect_1 = 51;
+  } else if (attract_var21 == 0x40) {
+    attract_var21 = 224;
+    attract_var5++;
+  } else if (attract_var21 < 0xf) {
+    int k = attract_var21 >> 3 & 1;
+    attract_x_base = kMaidenWarp_Case3_Xbase[k];
+    attract_y_base = 0x60;
+    Attract_DrawSpriteSet2(kAttract_MaidenWarpCase3_Oam + k, k ? 2 : 1);
+  }
+  attract_var21++;
+}
+
+void Attract_MaidenWarp_Case4() {
+  Attract_ShowTimedTextMessage();
+  if (!oam_priority_value) {
+    if (attract_var21 < 31 && !(attract_var21 & 1)) {
+      INIDISP_copy--;
+    }
+    if (!--attract_var21)
+      attract_var22++;
+  }
+}
+
+void Dungeon_LoadAndDrawEntranceRoom(uint8 a) {  // 82c533
+  attract_room_index = a;
+  Dungeon_LoadEntrance();
+  dung_num_lit_torches = 0;
+  hdr_dungeon_dark_with_lantern = 0;
+  Dungeon_LoadAndDrawRoom();
+  Dungeon_ResetTorchBackgroundAndPlayer();
+}
+
+void Dungeon_SaveAndLoadLoadAllPalettes(uint8 a, uint8 k) {  // 82c546
+  sprite_graphics_index = k;
+  main_tile_theme_index = a;
+  aux_tile_theme_index = a;
+  InitializeTilesets();
+  overworld_palette_aux_or_main = 0x200;
+  flag_update_cgram_in_nmi++;
+  Palette_BgAndFixedColor_Black();
+  Palette_Load_Sp0L();
+  Palette_Load_SpriteMain();
+  Palette_Load_Sp5L();
+  Palette_Load_Sp6L();
+  Palette_Load_SpriteEnvironment_Dungeon();
+  Palette_Load_HUD();
+  Palette_Load_DungeonSet();
+}
+
+void Module14_Attract() {  // 8cedad
+  uint8 st = attract_state;
+  if (INIDISP_copy && INIDISP_copy != 128 && st && st != 2 && st != 6 && filtered_joypad_H & 0x90)
+    attract_state = st = 9;
+
+  switch (st) {
+  case 0: Attract_Fade(); break;
+  case 1: Attract_InitGraphics(); break;
+  case 2: Attract_FadeOutSequence(); break;
+  case 3: Attract_LoadNewScene(); break;
+  case 4: Attract_FadeInSequence(); break;
+  case 5: Attract_EnactStory(); break;
+  case 6: Attract_FadeOutSequence(); break;
+  case 7: Attract_LoadNewScene(); break;
+  case 8: Attract_EnactStory(); break;
+  case 9: Attract_SkipToFileSelect(); break;
+  }
+}
+
+void Attract_Fade() {  // 8cede6
+  Intro_HandleAllTriforceAnimations();
+  intro_did_run_step = 0;
+  is_nmi_thread_active = 0;
+  Intro_PeriodicSwordAndIntroFlash();
+  if (INIDISP_copy) {
+    INIDISP_copy--;
+    return;
+  }
+  EnableForceBlank();
+  irq_flag = 255;
+  is_nmi_thread_active = 0;
+  nmi_flag_update_polyhedral = 0;
+  attract_state++;
+}
+
+void Attract_InitGraphics() {  // 8cee0c
+  memset(&attract_var12, 0, 0x51);
+  EraseTileMaps_normal();
+  Attract_LoadBG3GFX();
+  overworld_palette_mode = 4;
+  hud_palette = 1;
+  overworld_palette_aux_or_main = 0;
+  Palette_Load_HUD();
+  overworld_palette_aux_or_main = 0x200;
+  Palette_Load_OWBGMain();
+  Palette_Load_HUD();
+  Palette_Load_LinkArmorAndGloves();
+  main_palette_buffer[0x1d] = 0x3800;
+  flag_update_cgram_in_nmi++;
+  BYTE(BG3VOFS_copy2) = 20;
+  Attract_BuildBackgrounds();
+  messaging_module = 0;
+  dialogue_message_index = 0x112;
+  BG2VOFS_copy2 = 0;
+  attract_legend_ctr = 0x1010;
+  attract_state += 3;
+  HdmaSetup(0xCFA87, 0xCFA94, 1, (uint8)WH0, (uint8)WH2, 0);
+  HDMAEN_copy = 0xc0;
+
+  W12SEL_copy = 0;
+  W34SEL_copy = 0;
+  WOBJSEL_copy = 0xb0;
+  TMW_copy = 3;
+  TSW_copy = 0;
+  COLDATA_copy0 = 0x25;
+  COLDATA_copy1 = 0x45;
+  COLDATA_copy2 = 0x85;
+  CGWSEL_copy = 0x10;
+  CGADSUB_copy = 0xa3;
+
+  music_control = 6;
+  attract_legend_flag++;
+}
+
+void Attract_FadeInStep() {  // 8ceea6
+  if (INIDISP_copy != 15) {
+    if (sign8(--link_speed_setting)) {
+      INIDISP_copy++;
+      link_speed_setting = 1;
+    }
+  } else {
+    attract_var18++;
+  }
+}
+
+void Attract_FadeInSequence() {  // 8ceeba
+  if (INIDISP_copy != 15) {
+    if (sign8(--link_speed_setting)) {
+      INIDISP_copy++;
+      link_speed_setting = 1;
+    }
+  } else {
+    attract_state++;
+  }
+}
+
+void Attract_FadeOutSequence() {  // 8ceecb
+  if (INIDISP_copy != 0) {
+    if (sign8(--link_speed_setting)) {
+      INIDISP_copy--;
+      link_speed_setting = 1;
+    }
+  } else {
+    EnableForceBlank();
+    EraseTileMaps_normal();
+    attract_state++;
+  }
+}
+
+void Attract_LoadNewScene() {  // 8ceee5
+  switch (attract_sequence) {
+  case 0: AttractScene_PolkaDots(); break;
+  case 1: AttractScene_WorldMap(); break;
+  case 2: AttractScene_ThroneRoom(); break;
+  case 3: Attract_PrepZeldaPrison(); break;
+  case 4: Attract_PrepMaidenWarp(); break;
+  case 5: AttractScene_EndOfStory(); break;
+  }
+}
+
+void AttractScene_PolkaDots() {  // 8ceef8
+  attract_next_legend_gfx = 0;
+  attract_state++;
+  INIDISP_copy = 0;
+}
+
+void AttractScene_WorldMap() {  // 8ceeff
+  zelda_ppu_write(BG1SC, 0x13);
+  zelda_ppu_write(BG2SC, 0x3);
+  CGWSEL_copy = 0x80;
+  CGADSUB_copy = 0x21;
+  BGMODE_copy = 7;
+  WorldMap_LoadLightWorldMap();
+  M7Y_copy = 0xed;
+  M7X_copy = 0x100;
+  BG1HOFS_copy = 0x80;
+  BG1VOFS_copy = 0xc0;
+  timer_for_mode7_zoom = 255;
+  Attract_ControlMapZoom();
+  attract_var10 = 1;
+  attract_state++;
+  INIDISP_copy = 0;
+}
+
+void AttractScene_ThroneRoom() {  // 8cef4e
+  HDMAEN_copy = 0;
+  CGWSEL_copy = 2;
+  CGADSUB_copy = 0x20;
+  misc_sprites_graphics_index = 10;
+  LoadCommonSprites();
+  uint16 bak0 = attract_var12;
+  uint16 bak1 = WORD(attract_state);
+  Dungeon_LoadAndDrawEntranceRoom(0x74);
+  WORD(attract_state) = bak1;
+  attract_var12 = bak0;
+  palette_main_indoors = 0;
+  palette_sp0l = 0;
+  palette_sp5l = 14;
+  palette_sp6l = 3;
+  Dungeon_SaveAndLoadLoadAllPalettes(0, 0x7e);
+
+  main_palette_buffer[0x1d] = 0x3800;
+  messaging_module = 0;
+  dialogue_message_index = 0x113;
+  attract_var10 = 2;
+  attract_var13 = 0xe0;
+  oam_priority_value = 0x210;
+
+  Attract_PrepFinish();
+}
+
+void Attract_PrepFinish() {  // 8cefc0
+  attract_state++;
+  INIDISP_copy = 0;
+  BYTE(BG3VOFS_copy2) = 0;
+  BG2HOFS_copy &= 0x1ff;
+  BG2VOFS_copy &= 0x1ff;
+  BG2HOFS_copy2 &= 0x1ff;
+  BG2VOFS_copy2 &= 0x1ff;
+}
+
+void Attract_PrepZeldaPrison() {  // 8cefe3
+  CGWSEL_copy = 0;
+  CGADSUB_copy = 0;
+
+  uint16 bak0 = attract_var12;
+  uint16 bak1 = WORD(attract_state);
+  Dungeon_LoadAndDrawEntranceRoom(0x73);
+  WORD(attract_state) = bak1;
+  attract_var12 = bak0;
+
+  palette_main_indoors = 2;
+  palette_sp0l = 0;
+  palette_sp5l = 14;
+  palette_sp6l = 3;
+  Dungeon_SaveAndLoadLoadAllPalettes(1, 0x7f);
+  main_palette_buffer[0x1d] = 0x3800;
+
+  messaging_module = 0;
+  dialogue_message_index = 0x114;
+
+  attract_var9 = 148;
+  attract_vram_dst = 0x68;
+  attract_var1 = 0;
+  attract_var3 = 0;
+  attract_x_base_hi = 0;
+  attract_var17 = 0;
+  attract_var18 = 0;
+  attract_var10 = 255;
+  oam_priority_value = 0x240;
+  Attract_PrepFinish();
+}
+
+void Attract_PrepMaidenWarp() {  // 8cf058
+  uint16 bak0 = attract_var12;
+  uint16 bak1 = WORD(attract_state);
+  Dungeon_LoadAndDrawEntranceRoom(0x75);
+  WORD(attract_state) = bak1;
+  attract_var12 = bak0;
+
+  palette_main_indoors = 0;
+  palette_sp0l = 0;
+  palette_sp5l = 14;
+  palette_sp6l = 3;
+
+  overworld_palette_aux_or_main = 0;
+  Palette_Load_Sp0L();
+  Palette_Load_SpriteMain();
+  Palette_Load_Sp5L();
+  Palette_Load_Sp6L();
+  Palette_Load_SpriteEnvironment_Dungeon();
+  Palette_Load_HUD();
+  Palette_Load_DungeonSet();
+  Dungeon_SaveAndLoadLoadAllPalettes(2, 0x7f);
+  aux_palette_buffer[0x1d] = main_palette_buffer[0x1d] = 0x3800;
+
+  messaging_module = 0;
+  dialogue_message_index = 0x115;
+  attract_var10 = 255;
+  BYTE(attract_vram_dst) = 112;
+  attract_var19 = 112;
+  attract_var20 = 112;
+  attract_var1 = 8;
+  attract_var17 = 0;
+  attract_var21 = 0;
+  attract_var15 = 0;
+  attract_var18 = 0;
+  attract_var5 = 0;
+  attract_var11 = 0;
+
+  oam_priority_value = 0xc0;
+  Attract_PrepFinish();
+}
+
+void AttractScene_EndOfStory() {  // 8cf0dc
+  Attract_SetUpConclusionHDMA();
+  Death_Func31();
+}
+
+void Death_Func31() {  // 8cf0e2
+  nmi_disable_core_updates++;
+  Intro_InitializeMemory_darken();
+  Overworld_LoadAllPalettes();
+  BYTE(BG3VOFS_copy2) = 0;
+  M7Y_copy = 0;
+  M7X_copy = 0;
+  BG1HOFS_copy = 0;
+  BG1VOFS_copy = 0;
+  BG2HOFS_copy = 0;
+  BG2VOFS_copy = 0;
+  music_control = 0xF1;
+  attract_sequence = 0;
+  main_module_index = 0;
+  submodule_index = 10;
+  subsubmodule_index = 10;
+}
+
+void Attract_EnactStory() {  // 8cf115
+  switch (attract_sequence) {
+  case 0: AttractDramatize_PolkaDots(); break;
+  case 1: AttractDramatize_WorldMap(); break;
+  case 2: Attract_ThroneRoom(); break;
+  case 3: AttractDramatize_Prison(); break;
+  case 4: AttractDramatize_AgahnimAltar(); break;
+  }
+}
+
+void AttractDramatize_PolkaDots() {  // 8cf126
+  if (!(frame_counter & 3)) {
+    BYTE(BG1VOFS_copy)++;
+    BYTE(BG1HOFS_copy)++;
+    BYTE(BG2VOFS_copy)++;
+    BYTE(BG2HOFS_copy)--;
+  }
+
+  if (attract_legend_flag) {
+    Attract_BuildNextImageTileMap();
+    attract_legend_flag = 0;
+    attract_next_legend_gfx += 2;
+  }
+  joypad1L_last = 0;
+  filtered_joypad_L = 0;
+  filtered_joypad_H = 0;
+  RenderText();
+  if (!--attract_legend_ctr) {
+    attract_sequence++;
+    attract_state -= 3;
+  } else {
+    if (attract_legend_ctr < 0x18 && attract_legend_ctr & 1)
+      INIDISP_copy--;
+  }
+}
+
+void AttractDramatize_WorldMap() {  // 8cf176
+  if (timer_for_mode7_zoom != 0) {
+    if (timer_for_mode7_zoom < 15)
+      INIDISP_copy--;
+    if (!--attract_var10) {
+      attract_var10 = 1;
+      timer_for_mode7_zoom -= 1;
+      Attract_ControlMapZoom();
+    }
+  } else {
+    EnableForceBlank();
+    BGMODE_copy = 9;
+    EraseTileMaps_normal();
+    attract_sequence++;
+    attract_state -= 2;
+  }
+}
+
+void Attract_ThroneRoom() {  // 8cf1c8
+  static const AttractOamInfo kThroneRoom_Oams[] = {
+    {16, 16, 0x2a, 0x7b, 2},
+    { 0, 16, 0x2a, 0x3b, 2},
+    {16,  0, 0x0a, 0x7b, 2},
+    { 0,  0, 0x0a, 0x3b, 2},
+    { 0,  0, 0x0c, 0x31, 2},
+    {16,  0, 0x0e, 0x31, 2},
+    {32,  0, 0x0c, 0x71, 2},
+    { 0, 16, 0x2c, 0x31, 2},
+    {16, 16, 0x2e, 0x31, 2},
+    {32, 16, 0x2c, 0x71, 2},
+  };
+  static const uint8 kThroneRoom_OamOffs[3] = { 0, 4, 10 };
+  static const int8 kAttract_ThroneRoom_Xbase[2] = { 80, 104 };
+  static const int8 kAttract_ThroneRoom_Ybase[2] = { 88, 32 };
+  attract_oam_idx = 0;
+  if (!attract_var15) {
+    if (INIDISP_copy != 15)
+      INIDISP_copy++;
+    else
+      attract_var15++;
+  }
+  if (!BG2VOFS_copy) {
+    Attract_ShowTimedTextMessage();
+    if (!oam_priority_value) {
+      if (attract_var13 < 31 && !(attract_var13 & 1))
+        INIDISP_copy--;
+      if (!--attract_var13) {
+        attract_sequence++;
+        attract_state++;
+        return;
+      }
+    }
+  } else {
+    BG2VOFS_copy--;
+    BG1VOFS_copy--;
+  }
+  for (int i = 1; i >= 0; i--) {
+    const AttractOamInfo *oamp = &kThroneRoom_Oams[kThroneRoom_OamOffs[i]];
+    int n = kThroneRoom_OamOffs[i + 1] - kThroneRoom_OamOffs[i];
+    uint16 y = kAttract_ThroneRoom_Ybase[i] - BG2VOFS_copy;
+    if (!sign16(y + 32)) {
+      attract_x_base = kAttract_ThroneRoom_Xbase[i];
+      attract_y_base = y;
+      Attract_DrawSpriteSet2(oamp, n);
+    }
+  }
+
+  attract_var7 = 0xf8a7;
+}
+
+void AttractDramatize_Prison() {  // 8cf27a
+  static const uint8 kAttract_ZeldaPrison_Tab0[16] = { 0, 1, 2, 3, 4, 5, 5, 5, 4, 4, 3, 3, 2, 2, 1, 1 };
+  static const int8 kZeldaPrison_Soldier_X[2] = { 32, -12 };
+  static const int8 kZeldaPrison_Soldier_Y[2] = { 24, 24 };
+  static const uint8 kZeldaPrison_Soldier_Dir[2] = { 1, 1 };
+  static const uint8 kZeldaPrison_Soldier_Flags[2] = { 9, 7 };
+
+  attract_oam_idx = 0;
+  if (!attract_var18)
+    Attract_FadeInStep();
+  attract_x_base = 56;
+  Attract_DrawZelda();
+  if (attract_var10 >= 192) {
+    attract_y_base = 112;
+    if (sign8(--attract_var17))
+      attract_var17 = 0xf;
+    int t = attract_vram_dst + kAttract_ZeldaPrison_Tab0[attract_var17];
+    attract_x_base_hi = t >> 8;
+    attract_x_base = t;
+    Attract_ZeldaPrison_DrawA();
+
+    for (int k = 1; k >= 0; k--) {
+      SpritePrep_ResetProperties(k * 2);
+      uint16 x = kZeldaPrison_Soldier_X[k] + attract_vram_dst + 0x100;
+      attract_var4 = x;
+      Sprite_SimulateSoldier(k * 2,
+                             x, attract_y_base + kZeldaPrison_Soldier_Y[k],
+                             kZeldaPrison_Soldier_Dir[k], kZeldaPrison_Soldier_Flags[k], attract_var3);
+    }
+
+    if (!(++attract_var1 & 7)) {
+      if (attract_var3 == 2) {
+        attract_var3 = 0xff;
+        if (!HIBYTE(attract_vram_dst) && attract_var1 & 8)
+          sound_effect_2 = 4;
+      }
+      attract_var3++;
+    }
+  }
+
+  switch (attract_var5) {
+  case 0: Attract_ZeldaPrison_Case0(); break;
+  case 1: Attract_ZeldaPrison_Case1(); break;
+  }
+}
+
+void AttractDramatize_AgahnimAltar() {  // 8cf423
+  if (attract_var22) {
+    attract_sequence++;
+    attract_state -= 2;
+    return;
+  }
+  attract_oam_idx = 0;
+  HandleScreenFlash();
+  if (!attract_var18)
+    Attract_FadeInStep();
+  if (attract_var17 != 255)
+    attract_var17++;
+  if (intro_times_pal_flash & 4)
+    sound_effect_2 = 0x2b;
+  switch (attract_var5) {
+  case 0: Attract_MaidenWarp_Case0(); break;
+  case 1: Attract_MaidenWarp_Case1(); break;
+  case 2: Attract_MaidenWarp_Case2(); break;
+  case 3: Attract_MaidenWarp_Case3(); break;
+  case 4: Attract_MaidenWarp_Case4(); break;
+  }
+
+  static const uint8 kMaidenWarp_Soldier_X[6] = { 48, 192, 48, 192, 80, 160 };
+  static const uint8 kMaidenWarp_Soldier_Y[6] = { 112, 112, 152, 152, 192, 192 };
+  static const uint8 kMaidenWarp_Soldier_Dir[6] = { 0, 1, 0, 1, 3, 3 };
+  static const uint8 kMaidenWarp_Soldier_Flags[6] = { 9, 9, 9, 9, 7, 9 };
+  for (int k = 5; k >= 0; k--) {
+
+    SpritePrep_ResetProperties(k);
+    Sprite_SimulateSoldier(k, kMaidenWarp_Soldier_X[k], kMaidenWarp_Soldier_Y[k],
+                           kMaidenWarp_Soldier_Dir[k], kMaidenWarp_Soldier_Flags[k], 0);
+  }
+
+  if (attract_var17 >= 0xa0) {
+    if (BYTE(attract_vram_dst) != 0x60) {
+      if (!--attract_var1) {
+        BYTE(attract_vram_dst)--;
+        attract_var1 = 8;
+      }
+    } else {
+      attract_var11++;
+    }
+  }
+
+  if (attract_var15 == 0) {
+    static const AttractOamInfo kZeldaPrison_MaidenWarp0[] = {
+      { 0,  0, 0x03, 0x3d, 2},
+      { 8,  0, 0x04, 0x3d, 2},
+      { 0,  0, 0x00, 0x3d, 2},
+      { 8,  0, 0x01, 0x3d, 2},
+    };
+
+    attract_x_base = 116;
+    attract_y_base = attract_vram_dst;
+    Attract_DrawSpriteSet2(kZeldaPrison_MaidenWarp0 + (BYTE(attract_vram_dst) == 0x70 ? 0 : 2), 2);
+    static const uint8 kAttract_MaidenWarp_Xbase[8] = { 4, 4, 3, 3, 2, 2, 1, 0 };
+    static const AttractOamInfo kZeldaPrison_MaidenWarp1[] = {
+      { 0,  0, 0x6c, 0x38, 2},
+      { 0,  0, 0x6c, 0x38, 2},
+      { 0,  0, 0x6c, 0x38, 2},
+      { 0,  0, 0x6c, 0x38, 2},
+      { 0,  0, 0x6c, 0x38, 2},
+      { 2,  0, 0x6c, 0x38, 2},
+      { 0,  0, 0x6c, 0x38, 2},
+      { 2,  0, 0x6c, 0x38, 2},
+      { 0,  0, 0x6c, 0x38, 2},
+      { 4,  0, 0x6c, 0x38, 2},
+      { 0,  0, 0x6c, 0x38, 2},
+      { 4,  0, 0x6c, 0x38, 2},
+      { 0,  0, 0x6c, 0x38, 2},
+      { 6,  0, 0x6c, 0x38, 2},
+      { 0,  0, 0x6c, 0x38, 2},
+      { 8,  0, 0x6c, 0x38, 2},
+    };
+    int k = 7;
+    if (BYTE(attract_vram_dst) < 0x68)
+      k = (BYTE(attract_vram_dst) - 0x68) & 7;
+    attract_x_base = 0x74 + kAttract_MaidenWarp_Xbase[k];
+    attract_y_base = 0x76;
+    Attract_DrawSpriteSet2(kZeldaPrison_MaidenWarp1 + k * 2, 2);
+
+  }
+  static const AttractOamInfo kZeldaPrison_MaidenWarp2[] = {
+    { 5, 25, 0x6c, 0x38, 2},
+    {11, 25, 0x6c, 0x38, 2},
+    { 0,  0, 0x82, 0x3b, 2},
+    {16,  0, 0x82, 0x7b, 2},
+    { 0, 16, 0xa2, 0x3b, 2},
+    {16, 16, 0xa2, 0x7b, 2},
+    { 5, 25, 0x6c, 0x38, 2},
+    {11, 25, 0x6c, 0x38, 2},
+    { 0,  0, 0x80, 0x3b, 2},
+    {16,  0, 0x82, 0x7b, 2},
+    { 0, 16, 0xa0, 0x3b, 2},
+    {16, 16, 0xa2, 0x7b, 2},
+    { 5, 25, 0x6c, 0x38, 2},
+    {11, 25, 0x6c, 0x38, 2},
+    { 0,  0, 0x82, 0x3b, 2},
+    {16,  0, 0x82, 0x7b, 2},
+    { 0, 16, 0xa2, 0x3b, 2},
+    {16, 16, 0xa2, 0x7b, 2},
+    { 5, 25, 0x6c, 0x38, 2},
+    {11, 25, 0x6c, 0x38, 2},
+    { 0,  0, 0x82, 0x3b, 2},
+    {16,  0, 0x80, 0x7b, 2},
+    { 0, 16, 0xa2, 0x3b, 2},
+    {16, 16, 0xa0, 0x7b, 2},
+    { 5, 25, 0x6c, 0x38, 2},
+    {11, 25, 0x6c, 0x38, 2},
+    { 0,  0, 0x82, 0x3b, 2},
+    {16,  0, 0x82, 0x7b, 2},
+    { 0, 16, 0xa2, 0x3b, 2},
+    {16, 16, 0xa2, 0x7b, 2},
+    { 5, 25, 0x6c, 0x38, 2},
+    {11, 25, 0x6c, 0x38, 2},
+    { 0,  0, 0x80, 0x3b, 2},
+    {16,  0, 0x82, 0x7b, 2},
+    { 0, 16, 0xa0, 0x3b, 2},
+    {16, 16, 0xa2, 0x7b, 2},
+    { 5, 25, 0x6c, 0x38, 2},
+    {11, 25, 0x6c, 0x38, 2},
+    { 0,  0, 0x82, 0x3b, 2},
+    {16,  0, 0x82, 0x7b, 2},
+    { 0, 16, 0xa2, 0x3b, 2},
+    {16, 16, 0xa2, 0x7b, 2},
+    { 5, 25, 0x6c, 0x38, 2},
+    {11, 25, 0x6c, 0x38, 2},
+    { 0,  0, 0x80, 0x3b, 2},
+    {16,  0, 0x80, 0x7b, 2},
+    { 0, 16, 0xa0, 0x3b, 2},
+    {16, 16, 0xa0, 0x7b, 2},
+  };
+  int k = attract_var17 >> 5 & 7;
+  attract_x_base = 112;
+  attract_y_base = 70;
+  Attract_DrawSpriteSet2(kZeldaPrison_MaidenWarp2 + k * 6, 6);
+
+}
+
+void Attract_SkipToFileSelect() {  // 8cf700
+  if (--INIDISP_copy)
+    return;
+  EnableForceBlank();
+  zelda_ppu_write(BG1SC, 0x13);
+  zelda_ppu_write(BG2SC, 0x3);
+  Attract_SetUpConclusionHDMA();
+  M7Y_copy = 0;
+  M7X_copy = 0;
+  BG1HOFS_copy = 0;
+  BG1VOFS_copy = 0;
+  BG3VOFS_copy2 = 0;
+  FadeMusicAndResetSRAMMirror();
+}
+
+void Attract_BuildNextImageTileMap() {  // 8cf73e
+  static const uint8 *const kAttract_LegendGraphics_pointers[4] = {
+    kAttract_Legendgraphics_0,
+    kAttract_Legendgraphics_1,
+    kAttract_Legendgraphics_2,
+    kAttract_Legendgraphics_3,
+  };
+  static const uint16 kAttract_LegendGraphics_sizes[4] = { 157+1, 237+1, 199+1, 265+1 };
+  int i = attract_next_legend_gfx >> 1;
+  memcpy(&g_ram[0x1002], kAttract_LegendGraphics_pointers[i], kAttract_LegendGraphics_sizes[i]);
+  nmi_load_bg_from_vram = 1;
+}
+
+void Attract_ShowTimedTextMessage() {  // 8cf766
+  attract_var12 = BG2VOFS_copy2;
+  BYTE(joypad1L_last) = 0;
+  BYTE(filtered_joypad_L) = 0;
+  BYTE(filtered_joypad_H) = 0;
+  RenderText();
+  if (oam_priority_value)
+    oam_priority_value--;
+}
+
+void Attract_ControlMapZoom() {  // 8cf783
+  for (int i = 240 - 1; i >= 0; i--)
+    hdma_table_dynamic[i] = kMapMode_Zooms1[i] * timer_for_mode7_zoom >> 8;
+}
+
+void Attract_BuildBackgrounds() {  // 8cf7e6
+  static const uint16 kAttract_CopyToVram_Tab0[16] = { 0x1a0, 0x9a6, 0x89a5, 0x1a0, 0x9a5, 0x1a0, 0x1a0, 0x89a6, 0x49a5, 0x1a0, 0x1a0, 0x49a5, 0x1a0, 0x89a5, 0xc9a5, 0x1a0 };
+  static const uint16 kAttract_CopyToVram_Tab1[4] = { 0x9a1, 0x9a2, 0x9a3, 0x9a4 };
+
+  BGMODE_copy = 9;
+  TM_copy = 0x17;
+  TS_copy = 0;
+
+  zelda_ppu_write(BG1SC, 0x10);
+  zelda_ppu_write(BG2SC, 0x0);
+
+  {
+    int k = 0;
+    const uint16 *p = kAttract_CopyToVram_Tab0;
+    uint16 *dst = (uint16 *)&g_ram[0x1006];
+    do {
+      int j = k & 3;
+      do {
+        dst[k++] = p[j++];
+      } while (j & 3);
+    } while (k & 0x1f || (p += 4, k != 0x80));
+    Attract_TriggerBGDMA(0x1000);
+  }
+
+  {
+    int k = 0;
+    uint16 *dst = (uint16 *)&g_ram[0x1006];
+    do {
+      int j = k & 1;
+      const uint16 *p = kAttract_CopyToVram_Tab1 + ((k & 0x20) >> 4);
+      do {
+        dst[k++] = p[j++];
+      } while (j & 1);
+    } while (k != 0x80);
+    Attract_TriggerBGDMA(0);
+  }
+  attract_vram_dst = 0;
+}
+
+void Attract_TriggerBGDMA(uint16 dstv) {  // 8cf879
+  uint16 *dst = &g_zenv.vram[dstv];
+  for (int i = 0; i < 8; i++) {
+    memcpy(dst, &g_ram[0x1006], 0x100);
+    dst += 0x80;
+  }
+}
+
+void Attract_DrawPreloadedSprite(const uint8 *xp, const uint8 *yp, const uint8 *cp, const uint8 *fp, const uint8 *ep, int n) {  // 8cf9b5
+  OamEnt *oam = &oam_buf[attract_oam_idx + 64];
+  attract_oam_idx += n + 1;
+  do {
+    SetOamPlain(oam, attract_x_base + xp[n], attract_y_base + yp[n], cp[n], fp[n], ep[n]);
+  } while (oam++, --n >= 0);
+}
+
+void Attract_DrawZelda() {  // 8cf9e8
+  OamEnt *oam = &oam_buf[64 + attract_oam_idx];
+  SetOamPlain(oam + 0, 0x60, attract_x_base, 0x28, 0x29, 2);
+  SetOamPlain(oam + 1, 0x60, attract_x_base + 10, 0x2a, 0x29, 2);
+  attract_oam_idx += 2;
+}
+
+void Sprite_SimulateSoldier(int k, uint16 x, uint16 y, uint8 dir, uint8 flags, uint8 gfx) {  // 9deb84
+  static const uint8 kSimulateSoldier_Gfx[4] = { 11, 4, 0, 7 };
+  Sprite_SetX(k, x);
+  Sprite_SetY(k, y);
+  sprite_z[k] = 0;
+  Sprite_Get16BitCoords(k);
+  sprite_D[k] = sprite_head_dir[k] = dir;
+  sprite_graphics[k] = kSimulateSoldier_Gfx[dir] + gfx;
+  sprite_flags3[k] = 16;
+  sprite_obj_prio[k] = 0;
+  sprite_oam_flags[k] = flags | 0x30;
+  sprite_type[k] = (flags == 9) ? 0x41 : 0x43;
+  sprite_flags2[k] = 7;
+  int oam_idx = k * 8;
+  oam_cur_ptr = 0x800 + oam_idx * 4;
+  oam_ext_cur_ptr = 0xa20 + oam_idx;
+  Guard_HandleAllAnimation(k);
+}
+
--- /dev/null
+++ b/src/attract.h
@@ -1,0 +1,50 @@
+#pragma once
+typedef struct AttractOamInfo {
+  int8 x, y;
+  uint8 c, f, e;
+} AttractOamInfo;
+
+
+extern const uint16 kMapMode_Zooms1[240];
+extern const uint16 kMapMode_Zooms2[240];
+void Attract_DrawSpriteSet2(const AttractOamInfo *p, int n);
+void Attract_ZeldaPrison_Case0();
+void Attract_ZeldaPrison_Case1();
+void Attract_ZeldaPrison_DrawA();
+void Attract_MaidenWarp_Case0();
+void Attract_MaidenWarp_Case1();
+void Attract_MaidenWarp_Case2();
+void Attract_MaidenWarp_Case3();
+void Attract_MaidenWarp_Case4();
+void Dungeon_LoadAndDrawEntranceRoom(uint8 a);
+void Dungeon_SaveAndLoadLoadAllPalettes(uint8 a, uint8 k);
+void Module14_Attract();
+void Attract_Fade();
+void Attract_InitGraphics();
+void Attract_FadeInStep();
+void Attract_FadeInSequence();
+void Attract_FadeOutSequence();
+void Attract_LoadNewScene();
+void AttractScene_PolkaDots();
+void AttractScene_WorldMap();
+void AttractScene_ThroneRoom();
+void Attract_PrepFinish();
+void Attract_PrepZeldaPrison();
+void Attract_PrepMaidenWarp();
+void AttractScene_EndOfStory();
+void Death_Func31();
+void Attract_EnactStory();
+void AttractDramatize_PolkaDots();
+void AttractDramatize_WorldMap();
+void Attract_ThroneRoom();
+void AttractDramatize_Prison();
+void AttractDramatize_AgahnimAltar();
+void Attract_SkipToFileSelect();
+void Attract_BuildNextImageTileMap();
+void Attract_ShowTimedTextMessage();
+void Attract_ControlMapZoom();
+void Attract_BuildBackgrounds();
+void Attract_TriggerBGDMA(uint16 dstv);
+void Attract_DrawPreloadedSprite(const uint8 *xp, const uint8 *yp, const uint8 *cp, const uint8 *fp, const uint8 *ep, int n);
+void Attract_DrawZelda();
+void Sprite_SimulateSoldier(int k, uint16 x, uint16 y, uint8 dir, uint8 flags, uint8 gfx);
--- /dev/null
+++ b/src/audio.c
@@ -1,0 +1,542 @@
+#include "audio.h"
+#include "zelda_rtl.h"
+#include "variables.h"
+#include "features.h"
+#include "snes/snes_regs.h"
+#include "spc_player.h"
+#include "third_party/opus-1.3.1-stripped/opus.h"
+#include "config.h"
+#include "assets.h"
+
+// This needs to hold a lot more things than with just PCM
+typedef struct MsuPlayerResumeInfo {
+  uint32 tag;
+  uint32 offset;
+  uint32 samples_until_repeat;
+  uint16 range_cur, range_repeat;
+  uint64 initial_packet_bytes;  // To verify we seeked right
+  uint8 orig_track;        // Using the old zelda track numbers
+  uint8 actual_track;      // The MSU track index we're playing (Different if using msu deluxe)
+} MsuPlayerResumeInfo;
+
+enum {
+  kMsuState_Idle = 0,
+  kMsuState_FinishedPlaying = 1,
+  kMsuState_Resuming = 2,
+  kMsuState_Playing = 3,
+};
+
+typedef struct MsuPlayer {
+  FILE *f;
+  uint32 buffer_size, buffer_pos;
+  uint32 preskip, samples_until_repeat;
+  uint32 total_samples_in_file, repeat_position;
+  uint32 cur_file_offs;
+  MsuPlayerResumeInfo resume_info;
+  uint8 enabled;
+  uint8 state;
+  float volume, volume_step, volume_target;
+  uint16 range_cur, range_repeat;
+  OpusDecoder *opus;
+  int16 buffer[960 * 2];
+} MsuPlayer;
+
+static MsuPlayer g_msu_player;
+
+static void MsuPlayer_Open(MsuPlayer *mp, int orig_track, bool resume_from_snapshot);
+
+static const uint8 kMsuTracksWithRepeat[48] = {
+  1,0,1,1,1,1,1,1,0,1,0,1,1,1,1,0,
+  1,1,1,0,1,1,1,1,1,1,1,1,1,0,1,1,
+  1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,
+};
+
+static const uint8 kIsMusicOwOrDungeon[] = {
+  0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, // 1 = ow songs : 2 = lw, 5 = forest, 7 = town, 9 = dark world, 13 = mountain
+  2, 2, 2, 0, 0, 0, 2, 2, 0, 0, 0, 2, 0, 0, 0, 0, // 2 = indoor songs : 16, 17, 18, 22, 23, 27
+};
+
+
+static const uint8 kMsuDeluxe_OW_Songs[] = {
+  37, 37, 42, 38, 38, 38, 38, 39, 37, 37, 42, 38, 38, 38, 38, 41, // lw
+  42, 42, 42, 42, 42, 42, 40, 40, 43, 43, 42, 47, 47, 42, 45, 45,
+  43, 43, 43, 47, 47, 42, 45, 45, 112, 112, 48, 42, 42, 42, 42, 45,
+  44, 44, 48, 48, 48, 46, 46, 46, 44, 44, 44, 48, 48, 46, 46, 46,
+  49, 49, 51, 50, 50, 50, 50, 50, 49, 49, 51, 50, 50, 50, 50, 51, // dw
+  51, 51, 51, 51, 51, 51, 51, 51, 52, 52, 51, 56, 56, 51, 54, 54,
+  52, 52, 52, 56, 56, 51, 54, 54, 58, 52, 57, 51, 51, 51, 51, 54,
+  53, 53, 57, 57, 57, 55, 55, 110, 53, 53, 57, 57, 57, 55, 55, 110,
+  37, 41, 41, 42, 42, 42, 42, 42, 42, 41, 41, 42, 42, 42, 42, 42, // special
+  42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42,
+};
+
+static const uint8 kMsuDeluxe_Entrance_Songs[] = {
+   59,  59,  60,  61,  61,  61,  62,  62,  63,  64,  64,  64, 105,  65,  65,  66,
+   66,  62,  67,  62,  62,  68,  62,  62,  68,  68,  62,  62,  62,  62,  62,  62,
+   62,  62,  62,  62,  69,  70,  71,  72,  73,  73,  73, 106, 102,  74,  62,  62,
+   75,  75,  76,  77,  78,  68,  79,  80,  81,  62,  62,  62,  82,  75, 242,  59,
+   59,  76, 242, 242, 242,  96,  83,  99,  59, 242, 242, 242,  84,  95, 104,  62,
+   85,  62,  62,  86, 242,  67, 103,  83,  83,  87,  76,  88,  81,  98,  81,  88,
+   83,  89,  75,  97,  90,  91,  91, 100,  92,  93,  92, 242,  93, 107,  62,  75,
+   62,  67,  62, 242, 242, 242,  73,  73,  73,  73, 102, 114,  81,  76,  62,  67,
+   62,  61,  94,  62, 103,
+};
+
+
+// Remap an track number into a potentially different track number (used for msu deluxe)
+static uint8 RemapMsuDeluxeTrack(MsuPlayer *mp, uint8 track) {
+  if (!(mp->enabled & kMsuEnabled_MsuDeluxe) || track >= sizeof(kIsMusicOwOrDungeon))
+    return track;
+  switch (kIsMusicOwOrDungeon[track]) {
+  case 1:
+    return BYTE(overworld_area_index) < sizeof(kMsuDeluxe_OW_Songs) ? kMsuDeluxe_OW_Songs[BYTE(overworld_area_index)] : track;
+  case 2:
+    if (which_entrance >= sizeof(kMsuDeluxe_Entrance_Songs) || kMsuDeluxe_Entrance_Songs[which_entrance] == 242)
+      return track;
+    return kMsuDeluxe_Entrance_Songs[which_entrance];
+  default:
+    return track;
+  }
+}
+
+bool ZeldaIsPlayingMusicTrack(uint8 track) {
+  MsuPlayer *mp = &g_msu_player;
+  if (mp->state != kMsuState_Idle && mp->enabled & kMsuEnabled_MsuDeluxe)
+    return RemapMsuDeluxeTrack(mp, track) == mp->resume_info.actual_track;
+  else
+    return track == music_unk1;
+}
+
+bool ZeldaIsPlayingMusicTrackWithBug(uint8 track) {
+  MsuPlayer *mp = &g_msu_player;
+  if (mp->state != kMsuState_Idle && mp->enabled & kMsuEnabled_MsuDeluxe)
+    return RemapMsuDeluxeTrack(mp, track) == mp->resume_info.actual_track;
+  else
+    return track == (enhanced_features0 & kFeatures0_MiscBugFixes ? music_unk1 : last_music_control);
+}
+
+uint8 ZeldaGetEntranceMusicTrack(int i) {
+  MsuPlayer *mp = &g_msu_player;
+  uint8 rv = kEntranceData_musicTrack[i];
+
+  // For some entrances the original performs a fade out, while msu deluxe has new tracks.
+  if (mp->state != kMsuState_Idle && mp->enabled & kMsuEnabled_MsuDeluxe) {
+    if (rv == 242 && kMsuDeluxe_Entrance_Songs[which_entrance] != 242)
+      rv = 16;
+  }
+
+  return rv;
+}
+
+static const uint8 kVolumeTransitionTarget[4] = { 0, 64, 255, 255};
+static const uint8 kVolumeTransitionStep[4] = { 7, 3, 3, 24};
+// These are precomputed in the config parse
+static float kVolumeTransitionStepFloat[4];
+static float kVolumeTransitionTargetFloat[4];
+
+void ZeldaPlayMsuAudioTrack(uint8 music_ctrl) {
+  MsuPlayer *mp = &g_msu_player;
+  if (!mp->enabled) {
+    mp->resume_info.tag = 0;
+    zelda_apu_write(APUI00, music_ctrl);
+    return;
+  }
+  ZeldaApuLock();
+  if ((music_ctrl & 0xf0) != 0xf0)
+    MsuPlayer_Open(mp, music_ctrl, false);
+  else if (music_ctrl >= 0xf1 && music_ctrl <= 0xf3) {
+    mp->volume_target = kVolumeTransitionTargetFloat[music_ctrl - 0xf1];
+    mp->volume_step = kVolumeTransitionStepFloat[music_ctrl - 0xf1];
+  }
+
+  if (mp->state == 0) {
+    zelda_apu_write(APUI00, music_ctrl);
+  } else {
+    zelda_apu_write(APUI00, 0xf0);  // pause spc player
+  }
+  ZeldaApuUnlock();
+}
+
+static void MsuPlayer_CloseFile(MsuPlayer *mp) {
+  if (mp->f)
+    fclose(mp->f);
+  opus_decoder_destroy(mp->opus);
+  mp->opus = NULL;
+  mp->f = NULL;
+  if (mp->state != kMsuState_FinishedPlaying)
+    mp->state = kMsuState_Idle;
+  memset(&mp->resume_info, 0, sizeof(mp->resume_info));
+}
+
+static void MsuPlayer_Open(MsuPlayer *mp, int orig_track, bool resume_from_snapshot) {
+  MsuPlayerResumeInfo resume;
+  int actual_track = RemapMsuDeluxeTrack(mp, orig_track);
+
+  if (!resume_from_snapshot) {
+    resume.tag = 0;
+    // Attempt to resume MSU playback when exiting back to the overworld.
+    if (main_module_index == 9 &&
+        actual_track == ((MsuPlayerResumeInfo *)msu_resume_info_alt)->actual_track && g_config.resume_msu) {
+      memcpy(&resume, msu_resume_info_alt, sizeof(mp->resume_info));
+    }
+    if (mp->state >= kMsuState_Resuming)
+      memcpy(msu_resume_info_alt, &mp->resume_info, sizeof(mp->resume_info));
+  } else {
+    memcpy(&resume, msu_resume_info, sizeof(mp->resume_info));
+  }
+
+  mp->volume_target = kVolumeTransitionTargetFloat[3];
+  mp->volume_step = kVolumeTransitionStepFloat[3];
+
+  mp->state = kMsuState_Idle;
+  MsuPlayer_CloseFile(mp);
+  if (actual_track == 0)
+    return;
+  char fname[256], buf[8];
+  snprintf(fname, sizeof(fname), "%s%d.%s", g_config.msu_path ? g_config.msu_path : "", actual_track, mp->enabled & kMsuEnabled_Opuz ? "opuz" : "pcm");
+  printf("Loading MSU %s\n", fname);
+  mp->f = fopen(fname, "rb");
+  if (mp->f == NULL)
+    goto READ_ERROR;
+  setvbuf(mp->f, NULL, _IOFBF, 16384);
+  if (fread(buf, 1, 8, mp->f) != 8) READ_ERROR: {
+    fprintf(stderr, "Unable to read MSU file %s\n", fname);
+    MsuPlayer_CloseFile(mp);
+    return;
+  }
+  uint32 file_tag = *(uint32 *)(buf + 0);
+  mp->repeat_position = *(uint32 *)(buf + 4);
+  mp->state = (resume.actual_track == actual_track && resume.tag == file_tag) ? kMsuState_Resuming : kMsuState_Playing;
+  if (mp->state == kMsuState_Resuming) {
+    memcpy(&mp->resume_info, &resume, sizeof(mp->resume_info));
+  } else {
+    mp->resume_info.orig_track = orig_track;
+    mp->resume_info.actual_track = actual_track;
+    mp->resume_info.tag = file_tag;
+    mp->resume_info.range_cur = 8;
+  }
+  mp->cur_file_offs = mp->resume_info.offset;
+  mp->samples_until_repeat = mp->resume_info.samples_until_repeat;
+  mp->range_cur = mp->resume_info.range_cur;
+  mp->range_repeat = mp->resume_info.range_repeat;
+  mp->buffer_size = mp->buffer_pos = 0;
+  mp->preskip = 0;
+  if (file_tag == (('Z' << 24) | ('U' << 16) | ('P' << 8) | 'O')) {
+    mp->opus = opus_decoder_create(48000, 2, NULL);
+    if (!mp->opus)
+      goto READ_ERROR;
+    if (mp->state == kMsuState_Resuming)
+      fseek(mp->f, mp->cur_file_offs, SEEK_SET);
+  } else if (file_tag == (('1' << 24) | ('U' << 16) | ('S' << 8) | 'M')) {
+    fseek(mp->f, 0, SEEK_END);
+    mp->total_samples_in_file = (ftell(mp->f) - 8) / 4;
+    mp->samples_until_repeat = mp->total_samples_in_file - mp->cur_file_offs;
+    fseek(mp->f, mp->cur_file_offs * 4 + 8, SEEK_SET);
+  } else {
+    goto READ_ERROR;
+  }
+}
+
+static void MixToBufferWithVolume(int16 *dst, const int16 *src, size_t n, float volume) {
+  if (volume == 1.0f) {
+    for (size_t i = 0; i < n; i++) {
+      dst[i * 2 + 0] += src[i * 2 + 0];
+      dst[i * 2 + 1] += src[i * 2 + 1];
+    }
+  } else {
+    uint32 vol = (int32)(65536 * volume);
+    for (size_t i = 0; i < n; i++) {
+      dst[i * 2 + 0] += src[i * 2 + 0] * vol >> 16;
+      dst[i * 2 + 1] += src[i * 2 + 1] * vol >> 16;
+    }
+  }
+}
+
+static void MixToBufferWithVolumeRamp(int16 *dst, const int16 *src, size_t n, float volume, float volume_step, float ideal_target) {
+  int64 vol = volume * 281474976710656.0f;
+  int64 step = volume_step * 281474976710656.0f;
+  for (size_t i = 0; i < n; i++) {
+    uint32 v = (vol >> 32);
+    dst[i * 2 + 0] += src[i * 2 + 0] * v >> 16;
+    dst[i * 2 + 1] += src[i * 2 + 1] * v >> 16;
+    vol += step;
+  }
+}
+
+static void MixToBuffer(MsuPlayer *mp, int16 *dst, const int16 *src, uint32 n) {
+  if (mp->volume != mp->volume_target) {
+    float step = mp->volume < mp->volume_target ? mp->volume_step : -mp->volume_step;
+    float new_vol = mp->volume + step * n;
+    uint32 curn = n;
+    if (step >= 0 ? new_vol >= mp->volume_target : new_vol < mp->volume_target) {
+      uint32 maxn = (uint32)((mp->volume_target - mp->volume) / step);
+      curn = UintMin(maxn, curn);
+      new_vol = mp->volume_target;
+    }
+    float vol = mp->volume;
+    mp->volume = new_vol;
+    MixToBufferWithVolumeRamp(dst, src, curn, vol, step, new_vol);
+    dst += curn * 2, src += curn * 2, n -= curn;
+  }
+  MixToBufferWithVolume(dst, src, n, mp->volume);
+}
+
+void MsuPlayer_Mix(MsuPlayer *mp, int16 *audio_buffer, int audio_samples) {
+  int r;
+
+  do {
+    if (mp->buffer_size - mp->buffer_pos == 0) {
+      if (mp->opus != NULL) {
+        if (mp->samples_until_repeat == 0) {
+          if (mp->range_cur == 0) FINISHED_PLAYING: {
+            mp->state = kMsuState_FinishedPlaying;
+            MsuPlayer_CloseFile(mp);
+            return;
+          }
+          opus_decoder_ctl(mp->opus, OPUS_RESET_STATE);
+          fseek(mp->f, mp->range_cur, SEEK_SET);
+          uint8 *file_data = (uint8 *)mp->buffer;
+          if (fread(file_data, 1, 10, mp->f) != 10) READ_ERROR: {
+            fprintf(stderr, "MSU read/decode error!\n");
+            zelda_apu_write(APUI00, mp->resume_info.orig_track);
+            MsuPlayer_CloseFile(mp);
+            return;
+          }
+          uint32 file_offs = *(uint32 *)&file_data[0];
+          assert((file_offs & 0xF0000000) == 0);
+          uint32 samples_until_repeat = *(uint32 *)&file_data[4];
+          uint16 preskip = *(uint32 *)&file_data[8];
+          mp->samples_until_repeat = samples_until_repeat;
+          mp->preskip = preskip & 0x3fff;
+          if (preskip & 0x4000)
+            mp->range_repeat = mp->range_cur;
+          mp->range_cur = (preskip & 0x8000) ? mp->range_repeat : mp->range_cur + 10;
+          mp->cur_file_offs = file_offs;
+          mp->resume_info.range_repeat = mp->range_repeat;
+          mp->resume_info.range_cur = mp->range_cur;
+          fseek(mp->f, file_offs, SEEK_SET);
+        }
+        assert(mp->samples_until_repeat != 0);
+        for (;;) {
+          uint8 *file_data = (uint8 *)mp->buffer;
+          *(uint64 *)file_data = 0;
+          if (fread(file_data, 1, 2, mp->f) != 2)
+            goto READ_ERROR;
+          int size = *(uint16 *)file_data & 0x7fff;
+          if (size > 1275)
+            goto READ_ERROR;
+          int n = (*(uint16 *)file_data >> 15);
+          if (fread(&file_data[2], 1, size, mp->f) != size)
+            goto READ_ERROR;
+          // Verify if the snapshot matches the file on disk.
+          uint64 initial_file_data = *(uint64 *)file_data;
+          if (mp->state == kMsuState_Resuming) {
+            mp->state = kMsuState_Playing;
+            if (mp->resume_info.initial_packet_bytes != initial_file_data)
+              goto READ_ERROR;
+          }
+          mp->resume_info.initial_packet_bytes = initial_file_data;
+          mp->resume_info.samples_until_repeat = mp->samples_until_repeat + mp->preskip;
+          mp->resume_info.offset = mp->cur_file_offs;
+          mp->cur_file_offs += 2 + size;
+          file_data[1] = 0xfc;
+          r = opus_decode(mp->opus, &file_data[2 - n], size + n, mp->buffer, 960, 0);
+          if (r <= 0)
+            goto READ_ERROR;
+          if (r > mp->preskip)
+            break;
+          mp->preskip -= r;
+        }
+      } else {
+        if (mp->samples_until_repeat == 0) {
+          if (mp->resume_info.actual_track < sizeof(kMsuTracksWithRepeat) && !kMsuTracksWithRepeat[mp->resume_info.actual_track])
+            goto FINISHED_PLAYING;
+          mp->samples_until_repeat = mp->total_samples_in_file - mp->repeat_position;
+          if (mp->samples_until_repeat == 0)
+            goto READ_ERROR; // impossible to make progress
+          mp->cur_file_offs = mp->repeat_position;
+          fseek(mp->f, mp->cur_file_offs * 4 + 8, SEEK_SET);
+        }
+        r = UintMin(960, mp->samples_until_repeat);
+        if (fread(mp->buffer, 4, r, mp->f) != r)
+          goto READ_ERROR;
+        mp->resume_info.offset = mp->cur_file_offs;
+        mp->cur_file_offs += r;
+      }
+      uint32 n = UintMin(r - mp->preskip, mp->samples_until_repeat);
+      mp->samples_until_repeat -= n;
+      mp->buffer_pos = mp->preskip;
+      mp->buffer_size = mp->buffer_pos + n;
+      mp->preskip = 0;
+    }
+#if 0
+    if (mp->samples_to_play > 44100 * 5) {
+      mp->buffer_pos = mp->buffer_size;
+    }
+#endif
+    int nr = IntMin(audio_samples, mp->buffer_size - mp->buffer_pos);
+    int16 *buf = mp->buffer + mp->buffer_pos * 2;
+    mp->buffer_pos += nr;
+
+#if 0
+    static int t;
+    for (int i = 0; i < nr; i++) {
+      buf[i * 2 + 0] = buf[i * 2 + 1] = 5000 * sinf(2 * 3.1415 * t++ / 440);
+    }
+#endif
+    MixToBuffer(mp, audio_buffer, buf, nr);
+
+#if 0
+    static FILE *f;
+    if (!f)f = fopen("out.pcm", "wb");
+    fwrite(audio_buffer, 4, nr, f);
+    fflush(f);
+#endif
+    audio_samples -= nr, audio_buffer += nr * 2;
+  } while (audio_samples != 0);
+}
+
+// Maintain a queue cause the snes and audio callback are not in sync.
+struct ApuWriteEnt {
+  uint8 ports[4];
+};
+static struct ApuWriteEnt g_apu_write_ents[16], g_apu_write;
+static uint8 g_apu_write_ent_pos, g_apu_write_count, g_apu_total_write;
+void zelda_apu_write(uint32_t adr, uint8_t val) {
+  g_apu_write.ports[adr & 0x3] = val;
+}
+
+void ZeldaPushApuState() {
+  ZeldaApuLock();
+  g_apu_write_ents[g_apu_write_ent_pos++ & 0xf] = g_apu_write;
+  if (g_apu_write_count < 16)
+    g_apu_write_count++;
+  g_apu_total_write++;
+  ZeldaApuUnlock();
+}
+
+static void ZeldaPopApuState() {
+  if (g_apu_write_count != 0)
+    memcpy(g_zenv.player->input_ports, &g_apu_write_ents[(g_apu_write_ent_pos - g_apu_write_count--) & 0xf], 4);
+}
+
+void ZeldaDiscardUnusedAudioFrames() {
+  if (g_apu_write_count != 0 && memcmp(g_zenv.player->input_ports, &g_apu_write_ents[(g_apu_write_ent_pos - g_apu_write_count) & 0xf], 4) == 0) {
+    if (g_apu_total_write >= 16) {
+      g_apu_total_write = 14;
+      g_apu_write_count--;
+    }
+  } else {
+    g_apu_total_write = 0;
+  }
+}
+
+static void ZeldaResetApuQueue() {
+  g_apu_write_ent_pos = g_apu_total_write = g_apu_write_count = 0;
+}
+
+uint8_t zelda_read_apui00() {
+  // This needs to be here because the ancilla code reads
+  // from the apu and we don't want to make the core code
+  // dependent on the apu timings, so relocated this value
+  // to 0x648.
+  return g_ram[kRam_APUI00];
+}
+
+uint8_t zelda_apu_read(uint32_t adr) {
+  return g_zenv.player->port_to_snes[adr & 0x3];
+}
+
+void ZeldaRenderAudio(int16 *audio_buffer, int samples, int channels) {
+  ZeldaApuLock();
+  ZeldaPopApuState();
+  SpcPlayer_GenerateSamples(g_zenv.player);
+  dsp_getSamples(g_zenv.player->dsp, audio_buffer, samples, channels);
+  if (g_msu_player.f && channels == 2)
+    MsuPlayer_Mix(&g_msu_player, audio_buffer, samples);
+  ZeldaApuUnlock();
+}
+
+bool ZeldaIsMusicPlaying() {
+  if (g_msu_player.state != kMsuState_Idle) {
+    return g_msu_player.state != kMsuState_FinishedPlaying;
+  } else {
+    return g_zenv.player->port_to_snes[0] != 0;
+  }
+}
+
+void ZeldaRestoreMusicAfterLoad_Locked(bool is_reset) {
+  // Restore spc variables from the ram dump.
+  SpcPlayer_CopyVariablesFromRam(g_zenv.player);
+  // This is not stored in the snapshot
+  g_zenv.player->timer_cycles = 0;
+
+  // Restore input ports state
+  SpcPlayer *spc_player = g_zenv.player;
+  memcpy(spc_player->input_ports, &spc_player->ram[0x410], 4);
+  memcpy(g_apu_write.ports, spc_player->input_ports, 4);
+
+  if (is_reset) {
+    SpcPlayer_Initialize(g_zenv.player);
+  }
+
+  MsuPlayer *mp = &g_msu_player;
+  if (mp->enabled) {
+    mp->volume = 0.0;
+    MsuPlayer_Open(mp, (music_unk1 == 0xf1) ? ((MsuPlayerResumeInfo*)msu_resume_info)->orig_track : 
+                   music_unk1, true);
+
+    // If resuming in the middle of a transition, then override
+    // the volume with that of the transition.
+    if (last_music_control >= 0xf1 && last_music_control <= 0xf3) {
+      uint8 target = kVolumeTransitionTarget[last_music_control - 0xf1];
+      if (target != msu_volume) {
+        float f = kVolumeTransitionTargetFloat[3] * (1.0f / 255);
+        mp->volume = msu_volume * f;
+        mp->volume_target = target * f;
+        mp->volume_step = kVolumeTransitionStepFloat[last_music_control - 0xf1];
+      }
+    }
+
+    if (g_msu_player.state)
+      zelda_apu_write(APUI00, 0xf0);  // pause spc player
+  }
+  ZeldaResetApuQueue();
+}
+
+void ZeldaSaveMusicStateToRam_Locked() {
+  SpcPlayer_CopyVariablesToRam(g_zenv.player);
+  // SpcPlayer.input_ports is not saved to the SpcPlayer ram by SpcPlayer_CopyVariablesToRam,
+  // in any case, we want to save the most recently written data, and that might still
+  // be in the queue. 0x410 is a free memory location in the SPC ram, so store it there.
+  SpcPlayer *spc_player = g_zenv.player;
+  memcpy(&spc_player->ram[0x410], g_apu_write.ports, 4);
+
+  msu_volume = g_msu_player.volume * 255;
+  memcpy(msu_resume_info, &g_msu_player.resume_info, sizeof(g_msu_player.resume_info));
+}
+
+void ZeldaEnableMsu(uint8 enable) {
+  g_msu_player.volume = 1.0f;
+  g_msu_player.enabled = enable;
+  if (enable & kMsuEnabled_Opuz) {
+    if (g_config.audio_freq != 48000)
+      fprintf(stderr, "Warning: MSU Opuz requires: AudioFreq = 48000\n");
+  } else if (enable) {
+    if (g_config.audio_freq != 44100)
+      fprintf(stderr, "Warning: MSU requires: AudioFreq = 44100\n");
+  }
+
+  float volscale = g_config.msuvolume * (1.0f / 255 / 100);
+  float stepscale = g_config.msuvolume * (60.0f / 256 / 100) / g_config.audio_freq;
+  for (size_t i = 0; i != countof(kVolumeTransitionStepFloat); i++) {
+    kVolumeTransitionStepFloat[i] = kVolumeTransitionStep[i] * stepscale;
+    kVolumeTransitionTargetFloat[i] = kVolumeTransitionTarget[i] * volscale;
+  }
+}
+
+void LoadSongBank(const uint8 *p) {  // 808888
+  ZeldaApuLock();
+  SpcPlayer_Upload(g_zenv.player, p);
+  ZeldaApuUnlock();
+}
--- /dev/null
+++ b/src/audio.h
@@ -1,0 +1,20 @@
+#ifndef ZELDA3_AUDIO_H_
+#define ZELDA3_AUDIO_H_
+
+#include "types.h"
+
+// Things for msu
+bool ZeldaIsPlayingMusicTrack(uint8 track);
+bool ZeldaIsPlayingMusicTrackWithBug(uint8 track);
+void ZeldaPlayMsuAudioTrack(uint8 track);
+bool ZeldaIsMusicPlaying();
+
+void ZeldaEnableMsu(uint8 enable);
+
+void ZeldaRenderAudio(int16 *audio_buffer, int samples, int channels);
+void ZeldaDiscardUnusedAudioFrames();
+void ZeldaRestoreMusicAfterLoad_Locked(bool is_reset);
+void ZeldaSaveMusicStateToRam_Locked();
+void ZeldaPushApuState();
+
+#endif  // ZELDA3_AUDIO_H_
--- /dev/null
+++ b/src/config.c
@@ -1,0 +1,529 @@
+#include "config.h"
+#include "types.h"
+#include <stdio.h>
+#include <string.h>
+#include <SDL.h>
+#include "features.h"
+#include "util.h"
+
+enum {
+  kKeyMod_ScanCode = 0x200,
+  kKeyMod_Alt = 0x400,
+  kKeyMod_Shift = 0x800,
+  kKeyMod_Ctrl = 0x1000,
+};
+
+Config g_config;
+
+#define REMAP_SDL_KEYCODE(key) ((key) & SDLK_SCANCODE_MASK ? kKeyMod_ScanCode : 0) | (key) & (kKeyMod_ScanCode - 1)
+#define _(x) REMAP_SDL_KEYCODE(x)
+#define S(x) REMAP_SDL_KEYCODE(x) | kKeyMod_Shift
+#define A(x) REMAP_SDL_KEYCODE(x) | kKeyMod_Alt
+#define C(x) REMAP_SDL_KEYCODE(x) | kKeyMod_Ctrl
+#define N 0
+static const uint16 kDefaultKbdControls[kKeys_Total] = {
+  0,
+  // Controls
+  _(SDLK_UP), _(SDLK_DOWN), _(SDLK_LEFT), _(SDLK_RIGHT), _(SDLK_RSHIFT), _(SDLK_RETURN), _(SDLK_x), _(SDLK_z), _(SDLK_s), _(SDLK_a), _(SDLK_c), _(SDLK_v),
+  // LoadState
+  _(SDLK_F1), _(SDLK_F2), _(SDLK_F3), _(SDLK_F4), _(SDLK_F5), _(SDLK_F6), _(SDLK_F7), _(SDLK_F8), _(SDLK_F9), _(SDLK_F10), N, N, N, N, N, N, N, N, N, N,
+  // SaveState
+  S(SDLK_F1), S(SDLK_F2), S(SDLK_F3), S(SDLK_F4), S(SDLK_F5), S(SDLK_F6), S(SDLK_F7), S(SDLK_F8), S(SDLK_F9), S(SDLK_F10), N, N, N, N, N, N, N, N, N, N,
+  // Replay State
+  C(SDLK_F1), C(SDLK_F2), C(SDLK_F3), C(SDLK_F4), C(SDLK_F5), C(SDLK_F6), C(SDLK_F7), C(SDLK_F8), C(SDLK_F9), C(SDLK_F10), N, N, N, N, N, N, N, N, N, N,
+  // Load Ref State
+  N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N,
+  // Replay Ref State
+  N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N,
+  // CheatLife, CheatKeys, CheatEquipment, CheatWalkThroughWalls
+  _(SDLK_w), _(SDLK_o), S(SDLK_w), C(SDLK_e),
+  // ClearKeyLog, StopReplay, Fullscreen, Reset, Pause, PauseDimmed, Turbo, ReplayTurbo, WindowBigger, WindowSmaller, DisplayPerf, ToggleRenderer
+  _(SDLK_k), _(SDLK_l), A(SDLK_RETURN), C(SDLK_r), S(SDLK_p), _(SDLK_p), _(SDLK_TAB), _(SDLK_t), N, N, _(SDLK_f), _(SDLK_r),
+};
+#undef _
+#undef A
+#undef C
+#undef S
+#undef N
+
+typedef struct KeyNameId {
+  const char *name;
+  uint16 id, size;
+} KeyNameId;
+
+#define M(n) {#n, kKeys_##n, kKeys_##n##_Last - kKeys_##n + 1}
+#define S(n) {#n, kKeys_##n, 1}
+static const KeyNameId kKeyNameId[] = {
+  {"Null", kKeys_Null, 65535},
+  M(Controls), M(Load), M(Save), M(Replay), M(LoadRef), M(ReplayRef),
+  S(CheatLife), S(CheatKeys), S(CheatEquipment), S(CheatWalkThroughWalls),
+  S(ClearKeyLog), S(StopReplay), S(Fullscreen), S(Reset),
+  S(Pause), S(PauseDimmed), S(Turbo), S(ReplayTurbo), S(WindowBigger), S(WindowSmaller), S(VolumeUp), S(VolumeDown), S(DisplayPerf), S(ToggleRenderer),
+};
+#undef S
+#undef M
+typedef struct KeyMapHashEnt {
+  uint16 key, cmd, next;
+} KeyMapHashEnt;
+
+static uint16 keymap_hash_first[255];
+static KeyMapHashEnt *keymap_hash;
+static int keymap_hash_size;
+static bool has_keynameid[countof(kKeyNameId)];
+
+static bool KeyMapHash_Add(uint16 key, uint16 cmd) {
+  if ((keymap_hash_size & 0xff) == 0) {
+    if (keymap_hash_size > 10000)
+      Die("Too many keys");
+    keymap_hash = realloc(keymap_hash, sizeof(KeyMapHashEnt) * (keymap_hash_size + 256));
+  }
+  int i = keymap_hash_size++;
+  KeyMapHashEnt *ent = &keymap_hash[i];
+  ent->key = key;
+  ent->cmd = cmd;
+  ent->next = 0;
+  int j = (uint32)key % 255;
+
+  uint16 *cur = &keymap_hash_first[j];
+  while (*cur) {
+    KeyMapHashEnt *ent = &keymap_hash[*cur - 1];
+    if (ent->key == key)
+      return false;
+    cur = &ent->next;
+  }
+  *cur = i + 1;
+  return true;
+}
+
+static int KeyMapHash_Find(uint16 key) {
+  int i = keymap_hash_first[key % 255];
+  while (i) {
+    KeyMapHashEnt *ent = &keymap_hash[i - 1];
+    if (ent->key == key)
+      return ent->cmd;
+    i = ent->next;
+  }
+  return 0;
+}
+
+int FindCmdForSdlKey(SDL_Keycode code, SDL_Keymod mod) {
+  if (code & ~(SDLK_SCANCODE_MASK | 0x1ff))
+    return 0;
+  int key = 0;
+  if (code != SDLK_LALT && code != SDLK_RALT)
+    key |=  mod & KMOD_ALT ? kKeyMod_Alt : 0;
+  if (code != SDLK_LCTRL && code != SDLK_RCTRL)
+    key |= mod & KMOD_CTRL ? kKeyMod_Ctrl : 0;
+  if (code != SDLK_LSHIFT && code != SDLK_RSHIFT)
+    key |= mod & KMOD_SHIFT ? kKeyMod_Shift : 0;
+  key |= REMAP_SDL_KEYCODE(code);
+  return KeyMapHash_Find(key);
+}
+
+static void ParseKeyArray(char *value, int cmd, int size) {
+  char *s;
+  int i = 0;
+  for (; i < size && (s = NextDelim(&value, ',')) != NULL; i++, cmd += (cmd != 0)) {
+    if (*s == 0)
+      continue;
+    int key_with_mod = 0;
+    for (;;) {
+      if (StringStartsWithNoCase(s, "Shift+")) {
+        key_with_mod |= kKeyMod_Shift, s += 6;
+      } else if (StringStartsWithNoCase(s, "Ctrl+")) {
+        key_with_mod |= kKeyMod_Ctrl, s += 5;
+      } else if (StringStartsWithNoCase(s, "Alt+")) {
+        key_with_mod |= kKeyMod_Alt, s += 4;
+      } else {
+        break;
+      }
+    }
+    SDL_Keycode key = SDL_GetKeyFromName(s);
+    if (key == SDLK_UNKNOWN) {
+      fprintf(stderr, "Unknown key: '%s'\n", s);
+      continue;
+    }
+    if (!KeyMapHash_Add(key_with_mod | REMAP_SDL_KEYCODE(key), cmd))
+      fprintf(stderr, "Duplicate key: '%s'\n", s);
+  }
+}
+
+typedef struct GamepadMapEnt {
+  uint32 modifiers;
+  uint16 cmd, next;
+} GamepadMapEnt;
+
+static uint16 joymap_first[kGamepadBtn_Count];
+static GamepadMapEnt *joymap_ents;
+static int joymap_size;
+static bool has_joypad_controls;
+
+static int CountBits32(uint32 n) {
+  int count = 0;
+  for (; n != 0; count++)
+    n &= (n - 1);
+  return count;
+}
+
+static void GamepadMap_Add(int button, uint32 modifiers, uint16 cmd) {
+  if ((joymap_size & 0xff) == 0) {
+    if (joymap_size > 1000)
+      Die("Too many joypad keys");
+    joymap_ents = realloc(joymap_ents, sizeof(GamepadMapEnt) * (joymap_size + 64));
+    if (!joymap_ents) Die("realloc failure");
+  }
+  uint16 *p = &joymap_first[button];
+  // Insert it as early as possible but before after any entry with more modifiers.
+  int cb = CountBits32(modifiers);
+  while (*p && cb < CountBits32(joymap_ents[*p - 1].modifiers))
+    p = &joymap_ents[*p - 1].next;
+  int i = joymap_size++;
+  GamepadMapEnt *ent = &joymap_ents[i];
+  ent->modifiers = modifiers;
+  ent->cmd = cmd;
+  ent->next = *p;
+  *p = i + 1;
+}
+
+int FindCmdForGamepadButton(int button, uint32 modifiers) {
+  GamepadMapEnt *ent;
+  for(int e = joymap_first[button]; e != 0; e = ent->next) {
+    ent = &joymap_ents[e - 1];
+    if ((modifiers & ent->modifiers) == ent->modifiers)
+      return ent->cmd;
+  }
+  return 0;
+}
+
+static int ParseGamepadButtonName(const char **value) {
+  const char *s = *value;
+  // Longest substring first
+  static const char *const kGamepadKeyNames[] = {
+    "Back", "Guide", "Start", "L3", "R3",
+    "L1", "R1", "DpadUp", "DpadDown", "DpadLeft", "DpadRight", "L2", "R2",
+    "Lb", "Rb", "A", "B", "X", "Y"
+  };
+  static const uint8 kGamepadKeyIds[] = {
+    kGamepadBtn_Back, kGamepadBtn_Guide, kGamepadBtn_Start, kGamepadBtn_L3, kGamepadBtn_R3,
+    kGamepadBtn_L1, kGamepadBtn_R1, kGamepadBtn_DpadUp, kGamepadBtn_DpadDown, kGamepadBtn_DpadLeft, kGamepadBtn_DpadRight, kGamepadBtn_L2, kGamepadBtn_R2,
+    kGamepadBtn_L1, kGamepadBtn_R1, kGamepadBtn_A, kGamepadBtn_B, kGamepadBtn_X, kGamepadBtn_Y,
+  };
+  for (size_t i = 0; i != countof(kGamepadKeyNames); i++) {
+    const char *r = StringStartsWithNoCase(s, kGamepadKeyNames[i]);
+    if (r) {
+      *value = r;
+      return kGamepadKeyIds[i];
+    }
+  }
+  return kGamepadBtn_Invalid;
+}
+
+static const uint8 kDefaultGamepadCmds[] = {
+  kGamepadBtn_DpadUp, kGamepadBtn_DpadDown, kGamepadBtn_DpadLeft, kGamepadBtn_DpadRight, kGamepadBtn_Back, kGamepadBtn_Start,
+  kGamepadBtn_B, kGamepadBtn_A, kGamepadBtn_Y, kGamepadBtn_X, kGamepadBtn_L1, kGamepadBtn_R1,
+};
+
+static void ParseGamepadArray(char *value, int cmd, int size) {
+  char *s;
+  int i = 0;
+  for (; i < size && (s = NextDelim(&value, ',')) != NULL; i++, cmd += (cmd != 0)) {
+    if (*s == 0)
+      continue;
+    uint32 modifiers = 0;
+    const char *ss = s;
+    for (;;) {
+      int button = ParseGamepadButtonName(&ss);
+      if (button == kGamepadBtn_Invalid) BAD: {
+        fprintf(stderr, "Unknown gamepad button: '%s'\n", s);
+        break;
+      }
+      while (*ss == ' ' || *ss == '\t') ss++;
+      if (*ss == '+') {
+        ss++;
+        modifiers |= 1 << button;
+      } else if (*ss == 0) {
+        GamepadMap_Add(button, modifiers, cmd);
+        break;
+      } else
+        goto BAD;
+    }
+  }
+}
+
+static void RegisterDefaultKeys() {
+  for (int i = 1; i < countof(kKeyNameId); i++) {
+    if (!has_keynameid[i]) {
+      int size = kKeyNameId[i].size, k = kKeyNameId[i].id;
+      for (int j = 0; j < size; j++, k++)
+        KeyMapHash_Add(kDefaultKbdControls[k], k);
+    }
+  }
+  if (!has_joypad_controls) {
+    for (int i = 0; i < countof(kDefaultGamepadCmds); i++)
+      GamepadMap_Add(kDefaultGamepadCmds[i], 0, kKeys_Controls + i);
+  }
+}
+
+static int GetIniSection(const char *s) {
+  if (StringEqualsNoCase(s, "[KeyMap]"))
+    return 0;
+  if (StringEqualsNoCase(s, "[Graphics]"))
+    return 1;
+  if (StringEqualsNoCase(s, "[Sound]"))
+    return 2;
+  if (StringEqualsNoCase(s, "[General]"))
+    return 3;
+  if (StringEqualsNoCase(s, "[Features]"))
+    return 4;
+  if (StringEqualsNoCase(s, "[GamepadMap]"))
+    return 5;
+  return -1;
+}
+
+bool ParseBool(const char *value, bool *result) {
+  bool rv = false;
+  switch (*value++ | 32) {
+  case '0': if (*value == 0) break; return false;
+  case 'f': if (StringEqualsNoCase(value, "alse")) break; return false;
+  case 'n': if (StringEqualsNoCase(value, "o")) break; return false;
+  case 'o':
+    rv = (*value | 32) == 'n';
+    if (StringEqualsNoCase(value, rv ? "n" : "ff")) break;
+    return false;
+  case '1': rv = true; if (*value == 0) break; return false;
+  case 'y': rv = true; if (StringEqualsNoCase(value, "es")) break; return false;
+  case 't': rv = true; if (StringEqualsNoCase(value, "rue")) break; return false;
+  default: return false;
+  }
+  if (result) {
+    *result = rv;
+    return true;
+  }
+  return rv;
+}
+
+static bool ParseBoolBit(const char *value, uint32 *data, uint32 mask) {
+  bool tmp;
+  if (!ParseBool(value, &tmp))
+    return false;
+  *data = *data & ~mask | (tmp ? mask : 0);
+  return true;
+}
+
+static bool HandleIniConfig(int section, const char *key, char *value) {
+  if (section == 0) {
+    for (int i = 0; i < countof(kKeyNameId); i++) {
+      if (StringEqualsNoCase(key, kKeyNameId[i].name)) {
+        has_keynameid[i] = true;
+        ParseKeyArray(value, kKeyNameId[i].id, kKeyNameId[i].size);
+        return true;
+      }
+    }
+  } else if (section == 5) {
+    for (int i = 0; i < countof(kKeyNameId); i++) {
+      if (StringEqualsNoCase(key, kKeyNameId[i].name)) {
+        if (i == 1)
+          has_joypad_controls = true;
+        ParseGamepadArray(value, kKeyNameId[i].id, kKeyNameId[i].size);
+        return true;
+      }
+    }
+  } else if (section == 1) {
+    if (StringEqualsNoCase(key, "WindowSize")) {
+      char *s;
+      if (StringEqualsNoCase(value, "Auto")){
+        g_config.window_width  = 0;
+        g_config.window_height = 0;
+        return true;
+      }
+      while ((s = NextDelim(&value, 'x')) != NULL) {
+        if(g_config.window_width == 0) {
+          g_config.window_width = atoi(s);
+        } else {
+          g_config.window_height = atoi(s);
+          return true;
+        }
+      }
+    } else if (StringEqualsNoCase(key, "EnhancedMode7")) {
+      return ParseBool(value, &g_config.enhanced_mode7);
+    } else if (StringEqualsNoCase(key, "NewRenderer")) {
+      return ParseBool(value, &g_config.new_renderer);
+    } else if (StringEqualsNoCase(key, "IgnoreAspectRatio")) {
+      return ParseBool(value, &g_config.ignore_aspect_ratio);
+    } else if (StringEqualsNoCase(key, "Fullscreen")) {
+      g_config.fullscreen = (uint8)strtol(value, (char**)NULL, 10);
+      return true;
+    } else if (StringEqualsNoCase(key, "WindowScale")) {
+      g_config.window_scale = (uint8)strtol(value, (char**)NULL, 10);
+      return true;
+    } else if (StringEqualsNoCase(key, "OutputMethod")) {
+      g_config.output_method = StringEqualsNoCase(value, "SDL-Software") ? kOutputMethod_SDLSoftware :
+                               StringEqualsNoCase(value, "OpenGL") ? kOutputMethod_OpenGL : 
+                               StringEqualsNoCase(value, "OpenGL ES") ? kOutputMethod_OpenGL_ES :
+                                                                        kOutputMethod_SDL;
+      return true;
+    } else if (StringEqualsNoCase(key, "LinearFiltering")) {
+      return ParseBool(value, &g_config.linear_filtering);
+    } else if (StringEqualsNoCase(key, "NoSpriteLimits")) {
+      return ParseBool(value, &g_config.no_sprite_limits);
+    } else if (StringEqualsNoCase(key, "LinkGraphics")) {
+      g_config.link_graphics = value;
+      return true;
+    } else if (StringEqualsNoCase(key, "Shader")) {
+      g_config.shader = *value ? value : NULL;
+      return true;
+    } else if (StringEqualsNoCase(key, "DimFlashes")) {
+      return ParseBoolBit(value, &g_config.features0, kFeatures0_DimFlashes);
+    }
+  } else if (section == 2) {
+    if (StringEqualsNoCase(key, "EnableAudio")) {
+      return ParseBool(value, &g_config.enable_audio);
+    } else if (StringEqualsNoCase(key, "AudioFreq")) {
+      g_config.audio_freq = (uint16)strtol(value, (char**)NULL, 10);
+      return true;
+    } else if (StringEqualsNoCase(key, "AudioChannels")) {
+      g_config.audio_channels = (uint8)strtol(value, (char**)NULL, 10);
+      return true;
+    } else if (StringEqualsNoCase(key, "AudioSamples")) {
+      g_config.audio_samples = (uint16)strtol(value, (char**)NULL, 10);
+      return true;
+    } else if (StringEqualsNoCase(key, "EnableMSU")) {
+        if (StringEqualsNoCase(value, "opuz"))
+        g_config.enable_msu = kMsuEnabled_Opuz;
+      else if (StringEqualsNoCase(value, "deluxe"))
+        g_config.enable_msu = kMsuEnabled_MsuDeluxe;
+      else if (StringEqualsNoCase(value, "deluxe-opuz"))
+        g_config.enable_msu = kMsuEnabled_MsuDeluxe | kMsuEnabled_Opuz;
+      else 
+        return ParseBool(value, (bool*)&g_config.enable_msu);
+      return true;
+    } else if (StringEqualsNoCase(key, "MSUPath")) {
+      g_config.msu_path = value;
+      return true;
+    } else if (StringEqualsNoCase(key, "MSUVolume")) {
+      g_config.msuvolume = atoi(value);
+      return true;
+    } else if (StringEqualsNoCase(key, "ResumeMSU")) {
+      return ParseBool(value, &g_config.resume_msu);
+    }
+  } else if (section == 3) {
+    if (StringEqualsNoCase(key, "Autosave")) {
+      g_config.autosave = (bool)strtol(value, (char**)NULL, 10);
+      return true;
+    } else if (StringEqualsNoCase(key, "ExtendedAspectRatio")) {
+      const char* s;
+      int h = 224;
+      bool nospr = false, novis = false;
+      // todo: make it not depend on the order
+      while ((s = NextDelim(&value, ',')) != NULL) {
+        if (strcmp(s, "extend_y") == 0)
+          h = 240, g_config.extend_y = true;
+        else if (strcmp(s, "16:9") == 0)
+          g_config.extended_aspect_ratio = (h * 16 / 9 - 256) / 2;
+        else if (strcmp(s, "16:10") == 0)
+          g_config.extended_aspect_ratio = (h * 16 / 10 - 256) / 2;
+        else if (strcmp(s, "18:9") == 0)
+          g_config.extended_aspect_ratio = (h * 18 / 9 - 256) / 2;
+        else if (strcmp(s, "4:3") == 0)
+          g_config.extended_aspect_ratio = 0;
+        else if (strcmp(s, "unchanged_sprites") == 0)
+          nospr = true;
+        else if (strcmp(s, "no_visual_fixes") == 0)
+          novis = true;
+        else
+          return false;
+      }
+      if (g_config.extended_aspect_ratio && !nospr)
+        g_config.features0 |= kFeatures0_ExtendScreen64;
+      if (g_config.extended_aspect_ratio && !novis)
+        g_config.features0 |= kFeatures0_WidescreenVisualFixes;
+      return true;
+    } else if (StringEqualsNoCase(key, "DisplayPerfInTitle")) {
+      return ParseBool(value, &g_config.display_perf_title);
+    } else if (StringEqualsNoCase(key, "DisableFrameDelay")) {
+      return ParseBool(value, &g_config.disable_frame_delay);
+    } else if (StringEqualsNoCase(key, "Language")) {
+      g_config.language = value;
+      return true;
+    }
+  } else if (section == 4) {
+    if (StringEqualsNoCase(key, "ItemSwitchLR")) {
+      return ParseBoolBit(value, &g_config.features0, kFeatures0_SwitchLR);
+    } else if (StringEqualsNoCase(key, "ItemSwitchLRLimit")) {
+      return ParseBoolBit(value, &g_config.features0, kFeatures0_SwitchLRLimit);
+    } else if (StringEqualsNoCase(key, "TurnWhileDashing")) {
+      return ParseBoolBit(value, &g_config.features0, kFeatures0_TurnWhileDashing);
+    } else if (StringEqualsNoCase(key, "MirrorToDarkworld")) {
+      return ParseBoolBit(value, &g_config.features0, kFeatures0_MirrorToDarkworld);
+    } else if (StringEqualsNoCase(key, "CollectItemsWithSword")) {
+      return ParseBoolBit(value, &g_config.features0, kFeatures0_CollectItemsWithSword);
+    } else if (StringEqualsNoCase(key, "BreakPotsWithSword")) {
+      return ParseBoolBit(value, &g_config.features0, kFeatures0_BreakPotsWithSword);
+    } else if (StringEqualsNoCase(key, "DisableLowHealthBeep")) {
+      return ParseBoolBit(value, &g_config.features0, kFeatures0_DisableLowHealthBeep);
+    } else if (StringEqualsNoCase(key, "SkipIntroOnKeypress")) {
+      return ParseBoolBit(value, &g_config.features0, kFeatures0_SkipIntroOnKeypress);
+    } else if (StringEqualsNoCase(key, "ShowMaxItemsInYellow")) {
+      return ParseBoolBit(value, &g_config.features0, kFeatures0_ShowMaxItemsInYellow);
+    } else if (StringEqualsNoCase(key, "MoreActiveBombs")) {
+      return ParseBoolBit(value, &g_config.features0, kFeatures0_MoreActiveBombs);
+    } else if (StringEqualsNoCase(key, "CarryMoreRupees")) {
+      return ParseBoolBit(value, &g_config.features0, kFeatures0_CarryMoreRupees);
+    } else if (StringEqualsNoCase(key, "MiscBugFixes")) {
+      return ParseBoolBit(value, &g_config.features0, kFeatures0_MiscBugFixes);
+    } else if (StringEqualsNoCase(key, "GameChangingBugFixes")) {
+      return ParseBoolBit(value, &g_config.features0, kFeatures0_GameChangingBugFixes);
+    } else if (StringEqualsNoCase(key, "CancelBirdTravel")) {
+      return ParseBoolBit(value, &g_config.features0, kFeatures0_CancelBirdTravel);
+    }
+  }
+  return false;
+}
+
+static bool ParseOneConfigFile(const char *filename, int depth) {
+  char *filedata = (char*)ReadWholeFile(filename, NULL), *p;
+  if (!filedata)
+    return false;
+  
+  int section = -2;
+  g_config.memory_buffer = filedata;
+
+  for (int lineno = 1; (p = NextLineStripComments(&filedata)) != NULL; lineno++) {
+    if (*p == 0)
+      continue; // empty line
+    if (*p == '[') {
+      section = GetIniSection(p);
+      if (section < 0)
+        fprintf(stderr, "%s:%d: Invalid .ini section %s\n", filename, lineno, p);
+    } else if (*p == '!' && SkipPrefix(p + 1, "include ")) {
+      char *tt = p + 8;
+      char *new_filename = ReplaceFilenameWithNewPath(filename, NextPossiblyQuotedString(&tt));
+      if (depth > 10 || !ParseOneConfigFile(new_filename, depth + 1))
+        fprintf(stderr, "Warning: Unable to read %s\n", new_filename);
+      free(new_filename);
+    } else if (section == -2) {
+      fprintf(stderr, "%s:%d: Expecting [section]\n", filename, lineno);
+    } else {
+      char *v = SplitKeyValue(p);
+      if (v == NULL) {
+        fprintf(stderr, "%s:%d: Expecting 'key=value'\n", filename, lineno);
+        continue;
+      }
+      if (section >= 0 && !HandleIniConfig(section, p, v))
+        fprintf(stderr, "%s:%d: Can't parse '%s'\n", filename, lineno, p);
+    }
+  }
+  return true;
+}
+
+void ParseConfigFile(const char *filename) {
+  g_config.msuvolume = 100;  // default msu volume, 100%
+
+  if (filename != NULL || !ParseOneConfigFile("zelda3.user.ini", 0)) {
+    if (filename == NULL)
+      filename = "zelda3.ini";
+    if (!ParseOneConfigFile(filename, 0))
+      fprintf(stderr, "Warning: Unable to read config file %s\n", filename);
+  }
+  RegisterDefaultKeys();
+}
--- /dev/null
+++ b/src/config.h
@@ -1,0 +1,110 @@
+#pragma once
+#include "types.h"
+#include <SDL_keycode.h>
+
+enum {
+  kKeys_Null,
+  kKeys_Controls,
+  kKeys_Controls_Last = kKeys_Controls + 11,
+  kKeys_Load,
+  kKeys_Load_Last = kKeys_Load + 19,
+  kKeys_Save,
+  kKeys_Save_Last = kKeys_Save + 19,
+  kKeys_Replay,
+  kKeys_Replay_Last = kKeys_Replay + 19,
+  kKeys_LoadRef,
+  kKeys_LoadRef_Last = kKeys_LoadRef + 19,
+  kKeys_ReplayRef,
+  kKeys_ReplayRef_Last = kKeys_ReplayRef + 19,
+  kKeys_CheatLife,
+  kKeys_CheatKeys,
+  kKeys_CheatEquipment,
+  kKeys_CheatWalkThroughWalls,
+  kKeys_ClearKeyLog,
+  kKeys_StopReplay,
+  kKeys_Fullscreen,
+  kKeys_Reset,
+  kKeys_Pause,
+  kKeys_PauseDimmed,
+  kKeys_Turbo,
+  kKeys_ReplayTurbo,
+  kKeys_WindowBigger,
+  kKeys_WindowSmaller,
+  kKeys_DisplayPerf,
+  kKeys_ToggleRenderer,
+  kKeys_VolumeUp,
+  kKeys_VolumeDown,
+  kKeys_Total,
+};
+
+enum {
+  kOutputMethod_SDL,
+  kOutputMethod_SDLSoftware,
+  kOutputMethod_OpenGL,
+  kOutputMethod_OpenGL_ES,
+};
+
+typedef struct Config {
+  int window_width;
+  int window_height;
+  bool enhanced_mode7;
+  bool new_renderer;
+  bool ignore_aspect_ratio;
+  uint8 fullscreen;
+  uint8 window_scale;
+  bool enable_audio;
+  bool linear_filtering;
+  uint8 output_method;
+  uint16 audio_freq;
+  uint8 audio_channels;
+  uint16 audio_samples;
+  bool autosave;
+  uint8 extended_aspect_ratio;
+  bool extend_y;
+  bool no_sprite_limits;
+  bool display_perf_title;
+  uint8 enable_msu;
+  bool resume_msu;
+  bool disable_frame_delay;
+  uint8 msuvolume;
+  uint32 features0;
+
+  const char *link_graphics;
+  char *memory_buffer;
+  const char *shader;
+  const char *msu_path;
+  const char *language;
+} Config;
+
+enum {
+  kMsuEnabled_Msu = 1,
+  kMsuEnabled_MsuDeluxe = 2,
+  kMsuEnabled_Opuz = 4,
+};
+enum {
+  kGamepadBtn_Invalid = -1,
+  kGamepadBtn_A,
+  kGamepadBtn_B,
+  kGamepadBtn_X,
+  kGamepadBtn_Y,
+  kGamepadBtn_Back,
+  kGamepadBtn_Guide,
+  kGamepadBtn_Start,
+  kGamepadBtn_L3,
+  kGamepadBtn_R3,
+  kGamepadBtn_L1,
+  kGamepadBtn_R1,
+  kGamepadBtn_DpadUp,
+  kGamepadBtn_DpadDown,
+  kGamepadBtn_DpadLeft,
+  kGamepadBtn_DpadRight,
+  kGamepadBtn_L2,
+  kGamepadBtn_R2,
+  kGamepadBtn_Count,
+};
+
+extern Config g_config;
+
+void ParseConfigFile(const char *filename);
+int FindCmdForSdlKey(SDL_Keycode code, SDL_Keymod mod);
+int FindCmdForGamepadButton(int button, uint32 modifiers);
--- /dev/null
+++ b/src/dungeon.c
@@ -1,0 +1,8796 @@
+#include "zelda_rtl.h"
+#include "snes/snes_regs.h"
+#include "variables.h"
+#include "dungeon.h"
+#include "nmi.h"
+#include "hud.h"
+#include "load_gfx.h"
+#include "overworld.h"
+#include "sprite.h"
+#include "ancilla.h"
+#include "ending.h"
+#include "player.h"
+#include "misc.h"
+#include "player_oam.h"
+#include "tagalong.h"
+#include "messaging.h"
+#include "assets.h"
+
+// todo: move to config
+static const uint16 kBossRooms[] = {
+  200, 51, 7,
+  32,
+  6, 90, 41, 144, 222, 164, 172,
+  13
+};
+static const uint8 kDungeonExit_From[12] = {200, 51, 7, 32, 6, 90, 41, 144, 222, 164, 172, 13};
+static const uint8 kDungeonExit_To[12] = {201, 99, 119, 32, 40, 74, 89, 152, 14, 214, 219, 13};
+static const uint16 kObjectSubtype1Params[] = {
+  0x3d8, 0x2e8, 0x2f8, 0x328, 0x338, 0x400, 0x410, 0x388, 0x390, 0x420, 0x42a, 0x434, 0x43e, 0x448, 0x452, 0x45c,
+  0x466, 0x470, 0x47a, 0x484, 0x48e, 0x498, 0x4a2, 0x4ac, 0x4b6, 0x4c0, 0x4ca, 0x4d4, 0x4de, 0x4e8, 0x4f2, 0x4fc,
+  0x506, 0x598, 0x600, 0x63c, 0x63c, 0x63c, 0x63c, 0x63c, 0x642, 0x64c, 0x652, 0x658, 0x65e, 0x664, 0x66a, 0x688,
+  0x694, 0x6a8, 0x6a8, 0x6a8, 0x6c8, 0x0, 0x78a, 0x7aa, 0xe26, 0x84a, 0x86a, 0x882, 0x8ca, 0x85a, 0x8fa, 0x91a,
+  0x920, 0x92a, 0x930, 0x936, 0x93c, 0x942, 0x948, 0x94e, 0x96c, 0x97e, 0x98e, 0x902, 0x99e, 0x9d8, 0x9d8, 0x9d8,
+  0x9fa, 0x156c, 0x1590, 0x1d86, 0x0, 0xa14, 0xa24, 0xa54, 0xa54, 0xa84, 0xa84, 0x14dc, 0x1500, 0x61e, 0xe52, 0x600,
+  0x3d8, 0x2c8, 0x2d8, 0x308, 0x318, 0x3e0, 0x3f0, 0x378, 0x380, 0x5fa, 0x648, 0x64a, 0x670, 0x67c, 0x6a8, 0x6a8,
+  0x6a8, 0x6c8, 0x0, 0x7aa, 0x7ca, 0x84a, 0x89a, 0x8b2, 0x90a, 0x926, 0x928, 0x912, 0x9f8, 0x1d7e, 0x0, 0xa34,
+  0xa44, 0xa54, 0xa6c, 0xa84, 0xa9c, 0x1524, 0x1548, 0x85a, 0x606, 0xe52, 0x5fa, 0x6a0, 0x6a2, 0xb12, 0xb14, 0x9b0,
+  0xb46, 0xb56, 0x1f52, 0x1f5a, 0x288, 0xe82, 0x1df2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+  0x3d8, 0x3d8, 0x3d8, 0x3d8, 0x5aa, 0x5b2, 0x5b2, 0x5b2, 0x5b2, 0xe0, 0xe0, 0xe0, 0xe0, 0x110, 0x0, 0x0,
+  0x6a4, 0x6a6, 0xae6, 0xb06, 0xb0c, 0xb16, 0xb26, 0xb36, 0x1f52, 0x1f5a, 0x288, 0xeba, 0xe82, 0x1df2, 0x0, 0x0,
+  0x3d8, 0x510, 0x5aa, 0x5aa, 0x0, 0x168, 0xe0, 0x158, 0x100, 0x110, 0x178, 0x72a, 0x72a, 0x72a, 0x75a, 0x670,
+  0x670, 0x130, 0x148, 0x72a, 0x72a, 0x72a, 0x75a, 0xe0, 0x110, 0xf0, 0x110, 0x0, 0xab4, 0x8da, 0xade, 0x188,
+  0x1a0, 0x1b0, 0x1c0, 0x1d0, 0x1e0, 0x1f0, 0x200, 0x120, 0x2a8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+  0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+};
+static const uint16 kObjectSubtype2Params[] = {
+  0xb66, 0xb86, 0xba6, 0xbc6, 0xc66, 0xc86, 0xca6, 0xcc6, 0xbe6, 0xc06, 0xc26, 0xc46, 0xce6, 0xd06, 0xd26, 0xd46,
+  0xd66, 0xd7e, 0xd96, 0xdae, 0xdc6, 0xdde, 0xdf6, 0xe0e, 0x398, 0x3a0, 0x3a8, 0x3b0, 0xe32, 0xe26, 0xea2, 0xe9a,
+  0xeca, 0xed2, 0xede, 0xede, 0xf1e, 0xf3e, 0xf5e, 0xf6a, 0xef6, 0xf72, 0xf92, 0xfa2, 0xfa2, 0x1088, 0x10a8, 0x10a8,
+  0x10c8, 0x10c8, 0x10c8, 0x10c8, 0xe52, 0x1108, 0x1108, 0x12a8, 0x1148, 0x1160, 0x1178, 0x1190, 0x1458, 0x1488, 0x2062, 0x2086,
+};
+static const uint16 kObjectSubtype3Params[] = {
+  0x1614, 0x162c, 0x1654, 0xa0e, 0xa0c, 0x9fc, 0x9fe, 0xa00, 0xa02, 0xa04, 0xa06, 0xa08, 0xa0a, 0x0, 0xa10, 0xa12,
+  0x1dda, 0x1de2, 0x1dd6, 0x1dea, 0x15fc, 0x1dfa, 0x1df2, 0x1488, 0x1494, 0x149c, 0x14a4, 0x10e8, 0x10e8, 0x10e8, 0x11a8, 0x11c8,
+  0x11e8, 0x1208, 0x3b8, 0x3c0, 0x3c8, 0x3d0, 0x1228, 0x1248, 0x1268, 0x1288, 0x0, 0xe5a, 0xe62, 0x0, 0x0, 0xe82,
+  0xe8a, 0x14ac, 0x14c4, 0x10e8, 0x1614, 0x1614, 0x1614, 0x1614, 0x1614, 0x1614, 0x1cbe, 0x1cee, 0x1d1e, 0x1d4e, 0x1d8e, 0x1d96,
+  0x1d9e, 0x1da6, 0x1dae, 0x1db6, 0x1dbe, 0x1dc6, 0x1dce, 0x220, 0x260, 0x280, 0x1f3a, 0x1f62, 0x1f92, 0x1ff2, 0x2016, 0x1f42,
+  0xeaa, 0x1f4a, 0x1f52, 0x1f5a, 0x202e, 0x2062, 0x9b8, 0x9c0, 0x9c8, 0x9d0, 0xfa2, 0xfb2, 0xfc4, 0xff4, 0x1018, 0x1020,
+  0x15b4, 0x15d8, 0x20f6, 0xeba, 0x22e6, 0x22ee, 0x5da, 0x281e, 0x2ae0, 0x2d2a, 0x2f2a, 0x22f6, 0x2316, 0x232e, 0x2346, 0x235e,
+  0x2376, 0x23b6, 0x1e9a, 0x0, 0x2436, 0x149c, 0x24b6, 0x24e6, 0x2516, 0x1028, 0x1040, 0x1060, 0x1070, 0x1078, 0x1080, 0x0,
+};
+static const uint16 kDoorTypeSrcData[] = {
+  0x2716, 0x272e, 0x272e, 0x2746, 0x2746, 0x2746, 0x2746, 0x2746, 0x2746, 0x275e, 0x275e, 0x275e, 0x275e, 0x2776, 0x278e, 0x27a6,
+  0x27be, 0x27be, 0x27d6, 0x27d6, 0x27ee, 0x2806, 0x2806, 0x281e, 0x2836, 0x2836, 0x2836, 0x2836, 0x284e, 0x2866, 0x2866, 0x2866,
+  0x2866, 0x287e, 0x2896, 0x28ae, 0x28c6, 0x28de, 0x28f6, 0x28f6, 0x28f6, 0x290e, 0x2926, 0x2958, 0x2978, 0x2990, 0x2990, 0x2990,
+  0x2990, 0x29a8, 0x29c0, 0x29d8,
+};
+static const uint16 kDoorTypeSrcData2[] = {
+  0x29f0, 0x2a08, 0x2a08, 0x2a20, 0x2a20, 0x2a20, 0x2a20, 0x2a20, 0x2a20, 0x2a38, 0x2a38, 0x2a38, 0x2a38, 0x2a50, 0x2a68, 0x2a80,
+  0x2a98, 0x2a98, 0x2a98, 0x2a98, 0x2a98, 0x2ab0, 0x2ac8, 0x2ae0, 0x2af8, 0x2af8, 0x2af8, 0x2af8, 0x2b10, 0x2b28, 0x2b28, 0x2b28,
+  0x2b28, 0x2b40, 0x2b58, 0x2b70, 0x2b88, 0x2ba0, 0x2bb8, 0x2bb8, 0x2bb8, 0x2bd0, 0x2be8, 0x2c1a, 0x2c3a, 0x2c52, 0x2c6a, 0x2c6a,
+};
+static const uint16 kDoorTypeSrcData3[] = {
+  0x2c6a, 0x2c82, 0x2c82, 0x2c9a, 0x2c9a, 0x2c9a, 0x2c9a, 0x2c9a, 0x2c9a, 0x2cb2, 0x2cb2, 0x2cb2, 0x2cb2, 0x2cca, 0x2ce2, 0x2cfa,
+  0x2cfa, 0x2cfa, 0x2cfa, 0x2cfa, 0x2cfa, 0x2d12, 0x2d12, 0x2d2a, 0x2d42, 0x2d42, 0x2d42, 0x2d42, 0x2d5a, 0x2d72, 0x2d72, 0x2d72,
+  0x2d72, 0x2d8a, 0x2da2, 0x2dba, 0x2dd2, 0x2dea, 0x2e02, 0x2e02, 0x2e02, 0x2e1a, 0x2e32, 0x2e32, 0x2e52, 0x2e6a, 0x2e6a, 0x2e6a,
+};
+static const uint16 kDoorTypeSrcData4[] = {
+  0x2e6a, 0x2e82, 0x2e82, 0x2e9a, 0x2e9a, 0x2e9a, 0x2e9a, 0x2e9a, 0x2e9a, 0x2eb2, 0x2eb2, 0x2eb2, 0x2eb2, 0x2eca, 0x2ee2, 0x2efa,
+  0x2efa, 0x2efa, 0x2efa, 0x2efa, 0x2efa, 0x2f12, 0x2f12, 0x2f2a, 0x2f42, 0x2f42, 0x2f42, 0x2f42, 0x2f5a, 0x2f72, 0x2f72, 0x2f72,
+  0x2f72, 0x2f8a, 0x2fa2, 0x2fba, 0x2fd2, 0x2fea, 0x3002, 0x3002, 0x3002, 0x301a, 0x3032, 0x3032, 0x3052, 0x306a, 0x306a,
+};
+static const uint16 kDoorPositionToTilemapOffs_Up[] = { 0x21c, 0x23c, 0x25c, 0x39c, 0x3bc, 0x3dc, 0x121c, 0x123c, 0x125c, 0x139c, 0x13bc, 0x13dc };
+static const uint16 kDoorPositionToTilemapOffs_Down[] = { 0xd1c, 0xd3c, 0xd5c, 0xb9c, 0xbbc, 0xbdc, 0x1d1c, 0x1d3c, 0x1d5c, 0x1b9c, 0x1bbc, 0x1bdc };
+static const uint16 kDoorPositionToTilemapOffs_Left[] = { 0x784, 0xf84, 0x1784, 0x78a, 0xf8a, 0x178a, 0x7c4, 0xfc4, 0x17c4, 0x7ca, 0xfca, 0x17ca };
+static const uint16 kDoorPositionToTilemapOffs_Right[] = { 0x7b4, 0xfb4, 0x17b4, 0x7ae, 0xfae, 0x17ae, 0x7f4, 0xff4, 0x17f4, 0x7ee, 0xfee, 0x17ee };
+static const int8 kSpiralTab1[] = { 0, 1, 1, -1, 1, 1, 1, 1 };
+static const int8 kTeleportPitLevel1[] = { 0, 1, 1 };
+static const int8 kTeleportPitLevel2[] = { 0, 0, 1 };
+static const uint8 kDoorTypeRemap[] = {
+  0, 2, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 80, 0, 80, 80,
+  96, 98, 100, 102, 82, 90, 80, 82, 84, 86, 0, 80, 80, 0, 0, 0,
+  64, 88, 88, 0, 88, 88, 0, 0,
+};
+static const int8 kStaircaseTab2[] = {
+  12, 32, 48, 56, 72, -44, -40, -64, -64, -88, 12, 24, 40, 48, 64, -28,
+  -40, -56, -64, -80,
+};
+static const int8 kStaircaseTab3[] = { 4, -4, 4, -4 };
+static const int8 kStaircaseTab4[] = { 52, 52, 59, 58 };
+static const int8 kStaircaseTab5[] = { 32, -64, 32, -32 };
+static const uint8 kMovingWall_Sizes0[4] = { 5, 7, 11, 15 };
+static const uint8 kMovingWall_Sizes1[4] = { 8, 16, 24, 32 };
+static const uint8 kWatergateLayout[17] = {
+  0x1b, 0xa1, 0xc9,
+  0x51, 0xa1, 0xc9,
+  0x92, 0xa1, 0xc9,
+  0xa1, 0x33, 0xc9,
+  0xa1, 0x72, 0xc9,
+  0xff, 0xff,
+};
+static const uint16 kChestOpenMasks[] = { 0x100, 0x200, 0x400, 0x800, 0x1000, 0x2000 };
+const uint8 kLayoutQuadrantFlags[] = { 0xF, 0xF, 0xF, 0xF, 0xB, 0xB, 7, 7, 0xF, 0xB, 0xF, 7, 0xB, 0xF, 7, 0xF, 0xE, 0xD, 0xE, 0xD, 0xF, 0xF, 0xE, 0xD, 0xE, 0xD, 0xF, 0xF, 0xA, 9, 6, 5 };
+static const uint8 kQuadrantVisitingFlags[] = { 8, 4, 2, 1, 0xC, 0xC, 3, 3, 0xA, 5, 0xA, 5, 0xF, 0xF, 0xF, 0xF };
+#define XY(x, y) ((y)*64+(x))
+static const uint8 kDungeon_MinigameChestPrizes1[8] = {
+  0x40, 0x41, 0x34, 0x42, 0x43, 0x44, 0x27, 0x17
+};
+static const uint8 kDungeon_RupeeChestMinigamePrizes[32] = {
+  0x47, 0x34, 0x46, 0x34, 0x46, 0x46, 0x34, 0x47, 0x46, 0x47, 0x34, 0x46, 0x47, 0x34, 0x46, 0x47,
+  0x34, 0x47, 0x41, 0x47, 0x41, 0x41, 0x47, 0x34, 0x41, 0x34, 0x47, 0x41, 0x34, 0x47, 0x41, 0x34,
+};
+static const int8 kDungeon_QueryIfTileLiftable_x[4] = { 7, 7, -3, 16 };
+static const int8 kDungeon_QueryIfTileLiftable_y[4] = { 3, 24, 14, 14 };
+static const uint16 kDungeon_QueryIfTileLiftable_rv[16] = { 0x5252, 0x5050, 0x5454, 0x0, 0x2323 };
+static const uint16 kDoor_BlastWallUp_Dsts[] = { 0xd8a, 0xdaa, 0xdca, 0x2b6, 0xab6, 0x12b6 };
+#define adjacent_doors_flags (*(uint16*)(g_ram+0x1100))
+#define adjacent_doors ((uint16*)(g_ram+0x1110))
+static const DungPalInfo kDungPalinfos[41] = {
+  { 0,  0,  3,  1},
+  { 2,  0,  3,  1},
+  { 4,  0, 10,  1},
+  { 6,  0,  1,  7},
+  {10,  2,  2,  7},
+  { 4,  4,  3, 10},
+  {12,  5,  8, 20},
+  {14,  0,  3, 10},
+  { 2,  0, 15, 20},
+  {10,  2,  0,  7},
+  { 2,  0, 15, 12},
+  { 6,  0,  6,  7},
+  { 0,  0, 14, 18},
+  {18,  5,  5, 11},
+  {18,  0,  2, 12},
+  {16,  5, 10,  7},
+  {16,  0, 16, 12},
+  {22,  7,  2,  7},
+  {22,  0,  7, 15},
+  { 8,  0,  4, 12},
+  { 8,  0,  4,  9},
+  { 4,  0,  3,  1},
+  {20,  0,  4,  4},
+  {20,  0, 20, 12},
+  {24,  5,  7, 11},
+  {24,  6, 16, 12},
+  {26,  5,  8, 20},
+  {26,  2,  0,  7},
+  { 6,  0,  3, 10},
+  {28,  0,  3,  1},
+  {30,  0, 11, 17},
+  { 4,  0, 11, 17},
+  {14,  0,  0,  2},
+  {32,  8, 19, 13},
+  {10,  0,  3, 10},
+  {20,  0,  4,  4},
+  {26,  2,  2,  7},
+  {26, 10,  0,  0},
+  { 0,  0,  3,  2},
+  {14,  0,  3,  7},
+  {26,  5,  5, 11},
+};
+// these are not used by the code, but needed for the comparison with the real rom to work.
+static const uint8 kDungeon_DrawObjectOffsets_BG1[33] = {
+     0, 0x20, 0x7e,    2, 0x20, 0x7e,    4, 0x20, 0x7e,    6, 0x20, 0x7e, 0x80, 0x20, 0x7e, 0x82,
+  0x20, 0x7e, 0x84, 0x20, 0x7e, 0x86, 0x20, 0x7e,    0, 0x21, 0x7e, 0x80, 0x21, 0x7e,    0, 0x22,
+  0x7e,
+};
+static const uint8 kDungeon_DrawObjectOffsets_BG2[33] = {
+     0, 0x40, 0x7e,    2, 0x40, 0x7e,    4, 0x40, 0x7e,    6, 0x40, 0x7e, 0x80, 0x40, 0x7e, 0x82,
+  0x40, 0x7e, 0x84, 0x40, 0x7e, 0x86, 0x40, 0x7e,    0, 0x41, 0x7e, 0x80, 0x41, 0x7e,    0, 0x42,
+  0x7e,
+};
+static const uint16 kUploadBgSrcs[] = { 0x0, 0x1000, 0x0, 0x40, 0x40, 0x1040, 0x1000, 0x1040, 0x1000, 0x0, 0x40, 0x0, 0x1040, 0x40, 0x1040, 0x1000 };
+static const uint8 kUploadBgDsts[] = { 1, 5, 9, 13, 2, 6, 10, 14, 3, 7, 11, 15, 4, 8, 12, 16 };
+static const uint16 kTileAttrsByDoor[] = {
+  0x8080, 0x8484, 0x0, 0x101, 0x8484, 0x8e8e, 0x0, 0x0, 0x8888, 0x8e8e, 0x8080, 0x8080, 0x8282, 0x8080, 0x8080, 0x8080,
+  0x8080, 0x8080, 0x8080, 0x8080, 0x8282, 0x8e8e, 0x8080, 0x8282, 0x8080, 0x8080, 0x8080, 0x8282, 0x8282, 0x8080, 0x8080, 0x8080,
+  0x8484, 0x8484, 0x8686, 0x8888, 0x8686, 0x8686, 0x8080, 0x8080,
+};
+static PlayerHandlerFunc *const kDungeon_Effect_Handler[28] = {
+  &LayerEffect_Nothing,
+  &LayerEffect_Nothing,
+  &LayerEffect_Scroll,
+  &LayerEffect_WaterRapids,
+  &LayerEffect_Trinexx,
+  &LayerEffect_Agahnim2,
+  &LayerEffect_InvisibleFloor,
+  &LayerEffect_Ganon,
+};
+static const int16 kPushBlockMoveDistances[] = { -0x100, 0x100, -0x4, 0x4 };
+static HandlerFuncK *const kDungTagroutines[] = {
+  &Dung_TagRoutine_0x00,
+  &RoomTag_NorthWestTrigger,
+  &Dung_TagRoutine_0x2A,
+  &Dung_TagRoutine_0x2B,
+  &Dung_TagRoutine_0x2C,
+  &Dung_TagRoutine_0x2D,
+  &Dung_TagRoutine_0x2E,
+  &Dung_TagRoutine_0x2F,
+  &Dung_TagRoutine_0x30,
+  &RoomTag_QuadrantTrigger,
+  &RoomTag_RoomTrigger,
+  &RoomTag_NorthWestTrigger,
+  &Dung_TagRoutine_0x2A,
+  &Dung_TagRoutine_0x2B,
+  &Dung_TagRoutine_0x2C,
+  &Dung_TagRoutine_0x2D,
+  &Dung_TagRoutine_0x2E,
+  &Dung_TagRoutine_0x2F,
+  &Dung_TagRoutine_0x30,
+  &RoomTag_QuadrantTrigger,
+  &RoomTag_RoomTrigger_BlockDoor,
+  &RoomTag_PrizeTriggerDoorDoor,
+  &RoomTag_SwitchTrigger_HoldDoor,
+  &RoomTag_SwitchTrigger_ToggleDoor,
+  &RoomTag_WaterOff,
+  &RoomTag_WaterOn,
+  &RoomTag_WaterGate,
+  &Dung_TagRoutine_0x1B,
+  &RoomTag_MovingWall_East,
+  &RoomTag_MovingWall_West,
+  &RoomTag_MovingWallTorchesCheck,
+  &RoomTag_MovingWallTorchesCheck,
+  &RoomTag_Switch_ExplodingWall,
+  &RoomTag_Holes0,
+  &RoomTag_ChestHoles0,
+  &Dung_TagRoutine_0x23,
+  &RoomTag_Holes2,
+  &RoomTag_GetHeartForPrize,
+  &RoomTag_KillRoomBlock,
+  &RoomTag_TriggerChest,
+  &RoomTag_PullSwitchExplodingWall,
+  &RoomTag_NorthWestTrigger,
+  &Dung_TagRoutine_0x2A,
+  &Dung_TagRoutine_0x2B,
+  &Dung_TagRoutine_0x2C,
+  &Dung_TagRoutine_0x2D,
+  &Dung_TagRoutine_0x2E,
+  &Dung_TagRoutine_0x2F,
+  &Dung_TagRoutine_0x30,
+  &RoomTag_QuadrantTrigger,
+  &RoomTag_RoomTrigger,
+  &RoomTag_TorchPuzzleDoor,
+  &Dung_TagRoutine_0x34,
+  &Dung_TagRoutine_0x35,
+  &Dung_TagRoutine_0x36,
+  &Dung_TagRoutine_0x37,
+  &RoomTag_Agahnim,
+  &Dung_TagRoutine_0x39,
+  &Dung_TagRoutine_0x3A,
+  &Dung_TagRoutine_0x3B,
+  &RoomTag_PushBlockForChest,
+  &RoomTag_GanonDoor,
+  &RoomTag_TorchPuzzleChest,
+  &RoomTag_RekillableBoss,
+};
+static const uint16 kDoorAnimUpSrc[] = { 0x306a, 0x306a, 0x3082, 0x309a, 0x30b2 };
+static const uint16 kDoorAnimDownSrc[] = { 0x30b2, 0x30ca, 0x30e2, 0x30fa, 0x3112 };
+static const uint16 kDoorAnimLeftSrc[] = { 0x3112, 0x312a, 0x3142, 0x315a, 0x3172 };
+static const uint16 kDoorAnimRightSrc[] = { 0x3172, 0x318a, 0x31a2, 0x31ba, 0x31D2 };
+static PlayerHandlerFunc *const kDungeon_IntraRoomTrans[8] = {
+  &DungeonTransition_Subtile_PrepTransition,
+  &DungeonTransition_Subtile_ApplyFilter,
+  &DungeonTransition_Subtile_ResetShutters,
+  &DungeonTransition_ScrollRoom,
+  &DungeonTransition_FindSubtileLanding,
+  &Dungeon_IntraRoomTrans_State5,
+  &DungeonTransition_Subtile_ApplyFilter,
+  &DungeonTransition_Subtile_TriggerShutters,
+};
+static PlayerHandlerFunc *const kDungeon_InterRoomTrans[16] = {
+  &Module07_02_00_InitializeTransition,
+  &Module07_02_01_LoadNextRoom,
+  &Module07_02_FadedFilter,
+  &Dungeon_InterRoomTrans_State3,
+  &Dungeon_InterRoomTrans_State4,
+  &Dungeon_InterRoomTrans_notDarkRoom,
+  &Dungeon_InterRoomTrans_State4,
+  &Dungeon_InterRoomTrans_State7,
+  &DungeonTransition_ScrollRoom,
+  &Dungeon_InterRoomTrans_State9,
+  &Dungeon_InterRoomTrans_State10,
+  &Dungeon_InterRoomTrans_State9,
+  &Dungeon_InterRoomTrans_State12,
+  &Dungeon_InterRoomTrans_State13,
+  &Module07_02_FadedFilter,
+  &Dungeon_InterRoomTrans_State15,
+};
+static PlayerHandlerFunc *const kDungeon_Submodule_7_DownFloorTrans[18] = {
+  &Module07_07_00_HandleMusicAndResetRoom,
+  &ApplyPaletteFilter_bounce,
+  &Dungeon_InitializeRoomFromSpecial,
+  &DungeonTransition_TriggerBGC34UpdateAndAdvance,
+  &DungeonTransition_TriggerBGC56UpdateAndAdvance,
+  &DungeonTransition_LoadSpriteGFX,
+  &Module07_07_06_SyncBG1and2,
+  &Dungeon_InterRoomTrans_State4,
+  &Dungeon_InterRoomTrans_notDarkRoom,
+  &Dungeon_InterRoomTrans_State4,
+  &Dungeon_InterRoomTrans_notDarkRoom,
+  &Dungeon_InterRoomTrans_State4,
+  &Dungeon_InterRoomTrans_notDarkRoom,
+  &Dungeon_InterRoomTrans_State4,
+  &Dungeon_Staircase14,
+  &Module07_07_0F_FallingFadeIn,
+  &Module07_07_10_LandLinkFromFalling,
+  &Module07_07_11_CacheRoomAndSetMusic,
+};
+static PlayerHandlerFunc *const kWatergateFuncs[6] = {
+  &FloodDam_PrepTiles_init,
+  &Watergate_Main_State1,
+  &Watergate_Main_State1,
+  &Watergate_Main_State1,
+  &FloodDam_Expand,
+  &FloodDam_Fill,
+};
+static const int8 kSpiralStaircaseX[] = { -28, -28, 24, 24 };
+static const int8 kSpiralStaircaseY[] = { 16, -10, -10, -32 };
+static PlayerHandlerFunc *const kDungeon_SpiralStaircase[20] = {
+  &Module07_0E_00_InitPriorityAndScreens,
+  &Module07_0E_01_HandleMusicAndResetProps,
+  &Module07_0E_02_ApplyFilterIf,
+  &Dungeon_InitializeRoomFromSpecial,
+  &DungeonTransition_TriggerBGC34UpdateAndAdvance,
+  &DungeonTransition_TriggerBGC56UpdateAndAdvance,
+  &DungeonTransition_LoadSpriteGFX,
+  &Dungeon_SyncBackgroundsFromSpiralStairs,
+  &Dungeon_InterRoomTrans_State4,
+  &Dungeon_InterRoomTrans_notDarkRoom,
+  &Dungeon_InterRoomTrans_State4,
+  &Dungeon_SpiralStaircase11,
+  &Dungeon_SpiralStaircase12,
+  &Dungeon_SpiralStaircase11,
+  &Dungeon_SpiralStaircase12,
+  &Dungeon_DoubleApplyAndIncrementGrayscale,
+  &Dungeon_AdvanceThenSetBossMusicUnorthodox,
+  &Dungeon_SpiralStaircase17,
+  &Dungeon_SpiralStaircase18,
+  &Module07_0E_13_SetRoomAndLayerAndCache,
+};
+static PlayerHandlerFunc *const kDungeon_Submodule_F[2] = {
+  &Module07_0F_00_InitSpotlight,
+  &Module07_0F_01_OperateSpotlight,
+};
+static PlayerHandlerFunc *const kDungeon_StraightStaircase[2] = {
+  &Module07_10_00_InitStairs,
+  &Module07_10_01_ClimbStairs,
+};
+static PlayerHandlerFunc *const kDungeon_StraightStaircaseDown[2] = {
+  &Module07_08_00_InitStairs,
+  &Module07_08_01_ClimbStairs,
+};
+static PlayerHandlerFunc *const kDungeon_StraightStairs[19] = {
+  &Module07_11_00_PrepAndReset,
+  &Module07_11_01_FadeOut,
+  &Module07_11_02_LoadAndPrepRoom,
+  &Module07_11_03_FilterAndLoadBGChars,
+  &Module07_11_04_FilterDoBGAndResetSprites,
+  &Dungeon_SpiralStaircase11,
+  &Dungeon_SpiralStaircase12,
+  &Dungeon_SpiralStaircase11,
+  &Dungeon_SpiralStaircase12,
+  &Module07_11_09_LoadSpriteGraphics,
+  &Module07_11_0A_ScrollCamera,
+  &Module07_11_0B_PrepDestination,
+  &Dungeon_InterRoomTrans_State4,
+  &Dungeon_InterRoomTrans_notDarkRoom,
+  &Dungeon_InterRoomTrans_State4,
+  &Dungeon_DoubleApplyAndIncrementGrayscale,
+  &Module07_11_19_SetSongAndFilter,
+  &Module07_11_11_KeepSliding,
+  &ResetThenCacheRoomEntryProperties,
+};
+static PlayerHandlerFunc *const kDungeon_Teleport[15] = {
+  &ResetTransitionPropsAndAdvance_ResetInterface,
+  &Module07_15_01_ApplyMosaicAndFilter,
+  &Dungeon_InitializeRoomFromSpecial,
+  &DungeonTransition_LoadSpriteGFX,
+  &Module07_15_04_SyncRoomPropsAndBuildOverlay,
+  &Dungeon_InterRoomTrans_State4,
+  &Dungeon_InterRoomTrans_notDarkRoom,
+  &Dungeon_InterRoomTrans_State4,
+  &Dungeon_InterRoomTrans_notDarkRoom,
+  &Dungeon_InterRoomTrans_State4,
+  &Dungeon_InterRoomTrans_notDarkRoom,
+  &Dungeon_InterRoomTrans_State4,
+  &Dungeon_Staircase14,
+  &Module07_15_0E_FadeInFromWarp,
+  &Module07_15_0F_FinalizeAndCacheEntry,
+};
+static PlayerHandlerFunc *const kDungeonSubmodules[31] = {
+  &Module07_00_PlayerControl,
+  &Module07_01_SubtileTransition,
+  &Module07_02_SupertileTransition,
+  &Module07_03_OverlayChange,
+  &Module07_04_UnlockDoor,
+  &Module07_05_ControlShutters,
+  &Module07_06_FatInterRoomStairs,
+  &Module07_07_FallingTransition,
+  &Module07_08_NorthIntraRoomStairs,
+  &Module07_09_OpenCrackedDoor,
+  &Module07_0A_ChangeBrightness,
+  &Module07_0B_DrainSwampPool,
+  &Module07_0C_FloodSwampWater,
+  &Module07_0D_FloodDam,
+  &Module07_0E_SpiralStairs,
+  &Module07_0F_LandingWipe,
+  &Module07_10_SouthIntraRoomStairs,
+  &Module07_11_StraightInterroomStairs,
+  &Module07_11_StraightInterroomStairs,
+  &Module07_11_StraightInterroomStairs,
+  &Module07_14_RecoverFromFall,
+  &Module07_15_WarpPad,
+  &Module07_16_UpdatePegs,
+  &Module07_17_PressurePlate,
+  &Module07_18_RescuedMaiden,
+  &Module07_19_MirrorFade,
+  &Module07_1A_RoomDraw_OpenTriforceDoor_bounce,
+};
+const uint8 kDungAnimatedTiles[24] = {
+  0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5f, 0x5d, 0x5f, 0x5f, 0x5e, 0x5f, 0x5e, 0x5e, 0x5d,
+  0x5d, 0x5e, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d,
+};
+uint16 *DstoPtr(uint16 d) {
+  return (uint16 *)&(g_ram[dung_line_ptrs_row0 + d * 2]);
+}
+
+void Object_Fill_Nx1(int n, const uint16 *src, uint16 *dst) {
+  int t = src[0];
+  do *dst++ = t; while (--n);
+}
+
+void Object_Draw_5x4(const uint16 *src, uint16 *dst) {
+  int n = 5;
+  do {
+    dst[XY(0, 0)] = src[0];
+    dst[XY(1, 0)] = src[1];
+    dst[XY(2, 0)] = src[2];
+    dst[XY(3, 0)] = src[3];
+    dst += XY(0, 1), src += 4;
+  } while (--n);
+}
+
+void Object_Draw_4x2_BothBgs(const uint16 *src, uint16 dsto) {
+  dung_bg1[dsto + XY(0, 0)] = dung_bg2[dsto + XY(0, 0)] = src[0];
+  dung_bg1[dsto + XY(1, 0)] = dung_bg2[dsto + XY(1, 0)] = src[1];
+  dung_bg1[dsto + XY(2, 0)] = dung_bg2[dsto + XY(2, 0)] = src[2];
+  dung_bg1[dsto + XY(3, 0)] = dung_bg2[dsto + XY(3, 0)] = src[3];
+  dung_bg1[dsto + XY(0, 1)] = dung_bg2[dsto + XY(0, 1)] = src[4];
+  dung_bg1[dsto + XY(1, 1)] = dung_bg2[dsto + XY(1, 1)] = src[5];
+  dung_bg1[dsto + XY(2, 1)] = dung_bg2[dsto + XY(2, 1)] = src[6];
+  dung_bg1[dsto + XY(3, 1)] = dung_bg2[dsto + XY(3, 1)] = src[7];
+}
+
+void Object_ChestPlatform_Helper(const uint16 *src, int dsto) {
+  dung_bg2[dsto] = src[0];
+  int n = src[3];
+  for (int i = dung_draw_width_indicator; i--; dsto++)
+    dung_bg2[1 + dsto] = n;
+
+  dung_bg2[1 + dsto] = src[6];
+  dung_bg2[2 + dsto] = dung_bg2[3 + dsto] = dung_bg2[4 + dsto] = dung_bg2[5 + dsto] = src[9];
+
+  dung_bg2[6 + dsto] = src[12];
+  n = src[15];
+  for (int i = dung_draw_width_indicator; i--; dsto++)
+    dung_bg2[7 + dsto] = n;
+
+  dung_bg2[7 + dsto] = src[18];
+}
+
+void Object_Hole(const uint16 *src, uint16 *dst) {
+  Object_SizeAtoAplus15(4);
+  int w = dung_draw_width_indicator;
+  for (int i = 0; i < w; i++)
+    Object_Fill_Nx1(w, src, dst + XY(0, i));
+  // fill top/bottom
+  src = SrcPtr(0x63c);
+  dst[XY(0, 0)] = src[0];
+  Object_Fill_Nx1(w - 2, src + 1, dst + XY(1, 0));
+  dst[XY(w - 1, 0)] = src[2];
+
+  dst[XY(0, w - 1)] = src[3];
+  Object_Fill_Nx1(w - 2, src + 4, dst + XY(1, w - 1));
+  dst[XY(w - 1, w - 1)] = src[5];
+
+  // fill left/right edge
+  src = SrcPtr(0x648);
+  for (int i = 1; i < w - 1; i++) {
+    dst[XY(0, i)] = src[0];
+    dst[XY(w - 1, i)] = src[1];
+  }
+}
+
+// dsto is half the value of Y
+void LoadType1ObjectSubtype1(uint8 idx, uint16 *dst, uint16 dsto) {
+  uint16 param1 = kObjectSubtype1Params[idx];
+  const uint16 *src = SrcPtr(param1);
+  int n;
+
+  switch (idx) {
+  case 0x0:  // RoomDraw_Rightwards2x2_1to15or32 - Ceiling
+  case 0xb8: case 0xb9: // B8 -  Blue Switch Block [L-R]
+    RoomDraw_GetObjectSize_1to15or32();
+    do {
+      RoomDraw_Rightwards2x2(src, dst), dst += XY(2, 0);
+    } while (--dung_draw_width_indicator);
+    break;
+  case 0x1: case 0x2:  // RoomDraw_Rightwards2x4_1to15or26 - [N]Wall Horz: [L-R]
+  case 0xb6: case 0xb7:  // B6 -  [N]Wall Decor: 1/2 [L-R]
+    RoomDraw_GetObjectSize_1to15or26();
+    do {
+      RoomDraw_Object_Nx4(2, src, dst), dst += XY(2, 0);
+    } while (--dung_draw_width_indicator);
+    break;
+
+  case 0x3: case 0x4:  // RoomDraw_Rightwards2x4spaced4_1to16 - 03 -  [N]Wall Horz: (LOW) [L-R]
+    RoomDraw_GetObjectSize_1to16();
+    do {
+      dung_bg1[dsto + XY(0, 0)] = dung_bg2[dsto + XY(0, 0)] = src[0];
+      dung_bg1[dsto + XY(0, 1)] = dung_bg2[dsto + XY(0, 1)] = src[1];
+      dung_bg1[dsto + XY(0, 2)] = dung_bg2[dsto + XY(0, 2)] = src[2];
+      dung_bg1[dsto + XY(0, 3)] = dung_bg2[dsto + XY(0, 3)] = src[3];
+      dung_bg1[dsto + XY(1, 0)] = dung_bg2[dsto + XY(1, 0)] = src[4];
+      dung_bg1[dsto + XY(1, 1)] = dung_bg2[dsto + XY(1, 1)] = src[5];
+      dung_bg1[dsto + XY(1, 2)] = dung_bg2[dsto + XY(1, 2)] = src[6];
+      dung_bg1[dsto + XY(1, 3)] = dung_bg2[dsto + XY(1, 3)] = src[7];
+      dsto += XY(2, 0);
+    } while (--dung_draw_width_indicator);
+    break;
+
+  case 0x5: case 0x6: // RoomDraw_Rightwards2x4spaced4_1to16_BothBG - 05 -  [N]Wall Column [L-R]
+    RoomDraw_GetObjectSize_1to16();
+    do {
+      RoomDraw_Object_Nx4(2, src, dst), dst += XY(6, 0);
+    } while (--dung_draw_width_indicator);
+    break;
+
+  case 0x7: case 0x8: case 0x53: // RoomDraw_Rightwards2x2_1to16 - 07 -  [N]Wall Pit [L-R]
+    RoomDraw_GetObjectSize_1to16();
+    do {
+      RoomDraw_Rightwards2x2(src, dst), dst += XY(2, 0);
+    } while (--dung_draw_width_indicator);
+    break;
+
+  case 0x9: case 0x0c: case 0x0d: case 0x10: case 0x11: case 0x14:  // 09 -  / Wall Wood Bot (HIGH) [NW]
+    Object_SizeAtoAplus15(6);
+    do {
+      RoomDraw_DrawObject2x2and1(src, dst), dst += XY(1, -1);
+    } while (--dung_draw_width_indicator);
+    break;
+
+  case 0x0a: case 0x0b: case 0x0e: case 0x0f: case 0x12: case 0x13:  // 12 -  \ Wall Tile2 Bot (HIGH) [SW]
+    Object_SizeAtoAplus15(6);
+    do {
+      RoomDraw_DrawObject2x2and1(src, dst), dst += XY(1, 1);
+    } while (--dung_draw_width_indicator);
+    break;
+
+  case 0x15: case 0x18: case 0x19: case 0x1C: case 0x1D: case 0x20:  // 15 -  / Wall Tile Top (LOW)[NW]
+    Object_SizeAtoAplus15(6);
+    do {
+      dung_bg1[dsto + XY(0, 0)] = dung_bg2[dsto + XY(0, 0)] = src[0];
+      dung_bg1[dsto + XY(0, 1)] = dung_bg2[dsto + XY(0, 1)] = src[1];
+      dung_bg1[dsto + XY(0, 2)] = dung_bg2[dsto + XY(0, 2)] = src[2];
+      dung_bg1[dsto + XY(0, 3)] = dung_bg2[dsto + XY(0, 3)] = src[3];
+      dung_bg1[dsto + XY(0, 4)] = dung_bg2[dsto + XY(0, 4)] = src[4];
+      dsto -= 63;
+    } while (--dung_draw_width_indicator);
+    break;
+
+  case 0x16: case 0x17: case 0x1A: case 0x1B: case 0x1E: case 0x1F:  // 16 -  \ Wall Tile Top (LOW)[SW]
+    Object_SizeAtoAplus15(6);
+    do {
+      dung_bg1[dsto + XY(0, 0)] = dung_bg2[dsto + XY(0, 0)] = src[0];
+      dung_bg1[dsto + XY(0, 1)] = dung_bg2[dsto + XY(0, 1)] = src[1];
+      dung_bg1[dsto + XY(0, 2)] = dung_bg2[dsto + XY(0, 2)] = src[2];
+      dung_bg1[dsto + XY(0, 3)] = dung_bg2[dsto + XY(0, 3)] = src[3];
+      dung_bg1[dsto + XY(0, 4)] = dung_bg2[dsto + XY(0, 4)] = src[4];
+      dsto += 65;
+    } while (--dung_draw_width_indicator);
+    break;
+
+  case 0x21:  // 21 -  Mini Stairs [L-R]
+    dung_draw_width_indicator = (dung_draw_width_indicator << 2 | dung_draw_height_indicator) * 2 + 1;
+    RoomDraw_1x3_rightwards(2, src, dst), dst += XY(2, 0);
+    do {
+      RoomDraw_1x3_rightwards(1, src + 3, dst), dst += XY(1, 0);
+    } while (--dung_draw_width_indicator);
+    RoomDraw_1x3_rightwards(1, src + 6, dst);
+    break;
+
+  case 0x22: { // 22 -  Horz: Rail Thin [L-R]
+    Object_SizeAtoAplus15(2);
+    if ((dst[0] & 0x3ff) != 0xe2)
+      dst[0] = src[0];
+    n = src[1];
+    do *++dst = n; while (--dung_draw_width_indicator);
+    dst[1] = src[2];
+    break;
+  }
+  case 0x23: case 0x24: case 0x25: case 0x26: case 0x27: case 0x28:
+  case 0x29: case 0x2a: case 0x2b: case 0x2c: case 0x2d: case 0x2e:  // 23 -  Pit [N]Edge [L-R]
+  case 0x3f: case 0x40: case 0x41: case 0x42: case 0x43: case 0x44:  // 3F -  Water Edge [L-R]
+  case 0x45: case 0x46: case 0xb3: case 0xb4:
+    RoomDraw_GetObjectSize_1to16();
+    n = dst[0] & 0x3ff;
+    if (n != 0x1db && n != 0x1a6 && n != 0x1dd && n != 0x1fc)
+      dst[0] = src[0];
+    n = src[1];
+    do *++dst = n; while (--dung_draw_width_indicator);
+    dst[1] = src[2];
+    break;
+
+  case 0x2f: // 2F -  Rail Wall [L-R]
+    Object_SizeAtoAplus15(10);
+    n = *src++;
+    if ((dst[0] & 0x3ff) != 0xe2) {
+      dst[XY(0, 0)] = src[0];
+      dst[XY(1, 0)] = src[1];
+      dst[XY(1, 1)] = dst[XY(0, 1)] = n;
+      dst += 2;
+    }
+    src += 2;
+    do {
+      dst[XY(0, 0)] = src[0];
+      dst[XY(0, 1)] = n;
+    } while (dst++, --dung_draw_width_indicator);
+    src++;
+    dst[XY(0, 0)] = src[0];
+    dst[XY(1, 0)] = src[1];
+    dst[XY(1, 1)] = dst[XY(0, 1)] = n;
+    break;
+
+  case 0x30:  // 30 -  Rail Wall [L-R]
+    Object_SizeAtoAplus15(10);
+    n = *src++;
+    if ((dst[XY(0, 1)] & 0x3ff) != 0xe2) {
+      dst[XY(0, 0)] = dst[XY(1, 0)] = n;
+      dst[XY(0, 1)] = src[0];
+      dst[XY(1, 1)] = src[1];
+      dst += 2;
+    }
+    src += 2;
+    do {
+      dst[XY(0, 0)] = n;
+      dst[XY(0, 1)] = src[0];
+    } while (dst++, --dung_draw_width_indicator);
+    src++;
+    dst[XY(0, 0)] = dst[XY(1, 0)] = n;
+    dst[XY(0, 1)] = src[0];
+    dst[XY(1, 1)] = src[1];
+    break;
+  case 0x31: case 0x32:  // 31 -  Unused -empty
+  case 0x35: case 0x54: case 0x57:case 0x58:case 0x59:case 0x5A:
+    break;
+  case 0x33:  // 33 -  Red Carpet Floor [L-R]
+  case 0xb2: case 0xba:  // B2 -  Floor? [L-R]
+    RoomDraw_GetObjectSize_1to16();
+    do {
+      RoomDraw_4x4(src, dst), dst += XY(4, 0);
+    } while (--dung_draw_width_indicator);
+    break;
+  case 0x34:  // 34 -  Red Carpet Floor Trim [L-R]
+    Object_SizeAtoAplus15(4);
+    n = src[0];
+    do *dst++ = n; while (--dung_draw_width_indicator);
+    break;
+  case 0x36: case 0x37: // 36 -  [N]Curtain [L-R]
+    RoomDraw_GetObjectSize_1to16();
+    do {
+      RoomDraw_4x4(src, dst), dst += XY(6, 0);
+    } while (--dung_draw_width_indicator);
+    break;
+  case 0x38:  // 38 -  Statue [L-R]
+    src = (uint16 *)((uint8 *)src - param1 + 0xe26);
+    RoomDraw_GetObjectSize_1to16();
+    do {
+      RoomDraw_1x3_rightwards(2, src, dst), dst += XY(4, 0);
+    } while (--dung_draw_width_indicator);
+    break;
+  case 0x39: case 0x3d: // 39 -  Column [L-R]
+    RoomDraw_GetObjectSize_1to16();
+    do {
+      RoomDraw_Object_Nx4(2, src, dst), dst += XY(6, 0);
+    } while (--dung_draw_width_indicator);
+    break;
+  case 0x3a: case 0x3b: // 3A -  [N]Wall Decor: [L-R]
+    RoomDraw_GetObjectSize_1to16();
+    do {
+      RoomDraw_1x3_rightwards(4, src, dst), dst += XY(8, 0);
+    } while (--dung_draw_width_indicator);
+    break;
+  case 0x3c:  // 3C -  Double Chair [L-R]
+    RoomDraw_GetObjectSize_1to16();
+    do {
+      const uint16 *src = SrcPtr(0x8ca);
+      RoomDraw_Rightwards2x2(src + 0, dst);
+      RoomDraw_Rightwards2x2(src + 4, dst + XY(0, 6));
+      dst += 4;
+    } while (--dung_draw_width_indicator);
+    break;
+  case 0x3e: case 0x4b: // 3E -  [N]Wall Column [L-R]
+    RoomDraw_GetObjectSize_1to16();
+    do {
+      RoomDraw_Rightwards2x2(src, dst), dst += XY(14, 0);
+    } while (--dung_draw_width_indicator);
+    break;
+  case 0x47:  // 47 -  Unused Waterfall [L-R]
+    RoomDraw_GetObjectSize_1to16();
+    dung_draw_width_indicator <<= 1;
+    dst = RoomDraw_DrawObject2x2and1(src, dst) + 1;
+    do {
+      RoomDraw_DrawObject2x2and1(src + 5, dst);
+    } while (dst++, --dung_draw_width_indicator);
+    RoomDraw_DrawObject2x2and1(src + 10, dst);
+    break;
+  case 0x48:
+    RoomDraw_GetObjectSize_1to16();
+    dung_draw_width_indicator <<= 1;
+    RoomDraw_1x3_rightwards(1, src, dst), dst += XY(1, 0);
+    do {
+      dst[XY(0, 0)] = src[3];
+      dst[XY(0, 1)] = src[4];
+      dst[XY(0, 2)] = src[5];
+    } while (dst++, --dung_draw_width_indicator);
+    RoomDraw_1x3_rightwards(1, src + 6, dst);
+    break;
+  case 0x49: case 0x4A:  // RoomDraw_RightwardsFloorTile4x2_1to16      ; 49 -  N/A
+    RoomDraw_GetObjectSize_1to16();
+    RoomDraw_Downwards4x2VariableSpacing(4, src, dst);
+    break;
+  case 0x4c:  // 4C -  Bar [L-R]
+    RoomDraw_GetObjectSize_1to16();
+    dung_draw_width_indicator <<= 1;
+    dst = RoomDraw_RightwardBarSegment(src, dst) + 1;
+    do {
+      dst = RoomDraw_RightwardBarSegment(src + 3, dst) + 1;
+    } while (--dung_draw_width_indicator);
+    dst = RoomDraw_RightwardBarSegment(src + 6, dst) + 1;
+    break;
+
+  case 0x4d: case 0x4e: case 0x4f:  // 4C -  Bar [L-R]
+    RoomDraw_GetObjectSize_1to16();
+    RoomDraw_Object_Nx4(1, src, dst), dst += XY(1, 0);
+    do {
+      RoomDraw_Object_Nx4(2, src + 4, dst), dst += XY(2, 0);
+    } while (--dung_draw_width_indicator);
+    RoomDraw_RightwardShelfEnd(src + 12, dst);
+    break;
+
+  case 0x50:   // 50 -  Cane Ride [L-R]
+    Object_SizeAtoAplus15(2);
+    n = src[0];
+    do *dst++ = n; while (--dung_draw_width_indicator);
+    break;
+
+  case 0x51: case 0x52: // 51 -  [N]Canon Hole [L-R]
+  case 0x5B: case 0x5C:
+    RoomDraw_GetObjectSize_1to16();
+    RoomDraw_1x3_rightwards(2, src, dst), dst += XY(2, 0);
+    while (--dung_draw_width_indicator)
+      RoomDraw_1x3_rightwards(2, src + 6, dst), dst += XY(2, 0);
+    RoomDraw_1x3_rightwards(2, src + 12, dst);
+    break;
+
+  case 0x55: case 0x56:  // 55 -  [N]Wall Torches [L-R]
+    RoomDraw_GetObjectSize_1to16();
+    RoomDraw_Downwards4x2VariableSpacing(12, src, dst);
+    break;
+
+  case 0x5D:  // 5D -  Large Horz: Rail [L-R]
+    RoomDraw_GetObjectSize_1to16();
+    dung_draw_width_indicator++;
+    RoomDraw_1x3_rightwards(2, src, dst), dst += XY(2, 0);
+    do {
+      RoomDraw_RightwardBarSegment(src + 6, dst), dst += XY(1, 0);
+    } while (--dung_draw_width_indicator);
+    RoomDraw_1x3_rightwards(2, src + 9, dst);
+    break;
+
+  case 0x5E:  // 5E -  Block [L-R]
+  case 0xbb:  // BB -  N/A
+    RoomDraw_GetObjectSize_1to16();
+    do {
+      RoomDraw_Rightwards2x2(src, dst), dst += XY(4, 0);
+    } while (--dung_draw_width_indicator);
+    break;
+
+  case 0x5f: { // 5F -  Long Horz: Rail [L-R]
+    Object_SizeAtoAplus15(21);
+    if ((dst[0] & 0x3ff) != 0xe2)
+      dst[0] = src[0];
+    n = src[1];
+    do *++dst = n; while (--dung_draw_width_indicator);
+    dst[1] = src[2];
+    break;
+  }
+
+  case 0x60:  // 60 -  Ceiling [U-D]
+  case 0x92: case 0x93: // 92 -  Blue Peg Block [U-D]
+    RoomDraw_GetObjectSize_1to15or32();
+    do {
+      RoomDraw_Rightwards2x2(src, dst), dst += XY(0, 2);
+    } while (--dung_draw_width_indicator);
+    break;
+
+  case 0x61: case 0x62: case 0x90: case 0x91:  // 61 -  [W]Wall Vert: [U-D]
+    RoomDraw_GetObjectSize_1to15or26();
+    RoomDraw_Downwards4x2VariableSpacing(2 * 64, src, dst);
+    break;
+
+  case 0x63:
+  case 0x64:  // RoomDraw_Downwards4x2_1to16_BothBG - 63 -  [W]Wall Vert: (LOW) [U-D]
+    RoomDraw_GetObjectSize_1to16();
+    do {
+      dung_bg1[dsto + XY(0, 0)] = dung_bg2[dsto + XY(0, 0)] = src[0];
+      dung_bg1[dsto + XY(1, 0)] = dung_bg2[dsto + XY(1, 0)] = src[1];
+      dung_bg1[dsto + XY(2, 0)] = dung_bg2[dsto + XY(2, 0)] = src[2];
+      dung_bg1[dsto + XY(3, 0)] = dung_bg2[dsto + XY(3, 0)] = src[3];
+      dung_bg1[dsto + XY(0, 1)] = dung_bg2[dsto + XY(0, 1)] = src[4];
+      dung_bg1[dsto + XY(1, 1)] = dung_bg2[dsto + XY(1, 1)] = src[5];
+      dung_bg1[dsto + XY(2, 1)] = dung_bg2[dsto + XY(2, 1)] = src[6];
+      dung_bg1[dsto + XY(3, 1)] = dung_bg2[dsto + XY(3, 1)] = src[7];
+      dsto += XY(0, 2);
+    } while (--dung_draw_width_indicator);
+    break;
+
+  case 0x65: case 0x66:  // 65 -  [W]Wall Column [U-D]
+    RoomDraw_GetObjectSize_1to16();
+    RoomDraw_Downwards4x2VariableSpacing(6 * 64, src, dst);
+    break;
+
+  case 0x67: case 0x68: // 67 -  [W]Wall Pit [U-D]
+  case 0x7d:            // 7D -  Pipe Ride [U-D]
+    RoomDraw_GetObjectSize_1to16();
+    do {
+      RoomDraw_Rightwards2x2(src, dst), dst += XY(0, 2);
+    } while (--dung_draw_width_indicator);
+    break;
+  case 0x69:  // 69 -  Vert: Rail Thin [U-D]
+    Object_SizeAtoAplus15(2);
+    if ((dst[0] & 0x3ff) != 0xe3)
+      dst[0] = src[0];
+    n = src[1];
+    do { dst += 64; *dst = n; } while (--dung_draw_width_indicator);
+    dst[64] = src[2];
+    break;
+  case 0x6a: case 0x6b: // 6A -  [W]Pit Edge [U-D]
+  case 0x79: case 0x7a: // 79 -  Water Edge [U-D]
+  case 0x8d: case 0x8e: // 8D -  [W]Edge [U-D]
+    RoomDraw_GetObjectSize_1to16();
+    do {
+      dst[0] = src[0], dst += XY(0, 1);
+    } while (--dung_draw_width_indicator);
+    break;
+  case 0x6c: // 6C -  [W]Rail Wall [U-D]
+    Object_SizeAtoAplus15(10);
+    n = *src++;
+    if ((dst[0] & 0x3ff) != 0xe3) {
+      dst[XY(0, 0)] = src[0];
+      dst[XY(0, 1)] = src[1];
+      dst[XY(1, 0)] = dst[XY(1, 1)] = n;
+      dst += XY(0, 2);
+    }
+    src += 2;
+    do {
+      dst[XY(0, 0)] = src[0];
+      dst[XY(1, 0)] = n;
+      dst += XY(0, 1);
+    } while (--dung_draw_width_indicator);
+    src += 1;
+    dst[XY(0, 0)] = src[0];
+    dst[XY(0, 1)] = src[1];
+    dst[XY(1, 0)] = dst[XY(1, 1)] = n;
+    break;
+  case 0x6d:   // 6D -  [E]Rail Wall [U-D]
+    Object_SizeAtoAplus15(10);
+    n = *src++;
+    if ((dst[XY(1, 0)] & 0x3ff) != 0xe3) {
+      dst[XY(0, 0)] = dst[XY(0, 1)] = n;
+      dst[XY(1, 0)] = src[0];
+      dst[XY(1, 1)] = src[1];
+      dst += XY(0, 2);
+    }
+    src += 2;
+    do {
+      dst[XY(0, 0)] = n;
+      dst[XY(1, 0)] = src[0];
+      dst += XY(0, 1);
+    } while (--dung_draw_width_indicator);
+    src += 1;
+    dst[XY(0, 0)] = dst[XY(0, 1)] = n;
+    dst[XY(1, 0)] = src[0];
+    dst[XY(1, 1)] = src[1];
+    break;
+  case 0x6e: case 0x6f: // unused
+  case 0x72: case 0x7e:
+    break;
+  case 0x70: case 0x94:  // 70 -  Red Floor/Wire Floor [U-D]
+    RoomDraw_GetObjectSize_1to16();
+    do {
+      RoomDraw_4x4(src, dst), dst += XY(0, 4);
+    } while (--dung_draw_width_indicator);
+    break;
+  case 0x71:  // 71 -  Red Carpet Floor Trim [U-D]
+    Object_SizeAtoAplus15(4);
+    do {
+      *dst = src[0], dst += XY(0, 1);
+    } while (--dung_draw_width_indicator);
+    break;
+  case 0x73: case 0x74:  // 73 -  [W]Curtain [U-D]
+    RoomDraw_GetObjectSize_1to16();
+    do {
+      RoomDraw_4x4(src, dst), dst += XY(0, 6);
+    } while (--dung_draw_width_indicator);
+    break;
+  case 0x75: case 0x87:  // 75 -  Column [U-D]
+    RoomDraw_GetObjectSize_1to16();
+    do {
+      RoomDraw_Object_Nx4(2, src, dst), dst += XY(0, 6);
+    } while (--dung_draw_width_indicator);
+    break;
+  case 0x76: case 0x77:  // 76 -  [W]Wall Decor: [U-D]
+    RoomDraw_GetObjectSize_1to16();
+    do {
+      RoomDraw_Object_Nx4(3, src, dst), dst += XY(0, 8);
+    } while (--dung_draw_width_indicator);
+    break;
+  case 0x78: case 0x7b:  // 78 -  [W]Wall Top Column [U-D]
+    RoomDraw_GetObjectSize_1to16();
+    do {
+      RoomDraw_Rightwards2x2(src, dst), dst += XY(0, 14);
+    } while (--dung_draw_width_indicator);
+    break;
+  case 0x7c:  // 7C -  Cane Ride [U-D]
+    RoomDraw_GetObjectSize_1to16();
+    dung_draw_width_indicator += 1;
+    do {
+      dst[0] = src[0], dst += XY(0, 1);
+    } while (--dung_draw_width_indicator);
+    break;
+  case 0x7f: case 0x80:  // 7F -  [W]Wall Torches [U-D]
+    RoomDraw_GetObjectSize_1to16();
+    do {
+      RoomDraw_Object_Nx4(2, src, dst), dst += XY(0, 12);
+    } while (--dung_draw_width_indicator);
+    break;
+  case 0x81: case 0x82: case 0x83: case 0x84: // 81 -  [W]Wall Decor: [U-D]
+    RoomDraw_GetObjectSize_1to16();
+    do {
+      RoomDraw_Object_Nx4(3, src, dst), dst += XY(0, 6);
+    } while (--dung_draw_width_indicator);
+    break;
+  case 0x85: case 0x86:  // 85 -  [W]Wall Canon Hole [U-D]
+    RoomDraw_GetObjectSize_1to16();
+    Object_Draw_3x2(src, dst), dst += XY(0, 2);
+    while (--dung_draw_width_indicator)
+      Object_Draw_3x2(src + 6, dst), dst += XY(0, 2);
+    Object_Draw_3x2(src + 12, dst);
+    break;
+  case 0x88: // 88 -  Large Vert: Rail [U-D]
+    RoomDraw_GetObjectSize_1to16();
+    RoomDraw_Rightwards2x2(src, dst), dst += XY(0, 2), src += 4;
+    do {
+      dst[XY(0, 0)] = src[0];
+      dst[XY(1, 0)] = src[1];
+      dst += XY(0, 1);
+    } while (--dung_draw_width_indicator);
+    RoomDraw_1x3_rightwards(2, src + 2, dst);
+    break;
+  case 0x89: // 89 -  Block Vert: [U-D]
+    RoomDraw_GetObjectSize_1to16();
+    do {
+      RoomDraw_Rightwards2x2(src, dst), dst += XY(0, 4);
+    } while (--dung_draw_width_indicator);
+    break;
+  case 0x8a: // 8A -  Long Vert: Rail [U-D]
+    Object_SizeAtoAplus15(21);
+    if ((dst[0] & 0x3ff) != 0xe3)
+      dst[0] = src[0];
+    n = src[1];
+    do { dst += XY(0, 1); *dst = n; } while (--dung_draw_width_indicator);
+    dst[XY(0, 1)] = src[2];
+    break;
+  case 0x8b: case 0x8c: // 8B -  [W]Vert: Jump Edge [U-D]
+    Object_SizeAtoAplus15(8);
+    do {
+      dst[0] = src[0], dst += XY(0, 1);
+    } while (--dung_draw_width_indicator);
+    break;
+  case 0x8f: // 8F -  N/A
+    Object_SizeAtoAplus15(2);
+    dung_draw_width_indicator <<= 1;
+    dst[XY(0, 0)] = src[0], dst[XY(1, 0)] = src[1];
+    do {
+      dst[XY(0, 1)] = src[2], dst[XY(1, 1)] = src[3], dst += XY(0, 1);
+    } while (--dung_draw_width_indicator);
+    break;
+  case 0x95:  // 95 -  Fake Pot [U-D]
+    RoomDraw_GetObjectSize_1to16();
+    do {
+      RoomDraw_SinglePot(src, dst, dsto);
+      dst += XY(0, 2), dsto += XY(0, 2);
+    } while (--dung_draw_width_indicator);
+    break;
+  case 0x96:  // 96 -  Hammer Peg Block [U-D]
+    RoomDraw_GetObjectSize_1to16();
+    do {
+      RoomDraw_HammerPegSingle(src, dst, dsto);
+      dst += XY(0, 2), dsto += XY(0, 2);
+    } while (--dung_draw_width_indicator);
+    break;
+  case 0x97: case 0x98: case 0x99: case 0x9a: case 0x9b: case 0x9c: case 0x9d: case 0x9e: case 0x9f:
+  case 0xad: case 0xae: case 0xaf:
+  case 0xbe: case 0xbf:
+    break;
+  case 0xa0:  // A0 -  / Ceiling [NW]
+  case 0xa5: case 0xa9:  // A5 -  / Ceiling [Trans][NW]
+    Object_SizeAtoAplus15(4);
+    do {
+      Object_Fill_Nx1(dung_draw_width_indicator, src, dst), dst += XY(0, 1);
+    } while (--dung_draw_width_indicator);
+    break;
+  case 0xa1:  // A1 -  \ Ceiling [SW]
+  case 0xa6: case 0xaa:  // A6 -  \ Ceiling [Trans][SW]
+    Object_SizeAtoAplus15(4);
+    n = 1;
+    do {
+      Object_Fill_Nx1(n++, src, dst), dst += XY(0, 1);
+    } while (--dung_draw_width_indicator);
+    break;
+  case 0xa2:  // A2 -  \ Ceiling [NE]
+  case 0xa7: case 0xab:  // A7 -  \ Ceiling [Trans][NE]
+    Object_SizeAtoAplus15(4);
+    do {
+      Object_Fill_Nx1(dung_draw_width_indicator, src, dst), dst += XY(1, 1);
+    } while (--dung_draw_width_indicator);
+    break;
+  case 0xa3:             // A3 -  / Ceiling [SE]
+  case 0xa8: case 0xac:  // A8 -  / Ceiling [Trans][SE]
+    Object_SizeAtoAplus15(4);
+    do {
+      Object_Fill_Nx1(dung_draw_width_indicator, src, dst), dst += XY(1, -1);
+    } while (--dung_draw_width_indicator);
+    break;
+  case 0xa4: // A4 -  Hole [4-way]
+    Object_Hole(src, dst);
+    break;
+  case 0xb0: case 0xb1: // B0 -  [S]Horz: Jump Edge [L-R]
+    Object_SizeAtoAplus15(8);
+    Object_Fill_Nx1(dung_draw_width_indicator, src, dst);
+    break;
+  case 0xb5:  // B5 -  N/A
+    RoomDraw_GetObjectSize_1to16();
+    do {
+      src = SrcPtr(0xb16);
+      RoomDraw_Object_Nx4(2, src, dst), dst += XY(2, 0);
+    } while (--dung_draw_width_indicator);
+    break;
+  case 0xbc: // BC -  fake pots [L-R]
+    RoomDraw_GetObjectSize_1to16();
+    do {
+      RoomDraw_SinglePot(src, dst, dsto);
+      dst += XY(2, 0), dsto += XY(2, 0);
+    } while (--dung_draw_width_indicator);
+    break;
+  case 0xbd: // BD -  Hammer Pegs [L-R]
+    RoomDraw_GetObjectSize_1to16();
+    do {
+      RoomDraw_HammerPegSingle(src, dst, dsto);
+      dst += XY(2, 0), dsto += XY(2, 0);
+    } while (--dung_draw_width_indicator);
+    break;
+  case 0xc0: case 0xc2: // C0 -  Ceiling Large [4-way]
+    n = src[0];
+    for (int y = dung_draw_height_indicator; y-- >= 0; ) {
+      uint16 *dst_org = dst;
+      for (int x = dung_draw_width_indicator; x-- >= 0; dst += XY(4, 0)) {
+        dst[XY(0, 0)] = dst[XY(1, 0)] = dst[XY(2, 0)] = dst[XY(3, 0)] = n;
+        dst[XY(0, 1)] = dst[XY(1, 1)] = dst[XY(2, 1)] = dst[XY(3, 1)] = n;
+        dst[XY(0, 2)] = dst[XY(1, 2)] = dst[XY(2, 2)] = dst[XY(3, 2)] = n;
+        dst[XY(0, 3)] = dst[XY(1, 3)] = dst[XY(2, 3)] = dst[XY(3, 3)] = n;
+      }
+      dst = dst_org + XY(0, 4);
+    }
+    break;
+  case 0xc1: { // C1 -  Chest Pedastal [4-way]
+    dung_draw_width_indicator += 4;
+    dung_draw_height_indicator += 1;
+    // draw upper part
+    uint16 *dsto = dst;
+    RoomDraw_1x3_rightwards(3, src, dst), src += 9, dst += XY(3, 0);
+    for (int i = dung_draw_width_indicator; i--; )
+      RoomDraw_1x3_rightwards(2, src, dst), dst += XY(2, 0);
+    RoomDraw_1x3_rightwards(3, src + 6, dst), src += 6 + 9;
+    // draw center part
+    dst = dsto + XY(0, 3);
+    for (int i = dung_draw_height_indicator; i--; ) {
+      uint16 *dt = dst;
+      Object_Draw_3x2(src, dt), dt += XY(3, 0);
+      for (int j = dung_draw_width_indicator; j--; )
+        RoomDraw_Rightwards2x2(src + 6, dt), dt += XY(2, 0);
+      Object_Draw_3x2(src + 10, dt);
+      dst += XY(0, 2);
+    }
+    dsto = dst;
+    src += 6 + 4 + 6;
+    RoomDraw_1x3_rightwards(3, src, dst), src += 9, dst += XY(3, 0);
+    for (int i = dung_draw_width_indicator; i--; )
+      RoomDraw_1x3_rightwards(2, src, dst), dst += XY(2, 0);
+    RoomDraw_1x3_rightwards(3, src + 6, dst), src += 6 + 9;
+
+    src = SrcPtr(0x590);
+    RoomDraw_Rightwards2x2(src, dsto + XY(dung_draw_width_indicator + 2, -(dung_draw_height_indicator + 1)));
+    break;
+  }
+  case 0xc3:  // C3 -  Falling Edge Mask [4-way]
+  case 0xd7:  // D7 -  overlay tile? [4-way]
+    dung_draw_width_indicator++;
+    dung_draw_height_indicator++;
+    n = *src;
+    do {
+      uint16 *d = dst;
+      for (int i = dung_draw_width_indicator; i--; d += XY(3, 0)) {
+        d[XY(0, 0)] = d[XY(1, 0)] = d[XY(2, 0)] = n;
+        d[XY(0, 1)] = d[XY(1, 1)] = d[XY(2, 1)] = n;
+        d[XY(0, 2)] = d[XY(1, 2)] = d[XY(2, 2)] = n;
+      }
+      dst += XY(0, 3);
+    } while (--dung_draw_height_indicator);
+    break;
+
+  case 0xc4: // C4 -  Doorless Room Transition
+    src = SrcPtr(dung_floor_2_filler_tiles);
+    goto fill_floor;
+
+  case 0xdb: // C4 -  DB -  Floor2 [4-way]
+    src = SrcPtr(dung_floor_1_filler_tiles);
+    goto fill_floor;
+
+  case 0xc5: case 0xc6: case 0xc7: case 0xc8: case 0xc9: case 0xca:
+  case 0xd1: case 0xd2: case 0xd9:
+  case 0xdf: case 0xe0: case 0xe1: case 0xe2: case 0xe3: case 0xe4:
+  case 0xe5: case 0xe6: case 0xe7: case 0xe8:
+fill_floor:
+    dung_draw_width_indicator++;
+    dung_draw_height_indicator++;
+    do {
+      RoomDraw_A_Many32x32Blocks(dung_draw_width_indicator, src, dst);
+      dst += XY(0, 4);
+    } while (--dung_draw_height_indicator);
+    break;
+
+  case 0xcd: { // CD -  Moving Wall Right [4-way]
+    if (!RoomDraw_CheckIfWallIsMoved())
+      return;
+    dung_hdr_collision_2_mirror++;
+    int size0 = kMovingWall_Sizes0[dung_draw_width_indicator];
+    int size1 = kMovingWall_Sizes1[dung_draw_height_indicator];
+    MovingWall_FillReplacementBuffer(dsto - size1 - 1);
+    moving_wall_var2 = dung_draw_height_indicator * 2;
+    src = SrcPtr(0x3d8);
+    uint16 *dst1 = dst - size1;
+    do {
+      uint16 *dst2 = dst1;
+      dst2[XY(0, 0)] = src[0];
+      int n1 = size0 * 2 + 4;
+      do {
+        dst2[XY(0, 1)] = src[1];
+        dst2 += XY(0, 1);
+      } while (--n1);
+      dst2[XY(0, 1)] = src[2];
+      dst1++;
+    } while (--size1);
+    src = SrcPtr(0x72a);
+    RoomDraw_1x3_rightwards(3, src, dst);
+    dst += XY(0, 3);
+    do {
+      Object_Draw_3x2(src + 9, dst);
+    } while (dst += XY(0, 2), --size0);
+    RoomDraw_1x3_rightwards(3, src + 9 + 6, dst);
+    break;
+  }
+
+  case 0xce: { // CE -  Moving Wall Left [4-way]
+    if (!RoomDraw_CheckIfWallIsMoved())
+      return;
+    dung_hdr_collision_2_mirror++;
+    src = SrcPtr(0x75a);
+    int size1 = kMovingWall_Sizes1[dung_draw_height_indicator];
+    int size0 = kMovingWall_Sizes0[dung_draw_width_indicator];
+    moving_wall_var2 = dung_draw_height_indicator * 2;
+    MovingWall_FillReplacementBuffer(dsto + 3 + size1);
+    uint16 *dst1 = dst;
+    RoomDraw_1x3_rightwards(3, src, dst1);
+    dst1 += XY(0, 3);
+    int n = size0;
+    do {
+      Object_Draw_3x2(src + 9, dst1);
+      dst1 += XY(0, 2);
+    } while (--n);
+    RoomDraw_1x3_rightwards(3, src + 15, dst1);
+    src = SrcPtr(0x3d8);
+    dst1 = dst + XY(3, 0);
+    do {
+      uint16 *dst2 = dst1;
+      dst2[XY(0, 0)] = src[0];
+      int n1 = size0 * 2 + 4;
+      do {
+        dst2[XY(0, 1)] = src[1];
+        dst2 += XY(0, 1);
+      } while (--n1);
+      dst2[XY(0, 1)] = src[2];
+      dst1++;
+    } while (--size1);
+    break;
+  }
+
+  case 0xd8: {
+    // loads of lava/water hdma stuff
+    dung_draw_width_indicator += 2;
+    water_hdma_var3 = (dung_draw_width_indicator << 4);
+    dung_draw_height_indicator += 2;
+    water_hdma_var2 = (dung_draw_height_indicator << 4);
+    water_hdma_var4 = water_hdma_var2 - 24;
+    water_hdma_var0 = (dsto & 0x3f) << 3;
+    water_hdma_var0 += (dung_draw_width_indicator << 4) + dung_loade_bgoffs_h_copy;
+    water_hdma_var1 = (dsto & 0xfc0) >> 3;
+    water_hdma_var1 += (dung_draw_height_indicator << 4) + dung_loade_bgoffs_v_copy;
+    if (dung_savegame_state_bits & 0x800) {
+      dung_hdr_tag[1] = 0;
+      dung_hdr_bg2_properties = 0;
+      dung_num_interpseudo_upnorth_stairs = dung_num_inroom_upnorth_stairs_water;
+      dung_some_stairs_unk4 = dung_num_activated_water_ladders;
+      dung_num_activated_water_ladders = 0;
+      dung_num_inroom_upnorth_stairs_water = 0;
+      dung_num_stairs_wet = dung_num_inroom_upsouth_stairs_water;
+      dung_num_inroom_upsouth_stairs_water = 0;
+      dsto += (dung_draw_width_indicator - 1) << 1;
+      dsto += (dung_draw_height_indicator - 1) << 7;
+      DrawWaterThing(&dung_bg2[dsto], SrcPtr(0x1438));
+    } else {
+      src = SrcPtr(0x110);
+      do {
+        RoomDraw_A_Many32x32Blocks(dung_draw_width_indicator, src, dst);
+        dst += XY(0, 4);
+      } while (--dung_draw_height_indicator);
+    }
+    break;
+  }
+
+  case 0xda: {  // water hdma stuff
+    dung_draw_width_indicator += 2;
+    water_hdma_var3 = (dung_draw_width_indicator << 4) - 24;
+
+    dung_draw_height_indicator += 2;
+    water_hdma_var4 = (dung_draw_height_indicator << 4) - 8;
+
+    water_hdma_var2 = water_hdma_var4 - 24;
+    water_hdma_var5 = 0;
+    water_hdma_var0 = (dsto & 0x3f) << 3;
+    water_hdma_var0 += (dung_draw_width_indicator << 4) + dung_loade_bgoffs_h_copy;
+    water_hdma_var1 = (dsto & 0xfc0) >> 3;
+    water_hdma_var1 += (dung_draw_height_indicator << 4) + dung_loade_bgoffs_v_copy - 8;
+    if (dung_savegame_state_bits & 0x800) {
+      dung_hdr_tag[1] = 0;
+    } else {
+      dung_hdr_bg2_properties = 0;
+      dung_num_interpseudo_upnorth_stairs = dung_num_inroom_upnorth_stairs_water;
+      dung_some_stairs_unk4 = dung_num_activated_water_ladders;
+      dung_num_activated_water_ladders = 0;
+      dung_num_inroom_upnorth_stairs_water = 0;
+      dung_num_stairs_wet = dung_num_inroom_upsouth_stairs_water;
+      dung_num_inroom_upsouth_stairs_water = 0;
+    }
+    int n = dung_draw_height_indicator * 2 - 1;
+    src = SrcPtr(0x110);
+    do {
+      uint16 *dst2 = dst;
+      int j = dung_draw_width_indicator;
+      do {
+        dst[XY(0, 0)] = src[0];
+        dst[XY(1, 0)] = src[1];
+        dst[XY(2, 0)] = src[2];
+        dst[XY(3, 0)] = src[3];
+        dst[XY(0, 1)] = src[4];
+        dst[XY(1, 1)] = src[5];
+        dst[XY(2, 1)] = src[6];
+        dst[XY(3, 1)] = src[7];
+        dst += 4;
+      } while (--j);
+      dst = dst2 + XY(0, 2);
+    } while (--n);
+    break;
+  }
+
+  case 0xdc: { // DC -  Chest Platform? [4-way]
+    dsto |= (dung_line_ptrs_row0 != 0x4000 ? 0 : 0x1000);
+    dung_draw_width_indicator++;
+    dung_draw_height_indicator = dung_draw_height_indicator * 2 + 5;
+    src = SrcPtr(0xAB4);
+    do {
+      Object_ChestPlatform_Helper(src, dsto), dsto += XY(0, 1);
+    } while (--dung_draw_height_indicator);
+    Object_ChestPlatform_Helper(src + 1, dsto), dsto += XY(0, 1);
+    Object_ChestPlatform_Helper(src + 2, dsto), dsto += XY(0, 1);
+    break;
+  }
+  case 0xdd: // DD -  Table / Rock [4-way]
+    dung_draw_width_indicator++;
+    dung_draw_height_indicator = dung_draw_height_indicator * 2 + 1;
+    Object_Table_Helper(src, dst), dst += XY(0, 1);
+    do {
+      Object_Table_Helper(src + 4, dst), dst += XY(0, 1);
+    } while (--dung_draw_height_indicator);
+    Object_Table_Helper(src + 8, dst), dst += XY(0, 1);
+    Object_Table_Helper(src + 12, dst), dst += XY(0, 1);
+    break;
+
+  case 0xde: // DE -  Spike Block [4-way]
+    dung_draw_width_indicator++;
+    dung_draw_height_indicator++;
+    do {
+      int n = dung_draw_width_indicator;
+      uint16 *dst1 = dst;
+      do {
+        RoomDraw_Rightwards2x2(src, dst1), dst1 += XY(2, 0);
+      } while (--n);
+      dst += XY(0, 2);
+    } while (--dung_draw_height_indicator);
+    break;
+
+  case 0xcb: case 0xcc: case 0xcf: case 0xd0:
+  case 0xd3: case 0xd4: case 0xd5: case 0xd6:
+  case 0xe9: case 0xea: case 0xeb: case 0xec: case 0xed: case 0xee: case 0xef:
+  case 0xf0: case 0xf1: case 0xf2: case 0xf3: case 0xf4: case 0xf5: case 0xf6: case 0xf7:
+    assert(0);
+    break;
+  default:
+    assert(0);
+  }
+}
+
+void Object_DrawNx3_BothBgs(int n, const uint16 *src, int dsto) {
+  do {
+    dung_bg1[dsto + XY(0, 0)] = dung_bg2[dsto + XY(0, 0)] = src[0];
+    dung_bg1[dsto + XY(0, 1)] = dung_bg2[dsto + XY(0, 1)] = src[1];
+    dung_bg1[dsto + XY(0, 2)] = dung_bg2[dsto + XY(0, 2)] = src[2];
+    src += 3, dsto += 1;
+  } while (--n);
+}
+
+void LoadType1ObjectSubtype2(uint8 idx, uint16 *dst, uint16 dsto) {
+  uint16 params = kObjectSubtype2Params[idx];
+  const uint16 *src = SrcPtr(params);
+  int i;
+  switch (idx) {
+  case 0x00: case 0x01: case 0x02: case 0x03:
+  case 0x04: case 0x05: case 0x06: case 0x07:  // 00 -  Wall Outer Corner (HIGH) [NW]
+  case 0x1c: case 0x24: case 0x25: case 0x29:
+    RoomDraw_Object_Nx4(4, src, dst);
+    break;
+  case 0x08: case 0x09: case 0x0a: case 0x0b:
+  case 0x0c: case 0x0d: case 0x0e: case 0x0f:  // 08 -  Wall Outer Corner (LOW) [NW]
+    Object_DrawNx4_BothBgs(4, src, dsto);
+    break;
+  case 0x10: case 0x11: case 0x12: case 0x13:  // 10 -  Wall S-Bend (LOW) [N1]
+    Object_DrawNx4_BothBgs(3, src, dsto);
+    break;
+  case 0x14: case 0x15: case 0x16: case 0x17:  // 14 -  Wall S-Bend (LOW) [W1]
+    Object_DrawNx3_BothBgs(4, src, dsto);
+    break;
+  case 0x18: case 0x19: case 0x1a: case 0x1b:  // 18 -  Wall Pit Corner (Lower) [NW]
+  case 0x27: case 0x2b: case 0x34:
+    RoomDraw_Rightwards2x2(src, dst);
+    break;
+  case 0x1d: case 0x21: case 0x26:             // 1D -  Statue
+    RoomDraw_1x3_rightwards(2, src, dst);
+    break;
+  case 0x1e:                                   // 1E -  Star Tile Off
+    RoomDraw_Rightwards2x2(src, dst);
+    break;
+  case 0x1f:                                   // 1F -  Star Tile On
+    i = dung_num_star_shaped_switches >> 1;
+    dung_num_star_shaped_switches += 2;
+    star_shaped_switches_tile[i] = (dsto | (dung_line_ptrs_row0 != 0x4000 ? 0 : 0x1000));
+    RoomDraw_Rightwards2x2(src, dst);
+    break;
+  case 0x20:                                   // 20 -  Torch Lit
+    dung_num_lit_torches++;
+    RoomDraw_Rightwards2x2(src, dst);
+    break;
+  case 0x22: case 0x28:                        // 22 -  Weird Bed
+    Object_Draw_5x4(src, dst);
+    break;
+  case 0x23:                                   // 23 -  Table
+    RoomDraw_1x3_rightwards(4, src, dst);
+    break;
+  case 0x2a:                                   // 2A -  Wall Painting
+    dung_draw_width_indicator = 1;
+    RoomDraw_Downwards4x2VariableSpacing(1, src, dst);
+    break;
+  case 0x2c:                                   // 2C -  ???
+    RoomDraw_1x3_rightwards(6, src, dst);
+    break;
+  case 0x2d:    // 2D -  Floor Stairs Up (room)
+    i = dung_num_inter_room_upnorth_stairs >> 1;
+    dung_inter_starcases[i] = (dsto | (dung_line_ptrs_row0 != 0x4000 ? 0 : 0x1000));
+    dung_num_inter_room_upnorth_stairs =
+      dung_num_wall_upnorth_spiral_stairs =
+      dung_num_wall_upnorth_spiral_stairs_2 =
+      dung_num_inter_room_upnorth_straight_stairs =
+      dung_num_inter_room_upsouth_straight_stairs =
+      dung_num_inter_room_southdown_stairs =
+      dung_num_wall_downnorth_spiral_stairs =
+      dung_num_wall_downnorth_spiral_stairs_2 =
+      dung_num_inter_room_downnorth_straight_stairs =
+      dung_num_inter_room_downsouth_straight_stairs = dung_num_inter_room_upnorth_stairs + 2;
+    RoomDraw_4x4(SrcPtr(0x1088), dst);
+    break;
+  case 0x2e:    // 2E -  Floor Stairs Down (room)
+  case 0x2f:    // 2F -  Floor Stairs Down2 (room)
+    i = dung_num_inter_room_southdown_stairs >> 1;
+    dung_inter_starcases[i] = (dsto | (dung_line_ptrs_row0 != 0x4000 ? 0 : 0x1000));
+    dung_num_inter_room_southdown_stairs =
+      dung_num_wall_downnorth_spiral_stairs =
+      dung_num_wall_downnorth_spiral_stairs_2 =
+      dung_num_inter_room_downnorth_straight_stairs =
+      dung_num_inter_room_downsouth_straight_stairs = dung_num_inter_room_southdown_stairs + 2;
+    RoomDraw_4x4(SrcPtr(0x10A8), dst);
+    break;
+  case 0x30:     // 30 -  Stairs [N](unused)
+    assert(0);
+    break;
+  case 0x31:     // 31 -  Stairs [N](layer)
+    i = dung_num_inroom_southdown_stairs >> 1;
+    dung_stairs_table_1[i] = dsto;
+    dung_num_inroom_southdown_stairs =
+      dung_num_water_ladders =
+      dung_some_stairs_unk4 = dung_num_inroom_southdown_stairs + 2;
+    Object_DrawNx4_BothBgs(4, src, dsto);
+    break;
+  case 0x32:     // 32 -  Stairs [N](layer)
+non_submerged:
+    i = dung_num_interpseudo_upnorth_stairs >> 1;
+    dung_stairs_table_1[i] = dsto;
+    dung_num_interpseudo_upnorth_stairs =
+      dung_num_water_ladders =
+      dung_some_stairs_unk4 = dung_num_interpseudo_upnorth_stairs + 2;
+    RoomDraw_4x4(src, dst);
+    break;
+  case 0x33:       // 33 -  Stairs Submerged [N](layer)
+    if (dung_hdr_tag[1] == 27 && !(save_dung_info[dungeon_room_index] & 0x100)) {
+      dung_hdr_bg2_properties = 0;
+      src = SrcPtr(0x10C8);
+      goto non_submerged;
+    } else {
+      i = dung_num_inroom_upnorth_stairs_water >> 1;
+      dung_stairs_table_1[i] = dsto;
+      dung_num_inroom_upnorth_stairs_water =
+        dung_num_activated_water_ladders = dung_num_inroom_upnorth_stairs_water + 2;
+      RoomDraw_4x4(SrcPtr(0x10C8), dst);
+    }
+    break;
+  case 0x35:  // 35 -  Water Ladder
+    if (dung_hdr_tag[1] == 27 && !(save_dung_info[dungeon_room_index] & 0x100))
+      goto inactive_water_ladder;
+    dung_stairs_table_1[dung_num_activated_water_ladders >> 1] = dsto;
+    dung_num_activated_water_ladders += 2;
+    dung_draw_width_indicator = 1;
+    RoomDraw_Downwards4x2VariableSpacing(1, SrcPtr(0x1108), dst);
+    break;
+  case 0x36:  // 36 -  Water Ladder Inactive
+inactive_water_ladder:
+    dung_stairs_table_1[dung_num_water_ladders >> 1] = dsto;
+    dung_some_stairs_unk4 = (dung_num_water_ladders += 2);
+    Object_Draw_4x2_BothBgs(SrcPtr(0x1108), dsto);
+    break;
+  case 0x37:  // 37 -  Water Gate Large
+    if (!(dung_savegame_state_bits & 0x800)) {
+      RoomDraw_Object_Nx4(10, src, dst);
+      watergate_var1 = 0xf;
+      watergate_pos = dsto * 2;
+    } else {
+      RoomDraw_Object_Nx4(10, SrcPtr(0x13e8), dst);
+      uint16 bak0 = dung_load_ptr;
+      uint16 bak1 = dung_load_ptr_offs;
+      uint8 bak2 = dung_load_ptr_bank;
+      RoomTag_OperateWaterFlooring();
+      dung_load_ptr_bank = bak2;
+      dung_load_ptr_offs = bak1;
+      dung_load_ptr = bak0;
+    }
+    break;
+  case 0x38:  // 38 -  Door Staircase Up R
+    i = dung_num_wall_upnorth_spiral_stairs >> 1;
+    dung_inter_starcases[i] = (dsto - 0x40) | (dung_line_ptrs_row0 != 0x4000 ? 0 : 0x1000);
+    dung_num_wall_upnorth_spiral_stairs =
+      dung_num_wall_upnorth_spiral_stairs_2 =
+      dung_num_inter_room_upnorth_straight_stairs =
+      dung_num_inter_room_upsouth_straight_stairs =
+      dung_num_inter_room_southdown_stairs =
+      dung_num_wall_downnorth_spiral_stairs =
+      dung_num_wall_downnorth_spiral_stairs_2 =
+      dung_num_inter_room_downnorth_straight_stairs =
+      dung_num_inter_room_downsouth_straight_stairs = dung_num_wall_upnorth_spiral_stairs + 2;
+    RoomDraw_1x3_rightwards(4, SrcPtr(0x1148), dst);
+    dung_bg2[dsto - 1] |= 0x2000;
+    dung_bg2[dsto + 4] |= 0x2000;
+    break;
+  case 0x39:  // 39 -  Door Staircase Down L
+    i = dung_num_wall_downnorth_spiral_stairs >> 1;
+    dung_inter_starcases[i] = (dsto - 0x40) | (dung_line_ptrs_row0 != 0x4000 ? 0 : 0x1000);
+    dung_num_wall_downnorth_spiral_stairs =
+      dung_num_wall_downnorth_spiral_stairs_2 =
+      dung_num_inter_room_downnorth_straight_stairs =
+      dung_num_inter_room_downsouth_straight_stairs = dung_num_wall_downnorth_spiral_stairs + 2;
+    RoomDraw_1x3_rightwards(4, SrcPtr(0x1160), dst);
+    dung_bg2[dsto - 1] |= 0x2000;
+    dung_bg2[dsto + 4] |= 0x2000;
+    break;
+  case 0x3a:  // 3A -  Door Staircase Up R (Lower)
+    i = dung_num_wall_upnorth_spiral_stairs_2 >> 1;
+    dung_inter_starcases[i] = (dsto - 0x40) | (dung_line_ptrs_row0 != 0x4000 ? 0 : 0x1000);
+    dung_num_wall_upnorth_spiral_stairs_2 =
+      dung_num_inter_room_upnorth_straight_stairs =
+      dung_num_inter_room_upsouth_straight_stairs =
+      dung_num_inter_room_southdown_stairs =
+      dung_num_wall_downnorth_spiral_stairs =
+      dung_num_wall_downnorth_spiral_stairs_2 =
+      dung_num_inter_room_downnorth_straight_stairs =
+      dung_num_inter_room_downsouth_straight_stairs = dung_num_wall_upnorth_spiral_stairs_2 + 2;
+    RoomDraw_1x3_rightwards(4, SrcPtr(0x1178), dst);
+    dung_bg1[dsto - 1] |= 0x2000;
+    dung_bg1[dsto + 4] |= 0x2000;
+    break;
+  case 0x3b:  // 3B -  Door Staircase Down L (Lower)
+    i = dung_num_wall_downnorth_spiral_stairs_2 >> 1;
+    dung_inter_starcases[i] = (dsto - 0x40) | (dung_line_ptrs_row0 != 0x4000 ? 0 : 0x1000);
+    dung_num_wall_downnorth_spiral_stairs_2 =
+      dung_num_inter_room_downnorth_straight_stairs =
+      dung_num_inter_room_downsouth_straight_stairs =
+      dung_num_wall_downnorth_spiral_stairs_2 + 2;
+    RoomDraw_1x3_rightwards(4, SrcPtr(0x1190), dst);
+    dung_bg1[dsto - 1] |= 0x2000;
+    dung_bg1[dsto + 4] |= 0x2000;
+    break;
+  case 0x3c:  // 3C -  Sanctuary Wall
+    for (int i = 0; i < 6; i++) {
+      dung_bg2[dsto + 0] = dung_bg2[dsto + 4] = dung_bg2[dsto + 8] =
+        dung_bg2[dsto + 14] = dung_bg2[dsto + 18] = dung_bg2[dsto + 22] = src[0];
+      dung_bg2[dsto + 1] = dung_bg2[dsto + 5] = dung_bg2[dsto + 9] =
+        dung_bg2[dsto + 15] = dung_bg2[dsto + 19] = dung_bg2[dsto + 23] = src[0] | 0x4000;
+      dung_bg2[dsto + 2] = dung_bg2[dsto + 6] = dung_bg2[dsto + 16] = dung_bg2[dsto + 20] = src[6];
+      dung_bg2[dsto + 3] = dung_bg2[dsto + 7] = dung_bg2[dsto + 17] = dung_bg2[dsto + 21] = src[6] | 0x4000;
+      dsto += XY(0, 1);
+      src++;
+    }
+    RoomDraw_1x3_rightwards(4, src + 6, dst + 10);
+    break;
+  case 0x3e:  // 3E -  Church Pew
+    RoomDraw_1x3_rightwards(6, src, dst);
+    break;
+  case 0x3f: { // 3F - used in hole at the smithy dwarves
+    dsto |= (dung_line_ptrs_row0 != 0x4000 ? 0 : 0x1000);
+    dst = &dung_bg2[dsto];
+    for (int i = 0; i < 8; i++) {
+      dst[XY(0, 0)] = src[0];
+      dst[XY(0, 1)] = src[1];
+      dst[XY(0, 2)] = src[2];
+      dst[XY(0, 3)] = src[3];
+      dst[XY(0, 4)] = src[4];
+      dst[XY(0, 5)] = src[5];
+      dst[XY(0, 6)] = src[6];
+      dst += XY(1, 0);
+      src += 7;
+    }
+    break;
+  }
+
+  default:
+    assert(0);
+  }
+}
+
+void Object_BombableFloorHelper(uint16 a, const uint16 *src, const uint16 *src_below, uint16 *dst, uint16 dsto) {
+  int i = dung_misc_objs_index >> 1;
+  dung_replacement_tile_state[i] = a;
+  dung_misc_objs_index += 2;
+  dung_object_pos_in_objdata[i] = dung_load_ptr_offs;
+  dung_object_tilemap_pos[i] = dsto * 2 | (dung_line_ptrs_row0 != 0x4000 ? 0 : 0x2000);
+  replacement_tilemap_UL[i] = src_below[0];
+  replacement_tilemap_LL[i] = src_below[1];
+  replacement_tilemap_UR[i] = src_below[2];
+  replacement_tilemap_LR[i] = src_below[3];
+  RoomDraw_Rightwards2x2(src, dst);
+}
+
+void LoadType1ObjectSubtype3(uint8 idx, uint16 *dst, uint16 dsto) {
+  uint16 params = kObjectSubtype3Params[idx];
+  const uint16 *src = SrcPtr(params);
+  int i;
+
+  switch (idx) {
+  case 0x00:  // 00 -  Water Face Closed
+    if (dung_hdr_tag[1] == 27) {
+      if (save_dung_info[dungeon_room_index] & 0x100)
+        goto water_face_open;
+    } else if (dung_hdr_tag[1] == 25) {
+      if (dung_savegame_state_bits & 0x800)
+        goto water_face_open;
+    }
+    word_7E047C = dsto * 2;
+    RoomDraw_WaterHoldingObject(3, src, dst);
+    break;
+  case 0x01:  // 01 -  Waterfall Face
+water_face_open:
+    RoomDraw_WaterHoldingObject(5, SrcPtr(0x162c), dst);
+    break;
+  case 0x02:  // 02 -  Waterfall Face Longer
+    RoomDraw_WaterHoldingObject(7, src, dst);
+    break;
+  case 0x03: case 0x0e:  // 03 -  Cane Ride Spawn [?]Block
+    dung_unk6++;
+    dst[0] = src[0];
+    break;
+  case 0x04: case 0x05: case 0x06: case 0x07:  // 04 -  Cane Ride Node [4-way]
+  case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0f:
+    dst[0] = src[0];
+    break;
+  case 0x0d: case 0x17: { // 0D -  Prison Cell
+    src = SrcPtr(0x1488);
+    dsto |= (dung_line_ptrs_row0 != 0x4000 ? 0 : 0x1000);
+    uint16 *d = &dung_bg2[dsto], *dd = d;
+    for (int i = 0; i < 5; i++, d++) {
+      d[XY(2, 0)] = d[XY(9, 0)] = src[1];
+      d[XY(2, 1)] = src[2];
+      d[XY(9, 1)] = src[2] | 0x4000;
+      d[XY(2, 2)] = src[4];
+      d[XY(9, 2)] = src[4] | 0x4000;
+      d[XY(2, 3)] = src[5];
+      d[XY(9, 3)] = src[5] | 0x4000;
+    }
+    dd[XY(0, 0)] = src[0];
+    dd[XY(15, 0)] = src[0] | 0x4000;
+    dd[XY(1, 0)] = dd[XY(7, 0)] = dd[XY(8, 0)] = dd[XY(14, 0)] = src[1];
+    dd[XY(1, 2)] = src[3];
+    dd[XY(14, 2)] = src[3] | 0x4000;
+    break;
+  }
+  case 0x10: case 0x11: case 0x13: case 0x1a: case 0x22: case 0x23:
+  case 0x24: case 0x25:
+  case 0x3e: case 0x3f: case 0x40: case 0x41: case 0x42:
+  case 0x43: case 0x44: case 0x45: case 0x46: case 0x49: case 0x4a: case 0x4f:
+  case 0x50: case 0x51: case 0x52: case 0x53: case 0x56: case 0x57: case 0x58: case 0x59:
+  case 0x5e: case 0x5f: case 0x63: case 0x64: case 0x65:
+  case 0x75: case 0x7c: case 0x7d: case 0x7e:
+    RoomDraw_Rightwards2x2(src, dst);
+    break;
+
+  case 0x12:  // 12 -  Rupee Floor
+    if (dung_savegame_state_bits & 0x1000)
+      return;
+    src = SrcPtr(0x1dd6);
+    dst = &dung_bg2[dsto | (dung_line_ptrs_row0 != 0x4000 ? 0 : 0x1000)];
+    for (int i = 0; i < 3; i++) {
+      dst[XY(0, 0)] = dst[XY(0, 3)] = dst[XY(0, 6)] = src[0];
+      dst[XY(0, 1)] = dst[XY(0, 4)] = dst[XY(0, 7)] = src[1];
+      dst += 2;
+    }
+    break;
+  case 0x14: case 0x4E: // 14 -  Down Warp Door
+  case 0x67: case 0x68: case 0x6c: case 0x6d: case 0x79:
+    RoomDraw_1x3_rightwards(4, src, dst);
+    break;
+  case 0x15:  // 15 -  Kholdstare Shell - BG2
+    if (dung_savegame_state_bits & 0x8000)
+      return;
+    src = SrcPtr(0x1dfa);
+    RoomDraw_SomeBigDecors(10, src, dsto);
+    break;
+  case 0x16:   // 16 -  Single Hammer Peg
+    RoomDraw_HammerPegSingle(src, dst, dsto);
+    break;
+  case 0x18:  // 18 -  Cell Lock
+    i = dung_num_bigkey_locks_x2 >> 1;
+    dung_num_bigkey_locks_x2 += 2;
+    if (!(dung_savegame_state_bits & kChestOpenMasks[i])) {
+      dung_chest_locations[i] = dsto * 2;
+      RoomDraw_Rightwards2x2(SrcPtr(0x1494), dst);
+    } else {
+      dung_chest_locations[i] = 0;
+    }
+    break;
+  case 0x19: {  // 19 -  Chest
+    if (main_module_index == 26)
+      return;
+    i = dung_num_chests_x2 >> 1;
+    dung_num_bigkey_locks_x2 = (dung_num_chests_x2 += 2);
+
+    int h = -1;
+    if (dung_hdr_tag[0] == 0x27 || dung_hdr_tag[0] == 0x3c ||
+        dung_hdr_tag[0] == 0x3e || dung_hdr_tag[0] >= 0x29 && dung_hdr_tag[0] < 0x33)
+      h = 0;
+    else if (dung_hdr_tag[1] == 0x27 || dung_hdr_tag[1] == 0x3c ||
+             dung_hdr_tag[1] == 0x3e || dung_hdr_tag[1] >= 0x29 && dung_hdr_tag[1] < 0x33)
+      h = 1;
+
+    dung_chest_locations[i] = 2 * (dsto | (dung_line_ptrs_row0 != 0x4000 ? 0 : 0x1000));
+    if (!(dung_savegame_state_bits & kChestOpenMasks[i])) {
+      if (h >= 0) {
+        if (!(dung_savegame_state_bits & kChestOpenMasks[h]))
+          return;
+        dung_hdr_tag[h] = 0;
+      }
+      RoomDraw_Rightwards2x2(SrcPtr(0x149c), dst);
+    } else {
+      dung_chest_locations[i] = 0;
+      if (h >= 0)
+        dung_hdr_tag[h] = 0;
+      RoomDraw_Rightwards2x2(SrcPtr(0x14a4), dst);
+    }
+    break;
+  }
+  case 0x1b:  // 1B -  Stair
+    dung_stairs_table_1[dung_num_stairs_1 >> 1] = dsto;
+    dung_num_stairs_1 += 2;
+stair1b:
+    for (int i = 0; i < 4; i++) {
+      dung_bg1[dsto + XY(0, 0)] = dung_bg2[dsto + XY(0, 0)] = src[0];
+      dung_bg1[dsto + XY(0, 1)] = dung_bg2[dsto + XY(0, 1)] = src[1];
+      dung_bg1[dsto + XY(0, 2)] = dung_bg2[dsto + XY(0, 2)] = src[2];
+      dung_bg1[dsto + XY(0, 3)] = dung_bg2[dsto + XY(0, 3)] = src[3];
+      src += 4, dsto += 1;
+    }
+    break;
+  case 0x1c:  // 1C -  Stair [S](Layer)
+    dung_stairs_table_2[dung_num_stairs_2 >> 1] = dsto;
+    dung_num_stairs_2 += 2;
+    goto stair1b;
+  case 0x1d:  //  1D -  Stair Wet [S](Layer)
+stairs_wet:
+    dung_stairs_table_2[dung_num_stairs_wet >> 1] = dsto;
+    dung_num_stairs_wet += 2;
+    RoomDraw_4x4(src, dst);
+    break;
+  case 0x1e:  // 1E -  Staircase going Up(Up)
+    dung_inter_starcases[dung_num_inter_room_upnorth_straight_stairs >> 1] = dsto;
+    dung_num_inter_room_upnorth_straight_stairs =
+      dung_num_inter_room_upsouth_straight_stairs =
+      dung_num_inter_room_southdown_stairs =
+      dung_num_wall_downnorth_spiral_stairs =
+      dung_num_wall_downnorth_spiral_stairs_2 =
+      dung_num_inter_room_downnorth_straight_stairs =
+      dung_num_inter_room_downsouth_straight_stairs = dung_num_inter_room_upnorth_straight_stairs + 2;
+    RoomDraw_Object_Nx4(4, src, dst);
+    break;
+  case 0x1f: // 1F -  Staircase Going Down (Up)
+    dung_inter_starcases[dung_num_inter_room_downnorth_straight_stairs >> 1] = dsto;
+    dung_num_inter_room_downnorth_straight_stairs =
+      dung_num_inter_room_downsouth_straight_stairs = dung_num_inter_room_downnorth_straight_stairs + 2;
+    RoomDraw_Object_Nx4(4, src, dst);
+    break;
+  case 0x20:  // 20 -  Staircase Going Up (Down)
+    dung_inter_starcases[dung_num_inter_room_upsouth_straight_stairs >> 1] = dsto;
+    dung_num_inter_room_upsouth_straight_stairs =
+      dung_num_inter_room_southdown_stairs =
+      dung_num_wall_downnorth_spiral_stairs =
+      dung_num_wall_downnorth_spiral_stairs_2 =
+      dung_num_inter_room_downnorth_straight_stairs =
+      dung_num_inter_room_downsouth_straight_stairs = dung_num_inter_room_upsouth_straight_stairs + 2;
+    RoomDraw_Object_Nx4(4, src, dst);
+    break;
+  case 0x21:  // 21 -  Staircase Going Down (Down)
+    dung_inter_starcases[dung_num_inter_room_downsouth_straight_stairs >> 1] = dsto;
+    dung_num_inter_room_downsouth_straight_stairs = dung_num_inter_room_downsouth_straight_stairs + 2;
+    RoomDraw_Object_Nx4(4, src, dst);
+    break;
+  case 0x26:  // 26 -  Staircase Going Up (Lower)
+    i = dung_num_inter_room_upnorth_straight_stairs >> 1;
+    dung_inter_starcases[i] = dsto | (dung_line_ptrs_row0 != 0x4000 ? 0 : 0x1000);
+    dung_num_inter_room_upnorth_straight_stairs =
+      dung_num_inter_room_upsouth_straight_stairs =
+      dung_num_inter_room_southdown_stairs =
+      dung_num_wall_downnorth_spiral_stairs =
+      dung_num_wall_downnorth_spiral_stairs_2 =
+      dung_num_inter_room_downnorth_straight_stairs =
+      dung_num_inter_room_downsouth_straight_stairs = dung_num_inter_room_upnorth_straight_stairs + 2;
+door26:
+    for (int i = 0; i < 4; i++) {
+      dung_bg1[dsto] = dung_bg2[dsto] = src[0];
+      dung_bg1[dsto + XY(0, 1)] = src[1];
+      dung_bg1[dsto + XY(0, 2)] = src[2];
+      dung_bg1[dsto + XY(0, 3)] = src[3];
+      src += 4, dsto++;
+    }
+    dsto += XY(-4, -4);
+copy_door_bg2:
+    dung_bg2[dsto + XY(0, 0)] |= 0x2000;
+    dung_bg2[dsto + XY(0, 1)] |= 0x2000;
+    dung_bg2[dsto + XY(0, 2)] |= 0x2000;
+    dung_bg2[dsto + XY(0, 3)] |= 0x2000;
+    break;
+  case 0x27:  // 27 -  Staircase Going Up (Lower)
+    i = dung_num_inter_room_downnorth_straight_stairs >> 1;
+    dung_inter_starcases[i] = dsto | (dung_line_ptrs_row0 != 0x4000 ? 0 : 0x1000);
+    dung_num_inter_room_downnorth_straight_stairs =
+      dung_num_inter_room_downsouth_straight_stairs =
+      dung_num_inter_room_downnorth_straight_stairs + 2;
+    goto door26;
+  case 0x28:  // 28 -  Staircase Going Down (Lower)
+    i = dung_num_inter_room_upsouth_straight_stairs >> 1;
+    dung_inter_starcases[i] = dsto | (dung_line_ptrs_row0 != 0x4000 ? 0 : 0x1000);
+    dung_num_inter_room_upsouth_straight_stairs =
+      dung_num_inter_room_southdown_stairs =
+      dung_num_wall_downnorth_spiral_stairs =
+      dung_num_wall_downnorth_spiral_stairs_2 =
+      dung_num_inter_room_downnorth_straight_stairs =
+      dung_num_inter_room_downsouth_straight_stairs =
+      dung_num_inter_room_upsouth_straight_stairs + 2;
+door28:
+    for (int i = 0; i < 4; i++) {
+      dung_bg1[dsto + XY(0, 0)] = src[0];
+      dung_bg1[dsto + XY(0, 1)] = src[1];
+      dung_bg1[dsto + XY(0, 2)] = src[2];
+      dung_bg1[dsto + XY(0, 3)] = dung_bg2[dsto + XY(0, 3)] = src[3];
+      src += 4, dsto++;
+    }
+    dsto += XY(-4, 4);
+    goto copy_door_bg2;
+  case 0x29:  // 29 -  Staircase Going Down (Lower)
+    i = dung_num_inter_room_downsouth_straight_stairs >> 1;
+    dung_inter_starcases[i] = dsto | (dung_line_ptrs_row0 != 0x4000 ? 0 : 0x1000);
+    dung_num_inter_room_downsouth_straight_stairs =
+      dung_num_inter_room_downsouth_straight_stairs + 2;
+    goto door28;
+  case 0x2a:  // 2A -  Dark Room BG2 Mask
+    RoomDraw_SingleLampCone(0x514, 0x16dc);
+    RoomDraw_SingleLampCone(0x554, 0x17f6);
+    RoomDraw_SingleLampCone(0x1514, 0x1914);
+    RoomDraw_SingleLampCone(0x1554, 0x1a2a);
+    break;
+  case 0x2b:  // 2B -  Staircase Going Down (Lower) not really
+    DrawBigGraySegment(0x1010, src, dst, dsto);
+    break;
+  case 0x2c: // 2C -  Large Pick Up Block
+    DrawBigGraySegment(0x2020, SrcPtr(0xe62), dst, dsto);
+    DrawBigGraySegment(0x2121, SrcPtr(0xe6a), dst + XY(2, 0), dsto + XY(2, 0));
+    DrawBigGraySegment(0x2222, SrcPtr(0xe72), dst + XY(0, 2), dsto + XY(0, 2));
+    DrawBigGraySegment(0x2323, SrcPtr(0xe7a), dst + XY(2, 2), dsto + XY(2, 2));
+    break;
+  case 0x2d: { // 2D -  Agahnim Altar
+    src = SrcPtr(0x1b4a);
+    uint16 *d = &dung_bg2[dsto];
+    for (int j = 0; j < 14; j++) {
+      i = src[0], d[0] = i, d[13] = i | 0x4000;
+      i = src[14], d[1] = d[2] = i, d[11] = d[12] = i ^ 0x4000;
+      i = src[28], d[3] = i, d[10] = i ^ 0x4000;
+      i = src[42], d[4] = i, d[9] = i ^ 0x4000;
+      i = src[56], d[5] = i, d[8] = i ^ 0x4000;
+      i = src[70], d[6] = i, d[7] = i ^ 0x4000;
+      src++, d += 64;
+    }
+    break;
+  }
+  case 0x2e:  // 2E -  Agahnim Room
+    RoomDraw_AgahnimsWindows(dsto);
+    break;
+  case 0x2f:  // 2F -  Pot
+    RoomDraw_SinglePot(src, dst, dsto);
+    break;
+  case 0x30: // 30 -  ??
+    DrawBigGraySegment(0x1212, src, dst, dsto);
+    break;
+  case 0x31: // 31 -  Big Chest
+    i = dung_num_chests_x2;
+    dung_chest_locations[i >> 1] = dsto * 2 | 0x8000 | (dung_line_ptrs_row0 != 0x4000 ? 0 : 0x2000);
+    if (dung_savegame_state_bits & kChestOpenMasks[i >> 1]) {
+      dung_chest_locations[i >> 1] = 0;
+      dung_num_chests_x2 = dung_num_bigkey_locks_x2 = i + 2;
+      RoomDraw_1x3_rightwards(4, SrcPtr(0x14c4), dst);
+    } else {
+      dung_num_chests_x2 = dung_num_bigkey_locks_x2 = i + 2;
+      RoomDraw_1x3_rightwards(4, SrcPtr(0x14ac), dst);
+    }
+    break;
+  case 0x32:  // 32 -  Big Chest Open
+    RoomDraw_1x3_rightwards(4, src, dst);
+    break;
+  case 0x33:  // 33 -  Stairs Submerged [S](layer)
+    if (dung_hdr_tag[1] == 27) {
+      if (!(save_dung_info[dungeon_room_index] & 0x100)) {
+        dung_hdr_bg2_properties = 0;
+        goto stairs_wet;
+      }
+      CGWSEL_copy = 2;
+      CGADSUB_copy = 0x62;
+    }
+    dung_stairs_table_2[dung_num_inroom_upsouth_stairs_water >> 1] = dsto;
+    dung_num_inroom_upsouth_stairs_water += 2;
+    RoomDraw_4x4(src, dst);
+    break;
+  case 0x34: case 0x35: case 0x36: case 0x37: case 0x38: case 0x39:
+    assert(0);
+    break;
+  case 0x3a: case 0x3b: // 3A -  Pipe Ride Mouth [S]
+    RoomDraw_1x3_rightwards(4, src, dst);
+    RoomDraw_1x3_rightwards(4, src + 12, dst + XY(0, 3));
+    break;
+  case 0x3c: case 0x3d: case 0x5c:  // 3C -  Pipe Ride Mouth [E]
+    RoomDraw_Object_Nx4(6, src, dst);
+    break;
+  case 0x47:  // 47 -  Bomb Floor
+    RoomDraw_BombableFloor(src, dst, dsto);
+    break;
+  case 0x48: case 0x66: case 0x6b: case 0x7a:  // 48 -  Fake Bomb Floor
+    RoomDraw_4x4(src, dst);
+    break;
+  case 0x4b: case 0x76: case 0x77:
+    RoomDraw_1x3_rightwards(8, src, dst);
+    break;
+  case 0x4c:
+    RoomDraw_SomeBigDecors(6, SrcPtr(0x1f92), dsto);
+    break;
+  case 0x4d: case 0x5d:  // 5D -  Forge
+    RoomDraw_1x3_rightwards(6, src, dst);
+    break;
+  case 0x54:
+    RoomDraw_FortuneTellerRoom(dsto);
+    break;
+  case 0x55:
+  case 0x5b:  // 5B -  Water Troof
+    dst[XY(0, 0)] = src[0];
+    dst[XY(1, 0)] = src[1];
+    dst[XY(2, 0)] = src[2];
+    for (int i = 0; i < 3; i++) {
+      dst[XY(0, 1)] = src[3];
+      dst[XY(1, 1)] = src[4];
+      dst[XY(2, 1)] = src[5];
+      dst += XY(0, 1);
+    }
+    dst[XY(0, 1)] = src[6];
+    dst[XY(1, 1)] = src[7];
+    dst[XY(2, 1)] = src[8];
+    break;
+
+  case 0x5a:  // 5A -  Plate on Table
+    RoomDraw_WaterHoldingObject(2, src, dst);
+    break;
+
+  case 0x60: case 0x61: // 60 -  Left/Right Warp Door
+    RoomDraw_1x3_rightwards(3, src, dst);
+    RoomDraw_1x3_rightwards(3, src + 9, dst + XY(0, 3));
+    break;
+
+  case 0x62: {  // 62 ??
+    src = SrcPtr(0x20f6);
+    uint16 *d = &dung_bg1[dsto];
+    for (int i = 0; i < 22; i++) {
+      d[XY(0, 0)] = src[0];
+      d[XY(0, 1)] = src[1];
+      d[XY(0, 2)] = src[2];
+      d[XY(0, 3)] = src[3];
+      d[XY(0, 4)] = src[4];
+      d[XY(0, 5)] = src[5];
+      d[XY(0, 6)] = src[6];
+      d[XY(0, 7)] = src[7];
+      d[XY(0, 8)] = src[8];
+      d[XY(0, 9)] = src[9];
+      d[XY(0, 10)] = src[10];
+      d += XY(1, 0), src += 11;
+    }
+    d -= XY(1, 0) * 22;
+    src = SrcPtr(0x22da);
+    for (int i = 0; i < 3; i++) {
+      d[XY(9, 11)] = src[0];
+      d[XY(9, 12)] = src[3];
+      d += XY(1, 0), src += 1;
+    }
+    break;
+  }
+  case 0x69: case 0x6a: case 0x6e: case 0x6f:  // 69 -  Left Crack Wall
+    RoomDraw_Object_Nx4(3, src, dst);
+    break;
+
+  case 0x70:  // 70 -  Window Light
+    RoomDraw_4x4(src, dst + XY(0, 0));
+    RoomDraw_4x4(SrcPtr(0x2376), dst + XY(0, 2));
+    RoomDraw_4x4(SrcPtr(0x2396), dst + XY(0, 6));
+    break;
+
+  case 0x71:  // 71 -  Floor Light Blind BG2
+    if (!(save_dung_info[101] & 0x100))
+      return;
+    Object_Draw8x8(src, dst);
+    break;
+  case 0x72:  // 72 -  TrinexxShell  Boss Goo/Shell BG2
+    if (dung_savegame_state_bits & 0x8000)
+      return;
+    RoomDraw_SomeBigDecors(10, src, dsto);
+    break;
+  case 0x73:  // 73 -  Entire floor is pit, Bg2 Full Mask
+    RoomDraw_FloorChunks(SrcPtr(0xe0));
+    break;
+  case 0x74:  // 74 -  Boss Entrance
+    Object_Draw8x8(src, dst);
+    break;
+
+  case 0x78:  // Triforce
+    RoomDraw_4x4(src, dst);
+    RoomDraw_4x4(src + 16, dst + XY(-2, 4));
+    RoomDraw_4x4(src + 16, dst + XY(2, 4));
+    break;
+  case 0x7b: // 7B -  Vitreous Boss?
+    RoomDraw_A_Many32x32Blocks(5, src, dst);
+    RoomDraw_A_Many32x32Blocks(5, src, dst + XY(0, 4));
+    break;
+  default:
+    assert(0);
+  }
+}
+
+void RoomBounds_AddA(RoomBounds *r) {
+  r->a0 += 0x100;
+  r->a1 += 0x100;
+}
+
+void RoomBounds_AddB(RoomBounds *r) {
+  r->b0 += 0x200;
+  r->b1 += 0x200;
+}
+
+void RoomBounds_SubB(RoomBounds *r) {
+  r->b0 -= 0x200;
+  r->b1 -= 0x200;
+}
+
+void RoomBounds_SubA(RoomBounds *r) {
+  r->a0 -= 0x100;
+  r->a1 -= 0x100;
+}
+
+void Dungeon_StartInterRoomTrans_Left() {
+  assert(submodule_index == 0);
+  link_quadrant_x ^= 1;
+  Dungeon_AdjustQuadrant();
+  RoomBounds_SubA(&room_bounds_x);
+  Dung_SaveDataForCurrentRoom();
+  DungeonTransition_AdjustCamera_X(link_quadrant_x ^ 1);
+  HandleEdgeTransition_AdjustCameraBoundaries(3);
+  submodule_index = 1;
+  if (link_quadrant_x) {
+    RoomBounds_SubB(&room_bounds_x);
+    BYTE(dungeon_room_index_prev) = dungeon_room_index;
+    if ((link_tile_below & 0xcf) == 0x89) {
+      dungeon_room_index = dung_hdr_travel_destinations[3];
+      Dungeon_AdjustForTeleportDoors(dungeon_room_index + 1, 0xff);
+    } else {
+      if ((uint8)dungeon_room_index != (uint8)dungeon_room_index2) {
+        BYTE(dungeon_room_index_prev) = dungeon_room_index2;
+        Dungeon_AdjustAfterSpiralStairs();
+      }
+      dungeon_room_index--;
+    }
+    submodule_index = 2;
+    if (room_transitioning_flags & 1) {
+      link_is_on_lower_level ^= 1;
+      link_is_on_lower_level_mirror = link_is_on_lower_level;
+    }
+    if (room_transitioning_flags & 2) {
+      cur_palace_index_x2 ^= 2;
+    }
+  }
+  room_transitioning_flags = 0;
+  quadrant_fullsize_y = (dung_blastwall_flag_y || (kLayoutQuadrantFlags[composite_of_layout_and_quadrant] & (link_quadrant_y ? 8 : 4)) == 0) ? 2 : 0;
+}
+
+void Dung_StartInterRoomTrans_Left_Plus() {
+  link_x_coord -= 8;
+  Dungeon_StartInterRoomTrans_Left();
+}
+
+void Dungeon_StartInterRoomTrans_Up() {
+  assert(submodule_index == 0);
+  link_quadrant_y ^= 2;
+  Dungeon_AdjustQuadrant();
+  RoomBounds_SubA(&room_bounds_y);
+  Dung_SaveDataForCurrentRoom();
+  DungeonTransition_AdjustCamera_Y(link_quadrant_y ^ 2);
+  HandleEdgeTransition_AdjustCameraBoundaries(1);
+  submodule_index = 1;
+  if (link_quadrant_y) {
+    RoomBounds_SubB(&room_bounds_y);
+    BYTE(dungeon_room_index_prev) = dungeon_room_index;
+    if (link_tile_below == 0x8e) {
+      Dung_HandleExitToOverworld();
+      return;
+    }
+
+    if (dungeon_room_index == 0) {
+      SaveDungeonKeys();
+      main_module_index = 25;
+      submodule_index = 0;
+      subsubmodule_index = 0;
+      return;
+    }
+
+    if (BYTE(dungeon_room_index2) == BYTE(dungeon_room_index)) {
+      BYTE(dungeon_room_index_prev) = BYTE(dungeon_room_index2);
+      Dungeon_AdjustAfterSpiralStairs();
+    }
+    BYTE(dungeon_room_index) -= 0x10;
+    submodule_index = 2;
+    if (room_transitioning_flags & 1) {
+      link_is_on_lower_level ^= 1;
+      link_is_on_lower_level_mirror = link_is_on_lower_level;
+    }
+    if (room_transitioning_flags & 2) {
+      cur_palace_index_x2 ^= 2;
+    }
+  }
+  room_transitioning_flags = 0;
+  quadrant_fullsize_x = (dung_blastwall_flag_x || (kLayoutQuadrantFlags[composite_of_layout_and_quadrant] & (link_quadrant_x ? 2 : 1)) == 0) ? 2 : 0;
+}
+
+void Dungeon_StartInterRoomTrans_Down() {
+  assert(submodule_index == 0);
+  link_quadrant_y ^= 2;
+  Dungeon_AdjustQuadrant();
+  RoomBounds_AddA(&room_bounds_y);
+  Dung_SaveDataForCurrentRoom();
+  DungeonTransition_AdjustCamera_Y(link_quadrant_y);
+  HandleEdgeTransition_AdjustCameraBoundaries(0);
+  submodule_index = 1;
+  if (!link_quadrant_y) {
+    RoomBounds_AddB(&room_bounds_y);
+    BYTE(dungeon_room_index_prev) = dungeon_room_index;
+    if (link_tile_below == 0x8e) {
+      Dung_HandleExitToOverworld();
+      return;
+    }
+
+    if ((uint8)dungeon_room_index != (uint8)dungeon_room_index2) {
+      BYTE(dungeon_room_index_prev) = dungeon_room_index2;
+      Dungeon_AdjustAfterSpiralStairs();
+    }
+    BYTE(dungeon_room_index) += 16;
+    submodule_index = 2;
+    if (room_transitioning_flags & 1) {
+      link_is_on_lower_level ^= 1;
+      link_is_on_lower_level_mirror = link_is_on_lower_level;
+    }
+    if (room_transitioning_flags & 2) {
+      cur_palace_index_x2 ^= 2;
+    }
+  }
+  room_transitioning_flags = 0;
+  quadrant_fullsize_x = (dung_blastwall_flag_x || (kLayoutQuadrantFlags[composite_of_layout_and_quadrant] & (link_quadrant_x ? 2 : 1)) == 0) ? 2 : 0;
+}
+
+void Dungeon_Store2x2(uint16 pos, uint16 t0, uint16 t1, uint16 t2, uint16 t3, uint8 attr) {
+  uint16 *dst = &vram_upload_data[vram_upload_offset >> 1];
+  dst[2] = t0;
+  dst[5] = t1;
+  dst[8] = t2;
+  dst[11] = t3;
+  overworld_tileattr[pos] = t0;
+  overworld_tileattr[pos + 64] = t1;
+  overworld_tileattr[pos + 1] = t2;
+  overworld_tileattr[pos + 65] = t3;
+
+  dung_bg2_attr_table[pos] = attr;
+  dung_bg2_attr_table[pos + 64] = attr;
+  dung_bg2_attr_table[pos + 1] = attr;
+  dung_bg2_attr_table[pos + 65] = attr;
+
+  dst[0] = Dungeon_MapVramAddr(pos + 0);
+  dst[3] = Dungeon_MapVramAddr(pos + 64);
+  dst[6] = Dungeon_MapVramAddr(pos + 1);
+  dst[9] = Dungeon_MapVramAddr(pos + 65);
+
+  dst[1] = 0x100;
+  dst[4] = 0x100;
+  dst[7] = 0x100;
+  dst[10] = 0x100;
+
+  dst[12] = 0xffff;
+
+  vram_upload_offset += 24;
+  nmi_load_bg_from_vram = 1;
+}
+
+uint16 Dungeon_MapVramAddr(uint16 pos) {
+  pos *= 2;
+  return swap16(((pos & 0x40) << 4) | ((pos & 0x303f) >> 1) | ((pos & 0xf80) >> 2));
+}
+
+uint16 Dungeon_MapVramAddrNoSwap(uint16 pos) {
+  pos *= 2;
+  return ((pos & 0x40) << 4) | ((pos & 0x303f) >> 1) | ((pos & 0xf80) >> 2);
+}
+
+void Door_Up_EntranceDoor(uint16 dsto) {
+  // NOTE: This don't pass the right value to RoomDraw_FlagDoorsAndGetFinalType
+  assert(0);
+}
+
+void Door_Down_EntranceDoor(uint16 dsto) {
+  // NOTE: This don't pass the right value to RoomDraw_FlagDoorsAndGetFinalType
+  assert(0);
+}
+
+void Door_Left_EntranceDoor(uint16 dsto) {
+  // NOTE: This don't pass the right value to RoomDraw_FlagDoorsAndGetFinalType
+  assert(0);
+}
+
+void Door_Right_EntranceDoor(uint16 dsto) {
+  // NOTE: This don't pass the right value to RoomDraw_FlagDoorsAndGetFinalType
+  assert(0);
+}
+
+void Door_Draw_Helper4(uint8 door_type, uint16 dsto) {
+  int t = RoomDraw_FlagDoorsAndGetFinalType(1, door_type, dsto), new_type;
+  if (t & 0x100)
+    return;
+
+  if ((new_type = kDoorType_Regular, t == kDoorType_1E || t == kDoorType_36) ||
+      (new_type = kDoorType_ShuttersTwoWay, t == kDoorType_38)) {
+    int i = (dung_cur_door_idx >> 1) - 1;
+    door_type_and_slot[i] = (i << 8) | new_type;
+    t = new_type;
+  }
+
+  const uint16 *src = SrcPtr(kDoorTypeSrcData2[t >> 1]);
+  uint16 *dst = DstoPtr(dsto);
+  for (int i = 0; i < 4; i++) {
+    dst[XY(0, 1)] = src[0];
+    dst[XY(0, 2)] = src[1];
+    dst[XY(0, 3)] = src[2];
+    dst++, src += 3;
+  }
+}
+
+const uint16 *GetRoomDoorInfo(int room) {
+  return (uint16 *)(kDungeonRoom + kDungeonRoomDoorOffs[room]);
+}
+
+const uint8 *GetRoomHeaderPtr(int room) {
+  return kDungeonRoomHeaders + kDungeonRoomHeadersOffs[room];
+}
+
+const uint8 *GetDefaultRoomLayout(int i) {
+  return kDungeonRoomDefault + kDungeonRoomDefaultOffs[i];
+}
+
+const uint8 *GetDungeonRoomLayout(int i) {
+  return kDungeonRoom + kDungeonRoomOffs[i];
+}
+
+static inline void WriteAttr1(int j, uint16 attr) {
+  dung_bg1_attr_table[j + 0] = attr;
+  dung_bg1_attr_table[j + 1] = attr >> 8;
+}
+
+static inline void WriteAttr2(int j, uint16 attr) {
+  dung_bg2_attr_table[j + 0] = attr;
+  dung_bg2_attr_table[j + 1] = attr >> 8;
+}
+
+void Dung_TagRoutine_0x22_0x3B(int k, uint8 j) {
+  if (dung_savegame_state_bits & 0x100) {
+    dung_hdr_tag[k] = 0;
+    dung_overlay_to_load = j;
+    dung_load_ptr_offs = 0;
+    subsubmodule_index = 0;
+    sound_effect_2 = 0x1b;
+    submodule_index = 3;
+  }
+}
+
+void Sprite_HandlePushedBlocks_One(int i) {
+  Oam_AllocateFromRegionB(4);
+
+  int y = (uint8)pushedblocks_y_lo[i] | (uint8)pushedblocks_y_hi[i] << 8;
+  int x = (uint8)pushedblocks_x_lo[i] | (uint8)pushedblocks_x_hi[i] << 8;
+
+  y -= BG2VOFS_copy2 + 1;
+  x -= BG2HOFS_copy2;
+
+  if (pushedblocks_some_index < 3) {
+    uint8 *oam = &g_ram[oam_cur_ptr];
+    oam[0] = x;
+    oam[1] = y;
+    oam[2] = 12;
+    oam[3] = 0x20;
+    g_ram[oam_ext_cur_ptr] = 2;
+  }
+}
+
+void Object_Draw_DoorLeft_3x4(uint16 src, int door) {
+  const uint16 *s = SrcPtr(src);
+  uint16 *dst = &dung_bg2[dung_door_tilemap_address[door] >> 1];
+  for (int i = 0; i < 3; i++) {
+    dst[XY(0, 0)] = s[0];
+    dst[XY(0, 1)] = s[1];
+    dst[XY(0, 2)] = s[2];
+    dst[XY(0, 3)] = s[3];
+    dst += 1, s += 4;
+  }
+}
+
+void Object_Draw_DoorRight_3x4(uint16 src, int door) {
+  const uint16 *s = SrcPtr(src);
+  uint16 *dst = &dung_bg2[dung_door_tilemap_address[door] >> 1];
+  for (int i = 0; i < 3; i++) {
+    dst[XY(1, 0)] = s[0];
+    dst[XY(1, 1)] = s[1];
+    dst[XY(1, 2)] = s[2];
+    dst[XY(1, 3)] = s[3];
+    dst += 1, s += 4;
+  }
+}
+
+void Dungeon_OpeningLockedDoor_Combined(bool skip_anim) {
+  uint8 ctr = 2;
+  int m, k, dma_ptr;
+
+  if (skip_anim) {
+    door_animation_step_indicator = 16;
+    goto step12;
+  }
+
+  door_animation_step_indicator++;
+  if (door_animation_step_indicator != 4) {
+    if (door_animation_step_indicator != 12)
+      goto middle;
+step12:
+    m = kUpperBitmasks[dung_bg2_attr_table[dung_cur_door_pos] & 7];
+    dung_door_opened_incl_adjacent |= m;
+    dung_door_opened |= m;
+    ctr = 4;
+  }
+  door_open_closed_counter = ctr;
+
+  k = dung_bg2_attr_table[dung_cur_door_pos] & 0xf;
+  dma_ptr = DrawDoorOpening_Step1(k, 0);
+  Dungeon_PrepOverlayDma_nextPrep(dma_ptr, dung_door_tilemap_address[k]);
+  sound_effect_2 = 21;
+  nmi_copy_packets_flag = 1;
+
+middle:
+  if (door_animation_step_indicator == 16) {
+    Dungeon_LoadToggleDoorAttr_OtherEntry(dung_bg2_attr_table[dung_cur_door_pos] & 0xf);
+    if (dung_bg2_attr_table[dung_cur_door_pos] >= 0xf0) {
+      k = dung_bg2_attr_table[dung_cur_door_pos] & 0xf;
+      uint8 door_type = door_type_and_slot[k];
+      if (door_type >= kDoorType_StairMaskLocked0 && door_type <= kDoorType_StairMaskLocked3)
+        DrawCompletelyOpenDoor();
+    }
+    submodule_index = 0;
+  }
+}
+
+const DungPalInfo *GetDungPalInfo(int idx) {
+  return &kDungPalinfos[idx];
+}
+
+uint16 Dungeon_GetTeleMsg(int room) {
+  return kDungeonRoomTeleMsg[room];
+}
+
+bool Dungeon_IsPitThatHurtsPlayer() {
+  for (int i = kDungeonPitsHurtPlayer_SIZE / 2 - 1; i >= 0; i--) {
+    if (kDungeonPitsHurtPlayer[i] == dungeon_room_index)
+      return true;
+  }
+  return false;
+
+}
+
+void Dungeon_PrepareNextRoomQuadrantUpload() {  // 80913f
+  int ofs = (overworld_screen_transition & 0xf) + dung_cur_quadrant_upload;
+  uint16 *src = &dung_bg2[kUploadBgSrcs[ofs] / 2];
+  int p = 0;
+  do {
+    UploadVram_32x32 *d = (UploadVram_32x32 *)&g_ram[0x1000 + p * 2];
+    do {
+      d->row[0].col[0] = src[XY(0, 0)];
+      d->row[0].col[1] = src[XY(1, 0)];
+      d->row[1].col[0] = src[XY(0, 1)];
+      d->row[1].col[1] = src[XY(1, 1)];
+      d->row[2].col[0] = src[XY(0, 2)];
+      d->row[2].col[1] = src[XY(1, 2)];
+      d->row[3].col[0] = src[XY(0, 3)];
+      d->row[3].col[1] = src[XY(1, 3)];
+      d = (UploadVram_32x32 *)((uint16 *)d + 2);
+      src += 2, p += 2;
+    } while (p & 0x1f);
+    src += 224;
+    p += 128 - 32;
+  } while (p != 0x400);
+  dung_cur_quadrant_upload += 4;
+  BYTE(nmi_load_target_addr) = kUploadBgDsts[ofs];
+  nmi_subroutine_index = 1;
+  nmi_disable_core_updates = 1;
+}
+
+void WaterFlood_BuildOneQuadrantForVRAM() {  // 8091c4
+
+  // It never seems to be 25 here, so skip updating water stuff
+  assert(dung_hdr_tag[0] != 25);
+  TileMapPrep_NotWaterOnTag();
+}
+
+void TileMapPrep_NotWaterOnTag() {  // 8091d3
+  int ofs = (overworld_screen_transition & 0xf) + dung_cur_quadrant_upload;
+  uint16 *src = &dung_bg1[kUploadBgSrcs[ofs] / 2];
+  int p = 0;
+  do {
+    UploadVram_32x32 *d = (UploadVram_32x32 *)&g_ram[0x1000 + p * 2];
+    do {
+      d->row[0].col[0] = src[XY(0, 0)];
+      d->row[0].col[1] = src[XY(1, 0)];
+      d->row[1].col[0] = src[XY(0, 1)];
+      d->row[1].col[1] = src[XY(1, 1)];
+      d->row[2].col[0] = src[XY(0, 2)];
+      d->row[2].col[1] = src[XY(1, 2)];
+      d->row[3].col[0] = src[XY(0, 3)];
+      d->row[3].col[1] = src[XY(1, 3)];
+      d = (UploadVram_32x32 *)((uint16 *)d + 2);
+      src += 2, p += 2;
+    } while (p & 0x1f);
+    src += 224;
+    p += 128 - 32;
+  } while (p != 0x400);
+  BYTE(nmi_load_target_addr) = kUploadBgDsts[ofs] + 0x10;
+  nmi_subroutine_index = 1;
+  nmi_disable_core_updates = 1;
+}
+
+void OrientLampLightCone() {  // 80f567
+  static const uint16 kOrientLampBgTab0[] = { 0, 256, 0, 256 };
+  static const uint16 kOrientLampBgTab1[] = { 0, 0, 256, 256 };
+  static const int16 kOrientLampBgTab2[] = { 52, -2, 56, 6 };
+  static const int16 kOrientLampBgTab3[] = { 64, 64, 82, -176 };
+  static const int16 kOrientLampBgTab4[] = { 128, 384, 160, 160 };
+
+  if (!hdr_dungeon_dark_with_lantern || submodule_index == 20)
+    return;
+
+  uint8 a = link_direction_facing >> 1, idx = a;
+  if (is_standing_in_doorway) {
+    idx = (is_standing_in_doorway & 0xfe);
+    if (idx) {
+      if (a < 2)
+        idx += ((uint8)(link_x_coord + 8) >= 0x80);
+      else
+        idx = a;
+    } else {
+      if (a >= 2)
+        idx += ((uint8)link_y_coord >= 0x80);
+      else
+        idx = a;
+    }
+  }
+
+  if (idx < 2) {
+    BG1HOFS_copy2 = BG2HOFS_copy2 - (link_x_coord - 0x77) + kOrientLampBgTab0[idx];
+    uint16 t = BG2VOFS_copy2 - (link_y_coord - 0x58) + kOrientLampBgTab1[idx] + kOrientLampBgTab2[idx] + kOrientLampBgTab3[idx];
+    if ((int16)t < 0) t = 0;
+    if (t > kOrientLampBgTab4[idx]) t = kOrientLampBgTab4[idx];
+    BG1VOFS_copy2 = t - kOrientLampBgTab3[idx];
+  } else {
+    BG1VOFS_copy2 = BG2VOFS_copy2 - (link_y_coord - 0x72) + kOrientLampBgTab1[idx];
+    uint16 t = BG2HOFS_copy2 - (link_x_coord - 0x58) + kOrientLampBgTab0[idx] + kOrientLampBgTab2[idx] + kOrientLampBgTab3[idx];
+    if ((int16)t < 0) t = 0;
+    if (t > kOrientLampBgTab4[idx]) t = kOrientLampBgTab4[idx];
+    BG1HOFS_copy2 = t - kOrientLampBgTab3[idx];
+  }
+}
+
+void PrepareDungeonExitFromBossFight() {  // 80f945
+  SavePalaceDeaths();
+  SaveDungeonKeys();
+  dung_savegame_state_bits |= 0x8000;
+  Dungeon_FlagRoomData_Quadrants();
+
+  int j = FindInByteArray(kDungeonExit_From, BYTE(dungeon_room_index), countof(kDungeonExit_From));
+  assert(j >= 0);
+  BYTE(dungeon_room_index) = kDungeonExit_To[j];
+  if (BYTE(dungeon_room_index) == 0x20) {
+    sram_progress_indicator = 3;
+    save_ow_event_info[2] |= 0x20;
+    savegame_is_darkworld ^= 0x40;
+    Sprite_LoadGraphicsProperties_light_world_only();
+    Ancilla_TerminateSelectInteractives(0);
+    link_disable_sprite_damage = 0;
+    button_b_frames = 0;
+    button_mask_b_y = 0;
+    link_force_hold_sword_up = 0;
+    flag_is_link_immobilized = 1;
+    saved_module_for_menu = 8;
+    main_module_index = 21;
+    submodule_index = 0;
+    subsubmodule_index = 0;
+  } else if (BYTE(dungeon_room_index) == 0xd) {
+    main_module_index = 24;
+    submodule_index = 0;
+    overworld_map_state = 0;
+    CGADSUB_copy = 0x20;
+  } else {
+    if (j >= 3) {
+      music_control = 0xf1;
+      music_unk1 = 0xf1;
+      main_module_index = 22;
+    } else {
+      main_module_index = 19;
+    }
+    saved_module_for_menu = 8;
+    submodule_index = 0;
+    subsubmodule_index = 0;
+  }
+}
+
+void SavePalaceDeaths() {  // 80f9dd
+  int j = BYTE(cur_palace_index_x2);
+  deaths_per_palace[j >> 1] = death_save_counter;
+  if (j != 8)
+    death_save_counter = 0;
+}
+
+void Dungeon_LoadRoom() {  // 81873a
+  Dungeon_LoadHeader();
+  dung_unk6 = 0;
+
+  dung_hdr_collision_2_mirror = dung_hdr_collision_2;
+  dung_hdr_collision_2_mirror_PADDING = dung_hdr_tag[0];
+  dung_some_subpixel[0] = 0x30;
+  dung_some_subpixel[1] = 0xff;
+  dung_floor_move_flags = 0;
+  word_7E0420 = 0;
+  dung_floor_x_vel = dung_floor_y_vel = 0;
+  dung_floor_x_offs = dung_floor_y_offs = 0;
+  invisible_door_dir_and_index_x2 = 0xffff;
+  dung_blastwall_flag_x = dung_blastwall_flag_y = 0;
+  dung_unk_blast_walls_2 = dung_unk_blast_walls_3 = 0;
+  water_hdma_var5 = 0;
+  dung_num_toggle_floor = 0;
+  dung_num_toggle_palace = 0;
+  dung_unk2 = 0;
+  dung_cur_quadrant_upload = 0;
+  dung_num_inter_room_upnorth_stairs = 0;
+  dung_num_inter_room_southdown_stairs = 0;
+  dung_num_inroom_upnorth_stairs = 0;
+  dung_num_inroom_southdown_stairs = 0;
+  dung_num_interpseudo_upnorth_stairs = 0;
+  dung_num_inroom_upnorth_stairs_water = 0;
+  dung_num_activated_water_ladders = 0;
+  dung_num_water_ladders = 0;
+  dung_some_stairs_unk4 = 0;
+  dung_num_stairs_1 = 0;
+  dung_num_stairs_2 = 0;
+  dung_num_stairs_wet = 0;
+  dung_num_inroom_upsouth_stairs_water = 0;
+  dung_num_wall_upnorth_spiral_stairs = 0;
+  dung_num_wall_downnorth_spiral_stairs = 0;
+  dung_num_wall_upnorth_spiral_stairs_2 = 0;
+  dung_num_wall_downnorth_spiral_stairs_2 = 0;
+  dung_num_inter_room_upnorth_straight_stairs = 0;
+  dung_num_inter_room_upsouth_straight_stairs = 0;
+  dung_num_inter_room_downnorth_straight_stairs = 0;
+  dung_num_inter_room_downsouth_straight_stairs = 0;
+  dung_exit_door_addresses[0] = 0;
+  dung_exit_door_addresses[1] = 0;
+  dung_exit_door_addresses[2] = 0;
+  dung_exit_door_addresses[3] = 0;
+  dung_exit_door_count = 0;
+  dung_door_switch_triggered = 0;
+  dung_num_star_shaped_switches = 0;
+  dung_misc_objs_index = 0;
+  dung_index_of_torches = 0;
+  dung_num_chests_x2 = 0;
+  dung_num_bigkey_locks_x2 = 0;
+  dung_unk5 = 0;
+  dung_cur_door_idx = 0;
+
+  for (int i = 0; i < 16; i++) {
+    dung_door_tilemap_address[i] = 0;
+    door_type_and_slot[i] = 0;
+    dung_door_direction[i] = 0;
+    dung_torch_timers[i] = 0;
+    dung_replacement_tile_state[i] = 0;
+    dung_object_pos_in_objdata[i] = 0;
+    dung_object_tilemap_pos[i] = 0;
+  }
+
+  const uint8 *cur_p0 = GetDungeonRoomLayout(dungeon_room_index);
+  dung_load_ptr_offs = 0;
+  RoomDraw_DrawFloors(cur_p0);
+
+  uint16 old_offs = dung_load_ptr_offs;
+  dung_layout_and_starting_quadrant = cur_p0[dung_load_ptr_offs];
+
+  const uint8 *cur_p1 = GetDefaultRoomLayout(dung_layout_and_starting_quadrant >> 2);
+
+  dung_load_ptr_offs = 0;
+  RoomDraw_DrawAllObjects(cur_p1);
+
+  dung_load_ptr_offs = old_offs + 1;
+
+  RoomDraw_DrawAllObjects(cur_p0);  // Draw Layer 1 objects to BG2
+  dung_load_ptr_offs += 2;
+
+  memcpy(&dung_line_ptrs_row0, kDungeon_DrawObjectOffsets_BG2, 33);
+  RoomDraw_DrawAllObjects(cur_p0);  // Draw Layer 2 objects to BG2
+  dung_load_ptr_offs += 2;
+
+  memcpy(&dung_line_ptrs_row0, kDungeon_DrawObjectOffsets_BG1, 33);
+  RoomDraw_DrawAllObjects(cur_p0);  // Draw Layer 3 objects to BG2
+
+  for (dung_load_ptr_offs = 0; dung_load_ptr_offs != 0x18C; dung_load_ptr_offs += 4) {
+    MovableBlockData m = movable_block_datas[dung_load_ptr_offs >> 2];
+    if (m.room == dungeon_room_index)
+      DrawObjects_PushableBlock(m.tilemap, dung_load_ptr_offs);
+  }
+
+  uint16 t;
+
+  dung_index_of_torches = dung_index_of_torches_start = dung_misc_objs_index;
+  int i = 0;
+  do {
+    if (dung_torch_data[i >> 1] == dungeon_room_index) {
+      i += 2;
+
+      do {
+        t = dung_torch_data[i >> 1];
+        i += 2;
+        DrawObjects_LightableTorch(t, i - 2);
+      } while (dung_torch_data[i >> 1] != 0xffff);
+      break;
+    }
+    i += 2;
+    do {
+      t = dung_torch_data[i >> 1];
+      i += 2;
+    } while (t != 0xffff);
+  } while (i != 0x120);
+
+  dung_load_ptr_offs = 0x120;
+}
+
+void RoomDraw_DrawAllObjects(const uint8 *level_data) {  // 8188e4
+  for (;;) {
+    dung_draw_width_indicator = dung_draw_height_indicator = 0;
+    uint16 d = WORD(level_data[dung_load_ptr_offs]);
+    if (d == 0xffff)
+      return;
+    if (d == 0xfff0)
+      break;
+    RoomData_DrawObject(d, level_data);
+  }
+  for (;;) {
+    dung_load_ptr_offs += 2;
+    uint16 d = WORD(level_data[dung_load_ptr_offs]);
+    if (d == 0xffff)
+      return;
+    RoomData_DrawObject_Door(d);
+  }
+}
+
+void RoomData_DrawObject_Door(uint16 a) {  // 818916
+  uint8 door_type = a >> 8;
+  uint8 position = a >> 4 & 0xf;
+
+  switch (a & 3) {
+  case 0: RoomDraw_Door_North(door_type, position); break;
+  case 1: RoomDraw_Door_South(door_type, position); break;
+  case 2: RoomDraw_Door_West(door_type, position); break;
+  case 3: RoomDraw_Door_East(door_type, position); break;
+  }
+}
+
+void RoomData_DrawObject(uint16 r0, const uint8 *level_data) {  // 81893c
+  uint16 offs = dung_load_ptr_offs;
+  uint8 idx = level_data[offs + 2];
+  dung_load_ptr_offs = offs + 3;
+
+  if ((r0 & 0xfc) != 0xfc) {
+    dung_draw_width_indicator = (r0 & 3);
+    dung_draw_height_indicator = (r0 >> 8) & 3;
+    uint8 x = (uint8)r0 >> 2;
+    uint8 y = (r0 >> 10);
+    uint16 dst = y * 64 + x;
+    if (idx < 0xf8) {
+      LoadType1ObjectSubtype1(idx, DstoPtr(dst), dst);
+    } else {
+      idx = (idx & 7) << 4 | ((r0 >> 8) & 3) << 2 | (r0 & 3);
+      LoadType1ObjectSubtype3(idx, DstoPtr(dst), dst);
+    }
+  } else {
+    uint8 x = (r0 & 3) << 4 | (r0 >> 12) & 0xf;
+    uint8 y = ((r0 >> 8) & 0xf) << 2 | (idx >> 6);
+    uint16 dst = y * 64 + x;
+    LoadType1ObjectSubtype2(idx & 0x3f, DstoPtr(dst), dst);
+  }
+}
+
+void RoomDraw_DrawFloors(const uint8 *level_data) {  // 8189dc
+  memcpy(&dung_line_ptrs_row0, kDungeon_DrawObjectOffsets_BG2, 33);
+  uint8 ft = level_data[dung_load_ptr_offs++];
+  dung_floor_1_filler_tiles = ft & 0xf0;
+  RoomDraw_FloorChunks(SrcPtr(dung_floor_1_filler_tiles));
+  memcpy(&dung_line_ptrs_row0, kDungeon_DrawObjectOffsets_BG1, 33);
+  dung_floor_2_filler_tiles = (ft & 0xf) << 4;
+  RoomDraw_FloorChunks(SrcPtr(dung_floor_2_filler_tiles));
+}
+
+void RoomDraw_FloorChunks(const uint16 *src) {  // 818a1f
+  static const uint16 kDungeon_QuadrantOffsets[] = { 0x0, 0x40, 0x1000, 0x1040 };
+  for (int i = 0; i < 4; i++) {
+    uint16 *dst = DstoPtr(kDungeon_QuadrantOffsets[i] / 2);
+    for (int j = 0; j < 8; j++) {
+      RoomDraw_A_Many32x32Blocks(8, src, dst);
+      dst += XY(0, 4);
+    }
+  }
+}
+
+void RoomDraw_A_Many32x32Blocks(int n, const uint16 *src, uint16 *dst) {  // 818a44
+  do {
+    // draw 4x2 twice
+    for (int i = 0; i < 2; i++) {
+      dst[XY(0, 0)] = src[0];
+      dst[XY(1, 0)] = src[1];
+      dst[XY(2, 0)] = src[2];
+      dst[XY(3, 0)] = src[3];
+      dst[XY(0, 1)] = src[4];
+      dst[XY(1, 1)] = src[5];
+      dst[XY(2, 1)] = src[6];
+      dst[XY(3, 1)] = src[7];
+      dst += XY(0, 2);
+    }
+    dst += XY(4, -4);
+  } while (--n);
+}
+
+void RoomDraw_1x3_rightwards(int n, const uint16 *src, uint16 *dst) {  // 818d80
+  do {
+    dst[XY(0, 0)] = src[0];
+    dst[XY(0, 1)] = src[1];
+    dst[XY(0, 2)] = src[2];
+    dst++, src += 3;
+  } while (--n);
+}
+
+bool RoomDraw_CheckIfWallIsMoved() {  // 819298
+  dung_some_subpixel[0] = dung_some_subpixel[1] = 0;
+  dung_floor_move_flags = 0;
+  int i;
+  if ((i = 0, dung_hdr_tag[0] >= 0x1c && dung_hdr_tag[0] < 0x20) ||
+      (i = 1, dung_hdr_tag[1] >= 0x1c && dung_hdr_tag[1] < 0x20)) {
+    if (dung_savegame_state_bits & (0x1000 >> i)) {
+      dung_hdr_collision = 0;
+      dung_hdr_tag[i] = 0;
+      dung_hdr_bg2_properties = 0;
+      return false;
+    }
+  }
+  return true;
+}
+
+void MovingWall_FillReplacementBuffer(int dsto) {  // 8192d1
+  for (int i = 0; i < 64; i++)
+    moving_wall_arr1[i] = 0x1ec;
+  moving_wall_var1 = (dsto & 0x1f) | (dsto & 0x20 ? 0x400 : 0) | 0x1000;
+}
+
+void Object_Table_Helper(const uint16 *src, uint16 *dst) {  // 8193f7
+  int n = dung_draw_width_indicator;
+  dst[0] = src[0];
+  do {
+    dst[1] = src[1];
+    dst[2] = src[2];
+    dst += 2;
+  } while (--n);
+  dst[1] = src[3];
+}
+
+void DrawWaterThing(uint16 *dst, const uint16 *src) {  // 8195a0
+  for (int i = 3; i >= 0; i--) {
+    dst[0] = src[0];
+    dst[1] = src[1];
+    dst[2] = src[2];
+    dst[3] = src[3];
+    dst += XY(0, 1), src += 4;
+  }
+}
+
+void RoomDraw_4x4(const uint16 *src, uint16 *dst) {  // 8197ed
+  RoomDraw_Object_Nx4(4, src, dst);
+}
+
+void RoomDraw_Object_Nx4(int n, const uint16 *src, uint16 *dst) {  // 8197f0
+  do {
+    dst[XY(0, 0)] = src[0];
+    dst[XY(0, 1)] = src[1];
+    dst[XY(0, 2)] = src[2];
+    dst[XY(0, 3)] = src[3];
+    src += 4;
+    dst += XY(1, 0);
+  } while (--n);
+}
+
+void Object_DrawNx4_BothBgs(int n, const uint16 *src, int dsto) {  // 819819
+  do {
+    dung_bg1[dsto + XY(0, 0)] = dung_bg2[dsto + XY(0, 0)] = src[0];
+    dung_bg1[dsto + XY(0, 1)] = dung_bg2[dsto + XY(0, 1)] = src[1];
+    dung_bg1[dsto + XY(0, 2)] = dung_bg2[dsto + XY(0, 2)] = src[2];
+    dung_bg1[dsto + XY(0, 3)] = dung_bg2[dsto + XY(0, 3)] = src[3];
+    src += 4, dsto += 1;
+  } while (--n);
+}
+
+void RoomDraw_Rightwards2x2(const uint16 *src, uint16 *dst) {  // 819895
+  dst[XY(0, 0)] = src[0];
+  dst[XY(0, 1)] = src[1];
+  dst[XY(1, 0)] = src[2];
+  dst[XY(1, 1)] = src[3];
+}
+
+void Object_Draw_3x2(const uint16 *src, uint16 *dst) {  // 819d04
+  dst[XY(0, 0)] = src[0];
+  dst[XY(1, 0)] = src[1];
+  dst[XY(2, 0)] = src[2];
+  dst[XY(0, 1)] = src[3];
+  dst[XY(1, 1)] = src[4];
+  dst[XY(2, 1)] = src[5];
+}
+
+void RoomDraw_WaterHoldingObject(int n, const uint16 *src, uint16 *dst) {  // 819d6f
+  do {
+    dst[0] = src[0];
+    dst[1] = src[1];
+    dst[2] = src[2];
+    dst[3] = src[3];
+    src += 4;
+    dst += XY(0, 1);
+  } while (--n);
+}
+
+void RoomDraw_SomeBigDecors(int n, const uint16 *src, uint16 dsto) {  // 819da2
+  uint16 *dst = &dung_bg2[dsto | (dung_line_ptrs_row0 != 0x4000 ? 0 : 0x1000)];
+  for (int i = 0; i < 8; i++) {
+    for (int j = 0; j < n; j++)
+      dst[j] = src[j];
+    dst += 64, src += n;
+  }
+}
+
+void RoomDraw_SingleLampCone(uint16 a, uint16 y) {  // 819e06
+  const uint16 *src = SrcPtr(y);
+  uint16 *dst = &dung_bg1[a / 2];
+  for (int i = 0; i < 12; i++) {
+    for (int j = 0; j < 12; j++)
+      *dst++ = *src++;
+    dst += 64 - 12;
+  }
+}
+
+void RoomDraw_AgahnimsWindows(uint16 dsto) {  // 819ea3
+  const uint16 *src;
+
+  uint16 *d = &dung_bg2[dsto];
+  src = SrcPtr(0x1BF2);
+  for (int i = 0; i < 6; i++) {
+    d[XY(7, 4)] = d[XY(13, 4)] = d[XY(19, 4)] = src[0];
+    d[XY(7, 5)] = d[XY(13, 5)] = d[XY(19, 5)] = src[1];
+    d[XY(7, 6)] = d[XY(13, 6)] = d[XY(19, 6)] = src[2];
+    d[XY(7, 7)] = d[XY(13, 7)] = d[XY(19, 7)] = src[3];
+    src += 4, d += XY(1, 0);
+  }
+  d -= 6;
+
+  src = SrcPtr(0x1c22);
+  for (int i = 0; i < 5; i++) {
+    int j = src[0];
+    d[XY(2, 10)] = d[XY(3, 9)] = d[XY(4, 8)] = d[XY(5, 7)] = d[XY(6, 6)] = d[XY(7, 5)] = d[XY(8, 4)] = j;
+    d[XY(23, 4)] = d[XY(24, 5)] = d[XY(25, 6)] = d[XY(26, 7)] = d[XY(27, 8)] = d[XY(28, 9)] = d[XY(29, 10)] = j | 0x4000;
+    src++, d += XY(0, 1);
+  }
+  d -= XY(0, 1) * 5;
+
+  src = SrcPtr(0x1c2c);
+  for (int i = 0; i < 6; i++) {
+    int j = src[0];
+    d[XY(2, 11)] = d[XY(2, 17)] = d[XY(2, 23)] = j;
+    d[XY(29, 11)] = d[XY(29, 17)] = d[XY(29, 23)] = j | 0x4000;
+    j = src[1];
+    d[XY(3, 11)] = d[XY(3, 17)] = d[XY(3, 23)] = j;
+    d[XY(28, 11)] = d[XY(28, 17)] = d[XY(28, 23)] = j | 0x4000;
+    j = src[2];
+    d[XY(4, 11)] = d[XY(4, 17)] = d[XY(4, 23)] = j;
+    d[XY(27, 11)] = d[XY(27, 17)] = d[XY(27, 23)] = j | 0x4000;
+    j = src[3];
+    d[XY(5, 11)] = d[XY(5, 17)] = d[XY(5, 23)] = j;
+    d[XY(26, 11)] = d[XY(26, 17)] = d[XY(26, 23)] = j | 0x4000;
+    src += 4, d += XY(0, 1);
+  }
+  d -= XY(0, 1) * 6;
+
+  src = SrcPtr(0x1c5c);
+  for (int i = 0; i < 6; i++) {
+    d[XY(12, 9)] = d[XY(18, 9)] = src[0];
+    d[XY(12, 10)] = d[XY(18, 10)] = src[6];
+    src += 1, d += XY(1, 0);
+  }
+  d -= XY(1, 0) * 6;
+
+  src = SrcPtr(0x1c74);
+  for (int i = 0; i < 6; i++) {
+    d[XY(7, 14)] = d[XY(7, 20)] = src[0];
+    d[XY(8, 14)] = d[XY(8, 20)] = src[1];
+    src += 2, d += XY(0, 1);
+  }
+  d -= XY(0, 1) * 6;
+
+  src = SrcPtr(0x1c8c);
+  for (int i = 0; i < 5; i++) {
+    d[XY(7, 9)] = src[0];
+    d[XY(7, 10)] = src[1];
+    d[XY(7, 11)] = src[2];
+    d[XY(7, 12)] = src[3];
+    d[XY(7, 13)] = src[4];
+    src += 5, d += XY(1, 0);
+  }
+  d -= XY(1, 0) * 5;
+
+  for (int i = 0; i < 4; i++) {
+    d[XY(14, 28)] |= 0x2000;
+    d[XY(14, 29)] |= 0x2000;
+    d += XY(1, 0);
+  }
+}
+
+void RoomDraw_FortuneTellerRoom(uint16 dsto) {  // 81a095
+  const uint16 *src = SrcPtr(0x202e), *src_org = src;
+  uint16 *d = &dung_bg2[dsto];
+  int j;
+
+  for (int i = 0; i < 6; i++) {
+    d[XY(1, 0)] =
+      d[XY(2, 0)] =
+      d[XY(1, 1)] =
+      d[XY(2, 1)] = src[0];
+    d[XY(1, 2)] = (j = src[1]);
+    d[XY(2, 2)] = j | 0x4000;
+    d += XY(2, 0);
+  }
+  d -= XY(2, 0) * 6;
+
+  for (int i = 0; i < 3; i++) {
+    d[XY(0, 3)] = d[XY(2, 3)] = d[XY(10, 3)] = d[XY(12, 3)] = (j = src[2]);
+    d[XY(1, 3)] = d[XY(3, 3)] = d[XY(11, 3)] = d[XY(13, 3)] = j | 0x4000;
+    d[XY(4, 3)] = d[XY(6, 3)] = d[XY(8, 3)] = (j = src[5]);
+    d[XY(5, 3)] = d[XY(7, 3)] = d[XY(9, 3)] = j | 0x4000;
+    src++, d += XY(0, 1);
+  }
+  d -= XY(0, 1) * 3;
+
+  d[XY(0, 0)] = d[XY(0, 1)] = (j = src[5]);
+  d[XY(13, 0)] = d[XY(13, 1)] = j | 0x4000;
+  d[XY(0, 2)] = (j = src[6]);
+  d[XY(13, 2)] = j | 0x4000;
+
+  src = src_org;
+  for (int i = 0; i < 4; i++) {
+    d[XY(3, 10)] = (j = src[10]);
+    d[XY(10, 10)] = j ^ 0x4000;
+    d[XY(4, 10)] = (j = src[14]);
+    d[XY(9, 10)] = j ^ 0x4000;
+    d[XY(5, 10)] = (j = src[18]);
+    d[XY(8, 10)] = j ^ 0x4000;
+    d[XY(6, 10)] = (j = src[22]);
+    d[XY(7, 10)] = j ^ 0x4000;
+    src++, d += XY(0, 1);
+  }
+}
+
+void Object_Draw8x8(const uint16 *src, uint16 *dst) {  // 81a7dc
+  RoomDraw_4x4(src, dst + XY(0, 0));
+  RoomDraw_4x4(src + 16, dst + XY(4, 0));
+  RoomDraw_4x4(src + 32, dst + XY(0, 4));
+  RoomDraw_4x4(src + 48, dst + XY(4, 4));
+}
+
+void RoomDraw_Door_North(int type, int pos_enum) {  // 81a81c
+  uint16 dsto = kDoorPositionToTilemapOffs_Up[pos_enum] / 2;
+  if (type == kDoorType_LgExplosion)
+    RoomDraw_Door_ExplodingWall(pos_enum);
+  else if (type == kDoorType_PlayerBgChange)
+    RoomDraw_MarkLayerToggleDoor(dsto - 0xfe / 2);
+  else if (type == kDoorType_Slashable)
+    RoomDraw_NorthCurtainDoor(dsto);
+  else if (type == kDoorType_EntranceDoor)
+    Door_Up_EntranceDoor(dsto);
+  else if (type == kDoorType_ThroneRoom)
+    RoomDraw_MarkDungeonToggleDoor(dsto - 0xfe / 2);
+  else if (type == kDoorType_Regular2) {
+    RoomDraw_MakeDoorPartsHighPriority_Y(dsto & (0xF07F / 2));
+    RoomDraw_NormalRangedDoors_North(type, dsto, pos_enum);
+  } else if (type == kDoorType_ExitToOw) {
+    dung_exit_door_addresses[dung_exit_door_count >> 1] = dsto * 2;
+    dung_exit_door_count += 2;
+  } else if (type == kDoorType_WaterfallTunnel) {
+    RoomDraw_NormalRangedDoors_North(type, dsto, pos_enum);
+    Door_PrioritizeCurDoor();
+  } else if (type >= kDoorType_StairMaskLocked0 && type <= kDoorType_StairMaskLocked3) {
+    Door_Up_StairMaskLocked(type, dsto);
+  } else if (type >= kDoorType_RegularDoor33)
+    RoomDraw_HighRangeDoor_North(type, dsto, pos_enum);
+  else
+    RoomDraw_NormalRangedDoors_North(type, dsto, pos_enum);
+
+}
+
+void Door_Up_StairMaskLocked(uint8 door_type, uint16 dsto) {  // 81a892
+  int i = dung_cur_door_idx >> 1;
+  dung_door_direction[i] = 0;
+  dung_door_tilemap_address[i] = dsto * 2;
+  door_type_and_slot[i] = i << 8 | door_type;
+  if (dung_door_opened_incl_adjacent & kUpperBitmasks[i & 7]) {
+    dung_cur_door_idx += 2;
+    return;
+  }
+
+  if (door_type < kDoorType_StairMaskLocked2) {
+    RoomDraw_OneSidedShutters_North(door_type, dsto);
+    return;
+  }
+
+  uint8 t = RoomDraw_FlagDoorsAndGetFinalType(0, door_type, dsto);
+  const uint16 *src = SrcPtr(kDoorTypeSrcData[t >> 1]);
+  for (int i = 0; i < 4; i++) {
+    dung_bg1[dsto + XY(0, 0)] = src[0];
+    dung_bg1[dsto + XY(0, 1)] = src[1];
+    dung_bg1[dsto + XY(0, 2)] = src[2];
+    dsto++, src += 3;
+  }
+  Door_PrioritizeCurDoor();
+}
+
+void Door_PrioritizeCurDoor() {  // 81a8fa
+  dung_door_tilemap_address[(dung_cur_door_idx >> 1) - 1] |= 0x2000;
+}
+
+void RoomDraw_NormalRangedDoors_North(uint8 door_type, uint16 dsto, int pos_enum) {  // 81a90f
+  if (pos_enum >= 6) {
+    uint16 bak = dung_cur_door_idx;
+    dung_cur_door_idx |= 0x10;
+    RoomDraw_CheckIfLowerLayerDoors_Y(door_type, kDoorPositionToTilemapOffs_Down[pos_enum - 6] / 2);
+    dung_cur_door_idx = bak;
+  }
+  RoomDraw_OneSidedShutters_North(door_type, dsto);
+}
+
+void RoomDraw_OneSidedShutters_North(uint8 door_type, uint16 dsto) {  // 81a932
+  int t = RoomDraw_FlagDoorsAndGetFinalType(0, door_type, dsto);
+  if (t & 0x100)
+    return;
+  // Remap type
+  if (t == 54 || t == 56) {
+    int new_type = (t == 54) ? kDoorType_ShuttersTwoWay : kDoorType_Regular;
+    int i = (dung_cur_door_idx >> 1) - 1;
+    door_type_and_slot[i] = (i << 8) | new_type;
+    t = new_type;
+  }
+  const uint16 *src = SrcPtr(kDoorTypeSrcData[t >> 1]);
+  uint16 *dst = DstoPtr(dsto);
+  for (int i = 0; i < 4; i++) {
+    dst[XY(0, 0)] = src[0];
+    dst[XY(0, 1)] = src[1];
+    dst[XY(0, 2)] = src[2];
+    dst++, src += 3;
+  }
+}
+
+void RoomDraw_Door_South(int type, int pos_enum) {  // 81a984
+  uint16 dsto = kDoorPositionToTilemapOffs_Down[pos_enum] / 2;
+  if (type == kDoorType_PlayerBgChange)
+    RoomDraw_MarkLayerToggleDoor(dsto + XY(1, 4));
+  else if (type == kDoorType_EntranceDoor)
+    Door_Down_EntranceDoor(dsto);
+  else if (type == kDoorType_ThroneRoom)
+    RoomDraw_MarkDungeonToggleDoor(dsto + XY(1, 4));
+  else if (type == kDoorType_ExitToOw) {
+    dung_exit_door_addresses[dung_exit_door_count >> 1] = dsto * 2;
+    dung_exit_door_count += 2;
+  } else if (type >= kDoorType_RegularDoor33) {
+    RoomDraw_OneSidedLowerShutters_South(type, dsto);
+  } else if (type == kDoorType_EntranceLarge) {
+    RoomDraw_FlagDoorsAndGetFinalType(1, type, dsto);
+    RoomDraw_SomeBigDecors(10, SrcPtr(0x2656), dsto + XY(-3, -4));
+  } else if (type == kDoorType_EntranceLarge2) {
+    dsto |= 0x1000;
+    RoomDraw_FlagDoorsAndGetFinalType(1, type, dsto);
+    dsto += XY(-3, -4);
+    RoomDraw_SomeBigDecors(10, SrcPtr(0x2656), dsto);
+    dsto += -0x1000 + XY(0, 7);
+    for (int i = 0; i < 10; i++) {
+      dung_bg2[dsto] = dung_bg1[dsto] | 0x2000;
+      dsto += 1;
+    }
+  } else if (type == kDoorType_EntranceCave || type == kDoorType_EntranceCave2) {
+    if (type == kDoorType_EntranceCave2)
+      RoomDraw_MakeDoorPartsHighPriority_Y(dsto + XY(0, 4));
+    RoomDraw_FlagDoorsAndGetFinalType(1, type, dsto);
+    RoomDraw_4x4(SrcPtr(0x26f6), DstoPtr(dsto));
+  } else if (type == kDoorType_4) {
+    uint16 dsto_org = dsto;
+    dsto |= 0x1000;
+    RoomDraw_MakeDoorPartsHighPriority_Y(dsto + XY(0, 4));
+    RoomDraw_FlagDoorsAndGetFinalType(1, type, dsto);
+    RoomDraw_4x4(SrcPtr(0x26f6), DstoPtr(dsto));
+    for (int i = 0; i < 4; i++) {
+      dung_bg2[dsto_org + XY(0, 3)] = dung_bg1[dsto_org + XY(0, 3)] | 0x2000;
+      dsto_org += 1;
+    }
+  } else {
+    RoomDraw_CheckIfLowerLayerDoors_Y(type, dsto);
+  }
+}
+
+void RoomDraw_CheckIfLowerLayerDoors_Y(uint8 door_type, uint16 dsto) {  // 81aa66
+  if (door_type == kDoorType_Regular2) {
+    RoomDraw_MakeDoorPartsHighPriority_Y(dsto + XY(0, 4));
+    Door_Draw_Helper4(door_type, dsto);
+  } else if (door_type == kDoorType_WaterfallTunnel) {
+    Door_Draw_Helper4(door_type, dsto);
+    Door_PrioritizeCurDoor();
+  } else {
+    Door_Draw_Helper4(door_type, dsto);
+  }
+}
+
+void RoomDraw_Door_West(int type, int pos_enum) {  // 81aad7
+  uint16 dsto = kDoorPositionToTilemapOffs_Left[pos_enum] / 2;
+  if (type == kDoorType_PlayerBgChange)
+    RoomDraw_MarkLayerToggleDoor(dsto + XY(-2, 1));
+  else if (type == kDoorType_EntranceDoor)
+    Door_Left_EntranceDoor(dsto);
+  else if (type == kDoorType_ThroneRoom)
+    RoomDraw_MarkDungeonToggleDoor(dsto + XY(-2, 1));
+  else if (type == kDoorType_Regular2) {
+    RoomDraw_MakeDoorPartsHighPriority_X(dsto & ~0x1f);
+    RoomDraw_NormalRangedDoors_West(type, dsto, pos_enum);
+  } else if (type == kDoorType_WaterfallTunnel) {
+    RoomDraw_NormalRangedDoors_West(type, dsto, pos_enum);
+    Door_PrioritizeCurDoor();
+  } else if (type < kDoorType_RegularDoor33) {
+    RoomDraw_NormalRangedDoors_West(type, dsto, pos_enum);
+  } else {
+    RoomDraw_HighRangeDoor_West(type, dsto, pos_enum);
+  }
+}
+
+void RoomDraw_NormalRangedDoors_West(uint8 door_type, uint16 dsto, int pos_enum) {  // 81ab1f
+  if (pos_enum >= 6) {
+    uint16 bak = dung_cur_door_idx;
+    dung_cur_door_idx |= 0x10;
+    RoomDraw_NormalRangedDoors_East(door_type, kDoorPositionToTilemapOffs_Right[pos_enum - 6] / 2);
+    dung_cur_door_idx = bak;
+  }
+
+  int t = RoomDraw_FlagDoorsAndGetFinalType(2, door_type, dsto), new_type;
+  if (t & 0x100)
+    return;
+
+  if ((new_type = kDoorType_ShuttersTwoWay, t == kDoorType_36) ||
+      (new_type = kDoorType_Regular, t == kDoorType_38)) {
+    int i = (dung_cur_door_idx >> 1) - 1;
+    door_type_and_slot[i] = (i << 8) | new_type;
+    t = new_type;
+  }
+
+  const uint16 *src = SrcPtr(kDoorTypeSrcData3[t >> 1]);
+  uint16 *dst = DstoPtr(dsto);
+  for (int i = 0; i < 3; i++) {
+    dst[XY(0, 0)] = src[0];
+    dst[XY(0, 1)] = src[1];
+    dst[XY(0, 2)] = src[2];
+    dst[XY(0, 3)] = src[3];
+    dst++, src += 4;
+  }
+
+}
+
+void RoomDraw_Door_East(int type, int pos_enum) {  // 81ab99
+  uint16 dsto = kDoorPositionToTilemapOffs_Right[pos_enum] / 2;
+  if (type == kDoorType_PlayerBgChange)
+    RoomDraw_MarkLayerToggleDoor(dsto + XY(4, 1));
+  else if (type == kDoorType_EntranceDoor)
+    Door_Right_EntranceDoor(dsto);
+  else if (type == kDoorType_ThroneRoom)
+    RoomDraw_MarkDungeonToggleDoor(dsto + XY(4, 1));
+  else if (type < kDoorType_RegularDoor33) {
+    RoomDraw_NormalRangedDoors_East(type, dsto);
+  } else {
+    RoomDraw_OneSidedLowerShutters_East(type, dsto);
+  }
+}
+
+void RoomDraw_NormalRangedDoors_East(uint8 door_type, uint16 dsto) {  // 81abc8
+  if (door_type == kDoorType_Regular2)
+    RoomDraw_MakeDoorPartsHighPriority_X(dsto + XY(4, 0));
+  if (door_type == kDoorType_WaterfallTunnel) {
+    RoomDraw_OneSidedShutters_East(door_type, dsto);
+    Door_PrioritizeCurDoor();
+  } else {
+    RoomDraw_OneSidedShutters_East(door_type, dsto);
+  }
+}
+
+void RoomDraw_OneSidedShutters_East(uint8 door_type, uint16 dsto) {  // 81abe2
+  int t = RoomDraw_FlagDoorsAndGetFinalType(3, door_type, dsto), new_type;
+  if (t & 0x100)
+    return;
+  if ((new_type = kDoorType_Regular, t == kDoorType_36) ||
+      (new_type = kDoorType_ShuttersTwoWay, t == kDoorType_38)) {
+    int i = (dung_cur_door_idx >> 1) - 1;
+    door_type_and_slot[i] = (i << 8) | new_type;
+    t = new_type;
+  }
+  const uint16 *src = SrcPtr(kDoorTypeSrcData4[t >> 1]);
+  uint16 *dst = DstoPtr(dsto) + 1;
+  for (int i = 0; i < 3; i++) {
+    dst[XY(0, 0)] = src[0];
+    dst[XY(0, 1)] = src[1];
+    dst[XY(0, 2)] = src[2];
+    dst[XY(0, 3)] = src[3];
+    dst++, src += 4;
+  }
+}
+
+void RoomDraw_NorthCurtainDoor(uint16 dsto) {  // 81ac3b
+  int rv = RoomDraw_FlagDoorsAndGetFinalType(0, kDoorType_Slashable, dsto);
+  if (rv & 0x100) {
+    RoomDraw_4x4(SrcPtr(0x78a), DstoPtr(dsto));
+  } else {
+    RoomDraw_4x4(SrcPtr(kDoorTypeSrcData[rv >> 1]), DstoPtr(dsto));
+  }
+}
+
+void RoomDraw_Door_ExplodingWall(int pos_enum) {  // 81ac70
+  uint16 dsto = kDoor_BlastWallUp_Dsts[pos_enum] / 2;
+  int i = dung_cur_door_idx >> 1;
+  dung_door_tilemap_address[i] = 2 * (dsto + 10);
+  door_type_and_slot[i] = i << 8 | kDoorType_LgExplosion;
+  if (!(dung_door_opened_incl_adjacent & kUpperBitmasks[i & 7])) {
+    dung_door_direction[i] = 0;
+    dung_cur_door_idx += 2;
+    return;
+  }
+  int slot = dung_hdr_tag[0] != 0x20 && dung_hdr_tag[0] != 0x25 && dung_hdr_tag[0] != 0x28;
+  dung_hdr_tag[slot] = 0;
+  quadrant_fullsize_y = 2;
+  dung_blastwall_flag_y = 1;
+  RoomDraw_ExplodingWallSegment(SrcPtr(kDoorTypeSrcData2[42]), dsto);
+  dung_cur_door_idx += 2;
+  dung_unk2 |= 0x200;
+  RoomDraw_ExplodingWallSegment(SrcPtr(kDoorTypeSrcData[42]), dsto + XY(0, 6));
+}
+
+void RoomDraw_ExplodingWallSegment(const uint16 *src, uint16 dsto) {  // 81ace4
+  RoomDraw_ExplodingWallColumn(src, DstoPtr(dsto));
+  src += 12, dsto += 2;
+  int n = src[0];
+  uint16 *d = &dung_bg2[dsto];
+  dung_draw_width_indicator = 18;
+  do {
+    d[XY(0, 0)] = d[XY(0, 1)] = d[XY(0, 2)] = n;
+    d[XY(0, 3)] = d[XY(0, 4)] = d[XY(0, 5)] = n;
+    d++;
+  } while (--dung_draw_width_indicator);
+  RoomDraw_ExplodingWallColumn(src + 1, DstoPtr(dsto + 18));
+}
+
+void RoomDraw_ExplodingWallColumn(const uint16 *src, uint16 *dst) {  // 81ad25
+  for (int i = 0; i < 6; i++) {
+    dst[0] = src[0];
+    dst[1] = src[6];
+    dst += XY(0, 1), src += 1;
+  }
+}
+
+void RoomDraw_HighRangeDoor_North(uint8 door_type, uint16 dsto, int pos_enum) {  // 81ad41
+  if (pos_enum >= 6 && door_type != kDoorType_WarpRoomDoor) {
+    uint16 bak = dung_cur_door_idx;
+    dung_cur_door_idx |= 0x10;
+    RoomDraw_OneSidedLowerShutters_South(door_type, kDoorPositionToTilemapOffs_Down[pos_enum - 6] / 2);
+    dung_cur_door_idx = bak;
+  }
+  uint8 t = RoomDraw_FlagDoorsAndGetFinalType(0, door_type, dsto);
+  if (t == kDoorType_ShutterTrapUR || t == kDoorType_ShutterTrapDL) {
+    int new_type = (t == kDoorType_ShutterTrapUR) ? kDoorType_RegularDoor33 : kDoorType_Shutter;
+    int i = (dung_cur_door_idx >> 1) - 1;
+    door_type_and_slot[i] = (i << 8) | new_type;
+    t = new_type;
+  }
+  uint16 dsto_org = dsto;
+  const uint16 *src = SrcPtr(kDoorTypeSrcData[t >> 1]);
+  for (int i = 0; i < 4; i++) {
+    dung_bg2[dsto + XY(0, 0)] = src[0];
+    dung_bg1[dsto + XY(0, 1)] = src[1];
+    dung_bg1[dsto + XY(0, 2)] = src[2];
+    dsto++, src += 3;
+  }
+  if (door_type != kDoorType_WarpRoomDoor)
+    RoomDraw_MakeDoorHighPriority_North(dsto_org);
+  Door_PrioritizeCurDoor();
+}
+
+void RoomDraw_OneSidedLowerShutters_South(uint8 door_type, uint16 dsto) {  // 81add4
+  uint8 t = RoomDraw_FlagDoorsAndGetFinalType(1, door_type, dsto);
+  if (t == kDoorType_ShutterTrapUR || t == kDoorType_ShutterTrapDL) {
+    int new_type = (t == kDoorType_ShutterTrapUR) ? kDoorType_Shutter : kDoorType_RegularDoor33;
+    int i = (dung_cur_door_idx >> 1) - 1;
+    door_type_and_slot[i] = (i << 8) | new_type;
+    t = new_type;
+  }
+  uint16 dsto_org = dsto;
+  const uint16 *src = SrcPtr(kDoorTypeSrcData2[t >> 1]);
+  for (int i = 0; i < 4; i++) {
+    dung_bg1[dsto + XY(0, 1)] = src[0];
+    dung_bg1[dsto + XY(0, 2)] = src[1];
+    dung_bg2[dsto + XY(0, 3)] = src[2];
+    dsto++, src += 3;
+  }
+  RoomDraw_MakeDoorHighPriority_South(dsto_org + XY(0, 4));
+  Door_PrioritizeCurDoor();
+}
+
+void RoomDraw_HighRangeDoor_West(uint8 door_type, uint16 dsto, int pos_enum) {  // 81ae40
+  if (pos_enum >= 6) {
+    uint16 bak = dung_cur_door_idx;
+    dung_cur_door_idx |= 0x10;
+    RoomDraw_OneSidedLowerShutters_East(door_type, kDoorPositionToTilemapOffs_Right[pos_enum - 6] / 2);
+    dung_cur_door_idx = bak;
+  }
+
+  uint8 t = RoomDraw_FlagDoorsAndGetFinalType(2, door_type, dsto), new_type;
+  if ((new_type = kDoorType_Shutter, t == kDoorType_ShutterTrapUR) ||
+      (new_type = kDoorType_RegularDoor33, t == kDoorType_ShutterTrapDL)) {
+    int i = (dung_cur_door_idx >> 1) - 1;
+    door_type_and_slot[i] = (i << 8) | new_type;
+    t = new_type;
+  }
+
+  const uint16 *src = SrcPtr(kDoorTypeSrcData3[t >> 1]);
+  uint16 dsto_org = dsto;
+  dung_bg2[dsto + XY(0, 0)] = src[0];
+  dung_bg2[dsto + XY(0, 1)] = src[1];
+  dung_bg2[dsto + XY(0, 2)] = src[2];
+  dung_bg2[dsto + XY(0, 3)] = src[3];
+  dsto++, src += 4;
+  for (int i = 0; i < 2; i++) {
+    dung_bg1[dsto + XY(0, 0)] = src[0];
+    dung_bg1[dsto + XY(0, 1)] = src[1];
+    dung_bg1[dsto + XY(0, 2)] = src[2];
+    dung_bg1[dsto + XY(0, 3)] = src[3];
+    dsto++, src += 4;
+  }
+  RoomDraw_MakeDoorHighPriority_West(dsto_org);
+  Door_PrioritizeCurDoor();
+}
+
+void RoomDraw_OneSidedLowerShutters_East(uint8 door_type, uint16 dsto) {  // 81aef0
+  uint8 t = RoomDraw_FlagDoorsAndGetFinalType(3, door_type, dsto), new_type;
+  if ((new_type = kDoorType_RegularDoor33, t == kDoorType_ShutterTrapUR) ||
+      (new_type = kDoorType_Shutter, t == kDoorType_ShutterTrapDL)) {
+    int i = (dung_cur_door_idx >> 1) - 1;
+    door_type_and_slot[i] = (i << 8) | new_type;
+    t = new_type;
+  }
+
+  uint16 dst_org = dsto;
+  const uint16 *src = SrcPtr(kDoorTypeSrcData4[t >> 1]);
+  for (int i = 0; i < 2; i++) {
+    dung_bg1[dsto + XY(1, 0)] = src[0];
+    dung_bg1[dsto + XY(1, 1)] = src[1];
+    dung_bg1[dsto + XY(1, 2)] = src[2];
+    dung_bg1[dsto + XY(1, 3)] = src[3];
+    dsto++, src += 4;
+  }
+  dung_bg2[dsto + XY(1, 0)] = src[0];
+  dung_bg2[dsto + XY(1, 1)] = src[1];
+  dung_bg2[dsto + XY(1, 2)] = src[2];
+  dung_bg2[dsto + XY(1, 3)] = src[3];
+  RoomDraw_MakeDoorHighPriority_East(dst_org + XY(4, 0));
+  Door_PrioritizeCurDoor();
+}
+
+void RoomDraw_MakeDoorHighPriority_North(uint16 dsto) {  // 81af8b
+  uint16 dsto_org = dsto;
+  dsto &= 0xF07F >> 1;
+  do {
+    dung_bg2[dsto + 0] |= 0x2000;
+    dung_bg2[dsto + 1] |= 0x2000;
+    dung_bg2[dsto + 2] |= 0x2000;
+    dung_bg2[dsto + 3] |= 0x2000;
+    dsto += XY(0, 1);
+  } while (dsto != dsto_org);
+}
+
+void RoomDraw_MakeDoorHighPriority_South(uint16 dsto) {  // 81afd4
+  do {
+    dung_bg2[dsto + 0] |= 0x2000;
+    dung_bg2[dsto + 1] |= 0x2000;
+    dung_bg2[dsto + 2] |= 0x2000;
+    dung_bg2[dsto + 3] |= 0x2000;
+    dsto += XY(0, 1);
+  } while (dsto & 0x7c0);
+}
+
+void RoomDraw_MakeDoorHighPriority_West(uint16 dsto) {  // 81b017
+  uint16 dsto_org = dsto;
+  dsto &= 0xffe0;
+  do {
+    dung_bg2[dsto + XY(0, 0)] |= 0x2000;
+    dung_bg2[dsto + XY(0, 1)] |= 0x2000;
+    dung_bg2[dsto + XY(0, 2)] |= 0x2000;
+    dung_bg2[dsto + XY(0, 3)] |= 0x2000;
+    dsto += XY(1, 0);
+  } while (dsto != dsto_org);
+}
+
+void RoomDraw_MakeDoorHighPriority_East(uint16 dsto) {  // 81b05c
+  uint16 *d = &dung_bg2[dsto];
+  do {
+    d[XY(0, 0)] |= 0x2000;
+    d[XY(0, 1)] |= 0x2000;
+    d[XY(0, 2)] |= 0x2000;
+    d[XY(0, 3)] |= 0x2000;
+    d += XY(1, 0), dsto += 1;
+  } while (dsto & 0x1f);
+}
+
+void RoomDraw_MarkDungeonToggleDoor(uint16 dsto) {  // 81b092
+  dung_toggle_palace_pos[dung_num_toggle_palace >> 1] = dsto;
+  dung_num_toggle_palace += 2;
+}
+
+void RoomDraw_MarkLayerToggleDoor(uint16 dsto) {  // 81b09f
+  dung_toggle_floor_pos[dung_num_toggle_floor >> 1] = dsto;
+  dung_num_toggle_floor += 2;
+}
+
+void RoomDraw_GetObjectSize_1to16() {  // 81b0ac
+  dung_draw_width_indicator = (dung_draw_width_indicator << 2 | dung_draw_height_indicator) + 1;
+  dung_draw_height_indicator = 0;
+}
+
+void Object_SizeAtoAplus15(uint8 a) {  // 81b0af
+  dung_draw_width_indicator = (dung_draw_width_indicator << 2 | dung_draw_height_indicator) + a;
+  dung_draw_height_indicator = 0;
+}
+
+void RoomDraw_GetObjectSize_1to15or26() {  // 81b0be
+  uint16 x = dung_draw_width_indicator << 2 | dung_draw_height_indicator;
+  dung_draw_width_indicator = x ? x : 26;
+}
+
+void RoomDraw_GetObjectSize_1to15or32() {  // 81b0cc
+  uint16 x = dung_draw_width_indicator << 2 | dung_draw_height_indicator;
+  dung_draw_width_indicator = x ? x : 32;
+}
+
+// returns 0x100 on inverse carry
+int RoomDraw_FlagDoorsAndGetFinalType(uint8 direction, uint8 door_type, uint16 dsto) {  // 81b0da
+  int slot = dung_cur_door_idx >> 1;
+  dung_door_direction[slot] = direction;
+  dung_door_tilemap_address[slot] = dsto * 2;
+  door_type_and_slot[slot] = slot << 8 | door_type;
+
+  uint8 door_type_remapped = door_type;
+
+  if ((slot & 7) < 4 && (dung_door_opened_incl_adjacent & kUpperBitmasks[slot & 7])) {
+    if ((door_type == kDoorType_ShuttersTwoWay || door_type == kDoorType_Shutter) && dung_flag_trapdoors_down)
+      goto dont_mark_opened;
+    door_type_remapped = kDoorTypeRemap[door_type >> 1];
+
+    if (door_type != kDoorType_ShuttersTwoWay && door_type != kDoorType_Shutter &&
+        door_type >= kDoorType_InvisibleDoor && door_type != kDoorType_RegularDoor33 && door_type != kDoorType_WarpRoomDoor)
+      dung_door_opened |= kUpperBitmasks[slot];
+  }
+dont_mark_opened:
+  dung_cur_door_idx = slot * 2 + 2;
+
+  if (door_type_remapped == kDoorType_Slashable || door_type_remapped == kDoorType_WaterfallTunnel)
+    return 0x100 | door_type_remapped;
+
+  if (door_type != kDoorType_InvisibleDoor)
+    return door_type_remapped;
+
+  invisible_door_dir_and_index_x2 = (slot << 8 | direction) * 2;
+  //  if (direction * 2 == link_direction_facing || ((direction * 2) ^ 2) == link_direction_facing)
+  //    return door_type_remapped;
+  dung_door_opened_incl_adjacent |= kUpperBitmasks[slot];
+  return kDoorType_Regular;
+}
+
+void RoomDraw_MakeDoorPartsHighPriority_Y(uint16 dsto) {  // 81b1a4
+  uint16 *d = &dung_bg2[dsto];
+  for (int i = 0; i < 7; i++) {
+    d[XY(0, 0)] |= 0x2000;
+    d[XY(1, 0)] |= 0x2000;
+    d[XY(2, 0)] |= 0x2000;
+    d[XY(3, 0)] |= 0x2000;
+    d += XY(0, 1);
+  }
+}
+
+void RoomDraw_MakeDoorPartsHighPriority_X(uint16 dsto) {  // 81b1e7
+  uint16 *d = &dung_bg2[dsto];
+  for (int i = 0; i < 5; i++) {
+    d[XY(0, 0)] |= 0x2000;
+    d[XY(0, 1)] |= 0x2000;
+    d[XY(0, 2)] |= 0x2000;
+    d[XY(0, 3)] |= 0x2000;
+    d += XY(1, 0);
+  }
+}
+
+void RoomDraw_Downwards4x2VariableSpacing(int increment, const uint16 *src, uint16 *dst) {  // 81b220
+  do {
+    dst[XY(0, 0)] = src[0];
+    dst[XY(1, 0)] = src[1];
+    dst[XY(2, 0)] = src[2];
+    dst[XY(3, 0)] = src[3];
+    dst[XY(0, 1)] = src[4];
+    dst[XY(1, 1)] = src[5];
+    dst[XY(2, 1)] = src[6];
+    dst[XY(3, 1)] = src[7];
+    dst += increment;
+  } while (--dung_draw_width_indicator);
+}
+
+uint16 *RoomDraw_DrawObject2x2and1(const uint16 *src, uint16 *dst) {  // 81b279
+  dst[XY(0, 0)] = src[0];
+  dst[XY(0, 1)] = src[1];
+  dst[XY(0, 2)] = src[2];
+  dst[XY(0, 3)] = src[3];
+  dst[XY(0, 4)] = src[4];
+  return dst;
+}
+
+uint16 *RoomDraw_RightwardShelfEnd(const uint16 *src, uint16 *dst) {  // 81b2e1
+  dst[XY(0, 0)] = src[0];
+  dst[XY(0, 1)] = src[1];
+  dst[XY(0, 2)] = src[2];
+  dst[XY(0, 3)] = src[3];
+  return dst;
+}
+
+uint16 *RoomDraw_RightwardBarSegment(const uint16 *src, uint16 *dst) {  // 81b2f6
+  dst[XY(0, 0)] = src[0];
+  dst[XY(0, 1)] = src[1];
+  dst[XY(0, 2)] = src[2];
+  return dst;
+}
+
+void DrawBigGraySegment(uint16 a, const uint16 *src, uint16 *dst, uint16 dsto) {  // 81b33a
+  int i = dung_misc_objs_index >> 1;
+  dung_replacement_tile_state[i] = a;
+  dung_misc_objs_index += 2;
+  dung_object_pos_in_objdata[i] = dung_load_ptr_offs;
+  dung_object_tilemap_pos[i] = dsto * 2 | (dung_line_ptrs_row0 != 0x4000 ? 0 : 0x2000);
+  replacement_tilemap_UL[i] = dst[XY(0, 0)];
+  replacement_tilemap_LL[i] = dst[XY(0, 1)];
+  replacement_tilemap_UR[i] = dst[XY(1, 0)];
+  replacement_tilemap_LR[i] = dst[XY(1, 1)];
+  RoomDraw_Rightwards2x2(src, dst);
+}
+
+void RoomDraw_SinglePot(const uint16 *src, uint16 *dst, uint16 dsto) {  // 81b395
+  int i = dung_misc_objs_index >> 1;
+  dung_misc_objs_index += 2;
+  dung_replacement_tile_state[i] = 0x1111;
+  dung_object_pos_in_objdata[i] = dung_load_ptr_offs;
+  dung_object_tilemap_pos[i] = (dsto * 2) | (dung_line_ptrs_row0 != 0x4000 ? 0 : 0x2000);
+  replacement_tilemap_UL[i] = 0x0d0e;
+  replacement_tilemap_LL[i] = 0x0d1e;
+  replacement_tilemap_UR[i] = 0x4d0e;
+  replacement_tilemap_LR[i] = 0x4d1e;
+  if (savegame_is_darkworld)
+    src = SrcPtr(0xe92);
+  RoomDraw_Rightwards2x2(src, dst);
+}
+
+void RoomDraw_BombableFloor(const uint16 *src, uint16 *dst, uint16 dsto) {  // 81b3e1
+  if (dungeon_room_index == 101 && (dung_savegame_state_bits & 0x1000)) {
+    dung_draw_width_indicator = 0;
+    dung_draw_height_indicator = 0;
+    Object_Hole(SrcPtr(0x5aa), dst);
+    return;
+  }
+
+  src = SrcPtr(0x220);
+  const uint16 *src_below = SrcPtr(0x5ba);
+
+  Object_BombableFloorHelper(0x3030, src, src_below, dst, dsto);
+  Object_BombableFloorHelper(0x3131, src + 4, src_below + 4, dst + XY(2, 0), dsto + XY(2, 0));
+  Object_BombableFloorHelper(0x3232, src + 8, src_below + 8, dst + XY(0, 2), dsto + XY(0, 2));
+  Object_BombableFloorHelper(0x3333, src + 12, src_below + 12, dst + XY(2, 2), dsto + XY(2, 2));
+}
+
+void RoomDraw_HammerPegSingle(const uint16 *src, uint16 *dst, uint16 dsto) {  // 81b493
+  int i = dung_misc_objs_index >> 1;
+  dung_misc_objs_index += 2;
+  dung_replacement_tile_state[i] = 0x4040;
+  dung_object_pos_in_objdata[i] = dung_load_ptr_offs;
+  dung_object_tilemap_pos[i] = (dsto * 2) | (dung_line_ptrs_row0 != 0x4000 ? 0 : 0x2000);
+  replacement_tilemap_UL[i] = 0x19d8;
+  replacement_tilemap_LL[i] = 0x19d9;
+  replacement_tilemap_UR[i] = 0x59d8;
+  replacement_tilemap_LR[i] = 0x59d9;
+  RoomDraw_Rightwards2x2(src, dst);
+}
+
+void DrawObjects_PushableBlock(uint16 dsto_x2, uint16 slot) {  // 81b4d6
+  int x = dung_misc_objs_index >> 1;
+  dung_misc_objs_index += 2;
+  dung_replacement_tile_state[x] = 0;
+  dung_object_pos_in_objdata[x] = slot;
+  dung_object_tilemap_pos[x] = dsto_x2;
+  uint16 *dst = DstoPtr((dsto_x2 >> 1) & 0x1fff);
+  replacement_tilemap_UL[x] = dst[XY(0, 0)];
+  replacement_tilemap_LL[x] = dst[XY(0, 1)];
+  replacement_tilemap_UR[x] = dst[XY(1, 0)];
+  replacement_tilemap_LR[x] = dst[XY(1, 1)];
+  RoomDraw_Rightwards2x2(SrcPtr(0xe52), dst);
+}
+
+void DrawObjects_LightableTorch(uint16 dsto_x2, uint16 slot) {  // 81b509
+  int x = dung_index_of_torches >> 1;
+  dung_index_of_torches += 2;
+  dung_object_tilemap_pos[x] = dsto_x2;
+  dung_object_pos_in_objdata[x] = slot;
+  uint16 src_img = 0xec2;
+  uint16 *dst = DstoPtr((dsto_x2 >> 1) & 0x1fff);
+  if (dsto_x2 & 0x8000) {
+    src_img = 0xeca;
+    if (dung_num_lit_torches < 3)
+      dung_num_lit_torches++;
+  }
+  RoomDraw_Rightwards2x2(SrcPtr(src_img), dst);
+}
+
+void Dungeon_LoadHeader() {  // 81b564
+  dung_flag_statechange_waterpuzzle = 0;
+  dung_flag_somaria_block_switch = 0;
+  dung_flag_movable_block_was_pushed = 0;
+
+  static const int16 kAdjustment[] = { 256, -256 };
+
+  if (submodule_index == 0) {
+    dung_loade_bgoffs_h_copy = BG2HOFS_copy2 & ~0x1FF;
+    dung_loade_bgoffs_v_copy = BG2VOFS_copy2 & ~0x1FF;
+  } else if (submodule_index == 21 || submodule_index < 18 && submodule_index >= 6) {
+    dung_loade_bgoffs_h_copy = (BG2HOFS_copy2 + 0x20) & ~0x1FF;
+    dung_loade_bgoffs_v_copy = (BG2VOFS_copy2 + 0x20) & ~0x1FF;
+  } else {
+    if (((link_direction & 0xf) >> 1) < 2) {
+      dung_loade_bgoffs_h_copy = (BG2HOFS_copy2 + kAdjustment[(link_direction & 0xf) >> 1]) & ~0x1FF;
+      dung_loade_bgoffs_v_copy = (BG2VOFS_copy2 + 0x20) & ~0x1FF;
+    } else {
+      dung_loade_bgoffs_h_copy = (BG2HOFS_copy2 + 0x20) & ~0x1FF;
+      dung_loade_bgoffs_v_copy = (BG2VOFS_copy2 + kAdjustment[(link_direction & 0xf) >> 3]) & ~0x1FF;
+    }
+  }
+
+  const uint8 *hdr_ptr = GetRoomHeaderPtr(dungeon_room_index);
+
+  dung_bg2_properties_backup = dung_hdr_bg2_properties;
+  dung_hdr_bg2_properties = hdr_ptr[0] >> 5;
+  dung_hdr_collision = (hdr_ptr[0] >> 2) & 7;
+  dung_want_lights_out_copy = dung_want_lights_out;
+  dung_want_lights_out = hdr_ptr[0] & 1;
+  const DungPalInfo *dpi = &kDungPalinfos[hdr_ptr[1]];
+  palette_main_indoors = dpi->pal0;
+  palette_sp0l = dpi->pal1;
+  palette_sp5l = dpi->pal2;
+  palette_sp6l = dpi->pal3;
+  aux_tile_theme_index = hdr_ptr[2];
+  sprite_graphics_index = hdr_ptr[3] + 0x40;
+  dung_hdr_collision_2 = hdr_ptr[4];
+  dung_hdr_tag[0] = hdr_ptr[5];
+  dung_hdr_tag[1] = hdr_ptr[6];
+  dung_hdr_hole_teleporter_plane = hdr_ptr[7] & 3;
+  dung_hdr_staircase_plane[0] = (hdr_ptr[7] >> 2) & 3;
+  dung_hdr_staircase_plane[1] = (hdr_ptr[7] >> 4) & 3;
+  dung_hdr_staircase_plane[2] = (hdr_ptr[7] >> 6) & 3;
+  dung_hdr_staircase_plane[3] = hdr_ptr[8] & 3;
+  dung_hdr_travel_destinations[0] = hdr_ptr[9];
+  dung_hdr_travel_destinations[1] = hdr_ptr[10];
+  dung_hdr_travel_destinations[2] = hdr_ptr[11];
+  dung_hdr_travel_destinations[3] = hdr_ptr[12];
+  dung_hdr_travel_destinations[4] = hdr_ptr[13];
+  dung_flag_trapdoors_down = 1;
+  dung_overlay_to_load = 0;
+  dung_index_x3 = dungeon_room_index * 3;
+
+  uint16 x = save_dung_info[dungeon_room_index];
+  dung_door_opened = x & 0xf000;
+  dung_door_opened_incl_adjacent = dung_door_opened | 0xf00;
+  dung_savegame_state_bits = (x & 0xff0) << 4;
+  dung_quadrants_visited = x & 0xf;
+
+  const uint16 *dp = GetRoomDoorInfo(dungeon_room_index);
+  int i = 0;
+  for (; dp[i] != 0xffff; i++)
+    dung_door_tilemap_address[i] = dp[i];
+  dung_door_tilemap_address[i] = 0;
+
+  if (((dungeon_room_index - 1) & 0xf) != 0xf)
+    Dungeon_CheckAdjacentRoomsForOpenDoors(18, dungeon_room_index - 1);
+  if (((dungeon_room_index + 1) & 0xf) != 0)
+    Dungeon_CheckAdjacentRoomsForOpenDoors(12, dungeon_room_index + 1);
+  if (dungeon_room_index - 16 >= 0)
+    Dungeon_CheckAdjacentRoomsForOpenDoors(6, dungeon_room_index - 16);
+  if (dungeon_room_index + 16 < 0x140)
+    Dungeon_CheckAdjacentRoomsForOpenDoors(0, dungeon_room_index + 16);
+}
+
+void Dungeon_CheckAdjacentRoomsForOpenDoors(int idx, int room) {  // 81b759
+  static const uint16 kLookup[] = {
+    0x00, 0x10, 0x20, 0x30, 0x40, 0x50,
+    0x61, 0x71, 0x81, 0x91, 0xa1, 0xb1,
+    0x02, 0x12, 0x22, 0x32, 0x42, 0x52,
+    0x63, 0x73, 0x83, 0x93, 0xa3, 0xb3,
+  };
+  static const uint16 kLookup2[] = {
+    0x61, 0x71, 0x81, 0x91, 0xa1, 0xb1,
+    0x0, 0x10, 0x20, 0x30, 0x40, 0x50,
+    0x63, 0x73, 0x83, 0x93, 0xa3, 0xb3,
+    0x02, 0x12, 0x22, 0x32, 0x42, 0x52,
+  };
+  Dungeon_LoadAdjacentRoomDoors(room);
+  int i, j;
+  uint16 a;
+  for (i = 0; i != 8 && (a = adjacent_doors[i]) != 0xffff; i++) {
+    a &= 0xff;
+    j = idx;
+    if (a == kLookup[j] || a == kLookup[++j] || a == kLookup[++j] || a == kLookup[++j] || a == kLookup[++j] || a == kLookup[++j]) {
+      uint8 rev = kLookup2[j];
+      for (j = 0; j != 8; j++) {
+        if ((uint8)dung_door_tilemap_address[j] == rev) {
+          uint8 k = dung_door_tilemap_address[j] >> 8;
+          if (k == 0x30)
+            break;
+          if (k == 0x44 || k == 0x18) {
+            // trapdoor
+            if (room != dungeon_room_index_prev)
+              break;
+            dung_flag_trapdoors_down = 0;
+          } else {
+            // not trapdoor
+            if (!(adjacent_doors_flags & kUpperBitmasks[i]))
+              break;
+          }
+          dung_door_opened_incl_adjacent |= kUpperBitmasks[j];
+          break;
+        }
+      }
+    }
+  }
+}
+
+void Dungeon_LoadAdjacentRoomDoors(int room) {  // 81b7ef
+  const uint16 *dp = GetRoomDoorInfo(room);
+  adjacent_doors_flags = (save_dung_info[room] & 0xf000) | 0xf00;
+  for (int i = 0; ; i++) {
+    uint16 a = dp[i];
+    adjacent_doors[i] = a;
+    if (a == 0xffff)
+      break;
+    if ((a & 0xff00) == 0x4000 || (a & 0xff00) < 0x200)
+      adjacent_doors_flags |= kUpperBitmasks[i];
+  }
+}
+
+void Dungeon_LoadAttribute_Selectable() {  // 81b8b4
+  switch (overworld_map_state) {
+  case 0:  // Dungeon_LoadBasicAttribute
+    overworld_map_state = 1;
+    dung_draw_width_indicator = dung_draw_height_indicator = 0;
+  case 1:
+    Dungeon_LoadBasicAttribute_full(0x40);
+    break;
+  case 2:
+    Dungeon_LoadObjectAttribute();
+    break;
+  case 3:
+    Dungeon_LoadDoorAttribute();
+    break;
+  case 4:
+    overworld_map_state = 5;
+    if (orange_blue_barrier_state)
+      Dungeon_FlipCrystalPegAttribute();
+    break;
+  case 5:
+    break;
+  default:
+    assert(0);
+  }
+}
+
+void Dungeon_LoadAttributeTable() {  // 81b8bf
+  dung_draw_width_indicator = dung_draw_height_indicator = 0;
+  Dungeon_LoadBasicAttribute_full(0x1000);
+  Dungeon_LoadObjectAttribute();
+  Dungeon_LoadDoorAttribute();
+  if (orange_blue_barrier_state)
+    Dungeon_FlipCrystalPegAttribute();
+  overworld_map_state = 0;
+}
+
+void Dungeon_LoadBasicAttribute_full(uint16 loops) {  // 81b8f3
+  do {
+    int i = dung_draw_width_indicator / 2;
+    uint8 a0 = attributes_for_tile[dung_bg2[i] & 0x3ff];
+    if (a0 >= 0x10 && a0 < 0x1c)
+      a0 |= (dung_bg2[i] >> 14);  // vflip/hflip
+    uint8 a1 = attributes_for_tile[dung_bg2[i + 1] & 0x3ff];
+    if (a1 >= 0x10 && a1 < 0x1c)
+      a1 |= (dung_bg2[i + 1] >> 14);  // vflip/hflip
+    int j = dung_draw_height_indicator;
+    dung_bg2_attr_table[j] = a0;
+    dung_bg2_attr_table[j + 1] = a1;
+    dung_draw_height_indicator = j + 2;
+    dung_draw_width_indicator += 4;
+  } while (--loops);
+  if (dung_draw_height_indicator == 0x2000)
+    overworld_map_state++;
+}
+
+void Dungeon_LoadObjectAttribute() {  // 81b967
+  for (int i = 0; i != dung_num_star_shaped_switches; i += 2) {
+    int j = star_shaped_switches_tile[i >> 1];
+    WriteAttr2(j + XY(0, 0), 0x3b3b);
+    WriteAttr2(j + XY(0, 1), 0x3b3b);
+  }
+
+  int i = 0, t = 0x3030;
+  for (; i != dung_num_inter_room_upnorth_stairs; i += 2, t += 0x101) {
+    int j = dung_inter_starcases[i >> 1];
+    WriteAttr2(j + XY(1, 2), 0);
+    WriteAttr2(j + XY(1, 0), 0x2626);
+    WriteAttr2(j + XY(1, 1), t);
+  }
+  for (; i != dung_num_wall_upnorth_spiral_stairs; i += 2, t += 0x101) {
+    int j = dung_inter_starcases[i >> 1];
+    WriteAttr2(j + XY(1, 0), 0x5e5e);
+    WriteAttr2(j + XY(1, 2), 0x5e5e);
+    WriteAttr2(j + XY(1, 3), 0x5e5e);
+    WriteAttr2(j + XY(1, 1), t);
+  }
+  for (; i != dung_num_wall_upnorth_spiral_stairs_2; i += 2, t += 0x101) {
+    int j = dung_inter_starcases[i >> 1];
+    WriteAttr2(j + XY(1, 0), 0x5f5f);
+    WriteAttr2(j + XY(1, 2), 0x5f5f);
+    WriteAttr2(j + XY(1, 3), 0x5f5f);
+    WriteAttr2(j + XY(1, 1), t);
+  }
+  for (; i != dung_num_inter_room_upnorth_straight_stairs; i += 2, t += 0x101) {
+    int j = dung_inter_starcases[i >> 1];
+    WriteAttr2(j + XY(1, 0), 0x3838);
+    WriteAttr2(j + XY(1, 2), 0);
+    WriteAttr2(j + XY(1, 3), 0);
+    WriteAttr2(j + XY(1, 1), t);
+  }
+  for (; i != dung_num_inter_room_upsouth_straight_stairs; i += 2, t += 0x101) {
+    int j = dung_inter_starcases[i >> 1];
+    WriteAttr2(j + XY(1, 0), 0);
+    WriteAttr2(j + XY(1, 1), 0);
+    WriteAttr2(j + XY(1, 2), t);
+    WriteAttr2(j + XY(1, 3), 0x3939);
+  }
+  t = (t & 0x707) | 0x3434;
+  for (; i != dung_num_inter_room_southdown_stairs; i += 2, t += 0x101) {
+    int j = dung_inter_starcases[i >> 1];
+    WriteAttr2(j + XY(1, 2), t);
+    WriteAttr2(j + XY(1, 3), 0x2626);
+  }
+  for (; i != dung_num_wall_downnorth_spiral_stairs; i += 2, t += 0x101) {
+    int j = dung_inter_starcases[i >> 1];
+    WriteAttr2(j + XY(1, 0), 0x5e5e);
+    WriteAttr2(j + XY(1, 1), t);
+    WriteAttr2(j + XY(1, 2), 0x5e5e);
+    WriteAttr2(j + XY(1, 3), 0x5e5e);
+  }
+  for (; i != dung_num_wall_downnorth_spiral_stairs_2; i += 2, t += 0x101) {
+    int j = dung_inter_starcases[i >> 1];
+    WriteAttr2(j + XY(1, 0), 0x5f5f);
+    WriteAttr2(j + XY(1, 1), t);
+    WriteAttr2(j + XY(1, 2), 0x5f5f);
+    WriteAttr2(j + XY(1, 3), 0x5f5f);
+  }
+  for (; i != dung_num_inter_room_downnorth_straight_stairs; i += 2, t += 0x101) {
+    int j = dung_inter_starcases[i >> 1];
+    WriteAttr2(j + XY(1, 0), 0x3838);
+    WriteAttr2(j + XY(1, 1), t);
+    WriteAttr2(j + XY(1, 2), 0);
+    WriteAttr2(j + XY(1, 3), 0);
+  }
+  for (; i != dung_num_inter_room_downsouth_straight_stairs; i += 2, t += 0x101) {
+    int j = dung_inter_starcases[i >> 1];
+    WriteAttr2(j + XY(1, 0), 0);
+    WriteAttr2(j + XY(1, 1), 0);
+    WriteAttr2(j + XY(1, 2), t);
+    WriteAttr2(j + XY(1, 3), 0x3939);
+  }
+
+  i = 0;
+  int type = 0, iend = dung_num_inroom_upnorth_stairs;
+  uint16 attr = 0x1f1f;
+  if (iend == 0) {
+    type = 1, attr = 0x1e1e;
+    iend = dung_num_inroom_southdown_stairs;
+    if (iend == 0) {
+      type = 2, attr = 0x1d1d;
+      iend = dung_num_interpseudo_upnorth_stairs;
+      if (iend == 0)
+        goto skip3;
+    }
+  }
+  kind_of_in_room_staircase = type;
+  for (; i != iend; i += 2) {
+    int j = dung_stairs_table_1[i >> 1];
+    WriteAttr2(j + XY(0, 0), 0x02);
+    WriteAttr1(j + XY(0, 3), 0x02);
+    WriteAttr2(j + XY(2, 0), 0x0200);
+    WriteAttr1(j + XY(2, 3), 0x0200);
+    WriteAttr2(j + XY(0, 1), 0x01);
+    WriteAttr1(j + XY(0, 2), 0x01);
+    WriteAttr2(j + XY(2, 1), 0x0100);  // todo: use 8-bit write?
+    WriteAttr1(j + XY(2, 2), 0x0100);
+    WriteAttr2(j + XY(1, 1), attr);
+    WriteAttr1(j + XY(1, 1), attr);
+    WriteAttr2(j + XY(1, 2), attr);
+    WriteAttr1(j + XY(1, 2), attr);
+  }
+skip3:
+  if (i != dung_some_stairs_unk4) {
+    kind_of_in_room_staircase = 2;
+    for (; i != dung_some_stairs_unk4; i += 2) {
+      int j = dung_stairs_table_1[i >> 1];
+      WriteAttr2(j + XY(0, 0), 0xa03);
+      WriteAttr1(j + XY(0, 0), 0xa03);
+      WriteAttr2(j + XY(2, 0), 0x30a);
+      WriteAttr1(j + XY(2, 0), 0x30a);
+      WriteAttr2(j + XY(0, 1), 0x803);
+      WriteAttr2(j + XY(2, 1), 0x308);
+    }
+  }
+  i = 0;
+  if (i != dung_num_inroom_upnorth_stairs_water) {
+    kind_of_in_room_staircase = 2;
+    for (; i != dung_num_inroom_upnorth_stairs_water; i += 2) {
+      int j = dung_stairs_table_1[i >> 1];
+      WriteAttr2(j + XY(0, 0), 0x003);
+      WriteAttr2(j + XY(2, 0), 0x300);
+      WriteAttr1(j + XY(0, 0), 0xa03);
+      WriteAttr1(j + XY(2, 0), 0x30a);
+      WriteAttr2(j + XY(0, 1), 0x808);
+      WriteAttr2(j + XY(2, 1), 0x808);
+    }
+  }
+  if (i != dung_num_activated_water_ladders) {
+    kind_of_in_room_staircase = 2;
+    for (; i != dung_num_activated_water_ladders; i += 2) {
+      int j = dung_stairs_table_1[i >> 1];
+      WriteAttr2(j + XY(0, 0), 0x003);
+      WriteAttr2(j + XY(2, 0), 0x300);
+      WriteAttr1(j + XY(0, 0), 0xa03);
+      WriteAttr1(j + XY(2, 0), 0x30a);
+    }
+  }
+
+  for (i = 0, t = 0x7070; i != dung_misc_objs_index; i += 2, t += 0x101) {
+    uint16 k = dung_replacement_tile_state[i >> 1];
+    if ((k & 0xf0) != 0x30) {
+      int j = (dung_object_tilemap_pos[i >> 1] & 0x3fff) >> 1;
+      WriteAttr2(j + XY(0, 0), t);
+      WriteAttr2(j + XY(0, 1), t);
+    }
+  }
+
+  if (i != dung_index_of_torches) {
+    for (t = 0xc0c0; i != dung_index_of_torches; i += 2, t = (t & 0xefef) + 0x101) {
+      int j = (dung_object_tilemap_pos[i >> 1] & 0x3fff) >> 1;
+      WriteAttr2(j + XY(0, 0), t);
+      WriteAttr2(j + XY(0, 1), t);
+    }
+    dung_index_of_torches = 0;
+  }
+
+  t = 0x5858, i = 0;
+  if (dung_num_chests_x2) {
+    if (dung_hdr_tag[0] == 0x27 || dung_hdr_tag[0] == 0x3c || dung_hdr_tag[0] == 0x3e || dung_hdr_tag[0] >= 0x29 && dung_hdr_tag[0] < 0x33)
+      goto no_big_key_locks;
+    if (dung_hdr_tag[1] == 0x27 || dung_hdr_tag[1] == 0x3c || dung_hdr_tag[1] == 0x3e || dung_hdr_tag[1] >= 0x29 && dung_hdr_tag[1] < 0x33)
+      goto no_big_key_locks;
+
+    for (; i != dung_num_chests_x2; i += 2, t += 0x101) {
+      int k = dung_chest_locations[i >> 1];
+      if (k != 0) {
+        int j = (k & 0x7fff) >> 1;
+        WriteAttr2(j + XY(0, 0), t);
+        WriteAttr2(j + XY(0, 1), t);
+        if (k & 0x8000) {
+          dung_chest_locations[i >> 1] = k & 0x7fff;
+          WriteAttr2(j + XY(2, 1), t);
+          WriteAttr2(j + XY(0, 2), t);
+          WriteAttr2(j + XY(2, 2), t);
+        }
+      }
+    }
+  }
+  for (; i != dung_num_bigkey_locks_x2; i += 2, t += 0x101) {
+    int k = dung_chest_locations[i >> 1];
+    dung_chest_locations[i >> 1] = k | 0x8000;
+    int j = (k & 0x7fff) >> 1;
+    WriteAttr2(j + XY(0, 0), t);
+    WriteAttr2(j + XY(0, 1), t);
+  }
+no_big_key_locks:
+
+  i = 0;
+  type = 0, iend = dung_num_stairs_1;
+  attr = 0x3f3f;
+  if (iend == 0) {
+    type = 1, attr = 0x3e3e;
+    iend = dung_num_stairs_2;
+    if (iend == 0) {
+      type = 2, attr = 0x3d3d;
+      iend = dung_num_stairs_wet;
+      if (iend == 0)
+        goto skip7;
+    }
+  }
+  kind_of_in_room_staircase = type;
+  for (i = 0; i != iend; i += 2) {
+    int j = dung_stairs_table_2[i >> 1];
+    WriteAttr1(j + XY(0, 0), 0x02);
+    WriteAttr2(j + XY(0, 3), 0x02);
+    WriteAttr1(j + XY(0, 1), 0x01);
+    WriteAttr2(j + XY(0, 2), 0x01);
+    WriteAttr1(j + XY(2, 0), 0x0200);
+    WriteAttr2(j + XY(2, 3), 0x0200);
+    WriteAttr1(j + XY(2, 1), 0x0100);  // todo: use 8-bit write?
+    WriteAttr2(j + XY(2, 2), 0x0100);
+    WriteAttr1(j + XY(1, 1), attr);
+    WriteAttr2(j + XY(1, 1), attr);
+    WriteAttr1(j + XY(1, 2), attr);
+    WriteAttr2(j + XY(1, 2), attr);
+  }
+skip7:
+
+  if (dung_num_inroom_upsouth_stairs_water) {
+    kind_of_in_room_staircase = 2;
+    for (i = 0; i != dung_num_inroom_upsouth_stairs_water; i += 2) {
+      int j = dung_stairs_table_2[i >> 1];
+      WriteAttr1(j + XY(0, 3), 0xa03);
+      WriteAttr1(j + XY(2, 3), 0x30a);
+      WriteAttr2(j + XY(0, 3), 0x003);
+      WriteAttr2(j + XY(2, 3), 0x300);
+      WriteAttr2(j + XY(0, 2), 0x808);
+      WriteAttr2(j + XY(2, 2), 0x808);
+    }
+  }
+  overworld_map_state += 1;
+}
+
+void Dungeon_LoadDoorAttribute() {  // 81be17
+  for (int i = 0; i != 16; i++) {
+    if (dung_door_tilemap_address[i])
+      Dungeon_LoadSingleDoorAttribute(i);
+  }
+  Dungeon_LoadSingleDoorTileAttribute();
+  ChangeDoorToSwitch();
+  overworld_map_state += 1;
+}
+
+void Dungeon_LoadSingleDoorAttribute(int k) {  // 81be35
+  assert(k >= 0 && k < 16);
+  uint8 t = door_type_and_slot[k] & 0xfe, dir;
+  uint16 attr;
+  int i, j;
+
+  if (t == kDoorType_Regular || t == kDoorType_EntranceDoor || t == kDoorType_ExitToOw || t == kDoorType_EntranceLarge || t == kDoorType_EntranceCave)
+    goto alpha;
+
+  if (t == kDoorType_EntranceLarge2 || t == kDoorType_EntranceCave2 || t == kDoorType_4 || t == kDoorType_Regular2 || t == kDoorType_WaterfallTunnel)
+    goto beta;
+
+  if (t == kDoorType_LgExplosion)
+    return;
+
+  if (t >= kDoorType_RegularDoor33) {
+    if (t == kDoorType_RegularDoor33 || t == kDoorType_WarpRoomDoor)
+      goto beta;
+    if (dung_door_opened_incl_adjacent & kUpperBitmasks[k])
+      goto beta;
+
+    j = dung_door_tilemap_address[k] >> 1;
+    attr = (0xf0 + k) * 0x101;
+    WriteAttr2(j + XY(1, 1), attr);
+    WriteAttr2(j + XY(1, 2), attr);
+    return;
+
+  }
+
+  i = (t == kDoorType_ShuttersTwoWay || t == kDoorType_Shutter) ? k : k & 7;
+  if (!(dung_door_opened_incl_adjacent & kUpperBitmasks[i])) {
+    j = dung_door_tilemap_address[k] >> 1;
+    attr = (0xf0 + k) * 0x101;
+    WriteAttr2(j + XY(1, 1), attr);
+    WriteAttr2(j + XY(1, 2), attr);
+    return;
+  }
+
+alpha:
+  if (t >= kDoorType_StairMaskLocked0 && t <= kDoorType_StairMaskLocked3)
+    return;
+  attr = kTileAttrsByDoor[t >> 1];
+  dir = dung_door_direction[k] & 3;
+  if (dir == 0) {
+    uint16 a = dung_door_tilemap_address[k];
+    if (a == dung_exit_door_addresses[0] || a == dung_exit_door_addresses[1] || a == dung_exit_door_addresses[2] || a == dung_exit_door_addresses[3])
+      attr = 0x8e8e;
+    j = (a >> 1) & ~0x7c0;
+    WriteAttr2(j + XY(1, 0), attr);
+    WriteAttr2(j + XY(1, 1), attr);
+    WriteAttr2(j + XY(1, 2), attr);
+    WriteAttr2(j + XY(1, 3), attr);
+    WriteAttr2(j + XY(1, 4), attr);
+    WriteAttr2(j + XY(1, 5), attr);
+    WriteAttr2(j + XY(1, 6), attr);
+    WriteAttr2(j + XY(1, 7), 0);
+  } else if (dir == 1) {
+    uint16 a = dung_door_tilemap_address[k];
+    if (t == kDoorType_EntranceLarge || t == kDoorType_EntranceCave ||
+        a == dung_exit_door_addresses[0] || a == dung_exit_door_addresses[1] || a == dung_exit_door_addresses[2] || a == dung_exit_door_addresses[3])
+      attr = 0x8e8e;
+    j = a >> 1;
+    WriteAttr2(j + XY(1, 1), attr);
+    WriteAttr2(j + XY(1, 2), attr);
+    WriteAttr2(j + XY(1, 3), attr);
+    WriteAttr2(j + XY(1, 4), attr);
+    WriteAttr2(j + XY(1, 5), attr);
+  } else if (dir == 2) {
+    j = (dung_door_tilemap_address[k] >> 1) & ~0x1f;
+    WriteAttr2(j + XY(0, 1), attr + 0x101);
+    WriteAttr2(j + XY(2, 1), attr + 0x101);
+    WriteAttr2(j + XY(0, 2), attr + 0x101);
+    WriteAttr2(j + XY(2, 2), attr + 0x101);
+    WriteAttr2(j + XY(4, 1), (attr + 0x101) & 0xff);
+    WriteAttr2(j + XY(4, 2), (attr + 0x101) & 0xff);
+  } else {
+    j = (dung_door_tilemap_address[k] >> 1);
+    WriteAttr2(j + XY(2, 1), attr + 0x101);
+    WriteAttr2(j + XY(4, 1), attr + 0x101);
+    WriteAttr2(j + XY(2, 2), attr + 0x101);
+    WriteAttr2(j + XY(4, 2), attr + 0x101);
+    WriteAttr2(j + XY(0, 1), (attr + 0x101) & 0xff00);
+    WriteAttr2(j + XY(0, 2), (attr + 0x101) & 0xff00);
+  }
+  return;
+
+beta:
+  attr = kTileAttrsByDoor[t >> 1];
+  dir = dung_door_direction[k] & 3;
+  if (dir == 0) {
+    j = (dung_door_tilemap_address[k] >> 1) & ~0x7c0;
+    WriteAttr2(j + XY(1, 0), attr);
+    WriteAttr2(j + XY(1, 1), attr);
+    WriteAttr2(j + XY(1, 2), attr);
+    WriteAttr2(j + XY(1, 3), attr);
+    WriteAttr2(j + XY(1, 4), attr);
+    WriteAttr2(j + XY(1, 5), attr);
+    WriteAttr2(j + XY(1, 6), attr);
+    WriteAttr2(j + XY(1, 7), attr);
+    WriteAttr2(j + XY(1, 8), attr);
+    WriteAttr2(j + XY(1, 9), attr);
+  } else if (dir == 1) {
+    uint16 a = dung_door_tilemap_address[k] & 0x1fff;
+    if (t == kDoorType_EntranceLarge2 || t == kDoorType_EntranceCave2 || t == kDoorType_4 ||
+        a == dung_exit_door_addresses[0] || a == dung_exit_door_addresses[1] || a == dung_exit_door_addresses[2] || a == dung_exit_door_addresses[3])
+      attr = 0x8e8e;
+    j = dung_door_tilemap_address[k] >> 1;
+    WriteAttr2(j + XY(1, 1), attr);
+    WriteAttr2(j + XY(1, 2), attr);
+    WriteAttr2(j + XY(1, 3), attr);
+    WriteAttr2(j + XY(1, 4), attr);
+    WriteAttr2(j + XY(1, 5), attr);
+    WriteAttr2(j + XY(1, 6), attr);
+    WriteAttr2(j + XY(1, 7), attr);
+    WriteAttr2(j + XY(1, 8), attr);
+  } else if (dir == 2) {
+    j = (dung_door_tilemap_address[k] >> 1) & ~0x1f;
+    WriteAttr2(j + XY(0, 1), attr + 0x101);
+    WriteAttr2(j + XY(2, 1), attr + 0x101);
+    WriteAttr2(j + XY(4, 1), attr + 0x101);
+    WriteAttr2(j + XY(6, 1), attr + 0x101);
+    WriteAttr2(j + XY(0, 2), attr + 0x101);
+    WriteAttr2(j + XY(2, 2), attr + 0x101);
+    WriteAttr2(j + XY(4, 2), attr + 0x101);
+    WriteAttr2(j + XY(6, 2), attr + 0x101);
+  } else {
+    j = ((dung_door_tilemap_address[k] >> 1) + 1);
+    WriteAttr2(j + XY(0, 1), attr + 0x101);
+    WriteAttr2(j + XY(2, 1), attr + 0x101);
+    WriteAttr2(j + XY(4, 1), attr + 0x101);
+    WriteAttr2(j + XY(6, 1), attr + 0x101);
+    WriteAttr2(j + XY(0, 2), attr + 0x101);
+    WriteAttr2(j + XY(2, 2), attr + 0x101);
+    WriteAttr2(j + XY(4, 2), attr + 0x101);
+    WriteAttr2(j + XY(6, 2), attr + 0x101);
+  }
+}
+
+void Door_LoadBlastWallAttr(int k) {  // 81bfc1
+  int j = dung_door_tilemap_address[k] >> 1;
+  if (!(dung_door_direction[k] & 2)) {
+    for (int n = 12; n; n--) {
+      WriteAttr2(j + XY(0, 0), 0x102);
+      for (int i = 2; i < 20; i += 2)
+        WriteAttr2(j + XY(i, 0), 0x0);
+      WriteAttr2(j + XY(20, 0), 0x201);
+      j += XY(0, 1);
+    }
+  } else {
+    for (int n = 5; n; n--) {
+      WriteAttr2(j + XY(0, 0), 0x101);
+      WriteAttr2(j + XY(0, 21), 0x101);
+      WriteAttr2(j + XY(0, 1), 0x202);
+      WriteAttr2(j + XY(0, 20), 0x202);
+      for (int i = 2; i < 20; i++)
+        WriteAttr2(j + XY(0, i), 0x0);
+      j += XY(2, 0);
+    }
+  }
+}
+
+void ChangeDoorToSwitch() {  // 81c1ba
+  assert(dung_unk5 == 0);
+}
+
+void Dungeon_FlipCrystalPegAttribute() {  // 81c22a
+  for (int i = 0xfff; i >= 0; i--) {
+    if ((dung_bg2_attr_table[i] & ~1) == 0x66)
+      dung_bg2_attr_table[i] ^= 1;
+    if ((dung_bg1_attr_table[i] & ~1) == 0x66)
+      dung_bg1_attr_table[i] ^= 1;
+  }
+}
+
+void Dungeon_HandleRoomTags() {  // 81c2fd
+  if (!flag_skip_call_tag_routines) {
+    Dungeon_DetectStaircase();
+
+    // Dungeon_DetectStaircase might change the submodule, so avoid
+    // calling the tag routines cause they could also change the submodule,
+    // causing items to spawn in incorrect locations cause link_x/y_coord gets
+    // out of sync if you enter a staircase exactly when a room tag triggers.
+    if (enhanced_features0 & kFeatures0_MiscBugFixes && submodule_index != 0)
+      return;
+
+    g_ram[14] = 0;
+    kDungTagroutines[dung_hdr_tag[0]](0);
+    g_ram[14] = 1;
+    kDungTagroutines[dung_hdr_tag[1]](1);
+  }
+  flag_skip_call_tag_routines = 0;
+}
+
+void Dung_TagRoutine_0x00(int k) {  // 81c328
+}
+
+void Dungeon_DetectStaircase() {  // 81c329
+  int k = link_direction & 12;
+  if (!k)
+    return;
+
+  static const int8 kBuggyLookup[] = { 7, 24, 8, 8, 0, 0, -1, 17 };
+  int pos = ((link_y_coord + kBuggyLookup[k >> 1]) & 0x1f8) << 3;
+  pos |= (link_x_coord & 0x1f8) >> 3;
+  pos |= (link_is_on_lower_level ? 0x1000 : 0);
+
+  uint8 at = dung_bg2_attr_table[pos + (k == 4 ? 0x80 : 0)];
+  if (!(at == 0x26 || at == 0x38 || at == 0x39 || at == 0x5e || at == 0x5f))
+    return;
+
+  uint8 attr2 = dung_bg2_attr_table[pos + XY(0, 1)];
+  if ((attr2 & 0xf8) != 0x30)
+    return;
+
+  if (link_state_bits & 0x80) {
+    link_y_coord = link_y_coord_prev;
+    return;
+  }
+
+  which_staircase_index = attr2;
+  which_staircase_index_PADDING = pos >> 8; // residual
+  dungeon_room_index_prev = dungeon_room_index;
+  Dungeon_FlagRoomData_Quadrants();
+
+  if (at == 0x38 || at == 0x39) {
+    staircase_var1 = 0x20;
+    if (at == 0x38)
+      Dungeon_StartInterRoomTrans_Up();
+    else
+      Dungeon_StartInterRoomTrans_Down();
+  }
+
+  int j = (which_staircase_index & 3);
+  BYTE(dungeon_room_index) = dung_hdr_travel_destinations[j + 1];
+  cur_staircase_plane = dung_hdr_staircase_plane[j];
+  byte_7E0492 = (link_is_on_lower_level || link_is_on_lower_level_mirror) ? 2 : 0;
+  subsubmodule_index = 0;
+  bitmask_of_dragstate = 0;
+  link_delay_timer_spin_attack = 0;
+  button_mask_b_y = 0;
+  button_b_frames = 0;
+  link_cant_change_direction &= ~1;
+  if (at == 0x26) {
+    submodule_index = 6;
+    sound_effect_1 = (cur_staircase_plane < 0x34 ? 22 : 24); // wtf?
+  } else if (at == 0x38 || at == 0x39) {
+    submodule_index = (at == 0x38) ? 18 : 19;
+    link_timer_push_get_tired = 7;
+  } else {
+    UsedForStraightInterRoomStaircase();
+    submodule_index = 14;
+  }
+}
+
+void RoomTag_NorthWestTrigger(int k) {  // 81c432
+  if (!(link_x_coord & 0x100) && !(link_y_coord & 0x100))
+    RoomTag_QuadrantTrigger(k);
+}
+
+void Dung_TagRoutine_0x2A(int k) {  // 81c438
+  if ((link_x_coord & 0x100) && !(link_y_coord & 0x100))
+    RoomTag_QuadrantTrigger(k);
+}
+
+void Dung_TagRoutine_0x2B(int k) {  // 81c43e
+  if (!(link_x_coord & 0x100) && (link_y_coord & 0x100))
+    RoomTag_QuadrantTrigger(k);
+}
+
+void Dung_TagRoutine_0x2C(int k) {  // 81c444
+  if ((link_x_coord & 0x100) && (link_y_coord & 0x100))
+    RoomTag_QuadrantTrigger(k);
+}
+
+void Dung_TagRoutine_0x2D(int k) {  // 81c44a
+  if (!(link_x_coord & 0x100))
+    RoomTag_QuadrantTrigger(k);
+}
+
+void Dung_TagRoutine_0x2E(int k) {  // 81c450
+  if (link_x_coord & 0x100)
+    RoomTag_QuadrantTrigger(k);
+}
+
+void Dung_TagRoutine_0x2F(int k) {  // 81c456
+  if (!(link_y_coord & 0x100))
+    RoomTag_QuadrantTrigger(k);
+}
+
+void Dung_TagRoutine_0x30(int k) {  // 81c45c
+  if (link_y_coord & 0x100)
+    RoomTag_QuadrantTrigger(k);
+}
+
+void RoomTag_QuadrantTrigger(int k) {  // 81c461
+  uint8 tag = dung_hdr_tag[k];
+  if (tag >= 0xb) {
+    if (tag >= 0x29) {
+      if (Sprite_CheckIfScreenIsClear())
+        RoomTag_OperateChestReveal(k);
+    } else {
+      uint8 a = (dung_flag_movable_block_was_pushed ^ 1);
+      if (a != BYTE(dung_flag_trapdoors_down)) {
+        BYTE(dung_flag_trapdoors_down) = a;
+        sound_effect_2 = 37;
+        submodule_index = 5;
+        dung_cur_door_pos = 0;
+        door_animation_step_indicator = 0;
+      }
+    }
+  } else {
+    if (Sprite_CheckIfScreenIsClear())
+      Dung_TagRoutine_TrapdoorsUp();
+  }
+}
+
+void Dung_TagRoutine_TrapdoorsUp() {  // 81c49e
+  if (dung_flag_trapdoors_down) {
+    dung_flag_trapdoors_down = 0;
+    dung_cur_door_pos = 0;
+    door_animation_step_indicator = 0;
+    sound_effect_2 = 0x1b;
+    submodule_index = 5;
+  }
+}
+
+void RoomTag_RoomTrigger(int k) {  // 81c4bf
+  if (dung_hdr_tag[k] == 10) {
+    if (Sprite_CheckIfRoomIsClear())
+      Dung_TagRoutine_TrapdoorsUp();
+  } else {
+    if (Sprite_CheckIfRoomIsClear())
+      RoomTag_OperateChestReveal(k);
+  }
+}
+
+void RoomTag_RekillableBoss(int k) {  // 81c4db
+  if (Sprite_CheckIfRoomIsClear()) {
+    flag_block_link_menu = 0;
+    dung_hdr_tag[1] = 0;
+  }
+}
+
+void RoomTag_RoomTrigger_BlockDoor(int k) {  // 81c4e7
+  if (dung_flag_statechange_waterpuzzle && dung_flag_trapdoors_down) {
+    dung_flag_trapdoors_down = 0;
+    dung_cur_door_pos = 0;
+    door_animation_step_indicator = 0;
+    submodule_index = 5;
+  }
+}
+
+// Used for bosses
+void RoomTag_PrizeTriggerDoorDoor(int k) {  // 81c508
+  int t = savegame_is_darkworld ? link_has_crystals : link_which_pendants;
+  if (t & kDungeonCrystalPendantBit[BYTE(cur_palace_index_x2) >> 1]) {
+    dung_flag_trapdoors_down = 0;
+    dung_cur_door_pos = 0;
+    door_animation_step_indicator = 0;
+    submodule_index = 5;
+    dung_hdr_tag[k] = 0;
+  }
+}
+
+void RoomTag_SwitchTrigger_HoldDoor(int k) {  // 81c541
+  uint16 i = -2, v;
+  uint8 tmp;
+  for (;;) {
+    i += 2;
+    if (i == dung_index_of_torches_start)
+      break;
+    if (dung_replacement_tile_state[i >> 1] == 5) {
+      v = related_to_trapdoors_somehow;
+      if (v != 0xffff)
+        goto shortcut;
+      break;
+    }
+  }
+  v = !dung_flag_somaria_block_switch && !dung_flag_statechange_waterpuzzle && !RoomTag_CheckForPressedSwitch(&tmp);
+shortcut:
+  if (v != dung_flag_trapdoors_down) {
+    dung_flag_trapdoors_down = v;
+    dung_cur_door_pos = 0;
+    door_animation_step_indicator = 0;
+    if (v == 0)
+      sound_effect_2 = 0x25;
+    submodule_index = 5;
+  }
+}
+
+void RoomTag_SwitchTrigger_ToggleDoor(int k) {  // 81c599
+  uint8 attr;
+  if (!dung_door_switch_triggered) {
+    if (RoomTag_MaybeCheckShutters(&attr)) {
+      dung_cur_door_pos = 0;
+      door_animation_step_indicator = 0;
+      sound_effect_2 = 0x25;
+      PushPressurePlate(attr);
+      dung_flag_trapdoors_down ^= 1;
+      dung_door_switch_triggered = 1;
+    }
+  } else {
+    if (!RoomTag_MaybeCheckShutters(&attr))
+      dung_door_switch_triggered = 0;
+  }
+}
+
+void PushPressurePlate(uint8 attr) {  // 81c5cf
+  submodule_index = 5;
+  if (attr == 0x23 || !word_7E04B6)
+    return;
+  saved_module_for_menu = submodule_index;
+  submodule_index = 23;
+  subsubmodule_index = 32;
+  link_y_coord += 2;
+  if ((WORD(dung_bg2_attr_table[word_7E04B6]) & 0xfe00) != 0x2400)
+    word_7E04B6++;
+  Dungeon_UpdateTileMapWithCommonTile((word_7E04B6 & 0x3f) << 3, (word_7E04B6 >> 3) & 0x1f8, 0x10);
+}
+
+void RoomTag_TorchPuzzleDoor(int k) {  // 81c629
+  int j = 0;
+  for (int i = 0; i < 16; i++)
+    if (dung_object_tilemap_pos[i] & 0x8000)
+      j++;
+  int down = (j < 4);
+  if (down != dung_flag_trapdoors_down) {
+    dung_flag_trapdoors_down = down;
+    dung_cur_door_pos = 0;
+    door_animation_step_indicator = 0;
+    sound_effect_2 = 0x1b;
+    submodule_index = 5;
+  }
+}
+
+void RoomTag_Switch_ExplodingWall(int k) {  // 81c67a
+  uint8 yv;
+  if (!RoomTag_MaybeCheckShutters(&yv))
+    return;
+
+  Dung_TagRoutine_BlastWallStuff(k);
+}
+
+void RoomTag_PullSwitchExplodingWall(int k) {  // 81c685
+  if (!dung_flag_statechange_waterpuzzle)
+    return;
+  Dung_TagRoutine_BlastWallStuff(k);
+}
+
+void Dung_TagRoutine_BlastWallStuff(int k) {  // 81c68c
+  static const uint8 kBlastWall_Tab0[5] = { 4, 6, 0, 0, 2 };
+  static const uint16 kBlastWall_Tab1[5] = { 0, 0xa, 0, 0, 0x280 };
+
+  dung_hdr_tag[k] = 0;
+
+  int j = -1;
+  do {
+    j++;
+  } while ((door_type_and_slot[j] & ~1) != 0x30);
+  dung_unk_blast_walls_3 = j * 2;
+
+  int i = ((link_y_coord >> 8 & 1) + 1) * 2;
+  if (dung_door_direction[j] & 2)
+    i = (link_x_coord >> 8 & 1);
+
+  messaging_buf[0x1c / 2] = kBlastWall_Tab0[i];
+  j = dung_door_tilemap_address[j] + kBlastWall_Tab1[i];
+
+  messaging_buf[0x1a / 2] = (j & 0x7e) * 4 + dung_loade_bgoffs_h_copy;
+  messaging_buf[0x18 / 2] = ((j & 0x1f80) >> 4) + dung_loade_bgoffs_v_copy;
+  sound_effect_2 = 27;
+  BYTE(dung_unk_blast_walls_2) = 1;
+  AncillaAdd_BlastWall();
+}
+
+// Used for bosses
+void RoomTag_GetHeartForPrize(int k) {  // 81c709
+  static const uint8 kBossFinishedFallingItem[13] = { 0, 0, 1, 2, 0, 6, 6, 6, 6, 6, 3, 6, 6 };
+  if (!(dung_savegame_state_bits & 0x8000))
+    return;
+  int t = savegame_is_darkworld ? link_has_crystals : link_which_pendants;
+  if (!(t & kDungeonCrystalPendantBit[BYTE(cur_palace_index_x2) >> 1])) {
+    byte_7E04C2 = 128;
+    if (Ancilla_SpawnFallingPrize(kBossFinishedFallingItem[BYTE(cur_palace_index_x2) >> 1]) < 0)
+      return; // Zelda bugfix. Price won't spawn if we're out of ancillas
+  }
+  dung_hdr_tag[k] = 0;
+}
+
+void RoomTag_Agahnim(int k) {  // 81c74e
+  if (!(save_ow_event_info[0x5b] & 0x20) && dung_savegame_state_bits & 0x8000) {
+    Palette_RevertTranslucencySwap();
+    dung_hdr_tag[0] = 0;
+    PrepareDungeonExitFromBossFight();
+  }
+}
+
+void RoomTag_GanonDoor(int tagidx) {  // 81c767
+  for (int k = 15; k >= 0; k--) {
+    if (sprite_state[k] == 4 || !(sprite_flags4[k] & 64) && sprite_state[k])
+      return;
+  }
+  if (link_player_handler_state != kPlayerState_FallingIntoHole) {
+    flag_is_link_immobilized = 26;
+    submodule_index = 26;
+    subsubmodule_index = 0;
+    dung_hdr_tag[0] = 0;
+    link_force_hold_sword_up = 1;
+    button_mask_b_y = 0;
+    button_b_frames = 0;
+    R16 = 0x364;
+  }
+}
+
+void RoomTag_KillRoomBlock(int k) {  // 81c7a2
+  if (link_x_coord & 0x100 && link_y_coord & 0x100) {
+    if (Sprite_CheckIfScreenIsClear()) {
+      sound_effect_2 = 0x1b;
+      dung_hdr_tag[k] = 0;
+    }
+  }
+}
+
+void RoomTag_PushBlockForChest(int k) {  // 81c7c2
+  if (!nmi_load_bg_from_vram && dung_flag_movable_block_was_pushed)
+    RoomTag_OperateChestReveal(k);
+}
+
+void RoomTag_TriggerChest(int k) {  // 81c7cc
+  uint8 attr;
+  if (!countdown_for_blink && RoomTag_MaybeCheckShutters(&attr))
+    RoomTag_OperateChestReveal(k);
+}
+
+void RoomTag_OperateChestReveal(int k) {  // 81c7d8
+  dung_hdr_tag[k] = 0;
+  vram_upload_offset = 0;
+  WORD(overworld_map_state) = 0;
+  uint16 attr = 0x5858;
+  do {
+    int pos = dung_chest_locations[WORD(overworld_map_state) >> 1] >> 1 & 0x1fff;
+
+    WORD(dung_bg2_attr_table[pos + XY(0, 0)]) = attr;
+    WORD(dung_bg2_attr_table[pos + XY(0, 1)]) = attr;
+    attr += 0x101;
+
+    const uint16 *src = SrcPtr(0x149c);
+    dung_bg2[pos + XY(0, 0)] = src[0];
+    dung_bg2[pos + XY(0, 1)] = src[1];
+    dung_bg2[pos + XY(1, 0)] = src[2];
+    dung_bg2[pos + XY(1, 1)] = src[3];
+
+    uint16 yy = WORD(overworld_map_state);
+
+    uint16 *dst = &vram_upload_data[vram_upload_offset >> 1];
+    dst[0] = RoomTag_BuildChestStripes(XY(0, 0) * 2, yy);
+    dst[3] = RoomTag_BuildChestStripes(XY(0, 1) * 2, yy);
+    dst[6] = RoomTag_BuildChestStripes(XY(1, 0) * 2, yy);
+    dst[9] = RoomTag_BuildChestStripes(XY(1, 1) * 2, yy);
+
+    dst[2] = src[0];
+    dst[5] = src[1];
+    dst[8] = src[2];
+    dst[11] = src[3];
+
+    dst[1] = 0x100;
+    dst[4] = 0x100;
+    dst[7] = 0x100;
+    dst[10] = 0x100;
+
+    dst[12] = 0xffff;
+
+    vram_upload_offset += 24;
+    WORD(overworld_map_state) += 2;
+  } while (WORD(overworld_map_state) != dung_num_chests_x2);
+  WORD(overworld_map_state) = 0;
+  sound_effect_2 = 26;
+  nmi_load_bg_from_vram = 1;
+}
+
+void RoomTag_TorchPuzzleChest(int k) {  // 81c8ae
+  int j = 0;
+  for (int i = 0; i < 16; i++)
+    if (dung_object_tilemap_pos[i] & 0x8000)
+      j++;
+  if (j >= 4)
+    RoomTag_OperateChestReveal(k);
+}
+
+void RoomTag_MovingWall_East(int k) {  // 81c8d4
+  static const int16 kMovingWall_Tab1[8] = { -63, -127, -191, -255, -71, -135, -199, -263 };
+
+  if (!dung_floor_move_flags) {
+    RoomTag_MovingWallTorchesCheck(k);
+    dung_floor_x_vel = 0;
+  } else {
+    flag_unk1 = 1;
+    RoomTag_MovingWallShakeItUp(k);
+    dung_floor_x_vel = MovingWall_MoveALittle();
+  }
+  dung_floor_x_offs -= dung_floor_x_vel;
+  BG1HOFS_copy2 = BG2HOFS_copy2 + dung_floor_x_offs;
+
+  if (dung_floor_x_vel) {
+    if (dung_floor_x_offs < (uint16)kMovingWall_Tab1[moving_wall_var2 >> 1] &&
+        dung_floor_x_offs < (uint16)kMovingWall_Tab1[RoomTag_AdvanceGiganticWall(k) >> 1]) {
+      sound_effect_2 = 0x1b;
+      sound_effect_ambient = 5;
+      dung_hdr_tag[k] = 0;
+      flag_is_link_immobilized = 0;
+      flag_unk1 = 0;
+      bg1_x_offset = bg1_y_offset = 0;
+    }
+    nmi_subroutine_index = 5;
+    nmi_load_target_addr = (moving_wall_var1 - ((-dung_floor_x_offs & 0x1f8) >> 3)) & 0x141f;
+  }
+}
+
+void RoomTag_MovingWallShakeItUp(int k) {  // 81c969
+  int i = frame_counter & 1;
+  bg1_x_offset = i ? -1 : 1;
+  bg1_y_offset = -bg1_x_offset;
+  if (!dung_hdr_tag[k])
+    bg1_x_offset = bg1_y_offset = 0;
+}
+
+void RoomTag_MovingWall_West(int k) {  // 81c98b
+  static const uint16 kMovingWall_Tab0[8] = { 0x42, 0x82, 0xc2, 0x102, 0x4a, 0x8a, 0xca, 0x10a };
+
+  if (!dung_floor_move_flags) {
+    RoomTag_MovingWallTorchesCheck(k);
+    dung_floor_x_vel = 0;
+  } else {
+    flag_unk1 = 1;
+    RoomTag_MovingWallShakeItUp(k);
+    dung_floor_x_vel = MovingWall_MoveALittle();
+  }
+  dung_floor_x_offs += dung_floor_x_vel;
+  BG1HOFS_copy2 = BG2HOFS_copy2 + dung_floor_x_offs;
+  if (dung_floor_x_vel) {
+    if (dung_floor_x_offs >= kMovingWall_Tab0[moving_wall_var2 >> 1] &&
+        dung_floor_x_offs >= kMovingWall_Tab0[RoomTag_AdvanceGiganticWall(k) >> 1]) {
+      sound_effect_2 = 0x1b;
+      sound_effect_ambient = 5;
+      dung_hdr_tag[k] = 0;
+      flag_is_link_immobilized = 0;
+      flag_unk1 = 0;
+      bg1_x_offset = bg1_y_offset = 0;
+    }
+    nmi_subroutine_index = 5;
+    nmi_load_target_addr = moving_wall_var1 + ((dung_floor_x_offs & 0x1f8) >> 3);
+    if (nmi_load_target_addr & 0x1020)
+      nmi_load_target_addr = (nmi_load_target_addr & 0x1020) ^ 0x420;
+  }
+}
+
+void RoomTag_MovingWallTorchesCheck(int k) {  // 81ca17
+  if (!dung_flag_statechange_waterpuzzle) {
+    int count = 0;
+    for (int i = 0; i < 16; i++)
+      count += (dung_object_tilemap_pos[i] & 0x8000) != 0;
+    if (count < 4)
+      return;
+  }
+  dung_floor_move_flags++;
+  WORD(dung_flag_statechange_waterpuzzle) = 0;
+  dung_savegame_state_bits |= 0x1000 >> k;
+  sound_effect_ambient = 7;
+  flag_is_link_immobilized = 1;
+  flag_unk1 = 1;
+}
+
+int MovingWall_MoveALittle() {  // 81ca66
+  int t = dung_some_subpixel[1] + 0x22;
+  dung_some_subpixel[1] = t;
+  return t >> 8;
+}
+
+int RoomTag_AdvanceGiganticWall(int k) {  // 81ca75
+  int i = moving_wall_var2;
+  if (dung_hdr_tag[k] < 0x20) {
+    dung_hdr_collision = 0;
+    TM_copy = 0x16;
+    i += 8;
+  }
+  return i;
+}
+
+void RoomTag_WaterOff(int k) {  // 81ca94
+  if (dung_flag_statechange_waterpuzzle) {
+    W12SEL_copy = 3;
+    W34SEL_copy = 0;
+    WOBJSEL_copy = 0;
+    TMW_copy = 22;
+    TSW_copy = 1;
+    turn_on_off_water_ctr = 1;
+    AdjustWaterHDMAWindow();
+    submodule_index = 11;
+    palette_filter_countdown = 0;
+    darkening_or_lightening_screen = 0;
+    mosaic_target_level = 31;
+    flag_update_cgram_in_nmi++;
+    dung_hdr_tag[1] = 0;
+    dung_savegame_state_bits |= 0x800;
+    dung_flag_statechange_waterpuzzle = 0;
+    int dsto = ((water_hdma_var1 & 0x1ff) - 0x10) << 3 | ((water_hdma_var0 & 0x1ff) - 0x10) >> 3;
+    DrawWaterThing(&dung_bg2[dsto], SrcPtr(0x1438));
+    Dungeon_PrepOverlayDma_nextPrep(0, dsto * 2);
+    sound_effect_2 = 0x1b;
+    sound_effect_1 = 0x2e;
+    nmi_copy_packets_flag = 1;
+  }
+}
+
+void RoomTag_WaterOn(int k) {  // 81cb1a
+  if (dung_flag_statechange_waterpuzzle) {
+    sound_effect_2 = 0x1b;
+    sound_effect_1 = 0x2f;
+    submodule_index = 12;
+    subsubmodule_index = 0;
+    BYTE(dung_floor_y_offs) = 1;
+    dung_hdr_tag[1] = 0;
+    dung_savegame_state_bits |= 0x800;
+    dung_flag_statechange_waterpuzzle = 0;
+    dung_cur_quadrant_upload = 0;
+  }
+}
+
+void RoomTag_WaterGate(int k) {  // 81cb49
+  if (dung_savegame_state_bits & 0x800 || !dung_flag_statechange_waterpuzzle)
+    return;
+  submodule_index = 13;
+  subsubmodule_index = 0;
+  dung_hdr_tag[1] = 0;
+  dung_savegame_state_bits |= 0x800;
+  dung_flag_statechange_waterpuzzle = 0;
+  BYTE(water_hdma_var2) = 0;
+  BYTE(spotlight_var4) = 0;
+  W12SEL_copy = 3;
+  W34SEL_copy = 0;
+  WOBJSEL_copy = 0;
+  TMW_copy = 0x16;
+  TSW_copy = 1;
+  CGWSEL_copy = 2;
+  CGADSUB_copy = 0x62;
+  save_ow_event_info[0x3b] |= 32;
+  save_ow_event_info[0x7b] |= 32;
+  save_dung_info[0x28] |= 0x100;
+  RoomTag_OperateWaterFlooring();
+  water_hdma_var0 = ((watergate_pos & 0x7e) << 2) + (dung_draw_width_indicator * 16 + dung_loade_bgoffs_h_copy + 40);
+  word_7E0678 = spotlight_y_upper = (watergate_pos & 0x1f80) >> 4;
+  water_hdma_var1 = word_7E0678 + dung_loade_bgoffs_v_copy;
+  water_hdma_var3 = 0;
+  sound_effect_2 = 0x1b;
+  sound_effect_1 = 0x2f;
+}
+
+void Dung_TagRoutine_0x1B(int k) {  // 81cbff
+  // empty
+}
+
+void RoomTag_Holes0(int k) {  // 81cc00
+  Dung_TagRoutine_Func2(1);
+}
+
+void Dung_TagRoutine_0x23(int k) {  // 81cc04
+  Dung_TagRoutine_Func2(3);
+}
+
+void Dung_TagRoutine_0x34(int k) {  // 81cc08
+  Dung_TagRoutine_Func2(6);
+}
+
+void Dung_TagRoutine_0x35(int k) {  // 81cc0c
+  Dung_TagRoutine_Func2(8);
+}
+
+void Dung_TagRoutine_0x36(int k) {  // 81cc10
+  Dung_TagRoutine_Func2(10);
+}
+
+void Dung_TagRoutine_0x37(int k) {  // 81cc14
+  Dung_TagRoutine_Func2(12);
+}
+
+void Dung_TagRoutine_0x39(int k) {  // 81cc18
+  Dung_TagRoutine_Func2(14);
+}
+
+void Dung_TagRoutine_0x3A(int k) {  // 81cc1c
+  Dung_TagRoutine_Func2(16);
+}
+
+void Dung_TagRoutine_Func2(uint8 av) {  // 81cc1e
+  uint8 yv;
+  if (!dung_overlay_to_load)
+    dung_overlay_to_load = av;
+
+  if (RoomTag_CheckForPressedSwitch(&yv) && (av += yv) != dung_overlay_to_load) {
+    dung_overlay_to_load = av;
+    dung_load_ptr_offs = 0;
+    subsubmodule_index = 0;
+    sound_effect_2 = 27;
+    submodule_index = 3;
+    byte_7E04BC ^= 1;
+    Dungeon_RestoreStarTileChr();
+  }
+}
+
+void RoomTag_ChestHoles0(int k) {  // 81cc5b
+  Dung_TagRoutine_0x22_0x3B(k, 0x0);
+}
+
+void Dung_TagRoutine_0x3B(int k) {  // 81cc62
+  Dung_TagRoutine_0x22_0x3B(k, 0x12);
+}
+
+void RoomTag_Holes2(int k) {  // 81cc89
+  uint8 yv;
+
+  if (!RoomTag_CheckForPressedSwitch(&yv))
+    return;
+
+  dung_hdr_tag[k] = 0;
+  dung_overlay_to_load = 5;
+  dung_load_ptr_offs = 0;
+  subsubmodule_index = 0;
+  sound_effect_2 = 0x1b;
+  submodule_index = 3;
+}
+
+void RoomTag_OperateWaterFlooring() {  // 81cc95
+  dung_load_ptr_offs = 0;
+  const uint8 *layoutsrc = kWatergateLayout;
+  for (;;) {
+    dung_draw_width_indicator = 0;
+    dung_draw_height_indicator = 0;
+    uint16 t = WORD(*layoutsrc);
+    if (t == 0xffff)
+      break;
+    dung_draw_width_indicator = (t & 3) + 1;
+    dung_draw_height_indicator = (t >> 8 & 3) + 1;
+    dung_load_ptr_offs += 3, layoutsrc += 3;
+    const uint16 *src = SrcPtr(0x110);
+    int dsto2 = (t & 0xfc) >> 2 | (t >> 10) << 6;
+    do {
+      int dsto = dsto2;
+      int n = dung_draw_width_indicator;
+      do {
+        int nn = 2;
+        do {
+          dung_bg1[dsto + XY(0, 0)] = src[0];
+          dung_bg1[dsto + XY(1, 0)] = src[1];
+          dung_bg1[dsto + XY(2, 0)] = src[2];
+          dung_bg1[dsto + XY(3, 0)] = src[3];
+          dung_bg1[dsto + XY(0, 1)] = src[4];
+          dung_bg1[dsto + XY(1, 1)] = src[5];
+          dung_bg1[dsto + XY(2, 1)] = src[6];
+          dung_bg1[dsto + XY(3, 1)] = src[7];
+          dsto += XY(0, 2);
+        } while (--nn);
+        dsto += XY(4, -4);
+      } while (--n);
+      dsto2 += XY(0, 4);
+    } while (--dung_draw_height_indicator);
+  }
+}
+
+bool RoomTag_MaybeCheckShutters(uint8 *attr_out) {  // 81cd39
+  int p, t;
+  word_7E04B6 = 0;
+  if (flag_is_link_immobilized || link_auxiliary_state)
+    return false;
+  p = RoomTag_GetTilemapCoords();
+  t = WORD(dung_bg2_attr_table[p]);
+  if (t == 0x2323 || t == 0x2424)
+    goto done;
+  t = WORD(dung_bg2_attr_table[p += 64]);
+  if (t == 0x2323 || t == 0x2424)
+    goto done;
+  t = WORD(dung_bg2_attr_table[p -= 63]);
+  if (t == 0x2323 || t == 0x2424)
+    goto done;
+  t = WORD(dung_bg2_attr_table[p += 64]);
+  if (t == 0x2323 || t == 0x2424)
+    goto done;
+  return false;
+done:
+  if (t != WORD(dung_bg2_attr_table[p + 64]))
+    return false;
+  *attr_out = t;
+  word_7E04B6 = p;
+  return true;
+}
+
+int RoomTag_GetTilemapCoords() {  // 81cda5
+  return ((link_x_coord - 1) & 0x1f8) >> 3 | ((link_y_coord + 14) & 0x1f8) << 3 | (link_is_on_lower_level ? 0x1000 : 0);
+
+}
+
+bool RoomTag_CheckForPressedSwitch(uint8 *y_out) {  // 81cdcc
+  int p, t;
+  word_7E04B6 = 0;
+  if (flag_is_link_immobilized || link_auxiliary_state)
+    return false;
+  p = RoomTag_GetTilemapCoords();
+  t = WORD(dung_bg2_attr_table[p]);
+  if (t == 0x2323 || t == 0x3a3a || t == 0x3b3b)
+    goto done;
+  t = WORD(dung_bg2_attr_table[p += 64]);
+  if (t == 0x2323 || t == 0x3a3a || t == 0x3b3b)
+    goto done;
+  t = WORD(dung_bg2_attr_table[p -= 63]);
+  if (t == 0x2323 || t == 0x3a3a || t == 0x3b3b)
+    goto done;
+  t = WORD(dung_bg2_attr_table[p += 64]);
+  if (t == 0x2323 || t == 0x3a3a || t == 0x3b3b)
+    goto done;
+  return false;
+done:
+  if (t != WORD(dung_bg2_attr_table[p + 64]))
+    return false;
+  *y_out = (t == 0x3b3b);
+  word_7E04B6 = p;
+  return true;
+}
+
+void Dungeon_ProcessTorchesAndDoors() {  // 81ce70
+  static const int16 kDungLinkOffs1X[] = { 0, 0, -1, 17 };
+  static const int16 kDungLinkOffs1Y[] = { 7, 24, 8, 8 };
+  static const uint16 kDungLinkOffs1Pos[] = { 0x2, 0x2, 0x80, 0x80 };
+
+  if ((frame_counter & 3) == 0 && !flag_custom_spell_anim_active) {
+    for (int i = 0; i != 16; i++) {
+      if (dung_torch_timers[i] && !--dung_torch_timers[i]) {
+        byte_7E0333 = 0xc0 + i;
+        Dungeon_ExtinguishTorch();
+      }
+    }
+  }
+
+  if (!flag_is_link_immobilized) {
+    int dir = link_direction_facing >> 1;
+    int pos = ((link_y_coord + kDungLinkOffs1Y[dir]) & 0x1f8) << 3;
+    pos |= ((link_x_coord + kDungLinkOffs1X[dir]) & 0x1f8) >> 3;
+    pos |= (link_is_on_lower_level ? 0x1000 : 0);
+
+    if ((dung_bg2_attr_table[pos] & 0xf0) == 0xf0 ||
+        (dung_bg2_attr_table[pos += kDungLinkOffs1Pos[dir]] & 0xf0) == 0xf0) {
+      int k = dung_bg2_attr_table[pos] & 0xf;
+      dung_which_key_x2 = 2 * k;
+
+      if ((dung_door_direction[k] & 3) != dir)
+        goto not_openable;
+
+      uint8 door_type = door_type_and_slot[k] & 0xfe;
+      if (door_type == kDoorType_BreakableWall) {
+        if (link_is_running && link_dash_ctr < 63) {
+          dung_cur_door_pos = pos;
+
+          int db = AncillaAdd_DoorDebris();
+          if (db >= 0) {
+            door_debris_direction[db] = dung_door_direction[k] & 3;
+            door_debris_x[db] = dung_loade_bgoffs_h_copy + (dung_door_tilemap_address[k] & 0x7e) * 4;
+            door_debris_y[db] = dung_loade_bgoffs_v_copy + ((dung_door_tilemap_address[k] & 0x1f80) >> 4);
+          }
+          sound_effect_2 = 27;
+          submodule_index = 9;
+          Sprite_RepelDash();
+          return;
+        }
+      } else if (door_type == kDoorType_1E) {
+        door_animation_step_indicator = 0;
+        dung_cur_door_pos = pos;
+        if (link_bigkey & kUpperBitmasks[cur_palace_index_x2 >> 1])
+          goto has_key_for_door;
+        if (!big_key_door_message_triggered) {
+          big_key_door_message_triggered = 1;
+          dialogue_message_index = 0x7a;
+          Main_ShowTextMessage();
+        }
+      } else if (door_type >= kDoorType_SmallKeyDoor && door_type < 0x2c && door_type != 0x2a && link_num_keys != 0) {
+        link_num_keys -= 1;
+has_key_for_door:
+        door_animation_step_indicator = 0;
+        dung_cur_door_pos = pos;
+        submodule_index = 4;
+        static const uint8 kOpenDoorPanning[] = { 0x0, 0x0, 0x80, 0x40 };
+        sound_effect_2 = 20 | kOpenDoorPanning[dung_door_direction[k] & 3];
+        return;
+      }
+    } else {
+not_openable:
+      big_key_door_message_triggered = 0;
+    }
+  }
+
+  if (!(invisible_door_dir_and_index_x2 & 0x80) && !is_standing_in_doorway && (link_x_coord >> 8) == 0xc) {
+    uint8 dir = invisible_door_dir_and_index_x2;
+    int j = (invisible_door_dir_and_index_x2 >> 8) >> 1;
+    uint16 m = dung_door_opened_incl_adjacent;
+    if (dir != link_direction_facing && (dir ^ 2) == link_direction_facing)
+      m |= kUpperBitmasks[j];
+    else
+      m &= ~kUpperBitmasks[j];
+    if (m != dung_door_opened_incl_adjacent) {
+      dung_door_opened_incl_adjacent = m;
+      DrawEyeWatchDoor(j);
+      Dungeon_PrepOverlayDma_nextPrep(0, dung_door_tilemap_address[j]);
+      Dungeon_LoadToggleDoorAttr_OtherEntry(j);
+      nmi_copy_packets_flag = 1;
+      sound_effect_2 = 21;
+      return;
+    }
+  }
+
+  if (!(button_mask_b_y & 0x80) || button_b_frames != 4)
+    return;
+
+  int pos = ((link_y_coord + (int8)player_oam_y_offset) & 0x1f8) << 3;
+  pos |= ((link_x_coord + (int8)player_oam_x_offset) & 0x1f8) >> 3;
+  uint8 attr, y;
+
+#define is_6c_fx(yv,x) (y=yv, ((attr = (dung_bg2_attr_table[x] & 0xfc)) == 0x6c || (attr & 0xf0) == 0xf0))
+
+  if (!(is_6c_fx(0x41, pos) || is_6c_fx(0x40, pos += 1) || is_6c_fx(1, pos += 63) || is_6c_fx(0, pos += 1)))
+    return;
+
+  int addr;
+
+  if (attr == 0x6c) {
+    if (y & 0x40 && (dung_bg2_attr_table[pos -= 64] & 0xfc) != 0x6c)
+      pos += 64;
+    if (y & 1 && (dung_bg2_attr_table[pos -= 1] & 0xfc) != 0x6c)
+      pos += 1;
+    attr = dung_bg2_attr_table[pos];
+    WriteAttr2(pos + XY(0, 0), 0x202);
+    WriteAttr2(pos + XY(0, 1), 0x202);
+    static const uint16 kSrcTiles1[] = { 0x7ea, 0x80a, 0x80a, 0x82a };
+    addr = (pos - XY(1, 1)) * 2;
+    RoomDraw_Object_Nx4(4, SrcPtr(kSrcTiles1[attr & 3]), &dung_bg2[addr >> 1]);
+  } else {
+    dung_cur_door_pos = pos;
+    int k = attr & 0xf;
+
+    uint8 door_type = door_type_and_slot[k];
+    if (door_type != kDoorType_Slashable)
+      return;
+    sound_effect_2 = 27;
+    addr = dung_door_tilemap_address[k];
+    dung_door_opened_incl_adjacent |= kUpperBitmasks[k];
+    dung_door_opened |= kUpperBitmasks[k];
+    door_open_closed_counter = 0;
+    dung_cur_door_idx = k * 2;
+    dung_which_key_x2 = k * 2;
+    RoomDraw_Object_Nx4(4, SrcPtr(kDoorTypeSrcData[0x56 / 2]), &dung_bg2[addr >> 1]);
+    Dungeon_LoadToggleDoorAttr_OtherEntry(k);
+  }
+
+  Dungeon_PrepOverlayDma_nextPrep(0, addr);
+  sound_effect_1 = 30 | CalculateSfxPan_Arbitrary((addr & 0x7f) * 2);
+  nmi_copy_packets_flag = 1;
+}
+
+void Bomb_CheckForDestructibles(uint16 x, uint16 y, uint8 r14) {  // 81d1f4
+  if (main_module_index != 7) {
+    Overworld_BombTiles32x32(x, y);
+    return;
+  }
+  int k = ((y & 0x1f8) << 3 | (x & 0x1f8) >> 3) - 0x82;
+  uint8 a;
+  for (int i = 2; i >= 0; i--) {
+    a = dung_bg2_attr_table[k];
+    if (a == 0x62) {
+handle_62:
+      if (dungeon_room_index == 0x65)
+        dung_savegame_state_bits |= 0x1000;
+      Point16U pt;
+      printf("Wtf is R6\n");
+      ThievesAttic_DrawLightenedHole(0, 0, &pt);
+      sound_effect_2 = 0x1b;
+      return;
+    }
+    if ((a & 0xf0) == 0xf0) {
+      int j;
+handle_f0:
+      j = a & 0xf;
+      a = door_type_and_slot[j] & 0xfe;
+      if (a != kDoorType_BreakableWall && a != 0x2A && a != 0x2E)
+        return;
+      dung_cur_door_pos = k;
+      door_debris_x[r14] = ((dung_door_tilemap_address[j] & 0x7e) << 2) + dung_loade_bgoffs_h_copy;
+      door_debris_y[r14] = ((dung_door_tilemap_address[j] & 0x1f80) >> 4) + dung_loade_bgoffs_v_copy;
+      door_debris_direction[r14] = dung_door_direction[j] & 3;
+      sound_effect_2 = 0x1b;
+      submodule_index = 9;
+      return;
+    }
+
+    a = dung_bg2_attr_table[k += 2];
+    if (a == 0x62) goto handle_62;
+    if ((a & 0xf0) == 0xf0) goto handle_f0;
+
+    a = dung_bg2_attr_table[k += 2];
+    if (a == 0x62) goto handle_62;
+    if ((a & 0xf0) == 0xf0) goto handle_f0;
+
+    k += 0x7c;
+  }
+
+}
+
+int DrawDoorOpening_Step1(int door, int dma_ptr) {  // 81d2e8
+  dung_cur_door_idx = door * 2;
+  dung_which_key_x2 = door * 2;
+  switch (dung_door_direction[door] & 3) {
+  case 0: return DoorDoorStep1_North(door, dma_ptr);
+  case 1: return DoorDoorStep1_South(door, dma_ptr);
+  case 2: return DoorDoorStep1_West(door, dma_ptr);
+  case 3: return DoorDoorStep1_East(door, dma_ptr);
+  }
+  return 0;
+}
+
+void DrawShutterDoorSteps(int door) {  // 81d311
+  dung_cur_door_idx = door * 2;
+  dung_which_key_x2 = door * 2;
+  switch (dung_door_direction[door] & 3) {
+  case 0: GetDoorDrawDataIndex_North_clean_door_index(door); break;
+  case 1: GetDoorDrawDataIndex_South_clean_door_index(door); break;
+  case 2: GetDoorDrawDataIndex_West_clean_door_index(door); break;
+  case 3: GetDoorDrawDataIndex_East_clean_door_index(door); break;
+  }
+}
+
+void DrawEyeWatchDoor(int door) {  // 81d33a
+  dung_cur_door_idx = door * 2;
+  dung_which_key_x2 = door * 2;
+  switch (dung_door_direction[door] & 3) {
+  case 0: DrawDoorToTileMap_North(door, door); break;
+  case 1: DrawDoorToTileMap_South(door, door); break;
+  case 2: DrawDoorToTileMap_West(door, door); break;
+  case 3: DrawDoorToTileMap_East(door, door); break;
+  }
+}
+
+void Door_BlastWallExploding_Draw(int dsto) {  // 81d373
+  uint16 *dst = &dung_bg2[dsto];
+  const uint16 *src = SrcPtr(0x31ea);
+  ClearExplodingWallFromTileMap_ClearOnePair(dst, src);
+  dst += 2;
+  uint16 v = src[24];
+  for (int n = dung_unk_blast_walls_2 - 1; n; n--) {
+    for (int j = 0; j < 12; j++)
+      dst[XY(0, j)] = v;
+    dst++;
+  }
+  ClearExplodingWallFromTileMap_ClearOnePair(dst, src + 25);
+}
+
+void OperateShutterDoors() {  // 81d38f
+  int anim_dst = 0;
+  uint8 y = 2;
+
+  if (++door_animation_step_indicator != 4) {
+    y = dung_flag_trapdoors_down ? 0 : 4;
+    if (door_animation_step_indicator != 8)
+      goto getout;
+  }
+  door_open_closed_counter = y;
+
+  for (dung_cur_door_pos = 0; dung_cur_door_pos != 0x18; dung_cur_door_pos += 2) {
+    int j = dung_cur_door_pos >> 1;
+    uint8 door_type = door_type_and_slot[j] & 0xfe;
+    if (door_type != kDoorType_Shutter && door_type != kDoorType_ShuttersTwoWay)
+      continue;
+
+    int mask = kUpperBitmasks[j];
+    if (!dung_flag_trapdoors_down) {
+      if (dung_door_opened_incl_adjacent & mask)
+        continue;
+      if (door_animation_step_indicator == 8) {
+        sound_effect_2 = 21;
+        dung_door_opened_incl_adjacent ^= mask;
+      }
+    } else {
+      if (!(dung_door_opened_incl_adjacent & mask))
+        continue;
+      if (door_animation_step_indicator == 8) {
+        sound_effect_2 = 22;
+        dung_door_opened_incl_adjacent ^= mask;
+      }
+    }
+    DrawShutterDoorSteps(j);
+    anim_dst = Dungeon_PrepOverlayDma_nextPrep(anim_dst, dung_door_tilemap_address[j]);
+    if (door_animation_step_indicator == 8)
+      Dungeon_LoadToggleDoorAttr_OtherEntry(j);
+  }
+  dung_cur_door_pos -= 2;
+
+  if (anim_dst != 0) {
+    nmi_disable_core_updates = nmi_copy_packets_flag = 1;
+getout:
+    if (BYTE(door_animation_step_indicator) != 0x10)
+      return;
+  }
+  submodule_index = 0;
+  nmi_copy_packets_flag = 0;
+}
+
+void OpenCrackedDoor() {  // 81d469
+  Dungeon_OpeningLockedDoor_Combined(true);
+}
+
+void Dungeon_LoadToggleDoorAttr_OtherEntry(int door) {  // 81d51c
+  Dungeon_LoadSingleDoorAttribute(door);
+  Dungeon_LoadSingleDoorTileAttribute();
+}
+
+void Dungeon_LoadSingleDoorTileAttribute() {  // 81d51f
+  for (int i = 0; i != dung_num_toggle_floor; i += 2) {
+    int j = dung_toggle_floor_pos[i >> 1];
+    if ((dung_bg2_attr_table[j] & 0xf0) == 0x80) {
+      uint16 attr = *(uint16 *)&dung_bg2_attr_table[j];
+      WriteAttr2(j + XY(0, 0), attr | 0x1010);
+      WriteAttr2(j + XY(0, 1), attr | 0x1010);
+    } else {
+      uint16 attr = *(uint16 *)&dung_bg1_attr_table[j];
+      WriteAttr1(j + XY(0, 0), attr | 0x1010);
+      WriteAttr1(j + XY(0, 1), attr | 0x1010);
+    }
+  }
+  for (int i = 0; i != dung_num_toggle_palace; i += 2) {
+    int j = dung_toggle_palace_pos[i >> 1];
+    if ((dung_bg2_attr_table[j] & 0xf0) == 0x80) {
+      uint16 attr = *(uint16 *)&dung_bg2_attr_table[j];
+      WriteAttr2(j + XY(0, 0), attr | 0x2020);
+      WriteAttr2(j + XY(0, 1), attr | 0x2020);
+    } else {
+      uint16 attr = *(uint16 *)&dung_bg1_attr_table[j];
+      WriteAttr1(j + XY(0, 0), attr | 0x2020);
+      WriteAttr1(j + XY(0, 1), attr | 0x2020);
+    }
+  }
+}
+
+void DrawCompletelyOpenDoor() {  // 81d5aa
+  uint16 t;
+  int i;
+
+  for (i = 0, t = 0x3030; i != dung_num_inter_room_upnorth_stairs; i += 2, t += 0x101) {}
+
+  for (; i != dung_num_wall_upnorth_spiral_stairs; i += 2, t += 0x101) {
+    int pos = dung_inter_starcases[i >> 1];
+    WriteAttr2(pos + XY(1, 0), 0x5e5e);
+    WriteAttr2(pos + XY(1, 1), t);
+    WriteAttr2(pos + XY(1, 2), 0);
+    WriteAttr2(pos + XY(1, 3), 0);
+  }
+
+  for (; i != dung_num_wall_upnorth_spiral_stairs_2; i += 2, t += 0x101) {
+    int pos = dung_inter_starcases[i >> 1];
+    WriteAttr2(pos + XY(1, 0), 0x5f5f);
+    WriteAttr2(pos + XY(1, 1), t);
+    WriteAttr2(pos + XY(1, 2), 0);
+    WriteAttr2(pos + XY(1, 3), 0);
+  }
+
+  for (; i != dung_num_inter_room_upnorth_straight_stairs; i += 2, t += 0x101) {}
+  for (; i != dung_num_inter_room_upsouth_straight_stairs; i += 2, t += 0x101) {}
+
+  t = (t & 0x707) | 0x3434;
+
+  for (; i != dung_num_inter_room_southdown_stairs; i += 2, t += 0x101) {}
+
+  for (; i != dung_num_wall_downnorth_spiral_stairs; i += 2, t += 0x101) {
+    int pos = dung_inter_starcases[i >> 1];
+    WriteAttr2(pos + XY(1, 0), 0x5e5e);
+    WriteAttr2(pos + XY(1, 1), t);
+    WriteAttr2(pos + XY(1, 2), 0);
+    WriteAttr2(pos + XY(1, 3), 0);
+  }
+
+  for (; i != dung_num_wall_downnorth_spiral_stairs_2; i += 2, t += 0x101) {
+    int pos = dung_inter_starcases[i >> 1];
+    WriteAttr2(pos + XY(1, 0), 0x5f5f);
+    WriteAttr2(pos + XY(1, 1), t);
+    WriteAttr2(pos + XY(1, 2), 0);
+    WriteAttr2(pos + XY(1, 3), 0);
+  }
+}
+
+void Dungeon_ClearAwayExplodingWall() {  // 81d6c1
+  flag_is_link_immobilized = 6;
+  flag_unk1 = 6;
+  if (BYTE(messaging_buf[0]) != 6)
+    return;
+
+  word_7E045E = 0;
+  g_ram[12] = 0;
+  door_animation_step_indicator = 0;
+  dung_cur_door_idx = dung_unk_blast_walls_3;
+  int dsto = (dung_door_tilemap_address[dung_unk_blast_walls_3 >> 1] -= 2) >> 1;
+
+  Door_BlastWallExploding_Draw(dsto);
+  ClearAndStripeExplodingWall(dsto);
+
+  WORD(nmi_disable_core_updates) = 0xffff;
+  dung_unk_blast_walls_2 += 2;
+
+  if (dung_unk_blast_walls_2 == 21) {
+    int m = kUpperBitmasks[dung_unk_blast_walls_3 >> 1];
+    dung_door_opened_incl_adjacent |= m;
+    dung_door_opened |= m;
+
+    if (dung_door_direction[dung_unk_blast_walls_3 >> 1] & 2) {
+      dung_blastwall_flag_x = 1;
+      quadrant_fullsize_x = 2;
+    } else {
+      dung_blastwall_flag_y = 1;
+      quadrant_fullsize_y = 2;
+    }
+    WORD(quadrant_fullsize_x_cached) = WORD(quadrant_fullsize_x);
+    Door_LoadBlastWallAttr(dung_unk_blast_walls_3 >> 1);
+    dung_unk_blast_walls_2 = 0;
+    dung_unk_blast_walls_3 = 0;
+    Dungeon_FlagRoomData_Quadrants();
+    flag_is_link_immobilized = 0;
+    flag_unk1 = 0;
+  }
+  nmi_copy_packets_flag = 3;
+}
+
+uint16 Dungeon_CheckForAndIDLiftableTile() {  // 81d748
+  uint16 x = (link_x_coord + kDungeon_QueryIfTileLiftable_x[link_direction_facing >> 1]) & 0x1f8;
+  uint16 y = (link_y_coord + kDungeon_QueryIfTileLiftable_y[link_direction_facing >> 1]) & 0x1f8;
+  uint16 xy = (y << 3) | (x >> 3) | (link_is_on_lower_level ? 0x1000 : 0x0);
+
+  uint8 attr = dung_bg2_attr_table[xy];
+  if ((attr & 0xf0) != 0x70)
+    return 0xffff;  // clc
+
+  uint16 rt = dung_replacement_tile_state[attr & 0xf];
+  if (rt == 0)
+    return 0xffff;
+  if ((rt & 0xf0f0) == 0x2020)
+    return 0x55;
+  return kDungeon_QueryIfTileLiftable_rv[rt & 0xf];
+}
+
+void Dungeon_PushBlock_Handler() {  // 81d81b
+  while (dung_misc_objs_index != dung_index_of_torches_start) {
+    int k = dung_misc_objs_index >> 1;
+    int st = dung_replacement_tile_state[k];
+    if (st == 1) {
+      RoomDraw_16x16Single(k * 2);
+      dung_object_tilemap_pos[k] += kPushBlockMoveDistances[push_block_direction >> 1];
+      dung_replacement_tile_state[k] = 2;
+    } else if (st == 2) {
+      PushBlock_Slide(k * 2);
+
+      if (dung_replacement_tile_state[dung_misc_objs_index >> 1] == 3) {
+        PushBlock_CheckForPit(dung_misc_objs_index);
+        dung_replacement_tile_state[dung_misc_objs_index >> 1]++;
+      }
+    } else if (st == 4) {
+      PushBlock_HandleFalling(k * 2);
+    }
+
+    dung_misc_objs_index += 2;
+  }
+}
+
+void RoomDraw_16x16Single(uint8 index) {  // 81d828
+  index >>= 1;
+  uint16 pos = (dung_object_tilemap_pos[index] & 0x3fff) >> 1;
+  Dungeon_Store2x2(pos,
+                   replacement_tilemap_UL[index],
+                   replacement_tilemap_LL[index],
+                   replacement_tilemap_UR[index],
+                   replacement_tilemap_LR[index],
+                   attributes_for_tile[replacement_tilemap_LR[index] & 0x3ff]);
+}
+
+void PushBlock_CheckForPit(uint8 y) {  // 81d8d4
+  y >>= 1;
+  if (!(dung_object_tilemap_pos[y] & 0x4000))
+    dung_flag_movable_block_was_pushed ^= 1;
+
+  int p = (dung_object_tilemap_pos[y] & 0x3fff) >> 1;
+  uint8 attr = dung_bg2_attr_table[p];
+  if (attr == 0x20) {  // fall into pit
+    sound_effect_1 = 0x20;
+    int k = dung_object_pos_in_objdata[y] >> 2;
+    movable_block_datas[k].room = dung_hdr_travel_destinations[0];
+    movable_block_datas[k].tilemap = dung_object_tilemap_pos[y];
+    return;
+  }
+
+  int i = (index_of_changable_dungeon_objs[1] - 1) == y;
+  index_of_changable_dungeon_objs[i] = 0;
+
+  if (attr == 0x23) {
+    related_to_trapdoors_somehow = dung_flag_trapdoors_down ^ 1;
+    dung_replacement_tile_state[y] = 4;
+  } else {
+    dung_replacement_tile_state[y] = 0xffff;
+  }
+  Dungeon_Store2x2(p, 0x922, 0x932, 0x923, 0x933, 0x27);
+}
+
+uint8 Dungeon_LiftAndReplaceLiftable(Point16U *pt) {  // 81d9ec
+  uint16 x = link_x_coord + kDungeon_QueryIfTileLiftable_x[link_direction_facing >> 1];
+  uint16 y = link_y_coord + kDungeon_QueryIfTileLiftable_y[link_direction_facing >> 1];
+  pt->x = x;
+  pt->y = y;
+
+  R16 = y;
+  R18 = x;
+
+  x &= 0x1f8;
+  y &= 0x1f8;
+  uint16 xy = (y << 3) | (x >> 3) | (link_is_on_lower_level ? 0x1000 : 0x0);
+
+  uint8 attr = dung_bg2_attr_table[xy];
+
+  assert((attr & 0x70) == 0x70);
+
+  attr &= 0xf;
+  uint16 rt = dung_replacement_tile_state[attr];
+
+  if ((rt & 0xf0f0) == 0x1010) {
+    dung_misc_objs_index = attr * 2;
+    RevealPotItem(xy, dung_object_tilemap_pos[attr]);
+    RoomDraw_16x16Single(dung_misc_objs_index);
+    ManipBlock_Something(pt);
+    return kDungeon_QueryIfTileLiftable_rv[rt & 0xf];
+  } else if ((rt & 0xf0f0) == 0x2020) {
+    return ThievesAttic_DrawLightenedHole(xy, (attr - (rt & 0xf)) * 2, pt);
+  } else {
+    return 0;
+  }
+  return 0;
+}
+
+uint8 ThievesAttic_DrawLightenedHole(uint16 pos6, uint16 a, Point16U *pt) {  // 81da71
+  dung_misc_objs_index = a;
+  RevealPotItem(pos6, dung_object_tilemap_pos[a >> 1]);
+  RoomDraw_16x16Single(a);
+  RoomDraw_16x16Single(a + 2);
+  RoomDraw_16x16Single(a + 4);
+  RoomDraw_16x16Single(a + 6);
+  ManipBlock_Something(pt);
+  return 0x55;
+}
+
+uint8 HandleItemTileAction_Dungeon(uint16 x, uint16 y) {  // 81dabb
+  if (!(link_item_in_hand & 2)) {
+    if (!(enhanced_features0 & kFeatures0_BreakPotsWithSword) ||
+        button_b_frames == 0 || link_sword_type == 1)
+      return 0;
+  }
+  uint16 pos = (y & 0x1f8) * 8 + x + (link_is_on_lower_level ? 0x1000 : 0);
+  uint16 tile = dung_bg2_attr_table[pos];
+  if ((tile & 0xf0) == 0x70) {
+    uint16 tile2 = dung_replacement_tile_state[tile & 0xf];
+    if ((tile2 & 0xf0f0) == 0x4040) {  // Hammer peg
+      if (!(link_item_in_hand & 2))
+        return 0;  // only hammers on pegs
+      dung_misc_objs_index = (tile & 0xf) * 2;
+      RoomDraw_16x16Single(dung_misc_objs_index);
+      sound_effect_1 = 0x11;
+    } else if ((tile2 & 0xf0f0) == 0x1010) {  // Pot
+      dung_misc_objs_index = (tile & 0xf) * 2;
+      RevealPotItem(pos, dung_object_tilemap_pos[tile & 0xf]);
+      RoomDraw_16x16Single(dung_misc_objs_index);
+      Point16U pt;
+      ManipBlock_Something(&pt);
+      BYTE(dung_secrets_unk1) |= 0x80;
+      Sprite_SpawnImmediatelySmashedTerrain(1, pt.x, pt.y);
+      AncillaAdd_BushPoof(pt.x, pt.y);  // return value wtf?
+    }
+  }
+  return 0;
+}
+
+void ManipBlock_Something(Point16U *pt) {  // 81db41
+  uint16 pos = dung_object_tilemap_pos[dung_misc_objs_index >> 1];
+  pt->x = (link_x_coord & 0xfe00) | ((pos & 0x007e) << 2);
+  pt->y = (link_y_coord & 0xfe00) | ((pos & 0x1f80) >> 4);
+}
+
+void RevealPotItem(uint16 pos6, uint16 pos4) {  // 81e6b2
+  BYTE(dung_secrets_unk1) = 0;
+
+  const uint8 *src_ptr = kDungeonSecrets + WORD(kDungeonSecrets[dungeon_room_index * 2]);
+
+  int index = 0;
+  for (;;) {
+    uint16 test_pos = *(uint16 *)src_ptr;
+    if (test_pos == 0xffff)
+      return;
+    assert(!(test_pos & 0x8000));
+    if (test_pos == pos4)
+      break;
+    src_ptr += 3;
+    index++;
+  }
+
+  uint8 data = src_ptr[2];
+  if (data == 0)
+    return;
+
+  if (data < 0x80) {
+    if (data != 8) {
+      uint16 mask = 1 << index;
+      uint16 *pr = &pots_revealed_in_room[dungeon_room_index];
+      if (*pr & mask)
+        return;
+      *pr |= mask;
+    }
+    BYTE(dung_secrets_unk1) |= data;
+  } else if (data != 0x88) {
+    int j = dung_bg2_attr_table[pos6] & 0xf;
+    int k = (j - (dung_replacement_tile_state[j] & 0xf));
+    dung_misc_objs_index = 2 * k;
+    sound_effect_2 = 0x1b;
+    const uint16 *src = SrcPtr(0x5ba);
+    for (int i = 0; i < 4; i++, k++, src += 4) {
+      replacement_tilemap_UL[k] = src[0];
+      replacement_tilemap_LL[k] = src[1];
+      replacement_tilemap_UR[k] = src[2];
+      replacement_tilemap_LR[k] = src[3];
+    }
+  } else {
+    int k = dung_misc_objs_index >> 1;
+    replacement_tilemap_UL[k] = 0xD0B;
+    replacement_tilemap_LL[k] = 0xD1B;
+    replacement_tilemap_UR[k] = 0x4D0B;
+    replacement_tilemap_LR[k] = 0x4D1B;
+  }
+}
+
+void Dungeon_UpdateTileMapWithCommonTile(int x, int y, uint8 v) {  // 81e7a9
+  if (v == 8)
+    Dungeon_PrepSpriteInducedDma(x + 16, y, v + 2);
+  Dungeon_PrepSpriteInducedDma(x, y, v);
+  nmi_load_bg_from_vram = 1;
+}
+
+void Dungeon_PrepSpriteInducedDma(int x, int y, uint8 v) {  // 81e7df
+  static const uint16 kPrepSpriteInducedDma_Srcs[10] = { 0xe0, 0xade, 0x5aa, 0x198, 0x210, 0x218, 0x1f3a, 0xeaa, 0xeb2, 0x140 };
+  int pos = ((y + 1) & 0x1f8) << 3 | (x & 0x1f8) >> 3;
+  const uint16 *src = SrcPtr(kPrepSpriteInducedDma_Srcs[v >> 1]);
+  uint16 *dst = &vram_upload_data[vram_upload_offset >> 1];
+  dst[0] = Dungeon_MapVramAddr(pos + 0);
+  dst[3] = Dungeon_MapVramAddr(pos + 64);
+  dst[6] = Dungeon_MapVramAddr(pos + 1);
+  dst[9] = Dungeon_MapVramAddr(pos + 65);
+  uint8 attr = attributes_for_tile[src[3] & 0x3ff];
+  dung_bg2_attr_table[pos + XY(0, 0)] = attr;
+  dung_bg2_attr_table[pos + XY(0, 1)] = attr;
+  dung_bg2_attr_table[pos + XY(1, 0)] = attr;
+  dung_bg2_attr_table[pos + XY(1, 1)] = attr;
+  dung_bg2[pos + XY(0, 0)] = dst[2] = src[0];
+  dung_bg2[pos + XY(0, 1)] = dst[5] = src[1];
+  dung_bg2[pos + XY(1, 0)] = dst[8] = src[2];
+  dung_bg2[pos + XY(1, 1)] = dst[11] = src[3];
+  dst[1] = 0x100;
+  dst[4] = 0x100;
+  dst[7] = 0x100;
+  dst[10] = 0x100;
+  dst[12] = 0xffff;
+  vram_upload_offset += 24;
+}
+
+void Dungeon_DeleteRupeeTile(uint16 x, uint16 y) {  // 81e8bd
+  int pos = (y & 0x1f8) * 8 | (x & 0x1f8) >> 3;
+  uint16 *dst = &vram_upload_data[vram_upload_offset >> 1];
+  dst[2] = 0x190f;
+  dst[5] = 0x190f;
+  dung_bg2[pos + XY(0, 0)] = 0x190f;
+  dung_bg2[pos + XY(0, 1)] = 0x190f;
+  uint16 attr = attributes_for_tile[0x190f & 0x3ff] * 0x101;
+  WORD(dung_bg2_attr_table[pos + XY(0, 0)]) = attr;
+  WORD(dung_bg2_attr_table[pos + XY(0, 1)]) = attr;
+  dst[0] = Dungeon_MapVramAddr(pos + XY(0, 0));
+  dst[3] = Dungeon_MapVramAddr(pos + XY(0, 1));
+  dst[1] = 0x100;
+  dst[4] = 0x100;
+  dst[6] = 0xffff;
+  vram_upload_offset += 24;
+  dung_savegame_state_bits |= 0x1000;
+  nmi_load_bg_from_vram = 1;
+}
+
+// This doesn't return exactly like the original
+// Also returns in scratch_0
+uint8 OpenChestForItem(uint8 tile, int *chest_position) {  // 81eb66
+  static const uint16 kChestOpenMasks[] = { 0x100, 0x200, 0x400, 0x800, 0x1000, 0x2000 };
+  if (tile == 0x63)
+    return OpenMiniGameChest(chest_position);
+
+  int chest_idx = tile - 0x58, chest_idx_org = chest_idx;
+
+  uint16 loc = dung_chest_locations[chest_idx], pos, chest_room;
+  uint8 data = 0xff;
+  const uint16 *ptr;
+
+  if (loc >= 0x8000) {
+    // big key lock
+    if (!(link_bigkey & kUpperBitmasks[cur_palace_index_x2 >> 1])) {
+      dialogue_message_index = 0x7a;
+      Main_ShowTextMessage();
+      return 0xff;
+    } else {
+      dung_savegame_state_bits |= kChestOpenMasks[chest_idx];
+      sound_effect_1 = 0x29;
+      sound_effect_2 = 0x15;
+      pos = (loc & 0x7fff) >> 1;
+
+      ptr = SrcPtr(dung_floor_2_filler_tiles);
+      overworld_tileattr[pos + 0] = ptr[0];
+      overworld_tileattr[pos + 64] = ptr[1];
+      overworld_tileattr[pos + 1] = ptr[2];
+      overworld_tileattr[pos + 65] = ptr[3];
+      goto afterStoreCrap;
+    }
+  } else {
+    const uint8 *chest_data;
+    int i;
+    chest_data = kDungeonRoomChests;
+    for (i = 0; i < kDungeonRoomChests_SIZE; i += 3, chest_data += 3) {
+      chest_room = *(uint16 *)chest_data;
+      if ((chest_room & 0x7fff) == dungeon_room_index && --chest_idx < 0) {
+        data = chest_data[2];
+        if (chest_room & 0x8000) {
+          if (!(link_bigkey & kUpperBitmasks[cur_palace_index_x2 >> 1])) {
+            dialogue_message_index = 0x7a;
+            Main_ShowTextMessage();
+            return 0xff;
+          }
+          dung_savegame_state_bits |= kChestOpenMasks[chest_idx_org];
+          OpenBigChest(loc, chest_position);
+          return data;
+        } else {
+          dung_savegame_state_bits |= kChestOpenMasks[chest_idx_org];
+          ptr = SrcPtr(0x14A4);
+          pos = loc >> 1;
+
+          overworld_tileattr[pos + 0] = ptr[0];
+          overworld_tileattr[pos + 64] = ptr[1];
+          overworld_tileattr[pos + 1] = ptr[2];
+          overworld_tileattr[pos + 65] = ptr[3];
+
+          uint8 attr;
+afterStoreCrap:
+          attr = (loc < 0x8000) ? 0x27 : 0x00;
+
+          dung_bg2_attr_table[pos + 0] = attr;
+          dung_bg2_attr_table[pos + 64] = attr;
+          dung_bg2_attr_table[pos + 1] = attr;
+          dung_bg2_attr_table[pos + 65] = attr;
+
+          uint16 *dst = &vram_upload_data[vram_upload_offset >> 1];
+          dst[0] = Dungeon_MapVramAddr(pos + 0);
+          dst[3] = Dungeon_MapVramAddr(pos + 64);
+          dst[6] = Dungeon_MapVramAddr(pos + 1);
+          dst[9] = Dungeon_MapVramAddr(pos + 65);
+
+          dst[2] = ptr[0];
+          dst[5] = ptr[1];
+          dst[8] = ptr[2];
+          dst[11] = ptr[3];
+
+          dst[1] = 0x100;
+          dst[4] = 0x100;
+          dst[7] = 0x100;
+          dst[10] = 0x100;
+
+          dst[12] = 0xffff;
+
+          vram_upload_offset += 24;
+          nmi_load_bg_from_vram = 1;
+          Dungeon_FlagRoomData_Quadrants();
+          if (sound_effect_2 == 0)
+            sound_effect_2 = 14;
+
+          *chest_position = loc & 0x7fff;
+          return data;
+        }
+      }
+    }
+    return 0xff;
+  }
+}
+
+void OpenBigChest(uint16 loc, int *chest_position) {  // 81ed05
+  uint16 pos = loc >> 1;
+  const uint16 *src = SrcPtr(0x14C4);
+
+  for (int i = 0; i < 4; i++) {
+    dung_bg2[pos + XY(i, 0)] = src[0];
+    dung_bg2[pos + XY(i, 1)] = src[1];
+    dung_bg2[pos + XY(i, 2)] = src[2];
+    src += 3;
+  }
+
+  Dungeon_PrepOverlayDma_nextPrep(0, loc);
+  *chest_position = (loc + 2);
+  WORD(dung_bg2_attr_table[pos + XY(0, 0)]) = 0x2727;
+  WORD(dung_bg2_attr_table[pos + XY(2, 0)]) = 0x2727;
+  WORD(dung_bg2_attr_table[pos + XY(0, 1)]) = 0x2727;
+  WORD(dung_bg2_attr_table[pos + XY(2, 1)]) = 0x2727;
+  WORD(dung_bg2_attr_table[pos + XY(0, 2)]) = 0x2727;
+  WORD(dung_bg2_attr_table[pos + XY(2, 2)]) = 0x2727;
+  Dungeon_FlagRoomData_Quadrants();
+  sound_effect_2 = 14;
+  nmi_copy_packets_flag = 1;
+  byte_7E0B9E = 1;
+}
+
+uint8 OpenMiniGameChest(int *chest_position) {  // 81edab
+  int t;
+  if (minigame_credits == 0) {
+    dialogue_message_index = 0x163;
+    Main_ShowTextMessage();
+    return 0xff;
+  }
+  if (minigame_credits == 255) {
+    dialogue_message_index = 0x162;
+    Main_ShowTextMessage();
+    return 0xff;
+  }
+  minigame_credits--;
+
+  int pos = ((link_y_coord - 4) & 0x1f8) * 8;
+  pos |= ((link_x_coord + 7) & 0x1f8) >> 3;
+
+  if (WORD(dung_bg2_attr_table[pos]) != 0x6363) {
+    pos--;
+    if (WORD(dung_bg2_attr_table[pos]) != 0x6363)
+      pos += 2;
+  }
+
+  *chest_position = pos * 2;
+
+  WORD(dung_bg2_attr_table[pos + XY(0, 0)]) = 0x202;
+  WORD(dung_bg2_attr_table[pos + XY(0, 1)]) = 0x202;
+
+  const uint16 *src = SrcPtr(0x14A4);
+
+  int pos_wrong = pos + XY(0, 2);  // zelda bug?
+  dung_bg2[pos_wrong + XY(0, 0)] = src[0];
+  dung_bg2[pos_wrong + XY(0, 1)] = src[1];
+  dung_bg2[pos_wrong + XY(1, 0)] = src[2];
+  dung_bg2[pos_wrong + XY(1, 1)] = src[3];
+
+  // The orig asm code seems to access invalid vram here because it indexes by 0x14a4
+  uint16 *dst = &vram_upload_data[vram_upload_offset >> 1];
+  dst[0] = Dungeon_MapVramAddr(pos + 0);
+  dst[3] = Dungeon_MapVramAddr(pos + 64);
+  dst[6] = Dungeon_MapVramAddr(pos + 1);
+  dst[9] = Dungeon_MapVramAddr(pos + 65);
+
+  dst[2] = src[0];
+  dst[5] = src[1];
+  dst[8] = src[2];
+  dst[11] = src[3];
+
+  dst[1] = 0x100;
+  dst[4] = 0x100;
+  dst[7] = 0x100;
+  dst[10] = 0x100;
+
+  dst[12] = 0xffff;
+
+  vram_upload_offset += 24;
+
+  uint8 rv;
+
+  uint16 r16 = some_menu_ctr;
+
+  t = GetRandomNumber();
+  if (BYTE(dungeon_room_index) == 0) {
+    t = t & 0xf;
+    rv = kDungeon_RupeeChestMinigamePrizes[t & 0xf];
+
+  } else if (BYTE(dungeon_room_index) == 0x18) {
+    t = 0x10 + (t & 0xf);
+    rv = kDungeon_RupeeChestMinigamePrizes[0x10 + (t & 0xf)];
+  } else {
+    t &= 7;
+    if (t >= 2 && t == r16) {
+      t = (t + 1) & 7;
+    }
+    if (t == 7) {
+      if (dung_savegame_state_bits & 0x4000) {
+        t = 0;
+      } else {
+        dung_savegame_state_bits |= 0x4000;
+      }
+    }
+    rv = kDungeon_MinigameChestPrizes1[t];
+  }
+  some_menu_ctr = t;
+  nmi_load_bg_from_vram = 1;
+  sound_effect_2 = 14;
+  return rv;
+}
+
+uint16 RoomTag_BuildChestStripes(uint16 pos, uint16 y) {  // 81ef0f
+  pos += dung_chest_locations[y >> 1];
+  return swap16(((pos & 0x40) << 4) | ((pos & 0x303f) >> 1) | ((pos & 0xf80) >> 2));
+}
+
+void Dungeon_SetAttrForActivatedWaterOff() {  // 81ef93
+  CGWSEL_copy = 2;
+  CGADSUB_copy = 0x32;
+  TS_copy = 0;
+  W12SEL_copy = 0;
+  dung_hdr_collision = 0;
+  WORD(TMW_copy) = 0;
+  for (int j = 0; j != dung_num_inroom_upnorth_stairs_water; j += 2) {
+    int dsto = dung_stairs_table_1[j >> 1];
+    WriteAttr2(dsto + XY(1, 1), 0x1d1d);
+    WriteAttr2(dsto + XY(1, 2), 0x1d1d);
+  }
+  for (int j = 0; j != dung_num_inroom_upsouth_stairs_water; j += 2) {
+    int dsto = dung_stairs_table_2[j >> 1];
+    WriteAttr2(dsto + XY(1, 1), 0x1d1d);
+    WriteAttr2(dsto + XY(1, 2), 0x1d1d);
+  }
+  flag_update_cgram_in_nmi++;
+  subsubmodule_index++;
+}
+
+void Dungeon_FloodSwampWater_PrepTileMap() {  // 81f046
+  WaterFlood_BuildOneQuadrantForVRAM();
+  dung_cur_quadrant_upload += 4;
+  if (++subsubmodule_index == 6) {
+    dung_cur_quadrant_upload = 0;
+    subsubmodule_index = 0;
+    submodule_index = 0;
+  }
+}
+
+void Dungeon_AdjustWaterVomit(const uint16 *src, int depth) {  // 81f0c9
+  int dsto = (word_7E047C >> 1) + XY(0, 2);
+  uint16 *dst = &dung_bg2[dsto];
+  do {
+    dst[0] = src[0];
+    dst[1] = src[1];
+    dst[2] = src[2];
+    dst[3] = src[3];
+    dst += XY(0, 1), src += 4;
+  } while (--depth);
+  uint16 *vram = vram_upload_data;
+  for (int i = 0; i < 4; i++) {
+    uint16 *dst = &dung_bg2[dsto];
+    vram[0] = Dungeon_MapVramAddr(dsto);
+    vram[1] = 0x980;
+    vram[2] = dst[XY(0, 0)];
+    vram[3] = dst[XY(0, 1)];
+    vram[4] = dst[XY(0, 2)];
+    vram[5] = dst[XY(0, 3)];
+    vram[6] = dst[XY(0, 4)];
+    vram += 7, dsto++;
+  }
+  vram[0] = 0xffff;
+  nmi_load_bg_from_vram = 1;
+}
+
+void Dungeon_SetAttrForActivatedWater() {  // 81f237
+  WORD(TMW_copy) = 0;
+  for (int j = 0; j != dung_num_interpseudo_upnorth_stairs; j += 2) {
+    int dsto = dung_stairs_table_1[j >> 1];
+    WriteAttr2(dsto + 0, 0x003);
+    WriteAttr2(dsto + 2, 0x300);
+    WriteAttr1(dsto + 0, 0xa03);
+    WriteAttr1(dsto + 2, 0x30a);
+    WriteAttr2(dsto + XY(0, 1), 0x808);
+    WriteAttr2(dsto + XY(2, 1), 0x808);
+    WriteAttr1(dsto + XY(0, 1), 0x808);
+    WriteAttr1(dsto + XY(2, 1), 0x808);
+    WriteAttr1(dsto + XY(0, 2), 0x808);
+    WriteAttr1(dsto + XY(2, 2), 0x808);
+    WriteAttr1(dsto + XY(0, 3), 0x808);
+    WriteAttr1(dsto + XY(2, 3), 0x808);
+  }
+
+  for (int j = 0; j != dung_num_stairs_wet; j += 2) {
+    int dsto = dung_stairs_table_2[j >> 1];
+    WriteAttr2(dsto + XY(0, 3), 0x003);
+    WriteAttr2(dsto + XY(2, 3), 0x300);
+    WriteAttr1(dsto + XY(0, 3), 0xa03);
+    WriteAttr1(dsto + XY(2, 3), 0x30a);
+    WriteAttr2(dsto + XY(0, 2), 0x808);
+    WriteAttr2(dsto + XY(2, 2), 0x808);
+    WriteAttr1(dsto + XY(0, 0), 0x808);
+    WriteAttr1(dsto + XY(2, 0), 0x808);
+    WriteAttr1(dsto + XY(0, 1), 0x808);
+    WriteAttr1(dsto + XY(2, 1), 0x808);
+    WriteAttr1(dsto + XY(0, 2), 0x808);
+    WriteAttr1(dsto + XY(2, 2), 0x808);
+  }
+  submodule_index = 0;
+  nmi_boolean = 0; // wtf
+  subsubmodule_index = 0;
+}
+
+void FloodDam_Expand() {  // 81f30c
+  watergate_var1++;
+  water_hdma_var3 = watergate_var1 >> 1;
+  uint8 r0 = water_hdma_var3 - 8;
+  BYTE(spotlight_y_upper) = word_7E0678;
+  BYTE(spotlight_var4) += 1;
+  BYTE(water_hdma_var2) = spotlight_var4 + r0;
+
+  if (watergate_var1 & 0xf)
+    return;
+
+  if (watergate_var1 == 64)
+    subsubmodule_index++;
+
+  static const uint16 kWatergateSrcs1[] = { 0x12f8, 0x1348, 0x1398, 0x13e8 };
+  RoomDraw_Object_Nx4(10, SrcPtr(kWatergateSrcs1[(watergate_var1 >> 4) - 1]), &dung_bg2[watergate_pos >> 1]);
+  int pos = watergate_pos;
+  int n = 3;
+  int dma_ptr = 0;
+  do {
+    dma_ptr = Dungeon_PrepOverlayDma_watergate(dma_ptr, pos, 0x881, 4);
+    pos += 6;
+  } while (--n);
+  nmi_copy_packets_flag = 1;
+}
+
+void FloodDam_PrepTiles_init() {  // 81f3a7
+  dung_cur_quadrant_upload = 0;
+  overworld_screen_transition = 0;
+  WaterFlood_BuildOneQuadrantForVRAM();
+  dung_cur_quadrant_upload += 4;
+  subsubmodule_index++;
+}
+
+void Watergate_Main_State1() {  // 81f3aa
+  overworld_screen_transition = 0;
+  WaterFlood_BuildOneQuadrantForVRAM();
+  dung_cur_quadrant_upload += 4;
+  subsubmodule_index++;
+}
+
+void FloodDam_Fill() {  // 81f3bd
+  BYTE(water_hdma_var2)++;
+  uint8 t = water_hdma_var2 + spotlight_y_upper;
+  if (t >= 225) {
+    dung_cur_quadrant_upload = 0;
+    submodule_index = 0;
+    subsubmodule_index = 0;
+    TMW_copy = 0;
+    TSW_copy = 0;
+    IrisSpotlight_ResetTable();
+  }
+}
+
+void Ganon_ExtinguishTorch_adjust_translucency() {  // 81f496
+  Palette_AssertTranslucencySwap();
+  byte_7E0333 = 0xc0;
+  Dungeon_ExtinguishTorch();
+}
+
+void Ganon_ExtinguishTorch() {  // 81f4a1
+  byte_7E0333 = 193;
+  Dungeon_ExtinguishTorch();
+}
+
+void Dungeon_ExtinguishTorch() {  // 81f4a6
+  int y = (byte_7E0333 & 0xf) * 2 + dung_index_of_torches_start;
+
+  uint16 r8 = (dung_object_tilemap_pos[y >> 1] &= 0x7fff);
+
+  dung_torch_data[(dung_object_pos_in_objdata[y >> 1] & 0xff) >> 1] = r8;
+
+  r8 &= 0x3fff;
+  RoomDraw_AdjustTorchLightingChange(r8, 0xec2, r8);
+  nmi_copy_packets_flag = 1;
+
+  if (dung_want_lights_out && dung_num_lit_torches != 0 && --dung_num_lit_torches < 3) {
+    if (dung_num_lit_torches == 0)
+      TS_copy = 1;
+    overworld_fixed_color_plusminus = kLitTorchesColorPlus[dung_num_lit_torches];
+    submodule_index = 10;
+    subsubmodule_index = 0;
+  }
+
+  dung_torch_timers[byte_7E0333 & 0xf] = 0;
+  byte_7E0333 = 0;
+}
+
+void SpiralStairs_MakeNearbyWallsHighPriority_Entering() {  // 81f528
+  int pos = dung_inter_starcases[which_staircase_index & 3] - 4;
+  word_7E048C = pos * 2;
+  uint16 *dst = &dung_bg2[pos];
+  for (int i = 0; i < 5; i++) {
+    dst[XY(0, 0)] |= 0x2000;
+    dst[XY(0, 1)] |= 0x2000;
+    dst[XY(0, 2)] |= 0x2000;
+    dst[XY(0, 3)] |= 0x2000;
+    dst += 1;
+  }
+  int dp = Dungeon_PrepOverlayDma_nextPrep(0, pos * 2);
+  Dungeon_PrepOverlayDma_nextPrep(dp, pos * 2 + 8);
+  nmi_copy_packets_flag = 1;
+}
+
+void SpiralStairs_MakeNearbyWallsLowPriority() {  // 81f585
+  int pos = word_7E048C >> 1;
+  uint16 *dst = &dung_bg2[pos];
+  for (int i = 0; i < 5; i++) {
+    dst[XY(0, 0)] &= ~0x2000;
+    dst[XY(0, 1)] &= ~0x2000;
+    dst[XY(0, 2)] &= ~0x2000;
+    dst[XY(0, 3)] &= ~0x2000;
+    dst += 1;
+  }
+  int dp = Dungeon_PrepOverlayDma_nextPrep(0, pos * 2);
+  Dungeon_PrepOverlayDma_nextPrep(dp, pos * 2 + 8);
+  nmi_copy_packets_flag = 1;
+}
+
+void ClearAndStripeExplodingWall(uint16 dsto) {  // 81f811
+  static const uint16 kBlastWall_Tab2[16] = { 4, 8, 0xc, 0x10, 0x14, 0x18, 0x1c, 0x20, 0x100, 0x200, 0x300, 0x400, 0x500, 0x600, 0x700, 0x800 };
+
+  uint16 r6 = 0x80;
+  uint16 r14 = 0;
+  uint16 r10 = dung_unk_blast_walls_2 + 3;
+  uint16 r2 = 0;
+
+  if (!sign16(r10 - 8)) {
+    r2 = r10 - 6;
+    r14 = 1;
+    r10 = 3;
+  }
+  if (!(dung_door_direction[dung_cur_door_idx >> 1] & 2))
+    r6++;
+
+  uint16 *uvdata = &uvram.data[0];
+  for (;;) {
+    const uint16 *bg2 = &dung_bg2[dsto];
+    do {
+      uint16 vram_addr = Dungeon_MapVramAddrNoSwap(dsto);
+      uvdata[0] = vram_addr;
+      uvdata[1] = r6 | 0xa00;
+      uvdata[2] = bg2[XY(0, 0)];
+      uvdata[3] = bg2[XY(0, 1)];
+      uvdata[4] = bg2[XY(0, 2)];
+      uvdata[5] = bg2[XY(0, 3)];
+      uvdata[6] = bg2[XY(0, 4)];
+      uvdata[7] = vram_addr + 0x4a0;
+      uvdata[8] = r6 | 0xe00;
+      uvdata[9] = bg2[XY(0, 5)];
+      uvdata[10] = bg2[XY(0, 6)];
+      uvdata[11] = bg2[XY(0, 7)];
+      uvdata[12] = bg2[XY(0, 8)];
+      uvdata[13] = bg2[XY(0, 9)];
+      uvdata[14] = bg2[XY(0, 10)];
+      uvdata[15] = bg2[XY(0, 11)];
+      dsto++, bg2++, uvdata += 16;
+    } while (--r10);
+    if (!r14)
+      break;
+    r14--;
+    dsto += kBlastWall_Tab2[(r2 >> 1) + ((r6 & 1) ? 0 : 8) - 1] >> 1;
+    r10 = 3;
+  }
+  uvdata[0] = 0xffff;
+}
+
+void Dungeon_DrawRoomOverlay(const uint8 *src) {  // 81f967
+  for (;;) {
+    dung_draw_width_indicator = 0;
+    dung_draw_height_indicator = 0;
+    uint16 a = WORD(*src);
+    if (a == 0xffff)
+      break;
+    uint16 *p = &dung_bg2[(src[0] >> 2) | (src[1] >> 2) << 6];
+    uint8 type = src[2];
+    if (type == 0xa4) {
+      p[XY(0, 1)] = p[XY(1, 1)] = p[XY(2, 1)] = p[XY(3, 1)] =
+          p[XY(0, 2)] = p[XY(1, 2)] = p[XY(2, 2)] = p[XY(3, 2)] = SrcPtr(0x5aa)[0];
+      p[XY(0, 0)] = p[XY(1, 0)] = p[XY(2, 0)] = p[XY(3, 0)] = SrcPtr(0x63c)[1];
+      p[XY(0, 3)] = p[XY(1, 3)] = p[XY(2, 3)] = p[XY(3, 3)] = SrcPtr(0x642)[1];
+    } else {
+      const uint16 *sp = SrcPtr(dung_floor_2_filler_tiles);
+      p[XY(0, 0)] = p[XY(2, 0)] = p[XY(0, 2)] = p[XY(2, 2)] = sp[0];
+      p[XY(1, 0)] = p[XY(3, 0)] = p[XY(1, 2)] = p[XY(3, 2)] = sp[1];
+      p[XY(0, 1)] = p[XY(2, 1)] = p[XY(0, 3)] = p[XY(2, 3)] = sp[4];
+      p[XY(1, 1)] = p[XY(3, 1)] = p[XY(1, 3)] = p[XY(3, 3)] = sp[5];
+    }
+    src += 3;
+  }
+}
+
+void GetDoorDrawDataIndex_North_clean_door_index(int door) {  // 81fa4a
+  GetDoorDrawDataIndex_North(door, door);
+}
+
+int DoorDoorStep1_North(int door, int dma_ptr) {  // 81fa54
+  int pos = dung_door_tilemap_address[door];
+  if ((pos & 0x1fff) >= kDoorPositionToTilemapOffs_Up[6]) {
+    pos -= 0x500;
+    if ((door_type_and_slot[door] & 0xfe) >= 0x42)
+      pos -= 0x300;
+    GetDoorDrawDataIndex_South(door ^ 8, door & 7);
+    dma_ptr = Dungeon_PrepOverlayDma_nextPrep(dma_ptr, pos);
+    Dungeon_LoadSingleDoorAttribute(door ^ 8);
+  }
+  GetDoorDrawDataIndex_North(door, door & 7);
+  return dma_ptr;
+}
+
+void GetDoorDrawDataIndex_North(int door, int r4_door) {  // 81faa0
+  uint8 door_type = door_type_and_slot[door] & 0xfe;
+  int x = door_open_closed_counter;
+  if (x == 0 || x == 4) {
+    DrawDoorToTileMap_North(door, r4_door);
+    return;
+  }
+  x += (door_type == kDoorType_StairMaskLocked2 || door_type == kDoorType_StairMaskLocked3 || door_type >= 0x42) ? 4 : 0;
+  x += (door_type == kDoorType_ShuttersTwoWay || door_type == kDoorType_Shutter) ? 2 : 0;
+  //  assert(x < 8);
+  Object_Draw_DoorUp_4x3(kDoorAnimUpSrc[x >> 1], door);
+}
+
+void DrawDoorToTileMap_North(int door, int r4_door) {  // 81fad7
+  Object_Draw_DoorUp_4x3(kDoorTypeSrcData[GetDoorGraphicsIndex(door, r4_door) >> 1], door);
+}
+
+void Object_Draw_DoorUp_4x3(uint16 src, int door) {  // 81fae3
+  const uint16 *s = SrcPtr(src);
+  uint16 *dst = &dung_bg2[dung_door_tilemap_address[door] >> 1];
+  for (int i = 0; i < 4; i++) {
+    dst[XY(0, 0)] = s[0];
+    dst[XY(0, 1)] = s[1];
+    dst[XY(0, 2)] = s[2];
+    dst += 1, s += 3;
+  }
+}
+
+void GetDoorDrawDataIndex_South_clean_door_index(int door) {  // 81fb0b
+  GetDoorDrawDataIndex_South(door, door);
+}
+
+int DoorDoorStep1_South(int door, int dma_ptr) {  // 81fb15
+  int pos = dung_door_tilemap_address[door];
+  if ((pos & 0x1fff) < kDoorPositionToTilemapOffs_Down[9]) {
+    pos += 0x500;
+    if ((door_type_and_slot[door] & 0xfe) >= 0x42)
+      pos += 0x300;
+    GetDoorDrawDataIndex_North(door ^ 8, door & 7);
+    dma_ptr = Dungeon_PrepOverlayDma_nextPrep(dma_ptr, pos);
+    Dungeon_LoadSingleDoorAttribute(door ^ 8);
+  }
+  GetDoorDrawDataIndex_South(door, door & 7);
+  return dma_ptr;
+}
+
+void GetDoorDrawDataIndex_South(int door, int r4_door) {  // 81fb61
+  uint8 door_type = door_type_and_slot[door] & 0xfe;
+  int x = door_open_closed_counter;
+  if (x == 0 || x == 4) {
+    DrawDoorToTileMap_South(door, r4_door);
+    return;
+  }
+  x += (door_type >= 0x42) ? 4 : 0;
+  x += (door_type == kDoorType_ShuttersTwoWay || door_type == kDoorType_Shutter) ? 2 : 0;
+  //  assert(x < 8);
+  Object_Draw_DoorDown_4x3(kDoorAnimDownSrc[x >> 1], door);
+}
+
+void DrawDoorToTileMap_South(int door, int r4_door) {  // 81fb8e
+  Object_Draw_DoorDown_4x3(kDoorTypeSrcData2[GetDoorGraphicsIndex(door, r4_door) >> 1], door);
+}
+
+void Object_Draw_DoorDown_4x3(uint16 src, int door) {  // 81fb9b
+  const uint16 *s = SrcPtr(src);
+  uint16 *dst = &dung_bg2[dung_door_tilemap_address[door] >> 1];
+  for (int i = 0; i < 4; i++) {
+    dst[XY(0, 1)] = s[0];
+    dst[XY(0, 2)] = s[1];
+    dst[XY(0, 3)] = s[2];
+    dst += 1, s += 3;
+  }
+}
+
+void GetDoorDrawDataIndex_West_clean_door_index(int door) {  // 81fbc2
+  GetDoorDrawDataIndex_West(door, door);
+}
+
+int DoorDoorStep1_West(int door, int dma_ptr) {  // 81fbcc
+  int pos = dung_door_tilemap_address[door];
+  if ((pos & 0x7ff) >= kDoorPositionToTilemapOffs_Left[6]) {
+    pos -= 16;
+    if ((door_type_and_slot[door] & 0xfe) >= 0x42)
+      pos -= 12;
+    GetDoorDrawDataIndex_East(door ^ 8, door & 7);
+    dma_ptr = Dungeon_PrepOverlayDma_nextPrep(dma_ptr, pos);
+    Dungeon_LoadSingleDoorAttribute(door ^ 8);
+  }
+  GetDoorDrawDataIndex_West(door, door & 7);
+  return dma_ptr;
+}
+
+void GetDoorDrawDataIndex_West(int door, int r4_door) {  // 81fc18
+  uint8 door_type = door_type_and_slot[door] & 0xfe;
+  int x = door_open_closed_counter;
+  if (x == 0 || x == 4) {
+    DrawDoorToTileMap_West(door, r4_door);
+    return;
+  }
+  x += (door_type >= 0x42) ? 4 : 0;
+  x += (door_type == kDoorType_ShuttersTwoWay || door_type == kDoorType_Shutter) ? 2 : 0;
+  Object_Draw_DoorLeft_3x4(kDoorAnimLeftSrc[x >> 1], door);
+}
+
+void DrawDoorToTileMap_West(int door, int r4_door) {  // 81fc45
+  Object_Draw_DoorLeft_3x4(kDoorTypeSrcData3[GetDoorGraphicsIndex(door, r4_door) >> 1], door);
+}
+
+void GetDoorDrawDataIndex_East_clean_door_index(int door) {  // 81fc80
+  GetDoorDrawDataIndex_East(door, door);
+}
+
+int DoorDoorStep1_East(int door, int dma_ptr) {  // 81fc8a
+  int pos = dung_door_tilemap_address[door];
+  if ((pos & 0x7ff) < kDoorPositionToTilemapOffs_Right[6]) {
+    pos += 16;
+    if ((door_type_and_slot[door] & 0xfe) >= 0x42)
+      pos += 12;
+    GetDoorDrawDataIndex_West(door ^ 8, door & 7);
+    dma_ptr = Dungeon_PrepOverlayDma_nextPrep(dma_ptr, pos);
+    Dungeon_LoadSingleDoorAttribute(door ^ 8);
+  }
+  GetDoorDrawDataIndex_East(door, door & 7);
+  return dma_ptr;
+}
+
+void GetDoorDrawDataIndex_East(int door, int r4_door) {  // 81fcd6
+  uint8 door_type = door_type_and_slot[door] & 0xfe;
+  int x = door_open_closed_counter;
+  if (x == 0 || x == 4) {
+    DrawDoorToTileMap_East(door, r4_door);
+    return;
+  }
+  x += (door_type >= 0x42) ? 4 : 0;
+  x += (door_type == kDoorType_ShuttersTwoWay || door_type == kDoorType_Shutter) ? 2 : 0;
+  Object_Draw_DoorRight_3x4(kDoorAnimRightSrc[x >> 1], door);
+}
+
+void DrawDoorToTileMap_East(int door, int r4_door) {  // 81fd03
+  Object_Draw_DoorRight_3x4(kDoorTypeSrcData4[GetDoorGraphicsIndex(door, r4_door) >> 1], door);
+}
+
+uint8 GetDoorGraphicsIndex(int door, int r4_door) {  // 81fd79
+  uint8 door_type = door_type_and_slot[door] & 0xfe;
+  if (dung_door_opened_incl_adjacent & kUpperBitmasks[r4_door])
+    door_type = kDoorTypeRemap[door_type >> 1];
+  return door_type;
+}
+
+void ClearExplodingWallFromTileMap_ClearOnePair(uint16 *dst, const uint16 *src) {  // 81fddb
+  for (int i = 2; i != 0; i--) {
+    for (int j = 0; j < 12; j++)
+      dst[XY(0, j)] = src[j];
+    dst++;
+    src += 12;
+  }
+}
+
+void Dungeon_DrawRoomOverlay_Apply(int p) {  // 81fe41
+  for (int j = 0; j < 4; j++, p += 64) {
+    for (int i = 0; i < 4; i++) {
+      uint16 t = dung_bg2[p + i] & 0x3fe;
+      dung_bg2_attr_table[p + i] = (t == 0xee || t == 0xfe) ? 0 : 0x20;
+    }
+  }
+}
+
+void ApplyGrayscaleFixed_Incremental() {  // 81feb0
+  uint8 a = COLDATA_copy0 & 0x1f;
+  if (a == overworld_fixed_color_plusminus)
+    return;
+  a += (a < overworld_fixed_color_plusminus) ? 1 : -1;
+  Dungeon_ApproachFixedColor_variable(a);
+}
+
+void Dungeon_ApproachFixedColor_variable(uint8 a) {  // 81fec1
+  COLDATA_copy0 = a | 0x20;
+  COLDATA_copy1 = a | 0x40;
+  COLDATA_copy2 = a | 0x80;
+}
+
+void Module_PreDungeon() {  // 82821e
+  sound_effect_ambient = 5;
+  sound_effect_1 = 0;
+  dungeon_room_index = 0;
+  dungeon_room_index_prev = 0;
+  dung_savegame_state_bits = 0;
+
+  agahnim_pal_setting[0] = agahnim_pal_setting[1] = agahnim_pal_setting[2] = 0;
+  agahnim_pal_setting[3] = agahnim_pal_setting[4] = agahnim_pal_setting[5] = 0;
+
+  Dungeon_LoadEntrance();
+  uint8 d = cur_palace_index_x2;
+  link_num_keys = (d != 0xff) ? link_keys_earned_per_dungeon[d == 2 ? 0 : (d >> 1)] : 0xff;
+  Hud_Rebuild();
+  dung_num_lit_torches = 0;
+  hdr_dungeon_dark_with_lantern = 0;
+  Dungeon_LoadAndDrawRoom();
+  Dungeon_LoadCustomTileAttr();
+
+  DecompressAnimatedDungeonTiles(kDungAnimatedTiles[main_tile_theme_index]);
+  Dungeon_LoadAttributeTable();
+  misc_sprites_graphics_index = 10;
+  InitializeTilesets();
+  palette_sp6r_indoors = 10;
+  Dungeon_LoadPalettes();
+  if (link_is_bunny_mirror | link_is_bunny)
+    LoadGearPalettes_bunny();
+
+  dung_loade_bgoffs_h_copy = (dungeon_room_index & 0xf) << 9;
+  dung_loade_bgoffs_v_copy = swap16((dungeon_room_index & 0xff0) >> 3);
+
+  if (dungeon_room_index == 0x104 && sram_progress_flags & 0x10)
+    WORD(dung_want_lights_out) = 0;
+
+  SetAndSaveVisitedQuadrantFlags();
+  CGWSEL_copy = 2;
+  CGADSUB_copy = 0xb3;
+
+  uint8 x = dung_num_lit_torches;
+  if (!dung_want_lights_out) {
+    x = 3;
+    CGADSUB_copy = dung_hdr_bg2_properties == 7 ? 0x32 :
+      dung_hdr_bg2_properties == 4 ? 0x62 : 0x20;
+  }
+  overworld_fixed_color_plusminus = kLitTorchesColorPlus[x];
+  Dungeon_ApproachFixedColor_variable(overworld_fixed_color_plusminus);
+  BYTE(palette_filter_countdown) = 0x1f;
+  mosaic_target_level = 0;
+  BYTE(darkening_or_lightening_screen) = 2;
+  overworld_palette_aux_or_main = 0;
+  link_speed_modifier = 0;
+  button_mask_b_y = 0;
+  button_b_frames = 0;
+  Dungeon_ResetTorchBackgroundAndPlayer();
+  Link_CheckBunnyStatus();
+  ResetThenCacheRoomEntryProperties();
+  if (follower_indicator == 13) {
+    follower_indicator = 0;
+    super_bomb_indicator_unk2 = 0;
+    Hud_RemoveSuperBombIndicator();
+  }
+  BGMODE_copy = 9;
+  Follower_Initialize();
+  Sprite_ResetAll();
+  Dungeon_ResetSprites();
+  byte_7E02F0 = 0;
+  flag_skip_call_tag_routines++;
+  if (!sram_progress_indicator && !(sram_progress_flags & 0x10)) {
+    COLDATA_copy0 = 0x30;
+    COLDATA_copy1 = 0x50;
+    COLDATA_copy2 = 0x80;
+    dung_want_lights_out = dung_want_lights_out_copy = 0;
+    Link_TuckIntoBed();
+  }
+  saved_module_for_menu = 7;
+  main_module_index = 7;
+  submodule_index = 15;
+  Dungeon_LoadSongBankIfNeeded();
+  Module_PreDungeon_setAmbientSfx();
+}
+
+void Module_PreDungeon_setAmbientSfx() {  // 82838c
+  if (sram_progress_indicator < 2) {
+    sound_effect_ambient = 5;
+    if (!sign8(dung_cur_floor) && dungeon_room_index != 2 && dungeon_room_index != 18)
+      sound_effect_ambient = 3;
+  }
+}
+
+void LoadOWMusicIfNeeded() {  // 82854c
+  if (!flag_which_music_type)
+    return;
+  flag_which_music_type = 0;
+  LoadOverworldSongs();
+}
+
+void Module07_Dungeon() {  // 8287a2
+  Dungeon_HandleLayerEffect();
+  kDungeonSubmodules[submodule_index]();
+
+  // When having the somaria on door button and exiting in skull woods, 
+  // don't overwrite submodule_index
+  if (enhanced_features0 & kFeatures0_MiscBugFixes && main_module_index != 7)
+    goto skip;
+
+  dung_misc_objs_index = 0;
+  Dungeon_PushBlock_Handler();
+  if (submodule_index) goto skip;
+  Graphics_LoadChrHalfSlot();
+  Dungeon_HandleCamera();
+  if (submodule_index) goto skip;
+  Dungeon_HandleRoomTags();
+  if (submodule_index) goto skip;
+  Dungeon_ProcessTorchesAndDoors();
+  if (dung_unk_blast_walls_2)
+    Dungeon_ClearAwayExplodingWall();
+  if (!is_standing_in_doorway)
+    Dungeon_TryScreenEdgeTransition();
+skip:
+  OrientLampLightCone();
+
+  int bg2x = BG2HOFS_copy2;
+  int bg2y = BG2VOFS_copy2;
+  int bg1x = BG1HOFS_copy2;
+  int bg1y = BG1VOFS_copy2;
+
+  BG2HOFS_copy2 = BG2HOFS_copy = bg2x + bg1_x_offset;
+  BG2VOFS_copy2 = BG2VOFS_copy = bg2y + bg1_y_offset;
+  BG1HOFS_copy2 = BG1HOFS_copy = bg1x + bg1_x_offset;
+  BG1VOFS_copy2 = BG1VOFS_copy = bg1y + bg1_y_offset;
+
+  if (dung_hdr_collision_2_mirror) {
+    BG1HOFS_copy2 = BG1HOFS_copy = bg1x = BG2HOFS_copy2 + dung_floor_x_offs;
+    BG1VOFS_copy2 = BG1VOFS_copy = bg1y = BG2VOFS_copy2 + dung_floor_y_offs;
+  }
+
+  Sprite_Dungeon_DrawAllPushBlocks();
+  Sprite_Main();
+
+  BG2HOFS_copy2 = bg2x;
+  BG2VOFS_copy2 = bg2y;
+  BG1HOFS_copy2 = bg1x;
+  BG1VOFS_copy2 = bg1y;
+
+  LinkOam_Main();
+  Hud_RefillLogic();
+  Hud_FloorIndicator();
+}
+
+void Dungeon_TryScreenEdgeTransition() {  // 82885e
+  int dir;
+
+  if (link_y_vel != 0) {
+    int y = (link_y_coord & 0x1ff);
+    if ((dir = 3, y < 4) || (dir = 2, y >= 476))
+      goto trigger_trans;
+  }
+
+  if (link_x_vel != 0) {
+    int y = (link_x_coord & 0x1ff);
+    if ((dir = 1, y < 8) || (dir = 0, y >= 489))
+      goto trigger_trans;
+  }
+  return;
+
+trigger_trans:
+  if (!Link_CheckForEdgeScreenTransition() && main_module_index == 7) {
+    Dungeon_HandleEdgeTransitionMovement(dir);
+    if (main_module_index == 7)
+      submodule_index = 2;
+  }
+}
+
+void Dungeon_HandleEdgeTransitionMovement(int dir) {  // 8288c5
+  static const uint8 kLimitDirectionOnOneAxis[] = { 0x3, 0x3, 0xc, 0xc };
+  link_direction &= kLimitDirectionOnOneAxis[dir];
+  switch (dir) {
+  case 0: Dungeon_StartInterRoomTrans_Right(); break;
+  case 1: Dungeon_StartInterRoomTrans_Left(); break;
+  case 2: Dungeon_StartInterRoomTrans_Down(); break;
+  case 3: Dungeon_StartInterRoomTrans_Up(); break;
+  default:
+    assert(0);
+  }
+}
+
+void Module07_00_PlayerControl() {  // 8288de
+  if (!(flag_custom_spell_anim_active | flag_is_link_immobilized | flag_block_link_menu)) {
+    if (filtered_joypad_H & 0x10) {  // start
+      overworld_map_state = 0;
+      submodule_index = 1;
+      saved_module_for_menu = main_module_index;
+      main_module_index = 14;
+      return;
+    } else if (DidPressButtonForMap()) {  // x
+      if ((uint8)cur_palace_index_x2 != 0xff && (uint8)dungeon_room_index) {
+        overworld_map_state = 0;
+        submodule_index = 3;
+        saved_module_for_menu = main_module_index;
+        main_module_index = 14;
+        return;
+      }
+    } else if (joypad1H_last & 0x20) {  // select
+      if (sram_progress_indicator) {
+        overworld_map_state = 0;
+        DisplaySelectMenu();
+        return;
+      }
+    }
+    Hud_HandleItemSwitchInputs();
+  }
+  Link_Main();
+}
+
+void Module07_01_SubtileTransition() {  // 82897c
+  link_y_coord_prev = link_y_coord;
+  link_x_coord_prev = link_x_coord;
+  Link_HandleMovingAnimation_FullLongEntry();
+  kDungeon_IntraRoomTrans[subsubmodule_index]();
+}
+
+void DungeonTransition_Subtile_ResetShutters() {  // 828995
+  BYTE(dung_flag_trapdoors_down) = 0;
+  BYTE(door_animation_step_indicator) = 7;
+  uint8 bak = submodule_index;
+  OperateShutterDoors();
+  submodule_index = bak;
+  BYTE(palette_filter_countdown) = 31;
+  mosaic_target_level = 0;
+  subsubmodule_index++;
+}
+
+void DungeonTransition_Subtile_PrepTransition() {  // 8289b6
+  darkening_or_lightening_screen = 0;
+  palette_filter_countdown = 0;
+  mosaic_target_level = 31;
+  unused_config_gfx = 0;
+  dung_flag_somaria_block_switch = 0;
+  dung_flag_statechange_waterpuzzle = 0;
+  subsubmodule_index++;
+}
+
+void DungeonTransition_Subtile_ApplyFilter() {  // 8289d8
+  if (!dung_want_lights_out) {
+    subsubmodule_index++;
+    return;
+  }
+  ApplyPaletteFilter_bounce();
+  if (BYTE(palette_filter_countdown))
+    ApplyPaletteFilter_bounce();
+}
+
+void DungeonTransition_Subtile_TriggerShutters() {  // 8289f0
+  ResetThenCacheRoomEntryProperties();
+  if (!BYTE(dung_flag_trapdoors_down)) {
+    BYTE(dung_flag_trapdoors_down)++;
+    BYTE(dung_cur_door_pos) = 0;
+    BYTE(door_animation_step_indicator) = 0;
+    submodule_index = 5;
+  }
+}
+
+void Module07_02_SupertileTransition() {  // 828a26
+  link_y_coord_prev = link_y_coord;
+  link_x_coord_prev = link_x_coord;
+  if (subsubmodule_index != 0) {
+    if (subsubmodule_index >= 7)
+      Graphics_IncrementalVRAMUpload();
+    Dungeon_LoadAttribute_Selectable();
+  }
+  Link_HandleMovingAnimation_FullLongEntry();
+  kDungeon_InterRoomTrans[subsubmodule_index]();
+}
+
+void Module07_02_00_InitializeTransition() {  // 828a4f
+  uint8 bak = hdr_dungeon_dark_with_lantern;
+  ResetTransitionPropsAndAdvanceSubmodule();
+  hdr_dungeon_dark_with_lantern = bak;
+}
+
+void Module07_02_01_LoadNextRoom() {  // 828a5b
+  Dungeon_LoadRoom();
+  ResetStarTileGraphics();
+  LoadTransAuxGFX_sprite();
+  subsubmodule_index++;
+  overworld_map_state = 0;
+  BYTE(dungeon_room_index2) = BYTE(dungeon_room_index);
+  Dungeon_ResetSprites();
+  if (!hdr_dungeon_dark_with_lantern)
+    MirrorBg1Bg2Offs();
+  hdr_dungeon_dark_with_lantern = 0;
+}
+
+void Dungeon_InterRoomTrans_State3() {  // 828a87
+  if (dung_want_lights_out | dung_want_lights_out_copy)
+    TS_copy = 0;
+  Dungeon_AdjustForRoomLayout();
+  LoadNewSpriteGFXSet();
+  MirrorBg1Bg2Offs();
+  WaterFlood_BuildOneQuadrantForVRAM();
+  subsubmodule_index++;
+}
+
+void Dungeon_InterRoomTrans_State10() {  // 828aa5
+  if (dung_want_lights_out | dung_want_lights_out_copy)
+    ApplyPaletteFilter_bounce();
+  Dungeon_InterRoomTrans_notDarkRoom();
+}
+
+void Dungeon_SpiralStaircase11() {  // 828aaf
+  ApplyPaletteFilter_bounce();
+  WaterFlood_BuildOneQuadrantForVRAM();
+  subsubmodule_index++;
+}
+
+void Dungeon_InterRoomTrans_notDarkRoom() {  // 828ab3
+  WaterFlood_BuildOneQuadrantForVRAM();
+  subsubmodule_index++;
+}
+
+void Dungeon_InterRoomTrans_State9() {  // 828aba
+  if (dung_want_lights_out | dung_want_lights_out_copy)
+    ApplyPaletteFilter_bounce();
+  Dungeon_InterRoomTrans_State4();
+}
+
+void Dungeon_SpiralStaircase12() {  // 828ac4
+  ApplyPaletteFilter_bounce();
+  Dungeon_PrepareNextRoomQuadrantUpload();
+  subsubmodule_index++;
+}
+
+void Dungeon_InterRoomTrans_State4() {  // 828ac8
+  Dungeon_PrepareNextRoomQuadrantUpload();
+  subsubmodule_index++;
+}
+
+void Dungeon_InterRoomTrans_State12() {  // 828acf
+  if (submodule_index == 2) {
+    if (overworld_map_state != 5)
+      return;
+    SubtileTransitionCalculateLanding();
+    if (dung_want_lights_out | dung_want_lights_out_copy)
+      ApplyPaletteFilter_bounce();
+  }
+  subsubmodule_index++;
+  Dungeon_ResetTorchBackgroundAndPlayer();
+}
+
+void Dungeon_Staircase14() {  // 828aed
+  subsubmodule_index++;
+  Dungeon_ResetTorchBackgroundAndPlayer();
+}
+
+void Dungeon_ResetTorchBackgroundAndPlayer() {  // 828aef
+  uint8 ts = kSpiralTab1[dung_hdr_bg2_properties], tm = 0x16;
+  if (sign8(ts))
+    tm = 0x17, ts = 0;
+  if (dung_hdr_bg2_properties == 2)
+    ts = 3;
+  TM_copy = tm;
+  TS_copy = ts;
+  Hud_RestoreTorchBackground();
+  Dungeon_ResetTorchBackgroundAndPlayerInner();
+}
+
+void Dungeon_ResetTorchBackgroundAndPlayerInner() {  // 828b0c
+  Ancilla_TerminateSelectInteractives(0);
+  if (link_is_running && !(enhanced_features0 & kFeatures0_TurnWhileDashing)) {
+    link_auxiliary_state = 0;
+    link_incapacitated_timer = 0;
+    link_actual_vel_z = 0xff;
+    g_ram[0xc7] = 0xff;
+    link_delay_timer_spin_attack = 0;
+    link_speed_setting = 0;
+    swimcoll_var5[0] &= ~0xff;
+    link_is_running = 0;
+    link_player_handler_state = 0;
+  }
+}
+
+void Dungeon_InterRoomTrans_State7() {  // 828b2e
+  BG1HOFS_copy2 = BG2HOFS_copy2;
+  BG1VOFS_copy2 = BG2VOFS_copy2;
+
+  if (dungeon_room_index != 54 && dungeon_room_index != 56) {
+    uint16 y = kSpiralTab1[dung_hdr_bg2_properties] ? 0x116 : 0x16;
+    if (y != (TM_copy | TS_copy << 8) && (TM_copy == 0x17 || (TM_copy | TS_copy) != 0x17))
+      TM_copy = y, TS_copy = y >> 8;
+  }
+  DungeonTransition_RunFiltering();
+}
+
+void DungeonTransition_RunFiltering() {  // 828b67
+  if (dung_want_lights_out | dung_want_lights_out_copy) {
+    overworld_fixed_color_plusminus = kLitTorchesColorPlus[dung_want_lights_out ? dung_num_lit_torches : 3];
+    Dungeon_ApproachFixedColor_variable(overworld_fixed_color_plusminus);
+    mosaic_target_level = 0;
+  }
+  Dungeon_HandleTranslucencyAndPalette();
+}
+
+void Module07_02_FadedFilter() {  // 828b92
+  if (dung_want_lights_out | dung_want_lights_out_copy) {
+    ApplyPaletteFilter_bounce();
+    if (BYTE(palette_filter_countdown))
+      ApplyPaletteFilter_bounce();
+  } else {
+    subsubmodule_index++;
+  }
+}
+
+void Dungeon_InterRoomTrans_State15() {  // 828bae
+  ResetThenCacheRoomEntryProperties();
+  if (!BYTE(dung_flag_trapdoors_down) && (BYTE(dungeon_room_index) != 172 || dung_savegame_state_bits & 0x3000)) {
+    BYTE(dung_flag_trapdoors_down) = 1;
+    BYTE(dung_cur_door_pos) = 0;
+    BYTE(door_animation_step_indicator) = 0;
+    submodule_index = 5;
+  }
+  Dungeon_PlayMusicIfDefeated();
+}
+
+void Dungeon_PlayMusicIfDefeated() {  // 828bd7
+  uint8 x = 0x14;
+  if (dungeon_room_index != 18) {
+    x = 0x10;
+    if (dungeon_room_index != 2) {
+      if (FindInWordArray(kBossRooms, dungeon_room_index, countof(kBossRooms)) < 0)
+        return;
+      if (Sprite_CheckIfScreenIsClear())
+        return;
+      x = 0x15;
+    }
+  }
+  music_control = x;
+}
+
+void Module07_03_OverlayChange() {  // 828c05
+  const uint8 *overlay_p = kDungeonRoomOverlay + kDungeonRoomOverlayOffs[dung_overlay_to_load];
+  Dungeon_DrawRoomOverlay(overlay_p);
+  int dst_pos = 0;
+  for (;;) {
+    uint16 a = WORD(*overlay_p);
+    if (a == 0xffff)
+      break;
+    int p = (overlay_p[0] >> 2) | (overlay_p[1] >> 2) << 6;
+    dst_pos = Dungeon_PrepOverlayDma_nextPrep(dst_pos, p * 2);
+    Dungeon_DrawRoomOverlay_Apply(p);
+    overlay_p += 3;
+  }
+  nmi_copy_packets_flag = 1;
+  submodule_index = 0;
+}
+
+void Module07_04_UnlockDoor() {  // 828c0a
+  Dungeon_OpeningLockedDoor_Combined(false);
+}
+
+void Module07_05_ControlShutters() {  // 828c0f
+  OperateShutterDoors();
+}
+
+void Module07_06_FatInterRoomStairs() {  // 828c14
+  if (subsubmodule_index >= 3)
+    Dungeon_LoadAttribute_Selectable();
+
+  if (subsubmodule_index >= 13) {
+    Graphics_IncrementalVRAMUpload();
+    if (!staircase_var1)
+      goto table;
+    if (staircase_var1-- == 0x10)
+      link_speed_modifier = 2;
+    link_direction = which_staircase_index & 4 ? 4 : 8;
+    Link_HandleVelocity();
+    Dungeon_HandleCamera();
+  }
+  Link_HandleMovingAnimation_FullLongEntry();
+table:
+  switch (subsubmodule_index) {
+  case 0: ResetTransitionPropsAndAdvance_ResetInterface(); break;
+  case 1:
+    ApplyPaletteFilter_bounce();
+    if (BYTE(palette_filter_countdown))
+      ApplyPaletteFilter_bounce();
+    break;
+  case 2: Dungeon_InitializeRoomFromSpecial(); break;
+  case 3: DungeonTransition_TriggerBGC34UpdateAndAdvance(); break;
+  case 4: DungeonTransition_TriggerBGC56UpdateAndAdvance(); break;
+  case 5: DungeonTransition_LoadSpriteGFX(); break;
+  case 6: DungeonTransition_AdjustForFatStairScroll(); break;
+  case 7: Dungeon_InterRoomTrans_State4(); break;
+  case 8: Dungeon_InterRoomTrans_notDarkRoom(); break;
+  case 9: Dungeon_InterRoomTrans_State4(); break;
+  case 10: Dungeon_SpiralStaircase11(); break;
+  case 11: Dungeon_SpiralStaircase12(); break;
+  case 12: Dungeon_SpiralStaircase11(); break;
+  case 13: Dungeon_SpiralStaircase12(); break;
+  case 14: Dungeon_DoubleApplyAndIncrementGrayscale(); break;
+  case 15: Dungeon_Staircase14(); break;
+  case 16:
+    if (!(BYTE(darkening_or_lightening_screen) | BYTE(palette_filter_countdown)) && overworld_map_state == 5)
+      ResetThenCacheRoomEntryProperties();
+    break;
+  }
+}
+
+void Module07_0E_01_HandleMusicAndResetProps() {  // 828c78
+  if ((dungeon_room_index == 7 || dungeon_room_index == 23 && !ZeldaIsPlayingMusicTrack(17)) && !(link_which_pendants & 1))
+    music_control = 0xf1;
+  staircase_var1 = (which_staircase_index & 4) ? 106 : 88;
+  overworld_map_state = 0;
+  ResetTransitionPropsAndAdvanceSubmodule();
+}
+
+void ResetTransitionPropsAndAdvance_ResetInterface() {  // 828ca9
+  overworld_map_state = 0;
+  ResetTransitionPropsAndAdvanceSubmodule();
+}
+
+void ResetTransitionPropsAndAdvanceSubmodule() {  // 828cac
+  WORD(mosaic_level) = 0;
+  darkening_or_lightening_screen = 0;
+  palette_filter_countdown = 0;
+  mosaic_target_level = 31;
+  unused_config_gfx = 0;
+  dung_num_lit_torches = 0;
+  if (hdr_dungeon_dark_with_lantern) {
+    CGWSEL_copy = 0x02;
+    CGADSUB_copy = 0xB3;
+  }
+  hdr_dungeon_dark_with_lantern = 0;
+  Dungeon_ResetTorchBackgroundAndPlayerInner();
+  Overworld_CopyPalettesToCache();
+  subsubmodule_index += 1;
+}
+
+void Dungeon_InitializeRoomFromSpecial() {  // 828ce2
+  Dungeon_AdjustAfterSpiralStairs();
+  Dungeon_LoadRoom();
+  ResetStarTileGraphics();
+  LoadTransAuxGFX();
+  Dungeon_LoadCustomTileAttr();
+  BYTE(dungeon_room_index2) = BYTE(dungeon_room_index);
+  Follower_Initialize();
+  subsubmodule_index += 1;
+}
+
+void DungeonTransition_LoadSpriteGFX() {  // 828d10
+  LoadNewSpriteGFXSet();
+  Dungeon_ResetSprites();
+  DungeonTransition_RunFiltering();
+}
+
+void DungeonTransition_AdjustForFatStairScroll() {  // 828d1b
+  MirrorBg1Bg2Offs();
+  Dungeon_AdjustForRoomLayout();
+  uint8 ts = kSpiralTab1[dung_hdr_bg2_properties];
+  uint8 tm = 0x16;
+  if (sign8(ts))
+    tm = 0x17, ts = 0;
+  TM_copy = tm;
+  TS_copy = ts;
+
+  link_speed_modifier = 1;
+  if (which_staircase_index & 4) {
+    dung_cur_floor--;
+    staircase_var1 = 32;
+    sound_effect_1 = 0x19;
+  } else {
+    dung_cur_floor++;
+    staircase_var1 = 48;
+    sound_effect_1 = 0x17;
+  }
+  sound_effect_2 = 0x24;
+  Dungeon_PlayBlipAndCacheQuadrantVisits();
+  Dungeon_InterRoomTrans_notDarkRoom();
+}
+
+void ResetThenCacheRoomEntryProperties() {  // 828d71
+  overworld_map_state = 0;
+  subsubmodule_index = 0;
+  overworld_screen_transition = 0;
+  submodule_index = 0;
+  dung_flag_statechange_waterpuzzle = 0;
+  dung_flag_movable_block_was_pushed = 0;
+  CacheCameraProperties();
+}
+
+void DungeonTransition_TriggerBGC34UpdateAndAdvance() {  // 828e0f
+  PrepTransAuxGfx();
+  nmi_subroutine_index = nmi_disable_core_updates = 9;
+  subsubmodule_index += 1;
+}
+
+void DungeonTransition_TriggerBGC56UpdateAndAdvance() {  // 828e1d
+  nmi_subroutine_index = nmi_disable_core_updates = 10;
+  subsubmodule_index += 1;
+}
+
+void Module07_07_FallingTransition() {  // 828e27
+  if (subsubmodule_index >= 6) {
+    Graphics_IncrementalVRAMUpload();
+    Dungeon_LoadAttribute_Selectable();
+    ApplyGrayscaleFixed_Incremental();
+  }
+  kDungeon_Submodule_7_DownFloorTrans[subsubmodule_index]();
+}
+
+void Module07_07_00_HandleMusicAndResetRoom() {  // 828e63
+  if (dungeon_room_index == 0x10 || dungeon_room_index == 7 || dungeon_room_index == 0x17)
+    music_control = 0xf1;
+  ResetTransitionPropsAndAdvance_ResetInterface();
+}
+
+void Module07_07_06_SyncBG1and2() {  // 828e80
+  MirrorBg1Bg2Offs();
+  Dungeon_AdjustForRoomLayout();
+  uint8 ts = kSpiralTab1[dung_hdr_bg2_properties];
+  uint8 tm = 0x16;
+  if (sign8(ts))
+    tm = 0x17, ts = 0;
+  TM_copy = tm;
+  TS_copy = ts;
+  WaterFlood_BuildOneQuadrantForVRAM();
+  subsubmodule_index++;
+}
+
+void Module07_07_0F_FallingFadeIn() {  // 828ea1
+  ApplyPaletteFilter_bounce();
+  if (BYTE(darkening_or_lightening_screen))
+    return;
+  HIBYTE(tiledetect_which_y_pos[0]) = HIBYTE(link_y_coord) + (BYTE(link_y_coord) >= BYTE(tiledetect_which_y_pos[0]));
+  Dungeon_SetBossMusicUnorthodox();
+  if (BYTE(dungeon_room_index) == 0x89 || BYTE(dungeon_room_index) == 0x4f)
+    return;
+  if (BYTE(dungeon_room_index) == 0xA7) {
+    hud_floor_changed_timer = 0;
+    dung_cur_floor = 1;
+    return;
+  }
+  dung_cur_floor--;
+  Dungeon_PlayBlipAndCacheQuadrantVisits();
+}
+
+void Dungeon_PlayBlipAndCacheQuadrantVisits() {  // 828ec9
+  hud_floor_changed_timer = 1;
+  sound_effect_2 = 36;
+  SetAndSaveVisitedQuadrantFlags();
+}
+
+void Module07_07_10_LandLinkFromFalling() {  // 828ee0
+  HandleDungeonLandingFromPit();
+  if (submodule_index)
+    return;
+  submodule_index = 7;
+  subsubmodule_index = 17;
+  load_chr_halfslot_even_odd = 1;
+  Graphics_LoadChrHalfSlot();
+}
+
+void Module07_07_11_CacheRoomAndSetMusic() {  // 828efa
+  if (overworld_map_state == 5) {
+    ResetThenCacheRoomEntryProperties();
+    Dungeon_PlayMusicIfDefeated();
+    Graphics_LoadChrHalfSlot();
+  }
+}
+
+// straight staircase going down when walking south
+void Module07_08_NorthIntraRoomStairs() {  // 828f0c
+  uint8 t = staircase_var1;
+  if (t) {
+    staircase_var1--;
+    if (t == 20)
+      link_speed_modifier = 2;
+    Link_HandleVelocity();
+    ApplyLinksMovementToCamera();
+    Dungeon_HandleCamera();
+    Link_HandleMovingAnimation_FullLongEntry();
+  }
+  kDungeon_StraightStaircaseDown[subsubmodule_index]();
+}
+
+void Module07_08_00_InitStairs() {  // 828f35
+  draw_water_ripples_or_grass = 0;
+
+  uint8 v1 = 0x3c, sfx = 25;
+  if (link_direction & 8) {
+    v1 = 0x38, sfx = 23;
+    link_is_on_lower_level_mirror = 0;
+    if ((uint8)kind_of_in_room_staircase != 2)
+      link_is_on_lower_level = 0;
+  }
+  staircase_var1 = v1;
+  sound_effect_1 = sfx;
+  link_speed_modifier = 1;
+  subsubmodule_index++;
+}
+
+void Module07_08_01_ClimbStairs() {  // 828f5f
+  if (staircase_var1)
+    return;
+  if (link_direction & 4) {
+    link_is_on_lower_level_mirror = 1;
+    if ((uint8)kind_of_in_room_staircase != 2)
+      link_is_on_lower_level = 1;
+  }
+  subsubmodule_index = 0;
+  overworld_screen_transition = 0;
+  submodule_index = 0;
+  SetAndSaveVisitedQuadrantFlags();
+}
+
+// straight staircase going up when walking south
+void Module07_10_SouthIntraRoomStairs() {  // 828f88
+  uint8 t = staircase_var1;
+  if (t) {
+    staircase_var1--;
+    if (t == 20)
+      link_speed_modifier = 2;
+    Link_HandleVelocity();
+    ApplyLinksMovementToCamera();
+    Dungeon_HandleCamera();
+    Link_HandleMovingAnimation_FullLongEntry();
+  }
+  kDungeon_StraightStaircase[subsubmodule_index]();
+}
+
+void Module07_10_00_InitStairs() {  // 828fb1
+  uint8 v1 = 0x3c, sfx = 25;
+  if (link_direction & 4) {
+    v1 = 0x38, sfx = 23;
+    link_is_on_lower_level_mirror ^= 1;
+    if ((uint8)kind_of_in_room_staircase != 2)
+      link_is_on_lower_level ^= 1;
+  }
+  staircase_var1 = v1;
+  sound_effect_1 = sfx;
+  link_speed_modifier = 1;
+  subsubmodule_index++;
+}
+
+void Module07_10_01_ClimbStairs() {  // 828fe1
+  if (staircase_var1)
+    return;
+  if (link_direction & 8) {
+    link_is_on_lower_level_mirror ^= 1;
+    if ((uint8)kind_of_in_room_staircase != 2)
+      link_is_on_lower_level ^= 1;
+  }
+  subsubmodule_index = 0;
+  overworld_screen_transition = 0;
+  submodule_index = 0;
+  SetAndSaveVisitedQuadrantFlags();
+}
+
+void Module07_09_OpenCrackedDoor() {  // 82900f
+  OpenCrackedDoor();
+}
+
+// Used when lighting a lamp
+void Module07_0A_ChangeBrightness() {  // 829014
+  OrientLampLightCone();
+  ApplyGrayscaleFixed_Incremental();
+  if ((COLDATA_copy0 & 0x1f) != overworld_fixed_color_plusminus)
+    return;
+  submodule_index = 0;
+  subsubmodule_index = 0;
+}
+
+void Module07_0B_DrainSwampPool() {  // 82902d
+  static const int8 kTurnOffWater_Tab0[16] = { -1, -1, -1, 1, -1, -1, -1, 1, -1, -1, -1, 1, -1, -1, -1, 1 };
+  switch (subsubmodule_index) {
+  case 0: {
+    if (!(turn_on_off_water_ctr & 7)) {
+      int k = (turn_on_off_water_ctr >> 2) & 3;
+      if (water_hdma_var2 == water_hdma_var4) {
+        Dungeon_SetAttrForActivatedWaterOff();
+        return;
+      }
+      water_hdma_var2 += kTurnOffWater_Tab0[k];
+      water_hdma_var3 += kTurnOffWater_Tab0[k];
+    }
+    turn_on_off_water_ctr++;
+    AdjustWaterHDMAWindow();
+    break;
+  }
+  case 1: {
+    uint16 v = SrcPtr(0x1e0)[0];
+    for (int i = 0; i < 0x1000; i++)
+      dung_bg1[i] = v;
+    dung_cur_quadrant_upload = 0;
+    subsubmodule_index++;
+    break;
+  }
+  case 2: case 3: case 4: case 5:
+    Dungeon_FloodSwampWater_PrepTileMap();
+    break;
+  }
+}
+
+void Module07_0C_FloodSwampWater() {  // 82904a
+  int k;
+  static const int8 kTurnOnWater_Tab2[4] = { 1, 1, 1, -1 };
+  static const int8 kTurnOnWater_Tab1[4] = { 1, 2, 1, -1 };
+  static const int8 kTurnOnWater_Tab0[4] = { 1, -1, 1, -1 };
+
+  switch (subsubmodule_index) {
+  case 0: case 1: case 2: case 3:
+    Dungeon_FloodSwampWater_PrepTileMap();
+    break;
+  case 4: case 5: case 6: case 7: case 8:
+    if (!--turn_on_off_water_ctr) {
+      turn_on_off_water_ctr = 4;
+      int depth = ++subsubmodule_index - 4;
+      water_hdma_var3 = 8;
+      water_hdma_var5 = 0;
+      water_hdma_var2 = 0x30;
+      Dungeon_AdjustWaterVomit(SrcPtr(0x1654 + 0x10), depth);
+    }
+    break;
+  case 9:
+    W12SEL_copy = 3;
+    W34SEL_copy = 0;
+    WOBJSEL_copy = 0;
+    TMW_copy = 22;
+    TSW_copy = 1;
+    TS_copy = 1;
+    CGWSEL_copy = 2;
+    CGADSUB_copy = 98;
+    turn_on_off_water_ctr = 0;
+    subsubmodule_index++;
+    // fall through
+  case 10: {
+    k = (turn_on_off_water_ctr & 3);
+    uint16 r0 = 0x688 - BG2VOFS_copy2 - 0x24;
+    water_hdma_var3 += kTurnOnWater_Tab0[k];
+    water_hdma_var5 += kTurnOnWater_Tab1[k];
+    if (water_hdma_var5 >= r0) {
+      dung_hdr_bg2_properties = 7;
+      subsubmodule_index++;
+    }
+    turn_on_off_water_ctr++;
+    spotlight_y_lower = 0x688 - BG2VOFS_copy2 - water_hdma_var2;
+    spotlight_y_upper = spotlight_y_lower + water_hdma_var5;
+    AdjustWaterHDMAWindow_X(spotlight_y_upper);
+    break;
+  }
+  case 11: {
+    if (!(turn_on_off_water_ctr & 7)) {
+      k = (turn_on_off_water_ctr >> 2) & 3;
+      if (water_hdma_var2 == water_hdma_var4) {
+        Dungeon_SetAttrForActivatedWater();
+        return;
+      }
+      water_hdma_var2 += kTurnOnWater_Tab2[k];
+      water_hdma_var3 += kTurnOnWater_Tab2[k];
+
+      uint16 a = water_hdma_var4 - water_hdma_var2;
+      if (a == 0 || a == 8)
+        Dungeon_AdjustWaterVomit(SrcPtr(a == 0 ? 0x16b4 : 0x168c), 5);
+    }
+    turn_on_off_water_ctr++;
+    AdjustWaterHDMAWindow();
+    break;
+  }
+  }
+}
+
+void Module07_0D_FloodDam() {  // 82904f
+  FloodDam_PrepFloodHDMA();
+  kWatergateFuncs[subsubmodule_index]();
+}
+
+void Module07_0E_SpiralStairs() {  // 829054
+  if (subsubmodule_index >= 7) {
+    Graphics_IncrementalVRAMUpload();
+    Dungeon_LoadAttribute_Selectable();
+  }
+  HandleLinkOnSpiralStairs();
+  kDungeon_SpiralStaircase[subsubmodule_index]();
+}
+
+void Dungeon_DoubleApplyAndIncrementGrayscale() {  // 829094
+  ApplyPaletteFilter_bounce();
+  ApplyPaletteFilter_bounce();
+  ApplyGrayscaleFixed_Incremental();
+}
+
+void Module07_0E_02_ApplyFilterIf() {  // 8290a1
+  if (staircase_var1 < 9) {
+    ApplyPaletteFilter_bounce();
+    if (palette_filter_countdown)
+      ApplyPaletteFilter_bounce();
+  }
+  if (staircase_var1 != 0) {
+    staircase_var1--;
+    return;
+  }
+  tagalong_var5 = link_visibility_status = 12;
+}
+
+void Dungeon_SyncBackgroundsFromSpiralStairs() {  // 8290c7
+  if (follower_indicator == 6 && BYTE(dungeon_room_index) == 100)
+    follower_indicator = 0;
+  uint8 bak = link_is_on_lower_level;
+  link_y_coord += which_staircase_index & 4 ? 48 : -48;
+  link_is_on_lower_level = kTeleportPitLevel2[cur_staircase_plane];
+  SpiralStairs_MakeNearbyWallsHighPriority_Exiting();
+  link_is_on_lower_level = bak;
+  link_y_coord += which_staircase_index & 4 ? -48 : 48;
+  BG1HOFS_copy2 = BG2HOFS_copy2;
+  BG1VOFS_copy2 = BG2VOFS_copy2;
+  Dungeon_AdjustForRoomLayout();
+  uint8 ts = kSpiralTab1[dung_hdr_bg2_properties], tm = 0x16;
+  if (sign8(ts))
+    tm = 0x17, ts = 0;
+  if (dung_hdr_bg2_properties == 2)
+    ts = 3;
+  TM_copy = tm;
+  TS_copy = ts;
+  dung_cur_floor += (which_staircase_index & 4) ? -1 : 1;
+  staircase_var1 = 24;
+  Dungeon_PlayBlipAndCacheQuadrantVisits();
+  Hud_RestoreTorchBackground();
+  Dungeon_InterRoomTrans_notDarkRoom();
+}
+
+void Dungeon_AdvanceThenSetBossMusicUnorthodox() {  // 82915b
+  Dungeon_ResetTorchBackgroundAndPlayerInner();
+  staircase_var1 = 0x38;
+  subsubmodule_index++;
+  Dungeon_SetBossMusicUnorthodox();
+}
+
+void Dungeon_SetBossMusicUnorthodox() {  // 829165
+  uint8 x = 0x1c;
+  if (dungeon_room_index != 16) {
+    x = 0x15;
+    if (dungeon_room_index != 7) {
+      x = 0x11;
+      if (dungeon_room_index != 23 || ZeldaIsPlayingMusicTrack(17))
+        return;
+    }
+    if (music_unk1 != 0xf1 && (link_which_pendants & 1))
+      return;
+  }
+  music_control = x;
+}
+
+void Dungeon_SpiralStaircase17() {  // 82919b
+  SpiralStairs_FindLandingSpot();
+  if (!--staircase_var1) {
+    staircase_var1 = which_staircase_index & 4 ? 10 : 24;
+    subsubmodule_index++;
+  }
+}
+
+void Dungeon_SpiralStaircase18() {  // 8291b5
+  SpiralStairs_FindLandingSpot();
+  if (!--staircase_var1) {
+    subsubmodule_index++;
+    overworld_map_state = 0;
+  }
+}
+
+void Module07_0E_00_InitPriorityAndScreens() {  // 8291c4
+  SpiralStairs_MakeNearbyWallsHighPriority_Entering();
+  if (link_is_on_lower_level) {
+    TM_copy &= 0xf;
+    TS_copy |= 0x10;
+    link_is_on_lower_level = 3;
+  }
+  subsubmodule_index++;
+}
+
+void Module07_0E_13_SetRoomAndLayerAndCache() {  // 8291dd
+  link_is_on_lower_level_mirror = kTeleportPitLevel1[cur_staircase_plane];
+  link_is_on_lower_level = kTeleportPitLevel2[cur_staircase_plane];
+  TM_copy |= 0x10;
+  TS_copy &= 0xf;
+  if (!(which_staircase_index & 4))
+    SpiralStairs_MakeNearbyWallsLowPriority();
+  BYTE(dungeon_room_index2) = BYTE(dungeon_room_index);
+  ResetThenCacheRoomEntryProperties();
+}
+
+void RepositionLinkAfterSpiralStairs() {  // 82921a
+  link_visibility_status = 0;
+  tagalong_var5 = 0;
+
+  int i = (cur_staircase_plane == 0 && byte_7E0492 != 0) ? 1 : 0;
+  i += (which_staircase_index & 4) ? 2 : 0;
+
+  link_x_coord += kSpiralStaircaseX[i];
+  link_y_coord += kSpiralStaircaseY[i];
+
+  if (TM_copy & 0x10) {
+    if (cur_staircase_plane == 2) {
+      link_is_on_lower_level = 3;
+      TM_copy &= 0xf;
+      TS_copy |= 0x10;
+      if (byte_7E0492 != 2)
+        link_y_coord += 24;
+    }
+    Follower_Initialize();
+  } else {
+    if (cur_staircase_plane != 2) {
+      TM_copy |= 0x10;
+      TS_copy &= 0xf;
+      if (byte_7E0492 != 2)
+        link_y_coord -= 24;
+    }
+    Follower_Initialize();
+  }
+}
+
+void SpiralStairs_MakeNearbyWallsHighPriority_Exiting() {  // 8292b1
+  if (which_staircase_index & 4)
+    return;
+  int lf = (word_7E048C + 8) & 0x7f;
+  int x = 0, p;
+  while ((((p = dung_inter_starcases[x]) * 2) & 0x7f) != lf)
+    x++;
+  p -= 4;
+  word_7E048C = p * 2;
+  uint16 *dst = &dung_bg2[p];
+  for (int i = 0; i < 5; i++) {
+    dst[XY(0, 0)] |= 0x2000;
+    dst[XY(0, 1)] |= 0x2000;
+    dst[XY(0, 2)] |= 0x2000;
+    dst[XY(0, 3)] |= 0x2000;
+    dst += 1;
+  }
+}
+
+void Module07_0F_LandingWipe() {  // 82931d
+  kDungeon_Submodule_F[subsubmodule_index]();
+  Link_HandleMovingAnimation_FullLongEntry();
+  LinkOam_Main();
+}
+
+void Module07_0F_00_InitSpotlight() {  // 82932d
+  Spotlight_open();
+  subsubmodule_index++;
+}
+
+void Module07_0F_01_OperateSpotlight() {  // 829334
+  Sprite_Main();
+  IrisSpotlight_ConfigureTable();
+  if (!submodule_index) {
+    W12SEL_copy = 0;
+    W34SEL_copy = 0;
+    WOBJSEL_copy = 0;
+    TMW_copy = 0;
+    TSW_copy = 0;
+    subsubmodule_index = 0;
+    if (queued_music_control != 0xff)
+      music_control = queued_music_control;
+  }
+}
+
+// This is used for straight inter room stairs for example stairs to throne room in first dung
+void Module07_11_StraightInterroomStairs() {  // 829357
+  if (subsubmodule_index >= 3)
+    Dungeon_LoadAttribute_Selectable();
+  if (subsubmodule_index >= 13)
+    Graphics_IncrementalVRAMUpload();
+  if (staircase_var1) {
+    if (staircase_var1-- == 16)
+      link_speed_modifier = 2;
+    link_direction = (submodule_index == 18) ? 8 : 4;
+    Link_HandleVelocity();
+  }
+  Link_HandleMovingAnimation_FullLongEntry();
+  kDungeon_StraightStairs[subsubmodule_index]();
+}
+
+void Module07_11_00_PrepAndReset() {  // 8293bb
+  if (link_is_running) {
+    link_is_running = 0;
+    link_speed_setting = 2;
+  }
+  sound_effect_1 = (which_staircase_index & 4) ? 24 : 22;
+  if (dungeon_room_index == 48 || dungeon_room_index == 64)
+    music_control = 0xf1;
+  ResetTransitionPropsAndAdvance_ResetInterface();
+}
+
+void Module07_11_01_FadeOut() {  // 8293ed
+  if (staircase_var1 < 9) {
+    ApplyPaletteFilter_bounce();
+    if (BYTE(palette_filter_countdown) == 23)
+      subsubmodule_index++;
+  }
+}
+
+void Module07_11_02_LoadAndPrepRoom() {  // 829403
+  ApplyPaletteFilter_bounce();
+  Dungeon_LoadRoom();
+  Dungeon_RestoreStarTileChr();
+  LoadTransAuxGFX();
+  Dungeon_LoadCustomTileAttr();
+  Dungeon_AdjustForRoomLayout();
+  Follower_Initialize();
+  subsubmodule_index++;
+}
+
+void Module07_11_03_FilterAndLoadBGChars() {  // 829422
+  ApplyPaletteFilter_bounce();
+  DungeonTransition_TriggerBGC34UpdateAndAdvance();
+}
+
+void Module07_11_04_FilterDoBGAndResetSprites() {  // 82942a
+  ApplyPaletteFilter_bounce();
+  DungeonTransition_TriggerBGC56UpdateAndAdvance();
+  BYTE(dungeon_room_index2) = BYTE(dungeon_room_index);
+  Dungeon_ResetSprites();
+}
+
+void Module07_11_0B_PrepDestination() {  // 82943b
+  uint8 ts = kSpiralTab1[dung_hdr_bg2_properties], tm = 0x16;
+  if (sign8(ts))
+    tm = 0x17, ts = 0;
+  TM_copy = tm;
+  TS_copy = ts;
+
+  link_speed_modifier = 1;
+  dung_cur_floor += (which_staircase_index & 4) ? -1 : 1;
+  staircase_var1 = (which_staircase_index & 4) ? 0x32 : 0x3c;
+  sound_effect_1 = (which_staircase_index & 4) ? 25 : 23;
+
+  uint8 r0 = 0;
+  if (link_is_on_lower_level) {
+    link_y_coord += (submodule_index == 18) ? -32 : 32;
+    r0++;
+  }
+  link_is_on_lower_level_mirror = kTeleportPitLevel1[cur_staircase_plane];
+  link_is_on_lower_level = kTeleportPitLevel2[cur_staircase_plane];
+  if (link_is_on_lower_level) {
+    link_y_coord += (submodule_index == 18) ? -32 : 32;
+    r0++;
+  }
+
+  if (!r0) {
+    if (submodule_index == 18) {
+      link_y_coord += (which_staircase_index & 4) ? -24 : -8;
+    } else {
+      link_y_coord += 12;
+    }
+  }
+
+  Dungeon_PlayBlipAndCacheQuadrantVisits();
+  Hud_RestoreTorchBackground();
+  Dungeon_InterRoomTrans_notDarkRoom();
+}
+
+void Module07_11_09_LoadSpriteGraphics() {  // 8294e0
+  ApplyPaletteFilter_bounce();
+  subsubmodule_index--;
+  LoadNewSpriteGFXSet();
+  Dungeon_HandleTranslucencyAndPalette();
+}
+
+void Module07_11_19_SetSongAndFilter() {  // 8294ed
+  if (overworld_map_state == 5 && !BYTE(darkening_or_lightening_screen)) {
+    subsubmodule_index++;
+    if (dungeon_room_index == 48)
+      music_control = 0x1c;
+    else if (dungeon_room_index == 64)
+      music_control = 0x10;
+  }
+  ApplyGrayscaleFixed_Incremental();
+}
+
+void Module07_11_11_KeepSliding() {  // 829518
+  if (staircase_var1 == 0)
+    subsubmodule_index++;
+  else
+    ApplyGrayscaleFixed_Incremental();
+}
+
+void Module07_14_RecoverFromFall() {  // 829520
+  switch (subsubmodule_index) {
+  case 0:
+    Module07_14_00_ScrollCamera();
+    break;
+  case 1:
+    RecoverPositionAfterDrowning();
+    break;
+  }
+}
+
+void Module07_14_00_ScrollCamera() {  // 82952a
+  for (int i = 0; i < 2; i++) {
+    if (BG2HOFS_copy2 != BG2HOFS_copy2_cached)
+      BG2HOFS_copy2 += BG2HOFS_copy2 < BG2HOFS_copy2_cached ? 1 : -1;
+    if (BG2VOFS_copy2 != BG2VOFS_copy2_cached)
+      BG2VOFS_copy2 += BG2VOFS_copy2 < BG2VOFS_copy2_cached ? 1 : -1;
+  }
+  if (BG2HOFS_copy2 == BG2HOFS_copy2_cached && BG2VOFS_copy2 == BG2VOFS_copy2_cached)
+    subsubmodule_index++;
+  if (!hdr_dungeon_dark_with_lantern)
+    MirrorBg1Bg2Offs();
+}
+
+void Module07_15_WarpPad() {  // 82967a
+  if (subsubmodule_index >= 3) {
+    Graphics_IncrementalVRAMUpload();
+    Dungeon_LoadAttribute_Selectable();
+  }
+  kDungeon_Teleport[subsubmodule_index]();
+}
+
+void Module07_15_01_ApplyMosaicAndFilter() {  // 8296ac
+  ConditionalMosaicControl();
+  MOSAIC_copy = mosaic_level | 3;
+  ApplyPaletteFilter_bounce();
+}
+
+void Module07_15_04_SyncRoomPropsAndBuildOverlay() {  // 8296ba
+  ApplyGrayscaleFixed_Incremental();
+  if (dungeon_room_index == 0x17)
+    dung_cur_floor = 4;
+  MirrorBg1Bg2Offs();
+  Dungeon_AdjustForRoomLayout();
+  uint8 ts = kSpiralTab1[dung_hdr_bg2_properties], tm = 0x16;
+  if (sign8(ts))
+    tm = 0x17, ts = 0;
+  TM_copy = tm;
+  TS_copy = ts;
+  WaterFlood_BuildOneQuadrantForVRAM();
+  subsubmodule_index++;
+}
+
+void Module07_15_0E_FadeInFromWarp() {  // 8296ec
+  if (palette_filter_countdown & 1 && mosaic_level != 0)
+    mosaic_level -= 0x10;
+  BGMODE_copy = 9;
+  MOSAIC_copy = mosaic_level | 3;
+  ApplyPaletteFilter_bounce();
+}
+
+void Module07_15_0F_FinalizeAndCacheEntry() {  // 82970f
+  if (overworld_map_state == 5) {
+    SetAndSaveVisitedQuadrantFlags();
+    submodule_index = 0;
+    ResetThenCacheRoomEntryProperties();
+  }
+}
+
+void Module07_16_UpdatePegs() {  // 82972a
+  if (++subsubmodule_index & 3)
+    return;
+  switch (subsubmodule_index >> 2) {
+  case 0:
+  case 1: Module07_16_UpdatePegs_Step1(); break;
+  case 2: Module07_16_UpdatePegs_Step2(); break;
+  case 3: RecoverPegGFXFromMapping(); break;
+  case 4:
+    Dungeon_FlipCrystalPegAttribute();
+    subsubmodule_index = 0;
+    submodule_index = 0;
+    break;
+  }
+}
+
+void Module07_17_PressurePlate() {  // 8297c8
+  if (--subsubmodule_index)
+    return;
+  link_y_coord -= 2;
+  Dungeon_UpdateTileMapWithCommonTile((word_7E04B6 & 0x3f) << 3, (word_7E04B6 >> 3) & 0x1f8, 0xe);
+  submodule_index = saved_module_for_menu;
+}
+
+void Module07_18_RescuedMaiden() {  // 82980a
+  switch (subsubmodule_index) {
+  case 0:
+    PaletteFilter_RestoreBGSubstractiveStrict();
+    main_palette_buffer[0] = main_palette_buffer[32];
+    if (BYTE(darkening_or_lightening_screen) != 255)
+      return;
+    for (int i = 0; i < 0x1000; i++)
+      dung_bg2[i] = dung_bg1[i] = 0x1ec;
+    bg1_y_offset = 0;
+    bg1_x_offset = 0;
+    dung_floor_x_offs = 0;
+    dung_floor_y_offs = 0;
+    overworld_screen_transition = 0;
+    dung_cur_quadrant_upload = 0;
+    subsubmodule_index++;
+    break;
+  case 1: {
+    static const uint16 kCrystal_Tab0[7] = { 0x1618, 0x1658, 0x1658, 0x1618, 0x658, 0x1618, 0x1658 };
+    PaletteFilter_Crystal();
+    TS_copy = 1;
+    flag_is_link_immobilized = 2;
+    int j = FindInWordArray(kBossRooms, dungeon_room_index, countof(kBossRooms)) - 4;
+    uint16 *dst = &dung_bg1[kCrystal_Tab0[j] >> 1];
+    for (int n = 0, t = 0; n != 4; n++) {
+      for (int i = 0; i != 8; i++, t++) {
+        dst[i + XY(0, 0)] = 0x1f80 | t;
+        dst[i + XY(0, 4)] = 0x1f88 | t;
+      }
+      t += 8, dst += XY(0, 1);
+    }
+    subsubmodule_index++;
+    break;
+  }
+  case 2: case 4: case 6: case 8:
+    Dungeon_InterRoomTrans_notDarkRoom();
+    break;
+  case 3: case 5: case 7: case 9:
+    Dungeon_InterRoomTrans_State4();
+    break;
+  case 10:
+    is_nmi_thread_active++;
+    Polyhedral_InitializeThread();
+    CrystalCutscene_Initialize();
+    submodule_index = 0;
+    subsubmodule_index = 0;
+    break;
+  }
+}
+
+void Module07_19_MirrorFade() {  // 8298f7
+  // When using mirror
+  Overworld_ResetMosaic_alwaysIncrease();
+  if (!--INIDISP_copy) {
+    main_module_index = 5;
+    submodule_index = 0;
+    nmi_load_bg_from_vram = 0;
+    last_music_control = music_unk1;
+    if (palette_swap_flag)
+      Palette_RevertTranslucencySwap();
+  }
+}
+
+void Module07_1A_RoomDraw_OpenTriforceDoor_bounce() {  // 829916
+  static const uint16 kOpenGanonDoor_Tab[4] = { 0x2556, 0x2596, 0x25d6, 0x2616 };
+
+  flag_is_link_immobilized = 1;
+  if (R16 != 0) {
+    if (--BYTE(R16) || --HIBYTE(R16))
+      return;
+    sound_effect_ambient = 21;
+    link_force_hold_sword_up = 0;
+    link_cant_change_direction = 0;
+  }
+  flag_is_link_immobilized = 0;
+  if (++subsubmodule_index & 3)
+    return;
+
+  const uint16 *src = SrcPtr(kOpenGanonDoor_Tab[(subsubmodule_index - 4) >> 2]);
+  uint16 *dst = &dung_bg2[0];
+  for (int i = 0; i < 8; i++) {
+    dst[XY(44, 3)] = src[0];
+    dst[XY(44, 4)] = src[1];
+    dst[XY(44, 5)] = src[2];
+    dst[XY(44, 6)] = src[3];
+    dst += XY(1, 0), src += 4;
+  }
+
+  Dungeon_PrepOverlayDma_watergate(0, 0x1d8, 0x881, 8);
+  if (subsubmodule_index == 16) {
+    WriteAttr2(XY(44, 5), 0x202);
+    WriteAttr2(XY(44, 6), 0x202);
+    WriteAttr2(XY(50, 5), 0x200);
+    WriteAttr2(XY(50, 6), 0x200);
+    for (int i = 0; i != 6; i += 2) {
+      WriteAttr2(XY(45 + i, 0), 0x0);
+      WriteAttr2(XY(45 + i, 1), 0x0);
+      WriteAttr2(XY(45 + i, 2), 0x0);
+      WriteAttr2(XY(45 + i, 3), 0x0);
+      WriteAttr2(XY(45 + i, 4), 0x0);
+      WriteAttr2(XY(45 + i, 5), 0x0);
+      WriteAttr2(XY(45 + i, 6), 0x0);
+    }
+    room_bounds_y.a0 = -64;
+    submodule_index = 0;
+    subsubmodule_index = 0;
+  }
+  nmi_copy_packets_flag = 1;
+}
+
+void Module11_DungeonFallingEntrance() {  // 829af9
+  switch (subsubmodule_index) {
+  case 0:  // Module_11_00_SetSongAndInit
+    if (kEntranceData_musicTrack[which_entrance] != 3 || sram_progress_indicator >= 2)
+      music_control = 0xf1;
+    ResetTransitionPropsAndAdvance_ResetInterface();
+    break;
+  case 1:
+    if (!(frame_counter & 1))
+      ApplyPaletteFilter_bounce();
+    break;
+  case 2:
+    Module11_02_LoadEntrance();
+    break;
+  case 3:
+    DungeonTransition_LoadSpriteGFX();
+    break;
+  case 4:
+    INIDISP_copy = (INIDISP_copy + 1) & 0xf;
+    if (INIDISP_copy == 15)
+      subsubmodule_index++;
+  case 5:
+    HandleDungeonLandingFromPit();
+    if (submodule_index)
+      return;
+    main_module_index = 7;
+    flag_skip_call_tag_routines++;
+    Dungeon_PlayBlipAndCacheQuadrantVisits();
+    ResetThenCacheRoomEntryProperties();
+    music_control = queued_music_control;
+    last_music_control = music_unk1;
+    break;
+  }
+}
+
+void Module11_02_LoadEntrance() {  // 829b1c
+  EnableForceBlank();
+  CGWSEL_copy = 2;
+  Dungeon_LoadEntrance();
+
+  uint8 dung = BYTE(cur_palace_index_x2);
+  link_num_keys = (dung != 255) ? link_keys_earned_per_dungeon[((dung == 2) ? 0 : dung) >> 1] : 255;
+  Hud_Rebuild();
+  link_this_controls_sprite_oam = 4;
+  player_near_pit_state = 3;
+  link_visibility_status = 12;
+  link_speed_modifier = 16;
+
+  uint8 y = link_y_coord - BG2VOFS_copy2;
+  link_state_bits = 0;
+  link_picking_throw_state = 0;
+  some_animation_timer = 0;
+  dungeon_room_index_prev = dungeon_room_index;
+  tiledetect_which_y_pos[0] = link_y_coord;
+  link_y_coord -= y + 16;
+
+  uint8 bak = subsubmodule_index;
+  dung_num_lit_torches = 0;
+  hdr_dungeon_dark_with_lantern = 0;
+  Dungeon_LoadAndDrawRoom();
+  Dungeon_LoadCustomTileAttr();
+  DecompressAnimatedDungeonTiles(kDungAnimatedTiles[main_tile_theme_index]);
+  Dungeon_LoadAttributeTable();
+  subsubmodule_index = bak + 1;
+  misc_sprites_graphics_index = 10;
+  InitializeTilesets();
+  palette_sp6r_indoors = 10;
+  Dungeon_LoadPalettes();
+  Hud_RestoreTorchBackground();
+  button_mask_b_y = 0;
+  button_b_frames = 0;
+  Dungeon_ResetTorchBackgroundAndPlayer();
+  if (link_is_bunny_mirror)
+    LoadGearPalettes_bunny();
+  HDMAEN_copy = 0x80;
+  Hud_RefillLogic();
+  Module_PreDungeon_setAmbientSfx();
+  submodule_index = 7;
+  Dungeon_LoadSongBankIfNeeded();
+}
+
+void Dungeon_LoadSongBankIfNeeded() {  // 829bd7
+  if (queued_music_control == 0xff || queued_music_control == 0xf2)
+    return;
+
+  if (queued_music_control == 3 || queued_music_control == 7 || queued_music_control == 14) {
+    LoadOWMusicIfNeeded();
+  } else {
+    if (flag_which_music_type)
+      return;
+    flag_which_music_type = 1;
+    LoadDungeonSongs();
+  }
+}
+
+void Mirror_SaveRoomData() {  // 82a1b1
+  if (cur_palace_index_x2 == 0xff) {
+    sound_effect_1 = 60;
+    return;
+  }
+  submodule_index = 25;
+  subsubmodule_index = 0;
+  sound_effect_1 = 51;
+  Dungeon_FlagRoomData_Quadrants();
+  SaveDungeonKeys();
+}
+
+void SaveDungeonKeys() {  // 82a1c7
+  uint8 idx = cur_palace_index_x2;
+  if (idx == 0xff)
+    return;
+  if (idx == 2)
+    idx = 0;
+  link_keys_earned_per_dungeon[idx >> 1] = link_num_keys;
+}
+
+void Dungeon_AdjustAfterSpiralStairs() {  // 82a2f0
+  int xd = ((dungeon_room_index & 0xf) - (dungeon_room_index_prev & 0xf)) * 0x200;
+  link_x_coord += xd;
+  BG2HOFS_copy2 += xd;
+  room_bounds_x.a1 += xd;
+  room_bounds_x.b1 += xd;
+  room_bounds_x.a0 += xd;
+  room_bounds_x.b0 += xd;
+
+  int yd = (((dungeon_room_index & 0xf0) >> 4) - ((dungeon_room_index_prev & 0xf0) >> 4)) * 0x200;
+  link_y_coord += yd;
+  BG2VOFS_copy2 += yd;
+  room_bounds_y.a1 += yd;
+  room_bounds_y.b1 += yd;
+  room_bounds_y.a0 += yd;
+  room_bounds_y.b0 += yd;
+}
+
+void Dungeon_AdjustForTeleportDoors(uint8 room, uint8 flag) {  // 82a37c
+  dungeon_room_index2 = room;
+  dungeon_room_index_prev = room;
+
+  uint16 xx = (room & 0xf) * 2 - (link_x_coord >> 8) + flag;
+  link_x_coord += (xx << 8);
+  BG2HOFS_copy2 += (xx << 8);
+  room_bounds_x.a1 += (xx << 8);
+  room_bounds_x.b1 += (xx << 8);
+  room_bounds_x.a0 += (xx << 8);
+  room_bounds_x.b0 += (xx << 8);
+
+  xx = ((room & 0xf0) >> 3) - (link_y_coord >> 8);
+  link_y_coord += (xx << 8);
+  BG2VOFS_copy2 += (xx << 8);
+  room_bounds_y.a1 += (xx << 8);
+  room_bounds_y.b1 += (xx << 8);
+  room_bounds_y.a0 += (xx << 8);
+  room_bounds_y.b0 += (xx << 8);
+
+  for (int i = 0; i < 20; i++)
+    tagalong_y_hi[i] = link_y_coord >> 8;
+}
+
+void Dungeon_AdjustForRoomLayout() {  // 82b5dc
+  Dungeon_AdjustQuadrant();
+  quadrant_fullsize_x = (dung_blastwall_flag_x || (kLayoutQuadrantFlags[composite_of_layout_and_quadrant] & (link_quadrant_x ? 2 : 1)) == 0) ? 2 : 0;
+  quadrant_fullsize_y = (dung_blastwall_flag_y || (kLayoutQuadrantFlags[composite_of_layout_and_quadrant] & (link_quadrant_y ? 8 : 4)) == 0) ? 2 : 0;
+  if ((uint8)dung_unk2)
+    quadrant_fullsize_x = (uint8)dung_unk2;
+  if ((uint8)(dung_unk2 >> 8))
+    quadrant_fullsize_y = (uint8)(dung_unk2 >> 8);
+}
+
+void HandleEdgeTransitionMovementEast_RightBy8() {  // 82b62e
+  link_x_coord += 8;
+  Dungeon_StartInterRoomTrans_Right();
+}
+
+void Dungeon_StartInterRoomTrans_Right() {  // 82b63a
+  assert(submodule_index == 0);
+  link_quadrant_x ^= 1;
+  Dungeon_AdjustQuadrant();
+  RoomBounds_AddA(&room_bounds_x);
+  Dung_SaveDataForCurrentRoom();
+  DungeonTransition_AdjustCamera_X(link_quadrant_x);
+  HandleEdgeTransition_AdjustCameraBoundaries(2);
+  submodule_index = 1;
+  if (!link_quadrant_x) {
+    RoomBounds_AddB(&room_bounds_x);
+    BYTE(dungeon_room_index_prev) = dungeon_room_index;
+    if ((link_tile_below & 0xcf) == 0x89) {
+      dungeon_room_index = dung_hdr_travel_destinations[4];
+      Dungeon_AdjustForTeleportDoors(dungeon_room_index - 1, 1);
+    } else {
+      if ((uint8)dungeon_room_index != (uint8)dungeon_room_index2) {
+        BYTE(dungeon_room_index_prev) = dungeon_room_index2;
+        Dungeon_AdjustAfterSpiralStairs();
+      }
+      dungeon_room_index += 1;
+    }
+    submodule_index = 2;
+    if (room_transitioning_flags & 1) {
+      link_is_on_lower_level ^= 1;
+      link_is_on_lower_level_mirror = link_is_on_lower_level;
+    }
+    if (room_transitioning_flags & 2) {
+      cur_palace_index_x2 ^= 2;
+    }
+  }
+  room_transitioning_flags = 0;
+  quadrant_fullsize_y = (dung_blastwall_flag_y || (kLayoutQuadrantFlags[composite_of_layout_and_quadrant] & (link_quadrant_y ? 8 : 4)) == 0) ? 2 : 0;
+}
+
+void HandleEdgeTransitionMovementSouth_DownBy16() {  // 82b76e
+  link_y_coord += 16;
+  Dungeon_StartInterRoomTrans_Down();
+}
+
+void Dung_HandleExitToOverworld() {  // 82b7ae
+  SaveDungeonKeys();
+  SaveQuadrantsToSram();
+  saved_module_for_menu = 8;
+  main_module_index = 15;
+  submodule_index = 0;
+  subsubmodule_index = 0;
+  Dungeon_ResetTorchBackgroundAndPlayerInner();
+}
+
+void AdjustQuadrantAndCamera_right() {  // 82b8bd
+  link_quadrant_x ^= 1;
+  Dungeon_AdjustQuadrant();
+  RoomBounds_AddA(&room_bounds_x);
+  SetAndSaveVisitedQuadrantFlags();
+}
+
+void SetAndSaveVisitedQuadrantFlags() {  // 82b8cb
+  dung_quadrants_visited |= kQuadrantVisitingFlags[(quadrant_fullsize_y << 2) + (quadrant_fullsize_x << 1) + link_quadrant_y + link_quadrant_x];
+  save_dung_info[dungeon_room_index] |= dung_quadrants_visited;
+}
+
+void SaveQuadrantsToSram() {  // 82b8e5
+  save_dung_info[dungeon_room_index] |= dung_quadrants_visited;
+}
+
+void AdjustQuadrantAndCamera_left() {  // 82b8f9
+  link_quadrant_x ^= 1;
+  Dungeon_AdjustQuadrant();
+  RoomBounds_SubA(&room_bounds_x);
+  SetAndSaveVisitedQuadrantFlags();
+}
+
+void AdjustQuadrantAndCamera_down() {  // 82b909
+  link_quadrant_y ^= 2;
+  Dungeon_AdjustQuadrant();
+  RoomBounds_AddA(&room_bounds_y);
+  SetAndSaveVisitedQuadrantFlags();
+}
+
+void AdjustQuadrantAndCamera_up() {  // 82b919
+  link_quadrant_y ^= 2;
+  Dungeon_AdjustQuadrant();
+  RoomBounds_SubA(&room_bounds_y);
+  SetAndSaveVisitedQuadrantFlags();
+}
+
+void Dungeon_FlagRoomData_Quadrants() {  // 82b929
+  dung_quadrants_visited |= kQuadrantVisitingFlags[(quadrant_fullsize_y << 2) + (quadrant_fullsize_x << 1) + link_quadrant_y + link_quadrant_x];
+  Dung_SaveDataForCurrentRoom();
+}
+
+void Dung_SaveDataForCurrentRoom() {  // 82b947
+  save_dung_info[dungeon_room_index] =
+    (dung_savegame_state_bits >> 4) |
+    (dung_door_opened & 0xf000) |
+    dung_quadrants_visited;
+}
+
+void HandleEdgeTransition_AdjustCameraBoundaries(uint8 arg) {  // 82b9dc
+  static const uint16 kCameraBoundsX[] = { 127, 383, 127, 383 };
+  static const uint16 kCameraBoundsY[] = { 120, 376, 136, 392 };
+  overworld_screen_transition = arg;
+  if (link_direction & 3) {
+    uint8 t = link_direction & 1 ? 0 : 2;
+    if (link_quadrant_x) t += 1;
+    camera_x_coord_scroll_low = kCameraBoundsX[t];
+    camera_x_coord_scroll_hi = camera_x_coord_scroll_low + 2;
+  } else {
+    uint8 t = link_direction & 4 ? 0 : 2;
+    if (link_quadrant_y) t += 1;
+    camera_y_coord_scroll_low = kCameraBoundsY[t];
+    camera_y_coord_scroll_hi = camera_y_coord_scroll_low + 2;
+  }
+}
+
+void Dungeon_AdjustQuadrant() {  // 82ba27
+  composite_of_layout_and_quadrant = dung_layout_and_starting_quadrant | link_quadrant_y | link_quadrant_x;
+}
+
+void Dungeon_HandleCamera() {  // 82ba31
+  if (link_y_vel) {
+    int z = (allow_scroll_z && link_z_coord != 0xffff) ? link_z_coord : 0;
+    int y = ((link_y_coord - z) & 0x1ff) + 12;
+    int scrollamt = 1;
+    int y_vel_abs = sign8(link_y_vel) ? (scrollamt = -1, -(int8)link_y_vel) : link_y_vel;
+    do {
+      int qm = quadrant_fullsize_y >> 1;
+      if (sign8(link_y_vel)) {
+        if (y > camera_y_coord_scroll_low)
+          continue;
+      } else {
+        if (y < camera_y_coord_scroll_hi)
+          continue;
+        qm += 2;
+      }
+      if (BG2VOFS_copy2 == room_bounds_y.v[qm])
+        continue;
+      BG2VOFS_copy2 += scrollamt;
+      if (dungeon_room_index == 0xffff)
+        continue;
+
+      BG1VOFS_subpixel += 0x8000;
+      BG1VOFS_copy2 += (scrollamt >> 1) + ((BG1VOFS_subpixel & 0x8000) == 0);
+      camera_y_coord_scroll_low += scrollamt;
+      camera_y_coord_scroll_hi = camera_y_coord_scroll_low + 2;
+    } while (--y_vel_abs);
+  }
+  if (link_x_vel) {
+    int x = (link_x_coord & 0x1ff) + 8;
+    int scrollamt = 1;
+    int x_vel_abs = sign8(link_x_vel) ? (scrollamt = -1, -(int8)link_x_vel) : link_x_vel;
+    do {
+      int qm = quadrant_fullsize_x >> 1;
+      if (sign8(link_x_vel)) {
+        if (x > camera_x_coord_scroll_low)
+          continue;
+      } else {
+        if (x < camera_x_coord_scroll_hi)
+          continue;
+        qm += 2;
+      }
+      if (BG2HOFS_copy2 == room_bounds_x.v[qm])
+        continue;
+      BG2HOFS_copy2 += scrollamt;
+      if (dungeon_room_index == 0xffff)
+        continue;
+      BG1HOFS_subpixel += 0x8000;
+      BG1HOFS_copy2 += (scrollamt >> 1) + ((BG1HOFS_subpixel & 0x8000) == 0);
+      camera_x_coord_scroll_low += scrollamt;
+      camera_x_coord_scroll_hi = camera_x_coord_scroll_low + 2;
+    } while (--x_vel_abs);
+  }
+  if (dungeon_room_index != 0xffff) {
+    if (dung_hdr_bg2_properties == 0 || dung_hdr_bg2_properties == 2 || dung_hdr_bg2_properties == 3 || dung_hdr_bg2_properties == 4 || dung_hdr_bg2_properties >= 6) {
+      BG1HOFS_copy2 = BG2HOFS_copy2;
+      BG1VOFS_copy2 = BG2VOFS_copy2;
+    }
+  }
+}
+
+void MirrorBg1Bg2Offs() {  // 82bb7b
+  BG1HOFS_copy2 = BG2HOFS_copy2;
+  BG1VOFS_copy2 = BG2VOFS_copy2;
+}
+
+void DungeonTransition_AdjustCamera_X(uint8 arg) {  // 82bdc8
+  static const uint16 kUpDownScroll[4] = { 0, 256, 256, 0 };
+  left_right_scroll_target = kUpDownScroll[arg * 2];
+  left_right_scroll_target_end = kUpDownScroll[arg * 2 + 1];
+}
+
+void DungeonTransition_AdjustCamera_Y(uint8 arg) {  // 82bde2
+  static const uint16 kUpDownScroll[4] = { 0, 272, 256, 16 };
+  up_down_scroll_target = kUpDownScroll[arg];
+  up_down_scroll_target_end = kUpDownScroll[arg + 1];
+}
+
+void DungeonTransition_ScrollRoom() {  // 82be03
+  transition_counter++;
+  int i = overworld_screen_transition;
+  bg1_y_offset = bg1_x_offset = 0;
+  uint16 t;
+
+  if (i >= 2) {
+    t = BG1HOFS_copy2 = BG2HOFS_copy2 = (BG2HOFS_copy2 + kStaircaseTab3[i]) & ~1;
+    if (transition_counter >= kStaircaseTab4[i])
+      link_x_coord += kStaircaseTab3[i];
+  } else {
+    t = BG1VOFS_copy2 = BG2VOFS_copy2 = (BG2VOFS_copy2 + kStaircaseTab3[i]) & ~1;
+    if (transition_counter >= kStaircaseTab4[i])
+      link_y_coord += kStaircaseTab3[i];
+  }
+
+  if ((t & 0x1fc) == (&up_down_scroll_target)[i]) {
+    SetAndSaveVisitedQuadrantFlags();
+    subsubmodule_index++;
+    transition_counter = 0;
+    if (submodule_index == 2)
+      WaterFlood_BuildOneQuadrantForVRAM();
+  }
+
+}
+
+void Module07_11_0A_ScrollCamera() {  // 82be75
+  link_visibility_status = tagalong_var5 = 12;
+  int i = overworld_screen_transition;
+  BG1VOFS_copy2 = BG2VOFS_copy2 = (BG2VOFS_copy2 + kStaircaseTab3[i]) & ~3;
+  if ((BG1VOFS_copy2 & 0x1fc) == (&up_down_scroll_target)[i]) {
+    if (submodule_index >= 18)
+      i += 2;
+    link_y_coord += kStaircaseTab5[i];
+    link_visibility_status = tagalong_var5 = 0;
+    subsubmodule_index++;
+  }
+}
+
+void DungeonTransition_FindSubtileLanding() {  // 82c110
+  Dungeon_ResetTorchBackgroundAndPlayerInner();
+  SubtileTransitionCalculateLanding();
+  subsubmodule_index++;
+  save_dung_info[dungeon_room_index] |= dung_quadrants_visited;
+}
+
+void SubtileTransitionCalculateLanding() {  // 82c12c
+  int st = overworld_screen_transition;
+  int a = CalculateTransitionLanding();
+  if (a == 2)
+    a = 1;
+  else if (a == 4)
+    a = 2;
+  a += overworld_screen_transition * 5;
+
+  int8 v = kStaircaseTab2[a];
+  v -= (v < 0) ? -8 : 8;
+  if (st & 2)
+    BYTE(link_x_coord) = v;
+  else
+    BYTE(link_y_coord) = v;
+  link_visibility_status = 0;
+}
+
+void Dungeon_InterRoomTrans_State13() {  // 82c162
+  if (dung_want_lights_out | dung_want_lights_out_copy)
+    ApplyPaletteFilter_bounce();
+  Dungeon_IntraRoomTrans_State5();
+}
+
+void Dungeon_IntraRoomTrans_State5() {  // 82c170
+  Link_HandleMovingAnimation_FullLongEntry();
+  if (!DungeonTransition_MoveLinkOutDoor())
+    return;
+  if (byte_7E004E == 2 || byte_7E004E == 4)
+    is_standing_in_doorway = 0;
+  // todo: write to tiledetect_diag_state
+  BYTE(force_move_any_direction) = 0;
+  byte_7E004E = 0;
+  overworld_screen_transition = 0;
+  subsubmodule_index++;
+}
+
+bool DungeonTransition_MoveLinkOutDoor() {  // 82c191
+  uint8 x = kStaircaseTab2[byte_7E004E + overworld_screen_transition * 5];
+  int r0 = overworld_screen_transition & 1 ? -2 : 2;
+  if ((overworld_screen_transition & 2) == 0) {
+    link_y_coord += r0;
+    return (BYTE(link_y_coord) & 0xfe) == x;
+  } else {
+    link_x_coord += r0;
+    return (BYTE(link_x_coord) & 0xfe) == x;
+  }
+}
+
+uint8 CalculateTransitionLanding() {  // 82c1e5
+  int pos = ((link_y_coord + 12) & 0x1f8) << 3;
+  pos |= ((link_x_coord + 8) & 0x1f8) >> 3;
+  pos |= (link_is_on_lower_level ? 0x1000 : 0);
+  uint8 a = dung_bg2_attr_table[pos];
+  uint8 r = (a == 0 || a == 9) ? 0 :
+    ((a &= 0x8e) == 0x80) ? 1 :
+    (a == 0x82) ? 2 :
+    (a == 0x84 || a == 0x88) ? 3 :
+    (a == 0x86) ? 4 : 2;
+  return byte_7E004E = r;
+}
+
+// This gets called when entering a dungeon from ow.
+void Dungeon_LoadAndDrawRoom() {  // 82c57b
+  int bak = HDMAEN_copy;
+  HDMAEN_copy = 0;
+  Dungeon_LoadRoom();
+  overworld_screen_transition = 0;
+  overworld_map_state = 0;
+  for (dung_cur_quadrant_upload = 0; dung_cur_quadrant_upload != 16; ) {
+    TileMapPrep_NotWaterOnTag();
+    NMI_UploadTilemap();
+    Dungeon_PrepareNextRoomQuadrantUpload();
+    NMI_UploadTilemap();
+  }
+  HDMAEN_copy = bak;
+  nmi_subroutine_index = 0;
+  overworld_map_state = 0;
+  subsubmodule_index = 0;
+}
+
+void Dungeon_LoadEntrance() {  // 82d8b3
+  player_is_indoors = 1;
+
+  if (death_var5) {
+    death_var5 = 0;
+  } else {
+    overworld_area_index_exit = overworld_area_index;
+    TM_copy_exit = WORD(TM_copy);
+    BG2VOFS_copy2_exit = BG2VOFS_copy2;
+    BG2HOFS_copy2_exit = BG2HOFS_copy2;
+    link_y_coord_exit = link_y_coord;
+    link_x_coord_exit = link_x_coord;
+    camera_y_coord_scroll_low_exit = camera_y_coord_scroll_low;
+    camera_x_coord_scroll_low_exit = camera_x_coord_scroll_low;
+    overworld_screen_index_exit = overworld_screen_index;
+    map16_load_src_off_exit = map16_load_src_off;
+    overworld_screen_index = 0;
+    overlay_index = 0;
+    ow_scroll_vars0_exit = ow_scroll_vars0;
+    up_down_scroll_target_exit = up_down_scroll_target;
+    up_down_scroll_target_end_exit = up_down_scroll_target_end;
+    left_right_scroll_target_exit = left_right_scroll_target;
+    left_right_scroll_target_end_exit = left_right_scroll_target_end;
+    overworld_unk1_exit = overworld_unk1;
+    overworld_unk1_neg_exit = overworld_unk1_neg;
+    overworld_unk3_exit = overworld_unk3;
+    overworld_unk3_neg_exit = overworld_unk3_neg;
+    byte_7EC164 = byte_7E0AA0;
+    main_tile_theme_index_exit = main_tile_theme_index;
+    aux_tile_theme_index_exit = aux_tile_theme_index;
+    sprite_graphics_index_exit = sprite_graphics_index;
+  }
+  bg1_y_offset = bg1_x_offset = 0;
+  WORD(death_var5) = 0;
+  if (WORD(follower_indicator) == 4 || WORD(death_var4)) {
+    int i = which_starting_point;
+    WORD(which_entrance) = kStartingPoint_entrance[i];
+    dungeon_room_index = dungeon_room_index2 = kStartingPoint_rooms[i];
+    BG1VOFS_copy = BG2VOFS_copy = BG1VOFS_copy2 = BG2VOFS_copy2 = kStartingPoint_scrollY[i];
+    BG1HOFS_copy = BG2HOFS_copy = BG1HOFS_copy2 = BG2HOFS_copy2 = kStartingPoint_scrollX[i];
+    if (WORD(sram_progress_indicator)) {
+      link_y_coord = kStartingPoint_playerY[i];
+      link_x_coord = kStartingPoint_playerX[i];
+    }
+    camera_y_coord_scroll_low = kStartingPoint_cameraY[i];
+    camera_y_coord_scroll_hi = camera_y_coord_scroll_low + 2;
+    camera_x_coord_scroll_low = kStartingPoint_cameraX[i];
+    camera_x_coord_scroll_hi = camera_x_coord_scroll_low + 2;
+    tilemap_location_calc_mask = 0x1f8;
+    ow_entrance_value = kStartingPoint_doorSettings[i];
+    up_down_scroll_target = 0;
+    up_down_scroll_target_end = 0x110;
+    left_right_scroll_target = 0;
+    left_right_scroll_target_end = 0x100;
+    room_bounds_y.a0 = kStartingPoint_relativeCoords[i * 8 + 0] << 8;
+    room_bounds_y.b0 = kStartingPoint_relativeCoords[i * 8 + 1] << 8;
+    room_bounds_y.a1 = kStartingPoint_relativeCoords[i * 8 + 2] << 8 | 0x10;
+    room_bounds_y.b1 = kStartingPoint_relativeCoords[i * 8 + 3] << 8 | 0x10;
+    room_bounds_x.a0 = kStartingPoint_relativeCoords[i * 8 + 4] << 8;
+    room_bounds_x.b0 = kStartingPoint_relativeCoords[i * 8 + 5] << 8;
+    room_bounds_x.a1 = kStartingPoint_relativeCoords[i * 8 + 6] << 8;
+    room_bounds_x.b1 = kStartingPoint_relativeCoords[i * 8 + 7] << 8;
+
+    link_direction_facing = 2;
+    main_tile_theme_index = kStartingPoint_blockset[i];
+    dung_cur_floor = kStartingPoint_floor[i];
+    BYTE(cur_palace_index_x2) = kStartingPoint_palace[i];
+    is_standing_in_doorway = 0;
+    link_is_on_lower_level = kStartingPoint_startingBg[i] >> 4;
+    link_is_on_lower_level_mirror = kStartingPoint_startingBg[i] & 0xf;
+    quadrant_fullsize_x = kStartingPoint_quadrant1[i] >> 4;
+    quadrant_fullsize_y = kStartingPoint_quadrant1[i] & 0xf;
+    link_quadrant_x = kStartingPoint_quadrant2[i] >> 4;
+    link_quadrant_y = kStartingPoint_quadrant2[i] & 0xf;
+
+    queued_music_control = kStartingPoint_musicTrack[i];
+    if (i == 0 && sram_progress_indicator == 0)
+      queued_music_control = 0xff;
+    death_var4 = 0;
+  } else {
+    int i = which_entrance;
+    dungeon_room_index = dungeon_room_index2 = kEntranceData_rooms[i];
+    BG1VOFS_copy = BG2VOFS_copy = BG1VOFS_copy2 = BG2VOFS_copy2 = kEntranceData_scrollY[i];
+    BG1HOFS_copy = BG2HOFS_copy = BG1HOFS_copy2 = BG2HOFS_copy2 = kEntranceData_scrollX[i];
+    if (WORD(sram_progress_indicator)) {
+      link_y_coord = kEntranceData_playerY[i];
+      link_x_coord = kEntranceData_playerX[i];
+    }
+    camera_y_coord_scroll_low = kEntranceData_cameraY[i];
+    camera_y_coord_scroll_hi = camera_y_coord_scroll_low + 2;
+    camera_x_coord_scroll_low = kEntranceData_cameraX[i];
+    camera_x_coord_scroll_hi = camera_x_coord_scroll_low + 2;
+    tilemap_location_calc_mask = 0x1f8;
+    ow_entrance_value = kEntranceData_doorSettings[i];
+    big_rock_starting_address = 0;
+    up_down_scroll_target = 0;
+    up_down_scroll_target_end = 0x110;
+    left_right_scroll_target = 0;
+    left_right_scroll_target_end = 0x100;
+
+    room_bounds_y.a0 = kEntranceData_relativeCoords[i * 8 + 0] << 8;
+    room_bounds_y.b0 = kEntranceData_relativeCoords[i * 8 + 1] << 8;
+    room_bounds_y.a1 = kEntranceData_relativeCoords[i * 8 + 2] << 8 | 0x10;
+    room_bounds_y.b1 = kEntranceData_relativeCoords[i * 8 + 3] << 8 | 0x10;
+
+    room_bounds_x.a0 = kEntranceData_relativeCoords[i * 8 + 4] << 8;
+    room_bounds_x.b0 = kEntranceData_relativeCoords[i * 8 + 5] << 8;
+    room_bounds_x.a1 = kEntranceData_relativeCoords[i * 8 + 6] << 8;
+    room_bounds_x.b1 = kEntranceData_relativeCoords[i * 8 + 7] << 8;
+
+    link_direction_facing = (i == 0 || i == 0x43) ? 2 : 0;
+    main_tile_theme_index = kEntranceData_blockset[i];
+    queued_music_control = ZeldaGetEntranceMusicTrack(i);
+    if (queued_music_control == 3 && sram_progress_indicator >= 2)
+      queued_music_control = 18;
+
+    dung_cur_floor = kEntranceData_floor[i];
+    BYTE(cur_palace_index_x2) = kEntranceData_palace[i];
+    is_standing_in_doorway = kEntranceData_doorwayOrientation[i];
+    link_is_on_lower_level = kEntranceData_startingBg[i] >> 4;
+    link_is_on_lower_level_mirror = kEntranceData_startingBg[i] & 0xf;
+    quadrant_fullsize_x = kEntranceData_quadrant1[i] >> 4;
+    quadrant_fullsize_y = kEntranceData_quadrant1[i] & 0xf;
+    link_quadrant_x = kEntranceData_quadrant2[i] >> 4;
+    link_quadrant_y = kEntranceData_quadrant2[i] & 0xf;
+
+    if (dungeon_room_index >= 0x100)
+      dung_cur_floor = 0;
+  }
+  player_oam_x_offset = player_oam_y_offset = 0x80;
+  link_direction_mask_a = link_direction_mask_b = 0xf;
+  BYTE(link_z_coord) = link_actual_vel_z = 0xff;
+  memcpy(movable_block_datas, kMovableBlockDataInit, kMovableBlockDataInit_SIZE);
+  memcpy(&movable_block_datas[99], kTorchDataInit, 116); // junk
+  memcpy(dung_torch_data, kTorchDataInit, kTorchDataInit_SIZE);
+  memcpy(&dung_torch_data[144], kTorchDataJunk, kTorchDataJunk_SIZE);
+
+  memset(memorized_tile_addr, 0, 0x100);
+  memset(pots_revealed_in_room, 0, 0x280);
+  orange_blue_barrier_state = 0;
+  byte_7E04BC = 0;
+}
+
+void PushBlock_Slide(uint8 j) {  // 87edb5
+  if (submodule_index)
+    return;
+  int i = (index_of_changable_dungeon_objs[1] - 1) * 2 == j;
+  pushedblocks_maybe_timeout = 9;
+  pushedblocks_some_index = 0;
+  PushBlock_ApplyVelocity(i);
+  int y = (uint8)pushedblocks_y_lo[i] | (uint8)pushedblocks_y_hi[i] << 8;
+  int x = (uint8)pushedblocks_x_lo[i] | (uint8)pushedblocks_x_hi[i] << 8;
+  PushBlock_HandleCollision(i, x, y);
+}
+
+void PushBlock_HandleFalling(uint8 y) {  // 87edf9
+  y >>= 1;
+
+  if (!sign8(--pushedblocks_maybe_timeout))
+    return;
+
+  pushedblocks_maybe_timeout = 9;
+
+  if (++pushedblocks_some_index == 4) {
+    BYTE(dung_replacement_tile_state[y]) = 0;
+    pushedblocks_some_index = 0;
+    int i = (index_of_changable_dungeon_objs[1] - 1) == y;
+    index_of_changable_dungeon_objs[i] = 0;
+  }
+}
+
+void PushBlock_ApplyVelocity(uint8 i) {  // 87ee35
+  static const uint8 kPushedBlockDirMask[] = { 0x8, 0x4, 0x2, 0x1 };
+  uint8 m = kPushedBlockDirMask[(uint8)pushedblock_facing[i] >> 1];
+  uint32 o;
+  link_actual_vel_x = link_actual_vel_y = 0;
+  if (m & 3) {
+    int8 vel = (m & 2) ? -12 : 12;
+    link_actual_vel_x = vel;
+    o = (pushedblocks_subpixel[i] | pushedblocks_x_lo[i] << 8 | pushedblocks_x_hi[i] << 16) + vel * 16;
+    pushedblocks_subpixel[i] = (uint8)o;
+    pushedblocks_x_lo[i] = (uint8)(o >> 8);
+    pushedblocks_x_hi[i] = (uint8)(o >> 16);
+  } else {
+    int8 vel = (m & 8) ? -12 : 12;
+    link_actual_vel_y = vel;
+    o = (pushedblocks_subpixel[i] | pushedblocks_y_lo[i] << 8 | pushedblocks_y_hi[i] << 16);
+    o += vel * 16;
+    pushedblocks_subpixel[i] = (uint8)o;
+    pushedblocks_y_lo[i] = (uint8)(o >> 8);
+    pushedblocks_y_hi[i] = (uint8)(o >> 16);
+  }
+  if (((o >> 8) & 0xf) == (uint8)pushedblocks_target[i]) {
+    int j = index_of_changable_dungeon_objs[i] - 1;
+    dung_replacement_tile_state[j]++;
+    link_cant_change_direction &= ~0x4;
+    bitmask_of_dragstate &= ~0x4;
+  }
+  uint16 x = pushedblocks_x_lo[i] | pushedblocks_x_hi[i] << 8;
+  uint16 y = pushedblocks_y_lo[i] | pushedblocks_y_hi[i] << 8;
+  for (int j = 15; j >= 0; j--) {
+    if (sprite_state[j] >= 9) {
+      uint16 sx = sprite_x_lo[j] | sprite_x_hi[j] << 8;
+      uint16 sy = sprite_y_lo[j] | sprite_y_hi[j] << 8;
+      if ((uint16)(x - sx + 0x10) < 0x20 && (uint16)(y - sy + 0x10) < 0x20) {
+        sprite_F[j] = 8;
+        static const uint8 kPushBlockTab1[] = { 0x0, 0x0, 0xe0, 0x20 };
+        static const uint8 kPushBlockTab2[] = { 0xe0, 0x20, 0x0, 0x0 };
+        int k = (uint8)pushedblock_facing[i] >> 1;
+        sprite_x_recoil[j] = kPushBlockTab1[k];
+        sprite_y_recoil[j] = kPushBlockTab2[k];
+      }
+    }
+  }
+}
+
+void PushBlock_HandleCollision(uint8 i, uint16 x, uint16 y) {  // 87efb9
+  static const uint8 kPushBlock_A[] = { 0, 0, 8, 8 };
+  static const uint8 kPushBlock_B[] = { 15, 15, 23, 23 };
+  static const uint8 kPushBlock_D[] = { 15, 15, 15, 15 };
+  static const uint8 kPushBlock_C[] = { 0x0, 0x0, 0x0, 0x0 };
+  static const uint8 kPushBlock_E[] = { 8, 24, 0, 16 };
+  static const uint8 kPushBlock_F[] = { 15, 0, 15, 0 };
+
+  link_y_coord_safe_return_hi = link_y_coord >> 8;
+  link_x_coord_safe_return_hi = link_x_coord >> 8;
+
+  int dir = 3;
+  uint8 m = link_direction & 0xf;
+  while (!(m & 1)) {
+    m >>= 1;
+    if (--dir < 0)
+      return;
+  }
+  int l = (dir < 2) ? link_x_coord : link_y_coord;
+  int o = (dir < 2) ? x : y;
+
+  uint16 r0 = l + kPushBlock_A[dir];
+  uint16 r2 = l + kPushBlock_B[dir];
+  uint16 r4 = o + kPushBlock_C[dir];
+  uint16 r6 = o + kPushBlock_D[dir];
+
+  uint16 *coord_p = (dir < 2) ? &link_y_coord : &link_x_coord;
+  uint16 r8 = *coord_p + kPushBlock_E[dir];
+  uint16 r10 = ((dir < 2) ? y : x) + kPushBlock_F[dir];
+
+  bitmask_of_dragstate &= ~4;
+
+  if (r0 >= r4 && r0 < r6 || r2 >= r4 && r2 < r6) {
+    if (link_direction_facing == pushedblock_facing[i])
+      bitmask_of_dragstate |= index_of_changable_dungeon_objs[i] ? 4 : 1;
+    if (dir & 1 ? (r8 >= r10 && (uint16)(r8 - r10) < 8) : (uint16)(r8 - r10) >= 0xfff8) {
+      *coord_p -= r8 - r10;
+      *(dir & 2 ? &link_x_vel : &link_y_vel) -= r8 - r10;
+    }
+  }
+  HandleIndoorCameraAndDoors();
+}
+
+void Sprite_Dungeon_DrawAllPushBlocks() {  // 87f0ac
+  for (int i = 1; i >= 0; i--)
+    if (index_of_changable_dungeon_objs[i])
+      Sprite_HandlePushedBlocks_One(i);
+}
+
+void UsedForStraightInterRoomStaircase() {  // 87f25a
+  int i = 9;
+  do {
+    if (ancilla_type[i] == 13)
+      ancilla_type[i] = 0;
+  } while (--i >= 0);
+  if (link_animation_steps >= 5)
+    link_animation_steps = 0;
+  link_subpixel_x = 0;
+  link_subpixel_y = 0;
+  some_animation_timer_steps = 0;
+  link_timer_push_get_tired = 28;
+  countdown_timer_for_staircases = 32;
+  link_disable_sprite_damage = 1;
+  Ancilla_Sfx2_Near(which_staircase_index & 4 ? 0x18 : 0x16);
+
+  tiledetect_which_y_pos[1] = link_x_coord + (which_staircase_index & 4 ? -15 : 16);
+  tiledetect_which_y_pos[0] = link_y_coord;
+}
+
+void HandleLinkOnSpiralStairs() {  // 87f2c1
+  link_x_coord_prev = link_x_coord;
+  link_y_coord_prev = link_y_coord;
+  if (some_animation_timer_steps)
+    return;
+
+  link_give_damage = 0;
+  link_incapacitated_timer = 0;
+  link_auxiliary_state = 0;
+
+  if (which_staircase_index & 4) {
+    link_actual_vel_y = -2;
+    if (sign8(--link_timer_push_get_tired)) {
+      link_timer_push_get_tired = 0;
+      link_actual_vel_y = 0;
+      link_actual_vel_x = -2;
+    }
+  } else {
+    link_actual_vel_y = -2;
+    if (sign8(--link_timer_push_get_tired)) {
+      link_timer_push_get_tired = 0;
+      link_actual_vel_y = -2;
+      link_actual_vel_x = 2;
+    }
+  }
+  Link_MovePosition();
+  Link_HandleMovingAnimation_StartWithDash();
+  if (!link_timer_push_get_tired && sign8(--countdown_timer_for_staircases)) {
+    countdown_timer_for_staircases = 0;
+    link_direction_facing = (which_staircase_index & 4) ? 4 : 6;
+  }
+
+  int8 xd = link_x_coord - tiledetect_which_y_pos[1];
+  if (xd < 0)
+    xd = -xd;
+  if (xd)
+    return;
+
+  RepositionLinkAfterSpiralStairs();
+  if (follower_indicator)
+    Follower_Initialize();
+
+  tiledetect_which_y_pos[1] = link_x_coord + ((which_staircase_index & 4) ? -8 : 12);
+  some_animation_timer_steps = 1;
+  countdown_timer_for_staircases = 6;
+  Ancilla_Sfx2_Near(which_staircase_index & 4 ? 25 : 23);
+}
+
+void SpiralStairs_FindLandingSpot() {  // 87f391
+  link_give_damage = 0;
+  link_incapacitated_timer = 0;
+  link_auxiliary_state = 0;
+  link_disable_sprite_damage = 0;
+  link_x_coord_prev = link_x_coord;
+  link_y_coord_prev = link_y_coord;
+  if (sign8(--countdown_timer_for_staircases)) {
+    countdown_timer_for_staircases = 0;
+    link_direction_facing = 2;
+  }
+  link_actual_vel_x = 4, link_actual_vel_y = 0;
+  if (which_staircase_index & 4)
+    link_actual_vel_x = -4, link_actual_vel_y = 2;
+  if (some_animation_timer_steps == 2)
+    link_actual_vel_x = 0, link_actual_vel_y = 16;
+  Link_MovePosition();
+  Link_HandleMovingAnimation_StartWithDash();
+  if ((uint8)link_x_coord == (uint8)tiledetect_which_y_pos[1])
+    some_animation_timer_steps = 2;
+}
+
+void Dungeon_HandleLayerEffect() {  // 8afe80
+  kDungeon_Effect_Handler[dung_hdr_collision_2]();
+}
+
+void LayerEffect_Nothing() {  // 8afe87
+}
+
+void LayerEffect_Scroll() {  // 8afe88
+  if (dung_savegame_state_bits & 0x8000) {
+    dung_hdr_collision_2 = 0;
+    return;
+  }
+  dung_floor_x_vel = dung_floor_y_vel = 0;
+  if (dung_floor_move_flags & 1)
+    return;
+  int t = dung_some_subpixel[1] + 0x80;
+  dung_some_subpixel[1] = t;
+  t >>= 8;
+  if (dung_floor_move_flags & 2)
+    t = -t;
+
+  if (dung_floor_move_flags < 4) {
+    dung_floor_x_vel = t;
+    dung_floor_x_offs -= t;
+    BG1HOFS_copy2 = BG2HOFS_copy2 + dung_floor_x_offs;
+  } else {
+    dung_floor_y_vel = t;
+    dung_floor_y_offs -= t;
+    BG1VOFS_copy2 = BG2VOFS_copy2 + dung_floor_y_offs;
+  }
+}
+
+void LayerEffect_Trinexx() {  // 8afeee
+  dung_floor_x_offs += dung_floor_x_vel;
+  dung_floor_y_offs += dung_floor_y_vel;
+  dung_floor_x_vel = 0;
+  dung_floor_y_vel = 0;
+}
+
+void LayerEffect_Agahnim2() {  // 8aff0d
+  int j = frame_counter & 0x7f;
+  if (j == 3 || j == 36) {
+    main_palette_buffer[0x6d] = 0x1d59;
+    main_palette_buffer[0x6e] = 0x25ff;
+    main_palette_buffer[0x77] = main_palette_buffer[0x6f] = 0x1a;
+    flag_update_cgram_in_nmi++;
+  } else if (j == 5 || j == 38) {
+    main_palette_buffer[0x6d] = aux_palette_buffer[0x6d];
+    main_palette_buffer[0x6e] = aux_palette_buffer[0x6e];
+    main_palette_buffer[0x77] = main_palette_buffer[0x6f] = aux_palette_buffer[0x6f];
+    flag_update_cgram_in_nmi++;
+  }
+  TS_copy = 2;
+}
+
+void LayerEffect_InvisibleFloor() {  // 8aff5d
+  int count = 0;
+  for (int i = 0; i < 16; i++)
+    count += (dung_object_tilemap_pos[i] & 0x8000) != 0;
+
+  uint16 x = 0x2940, y = 0x4e60;
+  if (count == 0)
+    x = y = 0;
+
+  if (aux_palette_buffer[0x7b] != x) {
+    main_palette_buffer[0x7b] = aux_palette_buffer[0x7b] = x;
+    main_palette_buffer[0x7c] = aux_palette_buffer[0x7c] = y;
+    flag_update_cgram_in_nmi++;
+  }
+  TS_copy = 2;
+}
+
+void LayerEffect_Ganon() {  // 8affa4
+  int count = 0;
+  for (int i = 0; i < 16; i++)
+    count += (dung_object_tilemap_pos[i] & 0x8000) != 0;
+
+  byte_7E04C5 = count;
+  if (count == 0) {
+    TS_copy = 0;
+    CGADSUB_copy = 0xb3;
+  } else if (count == 1) {
+    TS_copy = 2;
+    CGADSUB_copy = 0x70;
+  } else {
+    TS_copy = 0;
+    CGADSUB_copy = 0x70;
+  }
+}
+
+void LayerEffect_WaterRapids() {  // 8affde
+  int t;
+  dung_some_subpixel[1] = t = dung_some_subpixel[1] + 0x80;
+  dung_floor_x_vel = -(t >> 8);
+}
+
+void Dungeon_LoadCustomTileAttr() {  // 8e942a
+  memcpy(&attributes_for_tile[0x140], &kDungAttrsForTile[kDungAttrsForTile_Offs[aux_tile_theme_index]], 0x80);
+}
+
+void Link_CheckBunnyStatus() {  // 8ffd22
+  if (link_player_handler_state == kPlayerState_RecoilWall) {
+    link_player_handler_state =
+      !link_is_bunny_mirror ? kPlayerState_Ground :
+      link_item_moon_pearl ? kPlayerState_TempBunny : kPlayerState_PermaBunny;
+  }
+}
+
+void CrystalCutscene_Initialize() {  // 9ecce3
+  static const uint16 kCrystalMaiden_Pal[8] = { 0, 0x3821, 0x4463, 0x54a5, 0x5ce7, 0x6d29, 0x79ad, 0x7e10 };
+
+  CGADSUB_copy = 0x33;
+  BYTE(palette_filter_countdown) = 0;
+  BYTE(darkening_or_lightening_screen) = 0;
+  Palette_AssertTranslucencySwap();
+  PaletteFilter_Crystal();
+  for (int i = 0; i < 8; i++)
+    main_palette_buffer[112 + i] = kCrystalMaiden_Pal[i];
+  flag_update_cgram_in_nmi++;
+  CrystalCutscene_SpawnMaiden();
+  CrystalCutscene_InitializePolyhedral();
+}
+
+void CrystalCutscene_SpawnMaiden() {  // 9ecd48
+  memset(sprite_state, 0, 16);
+  SpriteSpawnInfo info;
+  int j = Sprite_SpawnDynamically(0, 0xab, &info);
+  sprite_x_hi[j] = link_x_coord >> 8;
+  sprite_y_hi[j] = link_y_coord >> 8;
+  sprite_x_lo[j] = 0x78;
+  sprite_y_lo[j] = 0x7c;
+  sprite_D[j] = 1;
+  sprite_oam_flags[j] = 0xb;
+  sprite_subtype2[j] = 0;
+  sprite_floor[j] = 0;
+  sprite_A[j] = Ancilla_TerminateSelectInteractives(j);
+  item_receipt_method = 0;
+  if (BYTE(cur_palace_index_x2) == 24) {
+    sprite_oam_flags[j] = 9;
+    follower_indicator = 1;
+  } else {
+    follower_indicator = 6;
+  }
+  LoadFollowerGraphics();
+  follower_indicator = 0;
+  dung_floor_x_offs = BG2HOFS_copy2 - link_x_coord + 0x79;
+  dung_floor_y_offs = 0x30 - (uint8)BG1VOFS_copy2;
+  dung_hdr_collision_2_mirror = 1;
+}
+
--- /dev/null
+++ b/src/dungeon.h
@@ -1,0 +1,448 @@
+#pragma once
+
+typedef struct RoomBounds RoomBounds;
+
+enum {
+  kDoorType_Regular = 0,
+  kDoorType_Regular2 = 2,
+  kDoorType_4 = 4,
+  kDoorType_EntranceDoor = 6,
+  kDoorType_WaterfallTunnel = 8,
+  kDoorType_EntranceLarge = 10,
+  kDoorType_EntranceLarge2 = 12,
+  kDoorType_EntranceCave = 14,
+  kDoorType_EntranceCave2 = 16,
+  kDoorType_ExitToOw = 18,
+  kDoorType_ThroneRoom = 20,
+  kDoorType_PlayerBgChange = 22,
+  kDoorType_ShuttersTwoWay = 24,
+  kDoorType_InvisibleDoor = 26,
+  kDoorType_SmallKeyDoor = 0x1c,
+  kDoorType_1E = 0x1e,
+  kDoorType_StairMaskLocked0 = 32,
+  kDoorType_StairMaskLocked1 = 34,
+  kDoorType_StairMaskLocked2 = 36,
+  kDoorType_StairMaskLocked3 = 38,
+  kDoorType_BreakableWall = 0x28,
+  kDoorType_LgExplosion = 48,
+  kDoorType_Slashable = 50,
+  kDoorType_36 = 0x36,
+  kDoorType_38 = 0x38,
+
+  kDoorType_RegularDoor33 = 64,
+  kDoorType_Shutter = 68,
+  kDoorType_WarpRoomDoor = 70,
+  kDoorType_ShutterTrapUR = 72,
+  kDoorType_ShutterTrapDL = 74,
+};
+
+typedef struct DungPalInfo {
+  uint8 pal0;
+  uint8 pal1;
+  uint8 pal2;
+  uint8 pal3;
+} DungPalInfo;
+
+extern const uint8 kDungAnimatedTiles[24];
+uint16 *DstoPtr(uint16 d);
+void Object_Fill_Nx1(int n, const uint16 *src, uint16 *dst);
+void Object_Draw_5x4(const uint16 *src, uint16 *dst);
+void Object_Draw_4x2_BothBgs(const uint16 *src, uint16 dsto);
+void Object_ChestPlatform_Helper(const uint16 *src, int dsto);
+void Object_Hole(const uint16 *src, uint16 *dst);
+void LoadType1ObjectSubtype1(uint8 idx, uint16 *dst, uint16 dsto);
+void Object_DrawNx3_BothBgs(int n, const uint16 *src, int dsto);
+void LoadType1ObjectSubtype2(uint8 idx, uint16 *dst, uint16 dsto);
+void Object_BombableFloorHelper(uint16 a, const uint16 *src, const uint16 *src_below, uint16 *dst, uint16 dsto);
+void LoadType1ObjectSubtype3(uint8 idx, uint16 *dst, uint16 dsto);
+void RoomBounds_AddA(RoomBounds *r);
+void RoomBounds_AddB(RoomBounds *r);
+void RoomBounds_SubB(RoomBounds *r);
+void RoomBounds_SubA(RoomBounds *r);
+void Dungeon_StartInterRoomTrans_Left();
+void Dung_StartInterRoomTrans_Left_Plus();
+void Dungeon_StartInterRoomTrans_Up();
+void Dungeon_StartInterRoomTrans_Down();
+void Dungeon_Store2x2(uint16 pos, uint16 t0, uint16 t1, uint16 t2, uint16 t3, uint8 attr);
+uint16 Dungeon_MapVramAddr(uint16 pos);
+uint16 Dungeon_MapVramAddrNoSwap(uint16 pos);
+void Door_Up_EntranceDoor(uint16 dsto);
+void Door_Down_EntranceDoor(uint16 dsto);
+void Door_Left_EntranceDoor(uint16 dsto);
+void Door_Right_EntranceDoor(uint16 dsto);
+void Door_Draw_Helper4(uint8 door_type, uint16 dsto);
+const uint16 *GetRoomDoorInfo(int room);
+const uint8 *GetRoomHeaderPtr(int room);
+const uint8 *GetDefaultRoomLayout(int i);
+const uint8 *GetDungeonRoomLayout(int i);
+void Dung_TagRoutine_0x22_0x3B(int k, uint8 j);
+void Sprite_HandlePushedBlocks_One(int i);
+void Object_Draw_DoorLeft_3x4(uint16 src, int door);
+void Object_Draw_DoorRight_3x4(uint16 src, int door);
+void Dungeon_OpeningLockedDoor_Combined(bool skip_anim);
+const DungPalInfo *GetDungPalInfo(int idx);
+uint16 Dungeon_GetTeleMsg(int room);
+bool Dungeon_IsPitThatHurtsPlayer();
+void Dungeon_PrepareNextRoomQuadrantUpload();
+void WaterFlood_BuildOneQuadrantForVRAM();
+void TileMapPrep_NotWaterOnTag();
+void OrientLampLightCone();
+void PrepareDungeonExitFromBossFight();
+void SavePalaceDeaths();
+void Dungeon_LoadRoom();
+void RoomDraw_DrawAllObjects(const uint8 *level_data);
+void RoomData_DrawObject_Door(uint16 a);
+void RoomData_DrawObject(uint16 r0, const uint8 *level_data);
+void RoomDraw_DrawFloors(const uint8 *level_data);
+void RoomDraw_FloorChunks(const uint16 *src);
+void RoomDraw_A_Many32x32Blocks(int n, const uint16 *src, uint16 *dst);
+void RoomDraw_1x3_rightwards(int n, const uint16 *src, uint16 *dst);
+bool RoomDraw_CheckIfWallIsMoved();
+void MovingWall_FillReplacementBuffer(int dsto);
+void Object_Table_Helper(const uint16 *src, uint16 *dst);
+void DrawWaterThing(uint16 *dst, const uint16 *src);
+void RoomDraw_4x4(const uint16 *src, uint16 *dst);
+void RoomDraw_Object_Nx4(int n, const uint16 *src, uint16 *dst);
+void Object_DrawNx4_BothBgs(int n, const uint16 *src, int dsto);
+void RoomDraw_Rightwards2x2(const uint16 *src, uint16 *dst);
+void Object_Draw_3x2(const uint16 *src, uint16 *dst);
+void RoomDraw_WaterHoldingObject(int n, const uint16 *src, uint16 *dst);
+void RoomDraw_SomeBigDecors(int n, const uint16 *src, uint16 dsto);
+void RoomDraw_SingleLampCone(uint16 a, uint16 y);
+void RoomDraw_AgahnimsWindows(uint16 dsto);
+void RoomDraw_FortuneTellerRoom(uint16 dsto);
+void Object_Draw8x8(const uint16 *src, uint16 *dst);
+void RoomDraw_Door_North(int type, int pos_enum);
+void Door_Up_StairMaskLocked(uint8 door_type, uint16 dsto);
+void Door_PrioritizeCurDoor();
+void RoomDraw_NormalRangedDoors_North(uint8 door_type, uint16 dsto, int pos_enum);
+void RoomDraw_OneSidedShutters_North(uint8 door_type, uint16 dsto);
+void RoomDraw_Door_South(int type, int pos_enum);
+void RoomDraw_CheckIfLowerLayerDoors_Y(uint8 door_type, uint16 dsto);
+void RoomDraw_Door_West(int type, int pos_enum);
+void RoomDraw_NormalRangedDoors_West(uint8 door_type, uint16 dsto, int pos_enum);
+void RoomDraw_Door_East(int type, int pos_enum);
+void RoomDraw_NormalRangedDoors_East(uint8 door_type, uint16 dsto);
+void RoomDraw_OneSidedShutters_East(uint8 door_type, uint16 dsto);
+void RoomDraw_NorthCurtainDoor(uint16 dsto);
+void RoomDraw_Door_ExplodingWall(int pos_enum);
+void RoomDraw_ExplodingWallSegment(const uint16 *src, uint16 dsto);
+void RoomDraw_ExplodingWallColumn(const uint16 *src, uint16 *dst);
+void RoomDraw_HighRangeDoor_North(uint8 door_type, uint16 dsto, int pos_enum);
+void RoomDraw_OneSidedLowerShutters_South(uint8 door_type, uint16 dsto);
+void RoomDraw_HighRangeDoor_West(uint8 door_type, uint16 dsto, int pos_enum);
+void RoomDraw_OneSidedLowerShutters_East(uint8 door_type, uint16 dsto);
+void RoomDraw_MakeDoorHighPriority_North(uint16 dsto);
+void RoomDraw_MakeDoorHighPriority_South(uint16 dsto);
+void RoomDraw_MakeDoorHighPriority_West(uint16 dsto);
+void RoomDraw_MakeDoorHighPriority_East(uint16 dsto);
+void RoomDraw_MarkDungeonToggleDoor(uint16 dsto);
+void RoomDraw_MarkLayerToggleDoor(uint16 dsto);
+void RoomDraw_GetObjectSize_1to16();
+void Object_SizeAtoAplus15(uint8 a);
+void RoomDraw_GetObjectSize_1to15or26();
+void RoomDraw_GetObjectSize_1to15or32();
+int RoomDraw_FlagDoorsAndGetFinalType(uint8 direction, uint8 door_type, uint16 dsto);
+void RoomDraw_MakeDoorPartsHighPriority_Y(uint16 dsto);
+void RoomDraw_MakeDoorPartsHighPriority_X(uint16 dsto);
+void RoomDraw_Downwards4x2VariableSpacing(int increment, const uint16 *src, uint16 *dst);
+uint16 *RoomDraw_DrawObject2x2and1(const uint16 *src, uint16 *dst);
+uint16 *RoomDraw_RightwardShelfEnd(const uint16 *src, uint16 *dst);
+uint16 *RoomDraw_RightwardBarSegment(const uint16 *src, uint16 *dst);
+void DrawBigGraySegment(uint16 a, const uint16 *src, uint16 *dst, uint16 dsto);
+void RoomDraw_SinglePot(const uint16 *src, uint16 *dst, uint16 dsto);
+void RoomDraw_BombableFloor(const uint16 *src, uint16 *dst, uint16 dsto);
+void RoomDraw_HammerPegSingle(const uint16 *src, uint16 *dst, uint16 dsto);
+void DrawObjects_PushableBlock(uint16 dsto_x2, uint16 slot);
+void DrawObjects_LightableTorch(uint16 dsto_x2, uint16 slot);
+void Dungeon_LoadHeader();
+void Dungeon_CheckAdjacentRoomsForOpenDoors(int idx, int room);
+void Dungeon_LoadAdjacentRoomDoors(int room);
+void Dungeon_LoadAttribute_Selectable();
+void Dungeon_LoadAttributeTable();
+void Dungeon_LoadBasicAttribute_full(uint16 loops);
+void Dungeon_LoadObjectAttribute();
+void Dungeon_LoadDoorAttribute();
+void Dungeon_LoadSingleDoorAttribute(int k);
+void Door_LoadBlastWallAttr(int k);
+void ChangeDoorToSwitch();
+void Dungeon_FlipCrystalPegAttribute();
+void Dungeon_HandleRoomTags();
+void Dung_TagRoutine_0x00(int k);
+void Dungeon_DetectStaircase();
+void RoomTag_NorthWestTrigger(int k);
+void Dung_TagRoutine_0x2A(int k);
+void Dung_TagRoutine_0x2B(int k);
+void Dung_TagRoutine_0x2C(int k);
+void Dung_TagRoutine_0x2D(int k);
+void Dung_TagRoutine_0x2E(int k);
+void Dung_TagRoutine_0x2F(int k);
+void Dung_TagRoutine_0x30(int k);
+void RoomTag_QuadrantTrigger(int k);
+void Dung_TagRoutine_TrapdoorsUp();
+void RoomTag_RoomTrigger(int k);
+void RoomTag_RekillableBoss(int k);
+void RoomTag_RoomTrigger_BlockDoor(int k);
+void RoomTag_PrizeTriggerDoorDoor(int k);
+void RoomTag_SwitchTrigger_HoldDoor(int k);
+void RoomTag_SwitchTrigger_ToggleDoor(int k);
+void PushPressurePlate(uint8 attr);
+void RoomTag_TorchPuzzleDoor(int k);
+void RoomTag_Switch_ExplodingWall(int k);
+void RoomTag_PullSwitchExplodingWall(int k);
+void Dung_TagRoutine_BlastWallStuff(int k);
+void RoomTag_GetHeartForPrize(int k);
+void RoomTag_Agahnim(int k);
+void RoomTag_GanonDoor(int tagidx);
+void RoomTag_KillRoomBlock(int k);
+void RoomTag_PushBlockForChest(int k);
+void RoomTag_TriggerChest(int k);
+void RoomTag_OperateChestReveal(int k);
+void RoomTag_TorchPuzzleChest(int k);
+void RoomTag_MovingWall_East(int k);
+void RoomTag_MovingWallShakeItUp(int k);
+void RoomTag_MovingWall_West(int k);
+void RoomTag_MovingWallTorchesCheck(int k);
+int MovingWall_MoveALittle();
+int RoomTag_AdvanceGiganticWall(int k);
+void RoomTag_WaterOff(int k);
+void RoomTag_WaterOn(int k);
+void RoomTag_WaterGate(int k);
+void Dung_TagRoutine_0x1B(int k);
+void RoomTag_Holes0(int k);
+void Dung_TagRoutine_0x23(int k);
+void Dung_TagRoutine_0x34(int k);
+void Dung_TagRoutine_0x35(int k);
+void Dung_TagRoutine_0x36(int k);
+void Dung_TagRoutine_0x37(int k);
+void Dung_TagRoutine_0x39(int k);
+void Dung_TagRoutine_0x3A(int k);
+void Dung_TagRoutine_Func2(uint8 av);
+void RoomTag_ChestHoles0(int k);
+void Dung_TagRoutine_0x3B(int k);
+void RoomTag_Holes2(int k);
+void RoomTag_OperateWaterFlooring();
+bool RoomTag_MaybeCheckShutters(uint8 *attr_out);
+int RoomTag_GetTilemapCoords();
+bool RoomTag_CheckForPressedSwitch(uint8 *y_out);
+void Dungeon_ProcessTorchesAndDoors();
+void Bomb_CheckForDestructibles(uint16 x, uint16 y, uint8 r14);
+int DrawDoorOpening_Step1(int door, int dma_ptr);
+void DrawShutterDoorSteps(int door);
+void DrawEyeWatchDoor(int door);
+void Door_BlastWallExploding_Draw(int dsto);
+void OperateShutterDoors();
+void OpenCrackedDoor();
+void Dungeon_LoadToggleDoorAttr_OtherEntry(int door);
+void Dungeon_LoadSingleDoorTileAttribute();
+void DrawCompletelyOpenDoor();
+void Dungeon_ClearAwayExplodingWall();
+uint16 Dungeon_CheckForAndIDLiftableTile();
+void Dungeon_PushBlock_Handler();
+void RoomDraw_16x16Single(uint8 index);
+void PushBlock_CheckForPit(uint8 y);
+uint8 Dungeon_LiftAndReplaceLiftable(Point16U *pt);
+uint8 ThievesAttic_DrawLightenedHole(uint16 pos6, uint16 a, Point16U *pt);
+uint8 HandleItemTileAction_Dungeon(uint16 x, uint16 y);
+void ManipBlock_Something(Point16U *pt);
+void RevealPotItem(uint16 pos6, uint16 pos4);
+void Dungeon_UpdateTileMapWithCommonTile(int x, int y, uint8 v);
+void Dungeon_PrepSpriteInducedDma(int x, int y, uint8 v);
+void Dungeon_DeleteRupeeTile(uint16 x, uint16 y);
+uint8 OpenChestForItem(uint8 tile, int *chest_position);
+void OpenBigChest(uint16 loc, int *chest_position);
+uint8 OpenMiniGameChest(int *chest_position);
+uint16 RoomTag_BuildChestStripes(uint16 pos, uint16 y);
+void Dungeon_SetAttrForActivatedWaterOff();
+void Dungeon_FloodSwampWater_PrepTileMap();
+void Dungeon_AdjustWaterVomit(const uint16 *src, int depth);
+void Dungeon_SetAttrForActivatedWater();
+void FloodDam_Expand();
+void FloodDam_PrepTiles_init();
+void Watergate_Main_State1();
+void FloodDam_Fill();
+void Ganon_ExtinguishTorch_adjust_translucency();
+void Ganon_ExtinguishTorch();
+void Dungeon_ExtinguishTorch();
+void SpiralStairs_MakeNearbyWallsHighPriority_Entering();
+void SpiralStairs_MakeNearbyWallsLowPriority();
+void ClearAndStripeExplodingWall(uint16 dsto);
+void Dungeon_DrawRoomOverlay(const uint8 *src);
+void GetDoorDrawDataIndex_North_clean_door_index(int door);
+int DoorDoorStep1_North(int door, int dma_ptr);
+void GetDoorDrawDataIndex_North(int door, int r4_door);
+void DrawDoorToTileMap_North(int door, int r4_door);
+void Object_Draw_DoorUp_4x3(uint16 src, int door);
+void GetDoorDrawDataIndex_South_clean_door_index(int door);
+int DoorDoorStep1_South(int door, int dma_ptr);
+void GetDoorDrawDataIndex_South(int door, int r4_door);
+void DrawDoorToTileMap_South(int door, int r4_door);
+void Object_Draw_DoorDown_4x3(uint16 src, int door);
+void GetDoorDrawDataIndex_West_clean_door_index(int door);
+int DoorDoorStep1_West(int door, int dma_ptr);
+void GetDoorDrawDataIndex_West(int door, int r4_door);
+void DrawDoorToTileMap_West(int door, int r4_door);
+void GetDoorDrawDataIndex_East_clean_door_index(int door);
+int DoorDoorStep1_East(int door, int dma_ptr);
+void GetDoorDrawDataIndex_East(int door, int r4_door);
+void DrawDoorToTileMap_East(int door, int r4_door);
+uint8 GetDoorGraphicsIndex(int door, int r4_door);
+void ClearExplodingWallFromTileMap_ClearOnePair(uint16 *dst, const uint16 *src);
+void Dungeon_DrawRoomOverlay_Apply(int p);
+void ApplyGrayscaleFixed_Incremental();
+void Dungeon_ApproachFixedColor_variable(uint8 a);
+void Module_PreDungeon();
+void Module_PreDungeon_setAmbientSfx();
+void LoadOWMusicIfNeeded();
+void Module07_Dungeon();
+void Dungeon_TryScreenEdgeTransition();
+void Dungeon_HandleEdgeTransitionMovement(int dir);
+void Module07_00_PlayerControl();
+void Module07_01_SubtileTransition();
+void DungeonTransition_Subtile_ResetShutters();
+void DungeonTransition_Subtile_PrepTransition();
+void DungeonTransition_Subtile_ApplyFilter();
+void DungeonTransition_Subtile_TriggerShutters();
+void Module07_02_SupertileTransition();
+void Module07_02_00_InitializeTransition();
+void Module07_02_01_LoadNextRoom();
+void Dungeon_InterRoomTrans_State3();
+void Dungeon_InterRoomTrans_State10();
+void Dungeon_SpiralStaircase11();
+void Dungeon_InterRoomTrans_notDarkRoom();
+void Dungeon_InterRoomTrans_State9();
+void Dungeon_SpiralStaircase12();
+void Dungeon_InterRoomTrans_State4();
+void Dungeon_InterRoomTrans_State12();
+void Dungeon_Staircase14();
+void Dungeon_ResetTorchBackgroundAndPlayer();
+void Dungeon_ResetTorchBackgroundAndPlayerInner();
+void Dungeon_InterRoomTrans_State7();
+void DungeonTransition_RunFiltering();
+void Module07_02_FadedFilter();
+void Dungeon_InterRoomTrans_State15();
+void Dungeon_PlayMusicIfDefeated();
+void Module07_03_OverlayChange();
+void Module07_04_UnlockDoor();
+void Module07_05_ControlShutters();
+void Module07_06_FatInterRoomStairs();
+void Module07_0E_01_HandleMusicAndResetProps();
+void ResetTransitionPropsAndAdvance_ResetInterface();
+void ResetTransitionPropsAndAdvanceSubmodule();
+void Dungeon_InitializeRoomFromSpecial();
+void DungeonTransition_LoadSpriteGFX();
+void DungeonTransition_AdjustForFatStairScroll();
+void ResetThenCacheRoomEntryProperties();
+void DungeonTransition_TriggerBGC34UpdateAndAdvance();
+void DungeonTransition_TriggerBGC56UpdateAndAdvance();
+void Module07_07_FallingTransition();
+void Module07_07_00_HandleMusicAndResetRoom();
+void Module07_07_06_SyncBG1and2();
+void Module07_07_0F_FallingFadeIn();
+void Dungeon_PlayBlipAndCacheQuadrantVisits();
+void Module07_07_10_LandLinkFromFalling();
+void Module07_07_11_CacheRoomAndSetMusic();
+void Module07_08_NorthIntraRoomStairs();
+void Module07_08_00_InitStairs();
+void Module07_08_01_ClimbStairs();
+void Module07_10_SouthIntraRoomStairs();
+void Module07_10_00_InitStairs();
+void Module07_10_01_ClimbStairs();
+void Module07_09_OpenCrackedDoor();
+void Module07_0A_ChangeBrightness();
+void Module07_0B_DrainSwampPool();
+void Module07_0C_FloodSwampWater();
+void Module07_0D_FloodDam();
+void Module07_0E_SpiralStairs();
+void Dungeon_DoubleApplyAndIncrementGrayscale();
+void Module07_0E_02_ApplyFilterIf();
+void Dungeon_SyncBackgroundsFromSpiralStairs();
+void Dungeon_AdvanceThenSetBossMusicUnorthodox();
+void Dungeon_SetBossMusicUnorthodox();
+void Dungeon_SpiralStaircase17();
+void Dungeon_SpiralStaircase18();
+void Module07_0E_00_InitPriorityAndScreens();
+void Module07_0E_13_SetRoomAndLayerAndCache();
+void RepositionLinkAfterSpiralStairs();
+void SpiralStairs_MakeNearbyWallsHighPriority_Exiting();
+void Module07_0F_LandingWipe();
+void Module07_0F_00_InitSpotlight();
+void Module07_0F_01_OperateSpotlight();
+void Module07_11_StraightInterroomStairs();
+void Module07_11_00_PrepAndReset();
+void Module07_11_01_FadeOut();
+void Module07_11_02_LoadAndPrepRoom();
+void Module07_11_03_FilterAndLoadBGChars();
+void Module07_11_04_FilterDoBGAndResetSprites();
+void Module07_11_0B_PrepDestination();
+void Module07_11_09_LoadSpriteGraphics();
+void Module07_11_19_SetSongAndFilter();
+void Module07_11_11_KeepSliding();
+void Module07_14_RecoverFromFall();
+void Module07_14_00_ScrollCamera();
+void Module07_15_WarpPad();
+void Module07_15_01_ApplyMosaicAndFilter();
+void Module07_15_04_SyncRoomPropsAndBuildOverlay();
+void Module07_15_0E_FadeInFromWarp();
+void Module07_15_0F_FinalizeAndCacheEntry();
+void Module07_16_UpdatePegs();
+void Module07_17_PressurePlate();
+void Module07_18_RescuedMaiden();
+void Module07_19_MirrorFade();
+void Module07_1A_RoomDraw_OpenTriforceDoor_bounce();
+void Module11_DungeonFallingEntrance();
+void Module11_02_LoadEntrance();
+void Dungeon_LoadSongBankIfNeeded();
+void Mirror_SaveRoomData();
+void SaveDungeonKeys();
+void Dungeon_AdjustAfterSpiralStairs();
+void Dungeon_AdjustForTeleportDoors(uint8 room, uint8 flag);
+void Dungeon_AdjustForRoomLayout();
+void HandleEdgeTransitionMovementEast_RightBy8();
+void Dungeon_StartInterRoomTrans_Right();
+void HandleEdgeTransitionMovementSouth_DownBy16();
+void Dung_HandleExitToOverworld();
+void AdjustQuadrantAndCamera_right();
+void SetAndSaveVisitedQuadrantFlags();
+void SaveQuadrantsToSram();
+void AdjustQuadrantAndCamera_left();
+void AdjustQuadrantAndCamera_down();
+void AdjustQuadrantAndCamera_up();
+void Dungeon_FlagRoomData_Quadrants();
+void Dung_SaveDataForCurrentRoom();
+void HandleEdgeTransition_AdjustCameraBoundaries(uint8 arg);
+void Dungeon_AdjustQuadrant();
+void Dungeon_HandleCamera();
+void MirrorBg1Bg2Offs();
+void DungeonTransition_AdjustCamera_X(uint8 arg);
+void DungeonTransition_AdjustCamera_Y(uint8 arg);
+void DungeonTransition_ScrollRoom();
+void Module07_11_0A_ScrollCamera();
+void DungeonTransition_FindSubtileLanding();
+void SubtileTransitionCalculateLanding();
+void Dungeon_InterRoomTrans_State13();
+void Dungeon_IntraRoomTrans_State5();
+bool DungeonTransition_MoveLinkOutDoor();
+uint8 CalculateTransitionLanding();
+void Dungeon_LoadAndDrawRoom();
+void Dungeon_LoadEntrance();
+void PushBlock_Slide(uint8 j);
+void PushBlock_HandleFalling(uint8 y);
+void PushBlock_ApplyVelocity(uint8 i);
+void PushBlock_HandleCollision(uint8 i, uint16 x, uint16 y);
+void Sprite_Dungeon_DrawAllPushBlocks();
+void UsedForStraightInterRoomStaircase();
+void HandleLinkOnSpiralStairs();
+void SpiralStairs_FindLandingSpot();
+void Dungeon_HandleLayerEffect();
+void LayerEffect_Nothing();
+void LayerEffect_Scroll();
+void LayerEffect_Trinexx();
+void LayerEffect_Agahnim2();
+void LayerEffect_InvisibleFloor();
+void LayerEffect_Ganon();
+void LayerEffect_WaterRapids();
+void Dungeon_LoadCustomTileAttr();
+void Link_CheckBunnyStatus();
+void CrystalCutscene_Initialize();
+void CrystalCutscene_SpawnMaiden();
--- /dev/null
+++ b/src/ending.c
@@ -1,0 +1,2658 @@
+#include "zelda_rtl.h"
+#include "snes/snes_regs.h"
+#include "variables.h"
+#include "load_gfx.h"
+#include "dungeon.h"
+#include "sprite.h"
+#include "ending.h"
+#include "overworld.h"
+#include "player.h"
+#include "misc.h"
+#include "messaging.h"
+#include "player_oam.h"
+#include "sprite_main.h"
+#include "ancilla.h"
+#include "hud.h"
+#include "assets.h"
+
+static const uint16 kPolyhedralPalette[8] = { 0, 0x14d, 0x1b0, 0x1f3, 0x256, 0x279, 0x2fd, 0x35f };
+
+#define ending_which_dung (*(uint16*)(g_ram+0xcc))
+#define kPolyThreadRam (g_ram + 0x1f00)
+static const int8 kIntroSprite0_Xvel[3] = { 1, 0, -1 };
+static const int8 kIntroSprite0_Yvel[3] = { -1, 1, -1 };
+static const uint8 kIntroSprite3_X[4] = { 0xc2, 0x98, 0x6f, 0x34 };
+static const uint8 kIntroSprite3_Y[4] = { 0x7c, 0x54, 0x7c, 0x57 };
+static const uint8 kIntroSprite3_State[8] = { 0, 1, 2, 3, 2, 1, 0xff, 0xff };
+static const uint8 kTriforce_Xfinal[3] = { 0x59, 0x5f, 0x67 };
+static const uint8 kTriforce_Yfinal[3] = { 0x74, 0x68, 0x74 };
+static const uint16 kEndingSprites_X[] = {
+  0x1e0, 0x200, 0x1ed, 0x203, 0x1da, 0x216, 0x1c8, 0x228, 0x1c0, 0x1e0, 0x208, 0x228,
+  0xf8, 0xf0,
+  0x278, 0x298, 0x1e0, 0x200, 0x220, 0x288, 0x1e2,
+  0xe0, 0x150, 0xe8, 0x168, 0x128, 0x170, 0x170,
+  0x335, 0x335, 0x300,
+  0xb8, 0xce, 0xac, 0xc4,
+  0x3b0, 0x390, 0x3d0,
+  0xf8, 0xc8,
+  0x80,
+  0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xe8, 0xf8, 0xd8, 0xf8, 0xc8, 0x108,
+  0x70, 0x70, 0x70, 0x68, 0x88, 0x70,
+  0x40, 0x70, 0x4f, 0x61, 0x37, 0x79,
+  0xc8, 0x278, 0x258, 0x1d8, 0x1c8, 0x188, 0x270,
+  0x180,
+  0x2e8, 0x270, 0x270, 0x2a0, 0x2a0, 0x2a4, 0x2fc,
+  0x76, 0x73, 0x76, 0x0, 0xd0, 0x80,
+};
+static const uint16 kEndingSprites_Y[] = {
+  0x158, 0x158, 0x138, 0x138, 0x140, 0x140, 0x150, 0x150, 0x120, 0x120, 0x120, 0x120,
+  0x60, 0x37,
+  0xc2, 0xc2, 0x16b, 0x16c, 0x16b, 0xb8, 0x16b,
+  0x80, 0x60, 0x146, 0x146, 0x1c6, 0x70, 0x70,
+  0x128, 0x128, 0x16f,
+  0xf5, 0xfc, 0x10d, 0x10d,
+  0x40, 0x40, 0x40,
+  0x150, 0x158,
+  0xf4,
+  0x120, 0x120, 0x120, 0x120, 0x120, 0x108, 0x100, 0xd8, 0xd8, 0xf0, 0xf0,
+  0x3c, 0x3c, 0x3c, 0x90, 0x80, 0x3c,
+  0x16c, 0x16c, 0x174, 0x174, 0x175, 0x175,
+  0x250, 0x2b0, 0x2b0, 0x2a0, 0x2b0, 0x2b0, 0x2b8,
+  0xd8,
+  0x24b, 0x1b0, 0x1c8, 0x1c8, 0x1b0, 0x230, 0x230,
+  0x8b, 0x83, 0x85, 0x2c, 0xf8, 0x100,
+};
+static const uint8 kEndingSprites_Idx[17] = {
+  0, 12, 14, 21, 28, 31, 35, 38, 40, 41, 52, 58, 64, 71, 72, 79, 85
+};
+static PlayerHandlerFunc *const kEndSequence0_Funcs[3] = {
+&Credits_LoadScene_Overworld_PrepGFX,
+&Credits_LoadScene_Overworld_Overlay,
+&Credits_LoadScene_Overworld_LoadMap,
+};
+static PrepOamCoordsRet g_ending_coords;
+static const uint16 kEnding1_TargetScrollY[16] = { 0x6f2, 0x210, 0x72c, 0xc00, 0x10c, 0xa9b, 0x10, 0x510, 0x89, 0xa8e, 0x222c, 0x2510, 0x826, 0x5c, 0x20a, 0x30 };
+static const uint16 kEnding1_TargetScrollX[16] = { 0x77f, 0x480, 0x193, 0xaa, 0x878, 0x847, 0x4fd, 0xc57, 0x40f, 0x478, 0xa00, 0x200, 0x201, 0xaa1, 0x26f, 0 };
+static const int8 kEnding1_Yvel[16] = { -1, -1, 1, -1, 1, 1, 0, 1, 0, -1, -1, 0, 0, 0, 1, -1 };
+static const int8 kEnding1_Xvel[16] = { 0, 0, -1, 0, 0, -1, 1, 0, -1, 0, 0, 0, 1, -1, 1, 0 };
+static PlayerHandlerFunc *const kEndSequence_Funcs[39] = {
+&Credits_LoadNextScene_Overworld,
+&Credits_ScrollScene_Overworld,
+&Credits_LoadNextScene_Dungeon,
+&Credits_ScrollScene_Dungeon,
+&Credits_LoadNextScene_Overworld,
+&Credits_ScrollScene_Overworld,
+&Credits_LoadNextScene_Overworld,
+&Credits_ScrollScene_Overworld,
+&Credits_LoadNextScene_Overworld,
+&Credits_ScrollScene_Overworld,
+&Credits_LoadNextScene_Overworld,
+&Credits_ScrollScene_Overworld,
+&Credits_LoadNextScene_Overworld,
+&Credits_ScrollScene_Overworld,
+&Credits_LoadNextScene_Overworld,
+&Credits_ScrollScene_Overworld,
+&Credits_LoadNextScene_Overworld,
+&Credits_ScrollScene_Overworld,
+&Credits_LoadNextScene_Overworld,
+&Credits_ScrollScene_Overworld,
+&Credits_LoadNextScene_Dungeon,
+&Credits_ScrollScene_Dungeon,
+&Credits_LoadNextScene_Dungeon,
+&Credits_ScrollScene_Dungeon,
+&Credits_LoadNextScene_Overworld,
+&Credits_ScrollScene_Overworld,
+&Credits_LoadNextScene_Overworld,
+&Credits_ScrollScene_Overworld,
+&Credits_LoadNextScene_Overworld,
+&Credits_ScrollScene_Overworld,
+&Credits_LoadNextScene_Overworld,
+&Credits_ScrollScene_Overworld,
+&EndSequence_32,
+&Credits_BrightenTriangles,
+&Credits_FadeColorAndBeginAnimating,
+&Credits_StopCreditsScroll,
+&Credits_FadeAndDisperseTriangles,
+&Credits_FadeInTheEnd,
+&Credits_HangForever,
+};
+#define intro_sword_ypos WORD(g_ram[0xc8])
+#define intro_sword_18 g_ram[0xca]
+#define intro_sword_19 g_ram[0xcb]
+#define intro_sword_20 g_ram[0xcc]
+#define intro_sword_21 g_ram[0xcd]
+#define intro_sword_24 g_ram[0xd0]
+static const uint16 kEnding_Tab1[16] = {
+  0x1000, 2, 0x1002, 0x1012, 0x1004, 0x1006, 0x1010, 0x1014, 0x100a,
+  0x1016, 0x5d, 0x64, 0x100e, 0x1008, 0x1018, 0x180 };
+static const uint8 kEnding_SpritePack[17] = {
+  0x28, 0x46, 0x27, 0x2e, 0x2b, 0x2b, 0xe, 0x2c, 0x1a, 0x29, 0x47, 0x28, 0x27, 0x28, 0x2a, 0x28, 0x2d,
+};
+static const uint8 kEnding_SpritePal[17] = {
+  1, 0x40, 1, 4, 1, 1, 1, 0x11, 1, 1, 0x47, 0x40, 1, 1, 1, 1, 1,
+};
+void Intro_SetupScreen() {  // 828000
+  nmi_disable_core_updates = 0x80;
+  EnableForceBlank();
+  TM_copy = 16;
+  TS_copy = 0;
+  Intro_InitializeBackgroundSettings();
+  CGWSEL_copy = 0x20;
+  load_chr_halfslot_even_odd = 20;
+  Graphics_LoadChrHalfSlot();
+  load_chr_halfslot_even_odd = 0;
+  LoadOWMusicIfNeeded();
+
+  // why 17?
+  for(int i = 0; i < 17; i++)
+    main_palette_buffer[144 + i] = 0x7fff;
+
+  for (int i = 0; i < 17; i++)
+    g_zenv.vram[0x27f0 + i] = 0;
+
+  R16 = 0x1ffe;
+  R18 = 0x1bfe;
+}
+
+void Intro_LoadTextPointersAndPalettes() {  // 828116
+  Text_GenerateMessagePointers();
+  Overworld_LoadAllPalettes();
+}
+
+void Credits_LoadScene_Overworld_PrepGFX() {  // 828604
+  EnableForceBlank();
+  EraseTileMaps_normal();
+  CGWSEL_copy = 0x82;
+  int k = submodule_index >> 1;
+  dungeon_room_index = kEnding_Tab1[k];
+
+  if (k != 6 && k != 15)
+    LoadOverworldFromDungeon();
+  else
+    Overworld_EnterSpecialArea();
+  music_control = 0;
+  sound_effect_ambient = 0;
+
+  int t = BYTE(overworld_screen_index) & ~0x40;
+  DecompressAnimatedOverworldTiles((t == 3 || t == 5 || t == 7) ? 0x58 : 0x5a);
+
+  k = submodule_index >> 1;
+  sprite_graphics_index = kEnding_SpritePack[k];
+  uint8 sprpal = kEnding_SpritePal[k];
+  InitializeTilesets();
+  OverworldLoadScreensPaletteSet();
+  Overworld_LoadPalettes(GetOverworldBgPalette(BYTE(overworld_screen_index)), sprpal);
+
+  hud_palette = 1;
+  Palette_Load_HUD();
+  if (!submodule_index)
+    TransferFontToVRAM();
+  Overworld_LoadPalettesInner();
+  Overworld_SetFixedColAndScroll();
+  if (BYTE(overworld_screen_index) >= 128)
+    Palette_SetOwBgColor();
+  BGMODE_copy = 9;
+  subsubmodule_index++;
+}
+
+void Credits_LoadScene_Overworld_Overlay() {  // 828697
+  Overworld_LoadOverlays2();
+  music_control = 0;
+  sound_effect_ambient = 0;
+  submodule_index--;
+  subsubmodule_index++;
+}
+
+void Credits_LoadScene_Overworld_LoadMap() {  // 8286a5
+  Overworld_LoadAndBuildScreen();
+  Credits_PrepAndLoadSprites();
+  R16 = 0;
+  subsubmodule_index = 0;
+}
+
+void Credits_OperateScrollingAndTileMap() {  // 8286b3
+  Credits_HandleCameraScrollControl();
+  if (BYTE(overworld_screen_trans_dir_bits2))
+    OverworldHandleMapScroll();
+}
+
+void Credits_LoadCoolBackground() {  // 8286c0
+  main_tile_theme_index = 33;
+  aux_tile_theme_index = 59;
+  sprite_graphics_index = 45;
+  InitializeTilesets();
+  BYTE(overworld_screen_index) = 0x5b;
+  Overworld_LoadPalettes(GetOverworldBgPalette(BYTE(overworld_screen_index)), 0x13);
+  overworld_palette_aux2_bp5to7_hi = 3;
+  Palette_Load_OWBG2();
+  Overworld_CopyPalettesToCache();
+  Overworld_LoadOverlays2();
+  BG1VOFS_copy2 = 0;
+  BG1HOFS_copy2 = 0;
+  submodule_index--;
+}
+
+void Credits_LoadScene_Dungeon() {  // 8286fd
+  EnableForceBlank();
+  EraseTileMaps_normal();
+  WORD(which_entrance) = kEnding_Tab1[submodule_index >> 1];
+
+  Dungeon_LoadEntrance();
+  dung_num_lit_torches = 0;
+  hdr_dungeon_dark_with_lantern = 0;
+  Dungeon_LoadAndDrawRoom();
+  DecompressAnimatedDungeonTiles(kDungAnimatedTiles[main_tile_theme_index]);
+
+  int i = submodule_index >> 1;
+  sprite_graphics_index = kEnding_SpritePack[i];
+  const DungPalInfo *dpi = GetDungPalInfo(kEnding_SpritePal[i] & 0x3f);
+  palette_sp5l = dpi->pal2;
+  palette_sp6l = dpi->pal3;
+  misc_sprites_graphics_index = 10;
+  InitializeTilesets();
+  palette_sp6r_indoors = 10;
+  Dungeon_LoadPalettes();
+  BGMODE_copy = 9;
+  R16 = 0;
+  INIDISP_copy = 0;
+  submodule_index++;
+  Credits_PrepAndLoadSprites();
+}
+
+void Module18_GanonEmerges() {  // 829edc
+  uint16 hofs2 = BG2HOFS_copy2;
+  uint16 vofs2 = BG2VOFS_copy2;
+  uint16 hofs1 = BG1HOFS_copy2;
+  uint16 vofs1 = BG1VOFS_copy2;
+
+  BG2HOFS_copy2 = BG2HOFS_copy = hofs2 + bg1_x_offset;
+  BG2VOFS_copy2 = BG2VOFS_copy = vofs2 + bg1_y_offset;
+  BG1HOFS_copy2 = BG1HOFS_copy = hofs1 + bg1_x_offset;
+  BG1VOFS_copy2 = BG1VOFS_copy = vofs1 + bg1_y_offset;
+  Sprite_Main();
+  BG1VOFS_copy2 = vofs1;
+  BG1HOFS_copy2 = hofs1;
+  BG2VOFS_copy2 = vofs2;
+  BG2HOFS_copy2 = hofs2;
+
+  switch (overworld_map_state) {
+  case 0:  // GetBirdForPursuit
+    Dungeon_HandleLayerEffect();
+    CallForDuckIndoors();
+    SaveDungeonKeys();
+    overworld_map_state++;
+    flag_is_link_immobilized++;
+    break;
+  case 1:  // PrepForPyramidLocation
+    Dungeon_HandleLayerEffect();
+    if (submodule_index == 10) {
+      overworld_screen_index = 91;
+      player_is_indoors = 0;
+      main_module_index = 24;
+      submodule_index = 0;
+      overworld_map_state = 2;
+    }
+    break;
+  case 2:  // FadeOutDungeonScreen
+    Dungeon_HandleLayerEffect();
+    if (--INIDISP_copy)
+      break;
+    EnableForceBlank();
+    overworld_map_state++;
+    Hud_RebuildIndoor();
+    link_x_vel = link_y_vel = 0;
+    break;
+  case 3:  // LOadPyramidArea
+    birdtravel_var1[0] = 8;
+    birdtravel_var1[1] = 0;
+    FluteMenu_LoadSelectedScreen();
+    LoadOWMusicIfNeeded();
+    music_control = 9;
+    break;
+  case 4:  // LoadAmbientOverlay
+    Overworld_LoadOverlayAndMap();
+    subsubmodule_index = 0;
+    break;
+  case 5:  // BrightenScreenThenSpawnBat
+    if (++INIDISP_copy == 15) {
+      dung_savegame_state_bits = 0;
+      flag_unk1 = 0;
+      Sprite_SpawnBatCrashCutscene();
+      link_direction_facing = 2;
+      saved_module_for_menu = 9;
+      player_is_indoors = 0;
+      overworld_map_state++;
+      subsubmodule_index = 128;
+      BYTE(cur_palace_index_x2) = 255;
+    }
+    break;
+  case 6:  // DelayForBatSmashIntoPyramid
+    break;
+  case 7:  // DelayPlayerDropOff
+    if (!--subsubmodule_index)
+      overworld_map_state++;
+    break;
+  case 8:  // DropOffPlayerAtPyramid
+    BirdTravel_Finish_Doit();
+    break;
+  }
+
+  LinkOam_Main();
+}
+
+void Module19_TriforceRoom() {  // 829fec
+  switch (subsubmodule_index) {
+  case 0:  //
+    Link_ResetProperties_A();
+    link_last_direction_moved_towards = 0;
+    music_control = 0xf1;
+    ResetTransitionPropsAndAdvance_ResetInterface();
+    break;
+  case 1:  //
+    ConditionalMosaicControl();
+    ApplyPaletteFilter_bounce();
+    break;
+  case 2:  //
+    EnableForceBlank();
+    LoadCreditsSongs();
+    dungeon_room_index = 0x189;
+    EraseTileMaps_normal();
+    Palette_RevertTranslucencySwap();
+    Overworld_EnterSpecialArea();
+    Overworld_LoadOverlays2();
+    subsubmodule_index++;
+    main_module_index = 25;
+    submodule_index = 0;
+    break;
+  case 3:  //
+    main_tile_theme_index = 36;
+    sprite_graphics_index = 125;
+    aux_tile_theme_index = 81;
+    InitializeTilesets();
+    Overworld_LoadAreaPalettesEx(4);
+    Overworld_LoadPalettes(14, 0);
+    SpecialOverworld_CopyPalettesToCache();
+    subsubmodule_index++;
+    break;
+  case 4: { //
+    uint8 bak0 = subsubmodule_index;
+    Module08_02_LoadAndAdvance();
+    subsubmodule_index = bak0 + 1;
+    INIDISP_copy = 15;
+    palette_filter_countdown = 31;
+    mosaic_target_level = 0;
+    HIBYTE(BG1HOFS_copy2) = 1;
+    CGWSEL_copy = 2;
+    CGADSUB_copy = 50;
+    mosaic_level = 240;
+    BYTE(link_y_coord) = 236;
+    BYTE(link_x_coord) = 120;
+    link_is_on_lower_level = 2;
+    music_control = 32;
+    main_module_index = 25;
+    submodule_index = 0;
+    break;
+  }
+  case 5:  //
+    link_direction = 8;
+    link_direction_last = 8;
+    link_direction_facing = 0;
+    if (BYTE(link_y_coord) < 192) {
+      link_direction = 0;
+      link_direction_last = 0;
+      link_animation_steps = 0;
+      subsubmodule_index++;
+    }
+    break;
+  case 6:  //
+    if (!(palette_filter_countdown & 1) && mosaic_level != 0)
+      mosaic_level -= 0x10;
+    BGMODE_copy = 9;
+    MOSAIC_copy = mosaic_level | 7;
+    ApplyPaletteFilter_bounce();
+    break;
+  case 7:  //
+    TriforceRoom_PrepGFXSlotForPoly();
+    dialogue_message_index = 0x173;
+    Main_ShowTextMessage();
+    RenderText();
+    BYTE(R16) = 0x80;
+    main_module_index = 25;
+    subsubmodule_index++;
+    break;
+  case 8:  //
+  case 10:  //
+    AdvancePolyhedral();
+    if (subsubmodule_index == 11) {
+      music_control = 33;
+      main_module_index = 25;
+      link_direction = 0;
+      link_direction_last = 0;
+      submodule_index++;
+    }
+    break;
+  case 9:  //
+    AdvancePolyhedral();
+    RenderText();
+    if (!submodule_index) {
+      overworld_map_state = 0;
+      main_module_index = 25;
+      subsubmodule_index++;
+    }
+    break;
+  case 11:  //
+    AdvancePolyhedral();
+    TriforceRoom_LinkApproachTriforce();
+    if (subsubmodule_index == 12) {
+      link_direction = 0;
+      link_direction_last = 0;
+    }
+    break;
+  case 12:  //
+    AdvancePolyhedral();
+    if (!--BYTE(R16)) {
+      Palette_AnimGetMasterSword2();
+      submodule_index++;
+    }
+    break;
+  case 13:  //
+    AdvancePolyhedral();
+    PaletteFilter_BlindingWhiteTriforce();
+    if (BYTE(darkening_or_lightening_screen) == 255)
+      subsubmodule_index++;
+    break;
+  case 14:  //
+    if (!--INIDISP_copy) {
+      main_module_index = 26;
+      submodule_index = 0;
+      subsubmodule_index = 0;
+      irq_flag = 255;
+      is_nmi_thread_active = 0;
+      nmi_flag_update_polyhedral = 0;
+      savegame_is_darkworld = 0;
+    }
+    break;
+  }
+  BG1HOFS_copy = BG1HOFS_copy2;
+  BG1VOFS_copy = BG1VOFS_copy2;
+  BG2HOFS_copy = BG2HOFS_copy2;
+  BG2VOFS_copy = BG2VOFS_copy2;
+  if (subsubmodule_index < 7 || subsubmodule_index >= 11) {
+    Link_HandleVelocity();
+    Link_HandleMovingAnimation_FullLongEntry();
+  }
+  LinkOam_Main();
+}
+
+void Intro_InitializeBackgroundSettings() {  // 82c500
+  BGMODE_copy = 9;
+  MOSAIC_copy = 0;
+  zelda_ppu_write(BG1SC, 0x13);
+  zelda_ppu_write(BG2SC, 3);
+  zelda_ppu_write(BG3SC, 0x63);
+  CGADSUB_copy = 32;
+  COLDATA_copy0 = 32;
+  COLDATA_copy1 = 64;
+  COLDATA_copy2 = 128;
+}
+
+void Polyhedral_InitializeThread() {  // 89f7de
+  static const uint8 kPolyThreadInit[13] = { 9, 0, 0x1f, 0, 0, 0, 0, 0, 0, 0x30, 0x1d, 0xf8, 9 };
+  memset(kPolyThreadRam, 0, 256);
+  thread_other_stack = 0x1f31;
+  memcpy(&g_ram[0x1f32], kPolyThreadInit, 13);
+}
+
+void Module00_Intro() {  // 8cc120
+  uint8 skip_at = enhanced_features0 & kFeatures0_SkipIntroOnKeypress ? 4 : 8;
+
+  if (submodule_index >= skip_at && ((filtered_joypad_L & 0xc0 | filtered_joypad_H) & 0xd0)) {
+    FadeMusicAndResetSRAMMirror();
+    return;
+  }
+  switch (submodule_index) {
+  case 0: Intro_Init(); break;
+  case 1: Intro_Init_Continue(); break;
+  case 10:
+  case 2: Intro_InitializeTriforcePolyThread(); break;
+  case 3:
+  case 4:
+  case 9:
+  case 11: Intro_HandleAllTriforceAnimations(); break;
+  case 5: IntroZeldaFadein(); break;
+  case 6: Intro_SwordComingDown(); break;
+  case 7: Intro_FadeInBg(); break;
+  case 8: Intro_WaitPlayer(); break;
+  }
+}
+
+void Intro_Init() {  // 8cc15d
+  Intro_SetupScreen();
+  INIDISP_copy = 15;
+  subsubmodule_index = 0;
+  flag_update_cgram_in_nmi++;
+  submodule_index++;
+  sound_effect_2 = 10;
+  Intro_Init_Continue();
+}
+
+void Intro_Init_Continue() {  // 8cc170
+  Intro_DisplayLogo();
+  int t = subsubmodule_index++;
+  if (t >= 11) {
+    if (--INIDISP_copy)
+      return;
+    Intro_InitializeMemory_darken();
+    return;
+  }
+  switch (t) {
+  case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7:
+    Intro_Clear1kbBlocksOfWRAM();
+    break;
+  case 8: Intro_LoadTextPointersAndPalettes(); break;
+  case 9: LoadItemGFXIntoWRAM4BPPBuffer(); break;
+  case 10:LoadFollowerGraphics(); break;
+  }
+}
+
+void Intro_Clear1kbBlocksOfWRAM() {  // 8cc1a0
+  uint16 i = R16;
+  uint8 *dst = (uint8 *)&g_ram[0x2000];
+  do {
+    for (int j = 0; j < 15; j++)
+      WORD(dst[i + j * 0x2000]) = 0;
+  } while ((i -= 2) != R18);
+  R16 = i;
+  R18 = i - 0x400;
+}
+
+void Intro_InitializeMemory_darken() {  // 8cc1f5
+  EnableForceBlank();
+  EraseTileMaps_normal();
+  main_tile_theme_index = 35;
+  sprite_graphics_index = 125;
+  aux_tile_theme_index = 81;
+  misc_sprites_graphics_index = 8;
+  LoadDefaultGraphics();
+  InitializeTilesets();
+  DecompressAnimatedDungeonTiles(0x5d);
+  bg_tile_animation_countdown = 2;
+  BYTE(overworld_screen_index) = 0;
+  palette_main_indoors = 0;
+  overworld_palette_aux3_bp7_lo = 0;
+  R16 = 0;
+  R18 = 0;
+  darkening_or_lightening_screen = 2;
+  palette_filter_countdown = 31;
+  mosaic_target_level = 0;
+  submodule_index++;
+}
+
+void IntroZeldaFadein() {  // 8cc25c
+  Intro_HandleAllTriforceAnimations();
+  if (!(frame_counter & 1))
+    return;
+  Palette_FadeIntroOneStep();
+  if (BYTE(palette_filter_countdown) == 0) {
+    subsubmodule_index = 42;
+    submodule_index++;
+    Intro_SetupSwordAndIntroFlash();
+  } else if (BYTE(palette_filter_countdown) == 13) {
+    TM_copy = 0x15;
+    TS_copy = 0;
+  }
+}
+
+void Intro_FadeInBg() {  // 8cc284
+  Intro_PeriodicSwordAndIntroFlash();
+  Intro_HandleAllTriforceAnimations();
+  if (BYTE(palette_filter_countdown)) {
+    if (frame_counter & 1)
+      Palette_FadeIntro2();
+  } else {
+    if ((filtered_joypad_L & 0xc0 | filtered_joypad_H) & 0xd0)
+      FadeMusicAndResetSRAMMirror();
+    else {
+      if (!--subsubmodule_index)
+        submodule_index++;
+    }
+  }
+}
+
+void Intro_SwordComingDown() {  // 8cc2ae
+  Intro_HandleAllTriforceAnimations();
+  intro_did_run_step = 0;
+  is_nmi_thread_active = 0;
+  Intro_PeriodicSwordAndIntroFlash();
+  if (!--subsubmodule_index) {
+    submodule_index++;
+    CGWSEL_copy = 2;
+    CGADSUB_copy = 0x22;
+    palette_filter_countdown = 31;
+    TS_copy = 2;
+  }
+}
+
+void Intro_WaitPlayer() {  // 8cc2d4
+  Intro_HandleAllTriforceAnimations();
+  intro_did_run_step = 0;
+  is_nmi_thread_active = 0;
+  Intro_PeriodicSwordAndIntroFlash();
+  if (!--subsubmodule_index) {
+    submodule_index++;
+    main_module_index = 20;
+    submodule_index = 0;
+    BYTE(link_x_coord) = 0;
+  }
+}
+
+void FadeMusicAndResetSRAMMirror() {  // 8cc2f0
+  irq_flag = 255;
+  TM_copy = 0x15;
+  TS_copy = 0;
+  player_is_indoors = 0;
+  music_control = 0xf1;
+  SetBackdropcolorBlack();
+
+  memset(&link_y_coord, 0, 0x70);
+  memset(save_dung_info, 0, 256 * 5);
+
+  main_module_index = 1;
+  death_var4 = 1;
+  submodule_index = 0;
+}
+
+void Intro_InitializeTriforcePolyThread() {  // 8cc33c
+  misc_sprites_graphics_index = 8;
+  LoadCommonSprites();
+  Intro_InitGfx_Helper();
+  intro_sprite_isinited[0] = 1;
+  intro_sprite_isinited[1] = 1;
+  intro_sprite_isinited[2] = 1;
+  intro_sprite_subtype[0] = 0;
+  intro_sprite_subtype[1] = 0;
+  intro_sprite_subtype[2] = 0;
+  intro_sprite_isinited[4] = 1;
+  intro_sprite_subtype[4] = 2;
+  INIDISP_copy = 15;
+  submodule_index++;
+}
+
+void Intro_InitGfx_Helper() {  // 8cc36f
+  Polyhedral_InitializeThread();
+  LoadTriforceSpritePalette();
+  virq_trigger = 0x90;
+  poly_config1 = 255;
+  poly_base_x = 32;
+  poly_base_y = 32;
+  BYTE(poly_var1) = 32;
+  poly_a = 0xA0;
+  poly_b = 0x60;
+  poly_config_color_mode = 1;
+  poly_which_model = 1;
+  is_nmi_thread_active = 1;
+  intro_did_run_step = 1;
+  memset(&intro_step_index, 0, 7 * 16);
+}
+
+void LoadTriforceSpritePalette() {  // 8cc3bd
+  memcpy(main_palette_buffer + 0xd0, kPolyhedralPalette, 16);
+  flag_update_cgram_in_nmi++;
+}
+
+void Intro_HandleAllTriforceAnimations() {  // 8cc404
+  intro_frame_ctr++;
+  Intro_AnimateTriforce();
+  Scene_AnimateEverySprite();
+}
+
+void Scene_AnimateEverySprite() {  // 8cc412
+  intro_sprite_alloc = 0x800;
+  for (int k = 7; k >= 0; k--)
+    Intro_AnimOneObj(k);
+}
+
+void Intro_AnimateTriforce() {  // 8cc435
+  is_nmi_thread_active = 1;
+  if (!intro_did_run_step) {
+    Intro_RunStep();
+    intro_did_run_step = 1;
+  }
+}
+
+void Intro_RunStep() {  // 8cc448
+  switch (intro_step_index) {
+  case 0:
+    if (++intro_step_timer == 64)
+      intro_step_index++;
+    poly_b += 5, poly_a += 3;
+    break;
+  case 1:
+    if (poly_config1 < 2) {
+      poly_config1 = 0;
+      intro_step_index++;
+      intro_step_timer = 64;
+      return;
+    }
+    poly_config1 -= 2;
+    poly_b += 5;
+    poly_a += 3;
+    if (poly_config1 < 225)
+      submodule_index = 4;
+    if (poly_config1 == 113)
+      music_control = 1;
+    break;
+  case 2:
+    if (!--intro_step_timer) {
+      intro_step_index++;
+    } else {
+      poly_b += 5, poly_a += 3;
+    }
+    break;
+  case 3:
+    if (poly_b >= 250 && poly_a >= 252) {
+      intro_step_index++;
+      intro_step_timer = 32;
+    } else {
+      poly_b += 5, poly_a += 3;
+    }
+    break;
+  case 4:
+    poly_b = 0;
+    poly_a = 0;
+    if (!--intro_step_timer) {
+      intro_step_index++;
+      intro_sprite_isinited[5] = 1;
+      intro_sprite_subtype[5] = 3;
+      TM_copy = 0x10;
+      TS_copy = 5;
+      CGWSEL_copy = 2;
+      CGADSUB_copy = 0x31;
+      subsubmodule_index = 0;
+      flag_update_cgram_in_nmi++;
+      nmi_load_bg_from_vram = 3;
+      submodule_index++;
+    }
+    break;
+  }
+
+}
+
+void Intro_AnimOneObj(int k) {  // 8cc534
+  switch (intro_sprite_isinited[k]) {
+  case 0:
+    break;
+  case 1:
+    switch (intro_sprite_subtype[k]) {
+    case 0: Intro_SpriteType_A_0(k); break;
+    case 1: EXIT_0CCA90(k); break;
+    case 2: InitializeSceneSprite_Copyright(k); break;
+    case 3: InitializeSceneSprite_Sparkle(k); break;
+    case 4:
+    case 5:
+    case 6: InitializeSceneSprite_TriforceRoomTriangle(k); break;
+    case 7: InitializeSceneSprite_CreditsTriangle(k); break;
+    }
+    break;
+  case 2:
+    switch (intro_sprite_subtype[k]) {
+    case 0: Intro_SpriteType_B_0(k); break;
+    case 1: EXIT_0CCA90(k); break;
+    case 2: AnimateSceneSprite_Copyright(k); break;
+    case 3: AnimateSceneSprite_Sparkle(k); break;
+    case 4:
+    case 5:
+    case 6: Intro_SpriteType_B_456(k); break;
+    case 7: AnimateSceneSprite_CreditsTriangle(k); break;
+    }
+    break;
+  }
+}
+
+void Intro_SpriteType_A_0(int k) {  // 8cc57e
+  static const int16 kIntroSprite0_X[3] = { -38, 95, 230 };
+  static const int16 kIntroSprite0_Y[3] = { 200, -67, 200 };
+  intro_x_lo[k] = kIntroSprite0_X[k];
+  intro_x_hi[k] = kIntroSprite0_X[k] >> 8;
+  intro_y_lo[k] = kIntroSprite0_Y[k];
+  intro_y_hi[k] = kIntroSprite0_Y[k] >> 8;
+  intro_x_vel[k] = kIntroSprite0_Xvel[k];
+  intro_y_vel[k] = kIntroSprite0_Yvel[k];
+  intro_sprite_isinited[k]++;
+}
+
+void Intro_SpriteType_B_0(int k) {  // 8cc5b1
+  static const uint8 kIntroSprite0_XLimit[3] = { 75, 95, 117 };
+  static const uint8 kIntroSprite0_YLimit[3] = { 88, 48, 88 };
+
+  AnimateSceneSprite_DrawTriangle(k);
+  AnimateSceneSprite_MoveTriangle(k);
+  if (intro_step_index != 5) {
+    if (!(intro_frame_ctr & 31)) {
+      intro_x_vel[k] += kIntroSprite0_Xvel[k];
+      intro_y_vel[k] += kIntroSprite0_Yvel[k];
+    }
+    if (intro_x_lo[k] == kIntroSprite0_XLimit[k])
+      intro_x_vel[k] = 0;
+    if (intro_y_lo[k] == kIntroSprite0_YLimit[k])
+      intro_y_vel[k] = 0;
+  } else {
+    intro_x_vel[k] = 0;
+    intro_y_vel[k] = 0;
+  }
+}
+
+void AnimateSceneSprite_DrawTriangle(int k) {  // 8cc70f
+  static const IntroSpriteEnt kIntroSprite0_Left_Ents[16] = {
+    { 0,  0, 0x80, 0x1b, 2},
+    {16,  0, 0x82, 0x1b, 2},
+    {32,  0, 0x84, 0x1b, 2},
+    {48,  0, 0x86, 0x1b, 2},
+    { 0, 16, 0xa0, 0x1b, 2},
+    {16, 16, 0xa2, 0x1b, 2},
+    {32, 16, 0xa4, 0x1b, 2},
+    {48, 16, 0xa6, 0x1b, 2},
+    { 0, 32, 0x88, 0x1b, 2},
+    {16, 32, 0x8a, 0x1b, 2},
+    {32, 32, 0x8c, 0x1b, 2},
+    {48, 32, 0x8e, 0x1b, 2},
+    { 0, 48, 0xa8, 0x1b, 2},
+    {16, 48, 0xaa, 0x1b, 2},
+    {32, 48, 0xac, 0x1b, 2},
+    {48, 48, 0xae, 0x1b, 2},
+  };
+  static const IntroSpriteEnt kIntroSprite0_Right_Ents[16] = {
+    {48,  0, 0x80, 0x5b, 2},
+    {32,  0, 0x82, 0x5b, 2},
+    {16,  0, 0x84, 0x5b, 2},
+    { 0,  0, 0x86, 0x5b, 2},
+    {48, 16, 0xa0, 0x5b, 2},
+    {32, 16, 0xa2, 0x5b, 2},
+    {16, 16, 0xa4, 0x5b, 2},
+    { 0, 16, 0xa6, 0x5b, 2},
+    {48, 32, 0x88, 0x5b, 2},
+    {32, 32, 0x8a, 0x5b, 2},
+    {16, 32, 0x8c, 0x5b, 2},
+    { 0, 32, 0x8e, 0x5b, 2},
+    {48, 48, 0xa8, 0x5b, 2},
+    {32, 48, 0xaa, 0x5b, 2},
+    {16, 48, 0xac, 0x5b, 2},
+    { 0, 48, 0xae, 0x5b, 2},
+  };
+  AnimateSceneSprite_AddObjectsToOamBuffer(k, k == 2 ? kIntroSprite0_Right_Ents : kIntroSprite0_Left_Ents, 16);
+}
+
+void Intro_CopySpriteType4ToOam(int k) {  // 8cc82f
+  static const IntroSpriteEnt kIntroTriforceOam_Left[16] = {
+    { 0,  0, 0x80, 0x2b, 2},
+    {16,  0, 0x82, 0x2b, 2},
+    {32,  0, 0x84, 0x2b, 2},
+    {48,  0, 0x86, 0x2b, 2},
+    { 0, 16, 0xa0, 0x2b, 2},
+    {16, 16, 0xa2, 0x2b, 2},
+    {32, 16, 0xa4, 0x2b, 2},
+    {48, 16, 0xa6, 0x2b, 2},
+    { 0, 32, 0x88, 0x2b, 2},
+    {16, 32, 0x8a, 0x2b, 2},
+    {32, 32, 0x8c, 0x2b, 2},
+    {48, 32, 0x8e, 0x2b, 2},
+    { 0, 48, 0xa8, 0x2b, 2},
+    {16, 48, 0xaa, 0x2b, 2},
+    {32, 48, 0xac, 0x2b, 2},
+    {48, 48, 0xae, 0x2b, 2},
+  };
+  static const IntroSpriteEnt kIntroTriforceOam_Right[16] = {
+    {48,  0, 0x80, 0x6b, 2},
+    {32,  0, 0x82, 0x6b, 2},
+    {16,  0, 0x84, 0x6b, 2},
+    { 0,  0, 0x86, 0x6b, 2},
+    {48, 16, 0xa0, 0x6b, 2},
+    {32, 16, 0xa2, 0x6b, 2},
+    {16, 16, 0xa4, 0x6b, 2},
+    { 0, 16, 0xa6, 0x6b, 2},
+    {48, 32, 0x88, 0x6b, 2},
+    {32, 32, 0x8a, 0x6b, 2},
+    {16, 32, 0x8c, 0x6b, 2},
+    { 0, 32, 0x8e, 0x6b, 2},
+    {48, 48, 0xa8, 0x6b, 2},
+    {32, 48, 0xaa, 0x6b, 2},
+    {16, 48, 0xac, 0x6b, 2},
+    { 0, 48, 0xae, 0x6b, 2},
+  };
+  AnimateSceneSprite_AddObjectsToOamBuffer(k, k == 2 ? kIntroTriforceOam_Right : kIntroTriforceOam_Left, 16);
+}
+
+void EXIT_0CCA90(int k) {  // 8cc84f
+  // empty
+}
+
+void InitializeSceneSprite_Copyright(int k) {  // 8cc850
+  intro_x_lo[k] = 76;
+  intro_x_hi[k] = 0;
+  intro_y_lo[k] = 184;
+  intro_y_hi[k] = 0;
+  intro_sprite_isinited[k]++;
+}
+
+void AnimateSceneSprite_Copyright(int k) {  // 8cc864
+  static const IntroSpriteEnt kIntroSprite2_Ents[13] = {
+    { 0, 0, 0x40, 0x0a, 0},
+    { 8, 0, 0x41, 0x0a, 0},
+    {16, 0, 0x42, 0x0a, 0},
+    {24, 0, 0x68, 0x0a, 0},
+    {32, 0, 0x41, 0x0a, 0},
+    {40, 0, 0x42, 0x0a, 0},
+    {48, 0, 0x43, 0x0a, 0},
+    {56, 0, 0x44, 0x0a, 0},
+    {64, 0, 0x50, 0x0a, 0},
+    {72, 0, 0x51, 0x0a, 0},
+    {80, 0, 0x52, 0x0a, 0},
+    {88, 0, 0x53, 0x0a, 0},
+    {96, 0, 0x54, 0x0a, 0},
+  };
+  AnimateSceneSprite_AddObjectsToOamBuffer(k, kIntroSprite2_Ents, 13);
+}
+
+void InitializeSceneSprite_Sparkle(int k) {  // 8cc8e2
+  int j = intro_frame_ctr >> 5 & 3;
+  intro_x_lo[k] = kIntroSprite3_X[j];
+  intro_x_hi[k] = 0;
+  intro_y_lo[k] = kIntroSprite3_Y[j];
+  intro_y_hi[k] = 0;
+  intro_sprite_isinited[k]++;
+}
+
+void AnimateSceneSprite_Sparkle(int k) {  // 8cc90d
+  static const IntroSpriteEnt kIntroSprite3_Ents[4] = {
+    { 0,  0, 0x80, 0x34, 0},
+    { 0,  0, 0xb7, 0x34, 0},
+    {-4, -3, 0x64, 0x38, 2},
+    {-4, -3, 0x62, 0x34, 2},
+  };
+  if (intro_sprite_state[k] < 4)
+    AnimateSceneSprite_AddObjectsToOamBuffer(k, kIntroSprite3_Ents + intro_sprite_state[k], 1);
+
+  intro_sprite_state[k] = kIntroSprite3_State[intro_frame_ctr >> 2 & 7];
+  int j = intro_frame_ctr >> 5 & 3;
+  intro_x_lo[k] = kIntroSprite3_X[j];
+  intro_y_lo[k] = kIntroSprite3_Y[j];
+}
+
+void AnimateSceneSprite_AddObjectsToOamBuffer(int k, const IntroSpriteEnt *src, int num) {  // 8cc972
+  uint16 x = intro_x_hi[k] << 8 | intro_x_lo[k];
+  uint16 y = intro_y_hi[k] << 8 | intro_y_lo[k];
+  OamEnt *oam = (OamEnt *)&g_ram[intro_sprite_alloc];
+  intro_sprite_alloc += num * 4;
+  do {
+    SetOamHelper0(oam, x + src->x, y + src->y, src->charnum, src->flags, src->ext);
+  } while (oam++, src++, --num);
+}
+
+void AnimateSceneSprite_MoveTriangle(int k) {  // 8cc9f1
+  if (intro_x_vel[k] != 0) {
+    uint32 t = intro_x_subpixel[k] + (intro_x_lo[k] << 8) + (intro_x_hi[k] << 16) + ((int8)intro_x_vel[k] << 4);
+    intro_x_subpixel[k] = t, intro_x_lo[k] = t >> 8, intro_x_hi[k] = t >> 16;
+  }
+  if (intro_y_vel[k] != 0) {
+    uint32 t = intro_y_subpixel[k] + (intro_y_lo[k] << 8) + (intro_y_hi[k] << 16) + ((int8)intro_y_vel[k] << 4);
+    intro_y_subpixel[k] = t, intro_y_lo[k] = t >> 8, intro_y_hi[k] = t >> 16;
+  }
+}
+
+void TriforceRoom_PrepGFXSlotForPoly() {  // 8cca54
+  misc_sprites_graphics_index = 8;
+  LoadCommonSprites();
+  Intro_InitGfx_Helper();
+  intro_sprite_isinited[0] = 1;
+  intro_sprite_isinited[1] = 1;
+  intro_sprite_isinited[2] = 1;
+  intro_sprite_subtype[0] = 4;
+  intro_sprite_subtype[1] = 5;
+  intro_sprite_subtype[2] = 6;
+  INIDISP_copy = 15;
+  submodule_index++;
+}
+
+void Credits_InitializePolyhedral() {  // 8cca81
+  misc_sprites_graphics_index = 8;
+  LoadCommonSprites();
+  Intro_InitGfx_Helper();
+  poly_config1 = 0;
+  intro_sprite_isinited[0] = 1;
+  intro_sprite_isinited[1] = 1;
+  intro_sprite_isinited[2] = 1;
+  intro_sprite_subtype[0] = 7;
+  intro_sprite_subtype[1] = 7;
+  intro_sprite_subtype[2] = 7;
+  INIDISP_copy = 15;
+  submodule_index++;
+}
+
+void AdvancePolyhedral() {  // 8ccab1
+  TriforceRoom_HandlePoly();
+  Scene_AnimateEverySprite();
+}
+
+void TriforceRoom_HandlePoly() {  // 8ccabc
+  is_nmi_thread_active = 1;
+  intro_want_double_ret = 1;
+  if (intro_did_run_step)
+    return;
+  switch (intro_step_index) {
+  case 0:
+    poly_config1 -= 2;
+    if (poly_config1 < 2) {
+      poly_config1 = 0;
+      intro_step_index++;
+      subsubmodule_index++;
+    }
+    // fall through
+  case 1:
+    if (subsubmodule_index >= 10) {
+      intro_step_index++;
+      intro_y_vel[1] = 5;
+    }
+    poly_b += 2, poly_a += 1;
+    break;
+  case 2:
+    triforce_ctr = 0x1c0;
+    if (poly_config1 < 128) {
+      poly_config1 += 1;
+    } else {
+      if ((poly_b - 10 & 0x7f) >= 92 &&
+          (uint8)(poly_a - 11) >= 220) {
+        poly_a = 0;
+        poly_b = 0;
+        subsubmodule_index++;
+        intro_step_index++;
+        sound_effect_1 = 44;
+        main_palette_buffer[0xd7] = 0x7fff;
+        flag_update_cgram_in_nmi++;
+        intro_step_timer = 6;
+        break;
+      }
+    }
+    poly_b += 5, poly_a += 3;
+    break;
+  case 3:
+    if (!--intro_step_timer) {
+      main_palette_buffer[0xd7] = kPolyhedralPalette[7];
+      flag_update_cgram_in_nmi++;
+      intro_step_index++;
+    }
+    break;
+  case 4:
+    break;
+  }
+  intro_did_run_step = 1;
+  intro_want_double_ret = 0;
+  intro_frame_ctr++;
+}
+
+void Credits_AnimateTheTriangles() {  // 8ccba2
+  intro_frame_ctr++;
+  is_nmi_thread_active = 1;
+  if (!intro_did_run_step) {
+    poly_b += 3;
+    poly_a += 1;
+    intro_did_run_step = 1;
+  }
+  Scene_AnimateEverySprite();
+}
+
+void InitializeSceneSprite_TriforceRoomTriangle(int k) {  // 8ccbe8
+  static const int16 kIntroTriforce_X[3] = { 0x4e, 0x5f, 0x72 };
+  static const int16 kIntroTriforce_Y[3] = { 0x9c, 0x9c, 0x9c };
+  static const int8 kIntroTriforce_Xvel[3] = { -2, 0, 2 };
+  static const int8 kIntroTriforce_Yvel[3] = { 4, -4, 4 };
+
+  intro_x_lo[k] = kIntroTriforce_X[k];
+  intro_x_hi[k] = 0;
+  intro_y_lo[k] = kIntroTriforce_Y[k];
+  intro_y_hi[k] = 0;
+  intro_x_vel[k] = kIntroTriforce_Xvel[k];
+  intro_y_vel[k] = kIntroTriforce_Yvel[k];
+  intro_sprite_isinited[k]++;
+}
+
+void Intro_SpriteType_B_456(int k) {  // 8ccc13
+  static const int8 kTriforce_Xacc[3] = { -1, 0, 1 };
+  static const int8 kTriforce_Yacc[3] = { -1, -1, -1 };
+  static const uint8 kTriforce_Yfinal2[3] = { 0x72, 0x66, 0x72 };
+
+  Intro_CopySpriteType4ToOam(k);
+  if (intro_want_double_ret)
+    return;
+  AnimateSceneSprite_MoveTriangle(k);
+  switch (intro_step_index) {
+  case 0:
+    if (!(intro_frame_ctr & 7))
+      intro_x_vel[k] += kTriforce_Xacc[k];
+    if (!(intro_frame_ctr & 3))
+      intro_y_vel[k] += kTriforce_Yacc[k];
+    break;
+  case 1:
+    intro_x_vel[k] = 0;
+    intro_y_vel[k] = 0;
+    break;
+  case 2:
+    if (!(intro_frame_ctr & 3))
+      AnimateTriforceRoomTriangle_HandleContracting(k);
+    if (kTriforce_Xfinal[k] == intro_x_lo[k])
+      intro_x_vel[k] = 0;
+    if (kTriforce_Yfinal[k] == intro_y_lo[k])
+      intro_y_vel[k] = 0;
+    break;
+  case 3:
+  case 4:
+    if (triforce_ctr == 0) {
+      intro_y_lo[k] = kTriforce_Yfinal2[k];
+    } else {
+      triforce_ctr -= 1;
+    }
+    break;
+  }
+}
+
+void AnimateTriforceRoomTriangle_HandleContracting(int k) {  // 8cccb0
+  uint8 new_vel = intro_x_vel[k] + (intro_x_lo[k] <= kTriforce_Xfinal[k] ? 1 : -1);
+  intro_x_vel[k] = (new_vel == 0x11) ? 0x10 : (new_vel == 0xef) ? 0xf0 : new_vel;
+  new_vel = intro_y_vel[k] + (intro_y_lo[k] <= kTriforce_Yfinal[k] ? 1 : -1);
+  intro_y_vel[k] = (new_vel == 0x11) ? 0x10 : (new_vel == 0xef) ? 0xf0 : new_vel;
+}
+
+void InitializeSceneSprite_CreditsTriangle(int k) {  // 8ccd19
+  static const uint8 kIntroSprite7_X[3] = { 0x29, 0x5f, 0x97 };
+  static const uint8 kIntroSprite7_Y[3] = { 0x70, 0x20, 0x70 };
+  intro_x_lo[k] = kIntroSprite7_X[k];
+  intro_x_hi[k] = 0;
+  intro_y_lo[k] = kIntroSprite7_Y[k];
+  intro_y_hi[k] = 0;
+  intro_sprite_isinited[k]++;
+}
+
+void AnimateSceneSprite_CreditsTriangle(int k) {  // 8ccd3e
+  static const int8 kIntroSprite7_XAcc[3] = { -1, 0, 1 };
+  static const int8 kIntroSprite7_YAcc[3] = { 1, -1, 1 };
+
+  LoadTriforceSpritePalette();
+  Intro_CopySpriteType4ToOam(k);
+  AnimateSceneSprite_MoveTriangle(k);
+  if (submodule_index != 36) {
+    intro_sprite_state[k] = 0;
+    return;
+  }
+  if (intro_sprite_state[k] != 80) {
+    intro_sprite_state[k]++;
+    intro_x_vel[k] += kIntroSprite7_XAcc[k];
+    intro_y_vel[k] += kIntroSprite7_YAcc[k];
+  }
+}
+
+void Intro_DisplayLogo() {  // 8ced82
+  static const uint8 kIntroLogo_X[4] = { 0x60, 0x70, 0x80, 0x88 };
+  static const uint8 kIntroLogo_Tile[4] = { 0x69, 0x6b, 0x6d, 0x6e };
+  for (int i = 0; i < 4; i++)
+    SetOamPlain(&oam_buf[i], kIntroLogo_X[i], 0x68, kIntroLogo_Tile[i], 0x32, 2);
+}
+
+void Intro_SetupSwordAndIntroFlash() {  // 8cfe45
+  intro_sword_19 = 7;
+  intro_sword_20 = 0;
+  intro_sword_21 = 0;
+  intro_sword_ypos = -130;
+
+  Intro_PeriodicSwordAndIntroFlash();
+}
+
+void Intro_PeriodicSwordAndIntroFlash() {  // 8cfe56
+  if (intro_sword_18)
+    intro_sword_18--;
+  SetBackdropcolorBlack();
+  if (intro_times_pal_flash) {
+    if ((intro_times_pal_flash & 3) != 0) {
+      (&COLDATA_copy0)[intro_sword_24] |= (enhanced_features0 & kFeatures0_DimFlashes) ? 0x05 : 0x1f;
+      intro_sword_24 = (intro_sword_24 == 2) ? 0 : intro_sword_24 + 1;
+    }
+    intro_times_pal_flash--;
+  }
+  OamEnt *oam = oam_buf + 0x52;
+  for (int j = 9; j >= 0; j--) {
+    static const uint8 kIntroSword_Char[10] = { 0, 2, 0x20, 0x22, 4, 6, 8, 0xa, 0xc, 0xe };
+    static const uint8 kIntroSword_X[10] = { 0x40, 0x40, 0x30, 0x50, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40 };
+    static const uint16 kIntroSword_Y[10] = { 0x10, 0x20, 0x28, 0x28, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80 };
+    uint16 y = intro_sword_ypos + kIntroSword_Y[j];
+    SetOamPlain(&oam[j], kIntroSword_X[j], ((y & 0xff00) ? 0xf8 : y) - 8, kIntroSword_Char[j], 0x21, 2);
+  }
+
+  if (intro_sword_ypos != 30) {
+    if (intro_sword_ypos == 0xffbe) {
+      sound_effect_1 = 1;
+    } else if (intro_sword_ypos == 14) {
+      WORD(intro_sword_24) = 0;
+      intro_times_pal_flash = 0x20;
+      sound_effect_1 = 0x2c;
+    }
+    intro_sword_ypos += 16;
+  }
+
+  switch (intro_sword_20 >> 1) {
+  case 0:
+    if (!intro_times_pal_flash && intro_sword_ypos == 30)
+      intro_sword_20 += 2;
+    break;
+  case 1: {
+    static const uint8 kSwordSparkle_Tab[8] = { 4, 4, 6, 6, 6, 4, 4 };
+
+    if (!intro_sword_18) {
+      intro_sword_19 -= 1;
+      if (sign8(intro_sword_19)) {
+        intro_sword_19 = 0;
+        intro_sword_18 = 2;
+        intro_sword_20 += 2;
+        return;
+      }
+      intro_sword_18 = kSwordSparkle_Tab[intro_sword_19];
+    }
+    static const uint8 kSwordSparkle_Char[7] = { 0x28, 0x37, 0x27, 0x36, 0x27, 0x37, 0x28 };
+    SetOamPlain(&oam_buf[0x50], 0x44, 0x43, kSwordSparkle_Char[intro_sword_19], 0x25, 0);
+    break;
+  }
+  case 2: {
+    static const uint8 kIntroSwordSparkle_Char[8] = { 0x26, 0x20, 0x24, 0x34, 0x25, 0x20, 0x35, 0x20 };
+    int k = intro_sword_19;
+    if (k >= 7)
+      return;
+    uint8 y = (intro_sword_21 < 0x50 ? intro_sword_21 : 0x4f) + intro_sword_ypos + 0x31;
+    SetOamPlain(&oam_buf[0x50], 0x42, y + 0, kIntroSwordSparkle_Char[k + 0], 0x23, 0);
+    SetOamPlain(&oam_buf[0x51], 0x42, y + 8, kIntroSwordSparkle_Char[k + 1], 0x23, 0);
+    if (intro_sword_18 == 0) {
+      intro_sword_21 += 4;
+      if (intro_sword_21 == 0x4 || intro_sword_21 == 0x48 || intro_sword_21 == 0x4c || intro_sword_21 == 0x58)
+        intro_sword_19 += 2;
+    }
+    break;
+  }
+  }
+}
+
+void Module1A_Credits() {  // 8e986e
+  oam_region_base[0] = 0x30;
+  oam_region_base[1] = 0x1d0;
+  oam_region_base[2] = 0x0;
+
+  kEndSequence_Funcs[submodule_index]();
+}
+
+void Credits_LoadNextScene_Overworld() {  // 8e9889
+  kEndSequence0_Funcs[subsubmodule_index]();
+  Credits_AddEndingSequenceText();
+}
+
+void Credits_LoadNextScene_Dungeon() {  // 8e9891
+  Credits_LoadScene_Dungeon();
+  Credits_AddEndingSequenceText();
+}
+
+void Credits_PrepAndLoadSprites() {  // 8e98b9
+  for (int k = 15; k >= 0; k--) {
+    SpritePrep_ResetProperties(k);
+    sprite_state[k] = 0;
+    sprite_flags5[k] = 0;
+    sprite_defl_bits[k] = 0;
+  }
+  int k = submodule_index >> 1;
+  switch (k) {
+init_sprites_0:
+  case 0: case 4: case 5: case 8: case 13: {
+    int idx = kEndingSprites_Idx[k];
+    int num = kEndingSprites_Idx[k + 1] - idx;
+    const uint16 *px = kEndingSprites_X + idx;
+    const uint16 *py = kEndingSprites_Y + idx;
+    for (k = num - 1; k >= 0; k--) {
+      sprcoll_x_size = sprcoll_y_size = 0xffff;
+      uint16 x = (swap16(overworld_area_index << 1) & 0xf00) + px[k];
+      uint16 y = (swap16(overworld_area_index >> 2) & 0xe00) + py[k];
+      Sprite_SetX(k, x);
+      Sprite_SetY(k, y);
+    }
+    break;
+  }
+init_sprites_1:
+  case 1: {
+    int idx = kEndingSprites_Idx[k];
+    int num = kEndingSprites_Idx[k + 1] - idx;
+    const uint16 *px = kEndingSprites_X + idx;
+    const uint16 *py = kEndingSprites_Y + idx;
+    byte_7E0FB1 = dungeon_room_index2 >> 3 & 254;
+    byte_7E0FB0 = (dungeon_room_index2 & 15) << 1;
+    for (k = num - 1; k >= 0; k--) {
+      sprcoll_x_size = sprcoll_y_size = 0xffff;
+      uint16 x = byte_7E0FB0 * 256 + px[k];
+      uint16 y = byte_7E0FB1 * 256 + py[k];
+      Sprite_SetX(k, x);
+      Sprite_SetY(k, y);
+    }
+    break;
+  }
+  case 2:
+    sprite_y_vel[6] = -16;
+    goto init_sprites_0;
+  case 3:
+    sprite_A[5] = 22;
+    sprite_y_vel[0] = -16;
+    sprite_y_vel[1] = 16;
+    sprite_head_dir[1] = 1;
+    for (int j = 2; j >= 0; j--) {
+      sprite_type[2 + j] = 0x57;
+      sprite_oam_flags[2 + j] = 0x31;
+    }
+    goto init_sprites_0;
+  case 6:
+    sprite_delay_main[0] = 255;
+    sprite_delay_main[1] = 255;
+    sprite_delay_main[2] = 255;
+    goto init_sprites_0;
+  case 7:
+    sprite_delay_main[1] = 255;
+    goto init_sprites_0;
+  case 9:
+    for (int j = 4; j >= 0; j--) {
+      sprite_delay_main[j] = j * 19;
+      sprite_state[j] = 0;
+    }
+    sprite_type[5] = 0x2e;
+    for (int j = 1; j >= 0; j--) {
+      sprite_type[7 + j] = 0x9f;
+      sprite_type[9 + j] = 0xa0;
+      sprite_flags2[7 + j] = 1;
+      sprite_flags2[9 + j] = 2;
+      sprite_flags3[7 + j] = 0x10;
+      sprite_flags3[9 + j] = 0x10;
+    }
+    goto init_sprites_0;
+  case 10:
+    sprite_delay_main[1] = 0x10;
+    sprite_delay_main[2] = 0x20;
+    sprite_oam_flags[3] = 8;
+    sprite_oam_flags[4] = 8;
+    goto init_sprites_1;
+  case 11:
+    sprite_oam_flags[4] = 0x79;
+    sprite_oam_flags[5] = 0x39;
+    sprite_D[1] = 1;
+    sprite_A[1] = 4;
+    goto init_sprites_1;
+  case 12:
+    for (int j = 1; j >= 0; j--) {
+      sprite_oam_flags[j + 3] = 0x39;
+      sprite_type[j + 3] = 0xb;
+      sprite_flags3[j + 3] = 0x10;
+      sprite_flags2[j + 3] = 1;
+    }
+    sprite_type[5] = 0x2a;
+    sprite_type[6] = 0x79;
+    sprite_ai_state[6] = 1;
+    sprite_z[6] = 5;
+    goto init_sprites_0;
+  case 14:
+    sprite_y_vel[5] = -16;
+    sprite_y_vel[6] = 16;
+    sprite_head_dir[6] = 1;
+    sprite_A[0] = 8;
+    for (int j = 3; j >= 0; j--)
+      sprite_y_vel[1 + j] = 4;
+    goto init_sprites_0;
+  case 15:
+    sprite_C[4] = 2;
+    sprite_y_vel[5] = 8;
+    sprite_delay_main[1] = 0x13;
+    sprite_delay_main[4] = 0x40;
+    goto init_sprites_0;
+  }
+}
+
+void Credits_ScrollScene_Overworld() {  // 8e9958
+
+  for (int k = 15; k >= 0; k--)
+    if (sprite_delay_main[k])
+      sprite_delay_main[k]--;
+
+  int i = submodule_index >> 1;
+
+  link_x_vel = link_y_vel = 0;
+  if (R16 >= 0x40 && !(R16 & 1)) {
+    if (BG2VOFS_copy2 != kEnding1_TargetScrollY[i])
+      link_y_vel = kEnding1_Yvel[i];
+    if (BG2HOFS_copy2 != kEnding1_TargetScrollX[i])
+      link_x_vel = kEnding1_Xvel[i];
+  }
+
+  Credits_OperateScrollingAndTileMap();
+  Credits_HandleSceneFade();
+}
+
+void Credits_ScrollScene_Dungeon() {  // 8e99c5
+  for (int k = 15; k >= 0; k--)
+    if (sprite_delay_main[k])
+      sprite_delay_main[k]--;
+
+  int i = submodule_index >> 1;
+  if (R16 >= 0x40 && !(R16 & 1)) {
+    if (BG2VOFS_copy2 != kEnding1_TargetScrollY[i])
+      BG2VOFS_copy2 += kEnding1_Yvel[i];
+    if (BG2HOFS_copy2 != kEnding1_TargetScrollX[i])
+      BG2HOFS_copy2 += kEnding1_Xvel[i];
+  }
+  Credits_HandleSceneFade();
+}
+
+void Credits_HandleSceneFade() {  // 8e9a2a
+  static const uint16 kEnding1_3_Tab0[16] = { 0x300, 0x280, 0x250, 0x2e0, 0x280, 0x250, 0x2c0, 0x2c0, 0x250, 0x250, 0x280, 0x250, 0x480, 0x400, 0x250, 0x500 };
+  static const uint8 kEndSequence_Case0_Tab1[12] = { 0x1e, 0x20, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x16, 0x16, 0x16, 0x16 };
+  static const uint8 kEndSequence_Case0_Tab0[12] = { 6, 3, 2, 2, 2, 2, 2, 2, 6, 6, 6, 6 };
+  static const uint8 kEndSequence_Case0_OamFlags[12] = { 0x3b, 0x31, 0x3d, 0x3f, 0x39, 0x3b, 0x37, 0x3d, 0x39, 0x37, 0x37, 0x39 };
+  int i = submodule_index >> 1, j, k;
+
+  switch (i) {
+  case 0:
+    for (int k = 11; k != 7; k--) {
+      sprite_oam_flags[k] = kEndSequence_Case0_OamFlags[k];
+      Credits_SpriteDraw_Single(k, kEndSequence_Case0_Tab0[k], kEndSequence_Case0_Tab1[k]);
+    }
+    for (int k = 7; k != 1; k--) {
+      sprite_oam_flags[k] = kEndSequence_Case0_OamFlags[k] | (frame_counter << 2 & 0x40);
+      Credits_SpriteDraw_Single(k, kEndSequence_Case0_Tab0[k], kEndSequence_Case0_Tab1[k]);
+    }
+    for (int k = 1; k >= 0; k--) {
+      sprite_oam_flags[k] = kEndSequence_Case0_OamFlags[k];
+      Credits_SpriteDraw_Single(k, kEndSequence_Case0_Tab0[k], kEndSequence_Case0_Tab1[k]);
+    }
+    break;
+  case 1:
+    Credits_SpriteDraw_Single(0, 3, 12);
+    Credits_SpriteDraw_DrawShadow(0);
+    k = 1;
+    sprite_type[k] = 0x73;
+    sprite_oam_flags[k] = 0x27;
+    sprite_E[k] = 2;
+    Credits_SpriteDraw_PreexistingSpriteDraw(k, 16);
+    break;
+  case 2: {
+    static const uint8 kEnding_Case2_Tab0[2] = { 0x20, 0x40 };
+    static const int8 kEnding_Case2_Tab1[2] = { 16, -16 };
+    static const int8 kEnding_Case2_Tab2[5] = { 0x28, 0x2a, 0x2c, 0x2e, 0x2c };
+    static const int8 kEnding_Case2_Tab3[5] = { 3, 3, 3, 3, 3 };
+    static const uint8 kEnding_Case2_Delay[2] = { 0x30, 0x10 };
+
+    BYTE(flag_travel_bird) = kEnding_Case2_Tab0[frame_counter >> 2 & 1];
+    k = 6;
+    j = sprite_x_vel[k] >> 7 & 1;
+    sprite_oam_flags[k] = (sprite_x_vel[k] + kEnding_Case2_Tab1[j]) >> 1 & 0x40 | 0x32;
+    Credits_SpriteDraw_Single(k, 2, 0x24);
+    Credits_SpriteDraw_CirclingBirds(k);
+    k -= 1;
+    sprite_oam_flags[k] = 0x31;
+    if (!sprite_delay_main[k]) {
+      j = sprite_A[k];
+      sprite_A[k] ^= 1;
+      sprite_delay_main[k] = kEnding_Case2_Delay[j];
+      sprite_graphics[k] = sprite_graphics[k] + 1 & 3;
+    }
+    Credits_SpriteDraw_Single(k, 2, 0x26);
+    k -= 1;
+    do {
+      if (!(frame_counter & 15))
+        sprite_graphics[k] ^= 1;
+      sprite_oam_flags[k] = 0x31;
+      Credits_SpriteDraw_Single(k, kEnding_Case2_Tab3[k], kEnding_Case2_Tab2[k]);
+      EndSequence_DrawShadow2(k);
+    } while (--k >= 0);
+    break;
+  }
+  case 3: {
+    static const uint8 kEnding_Case3_Gfx[4] = { 1, 2, 3, 2 };
+    for (k = 0; k < 5; k++) {
+      if (k < 2) {
+        sprite_type[k] = 1;
+        sprite_oam_flags[k] = 0xb;
+        Credits_SpriteDraw_SetShadowProp(k, 2);
+        sprite_z[k] = 48;
+        j = (frame_counter + (k ? 0x5f : 0x7d)) >> 2 & 3;
+        sprite_graphics[k] = kEnding_Case3_Gfx[j];
+        Credits_SpriteDraw_CirclingBirds(k);
+        Credits_SpriteDraw_PreexistingSpriteDraw(k, 12);
+      } else {
+        Credits_SpriteDraw_PreexistingSpriteDraw(k, 16);
+      }
+    }
+    Credits_SpriteDraw_Single(k, 2, 0x38);
+    Ending_Func2(k, 0x30);
+    k++;
+    Credits_SpriteDraw_Single(k, 3, 0x3a);
+    break;
+  }
+  case 4: {
+    static const uint8 kEnding_Case4_Tab1[2] = { 0x30, 0x32 };
+    static const uint8 kEnding_Case4_Tab0[2] = { 2, 2 };
+    static const uint8 kEnding_Case4_Ctr[2] = { 0x20, 0 };
+    static const int8 kEnding_Case4_XYvel[10] = { 0, -12, -16, -12, 0, 12, 16, 12, 0, -12 };
+    static const uint8 kEnding_Case4_DelayVel[24] = {
+      0x3b, 0x14, 0x1e, 0x1d, 0x2c, 0x2b, 0x42, 0x20, 0x27, 0x28, 0x2e, 0x38, 0x3a, 0x4c, 0x32, 0x44,
+      0x2e, 0x2f, 0x1e, 0x28, 0x47, 0x35, 0x32, 0x30,
+    };
+    k = 2;
+    sprite_oam_flags[k] = 0x35;
+    Credits_SpriteDraw_Single(k, 1, 0x3c);
+    k--;
+    do {
+      sprite_oam_flags[k] = (sprite_x_vel[k] - 1) >> 1 & 0x40 ^ 0x71;
+      sprite_graphics[k] = frame_counter >> 3 & 1;
+      if (R16 >= kEnding_Case4_Ctr[k] && !sprite_delay_main[k]) {
+        uint8 a = kEnding_Case4_DelayVel[sprite_A[k]];
+        sprite_delay_main[k] = a & 0xf8;
+        sprite_y_vel[k] = kEnding_Case4_XYvel[(a & 7) + 2];
+        sprite_x_vel[k] = kEnding_Case4_XYvel[a & 7];
+        sprite_A[k]++;
+      }
+      Credits_SpriteDraw_Single(k, kEnding_Case4_Tab0[k], kEnding_Case4_Tab1[k]);
+      EndSequence_DrawShadow2(k);
+      Sprite_MoveXY(k);
+    } while (--k >= 0);
+    break;
+  }
+  case 5: {
+    static const uint8 kEnding_Case5_Tab0[2] = { 0, 4 };
+    static const uint16 kEnding_Case5_Tab1[2] = { 0xa, 0x224 };
+    static const uint8 kEnding_Case5_Tab2[2] = { 10, 14 };
+    if (R16 == 0x200)
+      sound_effect_1 = 1;
+    else if (R16 == 0x208)
+      sound_effect_1 = 0x2c;
+    if ((uint16)(R16 - 0x208) < 0x30)
+      Credits_SpriteDraw_AddSparkle(2, 10, R16 - 0x208); // wtf x,y
+    k = 3;
+    if (R16 >= 0x200)
+      sprite_graphics[k] = 1;
+    sprite_oam_flags[k] = 0x31;
+    Credits_SpriteDraw_Single(k, 4, 8);
+    EndSequence_DrawShadow2(k);
+    int j = sprite_graphics[k];
+    sprite_graphics[--k] = j;
+    link_dma_var3 = 0;
+    link_dma_var4 = kEnding_Case5_Tab0[j];
+    sprite_oam_flags[k] = 0x30;
+
+    link_dma_graphics_index = kEnding_Case5_Tab1[j];
+    Credits_SpriteDraw_Single(k, 5, kEnding_Case5_Tab2[j]);
+    EndSequence_DrawShadow2(k);
+    break;
+  }
+  case 6: {
+    static const uint8 kEnding_Case6_SprType[3] = { 0x52, 0x55, 0x55 };
+    static const uint8 kEnding_Case6_OamSize[3] = { 0x20, 8, 8 };
+    static const uint8 kEnding_Case6_State[3] = { 3, 1, 1 };
+    static const uint8 kEnding_Case6_Gfx[6] = { 0, 5, 5, 1, 6, 6 };
+
+    int idx = kEndingSprites_Idx[i];
+    int num = kEndingSprites_Idx[i + 1] - idx;
+
+    for (int k = num - 1; k >= 0; k--) {
+      cur_object_index = k;
+      sprite_type[k] = kEnding_Case6_SprType[k];
+      Oam_AllocateFromRegionA(kEnding_Case6_OamSize[k]);
+      sprite_ai_state[k] = kEnding_Case6_State[k];
+      j = (R16 >= 0x26f) ? k + 3 : k;
+      if (R16 == 0x26f)
+        sound_effect_2 = 0x21;
+      sprite_graphics[k] = kEnding_Case6_Gfx[j];
+      sprite_oam_flags[k] = 0x33;
+      Sprite_Get16BitCoords(k);
+      SpriteActive_Main(k);
+    }
+    break;
+  }
+  case 7:
+    k = 1;
+    Credits_SpriteDraw_SetShadowProp(k, 2);
+    sprite_type[k] = 0xe9;
+    Oam_AllocateFromRegionA(0xc);
+    sprite_oam_flags[k] = 0x37;
+    Sprite_Get16BitCoords(k);
+    if (!(frame_counter & 15))
+      sprite_graphics[k] ^= 1;
+    SpriteActive_Main(k);
+    if (R16 >= 0x180) {
+      sprite_y_vel[k] = 4;
+      if (sprite_y_lo[k] != 0x7c)
+        Sprite_MoveXY(k);
+    }
+    k--;
+    sprite_type[k] = 0x36;
+    Oam_AllocateFromRegionA(0x18);
+    sprite_oam_flags[k] = 0x39;
+    Sprite_Get16BitCoords(k);
+    if (!sprite_delay_main[k]) {
+      static const int8 kEnding_Case7_Gfx[2] = { 1, -1 };
+      sprite_delay_main[k] = 4;
+      sprite_graphics[k] = sprite_graphics[k] + kEnding_Case7_Gfx[R16 >> 9 & 1] & 7;
+    }
+    SpriteActive_Main(k);
+    break;
+  case 8:
+    k = 0;
+    sprite_type[k] = 0x2c;
+    Oam_AllocateFromRegionA(0x2c);
+    sprite_oam_flags[k] = 0x3b;
+    Sprite_Get16BitCoords(k);
+    sprite_graphics[k] = R16 < 0x1c0 ? R16 >> 5 & 1 : 2;
+    SpriteActive_Main(k);
+    break;
+  case 9:
+    for (k = 0; k < 5; k++) {
+      if (!sprite_delay_main[k]) {
+        sprite_delay_main[k] = 96;
+        sprite_state[k] = 96;
+        sprite_x_vel[k] = 0;
+        sprite_x_lo[k] = 238;
+        sprite_x_hi[k] = 4;
+        sprite_y_lo[k] = 24;
+        sprite_y_hi[k] = 11;
+      }
+      if (sprite_state[k]) {
+        sprite_y_vel[k] = -8;
+        Sprite_MoveXY(k);
+        if (!(frame_counter & 1))
+          sprite_x_vel[k] += ((frame_counter >> 5) ^ k) & 1 ? -1 : 1;
+        Credits_SpriteDraw_Single(k, 1, 0x10);
+      }
+    }
+    for (;;) {
+      if (!sprite_delay_main[k]) {
+        static const uint8 kEnding_Case8_Delay1[4] = { 16, 14, 16, 18 };
+        static const uint8 kEnding_Case8_Delay2[4] = { 20, 48, 20, 20 };
+        sprite_delay_main[k] = (k == 5) ? kEnding_Case8_Delay1[sprite_A[k]] : kEnding_Case8_Delay2[sprite_A[k]];
+        sprite_A[k] = sprite_A[k] + 1 & 3;
+        sprite_graphics[k] ^= 1;
+      }
+      if (k == 5) {
+        sprite_oam_flags[k] = 0x31;
+        Credits_SpriteDraw_PreexistingSpriteDraw(k, 0x10);
+        k++;
+      } else {
+        Credits_SpriteDraw_Single(k, 2, 0x12);
+        k++;
+        break;
+      }
+    }
+    do {
+      static const uint8 kEnding_Case8_D[4] = { 0, 1, 0, 1 };
+      static const uint8 kEnding_Case8_OamFlags[4] = { 55, 55, 59, 61 };
+      static const uint8 kEnding_Case8_Tab0[4] = { 8, 8, 12, 12 };
+      sprite_oam_flags[k] = kEnding_Case8_OamFlags[k - 7];
+      sprite_D[k] = kEnding_Case8_D[k - 7];
+      Credits_SpriteDraw_ActivateAndRunSprite(k, kEnding_Case8_Tab0[k - 7]);
+    } while (++k != 11);
+    break;
+  case 10: {
+    static const uint8 kWishPond_X[8] = { 0, 4, 8, 12, 16, 20, 24, 0 };
+    static const uint8 kWishPond_Y[8] = { 0, 8, 16, 24, 32, 40, 4, 36 };
+    k = 5;
+    Sprite_Get16BitCoords(k);
+    if (!sprite_pause[k]) {
+      uint8 xb = kWishPond_X[GetRandomNumber() & 7] + cur_sprite_x;
+      uint8 yb = kWishPond_Y[GetRandomNumber() & 7] + cur_sprite_y;
+      Credits_SpriteDraw_AddSparkle(3, xb, yb);
+    }
+    for (int k = 3; k < 5; k++) {
+      if (sprite_delay_aux1[k])
+        sprite_delay_aux1[k]--;
+      sprite_type[k] = 0xe3;
+      Credits_SpriteDraw_SetShadowProp(k, 1);
+      Credits_SpriteDraw_ActivateAndRunSprite(k, 8);
+    }
+    sprite_type[k] = 0x72;
+    sprite_oam_flags[k] = 0x3b;
+    sprite_state[k] = 9;
+    sprite_B[k] = 9;
+    Credits_SpriteDraw_PreexistingSpriteDraw(k, 0x30);
+    break;
+  }
+  case 11:
+    if (R16 >= 0x170) {
+      for (int k = 4; k != 6; k++) {
+        Credits_SpriteDraw_Single(k, 1, 0x3e);
+      }
+      k = 0;
+      sprite_oam_flags[k] = 0x39;
+      if (R16 < 0x1c0) {
+        sprite_graphics[k] = 2;
+      } else if (sprite_delay_main[k] == 0) {
+        sprite_delay_main[k] = 0x20;
+        sprite_graphics[k] = (sprite_graphics[k] ^ 1) & 1;
+      }
+      Credits_SpriteDraw_Single(k, 4, 6);
+    } else {
+      static const uint8 kEnding_Case11_Gfx[16] = { 1, 1, 2, 2, 1, 1, 1, 1, 2, 2, 2, 2, 0, 0, 0, 0 };
+      for (int k = 0; k < 2; k++) {
+        sprite_type[k] = 0x1a;
+        sprite_oam_flags[k] = 0x39;
+        Credits_SpriteDraw_SetShadowProp(k, 2);
+        uint8 bak0 = main_module_index;
+        Credits_SpriteDraw_ActivateAndRunSprite(k, 0xc);
+        main_module_index = bak0;
+        if (sprite_B[k] == 15 && sprite_A[k] == 4)
+          sprite_delay_main[k + 2] = 15;
+        int j = sprite_delay_main[k + 2];
+        if (j != 0) {
+          sprite_oam_flags[k + 2] = 2;
+          sprite_graphics[k + 2] = kEnding_Case11_Gfx[j];
+          Credits_SpriteDraw_Single(k + 2, 2, 0x36);
+        }
+      }
+    }
+    break;
+  case 12:
+    k = 6;
+    sprite_graphics[k] = frame_counter & 1;
+    if (!sprite_graphics[k]) {
+      sprite_x_vel[k] += sign8(sprite_x_lo[k] - 0x80) ? 1 : -1;
+      sprite_y_vel[k] += sign8(sprite_y_lo[k] - 0xb0) ? 1 : -1;
+      Sprite_MoveXY(k);
+    }
+
+    sprite_oam_flags[k] = sprite_x_vel[k] >> 1 & 0x40 ^ 0x7e;
+    sprite_flags2[k] = 1;
+    sprite_flags3[k] = 0x30;
+    sprite_z[k] = 16;
+    Credits_SpriteDraw_PreexistingSpriteDraw(k, 8);
+    k--;
+    sprite_oam_flags[k] = 0x37;
+    Credits_SpriteDraw_SetShadowProp(k, 2);
+    Credits_SpriteDraw_ActivateAndRunSprite(k, 12);
+    k--;
+    Credits_SpriteDraw_ActivateAndRunSprite(k, 8);
+    k--;
+    Credits_SpriteDraw_ActivateAndRunSprite(k, 8);
+    k--;
+    do {
+      static const uint8 kEnding_Case12_Tab[3] = { 3, 3, 8 };
+      static const uint8 kEnding_Case12_Z[15] = { 2, 4, 5, 6, 6, 7, 7, 7, 7, 6, 6, 5, 4, 2, 0 };
+
+      Credits_SpriteDraw_Single(k, kEnding_Case12_Tab[k], k * 2);
+      if (k == 0) {
+        Ending_Func2(k, 0x30);
+      } else if (k & ~1) {
+        sprite_graphics[k] = frame_counter >> 3 & 1;
+      } else {
+        int j = frame_counter & 0x1f;
+        if (j < 0xf) {
+          sprite_z[k] = kEnding_Case12_Z[j];
+        }
+        sprite_graphics[k] = (j < 0xf) ? 1 : 0;
+        Credits_SpriteDraw_DrawShadow(k);
+      }
+    } while (--k >= 0);
+    break;
+  case 13:
+    k = 0;
+    if (R16 == 0x200)
+      sprite_x_vel[k] = -4;
+    sprite_graphics[k] = frame_counter >> 4 & 1;
+    if (sprite_x_lo[k] == 56) {
+      sprite_x_vel[k] = 0;
+      sprite_graphics[k] += 2;
+    }
+    Credits_SpriteDraw_Single(k, 3, 0x34);
+    Sprite_MoveXY(k);
+    break;
+  case 14: {
+    static const int8 kEnding_Case14_Tab1[4] = { 0, 1, 0, 2 };
+    static const int8 kEnding_Case14_Tab0[5] = { 2, 8, 32, 32, 8 };
+    for (k = 6; k; k--) {
+      if (k >= 5) {
+        sprite_type[k] = 0;
+        Credits_SpriteDraw_SetShadowProp(k, 1);
+        sprite_graphics[k] = (frame_counter + 0x4a & 8) >> 3;
+        sprite_z[k] = 32;
+        Credits_SpriteDraw_CirclingBirds(k);
+        sprite_oam_flags[k] = (sprite_x_vel[k] >> 1 & 0x40) ^ 0xf;
+        Credits_SpriteDraw_PreexistingSpriteDraw(k, 8);
+      } else {
+        sprite_type[k] = 0xd;
+        if (k == 1)
+          sprite_head_dir[k] = 0xd;
+        Credits_SpriteDraw_SetShadowProp(k, 3);
+        sprite_oam_flags[k] = 0x2b;
+        uint8 a = sprite_delay_main[k];
+        if (!a)
+          sprite_delay_main[k] = a = 0xc0;
+        a >>= 1;
+        if (a == 0) {
+          sprite_y_vel[k] = sprite_x_vel[k] = 0;
+        } else {
+          if (a < kEnding_Case14_Tab0[k] && !(frame_counter & 3) && (a = sprite_y_vel[k]) != 0) {
+            sprite_y_vel[k] = --a;
+            a -= 4;
+            if (k < 3)
+              a = -a;
+            sprite_x_vel[k] = a;
+          }
+        }
+        Sprite_MoveXY(k);
+        sprite_graphics[k] = kEnding_Case14_Tab1[frame_counter >> 3 & 3];
+        Credits_SpriteDraw_PreexistingSpriteDraw(k, 16);
+      }
+    }
+    Credits_SpriteDraw_Single(k, 3, 0x18);
+    Ending_Func2(k, 0x20);
+    break;
+  }
+  case 15: {
+    static const uint8 kEnding_Case15_X[4] = { 0x76, 0x73, 0x71, 0x78 };
+    static const uint8 kEnding_Case15_Y[4] = { 0x8b, 0x83, 0x8d, 0x85 };
+    static const uint8 kEnding_Case15_Delay[8] = { 6, 6, 6, 6, 6, 6, 10, 8 };
+    static const uint8 kEnding_Case15_OamFlags[4] = { 0x61, 0x61, 0x3b, 0x39 };
+    j = kGeneratedEndSequence15[frame_counter] & 3;
+    Credits_SpriteDraw_AddSparkle(2, kEnding_Case15_X[j], kEnding_Case15_Y[j]);
+    k = 2;
+    sprite_type[k] = 0x62;
+    sprite_oam_flags[k] = 0x39;
+    Credits_SpriteDraw_PreexistingSpriteDraw(k, 0x18);
+    for (j = 1; j >= 0; j--) {
+      k++;
+      if (sprite_delay_aux1[k])
+        sprite_delay_aux1[k]--;
+      sprite_oam_flags[k] = (sprite_x_vel[k] >> 1 & 0x40) ^ kEnding_Case15_OamFlags[j];
+      if (!sprite_delay_main[k]) {
+        sprite_delay_main[k] = 128;
+        sprite_A[k] = 0;
+      }
+      if (!sprite_A[k]) {
+        sprite_graphics[k] = (frame_counter >> 2 & 1) + 2;
+        Credits_SpriteDraw_MoveSquirrel(k);
+      } else if (!sprite_delay_aux1[k]) {
+        if (sprite_B[k] == 8)
+          sprite_B[k] = 0;
+        sprite_delay_aux1[k] = kEnding_Case15_Delay[sprite_B[k] & 7];
+        sprite_graphics[k] = sprite_graphics[k] & 1 ^ 1;
+        sprite_B[k]++;
+      }
+      Credits_SpriteDraw_Single(k, 1, 20);
+      EndSequence_DrawShadow2(k);
+    }
+    Credits_SpriteDraw_WalkLinkAwayFromPedestal(k + 1);
+    break;
+  }
+  }
+
+  k = submodule_index >> 1;
+  if (R16 >= kEnding1_3_Tab0[k]) {
+    if (!(R16 & 1) && !--INIDISP_copy)
+      submodule_index++;
+    else
+      R16++;
+  } else {
+    if (!(R16 & 1) && INIDISP_copy != 15)
+      INIDISP_copy++;
+    R16++;
+  }
+  BG2HOFS_copy = BG2HOFS_copy2;
+  BG2VOFS_copy = BG2VOFS_copy2;
+  BG1HOFS_copy = BG1HOFS_copy2;
+  BG1VOFS_copy = BG1VOFS_copy2;
+}
+
+void Credits_SpriteDraw_DrawShadow(int k) {  // 8ea5f8
+  sprite_oam_flags[k] = 0x30;
+  Credits_SpriteDraw_SetShadowProp(k, 0);
+  Oam_AllocateFromRegionA(4);
+  SpriteDraw_Shadow(k, &g_ending_coords);
+}
+
+void EndSequence_DrawShadow2(int k) {  // 8ea5fd
+  Credits_SpriteDraw_SetShadowProp(k, 0);
+  Oam_AllocateFromRegionA(4);
+  SpriteDraw_Shadow(k, &g_ending_coords);
+}
+
+void Ending_Func2(int k, uint8 ain) {  // 8ea645
+  static const uint8 kEnding_Func2_Delay[27] = {
+  10, 10, 10, 10, 20, 8,   8,   0, 255, 12, 12, 12, 12, 12, 12, 30,
+   8,  4,  4,  4,  0, 0, 255, 255, 144,  4, 0,
+  };
+  static const int8 kEnding_Func2_Tab0[28] = {
+    0, 0, 1, 0, 1, 0, 2,  3,  0,  2, 0, 1, 0, 1, 0, 1,
+    2, 3, 4, 5, 6, 3, 0, -1, -1, -1, 2, 3,
+  };
+  sprite_oam_flags[k] = ain;
+  EndSequence_DrawShadow2(k);
+  int j = sprite_A[k];
+  if (!sprite_delay_main[k]) {
+    j++;
+    if (j == 8)
+      j = 6;
+    else if (j == 22)
+      j = 21;
+    else if (j == 28)
+      j = 27;
+    sprite_A[k] = j;
+    sprite_delay_main[k] = kEnding_Func2_Delay[j - 1];
+  }
+  uint8 a = kEnding_Func2_Tab0[j];
+  sprite_graphics[k] = (a == 255) ? frame_counter >> 3 & 1 : a;
+  if ((j < 5 || j >= 10 && j < 15) && !(frame_counter & 1))
+    sprite_y_lo[k]++;
+}
+
+void Credits_SpriteDraw_ActivateAndRunSprite(int k, uint8 a) {  // 8ea694
+  cur_object_index = k;
+  Oam_AllocateFromRegionA(a);
+  Sprite_Get16BitCoords(k);
+  uint8 bak0 = submodule_index;
+  submodule_index = 0;
+  sprite_state[k] = 9;
+  SpriteActive_Main(k);
+  submodule_index = bak0;
+}
+
+void Credits_SpriteDraw_PreexistingSpriteDraw(int k, uint8 a) {  // 8ea6b3
+  Oam_AllocateFromRegionA(a);
+  cur_object_index = k;
+  Sprite_Get16BitCoords(k);
+  SpriteActive_Main(k);
+}
+
+void Credits_SpriteDraw_Single(int k, uint8 a, uint8 j) {  // 8ea703
+  static const DrawMultipleData kEndSequence_Dmd0[12] = {
+    { 0, -8, 0x072a, 2},
+    { 0, -8, 0x072a, 2},
+    { 0,  0, 0x4fca, 2},
+    { 0, -8, 0x072a, 2},
+    { 0, -8, 0x072a, 2},
+    { 0,  0, 0x0fca, 2},
+    {-2,  0, 0x0f77, 0},
+    { 0, -8, 0x072a, 2},
+    { 0,  0, 0x4fca, 2},
+    {-3,  0, 0x0f66, 0},
+    { 0, -8, 0x072a, 2},
+    { 0,  0, 0x4fca, 2},
+  };
+  static const DrawMultipleData kEndSequence_Dmd1[6] = {
+    {14,  -7, 0x0d48, 2},
+    { 0,  -6, 0x0944, 2},
+    { 0,   0, 0x094e, 2},
+    {13, -14, 0x0d48, 2},
+    { 0,  -8, 0x0944, 2},
+    { 0,   0, 0x0946, 2},
+  };
+  static const DrawMultipleData kEndSequence_Dmd2[16] = {
+    {-2, -16, 0x3d78, 0},
+    { 0, -24, 0x3d24, 2},
+    { 0, -16, 0x3dc2, 2},
+    {61, -16, 0x3777, 0},
+    {64, -24, 0x37c4, 2},
+    {64, -16, 0x77ca, 2},
+    { 0,  -6, 0x326c, 2},
+    {64,  -6, 0x326c, 2},
+    {-2, -16, 0x3d68, 0},
+    { 0, -24, 0x3d24, 2},
+    { 0, -16, 0x3dc2, 2},
+    {61, -16, 0x3766, 0},
+    {64, -24, 0x37c4, 2},
+    {64, -16, 0x77ca, 2},
+    { 0,  -6, 0x326c, 2},
+    {64,  -6, 0x326c, 2},
+  };
+  static const DrawMultipleData kEndSequence_Dmd3[12] = {
+    { 0,  0, 0x0022, 2},
+    {48,  0, 0x0064, 2},
+    { 0, 10, 0x016c, 2},
+    {48, 10, 0x016c, 2},
+    { 0,  0, 0x0064, 2},
+    {48,  0, 0x0022, 2},
+    { 0, 10, 0x016c, 2},
+    {48, 10, 0x016c, 2},
+    { 0,  0, 0x0064, 2},
+    {48,  0, 0x0064, 2},
+    { 0, 10, 0x016c, 2},
+    {48, 10, 0x016c, 2},
+  };
+  static const DrawMultipleData kEndSequence_Dmd4[8] = {
+    {10,   8, 0x8a32, 0},
+    {10,  16, 0x8a22, 0},
+    { 0, -10, 0x0800, 2},
+    { 0,   0, 0x082c, 2},
+    {10, -14, 0x0a22, 0},
+    {10,  -6, 0x0a32, 0},
+    {0, -10, 0x082a, 2},
+    {0,   0, 0x0828, 2},
+  };
+  static const DrawMultipleData kEndSequence_Dmd5[10] = {
+    {10,  16, 0x8a05, 0},
+    {10,   8, 0x8a15, 0},
+    {-4,   2, 0x0a07, 2},
+    { 0,  -7, 0x0e00, 2},
+    { 0,   1, 0x0e02, 2},
+    {10, -20, 0x0a05, 0},
+    {10, -12, 0x0a15, 0},
+    {-7,   1, 0x4a07, 2},
+    { 0,  -7, 0x0e00, 2},
+    { 0,   1, 0x0e02, 2},
+  };
+  static const DrawMultipleData kEndSequence_Dmd6[3] = {
+    {-6, -2, 0x0706, 2},
+    { 0, -9, 0x090e, 2},
+    { 0, -1, 0x0908, 2},
+  };
+  static const DrawMultipleData kEndSequence_Dmd7[10] = {
+    {0, -10, 0x082a, 2},
+    {0,   0, 0x0828, 2},
+    {10,  16, 0x8a05, 0},
+    {10,   8, 0x8a15, 0},
+    {-4,   2, 0x0a07, 2},
+    { 0,  -7, 0x0e00, 2},
+    { 0,   1, 0x0e02, 2},
+    {10, -20, 0x0a05, 0},
+    {10, -12, 0x0a15, 0},
+    {-7,   1, 0x4a07, 2},
+  };
+  static const DrawMultipleData kEndSequence_Dmd8[1] = {
+    {0, -19, 0x39af, 0},
+  };
+  static const DrawMultipleData kEndSequence_Dmd9[4] = {
+    {-16, -24, 0x3704, 2},
+    {-16, -16, 0x3764, 2},
+    {-16, -24, 0x3762, 2},
+    {-16, -16, 0x3764, 2},
+  };
+  static const DrawMultipleData kEndSequence_Dmd10[4] = {
+    {0, 0, 0x0c0c, 2},
+    {0, 0, 0x0c0a, 2},
+    {0, 0, 0x0cc5, 2},
+    {0, 0, 0x0ce1, 2},
+  };
+  static const DrawMultipleData kEndSequence_Dmd11[6] = {
+    {1,  4, 0x002a, 0},
+    {1, 12, 0x003a, 0},
+    {4,  0, 0x0026, 2},
+    {0,  9, 0x0024, 2},
+    {8,  9, 0x4024, 2},
+    {4, 20, 0x016c, 2},
+  };
+  static const DrawMultipleData kEndSequence_Dmd12[21] = {
+    { 0, -7, 0x0d00, 2},
+    { 0, -7, 0x0d00, 2},
+    { 0,  0, 0x0d06, 2},
+    { 0, -7, 0x0d00, 2},
+    { 0, -7, 0x0d00, 2},
+    { 0,  0, 0x4d06, 2},
+    { 0, -8, 0x0d00, 2},
+    { 0, -8, 0x0d00, 2},
+    { 0,  0, 0x0d20, 2},
+    { 0, -8, 0x0d02, 2},
+    { 0, -8, 0x0d02, 2},
+    { 0,  0, 0x0d2c, 2},
+    {-3,  0, 0x0d2f, 0},
+    { 0, -7, 0x0d02, 2},
+    { 0,  0, 0x0d2c, 2},
+    {-5,  2, 0x0d2f, 0},
+    { 0, -8, 0x0d02, 2},
+    { 0,  0, 0x0d2c, 2},
+    {-5,  2, 0x0d3f, 0},
+    { 0, -8, 0x0d02, 2},
+    { 0,  0, 0x0d2c, 2},
+  };
+  static const DrawMultipleData kEndSequence_Dmd13[16] = {
+    {0, -7, 0x0e00, 2},
+    {0,  1, 0x4e02, 2},
+    {0, -8, 0x0e00, 2},
+    {0,  1, 0x0e02, 2},
+    {0, -9, 0x0e00, 2},
+    {0,  1, 0x0e02, 2},
+    {0, -7, 0x0e00, 2},
+    {0,  1, 0x0e02, 2},
+    {0, -7, 0x0e00, 2},
+    {0,  1, 0x4e02, 2},
+    {0, -8, 0x0e00, 2},
+    {0,  1, 0x4e02, 2},
+    {0, -9, 0x0e00, 2},
+    {0,  1, 0x4e02, 2},
+    {0, -7, 0x0e00, 2},
+    {0,  1, 0x4e02, 2},
+  };
+  static const DrawMultipleData kEndSequence_Dmd14[6] = {
+    {0, 0, 0, 0},
+    {0, 0, 0x34c7, 0},
+    {0, 0, 0x3480, 0},
+    {0, 0, 0x34b6, 0},
+    {0, 0, 0x34b7, 0},
+    {0, 0, 0x34a6, 0},
+  };
+  static const DrawMultipleData kEndSequence_Dmd15[6] = {
+    {-3, 17, 0x002b, 0},
+    {-3, 25, 0x003b, 0},
+    { 0,  0, 0x000e, 2},
+    {16,  0, 0x400e, 2},
+    { 0, 16, 0x002e, 2},
+    {16, 16, 0x402e, 2},
+  };
+  static const DrawMultipleData kEndSequence_Dmd16[3] = {
+    { 8,  5, 0x0a04, 2},
+    { 0, 16, 0x0806, 2},
+    {16, 16, 0x4806, 2},
+  };
+  static const DrawMultipleData kEndSequence_Dmd17[2] = {
+    {0,  0, 0x0000, 2},
+    {0, 11, 0x0002, 2},
+  };
+  static const DrawMultipleData kEndSequence_Dmd18[2] = {
+    {0,  0, 0x000e, 2},
+    {0, 64, 0x006c, 2},
+  };
+  static const DrawMultipleData kEndSequence_Dmd19[8] = {
+    {0, 0, 0x0882, 2},
+    {0, 7, 0x0a4e, 2},
+    {0, 0, 0x4880, 2},
+    {0, 7, 0x0a4e, 2},
+    {0, 0, 0x0882, 2},
+    {0, 7, 0x0a4e, 2},
+    {0, 0, 0x0880, 2},
+    {0, 7, 0x0a4e, 2},
+  };
+  static const DrawMultipleData kEndSequence_Dmd20[6] = {
+    {-4,  1, 0x0c68, 0},
+    { 0, -8, 0x0c40, 2},
+    { 0,  1, 0x0c42, 2},
+    {-4,  1, 0x0c78, 0},
+    { 0, -8, 0x0c40, 2},
+    { 0,  1, 0x0c42, 2},
+  };
+  static const DrawMultipleData kEndSequence_Dmd21[6] = {
+    {8,   5, 0x0679, 0},
+    {0, -10, 0x088e, 2},
+    {0,   0, 0x066e, 2},
+    {0, -10, 0x088e, 2},
+    {0, -10, 0x088e, 2},
+    {0,   0, 0x066e, 2},
+  };
+  static const DrawMultipleData kEndSequence_Dmd22[6] = {
+    {11,  -3, 0x0869, 0},
+    { 0, -12, 0x0804, 2},
+    { 0,   0, 0x0860, 2},
+    {10,  -3, 0x0867, 0},
+    { 0, -12, 0x0804, 2},
+    { 0,   0, 0x0860, 2},
+  };
+  static const DrawMultipleData kEndSequence_Dmd23[6] = {
+    {-2,  1, 0x0868, 0},
+    { 0, -8, 0x08c0, 2},
+    { 0,  0, 0x08c2, 2},
+    {-3,  1, 0x0878, 0},
+    { 0, -8, 0x08c0, 2},
+    { 0,  0, 0x08c2, 2},
+  };
+  static const DrawMultipleData kEndSequence_Dmd24[4] = {
+    {0, -10, 0x084c, 2},
+    {0,   0, 0x0a6c, 2},
+    {0,  -9, 0x084c, 2},
+    {0,   0, 0x0aa8, 2},
+  };
+  static const DrawMultipleData kEndSequence_Dmd25[4] = {
+    {0, -7, 0x084a, 2},
+    {0,  0, 0x0c6a, 2},
+    {0, -7, 0x084a, 2},
+    {0,  0, 0x0ca6, 2},
+  };
+  static const DrawMultipleData kEndSequence_Dmd26[12] = {
+    {-18, -24, 0x39a4, 2},
+    {-16, -16, 0x39a8, 2},
+    {-18, -24, 0x39a4, 2},
+    {-18, -24, 0x39a4, 2},
+    {-16, -16, 0x39a6, 2},
+    {-18, -24, 0x39a4, 2},
+    { -6, -17, 0x392d, 0},
+    {-16, -24, 0x39a0, 2},
+    {-16, -16, 0x39aa, 2},
+    { -5, -17, 0x392c, 0},
+    {-16, -24, 0x39a0, 2},
+    {-16, -16, 0x39aa, 2},
+  };
+  static const DrawMultipleData kEndSequence_Dmd27[6] = {
+    { 0,  -4, 0x30aa, 2},
+    { 0,  -4, 0x30aa, 2},
+    {-4,  -8, 0x3090, 0},
+    {12,  -8, 0x7090, 0},
+    {-6, -10, 0x3091, 0},
+    {14, -10, 0x7091, 0},
+  };
+  static const DrawMultipleData kEndSequence_Dmd28[8] = {
+    {0,  0, 0x0722, 2},
+    {0, -8, 0x09c2, 2},
+    {0,  0, 0x4722, 2},
+    {0, -8, 0x09c2, 2},
+    {0, -9, 0x09c4, 2},
+    {0,  0, 0x0722, 2},
+    {0, -9, 0x0924, 2},
+    {0,  0, 0x0722, 2},
+  };
+  static const DrawMultipleData kEndSequence_Dmd29[3] = {
+    {-16, -12, 0x3f08, 2},
+    {  0, -12, 0x3f20, 2},
+    { 16, -12, 0x3f20, 2},
+  };
+  static const DrawMultipleData kEndSequence_Dmd30[1] = {
+    {0, 0, 0x0086, 2},
+  };
+  static const DrawMultipleData kEndSequence_Dmd31[1] = {
+    {0, 0, 0x8060, 2},
+  };
+  static const DrawMultipleData *const kEndSequence_Dmds[] = {
+    kEndSequence_Dmd0, kEndSequence_Dmd1, kEndSequence_Dmd2, kEndSequence_Dmd3,
+    kEndSequence_Dmd4, kEndSequence_Dmd5, kEndSequence_Dmd6, kEndSequence_Dmd7,
+    kEndSequence_Dmd8, kEndSequence_Dmd9, kEndSequence_Dmd10, kEndSequence_Dmd11,
+    kEndSequence_Dmd12, kEndSequence_Dmd13, kEndSequence_Dmd14, kEndSequence_Dmd15,
+    kEndSequence_Dmd16, kEndSequence_Dmd17, kEndSequence_Dmd18, kEndSequence_Dmd19,
+    kEndSequence_Dmd20, kEndSequence_Dmd21, kEndSequence_Dmd22, kEndSequence_Dmd23,
+    kEndSequence_Dmd24, kEndSequence_Dmd25, kEndSequence_Dmd26, kEndSequence_Dmd27,
+    kEndSequence_Dmd28, kEndSequence_Dmd29, kEndSequence_Dmd30, kEndSequence_Dmd31
+  };
+
+  Oam_AllocateFromRegionA(a * 4);
+  Sprite_Get16BitCoords(k);
+  Sprite_DrawMultiple(k, kEndSequence_Dmds[j >> 1] + a * sprite_graphics[k], a, &g_ending_coords);
+}
+
+void Credits_SpriteDraw_SetShadowProp(int k, uint8 a) {  // 8eaca2
+  sprite_flags2[k] = a;
+  sprite_flags3[k] = 16;
+}
+
+void Credits_SpriteDraw_AddSparkle(int j_count, uint8 xb, uint8 yb) {  // 8eace5
+  static const uint8 kEnding_Func3_Delay[6] = { 32, 4, 4, 4, 5, 6 };
+  sprite_C[0] = j_count;
+  for (int k = 0; k < j_count; k++) {
+    int j = sprite_graphics[k];
+    if (!sprite_delay_main[k]) {
+      if (++j >= 6) {
+        sprite_x_lo[k] = xb;
+        sprite_y_lo[k] = yb;
+        j = 0;
+      }
+      sprite_graphics[k] = j;
+      sprite_delay_main[k] = kEnding_Func3_Delay[j];
+    }
+    if (j)
+      Credits_SpriteDraw_Single(k, 1, 0x1c);
+  }
+}
+
+void Credits_SpriteDraw_WalkLinkAwayFromPedestal(int k) {  // 8eadf7
+  static const uint16 kEnding_Func6_Dma[8] = { 0x16c, 0x16e, 0x170, 0x172, 0x16c, 0x174, 0x176, 0x178 };
+  if (!sprite_delay_main[k]) {
+    sprite_graphics[k] = sprite_graphics[k] + 1 & 7;
+    sprite_delay_main[k] = 4;
+  }
+  link_dma_graphics_index = kEnding_Func6_Dma[sprite_graphics[k]];
+  sprite_oam_flags[k] = 32;
+  Credits_SpriteDraw_Single(k, 2, 26);
+  EndSequence_DrawShadow2(k);
+  Sprite_MoveXY(k);
+}
+
+void Credits_SpriteDraw_MoveSquirrel(int k) {  // 8eae35
+  static const int8 kEnding_Func5_Xvel[4] = { 32, 24, -32, -24 };
+  static const int8 kEnding_Func5_Yvel[4] = { 8, -8, -8, 8 };
+  if (sprite_delay_main[k] < 64) {
+    sprite_C[k] = sprite_C[k] + 1 & 3;
+    sprite_A[k]++;
+  } else {
+    int j = sprite_C[k];
+    sprite_x_vel[k] = kEnding_Func5_Xvel[j];
+    sprite_y_vel[k] = kEnding_Func5_Yvel[j];
+    Sprite_MoveXY(k);
+  }
+}
+
+void Credits_SpriteDraw_CirclingBirds(int k) {  // 8eae63
+  static const int8 kEnding_MoveSprite_Func1_TargetX[2] = { 0x20, -0x20 };
+  static const int8 kEnding_MoveSprite_Func1_TargetY[2] = { 0x10, -0x10 };
+
+  int j = sprite_D[k] & 1;
+  sprite_x_vel[k] += j ? -1 : 1;
+  if (sprite_x_vel[k] == (uint8)kEnding_MoveSprite_Func1_TargetX[j])
+    sprite_D[k]++;
+  if (!(frame_counter & 1)) {
+    j = sprite_head_dir[k] & 1;
+    sprite_y_vel[k] += j ? -1 : 1;
+    if (sprite_y_vel[k] == (uint8)kEnding_MoveSprite_Func1_TargetY[j])
+      sprite_head_dir[k]++;
+  }
+  Sprite_MoveXY(k);
+}
+
+void Credits_HandleCameraScrollControl() {  // 8eaea6
+  if (link_y_vel != 0) {
+    uint8 yvel = link_y_vel;
+    BG2VOFS_copy2 += (int8)yvel;
+    uint16 *which = sign8(yvel) ? &overworld_unk1 : &overworld_unk1_neg;
+    *which += abs8(yvel);
+    if (!sign16(*which - 0x10)) {
+      *which -= 0x10;
+      overworld_screen_trans_dir_bits2 |= sign8(yvel) ? 8 : 4;
+    }
+    *(sign8(yvel) ? &overworld_unk1_neg : &overworld_unk1) = -*which;
+    uint16 r4 = (int8)yvel, subp;
+    WORD(byte_7E069E[0]) = r4;
+    uint8 oi = BYTE(overlay_index);
+    if (oi != 0x97 && oi != 0x9d) {
+      if (oi == 0xb5 || oi == 0xbe) {
+        subp = (r4 & 3) << 14;
+        r4 >>= 2;
+        if (r4 >= 0x3000)
+          r4 |= 0xf000;
+      } else {
+        subp = (r4 & 1) << 15;
+        r4 >>= 1;
+        if (r4 >= 0x7000)
+          r4 |= 0xf000;
+      }
+      uint32 tmp = BG1VOFS_subpixel | BG1VOFS_copy2 << 16;
+      tmp += subp | r4 << 16;
+      BG1VOFS_subpixel = (uint16)(tmp);
+      BG1VOFS_copy2 = (uint16)(tmp >> 16);
+    }
+  }
+
+  if (link_x_vel != 0) {
+    uint8 xvel = link_x_vel;
+    BG2HOFS_copy2 += (int8)xvel;
+    uint16 *which = sign8(xvel) ? &overworld_unk3 : &overworld_unk3_neg;
+    *which += abs8(xvel);
+    if (!sign16(*which - 0x10)) {
+      *which -= 0x10;
+      overworld_screen_trans_dir_bits2 |= sign8(xvel) ? 2 : 1;
+    }
+    *(sign8(xvel) ? &overworld_unk3_neg : &overworld_unk3) = -*which;
+
+    uint16 r4 = (int8)xvel, subp;
+    WORD(byte_7E069E[1]) = r4;
+    uint8 oi = BYTE(overlay_index);
+    if (oi != 0x97 && oi != 0x9d && r4 != 0) {
+      if (oi == 0x95 || oi == 0x9e) {
+        subp = (r4 & 3) << 14;
+        r4 >>= 2;
+        if (r4 >= 0x3000)
+          r4 |= 0xf000;
+      } else {
+        subp = (r4 & 1) << 15;
+        r4 >>= 1;
+        if (r4 >= 0x7000)
+          r4 |= 0xf000;
+      }
+      uint32 tmp = BG1HOFS_subpixel | BG1HOFS_copy2 << 16;
+      tmp += subp | r4 << 16;
+      BG1HOFS_subpixel = (uint16)(tmp), BG1HOFS_copy2 = (uint16)(tmp >> 16);
+    }
+  }
+
+  if (BYTE(overlay_index) == 0x9c) {
+    uint32 tmp = BG1VOFS_subpixel | BG1VOFS_copy2 << 16;
+    tmp -= 0x2000;
+    BG1VOFS_subpixel = (uint16)(tmp), BG1VOFS_copy2 = (uint16)(tmp >> 16) + WORD(byte_7E069E[0]);
+    BG1HOFS_copy2 = BG2HOFS_copy2;
+  } else if (BYTE(overlay_index) == 0x97 || BYTE(overlay_index) == 0x9d) {
+    uint32 tmp = BG1VOFS_subpixel | BG1VOFS_copy2 << 16;
+    tmp += 0x2000;
+    BG1VOFS_subpixel = (uint16)(tmp), BG1VOFS_copy2 = (uint16)(tmp >> 16);
+    tmp = BG1HOFS_subpixel | BG1HOFS_copy2 << 16;
+    tmp += 0x2000;
+    BG1HOFS_subpixel = (uint16)(tmp), BG1HOFS_copy2 = (uint16)(tmp >> 16);
+  }
+
+  if (dungeon_room_index == 0x181) {
+    BG1VOFS_copy2 = BG2VOFS_copy2 | 0x100;
+    BG1HOFS_copy2 = BG2HOFS_copy2;
+  }
+}
+
+void EndSequence_32() {  // 8ebc6d
+  EnableForceBlank();
+  EraseTileMaps_triforce();
+  TransferFontToVRAM();
+  Credits_LoadCoolBackground();
+  Credits_InitializePolyhedral();
+  INIDISP_copy = 128;
+  overworld_palette_aux_or_main = 0x200;
+  hud_palette = 1;
+  Palette_Load_HUD();
+  flag_update_cgram_in_nmi++;
+  deaths_per_palace[4] = 0;
+  deaths_per_palace[13] += death_save_counter;
+  int sum = deaths_per_palace[13];
+  for (int i = 12; i >= 0; i--)
+    sum += deaths_per_palace[i];
+  death_var2 = sum;
+  death_save_counter = 0;
+  link_health_current = kHealthAfterDeath[link_health_capacity >> 3];
+  savegame_is_darkworld = 0x40;
+  SaveGameFile();
+  aux_palette_buffer[38] = 0;
+  main_palette_buffer[38] = 0;
+  aux_palette_buffer[0] = 0;
+  main_palette_buffer[0] = 0;
+  TM_copy = 0x16;
+  TS_copy = 0;
+  R16 = 0x6800;
+  R18 = 0;
+  ending_which_dung = 0;
+  BG2VOFS_copy2 = -0x48;
+  BG2HOFS_copy2 = 0x90;
+  BG3VOFS_copy2 = 0;
+  BG3HOFS_copy2 = 0;
+  Credits_AddNextAttribution();
+  music_control = 0x22;
+  CGWSEL_copy = 0;
+  CGADSUB_copy = 162;
+  // real zelda does 0x12 here but this seems to work too
+  zelda_ppu_write(BG2SC, 0x13);
+  COLDATA_copy0 = 0x3f;
+  COLDATA_copy1 = 0x5f;
+  COLDATA_copy2 = 0x9f;
+  subsubmodule_index = 64;
+  INIDISP_copy = 0;
+
+  HdmaSetup(0, 0xebd53, 0x42, 0, (uint8)BG2HOFS, 0);
+  HDMAEN_copy = 0x80;
+
+  BG2HOFS_copy = BG2HOFS_copy2;
+  BG2VOFS_copy = BG2VOFS_copy2;
+  BG1HOFS_copy = BG1HOFS_copy2;
+  BG1VOFS_copy = BG1VOFS_copy2;
+}
+
+void Credits_FadeOutFixedCol() {  // 8ebd66
+  if (--subsubmodule_index == 0) {
+    subsubmodule_index = 16;
+    if (COLDATA_copy0 != 32) {
+      COLDATA_copy0--;
+    } else if (COLDATA_copy1 != 64) {
+      COLDATA_copy1--;
+    } else if (COLDATA_copy2 != 128) {
+      COLDATA_copy2--;
+    }
+  }
+}
+
+void Credits_FadeColorAndBeginAnimating() {  // 8ebd8b
+  Credits_FadeOutFixedCol();
+  nmi_disable_core_updates = 1;
+  Credits_AnimateTheTriangles();
+  if (!(frame_counter & 3)) {
+    if (++BG2HOFS_copy2 == 0xc00) {
+      // real zelda writes 0x00 to BG1SC here but that doesn't seem needed
+      zelda_ppu_write(BG2SC, 0x13);
+    }
+    room_bounds_y.a1 = BG2HOFS_copy2 >> 1;
+    room_bounds_y.a0 = room_bounds_y.a1 + BG2HOFS_copy2;
+    room_bounds_y.b0 = room_bounds_y.a0 >> 1;
+    room_bounds_y.b1 = room_bounds_y.a1 >> 1;
+    if (BG3VOFS_copy2 == 3288) {
+      R16 = 0x80;
+      submodule_index++;
+    } else {
+      BG3VOFS_copy2++;
+      if ((BG3VOFS_copy2 & 7) == 0) {
+        R18 = BG3VOFS_copy2 >> 3;
+        Credits_AddNextAttribution();
+      }
+    }
+  }
+  BG2HOFS_copy = BG2HOFS_copy2;
+  BG2VOFS_copy = BG2VOFS_copy2;
+  BG1HOFS_copy = BG1HOFS_copy2;
+  BG1VOFS_copy = BG1VOFS_copy2;
+}
+
+void Credits_AddNextAttribution() {  // 8ebe24
+  static const uint8 kEnding_Func9_Tab2[14] = { 1, 0, 2, 3, 10, 6, 5, 8, 11, 9, 7, 12, 13, 15 };
+  static const uint16 kEnding_Digits_ScrollY[14] = { 0x290, 0x298, 0x2a0, 0x2a8, 0x2b0, 0x2ba, 0x2c2, 0x2ca, 0x2d2, 0x2da, 0x2e2, 0x2ea, 0x2f2, 0x310 };
+  static const uint16 kEnding_Credits_DigitChar[2] = { 0x3ce6, 0x3cf6 };
+
+  uint16 *dst = vram_upload_data + (vram_upload_offset >> 1);
+
+  dst[0] = swap16(R16);
+  dst[1] = 0x3e40;
+  dst[2] = kEnding_MapData[159];
+  dst += 3;
+
+  if (R18 < 394) {
+    const uint8 *src = &kEnding_Credits_Text[kEnding_Credits_Offs[R18]];
+    if (*src != 0xff) {
+      *dst++ = swap16(R16 + *src++);
+      int n = *src++;
+      *dst++ = swap16(n);
+      n = (n + 1) >> 1;
+      do {
+        *dst++ = kEnding_MapData[*src++];
+      } while (--n);
+    }
+
+    if ((ending_which_dung & 1) || R18 * 2 == kEnding_Digits_ScrollY[ending_which_dung >> 1]) {
+      int t = kEnding_Credits_DigitChar[ending_which_dung & 1];
+      WORD(g_ram[0xce]) = t;
+
+      dst[0] = swap16(R16 + 0x19);
+      dst[1] = 0x500;
+
+      uint16 deaths = deaths_per_palace[kEnding_Func9_Tab2[ending_which_dung >> 1]];
+      if (deaths >= 1000)
+        deaths = 999;
+
+      dst[4] = t + deaths % 10, deaths /= 10;
+      dst[3] = t + deaths % 10, deaths /= 10;
+      dst[2] = t + deaths;
+      dst += 5;
+      ending_which_dung++;
+    }
+  }
+
+  R16 += 0x20;
+  if (!(R16 & 0x3ff))
+    R16 = (R16 & 0x6800) ^ 0x800;
+  vram_upload_offset = (char *)dst - (char *)vram_upload_data;
+  BYTE(*dst) = 0xff;
+  nmi_load_bg_from_vram = 1;
+}
+
+void Credits_AddEndingSequenceText() {  // 8ec303
+
+  uint16 *dst = vram_upload_data;
+  dst[0] = 0x60;
+  dst[1] = 0xfe47;
+  dst[2] = kEnding_MapData[159];
+  dst += 3;
+
+  const uint8 *curo = &kEnding0_Data[kEnding0_Offs[submodule_index >> 1]];
+  const uint8 *endo = &kEnding0_Data[kEnding0_Offs[(submodule_index >> 1) + 1]];
+  do {
+    dst[0] = WORD(curo[0]);
+    dst[1] = WORD(curo[2]);
+    int m = (dst[1] >> 9) & 0x7f;
+    dst += 2, curo += 4;
+    do {
+      *dst++ = kEnding_MapData[*curo++];
+    } while (--m >= 0);
+  } while (curo != endo);
+
+  vram_upload_offset = (char *)dst - (char *)vram_upload_data;
+  BYTE(*dst) = 0xff;
+  nmi_load_bg_from_vram = 1;
+}
+
+void Credits_BrightenTriangles() {  // 8ec37c
+  if (!(frame_counter & 15) && ++INIDISP_copy == 15)
+    submodule_index++;
+  Credits_AnimateTheTriangles();
+}
+
+void Credits_StopCreditsScroll() {  // 8ec391
+  if (!--BYTE(R16)) {
+    darkening_or_lightening_screen = 0;
+    palette_filter_countdown = 0;
+    WORD(mosaic_target_level) = 0x1f;
+    submodule_index++;
+    R16 = 0xc0;
+    R18 = 0;
+  }
+  Credits_AnimateTheTriangles();
+}
+
+void Credits_FadeAndDisperseTriangles() {  // 8ec3b8
+  BYTE(R16)--;
+  if (!BYTE(R18)) {
+    ApplyPaletteFilter_bounce();
+    if (BYTE(palette_filter_countdown)) {
+      Credits_AnimateTheTriangles();
+      return;
+    }
+    BYTE(R18)++;
+  }
+  if (BYTE(R16)) {
+    Credits_AnimateTheTriangles();
+    return;
+  }
+  submodule_index++;
+  PaletteFilter_WishPonds_Inner();
+}
+
+void Credits_FadeInTheEnd() {  // 8ec3d5
+  if (!(frame_counter & 7)) {
+    PaletteFilter_SP5F();
+    if (!BYTE(palette_filter_countdown))
+      submodule_index++;;
+  }
+  Credits_HangForever();
+}
+
+void Credits_HangForever() {  // 8ec41a
+  SetOamPlain(&oam_buf[0], -96, -72, 0x00, 0x3b, 2);
+  SetOamPlain(&oam_buf[1], -80, -72, 0x02, 0x3b, 2);
+  SetOamPlain(&oam_buf[2], -64, -72, 0x04, 0x3b, 2);
+  SetOamPlain(&oam_buf[3], -48, -72, 0x06, 0x3b, 2);
+}
+
+void CrystalCutscene_InitializePolyhedral() {  // 9ecdd9
+  poly_config1 = 156;
+  poly_config_color_mode = 1;
+  is_nmi_thread_active = 1;
+  intro_did_run_step = 1;
+  poly_base_x = 32;
+  poly_base_y = 32;
+  BYTE(poly_var1) = 32;
+  poly_which_model = 0;
+  poly_a = 16;
+  TS_copy = 0;
+  TM_copy = 0x16;
+}
+
--- /dev/null
+++ b/src/ending.h
@@ -1,0 +1,92 @@
+#pragma once
+
+typedef struct IntroSpriteEnt {
+  int8 x, y;
+  uint8 charnum, flags;
+  uint8 ext;
+} IntroSpriteEnt;
+
+void Intro_SetupScreen();
+void Intro_LoadTextPointersAndPalettes();
+void Credits_LoadScene_Overworld_PrepGFX();
+void Credits_LoadScene_Overworld_Overlay();
+void Credits_LoadScene_Overworld_LoadMap();
+void Credits_OperateScrollingAndTileMap();
+void Credits_LoadCoolBackground();
+void Credits_LoadScene_Dungeon();
+void Module18_GanonEmerges();
+void Module19_TriforceRoom();
+void Intro_InitializeBackgroundSettings();
+void Polyhedral_InitializeThread();
+void Module00_Intro();
+void Intro_Init();
+void Intro_Init_Continue();
+void Intro_Clear1kbBlocksOfWRAM();
+void Intro_InitializeMemory_darken();
+void IntroZeldaFadein();
+void Intro_FadeInBg();
+void Intro_SwordComingDown();
+void Intro_WaitPlayer();
+void FadeMusicAndResetSRAMMirror();
+void Intro_InitializeTriforcePolyThread();
+void Intro_InitGfx_Helper();
+void LoadTriforceSpritePalette();
+void Intro_HandleAllTriforceAnimations();
+void Scene_AnimateEverySprite();
+void Intro_AnimateTriforce();
+void Intro_RunStep();
+void Intro_AnimOneObj(int k);
+void Intro_SpriteType_A_0(int k);
+void Intro_SpriteType_B_0(int k);
+void AnimateSceneSprite_DrawTriangle(int k);
+void Intro_CopySpriteType4ToOam(int k);
+void EXIT_0CCA90(int k);
+void InitializeSceneSprite_Copyright(int k);
+void AnimateSceneSprite_Copyright(int k);
+void InitializeSceneSprite_Sparkle(int k);
+void AnimateSceneSprite_Sparkle(int k);
+void AnimateSceneSprite_AddObjectsToOamBuffer(int k, const IntroSpriteEnt *src, int num);
+void AnimateSceneSprite_MoveTriangle(int k);
+void TriforceRoom_PrepGFXSlotForPoly();
+void Credits_InitializePolyhedral();
+void AdvancePolyhedral();
+void TriforceRoom_HandlePoly();
+void Credits_AnimateTheTriangles();
+void InitializeSceneSprite_TriforceRoomTriangle(int k);
+void Intro_SpriteType_B_456(int k);
+void AnimateTriforceRoomTriangle_HandleContracting(int k);
+void InitializeSceneSprite_CreditsTriangle(int k);
+void AnimateSceneSprite_CreditsTriangle(int k);
+void Intro_DisplayLogo();
+void Intro_SetupSwordAndIntroFlash();
+void Intro_PeriodicSwordAndIntroFlash();
+void Module1A_Credits();
+void Credits_LoadNextScene_Overworld();
+void Credits_LoadNextScene_Dungeon();
+void Credits_PrepAndLoadSprites();
+void Credits_ScrollScene_Overworld();
+void Credits_ScrollScene_Dungeon();
+void Credits_HandleSceneFade();
+void Credits_SpriteDraw_DrawShadow(int k);
+void EndSequence_DrawShadow2(int k);
+void Ending_Func2(int k, uint8 ain);
+void Credits_SpriteDraw_ActivateAndRunSprite(int k, uint8 a);
+void Credits_SpriteDraw_PreexistingSpriteDraw(int k, uint8 a);
+void Credits_SpriteDraw_Single(int k, uint8 a, uint8 j);
+void Credits_SpriteDraw_SetShadowProp(int k, uint8 a);
+void Credits_SpriteDraw_AddSparkle(int j_count, uint8 xb, uint8 yb);
+void Credits_SpriteDraw_WalkLinkAwayFromPedestal(int k);
+void Credits_SpriteDraw_MoveSquirrel(int k);
+void Credits_SpriteDraw_CirclingBirds(int k);
+void Credits_HandleCameraScrollControl();
+void EndSequence_32();
+void Credits_FadeOutFixedCol();
+void Credits_FadeColorAndBeginAnimating();
+void Credits_AddNextAttribution();
+void Credits_AddEndingSequenceText();
+void Credits_BrightenTriangles();
+void Credits_StopCreditsScroll();
+void Credits_FadeAndDisperseTriangles();
+void Credits_FadeInTheEnd();
+void Credits_HangForever();
+void CrystalCutscene_InitializePolyhedral();
--- /dev/null
+++ b/src/features.h
@@ -1,0 +1,65 @@
+// This file declares extensions to the base game
+#ifndef ZELDA3_FEATURES_H_
+#define ZELDA3_FEATURES_H_
+
+#include "types.h"
+
+// Special RAM locations that are unused but I use for compat things.
+enum {
+  kRam_APUI00 = 0x648,
+  kRam_CrystalRotateCounter = 0x649,
+  kRam_BugsFixed = 0x64a,
+  kRam_Features0 = 0x64c,
+};
+
+enum {
+  // Poly rendered uses correct speed
+  kBugFix_PolyRenderer = 1,
+  kBugFix_AncillaOverwrites = 1,
+  kBugFix_Latest = 1,
+};
+
+// Enum values for kRam_Features0
+enum {
+  kFeatures0_ExtendScreen64 = 1,
+  kFeatures0_SwitchLR = 2,
+  kFeatures0_TurnWhileDashing = 4,
+  kFeatures0_MirrorToDarkworld = 8,
+  kFeatures0_CollectItemsWithSword = 16,
+  kFeatures0_BreakPotsWithSword = 32,
+  kFeatures0_DisableLowHealthBeep = 64,
+  kFeatures0_SkipIntroOnKeypress = 128,
+  kFeatures0_ShowMaxItemsInYellow = 256,
+  kFeatures0_MoreActiveBombs = 512,
+
+  // This is set for visual fixes that don't affect game behavior but will affect ram compare.
+  kFeatures0_WidescreenVisualFixes = 1024,
+
+  kFeatures0_CarryMoreRupees = 2048,
+
+  kFeatures0_MiscBugFixes = 4096,
+
+  kFeatures0_CancelBirdTravel = 8192,
+
+  kFeatures0_GameChangingBugFixes = 16384,
+
+  kFeatures0_SwitchLRLimit = 32768,
+
+  kFeatures0_DimFlashes = 65536,
+};
+
+#define enhanced_features0 (*(uint32*)(g_ram+0x64c))
+#define msu_curr_sample (*(uint32*)(g_ram+0x650))
+#define msu_volume (*(uint8*)(g_ram+0x654))
+#define msu_track (*(uint8*)(g_ram+0x655))
+#define hud_inventory_order ((uint8*)(g_ram + 0x225)) // 4x6 bytes
+#define hud_cur_item_x (*(uint8*)(g_ram+0x656))
+#define hud_cur_item_l (*(uint8*)(g_ram+0x657))
+#define hud_cur_item_r (*(uint8*)(g_ram+0x658))
+
+
+
+extern uint32 g_wanted_zelda_features;
+
+
+#endif  // ZELDA3_FEATURES_H_
--- /dev/null
+++ b/src/glsl_shader.c
@@ -1,0 +1,659 @@
+// This file is heavily influenced by Snes9x
+#include "third_party/gl_core/gl_core_3_1.h"
+#include "glsl_shader.h"
+#include "util.h"
+#include "config.h"
+#include <stdio.h>
+#include <assert.h>
+#include <string.h>
+#define STB_IMAGE_IMPLEMENTATION
+#define STBI_NO_THREAD_LOCALS
+#define STBI_ONLY_PNG
+#define STBI_MAX_DIMENSIONS 4096
+#define STBI_NO_FAILURE_STRINGS
+#include "third_party/stb/stb_image.h"
+
+static GlslPass *ParseConfigKeyPass(GlslShader *gs, const char *key, const char *match) {
+  char *endp;
+  for (; *match; key++, match++) {
+    if (*key != *match)
+      return NULL;
+  }
+  if ((uint8)(*key - '0') >= 10)
+    return NULL;
+  uint pass = strtoul(key, &endp, 10);
+  if (pass >= gs->n_pass || *endp != 0)
+    return NULL;
+  return gs->pass + pass + 1;
+}
+
+static uint8 ParseScaleType(const char *s) {
+  return StringEqualsNoCase(s, "source") ? GLSL_SOURCE : 
+         StringEqualsNoCase(s, "viewport") ? GLSL_VIEWPORT :
+         StringEqualsNoCase(s, "absolute") ? GLSL_ABSOLUTE : GLSL_NONE;
+}
+
+static uint ParseWrapMode(const char *s) {
+  return StringEqualsNoCase(s, "repeat") ? GL_REPEAT :
+         StringEqualsNoCase(s, "clamp_to_edge") ? GL_CLAMP_TO_EDGE :
+         StringEqualsNoCase(s, "clamp") ? GL_CLAMP : GL_CLAMP_TO_BORDER;
+}
+
+static void GlslPass_Initialize(GlslPass *pass) {
+  pass->scale_x = 1.0f;
+  pass->scale_y = 1.0f;
+  pass->wrap_mode = GL_CLAMP_TO_BORDER;
+}
+
+static void ParseTextures(GlslShader *gs, char *value) {
+  char *id;
+  GlslTexture **nextp = &gs->first_texture;
+  for (int num = 0; (id = NextDelim(&value, ';')) != NULL && num < kGlslMaxTextures; num++) {
+    GlslTexture *t = calloc(sizeof(GlslTexture), 1);
+    t->id = strdup(id);
+    t->wrap_mode = GL_CLAMP_TO_BORDER;
+    t->filter = GL_NEAREST;
+    *nextp = t;
+    nextp = &t->next;
+  }
+}
+
+static bool ParseTextureKeyValue(GlslShader *gs, const char *key, const char *value) {
+  for (GlslTexture *t = gs->first_texture; t != NULL; t = t->next) {
+    const char *key2 = SkipPrefix(key, t->id);
+    if (!key2) continue;
+    if (*key2 == 0) {
+      StrSet(&t->filename, value);
+      return true;
+    } else if (!strcmp(key2, "_wrap_mode")) {
+      t->wrap_mode = ParseWrapMode(value);
+      return true;
+    } else if (!strcmp(key2, "_mipmap")) {
+      t->mipmap = ParseBool(value, NULL);
+      return true;
+    } else if (!strcmp(key2, "_linear")) {
+      t->filter = ParseBool(value, NULL) ? GL_LINEAR : GL_NEAREST;
+      return true;
+    }
+  }
+  return false;
+}
+
+static GlslParam *GlslShader_GetParam(GlslShader *gs, const char *id) {
+  GlslParam **pp = &gs->first_param;
+  for (; (*pp) != NULL; pp = &(*pp)->next)
+    if (!strcmp((*pp)->id, id))
+      return *pp;
+  GlslParam *p = (GlslParam *)calloc(1, sizeof(GlslParam));
+  *pp = p;
+  p->id = strdup(id);
+  return p;
+}
+
+static void ParseParameters(GlslShader *gs, char *value) {
+  char *id;
+  while ((id = NextDelim(&value, ';')) != NULL)
+    GlslShader_GetParam(gs, id);
+}
+
+static bool ParseParameterKeyValue(GlslShader *gs, const char *key, const char *value) {
+  for (GlslParam *p = gs->first_param; p != NULL; p = p->next) {
+    if (strcmp(p->id, key) == 0) {
+      p->value = atof(value);
+      p->has_value = true;
+      return true;
+    }
+  }
+  return false;
+}
+
+static void GlslShader_InitializePasses(GlslShader *gs, int passes) {
+  gs->n_pass = passes;
+  gs->pass = (GlslPass *)calloc(gs->n_pass + 1, sizeof(GlslPass));
+  for (int i = 0; i < gs->n_pass; i++)
+    GlslPass_Initialize(gs->pass + i + 1);
+}
+
+static bool GlslShader_ReadPresetFile(GlslShader *gs, const char *filename) {
+  char *data = (char *)ReadWholeFile(filename, NULL), *data_org = data, *line;
+  GlslPass *pass;
+  if (data == NULL)
+    return false;
+  for (int lineno = 1; (line = NextLineStripComments(&data)) != NULL; lineno++) {
+    char *value = SplitKeyValue(line), *t;
+    if (value == NULL) {
+      if (*line)
+        fprintf(stderr, "%s:%d: Expecting key=value\n", filename, lineno);
+      continue;
+    }
+    if (*value == '"') {
+      for (t = ++value; *t && *t != '"'; t++);
+      if (*t) *t = 0;
+    }
+
+    if (gs->n_pass == 0) {
+      if (strcmp(line, "shaders") != 0) {
+        fprintf(stderr, "%s:%d: Expecting 'shaders'\n", filename, lineno);
+        break;
+      }
+      int passes = strtoul(value, NULL, 10);
+      if (passes < 1 || passes > kGlslMaxPasses)
+        break;
+      GlslShader_InitializePasses(gs, passes);
+      continue;
+    }
+    if ((pass = ParseConfigKeyPass(gs, line, "filter_linear")) != NULL)
+      pass->filter = ParseBool(value, NULL) ? GL_LINEAR : GL_NEAREST;
+    else if ((pass = ParseConfigKeyPass(gs, line, "scale_type")) != NULL)
+      pass->scale_type_x = pass->scale_type_y = ParseScaleType(value);
+    else if ((pass = ParseConfigKeyPass(gs, line, "scale_type_x")) != NULL)
+      pass->scale_type_x = ParseScaleType(value);
+    else if ((pass = ParseConfigKeyPass(gs, line, "scale_type_y")) != NULL)
+      pass->scale_type_y = ParseScaleType(value);
+    else if ((pass = ParseConfigKeyPass(gs, line, "scale")) != NULL)
+      pass->scale_x = pass->scale_y = atof(value);
+    else if ((pass = ParseConfigKeyPass(gs, line, "scale_x")) != NULL)
+      pass->scale_x = atof(value);
+    else if ((pass = ParseConfigKeyPass(gs, line, "scale_y")) != NULL)
+      pass->scale_y = atof(value);
+    else if ((pass = ParseConfigKeyPass(gs, line, "shader")) != NULL)
+      StrSet(&pass->filename, value);
+    else if ((pass = ParseConfigKeyPass(gs, line, "wrap_mode")) != NULL)
+      pass->wrap_mode = ParseWrapMode(value);
+    else if ((pass = ParseConfigKeyPass(gs, line, "mipmap_input")) != NULL)
+      pass->mipmap_input = ParseBool(value, NULL);
+    else if ((pass = ParseConfigKeyPass(gs, line, "frame_count_mod")) != NULL)
+      pass->frame_count_mod = atoi(value);
+    else if ((pass = ParseConfigKeyPass(gs, line, "float_framebuffer")) != NULL)
+      pass->float_framebuffer = ParseBool(value, NULL);
+    else if ((pass = ParseConfigKeyPass(gs, line, "srgb_framebuffer")) != NULL)
+      pass->srgb_framebuffer = ParseBool(value, NULL);
+    else if ((pass = ParseConfigKeyPass(gs, line, "alias")) != NULL)
+      ;
+    else if (strcmp(line, "textures") == 0 && gs->first_texture == NULL)
+      ParseTextures(gs, value);
+    else if (strcmp(line, "parameters") == 0)
+      ParseParameters(gs, value);
+    else if (!ParseTextureKeyValue(gs, line, value) && !ParseParameterKeyValue(gs, line, value))
+      fprintf(stderr, "%s:%d: Unknown key '%s'\n", filename, lineno, line);
+  }
+  free(data_org);
+  return gs->n_pass != 0;
+}
+
+void GlslShader_ReadShaderFile(GlslShader *gs, const char *filename, ByteArray *result) {
+  char *data = (char *)ReadWholeFile(filename, NULL), *data_org = data, *line;
+  if (data == NULL) {
+    fprintf(stderr, "Unable to read file '%s'\n", filename);
+    return;
+  }
+  while ((line = NextDelim(&data, '\n')) != NULL) {
+    size_t linelen = strlen(line);
+    if (linelen >= 8 && memcmp(line, "#include", 8) == 0) {
+      char *tt = line + 8;
+      char *new_filename = ReplaceFilenameWithNewPath(filename, NextPossiblyQuotedString(&tt));
+      GlslShader_ReadShaderFile(gs, new_filename, result);
+      free(new_filename);
+    } else if (linelen >= 17 && memcmp(line, "#pragma parameter", 17) == 0) {
+      char *tt = line + 17;
+      GlslParam *param = GlslShader_GetParam(gs, NextPossiblyQuotedString(&tt));
+      NextPossiblyQuotedString(&tt); // skip name
+      float value = atof(NextPossiblyQuotedString(&tt));
+      if (!param->has_value)
+        param->value = value;
+      param->min = atof(NextPossiblyQuotedString(&tt));
+      param->max = atof(NextPossiblyQuotedString(&tt));
+      // skip step
+    } else {
+      line[linelen] = '\n';
+      ByteArray_AppendData(result, (uint8 *)line, linelen + 1);
+    }
+  }
+  free(data_org);
+}
+
+size_t LengthOfInitialComments(const uint8 *data, size_t size) {
+  const uint8 *data_org = data, *data_end = data + size;
+  while (data != data_end) {
+    uint8 c = *data++;
+    if (c == ' ' || c == '\t' || c == '\r' || c == '\n')
+      continue;
+    if (c != '/' || data == data_end) {
+      data--;
+      break;
+    }
+    c = *data++;
+    if (c == '/') {
+      while (data != data_end && *data++ != '\n') {}
+    } else if (c == '*') {
+      do {
+        if (data_end - data < 2)
+          return 0;
+      } while (*data++ != '*' || data[0] != '/');
+      data++;
+    } else {
+      data--;
+      break;
+    }
+  }
+  return data - data_org;
+}
+
+static bool GlslPass_Compile(GlslPass *p, uint type, const uint8 *data, size_t size, bool use_opengl_es) {
+  static const char kVertexPrefix[] =   "#define VERTEX\n#define PARAMETER_UNIFORM\n";
+  static const char kFragmentPrefixCore[] = "#define FRAGMENT\n#define PARAMETER_UNIFORM\n";
+  static const char kFragmentPrefixEs[] = "#define FRAGMENT\n#define PARAMETER_UNIFORM\n" \
+					"precision mediump float;";
+  const GLchar *strings[3];
+  GLint lengths[3];
+  char buffer[256];
+  GLint compile_status = 0;
+  size_t skip = 0;
+
+  size_t commsize = LengthOfInitialComments(data, size);
+  data += commsize, size -= commsize;
+
+  if (size < 8 || memcmp(data, "#version", 8) != 0) {
+    if (!use_opengl_es) {
+      strings[0] = "#version 330\n";
+      lengths[0] = sizeof("#version 330\n") - 1;
+    } else {
+      strings[0] = "#version 300 es\n";
+      lengths[0] = sizeof("#version 300 es\n") - 1;
+    }
+  } else {
+    while (skip < size && data[skip++] != '\n') {}
+    strings[0] = (char*)data;
+    lengths[0] = (int)skip;
+  }
+  if (type == GL_VERTEX_SHADER) {
+    strings[1] = (char *)kVertexPrefix;
+    lengths[1] = sizeof(kVertexPrefix) - 1;
+  } else {
+    strings[1] = (use_opengl_es) ? (char *)kFragmentPrefixEs : kFragmentPrefixCore;
+    lengths[1] = (use_opengl_es) ? sizeof(kFragmentPrefixEs) - 1 : sizeof(kFragmentPrefixCore) - 1;
+  }
+  strings[2] = (GLchar *)data + skip;
+  lengths[2] = (int)(size - skip);
+  uint shader = glCreateShader(type);
+  glShaderSource(shader, 3, strings, lengths);
+  glCompileShader(shader);
+  glGetShaderiv(shader, GL_COMPILE_STATUS, &compile_status);
+  buffer[0] = 0;
+  glGetShaderInfoLog(shader, sizeof(buffer), NULL, buffer);
+  if (compile_status != GL_TRUE || buffer[0]) {
+    fprintf(stderr, "%s compiling %s shader in file '%s':\n%s\n",
+            compile_status != GL_TRUE ? "Error" : "While",
+            type == GL_VERTEX_SHADER ? "vertex" : "fragment", p->filename, buffer);
+  }
+  if (compile_status == GL_TRUE)
+    glAttachShader(p->gl_program, shader);
+  glDeleteShader(shader);
+  return (compile_status == GL_TRUE);
+}
+
+static void GlslTextureUniform_Read(uint program, const char *prefix, int i, GlslTextureUniform *result) {
+  char buf[40];
+  char *e = &buf[snprintf(buf, sizeof(buf), i >= 0 ? "%s%u" : "%s", prefix, i)];
+  memcpy(e, "Texture", 8);
+  result->Texture = glGetUniformLocation(program, buf);
+  memcpy(e, "InputSize", 10);
+  result->InputSize = glGetUniformLocation(program, buf);
+  memcpy(e, "TextureSize", 12);
+  result->TextureSize = glGetUniformLocation(program, buf);
+  memcpy(e, "TexCoord", 9);
+  result->TexCoord = glGetAttribLocation(program, buf);
+}
+
+static const float kMvpMatrixOrtho[16] = {
+   2.0f,  0.0f,  0.0f,  0.0f,
+   0.0f,  2.0f,  0.0f,  0.0f,
+   0.0f,  0.0f, -1.0f,  0.0f,
+  -1.0f, -1.0f,  0.0f,  1.0f
+};
+
+static void GlslShader_GetUniforms(GlslShader *gs) {
+  int pass_idx = 1;
+  gs->max_prev_frame = 0;
+  for (GlslPass *p = gs->pass + 1, *p_end = p + gs->n_pass; p < p_end; p++, pass_idx++) {
+    uint program = p->gl_program;
+    glUseProgram(program);
+
+    GLint MVPMatrix = glGetUniformLocation(program, "MVPMatrix");
+    if (MVPMatrix >= 0)
+      glUniformMatrix4fv(MVPMatrix, 1, GL_FALSE, kMvpMatrixOrtho);
+
+    GlslTextureUniform_Read(program, "", -1, &p->unif.Top);
+    p->unif.OutputSize = glGetUniformLocation(program, "OutputSize");
+    p->unif.FrameCount = glGetUniformLocation(program, "FrameCount");
+    p->unif.FrameDirection = glGetUniformLocation(program, "FrameDirection");
+    p->unif.LUTTexCoord = glGetAttribLocation(program, "LUTTexCoord");
+    p->unif.VertexCoord = glGetAttribLocation(program, "VertexCoord");
+    GlslTextureUniform_Read(program, "Orig", -1, &p->unif.Orig);
+    for (int j = 0; j < 7; j++) {
+      GlslTextureUniform_Read(program, "Prev", j ? j : -1, &p->unif.Prev[j]);
+      if (p->unif.Prev[j].Texture >= 0)
+        gs->max_prev_frame = j + 1;
+    }
+    for (int j = 0; j < gs->n_pass; j++) {
+      GlslTextureUniform_Read(program, "Pass", j, &p->unif.Pass[j]);
+      GlslTextureUniform_Read(program, "PassPrev", j, &p->unif.PassPrev[j]);
+    }
+    GlslTexture *t = gs->first_texture;
+    for (int j = 0; t != NULL; t = t->next, j++)
+      p->unif.Texture[j] = glGetUniformLocation(program, t->id);
+    for (GlslParam *pa = gs->first_param; pa != NULL; pa = pa->next)
+      pa->uniform[pass_idx] = glGetUniformLocation(program, pa->id);
+  }
+  glUseProgram(0);
+}
+
+static bool IsGlslFilename(const char *filename) {
+  size_t len = strlen(filename);
+  return len >= 5 && memcmp(filename + len - 5, ".glsl", 5) == 0;
+}
+
+GlslShader *GlslShader_CreateFromFile(const char *filename, bool opengl_es) {
+  char buffer[256];
+  GLint link_status;
+  ByteArray shader_code = { 0 };
+  bool success = false;
+  GlslShader *gs = (GlslShader *)calloc(sizeof(GlslShader), 1);
+  if (!gs)
+    return gs;
+
+  if (IsGlslFilename(filename)) {
+    GlslShader_InitializePasses(gs, 1);
+    gs->pass[1].filename = strdup(filename);
+    filename = "";
+  } else {
+    if (!GlslShader_ReadPresetFile(gs, filename)) {
+      fprintf(stderr, "Unable to read file '%s'\n", filename);
+      goto FAIL;
+    }
+  }
+  for (int i = 1; i <= gs->n_pass; i++) {
+    GlslPass *p = gs->pass + i;
+    shader_code.size = 0;
+
+    if (p->filename == NULL) {
+      fprintf(stderr, "shader%d attribute missing\n", i - 1);
+      goto FAIL;
+    }
+
+    char *new_filename = ReplaceFilenameWithNewPath(filename, p->filename);
+    GlslShader_ReadShaderFile(gs, new_filename, &shader_code);
+    free(new_filename);
+
+    if (shader_code.size == 0) {
+      fprintf(stderr, "Couldn't read shader in file '%s'\n", p->filename);
+      goto FAIL;
+    }
+    p->gl_program = glCreateProgram();
+    if (!GlslPass_Compile(p, GL_VERTEX_SHADER, shader_code.data, shader_code.size, opengl_es) ||
+        !GlslPass_Compile(p, GL_FRAGMENT_SHADER, shader_code.data, shader_code.size, opengl_es)) {
+      goto FAIL;
+    }
+    glLinkProgram(p->gl_program);
+    glGetProgramiv(p->gl_program, GL_LINK_STATUS, &link_status);
+    buffer[0] = 0;
+    glGetProgramInfoLog(p->gl_program, sizeof(buffer), NULL, buffer);
+    if (link_status != GL_TRUE || buffer[0])
+      fprintf(stderr, "%s linking shader in file '%s':\n%s\n",
+              link_status != GL_TRUE ? "Error" : "While", p->filename, buffer);
+    if (link_status != GL_TRUE)
+      goto FAIL;
+    glGenFramebuffers(1, &p->gl_fbo);
+    glGenTextures(1, &p->gl_texture);
+  }
+  for (GlslTexture *t = gs->first_texture; t; t = t->next) {
+    glGenTextures(1, &t->gl_texture);
+    glBindTexture(GL_TEXTURE_2D, t->gl_texture);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, t->wrap_mode);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, t->wrap_mode);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, t->filter);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, t->mipmap ? 
+                    (t->filter == GL_LINEAR ? GL_LINEAR_MIPMAP_LINEAR : GL_NEAREST_MIPMAP_NEAREST) : t->filter);
+    if (t->filename) {
+      char *new_filename = ReplaceFilenameWithNewPath(filename, t->filename);
+      int imw, imh, imn;
+      unsigned char *data = stbi_load(new_filename, &imw, &imh, &imn, 0);
+      if (!data) {
+        fprintf(stderr, "Unable to read PNG '%s'\n", new_filename);
+      } else {
+        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, imw, imh, 0, 
+                     (imn == 4) ? GL_RGBA : (imn == 3) ? GL_RGB : GL_LUMINANCE, GL_UNSIGNED_BYTE, data);
+      }
+      free(data);
+      free(new_filename);
+    }
+    if (t->mipmap)
+      glGenerateMipmap(GL_TEXTURE_2D);
+  }
+  for (GlslParam *p = gs->first_param; p; p = p->next)
+    p->value = (p->value < p->min) ? p->min : (p->value > p->max) ? p->max : p->value;
+
+  GlslShader_GetUniforms(gs);
+
+  for (int i = 0; i < gs->max_prev_frame; i++)
+    glGenTextures(1, &gs->prev_frame[-i - 1 & 7].gl_texture);
+
+  static const GLfloat kTexCoords[16] = {
+    0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f,
+    0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f
+  };
+  glGenBuffers(1, &gs->gl_vbo);
+  glBindBuffer(GL_ARRAY_BUFFER, gs->gl_vbo);
+  glBufferData(GL_ARRAY_BUFFER, sizeof(kTexCoords), kTexCoords, GL_STATIC_DRAW);
+  glBindBuffer(GL_ARRAY_BUFFER, 0);
+
+  success = true;
+FAIL:
+  if (!success) {
+    GlslShader_Destroy(gs);
+    gs = NULL;
+  }
+  ByteArray_Destroy(&shader_code);
+  return gs;
+}
+
+void GlslShader_Destroy(GlslShader *gs) {
+  for (GlslPass *p = gs->pass + 1, *p_end = p + gs->n_pass; p < p_end; p++) {
+    glDeleteProgram(p->gl_program);
+    glDeleteTextures(1, &p->gl_texture);
+    glDeleteFramebuffers(1, &p->gl_fbo);
+    free(p->filename);
+  }
+  free(gs->pass);
+  GlslTexture *t;
+  while ((t = gs->first_texture) != NULL) {
+    gs->first_texture = t->next;
+    glDeleteTextures(1, &t->gl_texture);
+    free(t->id);
+    free(t->filename);
+    free(t);
+  }
+  GlslParam *pp;
+  while ((pp = gs->first_param) != NULL) {
+    gs->first_param = pp->next;
+    free(pp->id);
+    free(pp);
+  }
+  for (int i = 0; i < 8; i++)
+    glDeleteTextures(1, &gs->prev_frame[i].gl_texture);
+  glDeleteBuffers(1, &gs->gl_vbo);
+  free(gs);
+}
+
+enum {
+  kMaxVaosInRenderCtx = 11 + kGlslMaxPasses * 2
+};
+
+typedef struct RenderCtx {
+  uint texture_unit;
+  uint offset;
+  uint num_vaos;
+  uint vaos[kMaxVaosInRenderCtx];
+} RenderCtx;
+
+static void RenderCtx_SetTexture(RenderCtx *ctx, int textureu, uint texture_id) {
+  if (textureu >= 0) {
+    glActiveTexture(GL_TEXTURE0 + ctx->texture_unit);
+    glBindTexture(GL_TEXTURE_2D, texture_id);
+    glUniform1i(textureu, ctx->texture_unit++);
+  }
+}
+
+static void RenderCtx_SetTexCoords(RenderCtx *ctx, int tex_coord, uintptr_t offset) {
+  if (tex_coord >= 0) {
+    assert(ctx->num_vaos < kMaxVaosInRenderCtx);
+    ctx->vaos[ctx->num_vaos++] = tex_coord;
+    glVertexAttribPointer(tex_coord, 2, GL_FLOAT, GL_FALSE, 0, (void *)offset);
+    glEnableVertexAttribArray(tex_coord);
+  }
+}
+
+static void RenderCtx_SetGlslTextureUniform(RenderCtx *ctx, GlslTextureUniform *u,
+                                            int width, int height, uint texture) {
+  float size[2] = { width, height };
+  RenderCtx_SetTexture(ctx, u->Texture, texture);
+  if (u->InputSize >= 0)
+    glUniform2fv(u->InputSize, 1, size);
+  if (u->TextureSize >= 0)
+    glUniform2fv(u->TextureSize, 1, size);
+  RenderCtx_SetTexCoords(ctx, u->TexCoord, ctx->offset);
+}
+
+static void GlslShader_SetShaderVars(GlslShader *gs, RenderCtx *ctx, int pass) {
+  GlslPass *p = &gs->pass[pass];
+    
+  RenderCtx_SetGlslTextureUniform(ctx, &p->unif.Top, p[-1].width, p[-1].height, p[-1].gl_texture);
+  if (p->unif.OutputSize >= 0) {
+    float output_size[2] = { (float)p[0].width, (float)p[0].height };
+    glUniform2fv(p->unif.OutputSize, 1, output_size);
+  }
+  if (p->unif.FrameCount >= 0)
+    glUniform1i(p->unif.FrameCount, p->frame_count_mod ? 
+                gs->frame_count % p->frame_count_mod : gs->frame_count);
+  if (p->unif.FrameDirection >= 0)
+    glUniform1i(p->unif.FrameDirection, 1);
+  RenderCtx_SetTexCoords(ctx, p->unif.LUTTexCoord, ctx->offset);
+  RenderCtx_SetTexCoords(ctx, p->unif.VertexCoord, 0);
+  RenderCtx_SetGlslTextureUniform(ctx, &p->unif.Orig, gs->pass[0].width, gs->pass[0].height, gs->pass[0].gl_texture);
+  // Prev, Prev1-Prev6 uniforms
+  for (int i = 0; i < gs->max_prev_frame; i++) {
+    GlTextureWithSize *t = &gs->prev_frame[(gs->frame_count - 1 - i) & 7];
+    assert(t->gl_texture != 0);
+    if (t->width)
+      RenderCtx_SetGlslTextureUniform(ctx, &p->unif.Prev[i], t->width, t->height, t->gl_texture);
+  }
+  // Texture uniforms
+  int tctr = 0;
+  for (GlslTexture *t = gs->first_texture; t; t = t->next, tctr++)
+    RenderCtx_SetTexture(ctx, p->unif.Texture[tctr], t->gl_texture);
+  // PassX uniforms
+  for (int i = 1; i < pass; i++)
+    RenderCtx_SetGlslTextureUniform(ctx, &p->unif.Pass[i], gs->pass[i].width, gs->pass[i].height, gs->pass[i].gl_texture);
+  // PassPrevX uniforms
+  for (int i = 1; i < pass; i++)
+    RenderCtx_SetGlslTextureUniform(ctx, &p->unif.PassPrev[pass - i], gs->pass[i].width, gs->pass[i].height, gs->pass[i].gl_texture);
+  // #parameter uniforms
+  for (GlslParam *pa = gs->first_param; pa != NULL; pa = pa->next)
+    if (pa->uniform[pass] >= 0)
+      glUniform1f(pa->uniform[pass], pa->value);
+
+  glActiveTexture(GL_TEXTURE0);
+}
+
+void GlslShader_Render(GlslShader *gs, GlTextureWithSize *tex, int viewport_x, int viewport_y, int viewport_width, int viewport_height) {
+  gs->pass[0].gl_texture = tex->gl_texture;
+  gs->pass[0].width = tex->width;
+  gs->pass[0].height = tex->height;
+
+  GLint previous_framebuffer;
+  glGetIntegerv(GL_FRAMEBUFFER_BINDING, &previous_framebuffer);
+  glBindBuffer(GL_ARRAY_BUFFER, gs->gl_vbo);
+
+  for (int pass = 1; pass <= gs->n_pass; pass++) {
+    bool last_pass = pass == gs->n_pass;
+    GlslPass *p = gs->pass + pass;
+
+    switch (p->scale_type_x) {
+    case GLSL_ABSOLUTE: p->width = (uint16)p->scale_x; break;
+    case GLSL_SOURCE: p->width = (uint16)(p[-1].width * p->scale_x); break;
+    case GLSL_VIEWPORT: p->width = (uint16)(viewport_width * p->scale_x); break;
+    default: p->width = (uint16)(last_pass ? viewport_width : (p[-1].width * p->scale_x)); break;
+    }
+
+    switch (p->scale_type_y) {
+    case GLSL_ABSOLUTE: p->height = (uint16)p->scale_y; break;
+    case GLSL_SOURCE: p->height = (uint16)(p[-1].height * p->scale_y); break;
+    case GLSL_VIEWPORT: p->height = (uint16)(viewport_height * p->scale_y); break;
+    default: p->height = (uint16)(last_pass ? viewport_height : (p[-1].height * p->scale_y)); break;
+    }
+
+    if (!last_pass) {
+      // output to a texture
+      glBindTexture(GL_TEXTURE_2D, p->gl_texture);
+      if (p->srgb_framebuffer) {
+        glEnable(GL_FRAMEBUFFER_SRGB);
+        glTexImage2D(GL_TEXTURE_2D, 0, GL_SRGB8_ALPHA8, p->width, p->height, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, NULL);
+      } else {
+        glTexImage2D(GL_TEXTURE_2D, 0, p->float_framebuffer ? GL_RGBA32F : GL_RGBA,
+                     p->width, p->height, 0, GL_RGBA,
+                     p->float_framebuffer ? GL_FLOAT : GL_UNSIGNED_INT_8_8_8_8, NULL);
+      }
+      glViewport(0, 0, p->width, p->height);
+      glBindFramebuffer(GL_FRAMEBUFFER, p->gl_fbo);
+      glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, p->gl_texture, 0);
+    } else {
+      // output to screen
+      glBindFramebuffer(GL_FRAMEBUFFER, previous_framebuffer);
+      glViewport(viewport_x, viewport_y, viewport_width, viewport_height);
+    }
+
+    glBindTexture(GL_TEXTURE_2D, p[-1].gl_texture);
+
+    uint filter = p->filter ? p->filter : (last_pass && g_config.linear_filtering) ? GL_LINEAR : GL_NEAREST;
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, p->mipmap_input ? 
+                    (filter == GL_LINEAR ? GL_LINEAR_MIPMAP_LINEAR : GL_NEAREST_MIPMAP_NEAREST) : filter);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, p->wrap_mode);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, p->wrap_mode);
+    if (p->mipmap_input)
+      glGenerateMipmap(GL_TEXTURE_2D);
+    glUseProgram(p->gl_program);
+
+    RenderCtx ctx;
+    ctx.texture_unit = ctx.num_vaos = 0;
+    ctx.offset = last_pass ? sizeof(float) * 8 : 0;
+    GlslShader_SetShaderVars(gs, &ctx, pass);
+    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+    for(int i = 0; i < ctx.num_vaos; i++)
+      glDisableVertexAttribArray(ctx.vaos[i]);
+    if (p->srgb_framebuffer)
+      glDisable(GL_FRAMEBUFFER_SRGB);
+  }
+
+  glBindFramebuffer(GL_FRAMEBUFFER, previous_framebuffer);
+  glUseProgram(0);
+  glBindTexture(GL_TEXTURE_2D, 0);
+  glBindBuffer(GL_ARRAY_BUFFER, 0);
+
+  // Store the input frame in the prev array, and extract the next one.
+  if (gs->max_prev_frame != 0) {
+    // 01234567
+    //    43210
+    // ^-- store pos
+    //    ^-- load pos
+    GlTextureWithSize *store_pos = &gs->prev_frame[gs->frame_count & 7];
+    GlTextureWithSize *load_pos = &gs->prev_frame[gs->frame_count - gs->max_prev_frame & 7];
+    assert(store_pos->gl_texture == 0);
+    *store_pos = *tex;
+    *tex = *load_pos;
+    memset(load_pos, 0, sizeof(GlTextureWithSize));
+  }
+
+  gs->frame_count++;
+}
+
--- /dev/null
+++ b/src/glsl_shader.h
@@ -1,0 +1,99 @@
+#ifndef ZELDA3_GLSL_SHADER_H_
+#define ZELDA3_GLSL_SHADER_H_
+
+#include "types.h"
+
+enum {
+  kGlslMaxPasses = 20,
+  kGlslMaxTextures = 10,
+};
+
+enum GLSLScaleType {
+  GLSL_NONE,
+  GLSL_SOURCE,
+  GLSL_VIEWPORT,
+  GLSL_ABSOLUTE
+};
+
+typedef struct GlslTextureUniform {
+  int Texture;
+  int InputSize;
+  int TextureSize;
+  int TexCoord;
+} GlslTextureUniform;
+
+typedef struct GlslUniforms {
+  GlslTextureUniform Top;
+  int OutputSize;
+  int FrameCount, FrameDirection;
+  int LUTTexCoord;
+  int VertexCoord;
+  GlslTextureUniform Orig;
+  GlslTextureUniform Prev[7];
+  GlslTextureUniform Pass[kGlslMaxPasses];
+  GlslTextureUniform PassPrev[kGlslMaxPasses];
+  int Texture[kGlslMaxTextures];
+} GlslUniforms;
+
+typedef struct GlslPass {
+  char *filename;
+  uint8 scale_type_x, scale_type_y;
+  bool float_framebuffer;
+  bool srgb_framebuffer;
+  bool mipmap_input;
+  float scale_x, scale_y;
+  uint wrap_mode;
+  uint frame_count_mod;
+  uint frame_count;
+  uint gl_program, gl_fbo;
+  uint filter;
+  uint gl_texture;
+  uint16 width, height;
+  GlslUniforms unif;
+} GlslPass;
+
+typedef struct GlTextureWithSize {
+  uint gl_texture;
+  uint16 width, height;
+} GlTextureWithSize;
+
+typedef struct GlslTexture {
+  struct GlslTexture *next;
+  char *id;
+  char *filename;
+  uint filter;
+  uint gl_texture;
+  uint wrap_mode;
+  bool mipmap;
+  int width;
+  int height;
+} GlslTexture;
+
+typedef struct GlslParam {
+  struct GlslParam *next;
+  char *id;
+  bool has_value;
+  float value;
+  float min;
+  float max;
+  uint uniform[kGlslMaxPasses];
+} GlslParam;
+
+typedef struct GlslShader {
+  int n_pass;
+  GlslPass *pass;
+  GlslParam *first_param;
+  GlslTexture *first_texture;
+  uint *gl_vao;
+  uint gl_vbo;
+  uint frame_count;
+  int max_prev_frame;
+  GlTextureWithSize prev_frame[8];
+} GlslShader;
+
+GlslShader *GlslShader_CreateFromFile(const char *filename, bool opengl_es);
+void GlslShader_Destroy(GlslShader *gs);
+void GlslShader_Render(GlslShader *gs, GlTextureWithSize *tex, int viewport_x, int viewport_y, int viewport_width, int viewport_height);
+
+
+#endif  // ZELDA3_GLSL_SHADER_H_
--- /dev/null
+++ b/src/hud.c
@@ -1,0 +1,1554 @@
+#include "hud.h"
+#include "zelda_rtl.h"
+
+#include "variables.h"
+#include "messaging.h"
+
+enum {
+  kNewStyleInventory = 0,
+  kHudItemCount = kNewStyleInventory ? 24 : 20,
+};
+
+typedef struct ItemBoxGfx {
+  uint16 v[4];
+} ItemBoxGfx;
+
+static void Hud_DrawItem(uint16 *dst, const ItemBoxGfx *src);
+static bool Hud_DoWeHaveThisItem(uint8 item);
+static void Hud_EquipPrevItem(uint8 *item);
+static void Hud_EquipNextItem(uint8 *item);
+static int Hud_GetItemPosition(int item);
+static void Hud_ReorderItem(int direction);
+static void Hud_Update_Magic();
+static void Hud_Update_Inventory();
+static void Hud_Update_Hearts();
+
+const uint8 kMaxBombsForLevel[] = { 10, 15, 20, 25, 30, 35, 40, 50 };
+const uint8 kMaxArrowsForLevel[] = { 30, 35, 40, 45, 50, 55, 60, 70 };
+static const uint8 kMaxHealthForLevel[] = { 9, 9, 9, 9, 9, 9, 9, 9, 17, 17, 17, 17, 17, 17, 17, 25, 25, 25, 25, 25, 25 };
+
+#define HUDXY(x, y) ((x) + (y) * 32)
+
+static const uint16 kHudItemInVramPtr_New[24] = {
+  HUDXY(2,  7), HUDXY(5,  7), HUDXY(8,  7), HUDXY(11,  7), HUDXY(14,  7), HUDXY(17, 7),
+  HUDXY(2, 10), HUDXY(5, 10), HUDXY(8, 10), HUDXY(11, 10), HUDXY(14, 10), HUDXY(17, 10),
+  HUDXY(2, 13), HUDXY(5, 13), HUDXY(8, 13), HUDXY(11, 13), HUDXY(14, 13), HUDXY(17, 13),
+  HUDXY(2, 16), HUDXY(5, 16), HUDXY(8, 16), HUDXY(11, 16), HUDXY(14, 16), HUDXY(17, 16),
+};
+
+static const uint16 kHudItemInVramPtr_Old[20] = {
+  HUDXY(4,  7), HUDXY(7,  7), HUDXY(10,  7), HUDXY(13,  7), HUDXY(16,  7),
+  HUDXY(4, 10), HUDXY(7, 10), HUDXY(10, 10), HUDXY(13, 10), HUDXY(16, 10),
+  HUDXY(4, 13), HUDXY(7, 13), HUDXY(10, 13), HUDXY(13, 13), HUDXY(16, 13),
+  HUDXY(4, 16), HUDXY(7, 16), HUDXY(10, 16), HUDXY(13, 16), HUDXY(16, 16),
+};
+
+
+#define kHudItemInVramPtr (kNewStyleInventory ? kHudItemInVramPtr_New : kHudItemInVramPtr_Old)
+
+static const ItemBoxGfx kHudItemBottles[9] = {
+  {{0x20f5, 0x20f5, 0x20f5, 0x20f5}},
+  {{0x2044, 0x2045, 0x2046, 0x2047}},
+  {{0x2837, 0x2838, 0x2cc3, 0x2cd3}},
+  {{0x24d2, 0x64d2, 0x24e2, 0x24e3}},
+  {{0x3cd2, 0x7cd2, 0x3ce2, 0x3ce3}},
+  {{0x2cd2, 0x6cd2, 0x2ce2, 0x2ce3}},
+  {{0x2855, 0x6855, 0x2c57, 0x2c5a}},
+  {{0x2837, 0x2838, 0x2839, 0x283a}},
+  {{0x2837, 0x2838, 0x2839, 0x283a}},
+};
+static const ItemBoxGfx kHudItemBow[5] = {
+  {{0x20f5, 0x20f5, 0x20f5, 0x20f5}},
+  {{0x28ba, 0x28e9, 0x28e8, 0x28cb}},
+  {{0x28ba, 0x284a, 0x2849, 0x28cb}},
+  {{0x28ba, 0x28e9, 0x28e8, 0x28cb}},
+  {{0x28ba, 0x28bb, 0x24ca, 0x28cb}},
+};
+static const ItemBoxGfx kHudItemBoomerang[3] = {
+  {{0x20f5, 0x20f5, 0x20f5, 0x20f5}},
+  {{0x2cb8, 0x2cb9, 0x2cf5, 0x2cc9}},
+  {{0x24b8, 0x24b9, 0x24f5, 0x24c9}},
+};
+static const ItemBoxGfx kHudItemHookshot[2] = {
+  {{0x20f5, 0x20f5, 0x20f5, 0x20f5}},
+  {{0x24f5, 0x24f6, 0x24c0, 0x24f5}},
+};
+static const ItemBoxGfx kHudItemBombs[2] = {
+  {{0x20f5, 0x20f5, 0x20f5, 0x20f5}},
+  {{0x2cb2, 0x2cb3, 0x2cc2, 0x6cc2}},
+};
+static const ItemBoxGfx kHudItemMushroom[3] = {
+  {{0x20f5, 0x20f5, 0x20f5, 0x20f5}},
+  {{0x2444, 0x2445, 0x2446, 0x2447}},
+  {{0x203b, 0x203c, 0x203d, 0x203e}},
+};
+static const ItemBoxGfx kHudItemFireRod[2] = {
+  {{0x20f5, 0x20f5, 0x20f5, 0x20f5}},
+  {{0x24b0, 0x24b1, 0x24c0, 0x24c1}},
+};
+static const ItemBoxGfx kHudItemIceRod[2] = {
+  {{0x20f5, 0x20f5, 0x20f5, 0x20f5}},
+  {{0x2cb0, 0x2cbe, 0x2cc0, 0x2cc1}},
+};
+static const ItemBoxGfx kHudItemBombos[2] = {
+  {{0x20f5, 0x20f5, 0x20f5, 0x20f5}},
+  {{0x287d, 0x287e, 0xe87e, 0xe87d}},
+};
+static const ItemBoxGfx kHudItemEther[2] = {
+  {{0x20f5, 0x20f5,  0x20f5,  0x20f5}},
+  {{0x2876, 0x2877, 0xE877, 0xE876}},
+};
+static const ItemBoxGfx kHudItemQuake[2] = {
+  {{0x20f5, 0x20f5,  0x20f5,  0x20f5}},
+  {{0x2866, 0x2867, 0xE867, 0xE866}},
+};
+static const ItemBoxGfx kHudItemTorch[2] = {
+  {{0x20f5, 0x20f5, 0x20f5, 0x20f5}},
+  {{0x24bc, 0x24bd, 0x24cc, 0x24cd}},
+};
+static const ItemBoxGfx kHudItemHammer[2] = {
+  {{0x20f5, 0x20f5, 0x20f5, 0x20f5}},
+  {{0x20b6, 0x20b7, 0x20c6, 0x20c7}},
+};
+static const ItemBoxGfx kHudItemFlute[4] = {
+  {{0x20f5, 0x20f5, 0x20f5, 0x20f5}},
+  {{0x20d0, 0x20d1, 0x20e0, 0x20e1}},
+  {{0x2cd4, 0x2cd5, 0x2ce4, 0x2ce5}},
+  {{0x2cd4, 0x2cd5, 0x2ce4, 0x2ce5}},
+};
+static const ItemBoxGfx kHudItemBugNet[2] = {
+  {{0x20f5, 0x20f5, 0x20f5, 0x20f5}},
+  {{0x3c40, 0x3c41, 0x2842, 0x3c43}},
+};
+static const ItemBoxGfx kHudItemBookMudora[2] = {
+  {{0x20f5, 0x20f5, 0x20f5, 0x20f5}},
+  {{0x3ca5, 0x3ca6, 0x3cd8, 0x3cd9}},
+};
+static const ItemBoxGfx kHudItemCaneSomaria[2] = {
+  {{0x20f5, 0x20f5, 0x20f5, 0x20f5}},
+  {{0x24dc, 0x24dd, 0x24ec, 0x24ed}},
+};
+static const ItemBoxGfx kHudItemCaneByrna[2] = {
+  {{0x20f5, 0x20f5, 0x20f5, 0x20f5}},
+  {{0x2cdc, 0x2cdd, 0x2cec, 0x2ced}},
+};
+static const ItemBoxGfx kHudItemCape[2] = {
+  {{0x20f5, 0x20f5, 0x20f5, 0x20f5}},
+  {{0x24b4, 0x24b5, 0x24c4, 0x24c5}},
+};
+static const ItemBoxGfx kHudItemMirror[4] = {
+  {{0x20f5, 0x20f5, 0x20f5, 0x20f5}},
+  {{0x28de, 0x28df, 0x28ee, 0x28ef}},
+  {{0x2c62, 0x2c63, 0x2c72, 0x2c73}},
+  {{0x2886, 0x2887, 0x2888, 0x2889}},
+};
+static const ItemBoxGfx kHudItemGloves[3] = {
+  {{0x20f5, 0x20f5, 0x20f5, 0x20f5}},
+  {{0x2130, 0x2131, 0x2140, 0x2141}},
+  {{0x28da, 0x28db, 0x28ea, 0x28eb}},
+};
+static const ItemBoxGfx kHudItemBoots[2] = {
+  {{0x20f5, 0x20f5, 0x20f5, 0x20f5}},
+  {{0x3429, 0x342a, 0x342b, 0x342c}},
+};
+static const ItemBoxGfx kHudItemFlippers[2] = {
+  {{0x20f5, 0x20f5, 0x20f5, 0x20f5}},
+  {{0x2c9a, 0x2c9b, 0x2c9d, 0x2c9e}},
+};
+static const ItemBoxGfx kHudItemMoonPearl[2] = {
+  {{0x20f5, 0x20f5, 0x20f5, 0x20f5}},
+  {{0x2433, 0x2434, 0x2435, 0x2436}},
+};
+static const ItemBoxGfx kHudItemEmpty[1] = {
+  {{0x20f5, 0x20f5, 0x20f5, 0x20f5}},
+};
+static const ItemBoxGfx kHudItemSword[5] = {
+  {{0x20f5, 0x20f5, 0x20f5, 0x20f5}},
+  {{0x2c64, 0x2cce, 0x2c75, 0x3d25}},
+  {{0x2c8a, 0x2c65, 0x2474, 0x3d26}},
+  {{0x248a, 0x2465, 0x3c74, 0x2d48}},
+  {{0x288a, 0x2865, 0x2c74, 0x2d39}},
+};
+static const ItemBoxGfx kHudItemShield[4] = {
+  {{0x24f5, 0x24f5, 0x24f5, 0x24f5}},
+  {{0x2cfd, 0x6cfd, 0x2cfe, 0x6cfe}},
+  {{0x34ff, 0x74ff, 0x349f, 0x749f}},
+  {{0x2880, 0x2881, 0x288d, 0x288e}},
+};
+static const ItemBoxGfx kHudItemArmor[5] = {
+  {{0x3c68, 0x7c68, 0x3c78, 0x7c78}},
+  {{0x2c68, 0x6c68, 0x2c78, 0x6c78}},
+  {{0x2468, 0x6468, 0x2478, 0x6478}},
+};
+
+
+static const ItemBoxGfx * const kHudItemBoxGfxPtrs[] = {
+  kHudItemBow,
+  kHudItemBoomerang,
+  kHudItemHookshot,
+  kHudItemBombs,
+  kHudItemMushroom,
+  kHudItemFireRod,
+  kHudItemIceRod,
+  kHudItemBombos,
+  kHudItemEther,
+  kHudItemQuake,
+  kHudItemTorch,
+  kHudItemHammer,
+  kHudItemFlute,
+  kHudItemBugNet,
+  kHudItemBookMudora,
+  kHudItemBottles,
+  kHudItemCaneSomaria,
+  kHudItemCaneByrna,
+  kHudItemCape,
+  kHudItemMirror,
+  kHudItemGloves,
+  kHudItemBoots,
+  kHudItemFlippers,
+  kHudItemMoonPearl,
+  kHudItemEmpty,
+  kHudItemSword,
+  kHudItemShield,
+  kHudItemArmor,
+  kHudItemBottles,
+  kHudItemBottles,
+  kHudItemBottles,
+  kHudItemBottles,
+
+};
+static const uint16 kUpdateMagicPowerTilemap[17][4] = {
+  {0x3cf5, 0x3cf5, 0x3cf5, 0x3cf5},
+  {0x3cf5, 0x3cf5, 0x3cf5, 0x3c5f},
+  {0x3cf5, 0x3cf5, 0x3cf5, 0x3c4c},
+  {0x3cf5, 0x3cf5, 0x3cf5, 0x3c4d},
+  {0x3cf5, 0x3cf5, 0x3cf5, 0x3c4e},
+  {0x3cf5, 0x3cf5, 0x3c5f, 0x3c5e},
+  {0x3cf5, 0x3cf5, 0x3c4c, 0x3c5e},
+  {0x3cf5, 0x3cf5, 0x3c4d, 0x3c5e},
+  {0x3cf5, 0x3cf5, 0x3c4e, 0x3c5e},
+  {0x3cf5, 0x3c5f, 0x3c5e, 0x3c5e},
+  {0x3cf5, 0x3c4c, 0x3c5e, 0x3c5e},
+  {0x3cf5, 0x3c4d, 0x3c5e, 0x3c5e},
+  {0x3cf5, 0x3c4e, 0x3c5e, 0x3c5e},
+  {0x3c5f, 0x3c5e, 0x3c5e, 0x3c5e},
+  {0x3c4c, 0x3c5e, 0x3c5e, 0x3c5e},
+  {0x3c4d, 0x3c5e, 0x3c5e, 0x3c5e},
+  {0x3c4e, 0x3c5e, 0x3c5e, 0x3c5e},
+};
+static const uint16 kDungFloorIndicator_Gfx0[11] = { 0x2508, 0x2509, 0x2509, 0x250a, 0x250b, 0x250c, 0x250d, 0x251d, 0xe51c, 0x250e, 0x7f };
+static const uint16 kDungFloorIndicator_Gfx1[11] = { 0x2518, 0x2519, 0xa509, 0x251a, 0x251b, 0x251c, 0x2518, 0xa51d, 0xe50c, 0xa50e, 0x7f };
+
+
+void Hud_RefreshIcon() {
+  Hud_SearchForEquippedItem();
+  Hud_UpdateHud();
+  Hud_Rebuild();
+  overworld_map_state = 0;
+}
+
+uint8 CheckPalaceItemPosession() {
+  switch (cur_palace_index_x2 >> 1) {
+  case 2: return link_item_bow != 0;
+  case 3: return link_item_gloves != 0;
+  case 5: return link_item_hookshot != 0;
+  case 6: return link_item_hammer != 0;
+  case 7: return link_item_cane_somaria != 0;
+  case 8: return link_item_fire_rod != 0;
+  case 9: return link_armor != 0;
+  case 10: return link_item_moon_pearl != 0;
+  case 11: return link_item_gloves != 1;
+  case 12: return link_shield_type == 3;
+  case 13: return link_armor == 2;
+  default:
+    return 0;
+  }
+}
+
+// Returns the zero based index of the currently selected hud item,
+// or -1 if the item is item 0.
+static int Hud_GetItemPosition(int item) {
+  if (item <= 0)
+    return -1;
+  if (hud_inventory_order[0] != 0) {
+    int i = 0;
+    for (; i < kHudItemCount - 1 && hud_inventory_order[i] != item; i++) {}
+    return i;
+  } else {
+    return item ? item - 1 : item;
+  }
+}
+
+static void Hud_GotoPrevItem(uint8 *item, uint8 first_item_index) {
+  if (hud_inventory_order[0] != 0) {
+    int pos = Hud_GetItemPosition(*item);
+    *item = (pos == 0 && !first_item_index) ? 0 :
+        hud_inventory_order[(pos <= 0 ? kHudItemCount : pos) - 1];
+  } else {
+    *item = (*item > first_item_index) ? *item - 1 : kHudItemCount;
+  }
+}
+
+static void Hud_GotoNextItem(uint8 *item, uint8 first_item_index) {
+  if (hud_inventory_order[0] != 0) {
+    int i = Hud_GetItemPosition(*item);
+    *item = hud_inventory_order[((uint)i >= kHudItemCount - 1) ? 0 : i + 1];
+  } else {
+    *item = (*item < kHudItemCount) ? *item + 1 : first_item_index;
+  }
+}
+
+void Hud_FloorIndicator() {  // 8afd0c
+  uint16 a = hud_floor_changed_timer;
+  if (a == 0) {
+    Hud_RemoveSuperBombIndicator();
+    return;
+  }
+  a += 1;
+  if (a == 0xc0)
+    a = 0;
+  WORD(hud_floor_changed_timer) = a;
+
+  hud_tile_indices_buffer[0xf2 / 2] = 0x251e;
+  hud_tile_indices_buffer[0x134 / 2] = 0x251f;
+  hud_tile_indices_buffer[0x132 / 2] = 0x2520;
+  hud_tile_indices_buffer[0xf4 / 2] = 0x250f;
+
+  int k = 0, j;
+
+  if (!sign8(dung_cur_floor)) {
+    if (!WORD(dung_cur_floor) && dungeon_room_index != 2 && sram_progress_indicator < 2)
+      sound_effect_ambient = 3;
+    j = dung_cur_floor;
+  } else {
+    sound_effect_ambient = 5;
+    k++;
+    j = dung_cur_floor ^ 0xff;
+  }
+  hud_tile_indices_buffer[k + 0xf2 / 2] = kDungFloorIndicator_Gfx0[j];
+  hud_tile_indices_buffer[k + 0x132 / 2] = kDungFloorIndicator_Gfx1[j];
+  flag_update_hud_in_nmi++;
+}
+
+void Hud_RemoveSuperBombIndicator() {  // 8afd90
+  hud_tile_indices_buffer[0xf2 / 2] = 0x7f;
+  hud_tile_indices_buffer[0x132 / 2] = 0x7f;
+  hud_tile_indices_buffer[0xf4 / 2] = 0x7f;
+  hud_tile_indices_buffer[0x134 / 2] = 0x7f;
+}
+
+void Hud_SuperBombIndicator() {  // 8afda8
+  if (!super_bomb_indicator_unk1) {
+    if (sign8(super_bomb_indicator_unk2))
+      goto remove;
+    super_bomb_indicator_unk2--;
+    super_bomb_indicator_unk1 = 62;
+  }
+  super_bomb_indicator_unk1--;
+  if (sign8(super_bomb_indicator_unk2)) {
+remove:
+    super_bomb_indicator_unk2 = 0xff;
+    Hud_RemoveSuperBombIndicator();
+    return;
+  }
+
+  int r = super_bomb_indicator_unk2 % 10;
+  int q = super_bomb_indicator_unk2 / 10;
+
+  int j = sign8(r - 1) ? 9 : r - 1;
+  hud_tile_indices_buffer[0xf4 / 2] = kDungFloorIndicator_Gfx0[j];
+  hud_tile_indices_buffer[0x134 / 2] = kDungFloorIndicator_Gfx1[j];
+
+  j = sign8(q - 1) ? 10 : q - 1;
+  hud_tile_indices_buffer[0xf2 / 2] = kDungFloorIndicator_Gfx0[j];
+  hud_tile_indices_buffer[0x132 / 2] = kDungFloorIndicator_Gfx1[j];
+}
+
+static int MaxRupees() {
+  return enhanced_features0 & kFeatures0_CarryMoreRupees ? 9999 : 999;
+}
+
+void Hud_RefillLogic() {  // 8ddb92
+  if (overworld_map_state)
+    return;
+  if (link_magic_filler) {
+    if (link_magic_power >= 128) {
+      link_magic_power = 128;
+      link_magic_filler = 0;
+    } else {
+      link_magic_filler--;
+      link_magic_power++;
+      if ((frame_counter & 3) == 0 && sound_effect_1 == 0)
+        sound_effect_1 = 45;
+    }
+  }
+
+  uint16 a = link_rupees_actual;
+  if (a != link_rupees_goal) {
+    if (a >= link_rupees_goal) {
+      if ((int16)--a < 0)
+        link_rupees_goal = a = 0;
+    } else {
+      int m = MaxRupees();
+      if (++a > m)
+        link_rupees_goal = a = m;
+    }
+    link_rupees_actual = a;
+    if (sound_effect_1 == 0) {
+      if ((rupee_sfx_sound_delay++ & 7) == 0)
+        sound_effect_1 = 41;
+    } else {
+      rupee_sfx_sound_delay = 0;
+    }
+  } else {
+    rupee_sfx_sound_delay = 0;
+  }
+
+  if (link_bomb_filler) {
+    link_bomb_filler--;
+    if (link_item_bombs != kMaxBombsForLevel[link_bomb_upgrades])
+      link_item_bombs++;
+  }
+
+  if (link_arrow_filler) {
+    link_arrow_filler--;
+    if (link_num_arrows != kMaxArrowsForLevel[link_arrow_upgrades])
+      link_num_arrows++;
+    if (link_item_bow && (link_item_bow & 1) == 1) {
+      link_item_bow++;
+      Hud_RefreshIcon();
+    }
+  }
+
+  if (!flag_is_link_immobilized && !link_hearts_filler &&
+      link_health_current < kMaxHealthForLevel[link_health_capacity >> 3]) {
+    if (link_lowlife_countdown_timer_beep) {
+      link_lowlife_countdown_timer_beep--;
+    } else if (!sound_effect_1) {
+      if (!(enhanced_features0 & kFeatures0_DisableLowHealthBeep))
+        sound_effect_1 = 43;
+      link_lowlife_countdown_timer_beep = 32 - 1;
+    }
+  }
+
+  if (is_doing_heart_animation)
+    goto doing_animation;
+  if (link_hearts_filler) {
+    if (link_health_current < link_health_capacity) {
+      link_health_current += 8;
+      if (link_health_current >= link_health_capacity)
+        link_health_current = link_health_capacity;
+
+      if (sound_effect_2 == 0)
+        sound_effect_2 = 13;
+
+      link_hearts_filler -= 8;
+      is_doing_heart_animation++;
+      animate_heart_refill_countdown = 7;
+
+doing_animation:
+      Hud_Update_Magic();
+      Hud_Update_Inventory();
+      Hud_AnimateHeartRefill();
+      flag_update_hud_in_nmi++;
+      return;
+    }
+    link_health_current = link_health_capacity;
+    link_hearts_filler = 0;
+  }
+  Hud_Update_Hearts();
+  Hud_Update_Magic();
+  Hud_Update_Inventory();
+  flag_update_hud_in_nmi++;
+}
+
+void Hud_Module_Run() {  // 8ddd36
+  byte_7E0206++;
+  switch (overworld_map_state) {
+  case 0: Hud_ClearTileMap(); break;
+  case 1: Hud_Init(); break;
+  case 2: Hud_BringMenuDown(); break;
+  case 3: Hud_ChooseNextMode(); break;
+  case 4: Hud_NormalMenu(); break;
+  case 5: Hud_UpdateHud(); break;
+  case 6: Hud_CloseMenu(); break;
+  case 7: Hud_GotoBottleMenu(); break;
+  case 8: Hud_InitBottleMenu(); break;
+  case 9: Hud_ExpandBottleMenu(); break;
+  case 10: Hud_BottleMenu(); break;
+  case 11: Hud_EraseBottleMenu(); break;
+  case 12: Hud_RestoreNormalMenu(); break;
+  default:
+    assert(0);
+  }
+}
+
+void Hud_ClearTileMap() {  // 8ddd5a
+  uint16 *target = (uint16 *)&g_ram[0x1000];
+  for (int i = 0; i < 1024; i++)
+    target[i] = 0x207f;
+  sound_effect_2 = 17;
+  nmi_subroutine_index = 1;
+  BYTE(nmi_load_target_addr) = 0x22;
+  overworld_map_state++;
+}
+
+bool Hud_HaveAnyItems() { // new
+  for (int i = 0; i < 20; i++)
+    if ((&link_item_bow)[i])
+      return true;
+  return false;
+}
+
+void Hud_Init() {  // 8dddab
+  Hud_SearchForEquippedItem();
+  Hud_DrawYButtonItems();
+  Hud_DrawAbilityBox();
+  Hud_DrawProgressIcons();
+  Hud_DrawEquipmentBox();
+  Hud_DrawSelectedYButtonItem();
+
+  if (Hud_HaveAnyItems()) {   
+    // This causes bottle flicker because it's not early enough
+    int first_bottle = 0;
+    while (first_bottle < 4 && link_bottle_info[first_bottle] == 0)
+      first_bottle++;
+    if (first_bottle == 4)
+      link_item_bottle_index = 0;
+    else if (link_item_bottle_index == 0)
+      link_item_bottle_index = first_bottle + 1;
+
+    if (hud_cur_item == kHudItem_BottleOld && !kNewStyleInventory) {
+      timer_for_flashing_circle = 16;
+      Hud_DrawBottleMenu();
+    }
+  }
+
+  timer_for_flashing_circle = 16;
+  nmi_subroutine_index = 1;
+  BYTE(nmi_load_target_addr) = 0x22;
+  overworld_map_state++;
+}
+
+void Hud_BringMenuDown() {  // 8dde59
+  BG3VOFS_copy2 -= 8;
+  if (BG3VOFS_copy2 == 0xff18)
+    overworld_map_state++;
+}
+
+void Hud_ChooseNextMode() {  // 8dde6e
+  if (Hud_HaveAnyItems()) {
+    nmi_subroutine_index = 1;
+    BYTE(nmi_load_target_addr) = 0x22;
+
+    Hud_DrawSelectedYButtonItem();
+
+    // Pick either the bottle state or normal one
+    overworld_map_state = (hud_cur_item == kHudItem_BottleOld && !kNewStyleInventory) ? 10 : 4;
+  } else {
+    if (filtered_joypad_H)
+      overworld_map_state = 5;
+  }
+}
+
+static bool Hud_DoWeHaveThisItem(uint8 item) {  // 8ddeb0
+  if (item == 0)
+    return true;  // for the x item, 0 is valid
+
+  if (item == kHudItem_Flute && kNewStyleInventory)
+    return link_item_flute >= 2;
+
+  if (item == kHudItem_Shovel && kNewStyleInventory)
+    return link_item_flute >= 1;
+
+  if (item >= kHudItem_Bottle1)
+    return link_bottle_info[item - kHudItem_Bottle1] != 0;
+
+  return (&link_item_bow)[item - 1] != 0;
+}
+
+static void Hud_EquipPrevItem(uint8 *item) {  // 8dded9
+  do {
+    Hud_GotoPrevItem(item, item == &hud_cur_item);
+  } while (!Hud_DoWeHaveThisItem(*item));
+}
+
+static void Hud_EquipNextItem(uint8 *item) {  // 8ddee2
+  do {
+    Hud_GotoNextItem(item, item == &hud_cur_item);
+  } while (!Hud_DoWeHaveThisItem(*item));
+}
+
+static void Hud_EquipItemAbove(uint8 *item) {  // 8ddeeb
+  do {
+    for(int i = 0; i < (kNewStyleInventory ? 6 : 5); i++)
+      Hud_GotoPrevItem(item, 1);
+  } while (!Hud_DoWeHaveThisItem(*item));
+}
+
+static void Hud_EquipItemBelow(uint8 *item) {  // 8ddf00
+  int num = *item == 0 ? 1 : (kNewStyleInventory ? 6 : 5);
+  do {
+    for (int i = 0; i < num; i++)
+      Hud_GotoNextItem(item, 1);
+  } while (!Hud_DoWeHaveThisItem(*item));
+}
+
+int GetCurrentItemButtonIndex() {
+  if (enhanced_features0 & kFeatures0_SwitchLR) {
+    return (joypad1L_last & kJoypadL_X) ? 1 :
+           (joypad1L_last & kJoypadL_L) ? 2 :
+           (joypad1L_last & kJoypadL_R) ? 3 : 0;
+  }
+  return 0;
+}
+
+uint8 *GetCurrentItemButtonPtr(int i) {
+  return (i == 0) ? &hud_cur_item : 
+         (i == 1) ? &hud_cur_item_x : 
+         (i == 2) ? &hud_cur_item_l : &hud_cur_item_r;
+}
+
+void Hud_NormalMenu() {  // 8ddf15
+  timer_for_flashing_circle++;
+  if (!BYTE(joypad1H_last))
+    BYTE(hud_tmp1) = 0;
+
+  if (filtered_joypad_H & kJoypadH_Start) {
+    overworld_map_state = 5;
+    sound_effect_2 = 18;
+    return;
+  }
+
+  // Allow select to open the save/exit thing
+  if (joypad1H_last & kJoypadH_Select && sram_progress_indicator) {
+    BG3VOFS_copy2 = -8;
+    Hud_CloseMenu();
+    DisplaySelectMenu();
+    return;
+  }
+
+  if (joypad1H_last & kJoypadH_Y && !(joypad1L_last & kJoypadL_X) && (enhanced_features0 & kFeatures0_SwitchLR)) {
+    if (filtered_joypad_H & kJoypadH_Up) {
+      Hud_ReorderItem(kNewStyleInventory ? -6 : -5);
+    } else if (filtered_joypad_H & kJoypadH_Down) {
+      Hud_ReorderItem(kNewStyleInventory ? 6 : 5);
+    } else if (filtered_joypad_H & kJoypadH_Left) {
+      Hud_ReorderItem(-1);
+    } else if (filtered_joypad_H & kJoypadH_Right) {
+      Hud_ReorderItem(1);
+    }
+  } else if (!BYTE(hud_tmp1)) {
+    // If Special Key button is down, then move their circle
+    int btn_index = GetCurrentItemButtonIndex();
+    uint8 *item_p = GetCurrentItemButtonPtr(btn_index);
+    uint16 old_item = *item_p;
+    if (filtered_joypad_H & kJoypadH_Up) {
+      Hud_EquipItemAbove(item_p);
+    } else if (filtered_joypad_H & kJoypadH_Down) {
+      Hud_EquipItemBelow(item_p);
+    } else if (filtered_joypad_H & kJoypadH_Left) {
+      Hud_EquipPrevItem(item_p);
+    } else if (filtered_joypad_H & kJoypadH_Right) {
+      Hud_EquipNextItem(item_p);
+    }
+    BYTE(hud_tmp1) = filtered_joypad_H;
+    if (*item_p != old_item) {
+      timer_for_flashing_circle = 16;
+      sound_effect_2 = 32;
+    }
+  }
+  Hud_DrawYButtonItems();
+  Hud_DrawSelectedYButtonItem();
+  if (hud_cur_item == kHudItem_BottleOld && !kNewStyleInventory)
+    overworld_map_state = 7;
+
+  nmi_subroutine_index = 1;
+  BYTE(nmi_load_target_addr) = 0x22;
+  //g_ram[0x15d0] = 0;
+}
+
+void Hud_UpdateHud() {  // 8ddfa9
+  overworld_map_state++;
+  Hud_Rebuild();
+  Hud_UpdateEquippedItem();
+}
+
+uint8 Hud_LookupInventoryItem(uint8 item) {
+  static const uint8 kHudItemToItemOrg[21] = {
+    0,
+    3,  2, 14, 1,  10,  5,
+    6, 15, 16, 17,  9,  4,
+    8,  7, 12, 11, 18, 13,
+    19, 20,
+  };
+
+  static const uint8 kHudItemToItemNew[25] = {
+    0,
+    3,  2, 14, 1,  10,  5,
+    6, 15, 16, 17,  9,  4,
+    8,  7, 12, 21, 18, 13, // 8 is ocarina / shovel combined. moved shovel to 21.
+    19, 20,11, 11, 11, 11, // 11 means bottle
+  };
+  return kNewStyleInventory ? kHudItemToItemNew[item] : kHudItemToItemOrg[item];
+}
+
+void Hud_UpdateEquippedItem() {  // 8ddfaf
+  if (hud_cur_item >= kHudItem_Bottle1)
+    link_item_bottle_index = hud_cur_item - kHudItem_Bottle1 + 1;
+
+  assert(hud_cur_item < 25);
+  current_item_y = Hud_LookupInventoryItem(hud_cur_item);
+}
+
+void Hud_CloseMenu() {  // 8ddfba
+  BG3VOFS_copy2 += 8;
+  if (BG3VOFS_copy2)
+    return;
+  Hud_Rebuild();
+  overworld_map_state = 0;
+  submodule_index = 0;
+  main_module_index = saved_module_for_menu;
+  if (submodule_index)
+    Hud_RestoreTorchBackground();
+  if (current_item_y != 5 && current_item_y != 6) {
+    eq_debug_variable = 2;
+    link_debug_value_1 = 0;
+  } else {
+    assert(!link_debug_value_1);
+    eq_debug_variable = 0;
+  }
+}
+
+void Hud_GotoBottleMenu() {  // 8ddffb
+  bottle_menu_expand_row = 0;
+  overworld_map_state++;
+}
+
+void Hud_InitBottleMenu() {  // 8de002
+  int r = bottle_menu_expand_row;
+  uint16 *dst = uvram_screen.row[0].col + (kNewStyleInventory ? 1 : 0);
+  for (int i = 21; i <= 30; i++)
+    dst[HUDXY(i, 11 + r)] = 0x207f;
+
+  if (++bottle_menu_expand_row == 19) {
+    overworld_map_state++;
+    bottle_menu_expand_row = 17;
+  }
+  nmi_subroutine_index = 1;
+  BYTE(nmi_load_target_addr) = 0x22;
+}
+
+void Hud_ExpandBottleMenu() {  // 8de08c
+  static const uint16 kBottleMenuTop[] = { 0x28FB, 0x28F9, 0x28F9, 0x28F9, 0x28F9, 0x28F9, 0x28F9, 0x28F9, 0x28F9, 0x68FB };
+  static const uint16 kBottleMenuTop2[] = { 0x28FC, 0x24F5, 0x24F5, 0x24F5, 0x24F5, 0x24F5, 0x24F5, 0x24F5, 0x24F5, 0x68FC };
+  static const uint16 kBottleMenuBottom[] = { 0xA8FB, 0xA8F9, 0xA8F9, 0xA8F9, 0xA8F9, 0xA8F9, 0xA8F9, 0xA8F9, 0xA8F9, 0xE8FB };
+
+  int r = bottle_menu_expand_row;
+  uint16 *dst = uvram_screen.row[0].col + (kNewStyleInventory ? 1 : 0);
+  memcpy(&dst[HUDXY(21, 11 + r)], kBottleMenuTop, sizeof(uint16) * 10);
+  memcpy(&dst[HUDXY(21, 12 + r)], kBottleMenuTop2, sizeof(uint16) * 10);
+  memcpy(&dst[HUDXY(21, 29)], kBottleMenuBottom, sizeof(uint16) * 10);
+
+  if (sign8(--bottle_menu_expand_row))
+    overworld_map_state++;
+  nmi_subroutine_index = 1;
+  BYTE(nmi_load_target_addr) = 0x22;
+}
+
+void Hud_BottleMenu() {  // 8de0df
+  timer_for_flashing_circle++;
+  if (filtered_joypad_H & kJoypadH_Start) {
+    sound_effect_2 = 18;
+    overworld_map_state = 5;
+  } else if (filtered_joypad_H & (kJoypadH_Left | kJoypadH_Right)) {
+    if (filtered_joypad_H & kJoypadH_Left) {
+      Hud_EquipPrevItem(&hud_cur_item);
+    } else {
+      Hud_EquipNextItem(&hud_cur_item);
+    }
+    timer_for_flashing_circle = 16;
+    sound_effect_2 = 32;
+    Hud_DrawYButtonItems();
+    Hud_DrawSelectedYButtonItem();
+    overworld_map_state++;
+    bottle_menu_expand_row = 0;
+    return;
+  }
+  Hud_DrawBottleMenu_Update();
+  if (filtered_joypad_H & (kJoypadH_Down | kJoypadH_Up)) {
+    uint8 old_val = link_item_bottle_index - 1, val = old_val;
+
+    if (filtered_joypad_H & kJoypadH_Up) {
+      do {
+        val = (val - 1) & 3;
+      } while (!link_bottle_info[val]);
+    } else {
+      do {
+        val = (val + 1) & 3;
+      } while (!link_bottle_info[val]);
+    }
+    if (old_val != val) {
+      link_item_bottle_index = val + 1;
+      timer_for_flashing_circle = 16;
+      sound_effect_2 = 32;
+    }
+  }
+}
+
+static void Hud_DrawItem(uint16 *dst, const ItemBoxGfx *src) {  // new
+  dst[0] = src->v[0];
+  dst[1] = src->v[1];
+  dst[32] = src->v[2];
+  dst[33] = src->v[3];
+}
+
+static void Hud_DrawNxN(uint16 *dst, const uint16 *src, int w, int h) {  // new
+  for (int y = 0; y < h; y++) {
+    memcpy(dst, src, sizeof(uint16) * w);
+    dst += 32, src += w;
+  }
+}
+
+static void Hud_Copy2x2(uint16 *dst, uint16 *src) {  // new
+  dst[0] = src[0];
+  dst[1] = src[1];
+  dst[32] = src[32];
+  dst[33] = src[33];
+}
+
+static void Hud_DrawBox(uint16 *dst, int x1, int y1, int x2, int y2, uint8 palette) {  // new
+  uint16 t;
+
+  t = 0x20fb | palette << 10;
+  dst[HUDXY(x1, y1)] = t;
+  dst[HUDXY(x2, y1)] = t + 0x4000;
+  dst[HUDXY(x1, y2)] = t + 0x8000;
+  dst[HUDXY(x2, y2)] = t + 0xc000;
+
+  t = 0x20fc | palette << 10;
+  for (int y = y1 + 1; y < y2; y++) {
+    dst[HUDXY(x1, y)] = t;
+    dst[HUDXY(x2, y)] = t + 0x4000;
+  }
+
+  t = 0x20f9 | palette << 10;
+  for (int x = x1 + 1; x < x2; x++) {
+    dst[HUDXY(x, y1)] = t;
+    dst[HUDXY(x, y2)] = t + 0x8000;
+  }
+
+  for (int y = y1 + 1; y < y2; y++) {
+    for (int x = x1 + 1; x < x2; x++)
+      dst[HUDXY(x, y)] = 0x24F5;
+  }
+}
+
+static void Hud_DrawFlashingCircle(uint16 *p, uint8 palette) {  // new
+  int pp = palette << 10;
+  p[HUDXY(0, -1)] = pp | 0x2061;
+  p[HUDXY(1, -1)] = pp | 0x2061 | 0x4000;
+  p[HUDXY(-1, 0)] = pp | 0x2070;
+  p[HUDXY(2, 0)] = pp | 0x2070 | 0x4000;
+  p[HUDXY(-1, 1)] = pp | 0xa070;
+  p[HUDXY(2, 1)] = pp | 0xa070 | 0x4000;
+  p[HUDXY(0, 2)] = pp | 0xa061;
+  p[HUDXY(1, 2)] = pp | 0xa061 | 0x4000;
+  p[HUDXY(-1, -1)] = pp | 0x2060;
+  p[HUDXY(2, -1)] = pp | 0x2060 | 0x4000;
+  p[HUDXY(2, 2)] = pp | 0x2060 | 0xC000;
+  p[HUDXY(-1, 2)] = pp | 0x2060 | 0x8000;
+}
+
+void Hud_DrawBottleMenu() {  // 8def67
+  uint16 *dst = uvram_screen.row[0].col + (kNewStyleInventory ? 1 : 0);
+  Hud_DrawBox(dst, 21, 11, 30, 29, 2);
+  for (int i = 0; i < 4; i++)
+    Hud_DrawItem(dst + HUDXY(25, 13 + i * 4), &kHudItemBottles[link_bottle_info[i]]);
+  const ItemBoxGfx *p = &kHudItemBottles[link_bottle_info[link_item_bottle_index - 1]];
+  Hud_DrawItem(uvram_screen.row[0].col + kHudItemInVramPtr[15], p);
+  if (timer_for_flashing_circle & 0x10)
+    Hud_DrawFlashingCircle(dst + HUDXY(25, 13 + (link_item_bottle_index - 1) * 4), 7);
+}
+
+
+void Hud_DrawBottleMenu_Update() {  // 8de17f
+  Hud_DrawBottleMenu();
+  Hud_DrawSelectedYButtonItem();
+
+  nmi_subroutine_index = 1;
+  BYTE(nmi_load_target_addr) = 0x22;
+}
+
+void Hud_EraseBottleMenu() {  // 8de2fd
+  uint16 *dst = uvram_screen.row[0].col + (kNewStyleInventory ? 1 : 0);
+  int r = bottle_menu_expand_row;
+  for (int i = 0; i < 10; i++)
+    dst[HUDXY(21 + i, 11 + r)] = 0x207f;
+  if (++bottle_menu_expand_row == 19)
+    overworld_map_state++;
+  nmi_subroutine_index = 1;
+  BYTE(nmi_load_target_addr) = 0x22;
+}
+
+void Hud_RestoreNormalMenu() {  // 8de346
+  Hud_DrawProgressIcons();
+  Hud_DrawEquipmentBox();
+  overworld_map_state = 4;
+  nmi_subroutine_index = 1;
+  BYTE(nmi_load_target_addr) = 0x22;
+}
+
+void Hud_SearchForEquippedItem() {  // 8de399
+  if (!Hud_HaveAnyItems()) {
+    hud_cur_item = 0;
+    hud_var1 = 0;
+  } else {
+    if (!hud_cur_item)
+      hud_cur_item = 1;
+    if (!Hud_DoWeHaveThisItem(hud_cur_item))
+      Hud_EquipNextItem(&hud_cur_item);
+  }
+}
+
+static const ItemBoxGfx *Hud_GetIconForItem(int i) {
+  if (i <= 0)
+    return kHudItemEmpty;
+
+  if (i >= kHudItem_Bottle1)
+    return &kHudItemBottles[link_bottle_info[i - kHudItem_Bottle1]];
+  if (i == kHudItem_Shovel && kNewStyleInventory)
+    return &kHudItemFlute[link_item_flute >= 1];
+
+  uint8 item_val = (&link_item_bow)[i - 1];
+  if (i == kHudItem_Bombs) // bombs
+    item_val = (item_val != 0);
+  else if (i == kHudItem_BottleOld && !kNewStyleInventory)
+    item_val = link_item_bottle_index ? link_bottle_info[link_item_bottle_index - 1] : 0;
+  return &kHudItemBoxGfxPtrs[i - 1][item_val];
+}
+
+static void CopyTilesForSwitchLR(int switch_lr) {
+#define PV(a0,a1,a2,a3,a4,a5,a6,a7)  ((a0 & 1) << 7 | (a0 >> 1 & 1) << 15 | (a1 & 1) << 6 | (a1 >> 1 & 1) << 14 | (a2 & 1) <<5 | (a2 >> 1&1) <<13 | (a3 & 1) << 4 | (a3>> 1 & 1) << 12 | (a4 & 1) << 3 | (a4 >> 1 & 1) << 11 | (a5 & 1) << 2 | (a5 >> 1 & 1) << 10 | (a6 & 1) << 1 | (a6 >> 1 & 1) << 9 | (a7 & 1) << 0 | (a7 >> 1 & 1) << 8) 
+    
+  if (switch_lr == 3) {
+    static const uint16 kBytesForNewTile0xC_TopOfR[8] = {
+      PV(1,1,1,1,1,1,3,3),
+      PV(1,1,1,1,1,1,1,3),
+      PV(1,1,1,1,1,1,1,1),
+      PV(1,1,1,3,3,1,1,1),
+      PV(1,1,1,3,3,1,1,1),
+      PV(1,1,1,3,3,1,1,1),
+      PV(1,1,1,3,3,1,1,1),
+      PV(1,1,1,1,1,1,1,3)
+    };
+    memcpy(&g_zenv.vram[0x7000 + 0xc * 8], kBytesForNewTile0xC_TopOfR, sizeof(kBytesForNewTile0xC_TopOfR));
+
+    static const uint16 kBytesForNewTile0xD_BottomofR[8] = {
+      PV(1,1,1,1,1,1,3,3),
+      PV(1,1,1,3,1,1,1,3),
+      PV(1,1,1,3,3,1,1,1),
+      PV(1,1,1,3,3,1,1,1),
+      PV(1,1,1,3,3,1,1,1),
+      PV(1,1,1,3,3,1,1,1),
+      PV(1,1,1,3,3,1,1,1),
+      PV(1,1,1,3,3,1,1,1)
+    };
+    memcpy(&g_zenv.vram[0x7000 + 0xd * 8], kBytesForNewTile0xD_BottomofR, sizeof(kBytesForNewTile0xD_BottomofR));
+  } else if (switch_lr == 2) {
+    static const uint16 kBytesForNewTile0xE_TopOfL[8] = {
+      PV(1,1,1,3,3,3,3,3),
+      PV(1,1,1,3,3,3,3,3),
+      PV(1,1,1,3,3,3,3,3),
+      PV(1,1,1,3,3,3,3,3),
+      PV(1,1,1,3,3,3,3,3),
+      PV(1,1,1,3,3,3,3,3),
+      PV(1,1,1,3,3,3,3,3),
+      PV(1,1,1,3,3,3,3,3)
+    };
+    memcpy(&g_zenv.vram[0x7000 + 0xe * 8], kBytesForNewTile0xE_TopOfL, sizeof(kBytesForNewTile0xE_TopOfL));
+
+    static const uint16 kBytesForNewTile0xF_BottomofL[8] = {
+      PV(1,1,1,3,3,3,3,3),
+      PV(1,1,1,3,3,3,3,3),
+      PV(1,1,1,3,3,3,3,3),
+      PV(1,1,1,3,3,3,3,3),
+      PV(1,1,1,3,3,3,3,3),
+      PV(1,1,1,1,1,1,1,1),
+      PV(1,1,1,1,1,1,1,1),
+      PV(1,1,1,1,1,1,1,1)
+    };
+    memcpy(&g_zenv.vram[0x7000 + 0xf * 8], kBytesForNewTile0xF_BottomofL, sizeof(kBytesForNewTile0xF_BottomofL));
+  }
+#undef PV
+}
+
+static const uint8 kSwitchLR_palettes[] = { 7, 3, 4, 4 };
+
+void Hud_DrawYButtonItems() {  // 8de3d9
+  uint16 *dst = uvram_screen.row[0].col;
+  int x = kNewStyleInventory ? 0 : 1;
+
+  int btn_index = GetCurrentItemButtonIndex();
+  CopyTilesForSwitchLR(btn_index);
+  Hud_DrawBox(dst, x, 5, 20 - x, 19, kSwitchLR_palettes[btn_index]);
+  static const uint16 kEquipmentLetterTiles[4][2] = {
+    {0x3CF0, 0x3CF1},  // Y
+    {0x2CF0, 0x2CF0 | 0x8000},  // X
+    {0x200E | 4 << 10, 0x200F | 4 << 10},  // L
+    {0x200C | 4 << 10, 0x200D | 4 << 10}   // R
+   };
+
+  if (!kNewStyleInventory) {
+    dst[HUDXY(2, 6)] = kEquipmentLetterTiles[btn_index][0];
+    dst[HUDXY(2, 7)] = kEquipmentLetterTiles[btn_index][1]; 
+  }
+  dst[HUDXY(x + 2, 5)] = 0x246E;
+  dst[HUDXY(x + 3, 5)] = 0x246F;
+
+  for (int i = 0; i < kHudItemCount; i++) {
+    int j = hud_inventory_order[i];
+    Hud_DrawItem(dst + kHudItemInVramPtr[i], Hud_GetIconForItem(j == 0 ? i + 1: j) );
+  }
+}
+
+void Hud_DrawAbilityBox() {  // 8de6b6
+  static const uint16 kHudAbilityText[80] = {
+    0x2cf5, 0x2cf5, 0x2cf5, 0x2cf5, 0x2cf5, 0x2d5b, 0x2d58, 0x2d55, 0x2d63, 0x2d27,
+    0x2cf5, 0x2cf5, 0x2cf5, 0x2cf5, 0x2cf5, 0x2cf5, 0x2d61, 0x2d54, 0x2d50, 0x2d53,
+    0x2cf5, 0x2cf5, 0x2cf5, 0x2cf5, 0x2cf5, 0x2cf5, 0x2d63, 0x2d50, 0x2d5b, 0x2d5a,
+    0x207f, 0x207f, 0x207f, 0x207f, 0x207f, 0x207f, 0x207f, 0x207f, 0x207f, 0x207f,
+    0x2cf5, 0x2cf5, 0x2c2e, 0x2cf5, 0x2cf5, 0x2d5f, 0x2d64, 0x2d5b, 0x2d5b, 0x2cf5,
+    0x2cf5, 0x2cf5, 0x2cf5, 0x2cf5, 0x2cf5, 0x2cf5, 0x2d61, 0x2d64, 0x2d5d, 0x2cf5,
+    0x2cf5, 0x2cf5, 0x2cf5, 0x2cf5, 0x2cf5, 0x2cf5, 0x2d62, 0x2d66, 0x2d58, 0x2d5c,
+    0x2cf5, 0x2cf5, 0x2cf5, 0x207f, 0x207f, 0x2c01, 0x2c18, 0x2c28, 0x207f, 0x207f,
+  };
+  static const uint16 kHudGlovesText[20] = {
+    0x2cf5, 0x2cf5, 0x2cf5, 0x2cf5, 0x2cf5, 0x2d5b, 0x2d58, 0x2d55, 0x2d63, 0x2d28,
+    0x2cf5, 0x2cf5, 0x2cf5, 0x2cf5, 0x2cf5, 0x2d5b, 0x2d58, 0x2d55, 0x2d63, 0x2d29,
+  };
+  uint16 *dst = uvram_screen.row[0].col;
+  int x = kNewStyleInventory ? 0 : 1;
+
+  Hud_DrawBox(dst, x, 21, 19, 29, 1);
+
+  uint8 flags = link_ability_flags;
+  for (int i = 0; i < 2; i++, flags <<= 1) {
+    for (int j = 0; j < 3; j++, flags <<= 1) {
+      if (flags & 0x80)
+        Hud_DrawNxN(dst + HUDXY(4 + j * 5, 22 + i * 2), kHudAbilityText + i * 40 + j * 10, 5, 2);
+    }
+  }
+  // A
+  if (!kNewStyleInventory) {
+    dst[HUDXY(2, 22)] = 0xA4F0;
+    dst[HUDXY(2, 23)] = 0x24F2;
+  }
+  // DO text
+  dst[HUDXY(x + 2, 21)] = 0x2482;
+  dst[HUDXY(x + 3, 21)] = 0x2483;
+
+  Hud_DrawItem(dst + HUDXY(8, 27), &kHudItemGloves[link_item_gloves]);
+  Hud_DrawItem(dst + HUDXY(4, 27), &kHudItemBoots[link_item_boots]);
+  Hud_DrawItem(dst + HUDXY(12, 27), &kHudItemFlippers[link_item_flippers]);
+  Hud_DrawItem(dst + HUDXY(16, 27), &kHudItemMoonPearl[link_item_moon_pearl]);
+  if (link_item_gloves)
+    Hud_DrawNxN(dst + HUDXY(4, 22), kHudGlovesText + (link_item_gloves != 1) * 10, 5, 2);
+}
+
+void Hud_DrawProgressIcons() {  // 8de9c8
+  if (sram_progress_indicator < 3)
+    Hud_DrawProgressIcons_Pendants();
+  else
+    Hud_DrawProgressIcons_Crystals();
+}
+
+void Hud_DrawProgressIcons_Pendants() {  // 8de9d3
+  static const uint16 kProgressIconPendantsBg[90] = {
+    0x28fb, 0x28f9, 0x28f9, 0x28f9, 0x28f9, 0x28f9, 0x28f9, 0x28f9, 0x28f9, 0x68fb,
+    0x28fc, 0x2521, 0x2522, 0x2523, 0x2524, 0x253f, 0x24f5, 0x24f5, 0x24f5, 0x68fc,
+    0x28fc, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x68fc,
+    0x28fc, 0x24f5, 0x24f5, 0x24f5, 0x213b, 0x213c, 0x24f5, 0x24f5, 0x24f5, 0x68fc,
+    0x28fc, 0x24f5, 0x24f5, 0x24f5, 0x213d, 0x213e, 0x24f5, 0x24f5, 0x24f5, 0x68fc,
+    0x28fc, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x68fc,
+    0x28fc, 0x24f5, 0x213b, 0x213c, 0x24f5, 0x24f5, 0x213b, 0x213c, 0x24f5, 0x68fc,
+    0x28fc, 0x24f5, 0x213d, 0x213e, 0x24f5, 0x24f5, 0x213d, 0x213e, 0x24f5, 0x68fc,
+    0xa8fb, 0xa8f9, 0xa8f9, 0xa8f9, 0xa8f9, 0xa8f9, 0xa8f9, 0xa8f9, 0xa8f9, 0xe8fb,
+  };
+  static const ItemBoxGfx kHudPendants0[2] = {
+    {{0x313b, 0x313c, 0x313d, 0x313e}},
+    {{0x252b, 0x252c, 0x252d, 0x252e}},
+  };
+  static const ItemBoxGfx kHudPendants1[2] = {
+    {{0x313b, 0x313c, 0x313d, 0x313e}},
+    {{0x2d2b, 0x2d2c, 0x2d2d, 0x2d2e}},
+  };
+  static const ItemBoxGfx kHudPendants2[2] = {
+    {{0x313b, 0x313c, 0x313d, 0x313e}},
+    {{0x3d2b, 0x3d2c, 0x3d2d, 0x3d2e}},
+  };
+  uint16 *dst = uvram_screen.row[0].col + (kNewStyleInventory ? HUDXY(22, 11) : HUDXY(21, 11));
+  Hud_DrawNxN(dst, kProgressIconPendantsBg, 10, 9);
+  Hud_DrawItem(dst + HUDXY(4, 3), &kHudPendants0[(link_which_pendants >> 0) & 1]);
+  Hud_DrawItem(dst + HUDXY(2, 6), &kHudPendants1[(link_which_pendants >> 1) & 1]);
+  Hud_DrawItem(dst + HUDXY(6, 6), &kHudPendants2[(link_which_pendants >> 2) & 1]);
+}
+
+void Hud_DrawProgressIcons_Crystals() {  // 8dea62
+  static const uint16 kProgressIconCrystalsBg[90] = {
+    0x28fb, 0x28f9, 0x28f9, 0x28f9, 0x28f9, 0x28f9, 0x28f9, 0x28f9, 0x28f9, 0x68fb,
+    0x28fc, 0x252f, 0x2534, 0x2535, 0x2536, 0x2537, 0x24f5, 0x24f5, 0x24f5, 0x68fc,
+    0x28fc, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x68fc,
+    0x28fc, 0x24f5, 0x24f5, 0x3146, 0x3147, 0x3146, 0x3147, 0x24f5, 0x24f5, 0x68fc,
+    0x28fc, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x68fc,
+    0x28fc, 0x24f5, 0x3146, 0x3147, 0x3146, 0x3147, 0x3146, 0x3147, 0x24f5, 0x68fc,
+    0x28fc, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x68fc,
+    0x28fc, 0x24f5, 0x24f5, 0x3146, 0x3147, 0x3146, 0x3147, 0x24f5, 0x24f5, 0x68fc,
+    0xa8fb, 0xa8f9, 0xa8f9, 0xa8f9, 0xa8f9, 0xa8f9, 0xa8f9, 0xa8f9, 0xa8f9, 0xe8fb,
+  };
+
+  uint16 *dst = uvram_screen.row[0].col + (kNewStyleInventory ? HUDXY(22, 11) : HUDXY(21, 11));
+  Hud_DrawNxN(dst, kProgressIconCrystalsBg, 10, 9);
+
+  uint8 f = link_has_crystals;
+  if (f & 1) {
+    dst[HUDXY(3, 3)] = 0x2D44;
+    dst[HUDXY(4, 3)] = 0x2D45;
+  }
+  if (f & 2) {
+    dst[HUDXY(5, 3)] = 0x2D44;
+    dst[HUDXY(6, 3)] = 0x2D45;
+  }
+  if (f & 4) {
+    dst[HUDXY(2, 5)] = 0x2D44;
+    dst[HUDXY(3, 5)] = 0x2D45;
+  }
+  if (f & 8) {
+    dst[HUDXY(4, 5)] = 0x2D44;
+    dst[HUDXY(5, 5)] = 0x2D45;
+  }
+  if (f & 16) {
+    dst[HUDXY(6, 5)] = 0x2D44;
+    dst[HUDXY(7, 5)] = 0x2D45;
+  }
+  if (f & 32) {
+    dst[HUDXY(3, 7)] = 0x2D44;
+    dst[HUDXY(4, 7)] = 0x2D45;
+  }
+  if (f & 64) {
+    dst[HUDXY(5, 7)] = 0x2D44;
+    dst[HUDXY(6, 7)] = 0x2D45;
+  }
+}
+
+void Hud_DrawSelectedYButtonItem() {  // 8deb3a
+  static const uint16 kHudBottlesItemText[128] = {
+    0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x255c, 0x2564, 0x2562, 0x2557, 0x2561, 0x255e, 0x255e, 0x255c,
+    0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x2551, 0x255e, 0x2563, 0x2563, 0x255b, 0x2554, 0x24f5, 0x24f5,
+    0x255b, 0x2558, 0x2555, 0x2554, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x255c, 0x2554, 0x2553, 0x2558, 0x2552, 0x2558, 0x255d, 0x2554,
+    0x255c, 0x2550, 0x2556, 0x2558, 0x2552, 0x24f5, 0x24f5, 0x24f5, 0x255c, 0x2554, 0x2553, 0x2558, 0x2552, 0x2558, 0x255d, 0x2554,
+    0x2552, 0x2564, 0x2561, 0x2554, 0x256a, 0x2550, 0x255b, 0x255b, 0x255c, 0x2554, 0x2553, 0x2558, 0x2552, 0x2558, 0x255d, 0x2554,
+    0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x2555, 0x2550, 0x2554, 0x2561, 0x2558, 0x2554, 0x24f5, 0x24f5,
+    0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x2551, 0x2554, 0x2554, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5,
+    0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x2556, 0x255e, 0x255e, 0x2553, 0x24f5, 0x2551, 0x2554, 0x2554,
+  };
+  static const uint16 kHudMushroomItemText[16] = {
+    0x255c, 0x2550, 0x2556, 0x2558, 0x2552, 0x24f5, 0x24f5, 0x24f5,
+    0x24f5, 0x255f, 0x255e, 0x2566, 0x2553, 0x2554, 0x2561, 0x24f5,
+  };
+  static const uint16 kHudFluteItemText[32] = {
+    0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x2555, 0x255b, 0x2564, 0x2563, 0x2554, 0x24f5, 0x24f5, 0x24f5,
+    0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x2555, 0x255b, 0x2564, 0x2563, 0x2554, 0x24f5, 0x24f5, 0x24f5
+  };
+  static const uint16 kHudMirrorItemText[16] = {
+    0x255c, 0x2550, 0x2556, 0x2558, 0x2552, 0x24f5, 0x24f5, 0x24f5,
+    0x24f5, 0x24f5, 0x255c, 0x2558, 0x2561, 0x2561, 0x255e, 0x2561
+  };
+  static const uint16 kHudBowItemText[48] = {
+    0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x256b, 0x256c, 0x256e, 0x256f, 0x257c, 0x257d, 0x257e, 0x257f,
+    0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x256b, 0x256c, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5,
+    0x256b, 0x256c, 0x24f5, 0x256e, 0x256f, 0x24f5, 0x24f5, 0x24f5, 0x2578, 0x2579, 0x257a, 0x257b, 0x257c, 0x257d, 0x257e, 0x257f,
+  };
+  static const uint16 kHudItemText[320] = {
+    0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x256b, 0x256c, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5,
+    0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x2570, 0x2571, 0x2572, 0x2573, 0x2574, 0x2575, 0x2576, 0x2577,
+    0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x2557, 0x255e, 0x255e, 0x255a, 0x2562, 0x2557, 0x255e, 0x2563,
+    0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x2551, 0x255e, 0x255c, 0x2551, 0x24f5, 0x24f5, 0x24f5, 0x24f5,
+    0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x255c, 0x2564, 0x2562, 0x2557, 0x2561, 0x255e, 0x255e, 0x255c,
+    
+    0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x2555, 0x2558, 0x2561, 0x2554, 0x2561, 0x255e, 0x2553, 0x24f5,
+    0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x2558, 0x2552, 0x2554, 0x2561, 0x255e, 0x2553, 0x24f5, 0x24f5,
+    0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x2551, 0x255e, 0x255c, 0x2551, 0x255e, 0x2562, 0x24f5, 0x24f5,
+    0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x2554, 0x2563, 0x2557, 0x2554, 0x2561, 0x24f5, 0x24f5, 0x24f5,
+    0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x2560, 0x2564, 0x2550, 0x255a, 0x2554, 0x24f5, 0x24f5, 0x24f5,
+    0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x255b, 0x2550, 0x255c, 0x255f, 0x24f5, 0x24f5, 0x24f5, 0x24f5,
+    0x255c, 0x2550, 0x2556, 0x2558, 0x2552, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x2557, 0x2550, 0x255c, 0x255c, 0x2554, 0x2561,
+    0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x2562, 0x2557, 0x255e, 0x2565, 0x2554, 0x255b, 0x24f5, 0x24f5,
+    0x2400, 0x2401, 0x2402, 0x2403, 0x2404, 0x2405, 0x2406, 0x2407, 0x2408, 0x2409, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5,
+    0x2551, 0x255e, 0x255e, 0x255a, 0x24f5, 0x255e, 0x2555, 0x24f5, 0x255c, 0x2564, 0x2553, 0x255e, 0x2561, 0x2550, 0x24f5, 0x24f5,
+    0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x255c, 0x2564, 0x2562, 0x2557, 0x2561, 0x255e, 0x255e, 0x255c,
+    0x2552, 0x2550, 0x255d, 0x2554, 0x24f5, 0x255e, 0x2555, 0x24f5, 0x24f5, 0x2562, 0x255e, 0x255c, 0x2550, 0x2561, 0x2558, 0x2550,
+    0x2552, 0x2550, 0x255d, 0x2554, 0x24f5, 0x255e, 0x2555, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x2551, 0x2568, 0x2561, 0x255d, 0x2550,
+    0x255c, 0x2550, 0x2556, 0x2558, 0x2552, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x2552, 0x2550, 0x255f, 0x2554, 0x24f5,
+    0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5,
+  };
+
+#define L(x) (x == ' ' ? 0x24f5 : 0x2550 + x - 'A')
+  const uint16 kNotAssignedItemText[16] = {
+    L('N'), L('O'), L('T'), L(' '), L(' '), L(' '), L(' '), L(' '),
+    L('A'), L('S'), L('S'), L('I'), L('G'), L('N'), L('E'), L('D'),
+  };
+#undef L
+
+  uint16 *dst_org = uvram_screen.row[0].col;
+  uint16 *dst_box = dst_org + (kNewStyleInventory ? 1 : 0);
+  
+  int btn_index = GetCurrentItemButtonIndex();
+  int item = *GetCurrentItemButtonPtr(btn_index);
+  Hud_DrawBox(dst_box, 21, 5, 21 + 9, 10, kSwitchLR_palettes[btn_index]);
+
+  // Display either the current item or the item assigned
+  // to the x, l, or r key.
+  if (item != 0) {
+    uint16 *p = dst_org + kHudItemInVramPtr[Hud_GetItemPosition(item)];
+    Hud_Copy2x2(dst_box + HUDXY(25, 6), p);
+    if (timer_for_flashing_circle & 0x10)
+      Hud_DrawFlashingCircle(p, kSwitchLR_palettes[btn_index]);
+  }
+
+  const uint16 *src_p;
+  if (item == kHudItem_BottleOld && !kNewStyleInventory && link_item_bottle_index) {
+    src_p = &kHudBottlesItemText[(link_bottle_info[link_item_bottle_index - 1] - 1) * 16];
+  } else if (item == 5 && link_item_mushroom != 1) {
+    src_p = &kHudMushroomItemText[(link_item_mushroom - 2) * 16];
+  } else if (item == 20 && link_item_mirror != 1) {
+    src_p = &kHudMirrorItemText[(link_item_mirror - 2) * 16];
+  } else if (item == 13 && link_item_flute != 1) {
+    src_p = &kHudFluteItemText[(link_item_flute - 2) * 16];
+  } else if (item == 1 && link_item_bow != 1) {
+    src_p = &kHudBowItemText[(link_item_bow - 2) * 16];
+  } else if (item >= kHudItem_Bottle1 && item <= kHudItem_Bottle4) {
+    src_p = &kHudBottlesItemText[(link_bottle_info[item - kHudItem_Bottle1] - 1) * 16];
+  } else if (item == kHudItem_Shovel) {
+    src_p = &kHudItemText[(13 - 1) * 16];
+  } else if (item == 0) {
+    src_p = btn_index ? kNotAssignedItemText : &kHudItemText[(20 - 1) * 16];
+  } else {
+    src_p = &kHudItemText[(item - 1) * 16];
+  }
+  Hud_DrawNxN(dst_box + HUDXY(22, 8), src_p, 8, 2);
+}
+
+void Hud_DrawEquipmentBox() {  // 8ded29
+  uint16 *dst = uvram_screen.row[0].col + (kNewStyleInventory ? 1 : 0);
+
+  Hud_DrawBox(dst, 21, 21, 30, 29, 2);
+
+  // Draw dotted lines
+  for (int i = 0; i < 8; i++)
+    dst[HUDXY(22 + i, 25)] = 0x28D7;
+
+  static const uint16 kHudEquipmentDungeonItemText[16] = {
+    0x2479, 0x247a, 0x247b, 0x247c, 0x248c, 0x24f5, 0x24f5, 0x24f5,
+    0x2469, 0x246a, 0x246b, 0x246c, 0x246d, 0x246e, 0x246f, 0x24f5,
+  };
+  memcpy(dst + HUDXY(22, 22), &kHudEquipmentDungeonItemText[0], 8 * sizeof(uint16));
+  memcpy(dst + HUDXY(22, 26), &kHudEquipmentDungeonItemText[8], 8 * sizeof(uint16));
+
+  static const ItemBoxGfx kHudItemHeartPieces[4] = {
+    {{0x2484, 0x6484, 0x2485, 0x6485}},
+    {{0x24ad, 0x6484, 0x2485, 0x6485}},
+    {{0x24ad, 0x6484, 0x24ae, 0x6485}},
+    {{0x24ad, 0x64ad, 0x24ae, 0x6485}},
+  };
+  if (cur_palace_index_x2 == 0xff) {
+    for (int i = 0; i < 8; i++)
+      dst[HUDXY(22 + i, 26)] = 0x24F5;
+    Hud_DrawItem(dst + HUDXY(25, 27), &kHudItemHeartPieces[link_heart_pieces]);
+  }
+  Hud_DrawItem(dst + HUDXY(22, 23), &kHudItemSword[link_sword_type == 0xff ? 0 : link_sword_type]);
+  Hud_DrawItem(dst + HUDXY(25, 23), &kHudItemShield[link_shield_type]);
+  Hud_DrawItem(dst + HUDXY(28, 23), &kHudItemArmor[link_armor]);
+
+  static const ItemBoxGfx kHudItemPalaceItem[2] = {
+    {{0x28d6, 0x68d6, 0x28e6, 0x28e7}},
+    {{0x354b, 0x354c, 0x354d, 0x354e}},
+  };
+  static const ItemBoxGfx kHudItemDungeonMap[1] = {
+    {{0x28de, 0x28df, 0x28ee, 0x28ef}},
+  };
+  static const ItemBoxGfx kHudItemDungeonCompass[1] = {
+    {{0x24bf, 0x64bf, 0x2ccf, 0x6ccf}},
+  };
+  if (cur_palace_index_x2 != 0xff &&
+     (link_bigkey << (cur_palace_index_x2 >> 1)) & 0x8000) {
+    Hud_DrawItem(dst + HUDXY(28, 27), &kHudItemPalaceItem[CheckPalaceItemPosession()]);
+  }
+  if (cur_palace_index_x2 != 0xff &&
+     (link_dungeon_map << (cur_palace_index_x2 >> 1)) & 0x8000) {
+    Hud_DrawItem(dst + HUDXY(22, 27), &kHudItemDungeonMap[0]);
+  }
+  if (cur_palace_index_x2 != 0xff &&
+     (link_compass << (cur_palace_index_x2 >> 1)) & 0x8000) {
+    Hud_DrawItem(dst + HUDXY(25, 27), &kHudItemDungeonCompass[0]);
+  }
+}
+
+static void Hud_IntToDecimal(unsigned int number, uint8 *out) {  // 8df0f7
+  out[0] = number / 1000 + 0x90;
+  out[1] = (number %= 1000) / 100 + 0x90;
+  out[2] = (number %= 100) / 10 + 0x90;
+  out[3] = (number % 10) + 0x90;
+}
+
+bool Hud_RefillHealth() {  // 8df128
+  if (link_health_current >= link_health_capacity) {
+    link_health_current = link_health_capacity;
+    link_hearts_filler = 0;
+    return (is_doing_heart_animation == 0);
+  }
+  link_hearts_filler = 160;
+  return false;
+}
+
+void Hud_AnimateHeartRefill() {  // 8df14f
+  if (--animate_heart_refill_countdown)
+    return;
+  uint16 n = ((uint16)((link_health_current & ~7) - 1) >> 3) << 1;
+  uint16 *p = hud_tile_indices_buffer + HUDXY(20, 1);
+  if (n >= 20) {
+    n -= 20;
+    p += 0x20;
+  }
+  n &= 0xff;
+  animate_heart_refill_countdown = 1;
+
+  static const uint16 kAnimHeartPartial[4] = { 0x24A3, 0x24A4, 0x24A3, 0x24A0 };
+  p[n >> 1] = kAnimHeartPartial[animate_heart_refill_countdown_subpos];
+
+  animate_heart_refill_countdown_subpos = (animate_heart_refill_countdown_subpos + 1) & 3;
+  if (!animate_heart_refill_countdown_subpos) {
+    Hud_Rebuild();
+    is_doing_heart_animation = 0;
+  }
+}
+
+bool Hud_RefillMagicPower() {  // 8df1b3
+  if (link_magic_power >= 0x80)
+    return true;
+  link_magic_filler = 0x80;
+  return false;
+}
+
+void Hud_RestoreTorchBackground() {  // 8dfa33
+  if (!link_item_torch || !dung_want_lights_out || hdr_dungeon_dark_with_lantern ||
+      dung_num_lit_torches)
+    return;
+  hdr_dungeon_dark_with_lantern = 1;
+  if (dung_hdr_bg2_properties != 2)
+    TS_copy = 1;
+}
+
+void Hud_RebuildIndoor() {  // 8dfa60
+  overworld_fixed_color_plusminus = 0;
+  link_num_keys = 0xff;
+  Hud_Rebuild();
+}
+
+static void Hud_UpdateItemBox() {  // 8dfafd
+  // Update r
+  if (hud_cur_item)
+    Hud_DrawItem(&hud_tile_indices_buffer[HUDXY(5, 1)], Hud_GetIconForItem(hud_cur_item));
+}
+
+static void Hud_UpdateHearts_Inner(uint16 *dst, const uint16 *src, int n) {  // 8dfdab
+  int x = 0;
+  while (n > 0) {
+    if (x >= 10) {
+      dst += 0x20;
+      x = 0;
+    }
+    dst[x] = src[n >= 5 ? 2 : 1];
+    x++;
+    n -= 8;
+  }
+}
+
+static void DrawHudComponents(uint16 *dst, const uint16 *src, int w, int h) {
+  do {
+    memcpy(dst, src, w * sizeof(uint16));
+  } while (src += w, dst += 32, --h);
+}
+
+static void Hud_Update_Hearts() {  // 8dfb94
+  static const uint16 kHudItemBoxTab1[] = { 0x24A2, 0x24A2, 0x24A2 };
+  static const uint16 kHudItemBoxTab2[] = { 0x24A2, 0x24A1, 0x24A0 };
+  // The life meter
+  Hud_UpdateHearts_Inner(&hud_tile_indices_buffer[HUDXY(20, 1)], kHudItemBoxTab1, link_health_capacity);
+  Hud_UpdateHearts_Inner(&hud_tile_indices_buffer[HUDXY(20, 1)], kHudItemBoxTab2, (link_health_current + 3) & ~3);
+}
+
+static void Hud_Update_Magic() {  // 8dfc09
+  uint16 *dst = &hud_tile_indices_buffer[HUDXY(2, 0)];
+  if (link_magic_consumption >= 1) {
+    dst[HUDXY(0, 0)] = 0x28F7;
+    dst[HUDXY(1, 0)] = 0x2851;
+    dst[HUDXY(2, 0)] = 0x28FA;
+  }
+  const uint16 *src = kUpdateMagicPowerTilemap[(link_magic_power + 7) >> 3];
+  dst[HUDXY(1, 1)] = src[0];
+  dst[HUDXY(1, 2)] = src[1];
+  dst[HUDXY(1, 3)] = src[2];
+  dst[HUDXY(1, 4)] = src[3];
+}
+
+static void Hud_Update_Inventory() {  // 8dfc09
+  uint8 d[4];
+  Hud_IntToDecimal(link_rupees_actual, d);
+
+  const uint16 base_tiles[2] = {
+    0x2400,
+    (enhanced_features0 & kFeatures0_ShowMaxItemsInYellow) ? 0x3400 : 0x2400,
+  };
+
+  int inv_offs = (d[0] == 0x90) ? 1 : 0;
+
+  static const uint16 kHudInventoryBg[26] = {
+    0x207f, 0x207f, 0x3ca8, 0x207f, 0x207f, 0x2c88, 0x2c89, 0x207f, 0x20a7, 0x20a9, 0x207f, 0x2871, 0x207f,
+    0x207f, 0x207f, 0x207f, 0x207f, 0x207f, 0x207f, 0x207f, 0x207f, 0x207f, 0x207f, 0x207f, 0x207f, 0x207f,
+  };
+
+  uint16 *dst = &hud_tile_indices_buffer[HUDXY(8, 0)];
+  memcpy(dst + HUDXY(0, 0), kHudInventoryBg +  0 + inv_offs, 12 * sizeof(uint16));
+  memcpy(dst + HUDXY(0, 1), kHudInventoryBg + 13 + inv_offs, 12 * sizeof(uint16));
+
+  if (link_item_bow) {
+    if (link_item_bow >= 3) {
+      hud_tile_indices_buffer[HUDXY(15, 0)] = 0x2486;
+      hud_tile_indices_buffer[HUDXY(16, 0)] = 0x2487;
+      link_item_bow = link_num_arrows ? 4 : 3;
+    } else {
+      link_item_bow = link_num_arrows ? 2 : 1;
+    }
+  }
+
+  // Offset everything if we have many coins?
+  int base_tile = base_tiles[link_rupees_actual == MaxRupees()];
+  if (inv_offs == 0) {
+    dst++;
+    dst[HUDXY(-1, 1)] = base_tile | d[0];
+  }
+  dst[HUDXY(0, 1)] = base_tile | d[1];
+  dst[HUDXY(1, 1)] = base_tile | d[2];
+  dst[HUDXY(2, 1)] = base_tile | d[3];
+
+  Hud_IntToDecimal(link_item_bombs, d);
+  base_tile = base_tiles[link_item_bombs == kMaxBombsForLevel[link_bomb_upgrades]];
+  dst[HUDXY(4, 1)] = base_tile | d[2];
+  dst[HUDXY(5, 1)] = base_tile | d[3];
+
+  Hud_IntToDecimal(link_num_arrows, d);
+  base_tile = base_tiles[link_num_arrows == kMaxArrowsForLevel[link_arrow_upgrades]];
+  dst[HUDXY(7, 1)] = base_tile | d[2];
+  dst[HUDXY(8, 1)] = base_tile | d[3];
+
+  // Show keys
+  d[3] = 0x7f;
+  if (link_num_keys != 0xff)
+    Hud_IntToDecimal(link_num_keys, d);
+  dst[HUDXY(10, 1)] = 0x2400 | d[3];
+  if (dst[HUDXY(10, 1)] == 0x247f)
+    dst[HUDXY(10, 0)] = 0x247f;
+}
+
+void Hud_Rebuild() {  // 8dfa70
+  // Ensure all of the 165 hud words are initialized.
+  // This was broken by my previous reorg... quick fix for now.
+  if (hud_tile_indices_buffer[HUDXY(8, 2)] == 0) {
+    for (int i = 0; i < 165; i++)
+      hud_tile_indices_buffer[i] = 0x207f;
+  }
+
+
+  // The magic meter and item box
+  static const uint16 kHudTilemapLeftPart[8 * 6] = {
+    0x207f, 0x207f, 0x2850, 0xa856, 0x2852, 0x285b, 0x285b, 0x285c,
+    0x207f, 0x207f, 0x2854, 0x2871, 0x2858, 0x207f, 0x207f, 0x285d,
+    0x207f, 0x207f, 0x2854, 0x304e, 0x2858, 0x207f, 0x207f, 0x285d,
+    0x207f, 0x207f, 0x2854, 0x305e, 0x2859, 0xa85b, 0xa85b, 0xa85c,
+    0x207f, 0x207f, 0x2854, 0x305e, 0x6854, 0x207f, 0x207f, 0x207f,
+    0x207f, 0x207f, 0xa850, 0x2856, 0xe850, 
+  };
+  DrawHudComponents(hud_tile_indices_buffer, kHudTilemapLeftPart, 8, 6);
+
+  static const uint16 kHudTilemapRightPart[12 * 5] = {
+    0x207f, 0x207f, 0x288b, 0x288f, 0x24ab, 0x24ac, 0x688f, 0x688b, 0x207f, 0x207f, 0x207f, 0x207f,
+    0x207f, 0x207f, 0x207f, 0x207f, 0x207f, 0x207f, 0x207f, 0x207f, 0x207f, 0x207f, 0x207f, 0x207f,
+    0x207f, 0x207f, 0x207f, 0x207f, 0x207f, 0x207f, 0x207f, 0x207f, 0x207f, 0x207f, 0x207f, 0x207f,
+    0x207f, 0x207f, 0x207f, 0x207f, 0x207f, 0x207f, 0x207f, 0x207f, 0x207f, 0x207f, 0x207f, 0x207f,
+    0x207f, 0x207f, 0x207f, 0x207f, 0x207f, 0x207f, 0x207f, 0x207f, 0x207f, 0x207f, 0x207f, 0x207f,
+  };
+  DrawHudComponents(&hud_tile_indices_buffer[HUDXY(20, 0)], kHudTilemapRightPart, 12, 5);
+
+
+  Hud_Update_Hearts();
+  Hud_Update_Magic();
+  Hud_Update_Inventory();
+  Hud_UpdateItemBox();
+  flag_update_hud_in_nmi++;
+}
+
+
+const uint16 *Hud_GetItemBoxPtr(int item) {
+  return kHudItemBoxGfxPtrs[item]->v;
+}
+
+void Hud_HandleItemSwitchInputs() {
+  if (!(enhanced_features0 & kFeatures0_SwitchLR))
+    return;
+  
+  bool direction;
+  
+  if (filtered_joypad_L & kJoypadL_L && (hud_cur_item_l == 0))
+    direction = (hud_cur_item_r != 0);
+  else if (filtered_joypad_L & kJoypadL_R && (hud_cur_item_r == 0))
+    direction = true;
+  else
+    return;
+
+  uint8 item = hud_cur_item;
+  for (int i = 0; i < kHudItemCount; i++) {
+    if (!direction)
+      Hud_GotoPrevItem(&item, 1);
+    else
+      Hud_GotoNextItem(&item, 1);
+    if (Hud_DoWeHaveThisItem(item) && (!(enhanced_features0 & kFeatures0_SwitchLRLimit) || Hud_GetItemPosition(item) <= 3)) {
+      if (item != hud_cur_item) {
+        hud_cur_item = item;
+        sound_effect_2 = 32;
+        Hud_UpdateEquippedItem();
+        Hud_UpdateItemBox();
+        flag_update_hud_in_nmi++;
+      }
+      break;
+    }
+  }
+}
+
+static void Hud_ReorderItem(int direction) {
+  // Initialize inventory order on first use
+  if (hud_inventory_order[0] == 0) {
+    for (int i = 0; i < 24; i++)
+      hud_inventory_order[i] = i + 1;
+  }
+  int old_pos = Hud_GetItemPosition(hud_cur_item), new_pos = old_pos + direction;
+  if (new_pos < 0)
+    new_pos += kHudItemCount;
+  else if (new_pos >= kHudItemCount)
+    new_pos -= kHudItemCount;
+  uint8 t = hud_inventory_order[old_pos];
+  hud_inventory_order[old_pos] = hud_inventory_order[new_pos];
+  hud_inventory_order[new_pos] = t;
+  Hud_DrawYButtonItems();
+  sound_effect_2 = 32;
+}
--- /dev/null
+++ b/src/hud.h
@@ -1,0 +1,62 @@
+#pragma once
+#include "types.h"
+
+enum kHudItems {
+
+  kHudItem_Bombs = 4,
+  kHudItem_Mushroom = 5,
+  kHudItem_Hammer = 12,
+  kHudItem_Flute = 13,
+  kHudItem_BookMudora = 15,
+  kHudItem_BottleOld = 16,
+  
+  kHudItem_Shovel = 16,
+  kHudItem_Bottle1 = 21,
+  kHudItem_Bottle2 = 22,
+  kHudItem_Bottle3 = 23,
+  kHudItem_Bottle4 = 24,
+};
+
+void Hud_RefreshIcon();
+uint8 CheckPalaceItemPosession();
+void Hud_FloorIndicator();
+void Hud_RemoveSuperBombIndicator();
+void Hud_SuperBombIndicator();
+void Hud_RefillLogic();
+void Hud_Module_Run();
+void Hud_ClearTileMap();
+void Hud_Init();
+void Hud_BringMenuDown();
+void Hud_ChooseNextMode();
+void Hud_NormalMenu();
+void Hud_UpdateHud();
+uint8 Hud_LookupInventoryItem(uint8 item);
+void Hud_UpdateEquippedItem();
+void Hud_CloseMenu();
+void Hud_GotoBottleMenu();
+void Hud_InitBottleMenu();
+void Hud_ExpandBottleMenu();
+void Hud_BottleMenu();
+void Hud_DrawBottleMenu_Update();
+void Hud_EraseBottleMenu();
+void Hud_RestoreNormalMenu();
+void Hud_SearchForEquippedItem();
+void Hud_DrawYButtonItems();
+void Hud_DrawAbilityBox();
+void Hud_DrawProgressIcons();
+void Hud_DrawProgressIcons_Pendants();
+void Hud_DrawProgressIcons_Crystals();
+void Hud_DrawSelectedYButtonItem();
+void Hud_DrawEquipmentBox();
+void Hud_DrawBottleMenu();
+bool Hud_RefillHealth();
+void Hud_AnimateHeartRefill();
+bool Hud_RefillMagicPower();
+void Hud_RestoreTorchBackground();
+void Hud_RebuildIndoor();
+void Hud_Rebuild();
+const uint16 *Hud_GetItemBoxPtr(int item);
+int GetCurrentItemButtonIndex();
+uint8 *GetCurrentItemButtonPtr(int i);
+
+void Hud_HandleItemSwitchInputs();
--- /dev/null
+++ b/src/load_gfx.c
@@ -1,0 +1,2182 @@
+#include "zelda_rtl.h"
+#include "variables.h"
+#include "snes/snes_regs.h"
+#include "overworld.h"
+#include "load_gfx.h"
+#include "player.h"
+#include "sprite.h"
+#include "assets.h"
+
+// Allow this to be overwritten
+uint16 kGlovesColor[2] = {0x52f6, 0x376};
+
+static const uint16 kPaletteFilteringBits[64] = {
+  0xffff, 0xffff, 0xfffe, 0xffff, 0x7fff, 0x7fff, 0x7fdf, 0xfbff, 0x7f7f, 0x7f7f, 0x7df7, 0xefbf, 0x7bdf, 0x7bdf, 0x77bb, 0xddef,
+  0x7777, 0x7777, 0x6edd, 0xbb77, 0x6db7, 0x6db7, 0x5b6d, 0xb6db, 0x5b5b, 0x5b5b, 0x56b6, 0xad6b, 0x5555, 0xad6b, 0x5555, 0xaaab,
+  0x5555, 0x5555, 0x2a55, 0x5555, 0x2a55, 0x2a55, 0x294a, 0x5295, 0x2525, 0x2525, 0x2492, 0x4925, 0x1249, 0x1249, 0x1122, 0x4489,
+  0x1111, 0x1111,  0x844, 0x2211,  0x421,  0x421,  0x208, 0x1041,  0x101,  0x101,   0x20,  0x401,      1,      1,      0,      1,
+};
+static const uint16 kPaletteFilter_Agahnim_Tab[3] = {0x160, 0x180, 0x1a0};
+static const uint8 kMainTilesets[37][8] = {
+  {  0,   1,  16,   6, 14, 31, 24, 15},
+  {  0,   1,  16,   8, 14, 34, 27, 15},
+  {  0,   1,  16,   6, 14, 31, 24, 15},
+  {  0,   1,  19,   7, 14, 35, 28, 15},
+  {  0,   1,  16,   7, 14, 33, 24, 15},
+  {  0,   1,  16,   9, 14, 32, 25, 15},
+  {  2,   3,  18,  11, 14, 33, 26, 15},
+  {  0,   1,  17,  12, 14, 36, 27, 15},
+  {  0,   1,  17,   8, 14, 34, 27, 15},
+  {  0,   1,  17,  12, 14, 37, 26, 15},
+  {  0,   1,  17,  12, 14, 38, 27, 15},
+  {  0,   1,  20,  10, 14, 39, 29, 15},
+  {  0,   1,  17,  10, 14, 40, 30, 15},
+  {  2,   3,  18,  11, 14, 41, 22, 15},
+  {  0,   1,  21,  13, 14, 42, 24, 15},
+  {  0,   1,  16,   7, 14, 35, 28, 15},
+  {  0,   1,  19,   7, 14,  4,  5, 15},
+  {  0,   1,  19,   7, 14,  4,  5, 15},
+  {  0,   1,  16,   9, 14, 32, 27, 15},
+  {  0,   1,  16,   9, 14, 42, 23, 15},
+  {  2,   3,  18,  11, 14, 33, 28, 15},
+  {  0,   8,  17,  27, 34, 46, 93, 91},
+  {  0,   8,  16,  24, 32, 43, 93, 91},
+  {  0,   8,  16,  24, 32, 43, 93, 91},
+  { 58,  59,  60,  61, 83, 77, 62, 91},
+  { 66,  67,  68,  69, 32, 43, 63, 93},
+  {  0,   8,  16,  24, 32, 43, 93, 91},
+  {  0,   8,  16,  24, 32, 43, 93, 91},
+  {  0,   8,  16,  24, 32, 43, 93, 91},
+  {  0,   8,  16,  24, 32, 43, 93, 91},
+  {  0,   8,  16,  24, 32, 43, 93, 91},
+  {113, 114, 113, 114, 32, 43, 93, 91},
+  { 58,  59,  60,  61, 83, 77, 62, 91},
+  { 66,  67,  68,  69, 32, 43, 63, 89},
+  {  0, 114, 113, 114, 32, 43, 93, 15},
+  { 22,  57,  29,  23, 64, 65, 57, 30},
+  {  0,  70,  57, 114, 64, 65, 57, 15},
+};
+static const uint8 kSpriteTilesets[144][4] = {
+  { 0, 73,   0,  0},
+  {70, 73,  12, 29},
+  {72, 73,  19, 29},
+  {70, 73,  19, 14},
+  {72, 73,  12, 17},
+  {72, 73,  12, 16},
+  {79, 73,  74, 80},
+  {14, 73,  74, 17},
+  {70, 73,  18,  0},
+  { 0, 73,   0, 80},
+  { 0, 73,   0, 17},
+  {72, 73,  12,  0},
+  { 0,  0,  55, 54},
+  {72, 73,  76, 17},
+  {93, 44,  12, 68},
+  { 0,  0,  78,  0},
+  {15,  0,  18, 16},
+  { 0,  0,   0, 76},
+  { 0, 13,  23,  0},
+  {22, 13,  23, 27},
+  {22, 13,  23, 20},
+  {21, 13,  23, 21},
+  {22, 13,  24, 25},
+  {22, 13,  23, 25},
+  {22, 13,   0,  0},
+  {22, 13,  24, 27},
+  {15, 73,  74, 17},
+  {75, 42,  92, 21},
+  {22, 73,  23, 29},
+  { 0,  0,   0, 21},
+  {22, 13,  23, 16},
+  {22, 73,  18,  0},
+  {22, 73,  12, 17},
+  { 0,  0,  18, 16},
+  {22, 13,   0, 17},
+  {22, 73,  12,  0},
+  {22, 13,  76, 17},
+  {14, 13,  74, 17},
+  {22, 26,  23, 27},
+  {79, 52,  74, 80},
+  {53, 77, 101, 54},
+  {74, 52,  78,  0},
+  {14, 52,  74, 17},
+  {81, 52,  93, 89},
+  {75, 73,  76, 17},
+  {45,  0,   0,  0},
+  {93,  0,  18, 89},
+  { 0,  0,   0,  0},
+  { 0,  0,   0,  0},
+  { 0,  0,   0,  0},
+  { 0,  0,   0,  0},
+  { 0,  0,   0,  0},
+  { 0,  0,   0,  0},
+  { 0,  0,   0,  0},
+  { 0,  0,   0,  0},
+  { 0,  0,   0,  0},
+  { 0,  0,   0,  0},
+  { 0,  0,   0,  0},
+  { 0,  0,   0,  0},
+  { 0,  0,   0,  0},
+  { 0,  0,   0,  0},
+  { 0,  0,   0,  0},
+  { 0,  0,   0,  0},
+  { 0,  0,   0,  0},
+  {71, 73,  43, 45},
+  {70, 73,  28, 82},
+  { 0, 73,  28, 82},
+  {93, 73,   0, 82},
+  {70, 73,  19, 82},
+  {75, 77,  74, 90},
+  {71, 73,  28, 82},
+  {75, 77,  57, 54},
+  {31, 44,  46, 82},
+  {31, 44,  46, 29},
+  {47, 44,  46, 82},
+  {47, 44,  46, 49},
+  {31, 30,  48, 82},
+  {81, 73,  19,  0},
+  {79, 73,  19, 80},
+  {79, 77,  74, 80},
+  {75, 73,  76, 43},
+  {31, 32,  34, 83},
+  {85, 61,  66, 67},
+  {31, 30,  35, 82},
+  {31, 30,  57, 58},
+  {31, 30,  58, 62},
+  {31, 30,  60, 61},
+  {64, 30,  39, 63},
+  {85, 26,  66, 67},
+  {31, 30,  42, 82},
+  {31, 30,  56, 82},
+  {31, 32,  40, 82},
+  {31, 32,  38, 82},
+  {31, 44,  37, 82},
+  {31, 32,  39, 82},
+  {31, 30,  41, 82},
+  {31, 44,  59, 82},
+  {70, 73,  36, 82},
+  {33, 65,  69, 51},
+  {31, 44,  40, 49},
+  {31, 13,  41, 82},
+  {31, 30,  39, 82},
+  {31, 32,  39, 83},
+  {72, 73,  19, 82},
+  {14, 30,  74, 80},
+  {31, 32,  38, 83},
+  {21,  0,   0,  0},
+  {31,  0,  42, 82},
+  { 0,  0,   0,  0},
+  { 0,  0,   0,  0},
+  { 0,  0,   0,  0},
+  { 0,  0,   0,  0},
+  { 0,  0,   0,  0},
+  { 0,  0,   0,  0},
+  { 0,  0,   0,  0},
+  { 0,  0,   0,  0},
+  { 0,  0,   0,  0},
+  { 0,  0,   0,  0},
+  { 0,  0,   0,  0},
+  { 0,  0,   0,  0},
+  { 0,  0,   0,  0},
+  { 0,  0,   0,  0},
+  { 0,  0,   0,  0},
+  { 0,  0,   0,  0},
+  { 0,  0,   0,  0},
+  {50,  0,   0,  8},
+  {93, 73,   0, 82},
+  {85, 73,  66, 67},
+  {97, 98,  99, 80},
+  {97, 98,  99, 80},
+  {97, 98,  99, 80},
+  {97, 98,  99, 80},
+  {97, 98,  99, 80},
+  {97, 98,  99, 80},
+  {97, 86,  87, 80},
+  {97, 98,  99, 80},
+  {97, 98,  99, 80},
+  {97, 86,  87, 80},
+  {97, 86,  99, 80},
+  {97, 86,  87, 80},
+  {97, 86,  51, 80},
+  {97, 86,  87, 80},
+  {97, 98,  99, 80},
+  {97, 98,  99, 80},
+};
+static const uint8 kAuxTilesets[82][4] = {
+  {  6,   0,  31,  24},
+  {  8,   0,  34,  27},
+  {  6,   0,  31,  24},
+  {  7,   0,  35,  28},
+  {  7,   0,  33,  24},
+  {  9,   0,  32,  25},
+  { 11,   0,  33,  26},
+  { 12,   0,  36,  25},
+  {  8,   0,  34,  27},
+  { 12,   0,  37,  27},
+  { 12,   0,  38,  27},
+  { 10,   0,  39,  29},
+  { 10,   0,  40,  30},
+  { 11,   0,  41,  22},
+  { 13,   0,  42,  24},
+  {  7,   0,  35,  28},
+  {  7,   0,   4,   5},
+  {  7,   0,   4,   5},
+  {  9,   0,  32,  27},
+  {  9,   0,  42,  23},
+  { 11,   0,  33,  28},
+  {  9,   0,  32,  25},
+  { 11,   0,  33,  26},
+  {  9,   0,  36,  27},
+  {  8,   0,  34,  27},
+  {  9,   0,  37,  27},
+  {  9,   0,  38,  27},
+  { 10,   0,  39,  29},
+  {  9,   0,  40,  30},
+  { 12,   0,  41,  22},
+  { 13,   0,  42,  23},
+  {114,   0,  43,  93},
+  {  0,   0,   0,   0},
+  {  0,  87,  76,   0},
+  {  0,  86,  79,   0},
+  {  0,  83,  77,   0},
+  {  0,  82,  73,   0},
+  {  0,  85,  74,   0},
+  {  0,  83,  84,   0},
+  {  0,  81,  78,   0},
+  {  0,   0,   0,   0},
+  {  0,  80,  75,   0},
+  {  0,  83,  77,   0},
+  {  0,  85,  84,   0},
+  {  0,   0,   0,   0},
+  {  0,   0,   0,   0},
+  {  0,   0,   0,   0},
+  {  0,  71,  72,   0},
+  {  0,   0,   0,   0},
+  {  0,  87,  76,   0},
+  {  0,  86,  79,   0},
+  {  0,  83,  77,   0},
+  {  0,  82,  73,   0},
+  {  0,  85,  74,   0},
+  {  0,  83,  84,   0},
+  {  0,  81,  78,   0},
+  {  0,   0,   0,   0},
+  {  0,  80,  75,   0},
+  {  0,  83,   0,   0},
+  {  0,  53,  54,   0},
+  {  0,  96,  52,   0},
+  {  0,  43,  44,   0},
+  {  0,  45,  46,   0},
+  {  0,  47,  48,   0},
+  {  0,  55,  56,   0},
+  {  0,  51,  52,   0},
+  {  0,  49,  50,   0},
+  {  0,   0,   0,   0},
+  {  0,   0,   0,   0},
+  {  0,   0,   0,   0},
+  {  0,   0,   0,   0},
+  {  0,   0,   0,   0},
+  {  0,   0,   0,   0},
+  {  0,   0,   0,   0},
+  {  0,   0,   0,   0},
+  {  0,   0,   0,   0},
+  {  0,   0,   0,   0},
+  {  0,   0,   0,   0},
+  {  0,   0,   0,   0},
+  {  0,   0,   0,   0},
+  {114, 113, 114, 113},
+  { 23,  64,  65,  57},
+};
+static const uint16 kTagalongWhich[14] = {0, 0x600, 0x300, 0x300, 0x300, 0, 0, 0x900, 0x600, 0x600, 0x900, 0x900, 0x600, 0x900};
+static const uint16 kDecodeAnimatedSpriteTile_Tab[57] = {
+  0x9c0, 0x30, 0x60, 0x90, 0xc0, 0x300, 0x318, 0x330, 0x348, 0x360, 0x378, 0x390, 0x930, 0x3f0, 0x420, 0x450,
+  0x468, 0x600, 0x630, 0x660, 0x690, 0x6c0, 0x6f0, 0x720, 0x750, 0x768, 0x900, 0x930, 0x960, 0x990, 0x9f0, 0,
+  0xf0, 0xa20, 0xa50, 0x660, 0x600, 0x618, 0x630, 0x648, 0x678, 0x6d8, 0x6a8, 0x708, 0x738, 0x768, 0x960, 0x900,
+  0x3c0, 0x990, 0x9a8, 0x9c0, 0x9d8, 0xa08, 0xa38, 0x600, 0x630,
+};
+static const uint16 kSwordTypeToGfxOffs[5] = {0, 0, 0x120, 0x120, 0x120};
+static const uint16 kShieldTypeToGfxOffs[4] = {0x660, 0x660, 0x6f0, 0x900};
+static const int8 kOwBgPalInfo[93] = {
+  0, -1, 7, 0, 1, 7, 0, 2, 7, 0, 3, 7, 0, 4, 7, 0, 5, 7, 0, 6, 7, 7, 6, 5,
+  0, 8, 7, 0, 9, 7, 0, 10, 7, 0, 11, 7, 0, -1, 7, 0, -1, 7, 3, 4, 7, 4, 4, 3,
+  16, -1, 6, 16, 1, 6, 16, 17, 6, 16, 3, 6, 16, 4, 6, 16, 5, 6, 16, 6, 6, 18, 19, 4,
+  18, 5, 4, 16, 9, 6, 16, 11, 6, 16, 12, 6, 16, 13, 6, 16, 14, 6, 16, 15, 6,
+};
+static const int8 kOwSprPalInfo[40] = {
+  -1, -1, 3, 10, 3, 6, 3, 1, 0, 2, 3, 14, 3, 2, 19, 1, 11, 12, 17, 1, 7, 5, 17, 0,
+  9, 11, 15, 5, 3, 5, 3, 7, 15, 2, 10, 2, 5, 1, 12, 14,
+};
+static const int8 kSpotlight_delta_size[4] = {-7, 7, 7, 7};
+static const uint8 kSpotlight_goal[4] = {0, 126, 35, 126};
+static const uint8 kConfigureSpotlightTable_Helper_Tab[129] = {
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfd, 0xfd, 0xfd, 0xfc, 0xfc, 0xfc, 0xfb, 0xfb, 0xfb, 0xfa, 0xfa, 0xf9, 0xf9, 0xf8, 0xf8,
+  0xf7, 0xf7, 0xf6, 0xf6, 0xf5, 0xf5, 0xf4, 0xf3, 0xf3, 0xf2, 0xf1, 0xf1, 0xf0, 0xef, 0xee, 0xee, 0xed, 0xec, 0xeb, 0xea, 0xe9, 0xe9, 0xe8, 0xe7, 0xe6, 0xe5, 0xe4, 0xe3, 0xe2, 0xe1, 0xdf, 0xde,
+  0xdd, 0xdc, 0xdb, 0xda, 0xd8, 0xd7, 0xd6, 0xd5, 0xd3, 0xd2, 0xd0, 0xcf, 0xcd, 0xcc, 0xca, 0xc9, 0xc7, 0xc6, 0xc4, 0xc2, 0xc1, 0xbf, 0xbd, 0xbb, 0xb9, 0xb7, 0xb6, 0xb4, 0xb1, 0xaf, 0xad, 0xab,
+  0xa9, 0xa7, 0xa4, 0xa2, 0x9f, 0x9d, 0x9a, 0x97, 0x95, 0x92, 0x8f, 0x8c, 0x89, 0x86, 0x82, 0x7f, 0x7b, 0x78, 0x74, 0x70, 0x6c, 0x67, 0x63, 0x5e, 0x59, 0x53, 0x4d, 0x46, 0x3f, 0x37, 0x2d, 0x1f,
+  0,
+};
+static const uint8 kGraphicsHalfSlotPacks[20] = {
+  1, 1, 8, 8, 9, 9, 2, 2, 2, 2, 3, 3, 4, 4, 5, 5,
+  8, 8, 8, 8,
+};
+static const int8 kGraphicsLoadSp6[20] = {
+  10, -1, 3, -1, 0, -1, -1, -1, 1, -1, 2, -1, 0, -1, -1,
+  -1, -1, -1, -1, -1,
+};
+static const uint8 kMirrorWarp_LoadNext_NmiLoad[15] = {0, 14, 15, 16, 17, 0, 0, 0, 0, 0, 0, 18, 19, 20, 0};
+
+static const uint8 *GetCompSpritePtr(int i) {
+  return kSprGfx(i).ptr;
+}
+
+void ApplyPaletteFilter_bounce() {
+
+  const uint16 *load_ptr = kPaletteFilteringBits + (palette_filter_countdown >= 0x10);
+
+  int mask = kUpperBitmasks[palette_filter_countdown & 0xf];
+  int dt = darkening_or_lightening_screen ? 1 : -1;
+  int j = 0;
+  for (;;) {
+    uint16 c = main_palette_buffer[j], a = aux_palette_buffer[j];
+    if (!(load_ptr[(a & 0x1f) * 2] & mask))
+      c += dt;
+    if (!(load_ptr[(a & 0x3e0) >> 4] & mask))
+      c += dt << 5;
+    if (!(load_ptr[(a & 0x7c00) >> 9] & mask))
+      c += dt << 10;
+    main_palette_buffer[j] = c;
+    j++;
+    if (j == 1)
+      j = 0x20;
+    else if (j == 0xd8)
+      j = 0xe0;
+    else if (j == 0xf0)
+      break;
+  }
+  flag_update_cgram_in_nmi++;
+  if (!darkening_or_lightening_screen) {
+    if (++palette_filter_countdown != mosaic_target_level)
+      return;
+  } else {
+    if (palette_filter_countdown-- != mosaic_target_level)
+      return;
+  }
+  darkening_or_lightening_screen ^= 2;
+  palette_filter_countdown = 0;
+  subsubmodule_index++;
+}
+
+void PaletteFilter_Range(int from, int to) {
+  const uint16 *load_ptr = kPaletteFilteringBits + (palette_filter_countdown >= 0x10);
+  int mask = kUpperBitmasks[palette_filter_countdown & 0xf];
+  int dt = darkening_or_lightening_screen ? 1 : -1;
+  for (int j = from; j != to; j++) {
+    uint16 c = main_palette_buffer[j], a = aux_palette_buffer[j];
+    if (!(load_ptr[(a & 0x1f) * 2] & mask))
+      c += dt;
+    if (!(load_ptr[(a & 0x3e0) >> 4] & mask))
+      c += dt << 5;
+    if (!(load_ptr[(a & 0x7c00) >> 9] & mask))
+      c += dt << 10;
+    main_palette_buffer[j] = c;
+  }
+}
+
+void PaletteFilter_IncrCountdown() {
+  if (++palette_filter_countdown == 0x1f) {
+    palette_filter_countdown = 0;
+    darkening_or_lightening_screen ^= 2;
+    if (darkening_or_lightening_screen)
+      WORD(link_actual_vel_y)++; // wtf?
+  }
+  flag_update_cgram_in_nmi++;
+}
+
+uint8 *LoadItemAnimationGfxOne(uint8 *dst, int num, int r12, bool from_temp) {
+  static const uint8 kIntro_LoadGfx_Tab[10] = { 0, 11, 8, 38, 42, 45, 34, 3, 33, 46 };
+  const uint8 *src = from_temp ? &g_ram[0x14000] : GetCompSpritePtr(0);
+  const uint8 *base_src = src;
+  src += kIntro_LoadGfx_Tab[r12] * 24;
+  Expand3To4High(dst, src, base_src, num);
+  Expand3To4High(dst + 0x20 * num, src + 0x180, base_src, num);
+  return dst + 0x40 * num;
+}
+
+uint16 snes_divide(uint16 dividend, uint8 divisor) {
+  return divisor ? dividend / divisor : 0xffff;
+}
+
+void EraseTileMaps_normal() {
+  EraseTileMaps(0x7f, 0x1ec);
+}
+
+static void DecompAndUpload2bpp(uint16 *vram_ptr, uint8 pack) {
+  Decomp_spr(&g_ram[0x14000], pack);
+  const uint8 *src = &g_ram[0x14000];
+  memcpy(vram_ptr, src, 1024 * sizeof(uint16));
+}
+
+void RecoverPegGFXFromMapping() {
+  if (BYTE(orange_blue_barrier_state))
+    Dungeon_UpdatePegGFXBuffer(0x180, 0x0);
+  else
+    Dungeon_UpdatePegGFXBuffer(0x0, 0x180);
+}
+
+void LoadOverworldMapPalette() {
+  memcpy(main_palette_buffer, &kOverworldMapPaletteData[overworld_screen_index & 0x40 ? 0x80 : 0], 256);
+}
+
+void EraseTileMaps_triforce() {  // 808333
+  EraseTileMaps(0xa9, 0x7f);
+}
+
+void EraseTileMaps_dungeonmap() {  // 80833f
+  EraseTileMaps(0x7f, 0x300);
+}
+
+void EraseTileMaps(uint16 r2, uint16 r0) {  // 808355
+  uint16 *dst = g_zenv.vram;
+  for (int i = 0; i < 0x2000; i++)
+    dst[i] = r0;
+
+  dst = g_zenv.vram + 0x6000;
+  for (int i = 0; i < 0x800; i++)
+    dst[i] = r2;
+}
+
+void EnableForceBlank() {  // 80893d
+  INIDISP_copy = 0x80;
+  HDMAEN_copy = 0;
+}
+
+void LoadItemGFXIntoWRAM4BPPBuffer() {  // 80d231
+  uint8 *dst = &g_ram[0x9000 + 0x480];
+  dst = LoadItemAnimationGfxOne(dst, 7, 0, false);  // rod
+  dst = LoadItemAnimationGfxOne(dst, 7, 1, false);  // hammer
+  dst = LoadItemAnimationGfxOne(dst, 3, 2, false);  // bow
+
+  Decomp_spr(&g_ram[0x14000], 95);
+  dst = LoadItemAnimationGfxOne(dst, 4, 3, true);  // shovel
+  dst = LoadItemAnimationGfxOne(dst, 3, 4, true);  // sleeping zzz
+  dst = LoadItemAnimationGfxOne(dst, 1, 5, true);  // misc #2
+  dst = LoadItemAnimationGfxOne(dst, 4, 6, false); // hookshot
+
+  Decomp_spr(&g_ram[0x14000], 96);
+  dst = LoadItemAnimationGfxOne(dst, 14, 7, true); // bugnet
+  dst = LoadItemAnimationGfxOne(dst, 7, 8, true);  // cane
+
+  Decomp_spr(&g_ram[0x14000], 95);
+  dst = LoadItemAnimationGfxOne(dst, 2, 9, true);  // book of mudora
+  Decomp_spr(&g_ram[0x14000], 84);
+
+  dst = &g_ram[0xa480];
+  Expand3To4High(dst, &g_ram[0x14000], g_ram, 8);
+  Expand3To4High(dst + 8 * 0x20, &g_ram[0x14180], g_ram, 8);
+
+  // rupees
+  Decomp_spr(&g_ram[0x14000], 96);
+  dst = &g_ram[0xb280];
+  Expand3To4High(dst, &g_ram[0x14000], g_ram, 3);
+  Expand3To4High(dst + 3 * 0x20, &g_ram[0x14180], g_ram, 3);
+
+  LoadItemGFX_Auxiliary();
+}
+
+void DecompressSwordGraphics() {  // 80d2c8
+  Decomp_spr(&g_ram[0x14600], 0x5f);
+  Decomp_spr(&g_ram[0x14000], 0x5e);
+  const uint8 *src = &g_ram[0x14000] + kSwordTypeToGfxOffs[link_sword_type];
+  Expand3To4High(&g_ram[0x9000 + 0], src, g_ram, 12);
+  Expand3To4High(&g_ram[0x9000 + 0x180], src + 0x180, g_ram, 12);
+}
+
+void DecompressShieldGraphics() {  // 80d308
+  Decomp_spr(&g_ram[0x14600], 0x5f);
+  Decomp_spr(&g_ram[0x14000], 0x5e);
+  const uint8 *src = &g_ram[0x14000] + kShieldTypeToGfxOffs[link_shield_type];
+  Expand3To4High(&g_ram[0x9000 + 0x300], src, g_ram, 6);
+  Expand3To4High(&g_ram[0x9000 + 0x3c0], src + 0x180, g_ram,6);
+}
+
+void DecompressAnimatedDungeonTiles(uint8 a) {  // 80d337
+  Decomp_bg(&g_ram[0x14000], a);
+  Do3To4Low16Bit(&g_ram[0x9000 + 0x1680], &g_ram[0x14000], 48);
+  Decomp_bg(&g_ram[0x14000], 0x5c);
+  Do3To4Low16Bit(&g_ram[0x9000 + 0x1C80], &g_ram[0x14000], 48);
+
+  for (int i = 0; i < 256; i++) {
+    uint8 *p = &g_ram[0x9000 + i * 2];
+    uint16 x = WORD(p[0x1880]);
+    WORD(p[0x1880]) = WORD(p[0x1C80]);
+    WORD(p[0x1C80]) = WORD(p[0x1E80]);
+    WORD(p[0x1E80]) = WORD(p[0x1A80]);
+    WORD(p[0x1A80]) = x;
+  }
+  animated_tile_vram_addr = 0x3b00;
+}
+
+void DecompressAnimatedOverworldTiles(uint8 a) {  // 80d394
+  Decomp_bg(&g_ram[0x14000], a);
+  Do3To4Low16Bit(&g_ram[0x9000 + 0x1680], &g_ram[0x14000], 64);
+  Decomp_bg(&g_ram[0x14000], a + 1);
+  Do3To4Low16Bit(&g_ram[0x9000 + 0x1E80], &g_ram[0x14000], 32);
+  animated_tile_vram_addr = 0x3c00;
+}
+
+void LoadItemGFX_Auxiliary() {  // 80d3c6
+  Decomp_bg(&g_ram[0x14000], 0xf);
+  Do3To4Low16Bit(&g_ram[0x9000 + 0x2340], &g_ram[0x14000], 16);
+
+  Decomp_spr(&g_ram[0x14000], 0x58);
+  Do3To4Low16Bit(&g_ram[0x9000 + 0x2540], &g_ram[0x14000], 32);
+
+  Decomp_bg(&g_ram[0x14000], 0x5);
+  Do3To4Low16Bit(&g_ram[0x9000 + 0x2dc0], &g_ram[0x14480], 2);
+}
+
+void LoadFollowerGraphics() {  // 80d423
+  uint8 yv = 0x64;
+  if (follower_indicator != 1) {
+    yv = 0x66;
+    if (follower_indicator >= 9) {
+      yv = 0x59;
+      if (follower_indicator >= 12)
+        yv = 0x58;
+    }
+  }
+  Decomp_spr(&g_ram[0x14600], yv);
+  Decomp_spr(&g_ram[0x14000], 0x65);
+  Do3To4Low16Bit(&g_ram[0x9000] + 0x2940, &g_ram[0x14000 + kTagalongWhich[follower_indicator]], 0x20);
+}
+
+void WriteTo4BPPBuffer_at_7F4000(uint8 a) {  // 80d4db
+  uint8 *src = &g_ram[0x14000] + kDecodeAnimatedSpriteTile_Tab[a];
+  Expand3To4High(&g_ram[0x9000] + 0x2d40, src, g_ram, 2);
+  Expand3To4High(&g_ram[0x9000] + 0x2d40 + 0x40, src + 0x180, g_ram, 2);
+}
+
+void DecodeAnimatedSpriteTile_variable(uint8 a) {  // 80d4ed
+  uint8 y = (a == 0x23 || a >= 0x37) ? 0x5d :
+            (a == 0xc || a >= 0x24) ? 0x5c : 0x5b;
+  Decomp_spr(&g_ram[0x14600], y);
+  Decomp_spr(&g_ram[0x14000], 0x5a);
+  WriteTo4BPPBuffer_at_7F4000(a);
+}
+
+void Expand3To4High(uint8 *dst, const uint8 *src, const uint8 *base, int num) {  // 80d61c
+  do {
+    const uint8 *src2 = src + 0x10;
+    int n = 8;
+    do {
+      uint16 t = WORD(src[0]);
+      uint8 u = src2[0];
+      WORD(dst[0]) = t;
+      WORD(dst[0x10]) = (t | (t >> 8) | u) << 8 | u;
+      src += 2, src2 += 1, dst += 2;
+    } while (--n);
+    dst += 16, src = src2;
+    if (!(src - base & 0x78))
+      src += 0x180;
+  } while (--num);
+}
+
+void LoadTransAuxGFX() {  // 80d66e
+  uint8 *dst = &g_ram[0x6000];
+  const uint8 *p = kAuxTilesets[aux_tile_theme_index];
+  int len;
+
+  if (p[0]) {
+    aux_bg_subset_0 = p[0];
+    len = Decomp_bg(dst, aux_bg_subset_0);
+    assert(len == 0x600);
+  }
+  if (p[1]) {
+    aux_bg_subset_1 = p[1];
+    len = Decomp_bg(dst + 0x600, aux_bg_subset_1);
+    assert(len == 0x600);
+  }
+  if (p[2]) {
+    aux_bg_subset_2 = p[2];
+    len = Decomp_bg(dst + 0x600*2, aux_bg_subset_2);
+    assert(len == 0x600);
+  }
+  if (p[3]) {
+    aux_bg_subset_3 = p[3];
+    len = Decomp_bg(dst + 0x600*3, aux_bg_subset_3);
+    assert(len == 0x600);
+  }
+  Gfx_LoadSpritesInner(dst + 0x600 * 4 );
+}
+
+void LoadTransAuxGFX_sprite() {  // 80d6f9
+  Gfx_LoadSpritesInner(&g_ram[0x7800]);
+}
+
+void Gfx_LoadSpritesInner(uint8 *dst) {  // 80d706
+  const uint8 *p = kSpriteTilesets[sprite_graphics_index];
+  int len;
+
+  if (p[0])
+    sprite_gfx_subset_0 = p[0];
+  len = Decomp_spr(dst, sprite_gfx_subset_0);
+  assert(len == 0x600);
+  if (p[1])
+    sprite_gfx_subset_1 = p[1];
+  len = Decomp_spr(dst + 0x600, sprite_gfx_subset_1);
+  assert(len == 0x600);
+  if (p[2])
+    sprite_gfx_subset_2 = p[2];
+  len = Decomp_spr(dst + 0x600*2, sprite_gfx_subset_2);
+  assert(len == 0x600);
+  if (p[3])
+    sprite_gfx_subset_3 = p[3];
+  len = Decomp_spr(dst + 0x600*3, sprite_gfx_subset_3);
+  assert(len == 0x600);
+  incremental_counter_for_vram = 0;
+}
+
+void ReloadPreviouslyLoadedSheets() {  // 80d788
+  Decomp_bg(&g_ram[0x6000], aux_bg_subset_0);
+  Decomp_bg(&g_ram[0x6600], aux_bg_subset_1);
+  Decomp_bg(&g_ram[0x6c00], aux_bg_subset_2);
+  Decomp_bg(&g_ram[0x7200], aux_bg_subset_3);
+  Decomp_spr(&g_ram[0x7800], sprite_gfx_subset_0);
+  Decomp_spr(&g_ram[0x7e00], sprite_gfx_subset_1);
+  Decomp_spr(&g_ram[0x8400], sprite_gfx_subset_2);
+  Decomp_spr(&g_ram[0x8a00], sprite_gfx_subset_3);
+  incremental_counter_for_vram = 0;
+}
+
+void Attract_DecompressStoryGFX() {  // 80d80e
+  Decomp_spr(&g_ram[0x14000], 0x67);
+  Decomp_spr(&g_ram[0x14800], 0x68);
+}
+
+void AnimateMirrorWarp() {  // 80d864
+  int st = overworld_map_state++, tt;
+  nmi_subroutine_index = nmi_disable_core_updates = kMirrorWarp_LoadNext_NmiLoad[st];
+  uint8 t, xt = overworld_screen_index & 0x40 ? 8 : 0;
+  switch (st) {
+  case 0:
+    if (++mirror_vars.ctr2 != 32)
+      overworld_map_state = 0;
+    else
+      SetTargetOverworldWarpToPyramid();
+    break;
+  case 1:
+    AnimateMirrorWarp_DecompressNewTileSets();
+    Decomp_bg(&g_ram[0x14000], kVariousPacks[xt]);
+    Decomp_bg(&g_ram[0x14600], kVariousPacks[xt + 1]);
+    Do3To4High16Bit(&g_ram[0x10000], &g_ram[0x14000], 64);
+    Do3To4Low16Bit(&g_ram[0x10800], &g_ram[0x14600], 64);
+    break;
+  case 2:
+    Decomp_bg(&g_ram[0x14000], kVariousPacks[xt + 2]);
+    Decomp_bg(&g_ram[0x14600], kVariousPacks[xt + 3]);
+    Do3To4Low16Bit(&g_ram[0x10000], &g_ram[0x14000], 64);
+    Do3To4High16Bit(&g_ram[0x10800], &g_ram[0x14600], 64);
+    break;
+  case 3:
+    Decomp_bg(&g_ram[0x14000], aux_bg_subset_1);
+    Decomp_bg(&g_ram[0x14600], aux_bg_subset_2);
+    Do3To4High16Bit(&g_ram[0x10000], &g_ram[0x14000], 128);
+    break;
+  case 4:
+    Decomp_bg(&g_ram[0x14000], kVariousPacks[xt + 4]);
+    Decomp_bg(&g_ram[0x14600], kVariousPacks[xt + 5]);
+    Do3To4Low16Bit(&g_ram[0x10000], &g_ram[0x14000], 128);
+    break;
+  case 5:
+    PreOverworld_LoadOverlays();
+    if (BYTE(overworld_screen_index) == 27 || BYTE(overworld_screen_index) == 91)
+      TS_copy = 1;
+    submodule_index--;
+    nmi_subroutine_index = nmi_disable_core_updates = 12;
+    break;
+  case 6:
+  case 9:
+    nmi_subroutine_index = nmi_disable_core_updates = 13;
+    break;
+  case 7:
+    Overworld_DrawScreenAtCurrentMirrorPosition();
+    nmi_disable_core_updates++;
+    break;
+  case 8:
+    MirrorWarp_LoadSpritesAndColors();
+    nmi_subroutine_index = nmi_disable_core_updates = 12;
+    break;
+  case 10:
+    t = overworld_screen_index & 0xbf;
+    DecompressAnimatedOverworldTiles(t == 3 || t == 5 || t == 7 ? 0x58 : 0x5a);
+    break;
+  case 11:
+    t = overworld_screen_index;
+    TS_copy = (t == 0 || t == 0x70 || t == 0x40 || t == 0x5b || t == 3 || t == 5 || t == 7 || t == 0x43 || t == 0x45 || t == 0x47);
+    Do3To4High16Bit(&g_ram[0x10000], GetCompSpritePtr(kVariousPacks[xt + 6]), 64);
+    break;
+  case 12:
+    Decomp_spr(&g_ram[0x14000], sprite_gfx_subset_0);
+    Decomp_spr(&g_ram[0x14600], sprite_gfx_subset_1);
+    tt = WORD(sprite_gfx_subset_0);
+    if (tt == 0x52 || tt == 0x53 || tt == 0x5a || tt == 0x5b)
+      Do3To4High16Bit(&g_ram[0x10000], &g_ram[0x14000], 64);
+    else
+      Do3To4Low16Bit(&g_ram[0x10000], &g_ram[0x14000], 64);
+    Do3To4Low16Bit(&g_ram[0x10800], &g_ram[0x14600], 64);
+    break;
+  case 13:
+    Decomp_spr(&g_ram[0x14000], sprite_gfx_subset_2);
+    Decomp_spr(&g_ram[0x14600], sprite_gfx_subset_3);
+    Do3To4Low16Bit(&g_ram[0x10000], &g_ram[0x14000], 128);
+    HandleFollowersAfterMirroring();
+    break;
+  case 14:
+    overworld_map_state = 14;
+    break;
+  }
+}
+
+void AnimateMirrorWarp_DecompressNewTileSets() {  // 80d8fe
+  const uint8 *mt = kMainTilesets[main_tile_theme_index];
+  const uint8 *at = kAuxTilesets[aux_tile_theme_index];
+
+  aux_bg_subset_0 = at[0] ? at[0] : mt[3];
+  aux_bg_subset_1 = at[1] ? at[1] : mt[4];
+  aux_bg_subset_2 = at[2] ? at[2] : mt[5];
+  aux_bg_subset_3 = at[3] ? at[3] : mt[6];
+
+  const uint8 *p = kSpriteTilesets[sprite_graphics_index];
+  if (p[0]) sprite_gfx_subset_0 = p[0];
+  if (p[1]) sprite_gfx_subset_1 = p[1];
+  if (p[2]) sprite_gfx_subset_2 = p[2];
+  if (p[3]) sprite_gfx_subset_3 = p[3];
+}
+
+void Graphics_IncrementalVRAMUpload() {  // 80deff
+  if (incremental_counter_for_vram == 16)
+    return;
+
+  static const uint8 kGraphics_IncrementalVramUpload_Dst[16] = { 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f };
+  static const uint8 kGraphics_IncrementalVramUpload_Src[16] = { 0x0, 0x2, 0x4, 0x6, 0x8, 0xa, 0xc, 0xe, 0x10, 0x12, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e };
+
+  nmi_update_tilemap_dst = kGraphics_IncrementalVramUpload_Dst[incremental_counter_for_vram];
+  nmi_update_tilemap_src = kGraphics_IncrementalVramUpload_Src[incremental_counter_for_vram] << 8;
+  incremental_counter_for_vram++;
+}
+
+void PrepTransAuxGfx() {  // 80df1a
+  Do3To4High16Bit(&g_ram[0x10000], &g_ram[0x6000], 0x40);
+  if (aux_tile_theme_index >= 32) {
+    Do3To4High16Bit(&g_ram[0x10800], &g_ram[0x6600], 0x80);
+    Do3To4Low16Bit(&g_ram[0x11800], &g_ram[0x7200], 0x40);
+  } else {
+    Do3To4Low16Bit(&g_ram[0x10800], &g_ram[0x6600], 0xC0);
+  }
+}
+
+void Do3To4High16Bit(uint8 *dst, const uint8 *src, int num) {  // 80df4f
+  do {
+    const uint8 *src2 = src + 0x10;
+    int n = 8;
+    do {
+      uint16 t = WORD(src[0]);
+      uint8 u = src2[0];
+      WORD(dst[0]) = t;
+      WORD(dst[0x10]) = (t | (t >> 8) | u) << 8 | u;
+      src += 2, src2 += 1, dst += 2;
+    } while (--n);
+    dst += 16, src = src2;
+  } while (--num);
+
+}
+
+void Do3To4Low16Bit(uint8 *dst, const uint8 *src, int num) {  // 80dfb8
+  do {
+    const uint8 *src2 = src + 0x10;
+    int n = 8;
+    do {
+      WORD(dst[0]) = WORD(src[0]);
+      WORD(dst[0x10]) = src2[0];
+      src += 2, src2 += 1, dst += 2;
+    } while (--n);
+    dst += 16, src = src2;
+  } while (--num);
+}
+
+void LoadNewSpriteGFXSet() {  // 80e031
+  Do3To4Low16Bit(&g_ram[0x10000], &g_ram[0x7800], 0xC0);
+  if (sprite_gfx_subset_3 == 0x52 || sprite_gfx_subset_3 == 0x53 || sprite_gfx_subset_3 == 0x5a || sprite_gfx_subset_3 == 0x5b)
+    Do3To4High16Bit(&g_ram[0x11800], &g_ram[0x8a00], 0x40);
+  else
+    Do3To4Low16Bit(&g_ram[0x11800], &g_ram[0x8a00], 0x40);
+}
+
+void InitializeTilesets() {  // 80e19b
+  LoadCommonSprites();
+
+  const uint8 *p = kSpriteTilesets[sprite_graphics_index];
+  if (p[0]) sprite_gfx_subset_0 = p[0];
+  if (p[1]) sprite_gfx_subset_1 = p[1];
+  if (p[2]) sprite_gfx_subset_2 = p[2];
+  if (p[3]) sprite_gfx_subset_3 = p[3];
+
+  LoadSpriteGraphics(&g_zenv.vram[0x5000], sprite_gfx_subset_0, &g_ram[0x7800]);
+  LoadSpriteGraphics(&g_zenv.vram[0x5400], sprite_gfx_subset_1, &g_ram[0x7e00]);
+  LoadSpriteGraphics(&g_zenv.vram[0x5800], sprite_gfx_subset_2, &g_ram[0x8400]);
+  LoadSpriteGraphics(&g_zenv.vram[0x5c00], sprite_gfx_subset_3, &g_ram[0x8a00]);
+
+  const uint8 *mt = kMainTilesets[main_tile_theme_index];
+  const uint8 *at = kAuxTilesets[aux_tile_theme_index];
+
+  aux_bg_subset_0 = at[0] ? at[0] : mt[3];
+  aux_bg_subset_1 = at[1] ? at[1] : mt[4];
+  aux_bg_subset_2 = at[2] ? at[2] : mt[5];
+  aux_bg_subset_3 = at[3] ? at[3] : mt[6];
+
+  LoadBackgroundGraphics(&g_zenv.vram[0x2000], mt[0], 7, &g_ram[0x14000]);
+  LoadBackgroundGraphics(&g_zenv.vram[0x2400], mt[1], 6, &g_ram[0x14000]);
+  LoadBackgroundGraphics(&g_zenv.vram[0x2800], mt[2], 5, &g_ram[0x14000]);
+  LoadBackgroundGraphics(&g_zenv.vram[0x2c00], aux_bg_subset_0, 4, &g_ram[0x6000]);
+  LoadBackgroundGraphics(&g_zenv.vram[0x3000], aux_bg_subset_1, 3, &g_ram[0x6600]);
+  LoadBackgroundGraphics(&g_zenv.vram[0x3400], aux_bg_subset_2, 2, &g_ram[0x6c00]);
+  LoadBackgroundGraphics(&g_zenv.vram[0x3800], aux_bg_subset_3, 1, &g_ram[0x7200]);
+  LoadBackgroundGraphics(&g_zenv.vram[0x3c00], mt[7], 0, &g_ram[0x14000]);
+}
+
+void LoadDefaultGraphics() {  // 80e2d0
+  const uint8 *src = GetCompSpritePtr(0);
+
+  uint16 *vram_ptr = &g_zenv.vram[0x4000];
+  uint16 *tmp = (uint16 *)&g_ram[0xbf];
+  int num = 64;
+  do {
+    for (int i = 7; i >= 0; i--, src += 2) {
+      *vram_ptr++ = WORD(src[0]);
+      tmp[i] = src[0] | src[1];
+    }
+    for (int i = 7; i >= 0; i--, src++) {
+      *vram_ptr++ = src[0] | (src[0] | tmp[i]) << 8;
+    }
+  } while (--num);
+
+  // Load 2bpp graphics used for hud
+  DecompAndUpload2bpp(&g_zenv.vram[0x7000], 0x6a);
+  DecompAndUpload2bpp(&g_zenv.vram[0x7400], 0x6b);
+  DecompAndUpload2bpp(&g_zenv.vram[0x7800], 0x69);
+}
+
+void Attract_LoadBG3GFX() {  // 80e36d
+  // load 2bpp gfx for attract images
+  DecompAndUpload2bpp(&g_zenv.vram[0x7800], 0x67);
+}
+
+void Graphics_LoadChrHalfSlot() {  // 80e3fa
+  int k = load_chr_halfslot_even_odd;
+  if (k == 0)
+    return;
+
+  int8 sp6 = kGraphicsLoadSp6[k - 1];
+  if (sp6 >= 0) {
+    palette_sp6r_indoors = sp6;
+    if (k == 1) {
+      palette_sp6r_indoors = 10;
+      overworld_palette_aux_or_main = 0x200;
+      Palette_Load_SpriteEnvironment();
+      flag_update_cgram_in_nmi++;
+    } else {
+      overworld_palette_aux_or_main = 0x200;
+      Palette_Load_SpriteEnvironment_Dungeon();
+      flag_update_cgram_in_nmi++;
+    }
+  }
+  int tilebytes = 0x44;
+  int bank_offs = 0;
+  load_chr_halfslot_even_odd++;
+
+  if (load_chr_halfslot_even_odd & 1) {
+    load_chr_halfslot_even_odd = 0;
+    if (k != 18) {
+      bank_offs = 0x300;
+      tilebytes = 0x46;
+      if (k == 2)
+        flag_custom_spell_anim_active = 0;
+    }
+  }
+  BYTE(nmi_load_target_addr) = tilebytes;
+  nmi_subroutine_index = 11;
+
+  k = kGraphicsHalfSlotPacks[k - 1];
+  if (k == 1)
+    k = misc_sprites_graphics_index;
+
+  const uint8 *srcp = GetCompSpritePtr(k) + bank_offs;
+  uint8 sprdata[24];
+  int num = 32;
+  uint8 *dst = &g_ram[0x11000];
+
+  do {
+    for (int i = 0; i < 24; i++)
+      sprdata[i] = *srcp++;
+
+    uint8 *src = sprdata, *src2 = sprdata + 16;
+    int n = 8;
+    do {
+      uint16 t = WORD(src[0]);
+      uint8 u = src2[0];
+      WORD(dst[0]) = t;
+      WORD(dst[16]) = (t | (t >> 8) | u) << 8 | u;
+      src += 2, src2 += 1, dst += 2;
+    } while (--n);
+    dst += 16;
+  } while (--num);
+}
+
+void TransferFontToVRAM() {  // 80e556
+  memcpy(&g_zenv.vram[0x7000], FindIndexInMemblk(kDialogueFont(0), 0).ptr, 0x800 * sizeof(uint16));
+}
+
+void Do3To4High(uint16 *vram_ptr, const uint8 *decomp_addr) {  // 80e5af
+  for (int j = 0; j < 64; j++) {
+    uint16 *t = (uint16 *)&dung_line_ptrs_row0;
+    for (int i = 7; i >= 0; i--, decomp_addr += 2) {
+      uint16 d = *(uint16 *)decomp_addr;
+      t[i] = (d | (d >> 8)) & 0xff;
+      *vram_ptr++ = d;
+    }
+    for (int i = 7; i >= 0; i--, decomp_addr += 1) {
+      uint8 d = *decomp_addr;
+      *vram_ptr++ = d | (t[i] | d) << 8;
+    }
+  }
+}
+
+void Do3To4Low(uint16 *vram_ptr, const uint8 *decomp_addr) {  // 80e63c
+  for (int j = 0; j < 64; j++) {
+    for (int i = 0; i < 8; i++, decomp_addr += 2)
+      *vram_ptr++ = *(uint16 *)decomp_addr;
+    for (int i = 0; i < 8; i++, decomp_addr += 1)
+      *vram_ptr++ = *decomp_addr;
+  }
+}
+
+void LoadSpriteGraphics(uint16 *vram_ptr, int gfx_pack, uint8 *decomp_addr) {  // 80e583
+  Decomp_spr(decomp_addr, gfx_pack);
+  if (gfx_pack == 0x52 || gfx_pack == 0x53 || gfx_pack == 0x5a || gfx_pack == 0x5b ||
+      gfx_pack == 0x5c || gfx_pack == 0x5e || gfx_pack == 0x5f)
+    Do3To4High(vram_ptr, decomp_addr);
+  else
+    Do3To4Low(vram_ptr, decomp_addr);
+}
+
+void LoadBackgroundGraphics(uint16 *vram_ptr, int gfx_pack, int slot, uint8 *decomp_addr) {  // 80e609
+  Decomp_bg(decomp_addr, gfx_pack);
+  if ((main_tile_theme_index >= 0x20) ? (slot == 7 || slot == 2 || slot == 3 || slot == 4) : (slot >= 4))
+    Do3To4High(vram_ptr, decomp_addr);
+  else
+    Do3To4Low(vram_ptr, decomp_addr);
+}
+
+void LoadCommonSprites() {  // 80e6b7
+  Do3To4High(&g_zenv.vram[0x4400], GetCompSpritePtr(misc_sprites_graphics_index));
+  if (main_module_index != 1) {
+    Do3To4Low(&g_zenv.vram[0x4800], GetCompSpritePtr(6));
+    Do3To4Low(&g_zenv.vram[0x4c00], GetCompSpritePtr(7));
+  } else {
+    // select file
+    LoadSpriteGraphics(&g_zenv.vram[0x4800], 94, &g_ram[0x14000]);
+    LoadSpriteGraphics(&g_zenv.vram[0x4c00], 95, &g_ram[0x14000]);
+  }
+}
+
+int Decomp_spr(uint8 *dst, int gfx) {  // 80e772
+  if (gfx < 12)
+    gfx = 12; // ensure it wont decode bad sheets.
+  MemBlk blk = kSprGfx(gfx);
+  const uint8 *sprite_data = GetCompSpritePtr(gfx);
+  // If the size is not 0x600 then it's compressed
+  if (gfx >= 103 || blk.size != 0x600)
+    return Decompress(dst, blk.ptr);
+  memcpy(dst, blk.ptr, 0x600);
+  return 0x600;
+}
+
+int Decomp_bg(uint8 *dst, int gfx) {  // 80e78f
+  return Decompress(dst, kBgGfx(gfx).ptr);
+}
+
+int Decompress(uint8 *dst, const uint8 *src) {  // 80e79e
+  uint8 *dst_org = dst;
+  int len;
+  for (;;) {
+    uint8 cmd = *src++;
+    if (cmd == 0xff)
+      return dst - dst_org;
+    if ((cmd & 0xe0) != 0xe0) {
+      len = (cmd & 0x1f) + 1;
+      cmd &= 0xe0;
+    } else {
+      len = *src++;
+      len += ((cmd & 3) << 8) + 1;
+      cmd = (cmd << 3) & 0xe0;
+    }
+    //printf("%d: %d,%d\n", (int)(dst - dst_org), cmd, len);
+    if (cmd == 0) {
+      do {
+        *dst++ = *src++;
+      } while (--len);
+    } else if (cmd & 0x80) {
+      uint32 offs = *src++;
+      offs |= *src++ << 8;
+      do {
+        *dst++ = dst_org[offs++];
+      } while (--len);
+    } else if (!(cmd & 0x40)) {
+      uint8 v = *src++;
+      do {
+        *dst++ = v;
+      } while (--len);
+    } else if (!(cmd & 0x20)) {
+      uint8 lo = *src++;
+      uint8 hi = *src++;
+      do {
+        *dst++ = lo;
+        if (--len == 0)
+          break;
+        *dst++ = hi;
+      } while (--len);
+    } else {
+      // copy bytes with the byte incrementing by 1 in between
+      uint8 v = *src++;
+      do {
+        *dst++ = v;
+      } while (v++, --len);
+    }
+  }
+}
+
+void ResetHUDPalettes4and5() {  // 80eb29
+  for (int i = 0; i < 8; i++)
+    main_palette_buffer[16 + i] = 0;
+  palette_filter_countdown = 0;
+  darkening_or_lightening_screen = 2;
+  flag_update_cgram_in_nmi++;
+}
+
+void PaletteFilterHistory() {  // 80eb5e
+  PaletteFilter_Range(0x10, 0x18);
+  PaletteFilter_IncrCountdown();
+}
+
+void PaletteFilter_WishPonds() {  // 80ebc5
+  TS_copy = 2;
+  CGADSUB_copy = 0x30;
+  PaletteFilter_WishPonds_Inner();
+}
+
+void PaletteFilter_Crystal() {  // 80ebcf
+  TS_copy = 1;
+  PaletteFilter_WishPonds_Inner();
+}
+
+void PaletteFilter_WishPonds_Inner() {  // 80ebd3
+  for (int i = 0; i < 8; i++)
+    main_palette_buffer[0xd0 + i] = 0;
+  palette_filter_countdown = 0;
+  darkening_or_lightening_screen = 2;
+  flag_update_cgram_in_nmi++;
+}
+
+void PaletteFilter_RestoreSP5F() {  // 80ebf2
+  for (int i = 7; i >= 0; i--)
+    main_palette_buffer[208 + i] = aux_palette_buffer[208 + i];
+  TS_copy = 0;
+  CGADSUB_copy = 32;
+  flag_update_cgram_in_nmi++;
+}
+
+void PaletteFilter_SP5F() {  // 80ec0d
+  for (int i = 0; i != 2; i++) {
+    PaletteFilter_Range(208, 216);
+    PaletteFilter_IncrCountdown();
+    if (palette_filter_countdown == 0)
+      break;
+  }
+}
+
+void KholdstareShell_PaletteFiltering() {  // 80ec79
+  int t = (enhanced_features0 & kFeatures0_MiscBugFixes) ? 0x50 : 0x40;
+  if (subsubmodule_index == 0) {
+    memcpy(main_palette_buffer + t, aux_palette_buffer + t, 8 * sizeof(uint16));
+    palette_filter_countdown = 0;
+    darkening_or_lightening_screen = 0;
+    flag_update_cgram_in_nmi++;
+    subsubmodule_index = 1;
+    return;
+  }
+  for (int i = 0; i != 2; i++) {
+    PaletteFilter_Range(t, t + 8);
+    PaletteFilter_IncrCountdown();
+    if (palette_filter_countdown == 0) {
+      TS_copy = 0;
+      break;
+    }
+  }
+}
+
+void AgahnimWarpShadowFilter(int k) {  // 80ecca
+  palette_filter_countdown = agahnim_pal_setting[k];
+  darkening_or_lightening_screen = agahnim_pal_setting[k + 3];
+  int t = kPaletteFilter_Agahnim_Tab[k] >> 1;
+  for (int i = 0; i < 2; i++) {
+    PaletteFilter_Range(t, t + 8);
+    if (++palette_filter_countdown == 0x1f) {
+      palette_filter_countdown = 0;
+      darkening_or_lightening_screen ^= 2;
+      break;
+    }
+  }
+  agahnim_pal_setting[k] = palette_filter_countdown;
+  agahnim_pal_setting[k + 3] = darkening_or_lightening_screen;
+  flag_update_cgram_in_nmi++;
+}
+
+void Palette_FadeIntroOneStep() {  // 80ed7c
+  PaletteFilter_RestoreAdditive(0x100, 0x1a0);
+  PaletteFilter_RestoreAdditive(0xc0, 0x100);
+  BYTE(palette_filter_countdown) -= 1;
+  flag_update_cgram_in_nmi++;
+}
+
+void Palette_FadeIntro2() {  // 80ed8f
+  PaletteFilter_RestoreAdditive(0x40, 0xc0);
+  PaletteFilter_RestoreAdditive(0x40, 0xc0);
+  BYTE(palette_filter_countdown) -= 1;
+  flag_update_cgram_in_nmi++;
+}
+
+void PaletteFilter_RestoreAdditive(int from, int to) {  // 80edca
+  from >>= 1, to >>= 1;
+  do {
+    uint16 c = main_palette_buffer[from], cx = c;
+    uint16 d = aux_palette_buffer[from];
+    if ((c & 0x1f) != (d & 0x1f))
+      cx += 1;
+    if ((c & 0x3e0) != (d & 0x3e0))
+      cx += 0x20;
+    if ((c & 0x7c00) != (d & 0x7c00))
+      cx += 0x400;
+    main_palette_buffer[from] = cx;
+  } while (++from != to);
+}
+
+void PaletteFilter_RestoreSubtractive(uint16 from, uint16 to) {  // 80ee21
+  from >>= 1, to >>= 1;
+  do {
+    uint16 c = main_palette_buffer[from], cx = c;
+    uint16 d = aux_palette_buffer[from];
+    if ((c & 0x1f) != (d & 0x1f))
+      cx -= 1;
+    if ((c & 0x3e0) != (d & 0x3e0))
+      cx -= 0x20;
+    if ((c & 0x7c00) != (d & 0x7c00))
+      cx -= 0x400;
+    main_palette_buffer[from] = cx;
+  } while (++from != to);
+}
+
+void PaletteFilter_InitializeWhiteFilter() {  // 80ee78
+  for (int i = 0; i < 256; i++)
+    aux_palette_buffer[i] = 0x7fff;
+  main_palette_buffer[32] = main_palette_buffer[0];
+  palette_filter_countdown = 0;
+  darkening_or_lightening_screen = 2;
+  if (overworld_screen_index == 27) {
+    aux_palette_buffer[0] = aux_palette_buffer[32] = 0;
+    main_palette_buffer[0] = main_palette_buffer[32] = 0;
+  }
+  mirror_vars.ctr = 8;
+  mirror_vars.ctr2 = 0;
+}
+
+void MirrorWarp_RunAnimationSubmodules() {  // 80eee7
+  if (--mirror_vars.ctr) {
+    AnimateMirrorWarp();
+    return;
+  }
+  mirror_vars.ctr = 2;
+  PaletteFilter_BlindingWhite();
+}
+
+void PaletteFilter_BlindingWhite() {  // 80eef1
+  if (darkening_or_lightening_screen == 0xff)
+    return;
+
+  if (darkening_or_lightening_screen == 2) {
+    PaletteFilter_RestoreAdditive(0x40, 0x1b0);
+    PaletteFilter_RestoreAdditive(0x1c0, 0x1e0);
+  } else {
+    PaletteFilter_RestoreSubtractive(0x40, 0x1b0);
+    PaletteFilter_RestoreSubtractive(0x1c0, 0x1e0);
+  }
+  PaletteFilter_StartBlindingWhite();
+}
+
+void PaletteFilter_StartBlindingWhite() {  // 80ef27
+  main_palette_buffer[0] = main_palette_buffer[32];
+  if (!darkening_or_lightening_screen) {
+    if (++palette_filter_countdown == 66) {
+      darkening_or_lightening_screen = 0xff;
+      mirror_vars.ctr = 32;
+    }
+  } else {
+    if (++palette_filter_countdown == 31) {
+      darkening_or_lightening_screen ^= 2;
+      if (main_module_index != 21)
+        return;
+      zelda_snes_dummy_write(HDMAEN, 0);
+      HDMAEN_copy = 0;
+      for (int i = 0; i < 240; i++)
+        hdma_table_dynamic[i] = 0x778;
+      HDMAEN_copy = 0xc0;
+    }
+  }
+  flag_update_cgram_in_nmi++;
+}
+
+void PaletteFilter_BlindingWhiteTriforce() {  // 80ef8a
+  PaletteFilter_RestoreAdditive(0x40, 0x200);
+  PaletteFilter_StartBlindingWhite();
+}
+
+void PaletteFilter_WhirlpoolBlue() {  // 80ef97
+  if (frame_counter & 1) {
+    for (int i = 0x20; i != 0x100; i++) {
+      uint16 t = main_palette_buffer[i];
+      if ((t & 0x7C00) != 0x7C00)
+        t += 0x400;
+      main_palette_buffer[i] = t;
+    }
+    main_palette_buffer[0] = main_palette_buffer[32];
+    if (!(palette_filter_countdown & 1))
+      mosaic_level += 16;
+    if (++palette_filter_countdown == 31) {
+      palette_filter_countdown = 0;
+      subsubmodule_index++;
+      mosaic_level = 0xf0;
+    }
+  }
+  BGMODE_copy = 9;
+  MOSAIC_copy = mosaic_level | 3;
+  flag_update_cgram_in_nmi++;
+}
+
+void PaletteFilter_IsolateWhirlpoolBlue() {  // 80f00c
+  for (int i = 0x20; i != 0x100; i++) {
+    uint16 t = main_palette_buffer[i];
+    if (t & 0x3e0)
+      t -= 0x20;
+    if (t & 0x1f)
+      t -= 1;
+    main_palette_buffer[i] = t;
+  }
+  main_palette_buffer[0] = main_palette_buffer[32];
+  if (++palette_filter_countdown == 31) {
+    palette_filter_countdown = 0;
+    subsubmodule_index++;
+    mosaic_level = 0xf0;
+  }
+  BGMODE_copy = 9;
+  MOSAIC_copy = mosaic_level | 3;
+  flag_update_cgram_in_nmi++;
+}
+
+void PaletteFilter_WhirlpoolRestoreBlue() {  // 80f04a
+  if (frame_counter & 1) {
+    for (int i = 0x20; i != 0x100; i++) {
+      uint16 u = aux_palette_buffer[i] & 0x7c00;
+      uint16 t = main_palette_buffer[i];
+      if ((t & 0x7C00) != u)
+        t -= 0x400;
+      main_palette_buffer[i] = t;
+    }
+    main_palette_buffer[0] = main_palette_buffer[32];
+    if (!(palette_filter_countdown & 1))
+      mosaic_level -= 16;
+    if (++palette_filter_countdown == 31) {
+      palette_filter_countdown = 0;
+      subsubmodule_index++;
+      mosaic_level = 0;
+    }
+  }
+  BGMODE_copy = 9;
+  MOSAIC_copy = mosaic_level | 3;
+  flag_update_cgram_in_nmi++;
+}
+
+void PaletteFilter_WhirlpoolRestoreRedGreen() {  // 80f0c7
+  for (int i = 0x20; i != 0x100; i++) {
+    uint16 u0 = aux_palette_buffer[i] & 0x3e0;
+    uint16 u1 = aux_palette_buffer[i] & 0x1f;
+    uint16 t = main_palette_buffer[i];
+    if ((t & 0x3e0) != u0)
+      t += 0x20;
+    if ((t & 0x1f) != u1)
+      t += 1;
+    main_palette_buffer[i] = t;
+  }
+  main_palette_buffer[0] = main_palette_buffer[32];
+  if (++palette_filter_countdown == 31) {
+    palette_filter_countdown = 0;
+    subsubmodule_index++;
+  }
+  flag_update_cgram_in_nmi++;
+}
+
+void PaletteFilter_RestoreBGSubstractiveStrict() {  // 80f135
+  if (darkening_or_lightening_screen == 255)
+    return;
+  PaletteFilter_RestoreSubtractive(0x40, 0x100);
+  if (++palette_filter_countdown == 0x20) {
+    darkening_or_lightening_screen = 255;
+    WORD(TS_copy) = 0;
+  }
+  flag_update_cgram_in_nmi++;
+}
+
+void PaletteFilter_RestoreBGAdditiveStrict() {  // 80f169
+  PaletteFilter_RestoreAdditive(0x40, 0x100);
+  palette_filter_countdown++;
+  flag_update_cgram_in_nmi++;
+}
+
+void Trinexx_FlashShellPalette_Red() {  // 80f183
+  if (!byte_7E04BE) {
+    for (int i = 0; i < 7; i++) {
+      uint16 v = main_palette_buffer[0x41 + i];
+      main_palette_buffer[0x41 + i] = (v & 0xffe0) | ((v & 0x1f) + ((v & 0x1f) != 0x1f));
+    }
+    flag_update_cgram_in_nmi++;
+    if (++byte_7E04C0 >= 12) {
+      byte_7E04C0 = byte_7E04BE = 0;
+      return;
+    }
+    byte_7E04BE = 3;
+  }
+  byte_7E04BE--;
+}
+
+void Trinexx_UnflashShellPalette_Red() {  // 80f1cf
+  if (!byte_7E04BE) {
+    for (int i = 0; i < 7; i++) {
+      uint16 u = aux_palette_buffer[0x41 + i];
+      uint16 v = main_palette_buffer[0x41 + i];
+      main_palette_buffer[0x41 + i] = (v & 0xffe0) | ((v & 0x1f) - ((v & 0x1f) != (u & 0x1f)));
+    }
+    flag_update_cgram_in_nmi++;
+    if (++byte_7E04C0 >= 12) {
+      byte_7E04C0 = byte_7E04BE = 0;
+      return;
+    }
+    byte_7E04BE = 3;
+  }
+  byte_7E04BE--;
+}
+
+void Trinexx_FlashShellPalette_Blue() {  // 80f207
+  if (!byte_7E04BF) {
+    for (int i = 0; i < 7; i++) {
+      uint16 v = main_palette_buffer[0x41 + i];
+      main_palette_buffer[0x41 + i] = (v & ~0x7c00) | (v & 0x7c00) + (((v & 0x7c00) != 0x7c00) << 10);
+    }
+    flag_update_cgram_in_nmi++;
+    if (++byte_7E04C1 >= 12) {
+      byte_7E04C1 = byte_7E04BF = 0;
+      return;
+    }
+    byte_7E04BF = 3;
+  }
+  byte_7E04BF--;
+
+}
+
+void Trinexx_UnflashShellPalette_Blue() {  // 80f253
+  if (!byte_7E04BF) {
+    for (int i = 0; i < 7; i++) {
+      uint16 u = aux_palette_buffer[0x41 + i];
+      uint16 v = main_palette_buffer[0x41 + i];
+      main_palette_buffer[0x41 + i] = (v & ~0x7c00) | (v & 0x7c00) - (((v & 0x7c00) != (u & 0x7c00)) << 10);
+    }
+    flag_update_cgram_in_nmi++;
+    if (++byte_7E04C1 >= 12) {
+      byte_7E04C1 = byte_7E04BF = 0;
+      return;
+    }
+    byte_7E04BF = 3;
+  }
+  byte_7E04BF--;
+}
+
+void IrisSpotlight_close() {  // 80f28b
+  SpotlightInternal(0x7e, 0);
+}
+
+void Spotlight_open() {  // 80f295
+  SpotlightInternal(0, 2);
+}
+
+void SpotlightInternal(uint8 x, uint8 y) {  // 80f29d
+  spotlight_var1 = x;
+  spotlight_var2 = y;
+
+  zelda_snes_dummy_write(HDMAEN, 0);
+  HdmaSetup(0xF2FB, 0xF2FB, 0x41, (uint8)WH0, (uint8)WH0, 0);
+
+  W12SEL_copy = 0x33;
+  W34SEL_copy = 3;
+  WOBJSEL_copy = 0x33;
+  TMW_copy = TM_copy;
+  TSW_copy = TS_copy;
+  if (!player_is_indoors) {
+    COLDATA_copy0 = 0x20;
+    COLDATA_copy1 = 0x40;
+    COLDATA_copy2 = 0x80;
+  }
+  IrisSpotlight_ConfigureTable();
+  HDMAEN_copy = 0x80;
+  INIDISP_copy = 0xf;
+}
+
+void IrisSpotlight_ConfigureTable() {  // 80f312
+  uint16 r14 = link_y_coord - BG2VOFS_copy2 + 12;
+  spotlight_y_lower = r14 - spotlight_var1;
+  spotlight_y_upper = r14 + spotlight_var1;
+  spotlight_var3 = link_x_coord - BG2HOFS_copy2 + 8;
+  spotlight_var4 = spotlight_var1;
+  uint16 r6 = r14 * 2;
+  if (r6 < 224)
+    r6 = 224;
+  uint16 r4 = r14 * 2 - r6;
+  for(;;) {
+    uint16 r8 = 0xff;
+    if (r6 < spotlight_y_upper) {
+      uint8 t = spotlight_var4;
+      if (spotlight_var4)
+        spotlight_var4--;
+      r8 = IrisSpotlight_CalculateCircleValue(t);
+    }
+    if (r4 < 240)
+      hdma_table_dynamic[r4] = r8;
+    if (r6 < 240)
+      hdma_table_dynamic[r6] = r8;
+    if (r4 == r14)
+      break;
+    r4++, r6--;
+  }
+
+  for (int i = 224; i < 240; i++)
+    hdma_table_dynamic[i] = 0;
+
+  memcpy(hdma_table_unused, hdma_table_dynamic, 224  * sizeof(uint16));
+
+  spotlight_var1 += kSpotlight_delta_size[spotlight_var2 >> 1];
+
+  if (spotlight_var1 != kSpotlight_goal[spotlight_var2 >> 1])
+    return;
+
+  if (!spotlight_var2) {
+    INIDISP_copy = 0x80;
+  } else {
+    IrisSpotlight_ResetTable();
+  }
+  subsubmodule_index = 0;
+  submodule_index = 0;
+
+  if (main_module_index == 7 || main_module_index == 16) {
+    if (!player_is_indoors)
+      sound_effect_ambient = overworld_music[BYTE(overworld_screen_index)] >> 4;
+    if (queued_music_control != 0xff)
+      music_control = queued_music_control;
+  }
+  main_module_index = saved_module_for_menu;
+  if (main_module_index == 6)
+    Sprite_ResetAll();
+}
+
+void IrisSpotlight_ResetTable() {  // 80f427
+  for (int i = 0; i < 240; i++)
+    hdma_table_dynamic[i] = 0xff00;
+}
+
+uint16 IrisSpotlight_CalculateCircleValue(uint8 a) {  // 80f4cc
+  uint8 t = snes_divide(a << 8, spotlight_var1) >> 1;
+  uint8 r10 = kConfigureSpotlightTable_Helper_Tab[t];
+  uint16 p = 2 * (uint8)(r10 * (uint8)spotlight_var1 >> 8);
+  if (!r10)
+    return 0xff;
+  uint16 r2 = spotlight_var3 + p;
+  uint16 r0 = spotlight_var3 - p;
+  r0 = ((int16)r0 < 0) ? 0 :
+         r0 < 255 ? r0 : 255;
+  r2 = r2 < 255 ? r2 : 255;
+  r0 |= r2 << 8;
+  return r0 == 0xffff ? 0xff : r0;
+}
+
+void AdjustWaterHDMAWindow() {  // 80f649
+  uint16 r10 = water_hdma_var1 - BG2VOFS_copy2;
+  spotlight_y_lower = r10 - water_hdma_var2;
+  spotlight_y_upper = r10 + water_hdma_var2;
+  AdjustWaterHDMAWindow_X(r10);
+}
+
+void AdjustWaterHDMAWindow_X(uint16 r10) {  // 80f660
+  spotlight_var3 = water_hdma_var0 - BG2HOFS_copy2;
+  uint16 r12 = water_hdma_var3 ? water_hdma_var3 - 1 : 0;
+  uint16 r2 = spotlight_var3 + r12;
+  uint16 r0 = spotlight_var3 - r12;
+
+  r0 = (r0 < 255) ? r0 : 255;
+  r2 = (r2 < 255) ? r2 : 255;
+  r12 = r0 | r2 << 8;
+
+  uint16 r6 = r10 * 2;
+  if (r6 < 0xe0)
+    r6 = 0xe0;
+  uint16 r4 = 2 * r10 - r6;
+  uint16 a;
+
+  do {
+    if (!sign16(r4)) {
+      if (!sign16(spotlight_y_lower) && r4 < spotlight_y_lower)
+        a = 0xff;
+      else
+        a = r12;
+      if (r4 < 240)
+        hdma_table_dynamic[r4] = (a != 0xffff) ? a : 0xff;
+    }
+    if (r6 >= spotlight_y_upper) {
+      a = 0xff;
+    } else {
+      if (r6 >= 225 && word_7E0678)
+        word_7E0678--;
+      a = r12;
+    }
+    if (r6 < 240)
+      hdma_table_dynamic[r6] = (a != 0xffff) ? a : 0xff;
+  } while (r6--, r10 != r4++);
+}
+
+void FloodDam_PrepFloodHDMA() {  // 80f734
+  spotlight_y_lower = water_hdma_var1 - BG2VOFS_copy2;
+  spotlight_var3 = water_hdma_var0 - BG2HOFS_copy2;
+  uint16 r14 = water_hdma_var3 ^ 1;
+  uint16 r12 = (spotlight_var3 + r14) << 8 | (uint8)(spotlight_var3 - r14);
+
+  int r4 = 0;
+  do {
+    hdma_table_dynamic[r4] = 0xff00;
+  } while (++r4 != spotlight_y_upper);
+
+  r12 = r14 - 7 + 8;
+  r12 = (spotlight_var3 + r12) << 8 | (uint8)(spotlight_var3 - r12);
+  uint16 r10 = (spotlight_y_upper + water_hdma_var2) ^ 1;
+
+  do {
+    if (r4 >= r10) {
+      hdma_table_dynamic[r4] = 0xff;
+    } else {
+      uint16 a = r4;
+      do {
+        a *= 2;
+      } while (a >= 480);
+      hdma_table_dynamic[a >> 1] = r12 == 0xffff ? 0xff : r12;
+    }
+  } while (++r4 < 225);
+}
+
+void ResetStarTileGraphics() {  // 80fda4
+  byte_7E04BC = 0;
+  Dungeon_RestoreStarTileChr();
+}
+
+void Dungeon_RestoreStarTileChr() {  // 80fda7
+  int xx = 0, yy = 32;
+  if (byte_7E04BC)
+    xx = 32, yy = 0;
+  uint16 *p = messaging_buf;
+  memcpy(p, g_ram + 0xbdc0 + xx, 32);
+  memcpy(p + 16, g_ram + 0xbdc0 + yy, 32);
+  nmi_subroutine_index = 0x18;
+}
+
+void LinkZap_HandleMosaic() {  // 81fed2
+  int level = mosaic_level;
+  if (!mosaic_inc_or_dec) {
+    level += 0x10;
+    if (level == 0xc0)
+      mosaic_inc_or_dec = 1;
+  } else {
+    level -= 0x10;
+    if (level == 0)
+      mosaic_inc_or_dec = 0;
+  }
+  mosaic_level = level;
+  MOSAIC_copy = mosaic_level >> 1 | 3;
+  BGMODE_copy = 9;
+}
+
+void Player_SetCustomMosaicLevel(uint8 a) {  // 81fef0
+  mosaic_inc_or_dec = 0;
+  mosaic_level = a;
+  MOSAIC_copy = mosaic_level >> 1 | 3;
+  BGMODE_copy = 9;
+}
+
+void Module07_16_UpdatePegs_Step1() {  // 829739
+  if (BYTE(orange_blue_barrier_state))
+    Dungeon_UpdatePegGFXBuffer(0x80, 0x100);
+  else
+    Dungeon_UpdatePegGFXBuffer(0x100, 0x80);
+}
+
+void Module07_16_UpdatePegs_Step2() {  // 82974d
+  if (BYTE(orange_blue_barrier_state))
+    Dungeon_UpdatePegGFXBuffer(0x100, 0x80);
+  else
+    Dungeon_UpdatePegGFXBuffer(0x80, 0x100);
+}
+
+void Dungeon_UpdatePegGFXBuffer(int x, int y) {  // 829773
+  uint16 *src = (uint16 *)&g_ram[0xb340];
+  for (int i = 0; i < 64; i++)
+    messaging_buf[i] = src[(x >> 1) + i];
+  for (int i = 0; i < 64; i++)
+    messaging_buf[64 + i] = src[(y >> 1) + i];
+  nmi_subroutine_index = 23;
+}
+
+void Dungeon_HandleTranslucencyAndPalette() {  // 82a1e9
+  if (palette_swap_flag)
+    Palette_RevertTranslucencySwap();
+
+  CGWSEL_copy = 2;
+  CGADSUB_copy = 0xb3;
+
+  uint8 torch = dung_num_lit_torches;
+  if (!dung_want_lights_out) {
+    uint8 a = 0x20;
+    if ((a = 0x20, dung_hdr_bg2_properties != 0) &&
+        (a = 0x32, dung_hdr_bg2_properties != 7) &&
+        (a = 0x62, dung_hdr_bg2_properties != 4) &&
+        (a = 0x20, dung_hdr_bg2_properties == 2)) {
+      Palette_AssertTranslucencySwap();
+      if (BYTE(dungeon_room_index) == 13) {
+        agahnim_pal_setting[0] = 0;
+        agahnim_pal_setting[1] = 0;
+        agahnim_pal_setting[2] = 0;
+        agahnim_pal_setting[3] = 0;
+        agahnim_pal_setting[4] = 0;
+        agahnim_pal_setting[5] = 0;
+        Palette_LoadAgahnim();
+      }
+      a = 0x70;
+    }
+    CGADSUB_copy = a;
+    torch = 3;
+  }
+  overworld_fixed_color_plusminus = kLitTorchesColorPlus[torch];
+  palette_filter_countdown = 31;
+  mosaic_target_level = 0;
+  darkening_or_lightening_screen = 2;
+  overworld_palette_aux_or_main = 0;
+  Palette_Load_DungeonSet();
+  Palette_Load_Sp0L();
+  Palette_Load_Sp5L();
+  Palette_Load_Sp6L();
+  subsubmodule_index += 1;
+}
+
+void Overworld_LoadAllPalettes() {  // 82c5b2
+  memset(aux_palette_buffer + 0x180 / 2, 0, 128);
+  memset(main_palette_buffer, 0, 512);
+
+  overworld_palette_mode = 5;
+  overworld_palette_aux1_bp2to4_hi = 3;
+  overworld_palette_aux2_bp5to7_hi = 3;
+  overworld_palette_aux3_bp7_lo = 0;
+  palette_sp6r_indoors = 5;
+  palette_sp0l = 11;
+  palette_swap_flag = 0;
+  overworld_palette_aux_or_main = 0;
+  Palette_BgAndFixedColor_Black();
+  Palette_Load_Sp0L();
+  Palette_Load_SpriteMain();
+  Palette_Load_OWBGMain();
+  Palette_Load_OWBG1();
+  Palette_Load_OWBG2();
+  Palette_Load_OWBG3();
+  Palette_Load_SpriteEnvironment_Dungeon();
+  Palette_Load_HUD();
+
+  for (int i = 0; i < 8; i++)
+    main_palette_buffer[0x1b0 / 2 + i] = aux_palette_buffer[0x1d0 / 2 + i];
+}
+
+void Dungeon_LoadPalettes() {  // 82c630
+  overworld_palette_aux_or_main = 0;
+  Palette_BgAndFixedColor_Black();
+  Palette_Load_Sp0L();
+  Palette_Load_SpriteMain();
+  Palette_Load_Sp5L();
+  Palette_Load_Sp6L();
+  Palette_Load_Sword();
+  Palette_Load_Shield();
+  Palette_Load_SpriteEnvironment();
+  Palette_Load_LinkArmorAndGloves();
+  Palette_Load_HUD();
+  Palette_Load_DungeonSet();
+  Overworld_LoadPalettesInner();
+}
+
+void Overworld_LoadPalettesInner() {  // 82c65f
+  overworld_pal_unk1 = palette_main_indoors;
+  overworld_pal_unk2 = overworld_palette_aux3_bp7_lo;
+  overworld_pal_unk3 = byte_7E0AB7;
+  darkening_or_lightening_screen = 2;
+  palette_filter_countdown = 0;
+  WORD(mosaic_target_level) = 0;
+  Overworld_CopyPalettesToCache();
+}
+
+void OverworldLoadScreensPaletteSet() {  // 82c692
+  uint8 sc = overworld_screen_index & 0x3f;
+  uint8 x = (sc == 3 || sc == 5 || sc == 7) ? 2 : 0;
+  x += (overworld_screen_index & 0x40) ? 1 : 0;
+  Overworld_LoadAreaPalettesEx(x);
+}
+
+void Overworld_LoadAreaPalettesEx(uint8 x) {  // 82c6ad
+  overworld_palette_mode = x;
+  overworld_palette_aux_or_main &= 0xff;
+  Palette_Load_SpriteMain();
+  Palette_Load_SpriteEnvironment();
+  Palette_Load_Sp5L();
+  Palette_Load_Sp6L();
+  Palette_Load_Sword();
+  Palette_Load_Shield();
+  Palette_Load_LinkArmorAndGloves();
+  palette_sp0l = (savegame_is_darkworld & 0x40) ? 3 : 1;
+  Palette_Load_Sp0L();
+  Palette_Load_HUD();
+  Palette_Load_OWBGMain();
+}
+
+void SpecialOverworld_CopyPalettesToCache() {  // 82c6eb
+  for (int i = 32; i < 32 * 8; i++)
+    main_palette_buffer[i] = 0;
+  for (int i = 0; i < 8; i++) {
+    main_palette_buffer[i] = aux_palette_buffer[i];
+    main_palette_buffer[i + 0x8] = aux_palette_buffer[i + 0x8];
+    main_palette_buffer[i + 0x10] = aux_palette_buffer[i + 0x10];
+    main_palette_buffer[i + 0x18] = aux_palette_buffer[i + 0x18];
+    main_palette_buffer[i + 0xd8] = aux_palette_buffer[i + 0xd8];
+    main_palette_buffer[i + 0xe8] = aux_palette_buffer[i + 0xe8];
+    main_palette_buffer[i + 0xf0] = aux_palette_buffer[i + 0xf0];
+    main_palette_buffer[i + 0xf8] = aux_palette_buffer[i + 0xf8];
+  }
+  MOSAIC_copy = 0xf7;
+  mosaic_level = 0xf7;
+  flag_update_cgram_in_nmi++;
+}
+
+void Overworld_CopyPalettesToCache() {  // 82c769
+  memcpy(main_palette_buffer, aux_palette_buffer, 512);
+  flag_update_cgram_in_nmi += 1;
+}
+
+void Overworld_LoadPalettes(uint8 bg, uint8 spr) {  // 8ed5a8
+  overworld_palette_aux_or_main = 0;
+
+  const int8 *d = kOwBgPalInfo + bg * 3;
+  if (d[0] >= 0)
+    overworld_palette_aux1_bp2to4_hi = d[0];
+  if (d[1] >= 0)
+    overworld_palette_aux2_bp5to7_hi = d[1];
+  if (d[2] >= 0)
+    overworld_palette_aux3_bp7_lo = d[2];
+
+  d = kOwSprPalInfo + spr * 2;
+  if (d[0] >= 0)
+    palette_sp5l = d[0];
+  if (d[1] >= 0)
+    palette_sp6l = d[1];
+  Palette_Load_OWBG1();
+  Palette_Load_OWBG2();
+  Palette_Load_OWBG3();
+  Palette_Load_Sp5L();
+  Palette_Load_Sp6L();
+}
+
+void Palette_BgAndFixedColor_Black() {  // 8ed5f4
+  Palette_SetBgAndFixedColor(0);
+}
+
+void Palette_SetBgAndFixedColor(uint16 color) {  // 8ed5f9
+  main_palette_buffer[0] = color;
+  main_palette_buffer[32] = color;
+  aux_palette_buffer[0] = color;
+  aux_palette_buffer[32] = color;
+  SetBackdropcolorBlack();
+}
+
+void SetBackdropcolorBlack() {  // 8ed60b
+  COLDATA_copy0 = 0x20;
+  COLDATA_copy1 = 0x40;
+  COLDATA_copy2 = 0x80;
+}
+
+void Palette_SetOwBgColor() {  // 8ed618
+  Palette_SetBgAndFixedColor(Palette_GetOwBgColor());
+}
+
+void Palette_SpecialOw() {  // 8ed61d
+  uint16 c = Palette_GetOwBgColor();
+  aux_palette_buffer[0] = c;
+  aux_palette_buffer[32] = c;
+  SetBackdropcolorBlack();
+}
+
+uint16 Palette_GetOwBgColor() {  // 8ed622
+  if (overworld_screen_index < 0x80)
+    return overworld_screen_index & 0x40 ? 0x2A32 : 0x2669;
+  if (dungeon_room_index == 0x180 || dungeon_room_index == 0x182 || dungeon_room_index == 0x183)
+    return 0x19C6;
+  return 0x2669;
+}
+
+void Palette_AssertTranslucencySwap() {  // 8ed657
+  Palette_SetTranslucencySwap(true);
+}
+
+void Palette_SetTranslucencySwap(bool v) {  // 8ed65c
+  palette_swap_flag = v;
+  uint16 a, b;
+  for (int i = 0; i < 8; i++) {
+    a = aux_palette_buffer[i + 0x80];
+    b = aux_palette_buffer[i + 0xf0];
+    main_palette_buffer[i + 0xf0] = aux_palette_buffer[i + 0xf0] = a;
+    main_palette_buffer[i + 0x80] = aux_palette_buffer[i + 0x80] = b;
+
+    a = aux_palette_buffer[i + 0x88];
+    b = aux_palette_buffer[i + 0xf8];
+    main_palette_buffer[i + 0xf8] = aux_palette_buffer[i + 0xf8] = a;
+    main_palette_buffer[i + 0x88] = aux_palette_buffer[i + 0x88] = b;
+
+    a = aux_palette_buffer[i + 0xb8];
+    b = aux_palette_buffer[i + 0xd8];
+    main_palette_buffer[i + 0xd8] = aux_palette_buffer[i + 0xd8] = a;
+    main_palette_buffer[i + 0xb8] = aux_palette_buffer[i + 0xb8] = b;
+  }
+  flag_update_cgram_in_nmi++;
+}
+
+void Palette_RevertTranslucencySwap() {  // 8ed6bb
+  Palette_SetTranslucencySwap(false);
+}
+
+void LoadActualGearPalettes() {  // 8ed6c0
+  LoadGearPalettes(link_sword_type, link_shield_type, link_armor);
+  if (enhanced_features0 & kFeatures0_MiscBugFixes)
+    Palette_UpdateGlovesColor();
+}
+
+void Palette_ElectroThemedGear() {  // 8ed6d1
+  LoadGearPalettes(2, 2, 4);
+}
+
+void LoadGearPalettes_bunny() {  // 8ed6dd
+  LoadGearPalettes(link_sword_type, link_shield_type, 3);
+}
+
+void LoadGearPalettes(uint8 sword, uint8 shield, uint8 armor) {  // 8ed6e8
+  const uint16 *src = kPalette_Sword + (sword && sword != 255 ? sword - 1 : 0) * 3;
+  Palette_LoadMultiple_Arbitrary(src, 0x1b2, 2);
+
+  src = kPalette_Shield + (shield ? shield - 1 : 0) * 4;
+  Palette_LoadMultiple_Arbitrary(src, 0x1b8, 3);
+
+  src = kPalette_ArmorAndGloves + armor * 15;
+  Palette_LoadMultiple_Arbitrary(src, 0x1e2, 14);
+  flag_update_cgram_in_nmi++;
+}
+
+void LoadGearPalette(int dst, const uint16 *src, int n) {  // 8ed741
+  memcpy(&aux_palette_buffer[dst >> 1], src, sizeof(uint16) * n);
+  memcpy(&main_palette_buffer[dst >> 1], src, sizeof(uint16) * n);
+}
+
+void Filter_Majorly_Whiten_Bg() {  // 8ed757
+  for (int i = 32; i < 128; i++)
+    main_palette_buffer[i] = Filter_Majorly_Whiten_Color(aux_palette_buffer[i]);
+  main_palette_buffer[0] = aux_palette_buffer[0] ? main_palette_buffer[32] : 0;
+}
+
+uint16 Filter_Majorly_Whiten_Color(uint16 c) {  // 8ed7fe
+  int amt = (enhanced_features0 & kFeatures0_DimFlashes) ? 3 : 14;
+  int r = (c & 0x1f) + amt;
+  int g = (c & 0x3e0) + (amt << 5);
+  int b = (c & 0x7c00) + (amt << 10);
+  if (r > 0x1f) r = 0x1f;
+  if (g > 0x3e0) g = 0x3e0;
+  if (b > 0x7c00) b = 0x7c00;
+  return r | g | b;
+}
+
+void Palette_Restore_BG_From_Flash() {  // 8ed83a
+  for (int i = 32; i < 128; i++)
+    main_palette_buffer[i] = aux_palette_buffer[i];
+  main_palette_buffer[0] = main_palette_buffer[32];
+  Palette_Restore_Coldata();
+}
+
+void Palette_Restore_Coldata() {  // 8ed8ae
+  if (!player_is_indoors) {
+    uint32 rgb;
+    switch (BYTE(overworld_screen_index)) {
+    case 3: case 5: case 7:
+      rgb = 0x8c4c26;
+      break;
+    case 0x43: case 0x45: case 0x47:
+      rgb = 0x874a26;
+      break;
+    case 0x5b:
+      rgb = 0x894f33;
+      break;
+    default:
+      rgb = 0x804020;
+    }
+    COLDATA_copy0 = (uint8)(rgb);
+    COLDATA_copy1 = (uint8)(rgb >> 8);
+    COLDATA_copy2 = (uint8)(rgb >> 16);
+  }
+}
+
+void Palette_Restore_BG_And_HUD() {  // 8ed8fb
+  memcpy(main_palette_buffer, aux_palette_buffer, 256);
+  flag_update_cgram_in_nmi++;
+  Palette_Restore_Coldata();
+}
+
+/* Summary of sprite palette usage 
+0l: kPalette_SpriteAux3[palette_sp0l]
+0r: kPalette_MiscSprite[7 / 9] or kPalette_DungBgMain[(palette_main_indoors >> 1) * 90]
+1 : common sprites
+2 :      -"-
+3 :      -"-
+4 :      -"-
+5l: palette_sp5l
+5r: link sword/shield
+6l: palette_sp6l
+6r: kPalette_MiscSprite[6 / 8] or kPalette_MiscSprite[palette_sp6r_indoors]
+7 : link armor and gloves
+*/
+
+enum {
+  kPal_sp0l = 0x102,
+  kPal_sp0r = 0x112,
+  kPal_sp1to4 = 0x122,   // This is used for 64 colors, colors switched if in darkworld mode
+  kPal_sp5l = 0x1a2,
+  kPal_Sword = 0x1b2,
+  kPal_Shield = 0x1b8,
+  kPal_sp6l = 0x1c2,
+  kPal_sp6r = 0x1d2,
+  kPal_sp7l = 0x1e2,
+  kPal_sp7r = 0x1f2,
+  kPal_ArmorGloves = 0x1e2,
+  kPal_PalaceMap = 0x182,
+};
+
+void Palette_Load_Sp0L() {  // 9bec77
+  const uint16 *src = kPalette_SpriteAux3 + palette_sp0l * 7;
+  Palette_LoadSingle(src, palette_swap_flag ? kPal_sp7l : kPal_sp0l, 6);
+}
+
+void Palette_Load_SpriteMain() {  // 9bec9e
+  const uint16 *src = kPalette_MainSpr + (overworld_screen_index & 0x40 ? 60 : 0);
+  Palette_LoadMultiple(src, kPal_sp1to4, 14, 3);
+}
+
+void Palette_Load_Sp5L() {  // 9becc5
+  const uint16 *src = kPalette_SpriteAux1 + (palette_sp5l) * 7;
+  Palette_LoadSingle(src, kPal_sp5l, 6);
+}
+
+void Palette_Load_Sp6L() {  // 9bece4
+  const uint16 *src = kPalette_SpriteAux1 + (palette_sp6l) * 7;
+  Palette_LoadSingle(src, kPal_sp6l, 6);
+}
+
+void Palette_Load_Sword() {  // 9bed03
+  const uint16 *src = kPalette_Sword + ((int8)link_sword_type > 0 ? link_sword_type - 1 : 0) * 3;  // wtf: zelda reads offset 0xff
+  Palette_LoadMultiple_Arbitrary(src, kPal_Sword, 2);
+  flag_update_cgram_in_nmi += 1;
+}
+
+void Palette_Load_Shield() {  // 9bed29
+  const uint16 *src = kPalette_Shield + (link_shield_type ? link_shield_type - 1 : 0) * 4;
+  Palette_LoadMultiple_Arbitrary(src, kPal_Shield, 3);
+  flag_update_cgram_in_nmi += 1;
+}
+
+void Palette_Load_SpriteEnvironment() {  // 9bed6e
+  if (player_is_indoors)
+    Palette_Load_SpriteEnvironment_Dungeon();
+  else
+    Palette_MiscSprite_Outdoors();
+}
+
+// avoid renaming in assets.dat
+#define kPalette_MiscSprite kPalette_MiscSprite_Indoors
+
+void Palette_Load_SpriteEnvironment_Dungeon() {  // 9bed72
+  const uint16 *src = kPalette_MiscSprite + palette_sp6r_indoors * 7;
+  Palette_LoadSingle(src, kPal_sp6r, 6);
+}
+
+void Palette_MiscSprite_Outdoors() {  // 9bed91
+  int t = (overworld_screen_index & 0x40) ? 9 : 7;
+  const uint16 *src = kPalette_MiscSprite + t * 7;
+  Palette_LoadSingle(src, palette_swap_flag ? kPal_sp7r : kPal_sp0r, 6);
+  Palette_LoadSingle(src - 7, kPal_sp6r, 6);
+}
+
+void Palette_Load_DungeonMapSprite() {  // 9beddd
+  Palette_LoadMultiple(kPalette_PalaceMapSpr, kPal_PalaceMap, 6, 2);
+}
+
+void Palette_Load_LinkArmorAndGloves() {  // 9bedf9
+  const uint16 *src = kPalette_ArmorAndGloves + link_armor * 15;
+  Palette_LoadMultiple_Arbitrary(src, kPal_ArmorGloves, 14);
+  Palette_UpdateGlovesColor();
+}
+
+void Palette_UpdateGlovesColor() {  // 9bee1b
+  if (link_item_gloves)
+    main_palette_buffer[0xfd] = aux_palette_buffer[0xfd] = kGlovesColor[link_item_gloves - 1];
+  flag_update_cgram_in_nmi += 1;
+}
+
+void Palette_Load_DungeonMapBG() {  // 9bee3a
+  Palette_LoadMultiple(kPalette_PalaceMapBg, 0x40, 15, 5);
+}
+
+void Palette_Load_HUD() {  // 9bee52
+  const uint16 *src = kHudPalData + hud_palette * 32;
+  Palette_LoadMultiple(src, 0x0, 15, 1);
+}
+
+void Palette_Load_DungeonSet() {  // 9bee74
+  const uint16 *src = kPalette_DungBgMain + (palette_main_indoors >> 1) * 90;
+  Palette_LoadMultiple(src, 0x42, 14, 5);
+  Palette_LoadSingle(src, palette_swap_flag ? kPal_sp7r : kPal_sp0r, 6);
+}
+
+void Palette_Load_OWBG3() {  // 9beea8
+  const uint16 *src = kPalette_OverworldBgAux3 + overworld_palette_aux3_bp7_lo * 7;
+  Palette_LoadSingle(src, 0xE2, 6);
+}
+
+void Palette_Load_OWBGMain() {  // 9beec7
+  const uint16 *src = kPalette_OverworldBgMain + overworld_palette_mode * 35;
+  Palette_LoadMultiple(src, 0x42, 6, 4);
+}
+
+void Palette_Load_OWBG1() {  // 9beee8
+  const uint16 *src = kPalette_OverworldBgAux12 + overworld_palette_aux1_bp2to4_hi * 21;
+  Palette_LoadMultiple(src, 0x52, 6, 2);
+}
+
+void Palette_Load_OWBG2() {  // 9bef0c
+  const uint16 *src = kPalette_OverworldBgAux12 + overworld_palette_aux2_bp5to7_hi * 21;
+  Palette_LoadMultiple(src, 0xB2, 6, 2);
+}
+
+void Palette_LoadSingle(const uint16 *src, int dst, int x_ents) {  // 9bef30
+  memcpy(&aux_palette_buffer[(dst + overworld_palette_aux_or_main) >> 1], src, sizeof(uint16) * (x_ents + 1));
+}
+
+void Palette_LoadMultiple(const uint16 *src, int dst, int x_ents, int y_pals) {  // 9bef4b
+  x_ents++;
+  do {
+    memcpy(&aux_palette_buffer[(dst + overworld_palette_aux_or_main) >> 1], src, sizeof(uint16) * x_ents);
+    src += x_ents;
+    dst += 32;
+  } while (--y_pals >= 0);
+}
+
+void Palette_LoadMultiple_Arbitrary(const uint16 *src, int dst, int x_ents) {  // 9bef7b
+  memcpy(&aux_palette_buffer[dst >> 1], src, sizeof(uint16) * (x_ents + 1));
+  memcpy(&main_palette_buffer[dst >> 1], src, sizeof(uint16) * (x_ents + 1));
+}
+
+void Palette_LoadForFileSelect() {  // 9bef96
+  uint8 *src = g_zenv.sram;
+  for (int i = 0; i < 3; i++) {
+    Palette_LoadForFileSelect_Armor(i * 0x20, src[kSrmOffs_Armor], src[kSrmOffs_Gloves]);
+    Palette_LoadForFileSelect_Sword(i * 0x20, src[kSrmOffs_Sword]);
+    Palette_LoadForFileSelect_Shield(i * 0x20, src[kSrmOffs_Shield]);
+    src += 0x500;
+  }
+  for (int i = 0; i < 7; i++) {
+    aux_palette_buffer[0xe8 + i] = main_palette_buffer[0xe8 + i] = kPalette_MainSpr[7 + i];
+    aux_palette_buffer[0xf8 + i] = main_palette_buffer[0xf8 + i] = kPalette_MainSpr[15 + 7 + i];
+  }
+}
+
+void Palette_LoadForFileSelect_Armor(int k, uint8 armor, uint8 gloves) {  // 9bf032
+  const uint16 *pal = kPalette_ArmorAndGloves + armor * 15;
+  for (int i = 0; i != 15; i++)
+    aux_palette_buffer[k + 0x81 + i] = main_palette_buffer[k + 0x81 + i] = pal[i];
+  if (gloves)
+    aux_palette_buffer[k + 0x8d] = main_palette_buffer[k + 0x8d] = kGlovesColor[gloves - 1];
+}
+
+void Palette_LoadForFileSelect_Sword(int k, uint8 sword) {  // 9bf072
+  const uint16 *src = kPalette_Sword + (sword ? sword - 1 : 0) * 3;
+  for (int i = 0; i != 3; i++)
+    aux_palette_buffer[k + 0x99 + i] = main_palette_buffer[k + 0x99 + i] = src[i];
+}
+
+void Palette_LoadForFileSelect_Shield(int k, uint8 shield) {  // 9bf09a
+  const uint16 *src = kPalette_Shield + (shield ? shield - 1 : 0) * 4;
+  for (int i = 0; i != 4; i++)
+    aux_palette_buffer[k + 0x9c + i] = main_palette_buffer[k + 0x9c + i] = src[i];
+}
+
+void Palette_LoadAgahnim() {  // 9bf0c2
+  const uint16 *src = kPalette_SpriteAux1 + 14 * 7;
+  Palette_LoadMultiple_Arbitrary(src, 0x162, 6);
+  Palette_LoadMultiple_Arbitrary(src, 0x182, 6);
+  Palette_LoadMultiple_Arbitrary(src, 0x1a2, 6);
+  src = kPalette_SpriteAux1 + 21 * 7;
+  Palette_LoadMultiple_Arbitrary(src, 0x1c2, 6);
+  flag_update_cgram_in_nmi++;
+}
+
+void HandleScreenFlash() {  // 9de9b6
+  int j = intro_times_pal_flash;
+  if (!j || submodule_index != 0)
+    return;
+  if (!--intro_times_pal_flash) {
+    Palette_Restore_BG_And_HUD();
+    return;
+  }
+
+  if (j & 1)
+    Filter_Majorly_Whiten_Bg();
+  else
+    Palette_Restore_BG_From_Flash();
+
+  flag_update_cgram_in_nmi++;
+}
+
--- /dev/null
+++ b/src/load_gfx.h
@@ -1,0 +1,164 @@
+#ifndef ZELDA3_LOAD_GFX_H_
+#define ZELDA3_LOAD_GFX_H_
+
+enum {
+  kSrmOffs_Gloves = 0x354,
+  kSrmOffs_Sword = 0x359,
+  kSrmOffs_Shield = 0x35a,
+  kSrmOffs_Armor = 0x35b,
+  kSrmOffs_DiedCounter = 0x405,
+  kSrmOffs_Name = 0x3d9,
+  kSrmOffs_Health = 0x36c,
+};
+
+extern uint16 kGlovesColor[2];
+
+void ApplyPaletteFilter_bounce();
+void PaletteFilter_Range(int from, int to);
+void PaletteFilter_IncrCountdown();
+uint8 *LoadItemAnimationGfxOne(uint8 *dst, int num, int r12, bool from_temp);
+uint16 snes_divide(uint16 dividend, uint8 divisor);
+void EraseTileMaps_normal();
+void RecoverPegGFXFromMapping();
+void LoadOverworldMapPalette();
+void EraseTileMaps_triforce();
+void EraseTileMaps_dungeonmap();
+void EraseTileMaps(uint16 r2, uint16 r0);
+void EnableForceBlank();
+void LoadItemGFXIntoWRAM4BPPBuffer();
+void DecompressSwordGraphics();
+void DecompressShieldGraphics();
+void DecompressAnimatedDungeonTiles(uint8 a);
+void DecompressAnimatedOverworldTiles(uint8 a);
+void LoadItemGFX_Auxiliary();
+void LoadFollowerGraphics();
+void WriteTo4BPPBuffer_at_7F4000(uint8 a);
+void DecodeAnimatedSpriteTile_variable(uint8 a);
+void Expand3To4High(uint8 *dst, const uint8 *src, const uint8 *base, int num);
+void LoadTransAuxGFX();
+void LoadTransAuxGFX_sprite();
+void Gfx_LoadSpritesInner(uint8 *dst);
+void ReloadPreviouslyLoadedSheets();
+void Attract_DecompressStoryGFX();
+void AnimateMirrorWarp();
+void AnimateMirrorWarp_DecompressNewTileSets();
+void Graphics_IncrementalVRAMUpload();
+void PrepTransAuxGfx();
+void Do3To4High16Bit(uint8 *dst, const uint8 *src, int num);
+void Do3To4Low16Bit(uint8 *dst, const uint8 *src, int num);
+void LoadNewSpriteGFXSet();
+void InitializeTilesets();
+void LoadDefaultGraphics();
+void Attract_LoadBG3GFX();
+void Graphics_LoadChrHalfSlot();
+void TransferFontToVRAM();
+void Do3To4High(uint16 *vram_ptr, const uint8 *decomp_addr);
+void Do3To4Low(uint16 *vram_ptr, const uint8 *decomp_addr);
+void LoadSpriteGraphics(uint16 *vram_ptr, int gfx_pack, uint8 *decomp_addr);
+void LoadBackgroundGraphics(uint16 *vram_ptr, int gfx_pack, int slot, uint8 *decomp_addr);
+void LoadCommonSprites();
+int Decomp_spr(uint8 *dst, int gfx);
+int Decomp_bg(uint8 *dst, int gfx);
+int Decompress(uint8 *dst, const uint8 *src);
+void ResetHUDPalettes4and5();
+void PaletteFilterHistory();
+void PaletteFilter_WishPonds();
+void PaletteFilter_Crystal();
+void PaletteFilter_WishPonds_Inner();
+void PaletteFilter_RestoreSP5F();
+void PaletteFilter_SP5F();
+void KholdstareShell_PaletteFiltering();
+void AgahnimWarpShadowFilter(int k);
+void Palette_FadeIntroOneStep();
+void Palette_FadeIntro2();
+void PaletteFilter_RestoreAdditive(int from, int to);
+void PaletteFilter_RestoreSubtractive(uint16 from, uint16 to);
+void PaletteFilter_InitializeWhiteFilter();
+void MirrorWarp_RunAnimationSubmodules();
+void PaletteFilter_BlindingWhite();
+void PaletteFilter_StartBlindingWhite();
+void PaletteFilter_BlindingWhiteTriforce();
+void PaletteFilter_WhirlpoolBlue();
+void PaletteFilter_IsolateWhirlpoolBlue();
+void PaletteFilter_WhirlpoolRestoreBlue();
+void PaletteFilter_WhirlpoolRestoreRedGreen();
+void PaletteFilter_RestoreBGSubstractiveStrict();
+void PaletteFilter_RestoreBGAdditiveStrict();
+void Trinexx_FlashShellPalette_Red();
+void Trinexx_UnflashShellPalette_Red();
+void Trinexx_FlashShellPalette_Blue();
+void Trinexx_UnflashShellPalette_Blue();
+void IrisSpotlight_close();
+void Spotlight_open();
+void SpotlightInternal(uint8 x, uint8 y);
+void IrisSpotlight_ConfigureTable();
+void IrisSpotlight_ResetTable();
+uint16 IrisSpotlight_CalculateCircleValue(uint8 a);
+void AdjustWaterHDMAWindow();
+void AdjustWaterHDMAWindow_X(uint16 r10);
+void FloodDam_PrepFloodHDMA();
+void ResetStarTileGraphics();
+void Dungeon_RestoreStarTileChr();
+void LinkZap_HandleMosaic();
+void Player_SetCustomMosaicLevel(uint8 a);
+void Module07_16_UpdatePegs_Step1();
+void Module07_16_UpdatePegs_Step2();
+void Dungeon_UpdatePegGFXBuffer(int x, int y);
+void Dungeon_HandleTranslucencyAndPalette();
+void Overworld_LoadAllPalettes();
+void Dungeon_LoadPalettes();
+void Overworld_LoadPalettesInner();
+void OverworldLoadScreensPaletteSet();
+void Overworld_LoadAreaPalettesEx(uint8 x);
+void SpecialOverworld_CopyPalettesToCache();
+void Overworld_CopyPalettesToCache();
+void Overworld_LoadPalettes(uint8 bg, uint8 spr);
+void Palette_BgAndFixedColor_Black();
+void Palette_SetBgAndFixedColor(uint16 color);
+void SetBackdropcolorBlack();
+void Palette_SetOwBgColor();
+void Palette_SpecialOw();
+uint16 Palette_GetOwBgColor();
+void Palette_AssertTranslucencySwap();
+void Palette_SetTranslucencySwap(bool v);
+void Palette_RevertTranslucencySwap();
+void LoadActualGearPalettes();
+void Palette_ElectroThemedGear();
+void LoadGearPalettes_bunny();
+void LoadGearPalettes(uint8 sword, uint8 shield, uint8 armor);
+void LoadGearPalette(int dst, const uint16 *src, int n);
+void Filter_Majorly_Whiten_Bg();
+uint16 Filter_Majorly_Whiten_Color(uint16 c);
+void Palette_Restore_BG_From_Flash();
+void Palette_Restore_Coldata();
+void Palette_Restore_BG_And_HUD();
+void Palette_Load_Sp0L();
+void Palette_Load_SpriteMain();
+void Palette_Load_Sp5L();
+void Palette_Load_Sp6L();
+void Palette_Load_Sword();
+void Palette_Load_Shield();
+void Palette_Load_SpriteEnvironment();
+void Palette_Load_SpriteEnvironment_Dungeon();
+void Palette_MiscSprite_Outdoors();
+void Palette_Load_DungeonMapSprite();
+void Palette_Load_LinkArmorAndGloves();
+void Palette_UpdateGlovesColor();
+void Palette_Load_DungeonMapBG();
+void Palette_Load_HUD();
+void Palette_Load_DungeonSet();
+void Palette_Load_OWBG3();
+void Palette_Load_OWBGMain();
+void Palette_Load_OWBG1();
+void Palette_Load_OWBG2();
+void Palette_LoadSingle(const uint16 *src, int dst, int x_ents);
+void Palette_LoadMultiple(const uint16 *src, int dst, int x_ents, int y_pals);
+void Palette_LoadMultiple_Arbitrary(const uint16 *src, int dst, int x_ents);
+void Palette_LoadForFileSelect();
+void Palette_LoadForFileSelect_Armor(int k, uint8 armor, uint8 gloves);
+void Palette_LoadForFileSelect_Sword(int k, uint8 sword);
+void Palette_LoadForFileSelect_Shield(int k, uint8 shield);
+void Palette_LoadAgahnim();
+void HandleScreenFlash();
+
+#endif // ZELDA3_LOAD_GFX_H_
--- /dev/null
+++ b/src/main.c
@@ -1,0 +1,872 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <SDL.h>
+#ifdef _WIN32
+#include "platform/win32/volume_control.h"
+#include <direct.h>
+#else
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+#endif
+
+#include "snes/ppu.h"
+
+#include "types.h"
+#include "variables.h"
+
+#include "zelda_rtl.h"
+#include "zelda_cpu_infra.h"
+
+#include "config.h"
+#include "assets.h"
+#include "load_gfx.h"
+#include "util.h"
+#include "audio.h"
+
+static bool g_run_without_emu = 0;
+
+// Forwards
+static bool LoadRom(const char *filename);
+static void LoadLinkGraphics();
+static void RenderNumber(uint8 *dst, size_t pitch, int n, bool big);
+static void HandleInput(int keyCode, int modCode, bool pressed);
+static void HandleCommand(uint32 j, bool pressed);
+static int RemapSdlButton(int button);
+static void HandleGamepadInput(int button, bool pressed);
+static void HandleGamepadAxisInput(int gamepad_id, int axis, int value);
+static void OpenOneGamepad(int i);
+static void HandleVolumeAdjustment(int volume_adjustment);
+static void LoadAssets();
+static void SwitchDirectory();
+
+enum {
+  kDefaultFullscreen = 0,
+  kMaxWindowScale = 10,
+  kDefaultFreq = 44100,
+  kDefaultChannels = 2,
+  kDefaultSamples = 2048,
+};
+
+static const char kWindowTitle[] = "The Legend of Zelda: A Link to the Past";
+static uint32 g_win_flags = SDL_WINDOW_RESIZABLE;
+static SDL_Window *g_window;
+
+static uint8 g_paused, g_turbo, g_replay_turbo = true, g_cursor = true;
+static uint8 g_current_window_scale;
+static uint8 g_gamepad_buttons;
+static int g_input1_state;
+static bool g_display_perf;
+static int g_curr_fps;
+static int g_ppu_render_flags = 0;
+static int g_snes_width, g_snes_height;
+static int g_sdl_audio_mixer_volume = SDL_MIX_MAXVOLUME;
+static struct RendererFuncs g_renderer_funcs;
+static uint32 g_gamepad_modifiers;
+static uint16 g_gamepad_last_cmd[kGamepadBtn_Count];
+
+void NORETURN Die(const char *error) {
+#if defined(NDEBUG) && defined(_WIN32)
+  SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, kWindowTitle, error, NULL);
+#endif
+  fprintf(stderr, "Error: %s\n", error);
+  exit(1);
+}
+
+void ChangeWindowScale(int scale_step) {
+  if ((SDL_GetWindowFlags(g_window) & (SDL_WINDOW_FULLSCREEN_DESKTOP | SDL_WINDOW_FULLSCREEN | SDL_WINDOW_MINIMIZED | SDL_WINDOW_MAXIMIZED)) != 0)
+    return;
+  int screen = SDL_GetWindowDisplayIndex(g_window);
+  if (screen < 0) screen = 0;
+  int max_scale = kMaxWindowScale;
+  SDL_Rect bounds;
+  int bt = -1, bl, bb, br;
+  // note this takes into effect Windows display scaling, i.e., resolution is divided by scale factor
+  if (SDL_GetDisplayUsableBounds(screen, &bounds) == 0) {
+    // this call may take a while before it is reported by Windows (or not at all in my testing)
+    if (SDL_GetWindowBordersSize(g_window, &bt, &bl, &bb, &br) != 0) {
+      // guess based on Windows 10/11 defaults
+      bl = br = bb = 1;
+      bt = 31;
+    }
+    // Allow a scale level slightly above the max that fits on screen
+    int mw = (bounds.w - bl - br + g_snes_width / 4) / g_snes_width;
+    int mh = (bounds.h - bt - bb + g_snes_height / 4) / g_snes_height;
+    max_scale = IntMin(mw, mh);
+  }
+  int new_scale = IntMax(IntMin(g_current_window_scale + scale_step, max_scale), 1);
+  g_current_window_scale = new_scale;
+  int w = new_scale * g_snes_width;
+  int h = new_scale * g_snes_height;
+
+  //SDL_RenderSetLogicalSize(g_renderer, w, h);
+  SDL_SetWindowSize(g_window, w, h);
+  if (bt >= 0) {
+    // Center the window on top of the mouse
+    int mx, my;
+    SDL_GetGlobalMouseState(&mx, &my);
+    int wx = IntMax(IntMin(mx - w / 2, bounds.x + bounds.w - bl - br - w), bounds.x + bl);
+    int wy = IntMax(IntMin(my - h / 2, bounds.y + bounds.h - bt - bb - h), bounds.y + bt);
+    SDL_SetWindowPosition(g_window, wx, wy);
+  } else {
+    SDL_SetWindowPosition(g_window, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED);
+  }
+}
+
+#define RESIZE_BORDER 20
+static SDL_HitTestResult HitTestCallback(SDL_Window *win, const SDL_Point *pt, void *data) {
+  uint32 flags = SDL_GetWindowFlags(win);
+  if ((flags & SDL_WINDOW_FULLSCREEN_DESKTOP) != 0 || (flags & SDL_WINDOW_FULLSCREEN) != 0)
+    return SDL_HITTEST_NORMAL;
+
+  if ((SDL_GetModState() & KMOD_CTRL) != 0)
+    return SDL_HITTEST_DRAGGABLE;
+
+  int w, h;
+  SDL_GetWindowSize(win, &w, &h);
+
+  if (pt->y < RESIZE_BORDER) {
+    return (pt->x < RESIZE_BORDER) ? SDL_HITTEST_RESIZE_TOPLEFT :
+           (pt->x >= w - RESIZE_BORDER) ? SDL_HITTEST_RESIZE_TOPRIGHT : SDL_HITTEST_RESIZE_TOP;
+  } else if (pt->y >= h - RESIZE_BORDER) {
+    return (pt->x < RESIZE_BORDER) ? SDL_HITTEST_RESIZE_BOTTOMLEFT :
+           (pt->x >= w - RESIZE_BORDER) ? SDL_HITTEST_RESIZE_BOTTOMRIGHT : SDL_HITTEST_RESIZE_BOTTOM;
+  } else {
+    if (pt->x < RESIZE_BORDER) {
+      return SDL_HITTEST_RESIZE_LEFT;
+    } else if (pt->x >= w - RESIZE_BORDER) {
+      return SDL_HITTEST_RESIZE_RIGHT;
+    }
+  }
+  return SDL_HITTEST_NORMAL;
+}
+
+static void DrawPpuFrameWithPerf() {
+  int render_scale = PpuGetCurrentRenderScale(g_zenv.ppu, g_ppu_render_flags);
+  uint8 *pixel_buffer = 0;
+  int pitch = 0;
+
+  g_renderer_funcs.BeginDraw(g_snes_width * render_scale,
+                             g_snes_height * render_scale,
+                             &pixel_buffer, &pitch);
+  if (g_display_perf || g_config.display_perf_title) {
+    static float history[64], average;
+    static int history_pos;
+    uint64 before = SDL_GetPerformanceCounter();
+    ZeldaDrawPpuFrame(pixel_buffer, pitch, g_ppu_render_flags);
+    uint64 after = SDL_GetPerformanceCounter();
+    float v = (double)SDL_GetPerformanceFrequency() / (after - before);
+    average += v - history[history_pos];
+    history[history_pos] = v;
+    history_pos = (history_pos + 1) & 63;
+    g_curr_fps = average * (1.0f / 64);
+  } else {
+    ZeldaDrawPpuFrame(pixel_buffer, pitch, g_ppu_render_flags);
+  }
+  if (g_display_perf)
+    RenderNumber(pixel_buffer + pitch * render_scale, pitch, g_curr_fps, render_scale == 4);
+  g_renderer_funcs.EndDraw();
+}
+
+static SDL_mutex *g_audio_mutex;
+static uint8 *g_audiobuffer, *g_audiobuffer_cur, *g_audiobuffer_end;
+static int g_frames_per_block;
+static uint8 g_audio_channels;
+
+static void SDLCALL AudioCallback(void *userdata, Uint8 *stream, int len) {
+  if (SDL_LockMutex(g_audio_mutex)) Die("Mutex lock failed!");
+  while (len != 0) {
+    if (g_audiobuffer_end - g_audiobuffer_cur == 0) {
+      ZeldaRenderAudio((int16*)g_audiobuffer, g_frames_per_block, g_audio_channels);
+      g_audiobuffer_cur = g_audiobuffer;
+      g_audiobuffer_end = g_audiobuffer + g_frames_per_block * g_audio_channels * sizeof(int16);
+    }
+    int n = IntMin(len, g_audiobuffer_end - g_audiobuffer_cur);
+    if (g_sdl_audio_mixer_volume == SDL_MIX_MAXVOLUME) {
+      memcpy(stream, g_audiobuffer_cur, n);
+    } else {
+      SDL_memset(stream, 0, n);
+      SDL_MixAudioFormat(stream, g_audiobuffer_cur, AUDIO_S16, n, g_sdl_audio_mixer_volume);
+    }
+    g_audiobuffer_cur += n;
+    stream += n;
+    len -= n;
+  }
+
+  ZeldaDiscardUnusedAudioFrames();
+  SDL_UnlockMutex(g_audio_mutex);
+}
+
+// State for sdl renderer
+static SDL_Renderer *g_renderer;
+static SDL_Texture *g_texture;
+static SDL_Rect g_sdl_renderer_rect;
+
+static bool SdlRenderer_Init(SDL_Window *window) {
+
+  if (g_config.shader)
+    fprintf(stderr, "Warning: Shaders are supported only with the OpenGL backend\n");
+
+  SDL_Renderer *renderer = SDL_CreateRenderer(g_window, -1,
+                                              g_config.output_method == kOutputMethod_SDLSoftware ? SDL_RENDERER_SOFTWARE :
+                                              SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
+  if (renderer == NULL) {
+    printf("Failed to create renderer: %s\n", SDL_GetError());
+    return false;
+  }
+  SDL_RendererInfo renderer_info;
+  SDL_GetRendererInfo(renderer, &renderer_info);
+  if (kDebugFlag) {
+    printf("Supported texture formats:");
+    for (int i = 0; i < renderer_info.num_texture_formats; i++)
+      printf(" %s", SDL_GetPixelFormatName(renderer_info.texture_formats[i]));
+    printf("\n");
+  }
+  g_renderer = renderer;
+  if (!g_config.ignore_aspect_ratio)
+    SDL_RenderSetLogicalSize(renderer, g_snes_width, g_snes_height);
+  if (g_config.linear_filtering)
+    SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "best");
+
+  int tex_mult = (g_ppu_render_flags & kPpuRenderFlags_4x4Mode7) ? 4 : 1;
+  g_texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING,
+                                g_snes_width * tex_mult, g_snes_height * tex_mult);
+  if (g_texture == NULL) {
+    printf("Failed to create texture: %s\n", SDL_GetError());
+    return false;
+  }
+  return true;
+}
+
+static void SdlRenderer_Destroy() {
+  SDL_DestroyTexture(g_texture);
+  SDL_DestroyRenderer(g_renderer);
+}
+
+static void SdlRenderer_BeginDraw(int width, int height, uint8 **pixels, int *pitch) {
+  g_sdl_renderer_rect.w = width;
+  g_sdl_renderer_rect.h = height;
+  if (SDL_LockTexture(g_texture, &g_sdl_renderer_rect, (void **)pixels, pitch) != 0) {
+    printf("Failed to lock texture: %s\n", SDL_GetError());
+    return;
+  }
+}
+
+static void SdlRenderer_EndDraw() {
+
+//  uint64 before = SDL_GetPerformanceCounter();
+  SDL_UnlockTexture(g_texture);
+//  uint64 after = SDL_GetPerformanceCounter();
+//  float v = (double)(after - before) / SDL_GetPerformanceFrequency();
+//  printf("%f ms\n", v * 1000);
+  SDL_RenderClear(g_renderer);
+  SDL_RenderCopy(g_renderer, g_texture, &g_sdl_renderer_rect, NULL);
+  SDL_RenderPresent(g_renderer); // vsyncs to 60 FPS?
+}
+
+static const struct RendererFuncs kSdlRendererFuncs  = {
+  &SdlRenderer_Init,
+  &SdlRenderer_Destroy,
+  &SdlRenderer_BeginDraw,
+  &SdlRenderer_EndDraw,
+};
+
+void OpenGLRenderer_Create(struct RendererFuncs *funcs, bool use_opengl_es);
+
+#undef main
+int main(int argc, char** argv) {
+  argc--, argv++;
+  const char *config_file = NULL;
+  if (argc >= 2 && strcmp(argv[0], "--config") == 0) {
+    config_file = argv[1];
+    argc -= 2, argv += 2;
+  } else {
+    SwitchDirectory();
+  }
+  ParseConfigFile(config_file);
+  LoadAssets();
+  LoadLinkGraphics();
+
+  ZeldaInitialize();
+  g_zenv.ppu->extraLeftRight = UintMin(g_config.extended_aspect_ratio, kPpuExtraLeftRight);
+  g_snes_width = (g_config.extended_aspect_ratio * 2 + 256);
+  g_snes_height = (g_config.extend_y ? 240 : 224);
+
+
+  // Delay actually setting those features in ram until any snapshots finish playing.
+  g_wanted_zelda_features = g_config.features0;
+
+  g_ppu_render_flags = g_config.new_renderer * kPpuRenderFlags_NewRenderer |
+                       g_config.enhanced_mode7 * kPpuRenderFlags_4x4Mode7 |
+                       g_config.extend_y * kPpuRenderFlags_Height240 |
+                       g_config.no_sprite_limits * kPpuRenderFlags_NoSpriteLimits;
+  ZeldaEnableMsu(g_config.enable_msu);
+  ZeldaSetLanguage(g_config.language);
+
+  if (g_config.fullscreen == 1)
+    g_win_flags ^= SDL_WINDOW_FULLSCREEN_DESKTOP;
+  else if (g_config.fullscreen == 2)
+    g_win_flags ^= SDL_WINDOW_FULLSCREEN;
+
+  // Window scale (1=100%, 2=200%, 3=300%, etc.)
+  g_current_window_scale = (g_config.window_scale == 0) ? 2 : IntMin(g_config.window_scale, kMaxWindowScale);
+
+  // audio_freq: Use common sampling rates (see user config file. values higher than 48000 are not supported.)
+  if (g_config.audio_freq < 11025 || g_config.audio_freq > 48000)
+    g_config.audio_freq = kDefaultFreq;
+
+  // Currently, the SPC/DSP implementation only supports up to stereo.
+  if (g_config.audio_channels < 1 || g_config.audio_channels > 2)
+    g_config.audio_channels = kDefaultChannels;
+
+  // audio_samples: power of 2
+  if (g_config.audio_samples <= 0 || ((g_config.audio_samples & (g_config.audio_samples - 1)) != 0))
+    g_config.audio_samples = kDefaultSamples;
+
+  // set up SDL
+  if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_GAMECONTROLLER) != 0) {
+    printf("Failed to init SDL: %s\n", SDL_GetError());
+    return 1;
+  }
+
+  bool custom_size  = g_config.window_width != 0 && g_config.window_height != 0;
+  int window_width  = custom_size ? g_config.window_width  : g_current_window_scale * g_snes_width;
+  int window_height = custom_size ? g_config.window_height : g_current_window_scale * g_snes_height;
+
+  if (g_config.output_method == kOutputMethod_OpenGL ||
+      g_config.output_method == kOutputMethod_OpenGL_ES) {
+    g_win_flags |= SDL_WINDOW_OPENGL;
+    OpenGLRenderer_Create(&g_renderer_funcs, (g_config.output_method == kOutputMethod_OpenGL_ES));
+  } else {
+    g_renderer_funcs = kSdlRendererFuncs;
+  }
+
+  SDL_Window* window = SDL_CreateWindow(kWindowTitle, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, window_width, window_height, g_win_flags);
+  if(window == NULL) {
+    printf("Failed to create window: %s\n", SDL_GetError());
+    return 1;
+  }
+  g_window = window;
+  SDL_SetWindowHitTest(window, HitTestCallback, NULL);
+
+  if (!g_renderer_funcs.Initialize(window))
+    return 1;
+
+  SDL_AudioDeviceID device = 0;
+  SDL_AudioSpec want = { 0 }, have;
+  g_audio_mutex = SDL_CreateMutex();
+  if (!g_audio_mutex) Die("No mutex");
+
+  if (g_config.enable_audio) {
+    want.freq = g_config.audio_freq;
+    want.format = AUDIO_S16;
+    want.channels = g_config.audio_channels;
+    want.samples = g_config.audio_samples;
+    want.callback = &AudioCallback;
+    device = SDL_OpenAudioDevice(NULL, 0, &want, &have, 0);
+    if (device == 0) {
+      printf("Failed to open audio device: %s\n", SDL_GetError());
+      return 1;
+    }
+    g_audio_channels = have.channels;
+    g_frames_per_block = (534 * have.freq) / 32000;
+    g_audiobuffer = malloc(g_frames_per_block * have.channels * sizeof(int16));
+  }
+
+  if (argc >= 1 && !g_run_without_emu)
+    LoadRom(argv[0]);
+
+#if defined(_WIN32)
+  _mkdir("saves");
+#else
+  mkdir("saves", 0755);
+#endif
+
+  ZeldaReadSram();
+
+  for (int i = 0; i < SDL_NumJoysticks(); i++)
+    OpenOneGamepad(i);
+
+  bool running = true;
+  SDL_Event event;
+  uint32 lastTick = SDL_GetTicks();
+  uint32 curTick = 0;
+  uint32 frameCtr = 0;
+  bool audiopaused = true;
+
+  if (g_config.autosave)
+    HandleCommand(kKeys_Load + 0, true);
+
+  while(running) {
+    while(SDL_PollEvent(&event)) {
+      switch(event.type) {
+      case SDL_CONTROLLERDEVICEADDED:
+        OpenOneGamepad(event.cdevice.which);
+        break;
+      case SDL_CONTROLLERAXISMOTION:
+        HandleGamepadAxisInput(event.caxis.which, event.caxis.axis, event.caxis.value);
+        break;
+      case SDL_CONTROLLERBUTTONDOWN:
+      case SDL_CONTROLLERBUTTONUP: {
+        int b = RemapSdlButton(event.cbutton.button);
+        if (b >= 0)
+          HandleGamepadInput(b, event.type == SDL_CONTROLLERBUTTONDOWN);
+        break;
+      }
+      case SDL_MOUSEWHEEL:
+        if (SDL_GetModState() & KMOD_CTRL && event.wheel.y != 0)
+          ChangeWindowScale(event.wheel.y > 0 ? 1 : -1);
+        break;
+      case SDL_MOUSEBUTTONDOWN:
+        if (event.button.button == SDL_BUTTON_LEFT && event.button.state == SDL_PRESSED && event.button.clicks == 2) {
+          if ((g_win_flags & SDL_WINDOW_FULLSCREEN_DESKTOP) == 0 && (g_win_flags & SDL_WINDOW_FULLSCREEN) == 0 && SDL_GetModState() & KMOD_SHIFT) {
+            g_win_flags ^= SDL_WINDOW_BORDERLESS;
+            SDL_SetWindowBordered(g_window, (g_win_flags & SDL_WINDOW_BORDERLESS) == 0);
+          }
+        }
+        break;
+      case SDL_KEYDOWN:
+        HandleInput(event.key.keysym.sym, event.key.keysym.mod, true);
+        break;
+      case SDL_KEYUP:
+        HandleInput(event.key.keysym.sym, event.key.keysym.mod, false);
+        break;
+      case SDL_QUIT:
+        running = false;
+        break;
+      }
+    }
+
+    if (g_paused != audiopaused) {
+      audiopaused = g_paused;
+      if (device)
+        SDL_PauseAudioDevice(device, audiopaused);
+    }
+
+    if (g_paused) {
+      SDL_Delay(16);
+      continue;
+    }
+
+    // Clear gamepad inputs when joypad directional inputs to avoid wonkiness
+    int inputs = g_input1_state;
+    if (g_input1_state & 0xf0)
+      g_gamepad_buttons = 0;
+    inputs |= g_gamepad_buttons;
+
+    SDL_LockMutex(g_audio_mutex);
+    bool is_replay = ZeldaRunFrame(inputs);
+    SDL_UnlockMutex(g_audio_mutex);
+
+    frameCtr++;
+
+    if ((g_turbo ^ (is_replay & g_replay_turbo)) && (frameCtr & (g_turbo ? 0xf : 0x7f)) != 0) {
+      continue;
+    }
+
+    DrawPpuFrameWithPerf();
+
+    if (g_config.display_perf_title) {
+      char title[60];
+      snprintf(title, sizeof(title), "%s | FPS: %d", kWindowTitle, g_curr_fps);
+      SDL_SetWindowTitle(g_window, title);
+    }
+
+    // if vsync isn't working, delay manually
+    curTick = SDL_GetTicks();
+
+    if (!g_config.disable_frame_delay) {
+      static const uint8 delays[3] = { 17, 17, 16 }; // 60 fps
+      lastTick += delays[frameCtr % 3];
+
+      if (lastTick > curTick) {
+        uint32 delta = lastTick - curTick;
+        if (delta > 500) {
+          lastTick = curTick - 500;
+          delta = 500;
+        }
+//        printf("Sleeping %d\n", delta);
+        SDL_Delay(delta);
+      } else if (curTick - lastTick > 500) {
+        lastTick = curTick;
+      }
+    }
+  }
+  if (g_config.autosave)
+    HandleCommand(kKeys_Save + 0, true);
+
+  // clean sdl
+  if (g_config.enable_audio) {
+    SDL_PauseAudioDevice(device, 1);
+    SDL_CloseAudioDevice(device);
+  }
+
+  SDL_DestroyMutex(g_audio_mutex);
+  free(g_audiobuffer);
+
+  g_renderer_funcs.Destroy();
+
+  SDL_DestroyWindow(window);
+  SDL_Quit();
+  //SaveConfigFile();
+  return 0;
+}
+
+static void RenderDigit(uint8 *dst, size_t pitch, int digit, uint32 color, bool big) {
+  static const uint8 kFont[] = {
+    0x1c, 0x36, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x36, 0x1c,
+    0x18, 0x1c, 0x1e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7e,
+    0x3e, 0x63, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x03, 0x63, 0x7f,
+    0x3e, 0x63, 0x60, 0x60, 0x3c, 0x60, 0x60, 0x60, 0x63, 0x3e,
+    0x30, 0x38, 0x3c, 0x36, 0x33, 0x7f, 0x30, 0x30, 0x30, 0x78,
+    0x7f, 0x03, 0x03, 0x03, 0x3f, 0x60, 0x60, 0x60, 0x63, 0x3e,
+    0x1c, 0x06, 0x03, 0x03, 0x3f, 0x63, 0x63, 0x63, 0x63, 0x3e,
+    0x7f, 0x63, 0x60, 0x60, 0x30, 0x18, 0x0c, 0x0c, 0x0c, 0x0c,
+    0x3e, 0x63, 0x63, 0x63, 0x3e, 0x63, 0x63, 0x63, 0x63, 0x3e,
+    0x3e, 0x63, 0x63, 0x63, 0x7e, 0x60, 0x60, 0x60, 0x30, 0x1e,
+  };
+  const uint8 *p = kFont + digit * 10;
+  if (!big) {
+    for (int y = 0; y < 10; y++, dst += pitch) {
+      int v = *p++;
+      for (int x = 0; v; x++, v >>= 1) {
+        if (v & 1)
+          ((uint32 *)dst)[x] = color;
+      }
+    }
+  } else {
+    for (int y = 0; y < 10; y++, dst += pitch * 2) {
+      int v = *p++;
+      for (int x = 0; v; x++, v >>= 1) {
+        if (v & 1) {
+          ((uint32 *)dst)[x * 2 + 1] = ((uint32 *)dst)[x * 2] = color;
+          ((uint32 *)(dst+pitch))[x * 2 + 1] = ((uint32 *)(dst + pitch))[x * 2] = color;
+        }
+      }
+    }
+  }
+}
+
+static void RenderNumber(uint8 *dst, size_t pitch, int n, bool big) {
+  char buf[32], *s;
+  int i;
+  sprintf(buf, "%d", n);
+  for (s = buf, i = 2 * 4; *s; s++, i += 8 * 4)
+    RenderDigit(dst + ((pitch + i + 4) << big), pitch, *s - '0', 0x404040, big);
+  for (s = buf, i = 2 * 4; *s; s++, i += 8 * 4)
+    RenderDigit(dst + (i << big), pitch, *s - '0', 0xffffff, big);
+}
+
+static void HandleCommand_Locked(uint32 j, bool pressed);
+
+static void HandleCommand(uint32 j, bool pressed) {
+  if (j <= kKeys_Controls_Last) {
+    static const uint8 kKbdRemap[] = { 0, 4, 5, 6, 7, 2, 3, 8, 0, 9, 1, 10, 11 };
+    if (pressed)
+      g_input1_state |= 1 << kKbdRemap[j];
+    else
+      g_input1_state &= ~(1 << kKbdRemap[j]);
+    return;
+  }
+
+  if (j == kKeys_Turbo) {
+    g_turbo = pressed;
+    return;
+  }
+
+  // Everything that might access audio state
+  // (like SaveLoad and Reset) must have the lock.
+  SDL_LockMutex(g_audio_mutex);
+  HandleCommand_Locked(j, pressed);
+  SDL_UnlockMutex(g_audio_mutex);
+}
+
+void ZeldaApuLock() {
+  SDL_LockMutex(g_audio_mutex);
+}
+
+void ZeldaApuUnlock() {
+  SDL_UnlockMutex(g_audio_mutex);
+}
+
+
+static void HandleCommand_Locked(uint32 j, bool pressed) {
+  if (!pressed)
+    return;
+  if (j <= kKeys_Load_Last) {
+    SaveLoadSlot(kSaveLoad_Load, j - kKeys_Load);
+  } else if (j <= kKeys_Save_Last) {
+    SaveLoadSlot(kSaveLoad_Save, j - kKeys_Save);
+  } else if (j <= kKeys_Replay_Last) {
+    SaveLoadSlot(kSaveLoad_Replay, j - kKeys_Replay);
+  } else if (j <= kKeys_LoadRef_Last) {
+    SaveLoadSlot(kSaveLoad_Load, 256 + j - kKeys_LoadRef);
+  } else if (j <= kKeys_ReplayRef_Last) {
+    SaveLoadSlot(kSaveLoad_Replay, 256 + j - kKeys_ReplayRef);
+  } else {
+    switch (j) {
+    case kKeys_CheatLife: PatchCommand('w'); break;
+    case kKeys_CheatEquipment: PatchCommand('W'); break;
+    case kKeys_CheatKeys: PatchCommand('o'); break;
+    case kKeys_CheatWalkThroughWalls: PatchCommand('E'); break;
+    case kKeys_ClearKeyLog: PatchCommand('k'); break;
+    case kKeys_StopReplay: PatchCommand('l'); break;
+    case kKeys_Fullscreen:
+      g_win_flags ^= SDL_WINDOW_FULLSCREEN_DESKTOP;
+      SDL_SetWindowFullscreen(g_window, g_win_flags & SDL_WINDOW_FULLSCREEN_DESKTOP);
+      g_cursor = !g_cursor;
+      SDL_ShowCursor(g_cursor);
+      break;
+    case kKeys_Reset:
+      ZeldaReset(true);
+      break;
+    case kKeys_Pause: g_paused = !g_paused; break;
+    case kKeys_PauseDimmed:
+      g_paused = !g_paused;
+      // SDL_RenderPresent may not be called more than once per frame.
+      // Seems to work on Windows still. Temporary measure until it's fixed.
+#ifdef _WIN32
+      if (g_paused) {
+        SDL_SetRenderDrawBlendMode(g_renderer, SDL_BLENDMODE_BLEND);
+        SDL_SetRenderDrawColor(g_renderer, 0, 0, 0, 159);
+        SDL_RenderFillRect(g_renderer, NULL);
+        SDL_RenderPresent(g_renderer);
+      }
+#endif
+      break;
+    case kKeys_ReplayTurbo: g_replay_turbo = !g_replay_turbo; break;
+    case kKeys_WindowBigger: ChangeWindowScale(1); break;
+    case kKeys_WindowSmaller: ChangeWindowScale(-1); break;
+    case kKeys_DisplayPerf: g_display_perf ^= 1; break;
+    case kKeys_ToggleRenderer: g_ppu_render_flags ^= kPpuRenderFlags_NewRenderer; break;
+    case kKeys_VolumeUp:
+    case kKeys_VolumeDown: HandleVolumeAdjustment(j == kKeys_VolumeUp ? 1 : -1); break;
+    default: assert(0);
+    }
+  }
+}
+
+static void HandleInput(int keyCode, int keyMod, bool pressed) {
+  int j = FindCmdForSdlKey(keyCode, keyMod);
+  if (j != 0)
+    HandleCommand(j, pressed);
+}
+
+static void OpenOneGamepad(int i) {
+  if (SDL_IsGameController(i)) {
+    SDL_GameController *controller = SDL_GameControllerOpen(i);
+    if (!controller)
+      fprintf(stderr, "Could not open gamepad %d: %s\n", i, SDL_GetError());
+  }
+}
+
+static int RemapSdlButton(int button) {
+  switch (button) {
+  case SDL_CONTROLLER_BUTTON_A: return kGamepadBtn_A;
+  case SDL_CONTROLLER_BUTTON_B: return kGamepadBtn_B;
+  case SDL_CONTROLLER_BUTTON_X: return kGamepadBtn_X;
+  case SDL_CONTROLLER_BUTTON_Y: return kGamepadBtn_Y;
+  case SDL_CONTROLLER_BUTTON_BACK: return kGamepadBtn_Back;
+  case SDL_CONTROLLER_BUTTON_GUIDE: return kGamepadBtn_Guide;
+  case SDL_CONTROLLER_BUTTON_START: return kGamepadBtn_Start;
+  case SDL_CONTROLLER_BUTTON_LEFTSTICK: return kGamepadBtn_L3;
+  case SDL_CONTROLLER_BUTTON_RIGHTSTICK: return kGamepadBtn_R3;
+  case SDL_CONTROLLER_BUTTON_LEFTSHOULDER: return kGamepadBtn_L1;
+  case SDL_CONTROLLER_BUTTON_RIGHTSHOULDER: return kGamepadBtn_R1;
+  case SDL_CONTROLLER_BUTTON_DPAD_UP: return kGamepadBtn_DpadUp;
+  case SDL_CONTROLLER_BUTTON_DPAD_DOWN: return kGamepadBtn_DpadDown;
+  case SDL_CONTROLLER_BUTTON_DPAD_LEFT: return kGamepadBtn_DpadLeft;
+  case SDL_CONTROLLER_BUTTON_DPAD_RIGHT: return kGamepadBtn_DpadRight;
+  default: return -1;
+  }
+}
+
+static void HandleGamepadInput(int button, bool pressed) {
+  if (!!(g_gamepad_modifiers & (1 << button)) == pressed)
+    return;
+  g_gamepad_modifiers ^= 1 << button;
+  if (pressed)
+    g_gamepad_last_cmd[button] = FindCmdForGamepadButton(button, g_gamepad_modifiers);
+  if (g_gamepad_last_cmd[button] != 0)
+    HandleCommand(g_gamepad_last_cmd[button], pressed);
+}
+
+static void HandleVolumeAdjustment(int volume_adjustment) {
+#if SYSTEM_VOLUME_MIXER_AVAILABLE
+  int current_volume = GetApplicationVolume();
+  int new_volume = IntMin(IntMax(0, current_volume + volume_adjustment * 5), 100);
+  SetApplicationVolume(new_volume);
+  printf("[System Volume]=%i\n", new_volume);
+#else
+  g_sdl_audio_mixer_volume = IntMin(IntMax(0, g_sdl_audio_mixer_volume + volume_adjustment * (SDL_MIX_MAXVOLUME >> 4)), SDL_MIX_MAXVOLUME);
+  printf("[SDL mixer volume]=%i\n", g_sdl_audio_mixer_volume);
+#endif
+}
+
+// Approximates atan2(y, x) normalized to the [0,4) range
+// with a maximum error of 0.1620 degrees
+// normalized_atan(x) ~ (b x + x^2) / (1 + 2 b x + x^2)
+static float ApproximateAtan2(float y, float x) {
+  uint32 sign_mask = 0x80000000;
+  float b = 0.596227f;
+  // Extract the sign bits
+  uint32 ux_s = sign_mask & *(uint32 *)&x;
+  uint32 uy_s = sign_mask & *(uint32 *)&y;
+  // Determine the quadrant offset
+  float q = (float)((~ux_s & uy_s) >> 29 | ux_s >> 30);
+  // Calculate the arctangent in the first quadrant
+  float bxy_a = b * x * y;
+  if (bxy_a < 0.0f) bxy_a = -bxy_a;  // avoid fabs
+  float num = bxy_a + y * y;
+  float atan_1q = num / (x * x + bxy_a + num + 0.000001f);
+  // Translate it to the proper quadrant
+  uint32_t uatan_2q = (ux_s ^ uy_s) | *(uint32 *)&atan_1q;
+  return q + *(float *)&uatan_2q;
+}
+
+static void HandleGamepadAxisInput(int gamepad_id, int axis, int value) {
+  static int last_gamepad_id, last_x, last_y;
+  if (axis == SDL_CONTROLLER_AXIS_LEFTX || axis == SDL_CONTROLLER_AXIS_LEFTY) {
+    // ignore other gamepads unless they have a big input
+    if (last_gamepad_id != gamepad_id) {
+      if (value > -16000 && value < 16000)
+        return;
+      last_gamepad_id = gamepad_id;
+      last_x = last_y = 0;
+    }
+    *(axis == SDL_CONTROLLER_AXIS_LEFTX ? &last_x : &last_y) = value;
+    int buttons = 0;
+    if (last_x * last_x + last_y * last_y >= 10000 * 10000) {
+      // in the non deadzone part, divide the circle into eight 45 degree
+      // segments rotated by 22.5 degrees that control which direction to move.
+      // todo: do this without floats?
+      static const uint8 kSegmentToButtons[8] = {
+        1 << 4,           // 0 = up
+        1 << 4 | 1 << 7,  // 1 = up, right
+        1 << 7,           // 2 = right
+        1 << 7 | 1 << 5,  // 3 = right, down
+        1 << 5,           // 4 = down
+        1 << 5 | 1 << 6,  // 5 = down, left
+        1 << 6,           // 6 = left
+        1 << 6 | 1 << 4,  // 7 = left, up
+      };
+      uint8 angle = (uint8)(int)(ApproximateAtan2(last_y, last_x) * 64.0f + 0.5f);
+      buttons = kSegmentToButtons[(uint8)(angle + 16 + 64) >> 5];
+    }
+    g_gamepad_buttons = buttons;
+  } else if ((axis == SDL_CONTROLLER_AXIS_TRIGGERLEFT || axis == SDL_CONTROLLER_AXIS_TRIGGERRIGHT)) {
+    if (value < 12000 || value >= 16000)  // hysteresis
+      HandleGamepadInput(axis == SDL_CONTROLLER_AXIS_TRIGGERLEFT ? kGamepadBtn_L2 : kGamepadBtn_R2, value >= 12000);
+  }
+}
+
+static bool LoadRom(const char *filename) {
+  size_t length = 0;
+  uint8 *file = ReadWholeFile(filename, &length);
+  if(!file) Die("Failed to read file");
+  bool result = EmuInitialize(file, length);
+  free(file);
+  return result;
+}
+
+static bool ParseLinkGraphics(uint8 *file, size_t length) {
+  if (length < 27 || memcmp(file, "ZSPR", 4) != 0)
+    return false;
+  uint32 pixel_offs = DWORD(file[9]);
+  uint32 pixel_length = WORD(file[13]);
+  uint32 palette_offs = DWORD(file[15]);
+  uint32 palette_length = WORD(file[19]);
+  if ((uint64)pixel_offs + pixel_length > length ||
+      (uint64)palette_offs + palette_length > length ||
+      pixel_length != 0x7000)
+    return false;
+  if (kPalette_ArmorAndGloves_SIZE != 150 || kLinkGraphics_SIZE != 0x7000)
+    Die("ParseLinkGraphics: Invalid asset sizes");
+  memcpy(kLinkGraphics, file + pixel_offs, 0x7000);
+  if (palette_length >= 120)
+    memcpy(kPalette_ArmorAndGloves, file + palette_offs, 120);
+  if (palette_length >= 124)
+    memcpy(kGlovesColor, file + palette_offs + 120, 4);
+  return true;
+}
+
+static void LoadLinkGraphics() {
+  if (g_config.link_graphics) {
+    fprintf(stderr, "Loading Link Graphics: %s\n", g_config.link_graphics);
+    size_t length = 0;
+    uint8 *file = ReadWholeFile(g_config.link_graphics, &length);
+    if (file == NULL || !ParseLinkGraphics(file, length))
+      Die("Unable to load file");
+    free(file);
+  }
+}
+
+
+const uint8 *g_asset_ptrs[kNumberOfAssets];
+uint32 g_asset_sizes[kNumberOfAssets];
+
+static void LoadAssets() {
+  size_t length = 0;
+  uint8 *data = ReadWholeFile("zelda3_assets.dat", &length);
+  if (!data)
+    data = ReadWholeFile("tables/zelda3_assets.dat", &length);
+  if (!data) Die("Failed to read zelda3_assets.dat. Please see the README for information about how you get this file.");
+
+  static const char kAssetsSig[] = { kAssets_Sig };
+
+  if (length < 16 + 32 + 32 + 8 + kNumberOfAssets * 4 ||
+      memcmp(data, kAssetsSig, 48) != 0 ||
+      *(uint32*)(data + 80) != kNumberOfAssets)
+    Die("Invalid assets file");
+
+  uint32 offset = 88 + kNumberOfAssets * 4 + *(uint32 *)(data + 84);
+
+  for (size_t i = 0; i < kNumberOfAssets; i++) {
+    uint32 size = *(uint32 *)(data + 88 + i * 4);
+    offset = (offset + 3) & ~3;
+    if ((uint64)offset + size > length)
+      Die("Assets file corruption");
+    g_asset_sizes[i] = size;
+    g_asset_ptrs[i] = data + offset;
+    offset += size;
+  }
+
+  if (g_config.features0 & kFeatures0_DimFlashes) { // patch dungeon floor palettes
+    kPalette_DungBgMain[0x484] = 0x70;
+    kPalette_DungBgMain[0x485] = 0x95;
+    kPalette_DungBgMain[0x486] = 0x57;
+  }
+}
+
+// Go some steps up and find zelda3.ini
+static void SwitchDirectory() {
+  char buf[4096];
+  if (!getcwd(buf, sizeof(buf) - 32))
+    return;
+  size_t pos = strlen(buf);
+
+  for (int step = 0; pos != 0 && step < 3; step++) {
+    memcpy(buf + pos, "/zelda3.ini", 12);
+    FILE *f = fopen(buf, "rb");
+    if (f) {
+      fclose(f);
+      buf[pos] = 0;
+      if (step != 0) {
+        printf("Found zelda3.ini in %s\n", buf);
+        int err = chdir(buf);
+        (void)err;
+      }
+      return;
+    }
+    pos--;
+    while (pos != 0 && buf[pos] != '/' && buf[pos] != '\\')
+      pos--;
+  }
+}
+
+MemBlk FindInAssetArray(int asset, int idx) {
+  return FindIndexInMemblk((MemBlk) { g_asset_ptrs[asset], g_asset_sizes[asset] }, idx);
+}
--- /dev/null
+++ b/src/messaging.c
@@ -1,0 +1,2935 @@
+#include "messaging.h"
+#include "zelda_rtl.h"
+#include "variables.h"
+#include "snes/snes_regs.h"
+#include "dungeon.h"
+#include "hud.h"
+#include "load_gfx.h"
+#include "dungeon.h"
+#include "overworld.h"
+#include "variables.h"
+#include "ancilla.h"
+#include "player.h"
+#include "misc.h"
+#include "sprite.h"
+#include "player_oam.h"
+#include "attract.h"
+#include "nmi.h"
+#include "assets.h"
+
+static void WorldMap_AddSprite(int spr, uint8 big, uint8 flags, uint8 ch, uint16 x, uint16 y);
+static bool WorldMap_CalculateOamCoordinates(Point16U *pt);
+
+static const int8 kDungMap_Tab0[14] = {-1, -1, -1, -1, -1, 2, 0, 10, 4, 8, -1, 6, 12, 14};
+static const uint16 kDungMap_Tab1[8] = {0x2108, 0x2109, 0x2109, 0x210a, 0x210b, 0x210c, 0x210d, 0x211d};
+static const uint16 kDungMap_Tab2[8] = {0x2118, 0x2119, 0xa109, 0x211a, 0x211b, 0x211c, 0x2118, 0xa11d};
+static const uint8 kDungMap_Tab3[14] = {0x60, 0x84, 0, 0xb, 0x32, 0x21, 0x33, 0x21, 0x38, 0x21, 0x3a, 0x21, 0x7f, 0x20};
+static const uint8 kDungMap_Tab4[14] = {0x60, 0xa4, 0, 0xb, 0x42, 0x21, 0x43, 0x21, 0x49, 0x21, 0x4a, 0x21, 0x7f, 0x20};
+static const uint16 kDungMap_Tab8[7] = {0x1b28, 0x1b29, 0x1b2a, 0x1b2b, 0x1b2c, 0x1b2d, 0x1b2e};
+static const uint16 kDungMap_Tab6[21] = {0xaa10, 0x100, 0x1b2f, 0xc910, 0x300, 0x1b2f, 0x1b2e, 0xe510, 0xb00, 0x1b2f, 0x1b2e, 0x5b2f, 0x1b2f, 0x1b2e, 0x1b2e, 0x311, 0x100, 0x1b2f, 0x411, 0xc40, 0x1b2e};
+static const uint16 kDungMap_Tab5[14] = {0x21, 0x23, 0x20, 0x21, 0x70, 0x12, 0x11, 0x212, 2, 0x217, 0x160, 0x12, 0x113, 0x171};
+static const uint16 kDungMap_Tab7[9] = {0x1223, 0x1263, 0x12a3, 0x12e3, 0x1323, 0x11e3, 0x11a3, 0x1163, 0x1123};
+static const uint16 kDungMap_Tab9[8] = {0xf26, 0xf27, 0x4f27, 0x4f26, 0x8f26, 0x8f27, 0xcf27, 0xcf26};
+static const uint16 kDungMap_Tab10[4] = {0xe2, 0xf8, 0x3a2, 0x3b8};
+static const uint16 kDungMap_Tab11[4] = {0x1f19, 0x5f19, 0x9f19, 0xdf19};
+static const uint16 kDungMap_Tab12[2] = {0xe4, 0x3a4};
+static const uint16 kDungMap_Tab13[2] = {0x1f1a, 0x9f1a};
+static const uint16 kDungMap_Tab14[2] = {0x122, 0x138};
+static const uint16 kDungMap_Tab15[2] = {0x1f1b, 0x5f1b};
+static const uint16 kDungMap_Tab16[8] = {0x1f1e, 0x1f1f, 0x1f20, 0x1f21, 0x1f22, 0x1f23, 0x1f24, 0x1f25};
+static const uint16 kDungMap_Tab23[744] = {
+  0xb61, 0x5361, 0x8b61, 0x8b62, 0xb60, 0xb63, 0x8b60, 0xb64, 0xb00, 0xb00, 0xb65, 0xb66, 0xb67, 0x4b67, 0x9367, 0xd367, 0xb60, 0x5360, 0x8b60, 0xcb60, 0xb6a, 0x4b6a, 0x4b6d, 0xb6d, 0x1368, 0x1369, 0xb00, 0xb00, 0xb6a, 0x136b, 0xb6c, 0xb6d,
+  0x136e, 0x4b6e, 0xb00, 0xb00, 0x136f, 0xb00, 0xb00, 0xb00, 0x1340, 0xb00, 0xb78, 0x1744, 0x536d, 0x136d, 0x4b76, 0xb76, 0xb70, 0xb71, 0xb72, 0x8b71, 0xb75, 0xb76, 0x8b75, 0x8b76, 0xb00, 0xb53, 0xb00, 0xb55, 0x1354, 0x5354, 0xb00, 0xb00,
+  0x4b53, 0xb00, 0xb56, 0xb57, 0xb00, 0xb59, 0xb00, 0x135e, 0x135a, 0x135b, 0x135f, 0x535f, 0xb5c, 0xb5d, 0x535e, 0xcb58, 0xb50, 0x4b50, 0x1352, 0x5352, 0xb00, 0xb40, 0x1345, 0xb46, 0x8b42, 0xb47, 0xb42, 0xb49, 0x1348, 0x5348, 0x174a, 0x574a,
+  0x4b47, 0xcb42, 0x4b49, 0x4b42, 0xb00, 0xb4b, 0xb00, 0xb4d, 0xb4c, 0x4b4c, 0xb4e, 0x4b4e, 0xb51, 0xb44, 0xb00, 0xb00, 0xb4f, 0x4b4f, 0x934f, 0xd34f, 0xb00, 0xb00, 0xb00, 0xb40, 0xb00, 0xb41, 0xb00, 0xb42, 0xb00, 0xb00, 0xb43, 0xb43,
+  0xb00, 0xb00, 0x9344, 0xb00, 0x1340, 0xb00, 0x1341, 0xb00, 0x1740, 0xb40, 0xb42, 0xb7d, 0x4b7a, 0xb7a, 0xb7e, 0x4b7e, 0xb40, 0x8b4d, 0x4bba, 0xb55, 0xb40, 0x8b55, 0x1378, 0xcb53, 0x4b76, 0x4b75, 0x13bb, 0x53bb, 0x4b7f, 0x4b42, 0xb83, 0x13bc,
+  0xb00, 0xb00, 0xb79, 0xb00, 0xb6e, 0x4b7c, 0xb00, 0xb41, 0x1340, 0x8b55, 0xb42, 0xb7b, 0x8b42, 0x9344, 0x1341, 0xb00, 0xb53, 0x9344, 0x8b53, 0x9344, 0x8b42, 0x9344, 0xb42, 0x9344, 0x934d, 0xb00, 0x8b53, 0x9344, 0xb00, 0xb00, 0xb40, 0xb00,
+  0xb41, 0xb00, 0x1384, 0xb00, 0xbb8, 0x13b9, 0x4b85, 0xcb7c, 0xb87, 0x13b0, 0x4b7b, 0x9344, 0xb00, 0xb00, 0xb40, 0xb00, 0xb91, 0x5391, 0xb9c, 0x4b9c, 0x8b42, 0x1392, 0xb93, 0x1394, 0xb95, 0xb96, 0x9395, 0x8b96, 0xb97, 0xb98, 0x8b97, 0x8b98,
+  0x1799, 0x5799, 0x9799, 0xd799, 0x4b98, 0x4b97, 0xcb98, 0xcb97, 0x937b, 0xb00, 0xb7b, 0xb00, 0xba6, 0x4ba6, 0xcb7a, 0x8b7a, 0xb8e, 0x4b8e, 0x938e, 0xcb8e, 0x934d, 0xb8f, 0x1390, 0x5390, 0xb00, 0xb00, 0xb00, 0x8b48, 0xb00, 0x934e, 0xb00, 0x8b4d,
+  0x8b72, 0x1346, 0xb45, 0xb46, 0x5744, 0x1744, 0xb00, 0xb00, 0x134d, 0xb00, 0x8b54, 0xb00, 0x1349, 0x1349, 0xb00, 0xb00, 0xb4b, 0x8b48, 0xb72, 0x4b72, 0xb00, 0xb74, 0xb00, 0xbb0, 0xb71, 0x1747, 0x17af, 0xb4b, 0xb6f, 0x1370, 0xb4b, 0xb00,
+  0xb6b, 0x8b6c, 0x8b6b, 0xbad, 0xb73, 0xb00, 0x13ae, 0xb46, 0x176b, 0x576b, 0xb6a, 0x4b6a, 0x1368, 0x5368, 0x1369, 0x5369, 0x8b4e, 0xb00, 0x9354, 0xb00, 0xb00, 0xb00, 0xb00, 0x5377, 0xb00, 0x974d, 0xb00, 0x4b7b, 0xb40, 0x8b4d, 0xb51, 0xb8d,
+  0x537a, 0x137a, 0x4b42, 0x8b40, 0xb00, 0xb00, 0xb00, 0xb00, 0xb00, 0xb00, 0xb40, 0xb00, 0xcb7a, 0x576e, 0xb00, 0xb00, 0xb6e, 0xb9f, 0xb00, 0x4ba5, 0x13a0, 0x13a1, 0xba2, 0xba3, 0xba4, 0xb00, 0xba5, 0xb00, 0xb40, 0x8b55, 0xb42, 0xcb87,
+  0x8b95, 0xba7, 0x8b42, 0xbaf, 0x4b78, 0xb00, 0x4b78, 0xb00, 0x8b42, 0xb51, 0xb78, 0x8b51, 0xba8, 0xba9, 0xbac, 0x8ba9, 0xbaa, 0x17ab, 0x13b4, 0x8bab, 0x17b1, 0xb41, 0x4b44, 0x4b42, 0xb00, 0xbad, 0xb00, 0x13ae, 0x1340, 0xbb7, 0xb42, 0xbb6,
+  0xb00, 0xb00, 0x139d, 0x139e, 0xb00, 0xb00, 0xb00, 0xb79, 0xb00, 0xb00, 0x8b42, 0xb86, 0xb42, 0x8b7b, 0x8b42, 0xb7b, 0xb87, 0x8b7b, 0x9387, 0xb7b, 0xb40, 0x13b3, 0x1378, 0xb8d, 0x8b42, 0xb88, 0x5378, 0xb40, 0x4b44, 0xd342, 0x97b5, 0x4b78,
+  0x13b3, 0x8b55, 0x4b7b, 0xb8d, 0xb89, 0x138a, 0xb8b, 0xb8c, 0xb00, 0xb7c, 0xb00, 0xb00, 0xb00, 0x9348, 0xb00, 0xb56, 0xb00, 0xb00, 0xb88, 0xb00, 0xb00, 0xb48, 0xb00, 0xb00, 0xb00, 0x9348, 0x1786, 0xb65, 0xb00, 0xb00, 0xcb5a, 0xb00,
+  0xb00, 0x5388, 0xb00, 0xb00, 0x4b5a, 0xb00, 0xb00, 0xb00, 0xb00, 0xcb5b, 0x13ab, 0xbac, 0xcb5a, 0xb00, 0x137e, 0xb00, 0xb00, 0x137e, 0xb00, 0xb00, 0xb00, 0x8b48, 0x1783, 0x1384, 0xb00, 0xb00, 0x1385, 0xb00, 0xb00, 0x537e, 0xb00, 0xb00,
+  0xb00, 0x8b48, 0xb43, 0xcb43, 0xb00, 0xb00, 0x1379, 0x137a, 0xb5a, 0x137b, 0xb00, 0xb00, 0xb00, 0x8b48, 0x137f, 0x1380, 0xb00, 0xb00, 0x1381, 0x1382, 0xb00, 0xb48, 0xb00, 0xb00, 0xb00, 0xb00, 0x1387, 0x1377, 0x5746, 0xb47, 0x1349, 0xb48,
+  0x1375, 0x4b42, 0x174a, 0x574a, 0xb43, 0x1344, 0xb45, 0x1746, 0x1742, 0x5742, 0x8b42, 0xcb42, 0x1375, 0x5375, 0x8b42, 0xcb42, 0x4b40, 0x1340, 0xb41, 0x4b41, 0x4b46, 0xb71, 0x1786, 0x8b71, 0x1347, 0xb4d, 0xb65, 0xb5b, 0xb00, 0xb00, 0x9348, 0xb00,
+  0xb00, 0xb00, 0xb00, 0x8b48, 0x4b66, 0x8b65, 0x4b5b, 0xb65, 0x9365, 0xb66, 0xb63, 0x8b66, 0x4b51, 0xb5f, 0xcb76, 0xb60, 0xb64, 0x4b4f, 0x4b60, 0x8b76, 0x4b76, 0xb61, 0xd376, 0x1362, 0x4b61, 0xb76, 0xcb58, 0x8b51, 0xb00, 0xb00, 0x5746, 0xb5e,
+  0xb00, 0xb00, 0xb5e, 0xb46, 0xb00, 0xb00, 0x8b48, 0xb00, 0xb4f, 0xb51, 0xcb76, 0x8b76, 0x5351, 0xb51, 0x8b4f, 0x8b51, 0x4b76, 0xb76, 0xcb51, 0x8b58, 0xb54, 0xb00, 0x8b66, 0xb00, 0x9348, 0x8b48, 0xb56, 0x4b45, 0xb00, 0xb57, 0xb00, 0xb59,
+  0x4b50, 0xb58, 0xcb50, 0x8b50, 0x5758, 0x1751, 0xcb58, 0x8b51, 0xb56, 0x4b56, 0xb65, 0x5756, 0x9348, 0x8b48, 0xb4c, 0xb4b, 0xb4d, 0xb00, 0x8b54, 0xb00, 0xb4f, 0xb50, 0x8b4f, 0x8b50, 0x4b50, 0xb51, 0xcb58, 0x8b51, 0xb52, 0xb54, 0xb53, 0x9354,
+  0x9748, 0x9748, 0x138d, 0x138e, 0x1391, 0x1392, 0x138c, 0x138f, 0x1393, 0x1390, 0x9393, 0x138f, 0x1394, 0x1395, 0x138e, 0x138c, 0x175d, 0x1399, 0x975d, 0x538f, 0x1397, 0x1398, 0x179a, 0x138c, 0x1399, 0x1766, 0x138f, 0xd75d, 0x538e, 0x538f, 0x1391, 0x1392,
+  0x139b, 0x539b, 0x139c, 0x539c, 0x138f, 0x138e, 0x5392, 0x5391, 0x138a, 0x538a, 0x138b, 0x538b, 0xb00, 0xcb5b, 0xb00, 0x8b54, 0x4b74, 0x13a6, 0xb00, 0x4b48, 0x13a0, 0x13a1, 0x538e, 0x138e, 0xd38e, 0x53a3, 0x13a4, 0xb00, 0x97aa, 0xb00, 0x538e, 0x1399,
+  0x13a4, 0xb00, 0x138e, 0xb00, 0xb00, 0x5393, 0xb00, 0x574e, 0x4b7d, 0xb00, 0x8b7d, 0x139f, 0x97aa, 0x13a4, 0x13a9, 0x53a9, 0x13a5, 0x13a6, 0x93a5, 0xd3a5, 0xd38e, 0x938e, 0x13a4, 0x13aa, 0xb00, 0x13a6, 0xb00, 0x8b5f, 0x139b, 0x13a6, 0x139c, 0x53a2,
+  0xb00, 0xb00, 0x138c, 0xb00, 0x9394, 0x139e, 0xb00, 0xb00,
+};
+static const uint16 kDungMap_Tab21[3] = {137, 167, 79};
+static const uint16 kDungMap_Tab22[3] = {169, 119, 190};
+static const uint16 kDungMap_Tab24[2] = {0x1f, 0x7f};
+static const uint16 kDungMap_Tab25[14] = {15, 15, 200, 51, 32, 6, 90, 144, 41, 222, 7, 172, 164, 13};
+static const int16 kDungMap_Tab28[14] = {-1, -1, 1, 1, 6, 0xff, 0xff, 0xff, 0xfe, 0xf9, 5, 0xff, 0xfd, 6};
+static PlayerHandlerFunc *const kDungMapInit[] = {
+  &Module0E_03_01_00_PrepMapGraphics,
+  &Module0E_03_01_01_DrawLEVEL,
+  &Module0E_03_01_02_DrawFloorsBackdrop,
+  &Module0E_03_01_03_DrawRooms,
+  &DungeonMap_DrawRoomMarkers,
+};
+static const uint8 kDungMap_Tab38[4] = {0x39, 0x3b, 0x3d, 0x3b};
+static const int8 kDungMap_Tab29[4] = {-9, 8, -9, 8};
+static const int8 kDungMap_Tab30[4] = {-8, -8, 9, 9};
+static const uint8 kDungMap_Tab31[4] = {0xf1, 0xb1, 0x71, 0x31};
+static const uint8 kDungMap_Tab32[4] = {0xc, 0xc, 8, 0xa};
+static const uint8 kDungMap_Tab33[8] = {187, 171, 155, 139, 123, 107, 91, 75};
+static const uint8 kDungMap_Tab34[8] = {0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25};
+static const uint8 kDungMap_Tab35[2] = {0, 8};
+static const uint8 kDungMap_Tab36[4] = {0x37, 0x38, 0x38, 0x37};
+static const int16 kDungMap_Tab37[14] = { -1, -1, 0x808, 8, 0, 8, 0x808, 8, 0x808, 0x800, 0x404, 0x808, 8, 8 };
+static const int8 kDungMap_Tab39[2] = {-4, 4};
+static const int8 kDungMap_Tab40[2] = {4, -4};
+static const int16 kDungMap_Tab26[2] = {0x60, -0x60};
+static PlayerHandlerFunc *const kDungMapSubmodules[] = {
+  &DungMap_Backup,
+  &Module0E_03_01_DrawMap,
+  &DungMap_LightenUpMap,
+  &DungeonMap_HandleInputAndSprites,
+  &DungMap_4,
+  &DungMap_FadeMapToBlack,
+  &DungeonMap_RecoverGFX,
+  &ToggleStarTilesAndAdvance,
+  &DungMap_RestoreOld,
+};
+static const uint16 kText_Positions[2] = {0x6125, 0x6244};
+static const uint16 kSrmOffsets[4] = {0, 0x500, 0xa00, 0xf00};
+static const int8 kText_InitializationData[32] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0x39, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1c, 4, 0, 0, 0, 0, 0};
+static const uint16 kText_BorderTiles[9] = {0x28f3, 0x28f4, 0x68f3, 0x28c8, 0x387f, 0x68c8, 0xa8f3, 0xa8f4, 0xe8f3};
+static const uint8 kText_CommandLengths[25] = {
+  1, 1, 1, 1, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1,
+  2, 2, 2, 2, 1, 1, 1, 1, 1,
+};
+static const uint8 kVWF_RenderCharacter_setMasks[8] = {0x80, 0x40, 0x20, 0x10, 8, 4, 2, 1};
+static const uint16 kVWF_RenderCharacter_renderPos[3] = {0, 0x2a0, 0x540};
+static const uint16 kVWF_RenderCharacter_linePositions[3] = {0, 0x40, 0x80};
+static const uint16 kVWF_RowPositions[3] = {0, 2, 4};
+static const uint16 kText_WaitDurations[16] = {31, 63, 94, 125, 156, 188, 219, 250, 281, 313, 344, 375, 406, 438, 469, 500};
+static PlayerHandlerFunc *const kText_Render[] = {
+  &RenderText_Draw_Border,
+  &RenderText_Draw_BorderIncremental,
+  &RenderText_Draw_CharacterTilemap,
+  &RenderText_Draw_MessageCharacters,
+  &RenderText_Draw_Finish,
+};
+static PlayerHandlerFunc *const kMessaging_Text[] = {
+  &Text_Initialize,
+  &Text_Render,
+  &RenderText_PostDeathSaveOptions,
+};
+static const uint8 kOverworldMap_tab1[333] = {
+  0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xdf,
+  0xde, 0xdd, 0xdc, 0xdb, 0xda, 0xd8, 0xd7, 0xd6, 0xd5, 0xd4, 0xd3, 0xd2, 0xd1, 0xd0, 0xcf, 0xce,
+  0xcd, 0xcc, 0xcb, 0xca, 0xc9, 0xc7, 0xc6, 0xc5, 0xc4, 0xc3, 0xc2, 0xc1, 0xc0, 0xbf, 0xbe, 0xbd,
+  0xbc, 0xbb, 0xba, 0xb9, 0xb8, 0xb7, 0xb6, 0xb5, 0xb4, 0xb3, 0xb2, 0xb1, 0xb0, 0xaf, 0xae, 0xad,
+  0xac, 0xab, 0xaa, 0xa9, 0xa8, 0xa7, 0xa6, 0xa5, 0xa4, 0xa3, 0xa2, 0xa1, 0xa0, 0x9f, 0x9e, 0x9d,
+  0x9c, 0x9b, 0x9b, 0x9a, 0x99, 0x98, 0x97, 0x96, 0x95, 0x94, 0x93, 0x92, 0x91, 0x90, 0x8f, 0x8e,
+  0x8d, 0x8c, 0x8b, 0x8b, 0x8a, 0x89, 0x88, 0x87, 0x86, 0x85, 0x84, 0x83, 0x82, 0x81, 0x81, 0x80,
+  0x7f, 0x7e, 0x7d, 0x7c, 0x7b, 0x7a, 0x79, 0x79, 0x78, 0x77, 0x76, 0x75, 0x74, 0x73, 0x72, 0x72,
+  0x71, 0x70, 0x6f, 0x6e, 0x6d, 0x6c, 0x6c, 0x6b, 0x6a, 0x69, 0x68, 0x67, 0x67, 0x66, 0x65, 0x64,
+  0x63, 0x62, 0x62, 0x61, 0x60, 0x5f, 0x5e, 0x5d, 0x5d, 0x5c, 0x5b, 0x5a, 0x59, 0x59, 0x58, 0x57,
+  0x56, 0x55, 0x55, 0x54, 0x53, 0x52, 0x51, 0x51, 0x50, 0x4f, 0x4e, 0x4e, 0x4d, 0x4c, 0x4b, 0x4a,
+  0x4a, 0x49, 0x48, 0x47, 0x47, 0x46, 0x45, 0x44, 0x44, 0x43, 0x42, 0x41, 0x41, 0x40, 0x3f, 0x3e,
+  0x3e, 0x3d, 0x3c, 0x3c, 0x3b, 0x3a, 0x39, 0x39, 0x38, 0x37, 0x36, 0x36, 0x35, 0x34, 0x34, 0x33,
+  0x32, 0x32, 0x31, 0x30, 0x2f, 0x2f, 0x2e, 0x2d, 0x2d, 0x2c, 0x2b, 0x2b, 0x2a, 0x29, 0x29, 0x28,
+  0x27, 0x27, 0x26, 0x25, 0x25, 0x24, 0x23, 0x23, 0x22, 0x21, 0x21, 0x20, 0x1f, 0x1f, 0x1e, 0x1d,
+  0x1d, 0x1c, 0x1c, 0x1b, 0x1a, 0x1a, 0x19, 0x18, 0x18, 0x17, 0x17, 0x16, 0x15, 0x15, 0x14, 0x14,
+  0x13, 0x12, 0x12, 0x11, 0x10, 0x10,  0xf,  0xf,  0xe,  0xe,  0xd,  0xc,  0xc,  0xb,  0xb,  0xa,
+     9,    9,    8,    8,    7,    7,    6,    5,    5,    4,    4,    3,    3,    2,    1,    1,
+     0,    0,    0,    0, 0xff, 0xfe, 0xfe, 0xfd, 0xfc, 0xfc, 0xfb, 0xfb, 0xfa, 0xf9, 0xf9, 0xf8,
+  0xf7, 0xf7, 0xf6, 0xf5, 0xf4, 0xf4, 0xf3, 0xf2, 0xf2, 0xf1, 0xf0, 0xef, 0xee, 0xee, 0xed, 0xec,
+  0xeb, 0xea, 0xe9, 0xe8, 0xe8, 0xe7, 0xe6, 0xe5, 0xe4, 0xe3, 0xe2, 0xe1, 0xe0,
+};
+static const uint8 kOverworldMapData[7] = {0x79, 0x6e, 0x6f, 0x6d, 0x7c, 0x6c, 0x7f};
+static const uint8 kBirdTravel_tab1[8] = {0x7f, 0x79, 0x6c, 0x6d, 0x6e, 0x6f, 0x7c, 0x7d};
+static const uint8 kBirdTravel_x_lo[8] = {0x80, 0xcf, 0x10, 0xb8, 0x30, 0x70, 0x70, 0xf0};
+static const uint8 kBirdTravel_x_hi[8] = {6, 0xc, 2, 8, 0xf, 0, 7, 0xe};
+static const uint8 kBirdTravel_y_lo[8] = {0x5b, 0x98, 0xc0, 0x20, 0x50, 0xb0, 0x30, 0x80};
+static const uint8 kBirdTravel_y_hi[8] = {3, 5, 7, 0xb, 0xb, 0xf, 0xf, 0xf};
+static const uint8 kPendantBitMask[3] = {4, 1, 2};
+static const uint8 kCrystalBitMask[7] = {2, 0x40, 8, 0x20, 1, 4, 0x10};
+static const uint16 kOwMapCrystal0_x[9] = {0x7ff, 0x2c0, 0xd00, 0xf31, 0x6d, 0x7e0, 0xf40, 0xf40, 0x8dc};
+static const uint16 kOwMapCrystal0_y[9] = {0x730, 0x6a0, 0x710, 0x620, 0x70, 0x640, 0x620, 0x620, 0x30};
+static const uint16 kOwMapCrystal1_x[9] = {0xff00, 0xff00, 0xff00, 0x8d0, 0xff00, 0xff00, 0xff00, 0x82, 0xff00};
+static const uint16 kOwMapCrystal1_y[9] = {0xff00, 0xff00, 0xff00, 0x80, 0xff00, 0xff00, 0xff00, 0xb0, 0xff00};
+static const uint16 kOwMapCrystal2_x[9] = {0xff00, 0xff00, 0xff00, 0x108, 0xff00, 0xff00, 0xff00, 0xf11, 0xff00};
+static const uint16 kOwMapCrystal2_y[9] = {0xff00, 0xff00, 0xff00, 0xd70, 0xff00, 0xff00, 0xff00, 0x103, 0xff00};
+static const uint16 kOwMapCrystal3_x[9] = {0xff00, 0xff00, 0xff00, 0x6d, 0xff00, 0xff00, 0xff00, 0x1d0, 0xff00};
+static const uint16 kOwMapCrystal3_y[9] = {0xff00, 0xff00, 0xff00, 0x70, 0xff00, 0xff00, 0xff00, 0x780, 0xff00};
+static const uint16 kOwMapCrystal4_x[9] = {0xff00, 0xff00, 0xff00, 0xff00, 0xff00, 0xff00, 0xff00, 0x100, 0xff00};
+static const uint16 kOwMapCrystal4_y[9] = {0xff00, 0xff00, 0xff00, 0xff00, 0xff00, 0xff00, 0xff00, 0xca0, 0xff00};
+static const uint16 kOwMapCrystal5_x[9] = {0xff00, 0xff00, 0xff00, 0xff00, 0xff00, 0xff00, 0xff00, 0xca0, 0xff00};
+static const uint16 kOwMapCrystal5_y[9] = {0xff00, 0xff00, 0xff00, 0xff00, 0xff00, 0xff00, 0xff00, 0xda0, 0xff00};
+static const uint16 kOwMapCrystal6_x[9] = {0xff00, 0xff00, 0xff00, 0xff00, 0xff00, 0xff00, 0xff00, 0x759, 0xff00};
+static const uint16 kOwMapCrystal6_y[9] = {0xff00, 0xff00, 0xff00, 0xff00, 0xff00, 0xff00, 0xff00, 0xed0, 0xff00};
+static const uint16 kOwMapCrystal0_tab[9] = {0, 0, 0, 0x6038, 0x6234, 0x6632, 0x6434, 0x6434, 0x6632};
+static const uint16 kOwMapCrystal1_tab[9] = {0, 0, 0, 0x6032, 0, 0, 0, 0x6434, 0};
+static const uint16 kOwMapCrystal2_tab[9] = {0, 0, 0, 0x6034, 0, 0, 0, 0x6434, 0};
+static const uint16 kOwMapCrystal3_tab[9] = {0, 0, 0, 0x6234, 0, 0, 0, 0x6434, 0};
+static const uint16 kOwMapCrystal4_tab[9] = {0, 0, 0, 0, 0, 0, 0, 0x6434, 0};
+static const uint16 kOwMapCrystal5_tab[9] = {0, 0, 0, 0, 0, 0, 0, 0x6434, 0};
+static const uint16 kOwMapCrystal6_tab[9] = {0, 0, 0, 0, 0, 0, 0, 0x6434, 0};
+static const uint8 kOwMap_tab2[4] = {0x68, 0x69, 0x78, 0x69};
+static const uint8 kOverworldMap_Table4[4] = {0x34, 0x74, 0xf4, 0xb4};
+static const uint8 kOverworldMap_Timer[2] = {33, 12};
+static const int16 kOverworldMap_Table3[8] = {0, 0, 1, 2, -1, -2, 1, 2};
+static const int16 kOverworldMap_Table2[8] = {0, 0, 224, 480, -72, -224, 0, 0};
+static PlayerHandlerFunc *const kMessagingSubmodules[12] = {
+  &Module_Messaging_0,
+  &Hud_Module_Run,
+  &RenderText,
+  &Module0E_03_DungeonMap,
+  &Module0E_04_RedPotion,
+  &Module0E_05_DesertPrayer,
+  &Module_Messaging_6,
+  &Messaging_OverworldMap,
+  &Module0E_08_GreenPotion,
+  &Module0E_09_BluePotion,
+  &Module0E_0A_FluteMenu,
+  &Module0E_0B_SaveMenu,
+};
+static const uint8 kDeath_AnimCtr0[15] = {0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 4, 5, 5};
+static const uint8 kDeath_AnimCtr1[15] = {5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 3, 3, 0x62};
+static const uint8 kDeath_SprFlags[2] = {0x20, 0x10};
+static const uint8 kDeath_SprChar0[2] = {0xea, 0xec};
+static const uint8 kDeath_SprY0[3] = {0x7f, 0x8f, 0x9f};
+const uint8 kHealthAfterDeath[21] = {
+  0x18, 0x18, 0x18, 0x18, 0x18, 0x20, 0x20, 0x28, 0x28, 0x30, 0x30, 0x38, 0x38, 0x38, 0x40, 0x40,
+  0x40, 0x48, 0x48, 0x48, 0x50,
+};
+static PlayerHandlerFunc *const kModule_Death[16] = {
+  &GameOver_AdvanceImmediately,
+  &Death_Func1,
+  &GameOver_DelayBeforeIris,
+  &GameOver_IrisWipe,
+  &Death_Func4,
+  &GameOver_SplatAndFade,
+  &Death_Func6,
+  &Animate_GAMEOVER_Letters_bounce,
+  &GameOver_Finalize_GAMEOVR,
+  &GameOver_SaveAndOrContinue,
+  &GameOver_InitializeRevivalFairy,
+  &RevivalFairy_Main_bounce,
+  &GameOver_RiseALittle,
+  &GameOver_Restore0D,
+  &GameOver_Restore0E,
+  &GameOver_ResituateLink,
+};
+static const uint8 kLocationMenuStartPos[3] = {0, 1, 6};
+static void RunInterface();
+const uint8 *GetDungmapFloorLayout() {
+  return kDungMap_FloorLayout(cur_palace_index_x2 >> 1).ptr;
+}
+
+uint8 GetOtherDungmapInfo(int count) {
+  const uint8 *p = kDungMap_Tiles(cur_palace_index_x2 >> 1).ptr;
+  return p[count];
+}
+
+void DungMap_4() {
+  BG2VOFS_copy2 += dungmap_var4;
+  dungmap_var5 -= dungmap_var4;
+  if (!--bottle_menu_expand_row)
+    overworld_map_state--;
+}
+
+void Module_Messaging_6() {
+  assert(0);
+}
+
+void OverworldMap_SetupHdma() {
+  static const uint32 kOverworldMap_TableLow[2] = {0xabdcf, 0xabdd6};
+  uint32 a = kOverworldMap_TableLow[overworld_map_flags];
+  HdmaSetup(a, a, 0x42, (uint8)M7A, (uint8)M7D, 10);
+}
+
+const uint8 *GetLightOverworldTilemap() {
+  return kLightOverworldTilemap;
+}
+
+void SaveGameFile() {  // 80894a
+  int offs = ((srm_var1 >> 1) - 1) * 0x500;
+  memcpy(g_zenv.sram + offs, save_dung_info, 0x500);
+  memcpy(g_zenv.sram + offs + 0xf00, save_dung_info, 0x500);
+  uint16 t = 0x5a5a;
+  for (int i = 0; i < 0x4fe; i += 2)
+    t -= *(uint16 *)((char *)save_dung_info + i);
+  word_7EF4FE = t;
+  WORD(g_zenv.sram[offs + 0x4fe]) = t;
+  WORD(g_zenv.sram[offs + 0x4fe + 0xf00]) = t;
+  ZeldaWriteSram();
+}
+
+void TransferMode7Characters() {  // 80e399
+  uint16 *dst = g_zenv.vram;
+  const uint8 *src = kOverworldMapGfx;
+  for (int i = 0; i != 0x4000; i++)
+    HIBYTE(dst[i]) = src[i];
+}
+
+void Module0E_Interface() {  // 80f800
+  bool skip_run = false;
+  if (player_is_indoors) {
+    if (submodule_index == 3) {
+      skip_run = (overworld_map_state != 0 && overworld_map_state != 7);
+    } else {
+      Dungeon_PushBlock_Handler();
+    }
+  } else {
+    skip_run = ((submodule_index == 7 || submodule_index == 10) && overworld_map_state);
+  }
+  if (!skip_run) {
+    Sprite_Main();
+    LinkOam_Main();
+    if (!player_is_indoors)
+      OverworldOverlay_HandleRain();
+    Hud_RefillLogic();
+    if (submodule_index != 2)
+      OrientLampLightCone();
+  }
+  RunInterface();
+  BG2HOFS_copy = BG2HOFS_copy2 + bg1_x_offset;
+  BG2VOFS_copy = BG2VOFS_copy2 + bg1_y_offset;
+  BG1HOFS_copy = BG1HOFS_copy2 + bg1_x_offset;
+  BG1VOFS_copy = BG1VOFS_copy2 + bg1_y_offset;
+}
+
+void Module_Messaging_0() {  // 80f875
+  assert(0);
+}
+
+static void RunInterface() {  // 80f89a
+  kMessagingSubmodules[submodule_index]();
+}
+
+void Module0E_05_DesertPrayer() {  // 80f8b1
+  switch (subsubmodule_index) {
+  case 0: ResetTransitionPropsAndAdvance_ResetInterface(); break;
+  case 1: ApplyPaletteFilter_bounce(); break;
+  case 2:
+    DesertPrayer_InitializeIrisHDMA();
+    BYTE(palette_filter_countdown) = mosaic_target_level - 1;
+    mosaic_target_level = 0;
+    BYTE(darkening_or_lightening_screen) = 2;
+    break;
+  case 3:
+    ApplyPaletteFilter_bounce();
+    // fall through
+  case 4:
+    DesertPrayer_BuildIrisHDMATable();
+    break;
+  }
+}
+
+void Module0E_04_RedPotion() {  // 80f8fb
+  if (Hud_RefillHealth()) {
+    button_mask_b_y &= ~0x40;
+    flag_update_hud_in_nmi++;
+    submodule_index = 0;
+    main_module_index = saved_module_for_menu;
+  }
+}
+
+void Module0E_08_GreenPotion() {  // 80f911
+  if (Hud_RefillMagicPower()) {
+    button_mask_b_y &= ~0x40;
+    flag_update_hud_in_nmi++;
+    submodule_index = 0;
+    main_module_index = saved_module_for_menu;
+  }
+}
+
+void Module0E_09_BluePotion() {  // 80f918
+  if (Hud_RefillHealth())
+    submodule_index = 8;
+  if (Hud_RefillMagicPower())
+    submodule_index = 4;
+}
+
+void Module0E_0B_SaveMenu() {  // 80f9fa
+  // This is the continue / save and quit menu
+  if (!player_is_indoors)
+    Overworld_DwDeathMountainPaletteAnimation();
+  RenderText();
+  flag_update_hud_in_nmi = 0;
+  nmi_disable_core_updates = 0;
+  if (subsubmodule_index < 3)
+    subsubmodule_index++;
+  else
+    nmi_load_bg_from_vram = 0;
+  if (!submodule_index) {
+    subsubmodule_index = 0;
+    nmi_load_bg_from_vram = 1;
+    if (choice_in_multiselect_box) {
+      sound_effect_ambient = 15;
+      main_module_index = 23;
+      submodule_index = 1;
+      index_of_changable_dungeon_objs[0] = 0;
+      index_of_changable_dungeon_objs[1] = 0;
+    } else {
+      choice_in_multiselect_box = choice_in_multiselect_box_bak;
+    }
+  }
+}
+
+void Module1B_SpawnSelect() {  // 828586
+  RenderText();
+  if (submodule_index)
+    return;
+  nmi_load_bg_from_vram = 0;
+  EnableForceBlank();
+  EraseTileMaps_normal();
+  uint8 bak = which_starting_point;
+  which_starting_point = kLocationMenuStartPos[choice_in_multiselect_box];
+  subsubmodule_index = 0;
+  LoadDungeonRoomRebuildHUD();
+  which_starting_point = bak;
+}
+
+void CleanUpAndPrepDesertPrayerHDMA() {  // 82c7b8
+  HdmaSetup(0, 0x2c80c, 0x41, 0, (uint8)WH0, 0);
+
+  W12SEL_copy = 0x33;
+  W34SEL_copy = 3;
+  WOBJSEL_copy = 0x33;
+  TMW_copy = TM_copy;
+  TSW_copy = TS_copy;
+  HDMAEN_copy = 0x80;
+  memset(hdma_table_dynamic, 0, 240 * sizeof(uint16));
+}
+
+void DesertPrayer_InitializeIrisHDMA() {  // 87ea06
+  CleanUpAndPrepDesertPrayerHDMA();
+  spotlight_var1 = 0x26;
+  BYTE(spotlight_var2) = 0;
+  DesertPrayer_BuildIrisHDMATable();
+  subsubmodule_index++;
+}
+
+void DesertPrayer_BuildIrisHDMATable() {  // 87ea27
+  uint16 r14 = link_y_coord - BG2VOFS_copy2 + 12;
+  spotlight_y_lower = r14 - spotlight_var1;
+  uint16 r4 = sign16(spotlight_y_lower) ? spotlight_y_lower : 0;
+  uint16 k;
+  spotlight_y_upper = spotlight_y_lower + spotlight_var1 * 2;
+  spotlight_var3 = link_x_coord - BG2HOFS_copy2 + 8;
+  spotlight_var4 = 1;
+  do {
+    uint16 r0 = 0x100, r2 = 0x100;
+    if (!(sign16(spotlight_y_lower) || (r4 >= spotlight_y_lower && r4 < spotlight_y_upper))) {
+      k = (r4 - 1);
+    } else if (spotlight_var1 < spotlight_var4) {
+      spotlight_var4 = 1;
+      spotlight_y_lower = 0;
+      r4 = spotlight_y_upper;
+      if (r4 >= 225)
+        break;
+      k = (r4 - 1);
+    } else {
+      Pair16U pair = DesertHDMA_CalculateIrisShapeLine();
+      if (pair.a == 0) {
+        spotlight_y_lower = 0;
+      } else {
+        r2 = spotlight_var3 + pair.b;
+        r0 = spotlight_var3 - pair.b;
+      }
+      k = (r14 - BYTE(spotlight_var4) - 1);
+    }
+    uint8 t6 = (r0 < 256) ? r0 : (r0 < 512) ? 255 : 0;
+    uint8 t7 = (r2 < 256) ? r2 : 255;
+    uint16 r6 = t7 << 8 | t6;
+    if (k < 240)
+     hdma_table_dynamic[k] = (r6 == 0xffff) ? 0xff : r6;
+    if (sign16(spotlight_y_lower) || (r4 >= spotlight_y_lower && r4 < spotlight_y_upper)) {
+      k = BYTE(spotlight_var4) - 2 + r14;
+      if (k < 240)
+        hdma_table_dynamic[k] = (r6 == 0xffff) ? 0xff : r6;
+      spotlight_var4++;
+    }
+    r4++;
+  } while (sign16(r4) || r4 < 225);
+
+  if (subsubmodule_index != 4)
+    return;
+  if (BYTE(spotlight_var2) != 1 && (filtered_joypad_H | filtered_joypad_L) & 0xc0) {
+    BYTE(spotlight_var2) = 1;
+    BYTE(spotlight_var1) >>= 1;
+  }
+  if (BYTE(spotlight_var2) && (BYTE(spotlight_var1) += 8) >= 0xc0) {
+    byte_7E02F0 ^= 1;
+    music_control = 0xf3;
+    sound_effect_ambient = 0;
+    flag_unk1 = 0;
+    some_animation_timer_steps = 0;
+    button_mask_b_y = 0;
+    link_state_bits = 0;
+    link_cant_change_direction &= ~1;
+    subsubmodule_index = 0;
+    submodule_index = 0;
+    main_module_index = saved_module_for_menu;
+    TMW_copy = 0;
+    TSW_copy = 0;
+    W12SEL_copy = 0;
+    W34SEL_copy = 0;
+    WOBJSEL_copy = 0;
+    IrisSpotlight_ResetTable();
+  } else {
+    static const uint8 kPrayingScene_Delays[5] = {22, 22, 22, 64, 1};
+    if (sign8(--link_delay_timer_spin_attack)) {
+      int i = some_animation_timer_steps + 1;
+      if (i != 4)
+        some_animation_timer_steps = i;
+      link_delay_timer_spin_attack = kPrayingScene_Delays[i];
+    }
+  }
+}
+
+Pair16U DesertHDMA_CalculateIrisShapeLine() {  // 87ecdc
+  static const uint8 kPrayingScene_Tab1[129] = {
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xfe, 0xfe, 0xfe,
+    0xfd, 0xfd, 0xfd, 0xfd, 0xfc, 0xfc, 0xfc, 0xfb, 0xfb, 0xfb, 0xfa, 0xfa, 0xf9, 0xf9, 0xf8, 0xf8,
+    0xf7, 0xf7, 0xf6, 0xf6, 0xf5, 0xf5, 0xf4, 0xf3, 0xf3, 0xf2, 0xf1, 0xf1, 0xf0, 0xef, 0xee, 0xee,
+    0xed, 0xec, 0xeb, 0xea, 0xe9, 0xe9, 0xe8, 0xe7, 0xe6, 0xe5, 0xe4, 0xe3, 0xe2, 0xe1, 0xdf, 0xde,
+    0xdd, 0xdc, 0xdb, 0xda, 0xd8, 0xd7, 0xd6, 0xd5, 0xd3, 0xd2, 0xd0, 0xcf, 0xcd, 0xcc, 0xca, 0xc9,
+    0xc7, 0xc6, 0xc4, 0xc2, 0xc1, 0xbf, 0xbd, 0xbb, 0xb9, 0xb7, 0xb6, 0xb4, 0xb1, 0xaf, 0xad, 0xab,
+    0xa9, 0xa7, 0xa4, 0xa2, 0x9f, 0x9d, 0x9a, 0x97, 0x95, 0x92, 0x8f, 0x8c, 0x89, 0x86, 0x82, 0x7f,
+    0x7b, 0x78, 0x74, 0x70, 0x6c, 0x67, 0x63, 0x5e, 0x59, 0x53, 0x4d, 0x46, 0x3f, 0x37, 0x2d, 0x1f,
+    0,
+  };
+  static const uint8 kPrayingScene_Tab0[129] = {
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xfe, 0xfd, 0xfd, 0xfc, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8,
+    0xf7, 0xf6, 0xf5, 0xf4, 0xf3, 0xf1, 0xf0, 0xee, 0xed, 0xeb, 0xe9, 0xe8, 0xe6, 0xe4, 0xe2, 0xdf,
+    0xdd, 0xdb, 0xd8, 0xd6, 0xd3, 0xd0, 0xcd, 0xca, 0xc7, 0xc4, 0xc1, 0xbd, 0xb9, 0xb6, 0xb1, 0xad,
+    0xa9, 0xa4, 0x9f, 0x9a, 0x95, 0x8f, 0x89, 0x82, 0x7b, 0x74, 0x6c, 0x63, 0x59, 0x4d, 0x3f, 0x2d,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,
+  };
+  uint8 t = snes_divide(BYTE(spotlight_var4) << 8, BYTE(spotlight_var1)) >> 1;
+  uint8 r6 = BYTE(spotlight_var2) ? kPrayingScene_Tab1[t] : kPrayingScene_Tab0[t];
+  uint16 r8 = r6 * BYTE(spotlight_var1) >> 8;
+  if (BYTE(spotlight_var2))
+    r8 <<= 1;
+  Pair16U ret = { r6, r8 };
+  return ret;
+}
+
+void Animate_GAMEOVER_Letters() {  // 88f4ca
+  switch (ancilla_type[0]) {
+  case 0:
+    submodule_index++;
+    break;
+  case 1:
+    GameOverText_SweepLeft();
+    break;
+  case 2:
+    GameOverText_UnfurlRight();
+    break;
+  case 3:
+    GameOverText_Draw();
+    break;
+  }
+}
+
+void GameOverText_SweepLeft() {  // 88f4f6
+  static const uint8 kGameOverText_Tab1[8] = {0x40, 0x50, 0x60, 0x70, 0x88, 0x98, 0xa8, 0x40};
+
+  int k = flag_for_boomerang_in_place;
+  cur_object_index = k;
+  ancilla_x_vel[k] = 0x80;
+  Ancilla_MoveX(k);
+  if (Ancilla_GetX(k) < kGameOverText_Tab1[k]) {
+    ancilla_x_lo[k] = kGameOverText_Tab1[k];
+    flag_for_boomerang_in_place = ++k;
+    if (k == 8) {
+      flag_for_boomerang_in_place = 7;
+      ancilla_type[0]++;
+      hookshot_effect_index = 0;
+      sound_effect_2 = 38;
+      goto draw;
+    }
+  }
+  if (k == 7) {
+    int j = 6;
+    while (j != hookshot_effect_index)
+      ancilla_x_lo[j--] = ancilla_x_lo[k];
+    if (Ancilla_GetX(k) < kGameOverText_Tab1[hookshot_effect_index])
+      hookshot_effect_index--;
+  }
+draw:
+  GameOverText_Draw();
+}
+
+void GameOverText_UnfurlRight() {  // 88f56d
+  static const uint8 kGameOverText_Tab2[8] = {0x58, 0x60, 0x68, 0x70, 0x88, 0x90, 0x98, 0xa0};
+
+  int k = flag_for_boomerang_in_place, end;
+  cur_object_index = k;
+  ancilla_x_vel[k] = 0x60;
+  Ancilla_MoveX(k);
+  int j = hookshot_effect_index;
+  if (ancilla_x_lo[k] >= kGameOverText_Tab2[j]) {
+    ancilla_x_lo[j] = kGameOverText_Tab2[j];
+    if (++hookshot_effect_index == 8) {
+      submodule_index++;
+      ancilla_type[0]++;
+      goto draw;
+    }
+  }
+  end = hookshot_effect_index - 1;
+  k = flag_for_boomerang_in_place;
+  j = k;
+  do {
+    ancilla_x_lo[j] = ancilla_x_lo[k];
+  } while (--j != end);
+draw:
+  GameOverText_Draw();
+}
+
+void Module12_GameOver() {  // 89f290
+  kModule_Death[submodule_index]();
+  if (submodule_index != 9)
+    LinkOam_Main();
+}
+
+void GameOver_AdvanceImmediately() {  // 89f2a2
+  submodule_index++;
+  Death_Func1();
+}
+
+void Death_Func1() {  // 89f2a4
+  music_unk1_death = music_unk1;
+  sound_effect_ambient_last_death = sound_effect_ambient_last;
+  music_control = 241;
+  sound_effect_ambient = 5;
+  overworld_map_state = 5;
+  link_on_conveyor_belt = 0;
+  byte_7E0322 = 0;
+  link_cape_mode = 0;
+  mapbak_bg1_x_offset = palette_filter_countdown;
+  mapbak_bg1_y_offset = darkening_or_lightening_screen;
+  memcpy(mapbak_palette, aux_palette_buffer, 256);
+  memset(aux_palette_buffer + 32, 0, 192);
+  palette_filter_countdown = 0;
+  darkening_or_lightening_screen = 0;
+  bg1_x_offset = 0;
+  bg1_y_offset = 0;
+  mapbak_CGWSEL = WORD(CGWSEL_copy);
+  some_menu_ctr = 32;
+  hud_floor_changed_timer = 0;
+  Hud_FloorIndicator();
+  flag_update_hud_in_nmi++;
+  sound_effect_ambient = 5;
+  submodule_index++;
+}
+
+void GameOver_DelayBeforeIris() {  // 89f33b
+  if (--some_menu_ctr)
+    return;
+  Death_InitializeGameOverLetters();
+  IrisSpotlight_close();
+  WOBJSEL_copy = 0x30;
+  W34SEL_copy = 0;
+  submodule_index++;
+}
+
+void GameOver_IrisWipe() {  // 89f350
+  PaletteFilter_RestoreBGSubstractiveStrict();
+  main_palette_buffer[0] = main_palette_buffer[32];
+  uint8 bak = main_module_index;
+  IrisSpotlight_ConfigureTable();
+  main_module_index = bak;
+  if (submodule_index)
+    return;
+  for (int i = 0; i < 16; i++) {
+    main_palette_buffer[0x20 + i] = 0x18;
+    main_palette_buffer[0x30 + i] = 0x18;
+    main_palette_buffer[0x40 + i] = 0x18;
+    main_palette_buffer[0x50 + i] = 0x18;
+    main_palette_buffer[0x60 + i] = 0x18;
+    main_palette_buffer[0x70 + i] = 0x18;
+  }
+  main_palette_buffer[0] = main_palette_buffer[32] = 0x18;
+
+  IrisSpotlight_ResetTable();
+  COLDATA_copy0 = 32;
+  COLDATA_copy1 = 64;
+  COLDATA_copy2 = 128;
+  W12SEL_copy = 0;
+  W34SEL_copy = 0;
+  WOBJSEL_copy = 0;
+  submodule_index = 4;
+  flag_update_cgram_in_nmi++;
+  INIDISP_copy = 15;
+  TM_copy = 20;
+  TS_copy = 0;
+  CGADSUB_copy = 32;
+  some_menu_ctr = 64;
+  BYTE(palette_filter_countdown) = 0;
+  BYTE(darkening_or_lightening_screen) = 0;
+  Death_PrepFaint();
+}
+
+void GameOver_SplatAndFade() {  // 89f3de
+  if (some_menu_ctr) {
+    some_menu_ctr--;
+    return;
+  }
+  PaletteFilter_RestoreBGSubstractiveStrict();
+  main_palette_buffer[0] = main_palette_buffer[32];
+  if (BYTE(darkening_or_lightening_screen) != 0xff)
+    return;
+  mosaic_level = 0;
+  mosaic_inc_or_dec = 0;
+  MOSAIC_copy = 3;
+
+  for (int i = 0; i != 4; i++) {
+    if (link_bottle_info[i] == 6) {
+      link_bottle_info[i] = 2;
+      some_menu_ctr = 12;
+      load_chr_halfslot_even_odd = 15;
+      Graphics_LoadChrHalfSlot();
+      load_chr_halfslot_even_odd = 0;
+      submodule_index = 10;
+      return;
+    }
+  }
+  index_of_changable_dungeon_objs[0] = 0;
+  index_of_changable_dungeon_objs[1] = 0;
+  nmi_subroutine_index = 22;
+  nmi_disable_core_updates = 22;
+  submodule_index++;
+}
+
+void Death_Func6() {  // 89f458
+  some_menu_ctr = 12;
+  load_chr_halfslot_even_odd = 15;
+  Graphics_LoadChrHalfSlot();
+  load_chr_halfslot_even_odd = 0;
+  palette_sp6r_indoors = 5;
+  overworld_palette_aux_or_main = 0x200;
+  Palette_Load_SpriteEnvironment_Dungeon();
+  Palette_Load_SpriteMain();
+  flag_update_cgram_in_nmi++;
+  submodule_index++;
+  Death_PlayerSwoon();
+}
+
+void Death_Func4() {  // 89f47e
+  Death_PlayerSwoon();
+}
+
+void Animate_GAMEOVER_Letters_bounce() {  // 89f483
+  Animate_GAMEOVER_Letters();
+}
+
+void GameOver_Finalize_GAMEOVR() {  // 89f488
+  Animate_GAMEOVER_Letters();
+  uint8 bak1 = main_module_index;
+  uint8 bak2 = submodule_index;
+  messaging_module = 2;
+  RenderText();
+  submodule_index = bak2 + 1;
+  main_module_index = bak1;
+  some_menu_ctr = 2;
+  music_control = 11;
+}
+
+void GameOver_SaveAndOrContinue() {  // 89f4c1
+  GameOver_AnimateChoiceFairy();
+  if (ancilla_type)
+    Animate_GAMEOVER_Letters();
+
+  if (filtered_joypad_H & 0x20)
+    goto do_inc;
+
+  if (!--some_menu_ctr) {
+    some_menu_ctr = 1;
+    if (joypad1H_last & 12) {
+      if (joypad1H_last & 4) {
+do_inc:
+        if (++subsubmodule_index >= 3)
+          subsubmodule_index = 0;
+      } else {
+        if (sign8(--subsubmodule_index))
+          subsubmodule_index = 2;
+      }
+      some_menu_ctr = 12;
+      sound_effect_2 = 32;
+    }
+  }
+  if (!((filtered_joypad_L & 0xc0 | filtered_joypad_H) & 0xd0))
+    return;
+  sound_effect_1 = 44;
+  // Only death with save/continue or save/quit counts as a death
+  Death_Func15(subsubmodule_index != 2);
+}
+
+void Death_Func15(bool count_as_death) {  // 89f50f
+  music_control = 0xf1;
+  if (player_is_indoors)
+    Dungeon_FlagRoomData_Quadrants();
+  AdjustLinkBunnyStatus();
+  if (sram_progress_indicator < 3) {
+    savegame_is_darkworld = 0;
+    if (!link_item_moon_pearl)
+      ForceNonbunnyStatus();
+  }
+  if (dungeon_room_index == 0)
+    player_is_indoors = 0;
+
+  ResetSomeThingsAfterDeath((uint8)dungeon_room_index);
+  if (follower_indicator == 6 || follower_indicator == 9 || follower_indicator == 10 || follower_indicator == 13)
+    follower_indicator = 0;
+
+  death_var4 = link_health_current = kHealthAfterDeath[link_health_capacity >> 3];
+  uint8 i = BYTE(cur_palace_index_x2);
+  if (i != 0xff)
+    link_keys_earned_per_dungeon[(i == 2 ? 0 : i) >> 1] = link_num_keys;
+  Sprite_ResetAll();
+  if (death_var2 == 0xffff && (!(enhanced_features0 & kFeatures0_MiscBugFixes) || count_as_death))
+    death_save_counter++;
+  death_var5++;
+  if (subsubmodule_index != 1) {
+    if (!player_is_indoors)
+      goto outdoors;
+
+    if (follower_indicator != 1 && BYTE(cur_palace_index_x2) != 255) {
+      death_var4 = 0;
+    } else {
+      queued_music_control = 0;
+      player_is_indoors = 0;
+    outdoors:
+      if (savegame_is_darkworld)
+        dungeon_room_index = 32;
+    }
+
+    if (sram_progress_indicator) {
+      if (subsubmodule_index == 0)
+        SaveGameFile();
+      main_module_index = 5;
+      submodule_index = 0;
+      nmi_load_bg_from_vram = 0;
+    } else {
+      uint8 slot = srm_var1;
+      int offs = kSrmOffsets[(slot >> 1) - 1];
+      WORD(g_ram[0]) = offs;
+      death_var5 = 0;
+      CopySaveToWRAM();
+    }
+  } else {
+    if (sram_progress_indicator)
+      SaveGameFile();
+    TM_copy = 16;
+    player_is_indoors = 0;
+    Death_Func31();
+    death_var4 = 0;
+    death_var5 = 0;
+    queued_music_control = 0;
+    BG1HOFS_copy2 = 0;
+    BG2HOFS_copy2 = 0;
+    BG3HOFS_copy2 = 0;
+    BG1VOFS_copy2 = 0;
+    BG2VOFS_copy2 = 0;
+    BG3VOFS_copy2 = 0;
+    BG1HOFS_copy = 0;
+    BG2HOFS_copy = 0;
+    BG1VOFS_copy = 0;
+    BG2VOFS_copy = 0;
+    memset(save_dung_info, 0, 256 * 5);
+    flag_which_music_type = 0;
+    LoadOverworldSongs();
+  }
+}
+
+void GameOver_AnimateChoiceFairy() {  // 89f67a
+  SetOamPlain(&oam_buf[0x14], 0x34, kDeath_SprY0[subsubmodule_index], kDeath_SprChar0[frame_counter >> 3 & 1], 0x78, 2);
+}
+
+void GameOver_InitializeRevivalFairy() {  // 89f6a4
+  ConfigureRevivalAncillae();
+  link_hearts_filler = 56;
+  submodule_index += 1;
+  overworld_map_state = 0;
+}
+
+void RevivalFairy_Main_bounce() {  // 89f6b4
+  RevivalFairy_Main();
+}
+
+void GameOver_RiseALittle() {  // 89f6b9
+  if (link_hearts_filler == 0) {
+    memcpy(aux_palette_buffer, mapbak_palette, 256);
+    memset(main_palette_buffer + 32, 0, 192);
+    main_palette_buffer[0] = 0;
+    palette_filter_countdown = 0;
+    darkening_or_lightening_screen = 2;
+    WORD(CGWSEL_copy) = mapbak_CGWSEL;
+    submodule_index++;
+  }
+  RevivalFairy_Main();
+  Hud_RefillLogic();
+}
+
+void GameOver_Restore0D() {  // 89f71d
+  if (!is_doing_heart_animation) {
+    load_chr_halfslot_even_odd = 1;
+    Graphics_LoadChrHalfSlot();
+    Dungeon_ApproachFixedColor_variable(overworld_fixed_color_plusminus);
+    submodule_index++;
+  }
+  RevivalFairy_Main();
+  Hud_RefillLogic();
+}
+
+void GameOver_Restore0E() {  // 89f735
+  Graphics_LoadChrHalfSlot();
+  TS_copy = mapbak_TS;
+  submodule_index++;
+}
+
+void GameOver_ResituateLink() {  // 89f742
+  PaletteFilter_RestoreBGAdditiveStrict();
+  main_palette_buffer[0] = main_palette_buffer[32];
+  if (BYTE(palette_filter_countdown) != 32)
+    return;
+  if (!player_is_indoors)
+    Overworld_SetFixedColAndScroll();
+  TS_copy = mapbak_TS;
+  main_module_index = saved_module_for_menu;
+  submodule_index = 0;
+  countdown_for_blink = 144;
+  music_control = music_unk1_death;
+  sound_effect_ambient = sound_effect_ambient_last_death;
+  palette_filter_countdown = mapbak_bg1_x_offset;
+  darkening_or_lightening_screen = mapbak_bg1_y_offset;
+}
+
+void Module0E_0A_FluteMenu() {  // 8ab730
+  switch (overworld_map_state) {
+  case 0:
+    WorldMap_FadeOut();
+    break;
+  case 1:
+    birdtravel_var1[0] = 0;
+    WorldMap_LoadLightWorldMap();
+    break;
+  case 2:
+    WorldMap_LoadSpriteGFX();
+    break;
+  case 3:
+    WorldMap_Brighten();
+    break;
+  case 4:
+    some_menu_ctr = 0x10;
+    overworld_map_state++;
+    break;
+  case 5:
+    FluteMenu_HandleSelection();
+    break;
+  case 6:
+    WorldMap_RestoreGraphics();
+    break;
+  case 7:
+    FluteMenu_LoadSelectedScreen();
+    break;
+  case 8:
+    Overworld_LoadOverlayAndMap();
+    break;
+  case 9:
+    FluteMenu_FadeInAndQuack();
+    break;
+  default:
+    assert(0);
+  }
+}
+
+void FluteMenu_HandleSelection() {  // 8ab78b
+  Point16U pt;
+
+  if (some_menu_ctr == 0) {
+    if ((joypad1L_last | joypad1H_last) & 0xc0) {
+
+      if (enhanced_features0 & kFeatures0_CancelBirdTravel)
+        some_menu_ctr = joypad1L_last;
+
+      overworld_map_state++;
+      return;
+    }
+  } else {
+    some_menu_ctr--;
+  }
+  if (filtered_joypad_H & 10) {
+    birdtravel_var1[0]--;
+    sound_effect_2 = 32;
+  }
+  if (filtered_joypad_H & 5) {
+    birdtravel_var1[0]++;
+    sound_effect_2 = 32;
+  }
+  birdtravel_var1[0] = birdtravel_var1[0] & 7;
+  if (frame_counter & 0x10 && WorldMap_CalculateOamCoordinates(&pt))
+    WorldMap_AddSprite(16, 2, 0x3e, 0, pt.x - 4, pt.y - 4);
+
+  uint16 ybak = link_y_coord_spexit;
+  uint16 xbak = link_x_coord_spexit;
+  for (int i = 7; i >= 0; i--) {
+    bird_travel_x_lo[i] = kBirdTravel_x_lo[i];
+    bird_travel_x_hi[i] = kBirdTravel_x_hi[i];
+    link_x_coord_spexit = kBirdTravel_x_hi[i] << 8 | kBirdTravel_x_lo[i];
+
+    bird_travel_y_lo[i] = kBirdTravel_y_lo[i];
+    bird_travel_y_hi[i] = kBirdTravel_y_hi[i];
+    link_y_coord_spexit = kBirdTravel_y_hi[i] << 8 | kBirdTravel_y_lo[i];
+
+    if (WorldMap_CalculateOamCoordinates(&pt))
+      WorldMap_AddSprite(i, 0, (i == birdtravel_var1[0]) ? 0x30 + (frame_counter & 6) : 0x32, kBirdTravel_tab1[i], pt.x, pt.y);
+  }
+  link_x_coord_spexit = xbak;
+  link_y_coord_spexit = ybak;
+}
+
+void FluteMenu_LoadSelectedScreen() {  // 8ab8c5
+  save_ow_event_info[0x3b] &= ~0x20;
+  save_ow_event_info[0x7b] &= ~0x20;
+  save_dung_info[267] &= ~0x80;
+  save_dung_info[40] &= ~0x100;
+
+  // This is kFeatures0_CancelBirdTravel
+  if (!(some_menu_ctr & 0x40))
+    FluteMenu_LoadTransport();
+
+  FluteMenu_LoadSelectedScreenPalettes();
+  uint8 t = overworld_screen_index & 0xbf;
+  DecompressAnimatedOverworldTiles((t == 3 || t == 5 || t == 7) ? 0x58 : 0x5a);
+  Overworld_SetFixedColAndScroll();
+  overworld_palette_aux_or_main = 0;
+  hud_palette = 0;
+  InitializeTilesets();
+  overworld_map_state++;
+  BYTE(dung_draw_width_indicator) = 0;
+  Overworld_LoadOverlays2();
+  submodule_index--;
+  sound_effect_2 = 16;
+  uint8 m = overworld_music[BYTE(overworld_screen_index)];
+  sound_effect_ambient = m >> 4;
+  music_control = ZeldaIsPlayingMusicTrack(m & 0xf) ? 0xf3 : m & 0xf;
+}
+
+void Overworld_LoadOverlayAndMap() {  // 8ab948
+  uint16 bak1 = WORD(main_module_index);
+  uint16 bak2 = WORD(overworld_map_state);
+  Overworld_LoadAndBuildScreen();
+  WORD(overworld_map_state) = bak2 + 1;
+  WORD(main_module_index) = bak1;
+}
+
+void FluteMenu_FadeInAndQuack() {  // 8ab964
+  if (++INIDISP_copy == 15) {
+    BirdTravel_Finish_Doit();
+  } else {
+    Sprite_Main();
+  }
+}
+
+void BirdTravel_Finish_Doit() {  // 8ab96c
+  overworld_map_state = 0;
+  subsubmodule_index = 0;
+  main_module_index = saved_module_for_menu;
+  submodule_index = 0;
+  HDMAEN_copy = mapbak_HDMAEN;
+  AddBirdTravelSomething(0x27, 4);
+  Sprite_Main();
+}
+
+void Messaging_OverworldMap() {  // 8ab98b
+  switch (overworld_map_state) {
+  case 0:
+    WorldMap_FadeOut();
+    break;
+  case 1:
+    WorldMap_LoadLightWorldMap();
+    break;
+  case 2:
+    WorldMap_LoadDarkWorldMap();
+    break;
+  case 3:
+    WorldMap_LoadSpriteGFX();
+    break;
+  case 4:
+    WorldMap_Brighten();
+    break;
+  case 5:
+    WorldMap_PlayerControl();
+    break;
+  case 6:
+    WorldMap_RestoreGraphics();
+    break;
+  case 7:
+    WorldMap_ExitMap();
+    break;
+  }
+}
+
+void WorldMap_FadeOut() {  // 8ab9a3
+  if (--INIDISP_copy)
+    return;
+  mapbak_HDMAEN = HDMAEN_copy;
+  EnableForceBlank();
+  MOSAIC_copy = 3;
+  overworld_map_state++;
+  WORD(mapbak_TM) = WORD(TM_copy);
+  mapbak_BG1HOFS_copy2 = BG1HOFS_copy2;
+  mapbak_BG2HOFS_copy2 = BG2HOFS_copy2;
+  mapbak_BG1VOFS_copy2 = BG1VOFS_copy2;
+  mapbak_BG2VOFS_copy2 = BG2VOFS_copy2;
+  BG1HOFS_copy2 = BG2HOFS_copy2 = BG3HOFS_copy2 = 0;
+  BG1VOFS_copy2 = BG2VOFS_copy2 = BG3VOFS_copy2 = 0;
+  WORD(mapbak_CGWSEL) = WORD(CGWSEL_copy);
+  link_dma_graphics_index = 0x1fc;
+  if (BYTE(overworld_screen_index) < 0x80) {
+    link_y_coord_spexit = link_y_coord;
+    link_x_coord_spexit = link_x_coord;
+  }
+  if (sram_progress_indicator < 2) {
+    CGWSEL_copy = 0x80;
+    CGADSUB_copy = 0x61;
+  }
+  sound_effect_2 = 16;
+  sound_effect_ambient = 5;
+  music_control = 0xf2;
+  BGMODE_copy = 7;
+}
+
+void WorldMap_LoadLightWorldMap() {  // 8aba30
+  WorldMap_FillTilemapWithEF();
+  TM_copy = 0x11;
+  TS_copy = 0;
+  TransferMode7Characters();
+  WorldMap_SetUpHDMA();
+  LoadOverworldMapPalette();
+  LoadActualGearPalettes();
+  flag_update_cgram_in_nmi++;
+  nmi_subroutine_index = 7;
+  INIDISP_copy = 0;
+  nmi_disable_core_updates++;
+  overworld_map_state++;
+}
+
+void WorldMap_LoadDarkWorldMap() {  // 8aba7a
+  if (overworld_screen_index & 0x40) {
+    memcpy(&uvram, kDarkOverworldTilemap, 1024);
+    nmi_subroutine_index = 21;
+  }
+  overworld_map_state++;
+}
+
+void WorldMap_LoadSpriteGFX() {  // 8aba9a
+  load_chr_halfslot_even_odd = 0x10;
+  Graphics_LoadChrHalfSlot();
+  load_chr_halfslot_even_odd = 0;
+  overworld_map_state++;
+}
+
+void WorldMap_Brighten() {  // 8abaaa
+  if (++INIDISP_copy == 15)
+    overworld_map_state++;
+}
+
+bool DidPressButtonForMap() {
+  if (hud_cur_item_x != 0)
+    return filtered_joypad_H & 0x20;  // select
+  else
+    return filtered_joypad_L & 0x40;  // x
+}
+
+void WorldMap_PlayerControl() {  // 8abae6
+  if (overworld_map_flags & 0x80) {
+    overworld_map_flags &= ~0x80;
+    OverworldMap_SetupHdma();
+  }
+
+  if (!overworld_map_flags && DidPressButtonForMap()) { // X
+    // getout
+    overworld_map_state++;
+    return;
+  }
+  if (BYTE(dung_draw_width_indicator)) {
+    BYTE(dung_draw_width_indicator)--;
+  } else if (filtered_joypad_L & 0x30 || DidPressButtonForMap()) {
+    // next zoom level
+    sound_effect_2 = 36;
+    BYTE(dung_draw_width_indicator) = 8;
+
+    int t = overworld_map_flags ^ 1;
+    overworld_map_flags = t | 0x80;
+    timer_for_mode7_zoom = kOverworldMap_Timer[t];
+    if (timer_for_mode7_zoom == 12) {
+      BG1VOFS_copy2 = ((link_y_coord_spexit >> 4) - 0x48 & ~1);
+      M7Y_copy = BG1VOFS_copy2 + 0x100;
+      uint16 t0 = (link_x_coord_spexit >> 4) - 0x80;
+      uint16 t1 = (uint16)(5 * (sign16(t0) ? -t0 : t0)) >> 1;
+      uint16 t2 = sign16(t0) ? -t1 : t1;
+      BG1HOFS_copy2 = t2 + 0x80 & ~1;
+    } else {
+      BG1VOFS_copy2 = 200;
+      M7Y_copy = 200 + 256;
+      BG1HOFS_copy2 = 128;
+    }
+  }
+
+  if (overworld_map_flags) {
+    int k = (joypad1H_last & 12) >> 1;
+    if (BG1VOFS_copy2 != (uint16)kOverworldMap_Table2[k]) {
+      BG1VOFS_copy2 += kOverworldMap_Table3[k];
+      M7Y_copy = BG1VOFS_copy2 + 0x100;
+    }
+    k = (joypad1H_last & 3) * 2 + 1;
+    if (BG1HOFS_copy2 != (uint16)kOverworldMap_Table2[k])
+      BG1HOFS_copy2 += kOverworldMap_Table3[k];
+  }
+  WorldMap_HandleSprites();
+}
+
+void WorldMap_RestoreGraphics() {  // 8abbd6
+  if (--INIDISP_copy)
+    return;
+  EnableForceBlank();
+  overworld_map_state++;
+  memcpy(main_palette_buffer, aux_palette_buffer, 512);
+  WORD(CGWSEL_copy) = WORD(mapbak_CGWSEL);
+  BG3HOFS_copy2 = BG3VOFS_copy2 = 0;
+  BG1HOFS_copy2 = mapbak_BG1HOFS_copy2;
+  BG2HOFS_copy2 = mapbak_BG2HOFS_copy2;
+  BG1VOFS_copy2 = mapbak_BG1VOFS_copy2;
+  BG2VOFS_copy2 = mapbak_BG2VOFS_copy2;
+  WORD(TM_copy) = WORD(mapbak_TM);
+  Attract_SetUpConclusionHDMA();
+}
+
+void Attract_SetUpConclusionHDMA() {  // 8abc33
+  HdmaSetup(0xABDDD, 0xABDDD, 0x42, (uint8)M7A, (uint8)M7D, 0);
+  HDMAEN_copy = 0x80;
+  BGMODE_copy = 9;
+  nmi_disable_core_updates = 0;
+}
+
+void WorldMap_ExitMap() {  // 8abc54
+  overworld_palette_aux_or_main = 0;
+  hud_palette = 0;
+  InitializeTilesets();
+  flag_update_cgram_in_nmi++;
+  BYTE(dung_draw_width_indicator) = 0;
+  overworld_map_state = 0;
+  subsubmodule_index = 0;
+  main_module_index = saved_module_for_menu;
+  submodule_index = 32;
+  vram_upload_offset = 0;
+  HDMAEN_copy = mapbak_HDMAEN;
+  sound_effect_ambient = overworld_music[BYTE(overworld_screen_index)] >> 4;
+  sound_effect_2 = 0x10;
+  music_control = 0xf3;
+}
+
+void WorldMap_SetUpHDMA() {  // 8abc96
+  BG1HOFS_copy2 = 0x80;
+  BG1VOFS_copy2 = 0xc8;
+  M7Y_copy = 0x1c9;
+  M7X_copy = 0x100;
+  W12SEL_copy = 0;
+  W34SEL_copy = 0;
+  WOBJSEL_copy = 0;
+  TMW_copy = 0;
+  TSW_copy = 0;
+
+  if (main_module_index == 20) {
+    HdmaSetup(0xABDDD, 0xABDDD, 0x42, (uint8)M7A, (uint8)M7D, 0);
+    HDMAEN_copy = 0xc0;
+  } else if (submodule_index != 10) {
+    byte_7E0635 = 4;
+    timer_for_mode7_zoom = 12;
+    overworld_map_flags = 1;
+    BG1VOFS_copy2 = ((link_y_coord_spexit >> 4) - 0x48 & ~1);
+    M7Y_copy = BG1VOFS_copy2 + 0x100;
+    uint16 t0 = (link_x_coord_spexit >> 4) - 0x80;
+    uint16 t1 = (uint16)(5 * (sign16(t0) ? -t0 : t0)) >> 1;
+    uint16 t2 = sign16(t0) ? -t1 : t1;
+    BG1HOFS_copy2 = t2 + 0x80 & ~1;
+    OverworldMap_SetupHdma();
+    HDMAEN_copy = 0xc0;
+  } else {
+    byte_7E0635 = 4;
+    timer_for_mode7_zoom = 33;
+    overworld_map_flags = 0;
+    HdmaSetup(0xABDCF, 0xABDCF, 0x42, (uint8)M7A, (uint8)M7D, 10);
+    HDMAEN_copy = 0xc0;
+  }
+}
+
+void WorldMap_FillTilemapWithEF() {  // 8abda5
+  uint16 *dst = g_zenv.vram;
+  for (int i = 0; i != 0x4000; i++)
+    BYTE(dst[i]) = 0xef;
+}
+
+void WorldMap_HandleSprites() {  // 8abf66
+  Point16U pt;
+
+  if (frame_counter & 0x10 && WorldMap_CalculateOamCoordinates(&pt))
+    WorldMap_AddSprite(0, 2, 0x3e, 0, pt.x - 4, pt.y - 4);
+
+  uint16 ybak = link_y_coord_spexit;
+  uint16 xbak = link_x_coord_spexit;
+
+  int k = 15;
+  if (BYTE(overworld_screen_index) < 0x40 && (bird_travel_x_lo[k] | bird_travel_x_hi[k] | bird_travel_y_lo[k] | bird_travel_y_hi[k])) {
+    if (!frame_counter)
+      birdtravel_var1[k]++;
+    link_x_coord_spexit = bird_travel_x_hi[k] << 8 | bird_travel_x_lo[k];
+    link_y_coord_spexit = bird_travel_y_hi[k] << 8 | bird_travel_y_lo[k];
+    if (WorldMap_CalculateOamCoordinates(&pt))
+      WorldMap_AddSprite(15, 2, kOverworldMap_Table4[frame_counter >> 1 & 3], 0x6a, pt.x, pt.y);
+  }
+
+  if (save_ow_event_info[0x5b] & 0x20 || (((savegame_map_icons_indicator >= 6) ^ is_in_dark_world) & 1))
+    goto out;
+
+  k = savegame_map_icons_indicator;
+
+  if (!OverworldMap_CheckForPendant(0) && !OverworldMap_CheckForCrystal(0) && !sign16(kOwMapCrystal0_x[k])) {
+    link_x_coord_spexit = kOwMapCrystal0_x[k];
+    link_y_coord_spexit = kOwMapCrystal0_y[k];
+    uint8 t = kOwMapCrystal0_tab[k] >> 8;
+    if (t != 0) {
+      if (t != 100 && frame_counter & 0x10)
+        goto endif_crystal0;
+      link_x_coord_spexit -= 4, link_y_coord_spexit -= 4;
+    }
+    if (WorldMap_CalculateOamCoordinates(&pt)) {
+      uint16 info = kOwMapCrystal0_tab[k];
+      uint8 ext = 2;
+      if (!(info >> 8))
+        info = kOwMap_tab2[frame_counter >> 3 & 3] << 8 | 0x32, ext = 0;
+      WorldMap_AddSprite(14, ext, (uint8)info, (uint8)(info >> 8), pt.x, pt.y);
+    }
+  endif_crystal0:;
+  }
+
+  if (!OverworldMap_CheckForPendant(1) && !OverworldMap_CheckForCrystal(1) && !sign16(kOwMapCrystal1_x[k])) {
+    link_x_coord_spexit = kOwMapCrystal1_x[k];
+    link_y_coord_spexit = kOwMapCrystal1_y[k];
+    uint8 t = kOwMapCrystal1_tab[k] >> 8;
+    if (t != 0) {
+      if (t != 100 && frame_counter & 0x10)
+        goto endif_crystal1;
+      link_x_coord_spexit -= 4, link_y_coord_spexit -= 4;
+    }
+    if (WorldMap_CalculateOamCoordinates(&pt)) {
+      uint16 info = kOwMapCrystal1_tab[k];
+      uint8 ext = 2;
+      if (!(info >> 8))
+        info = kOwMap_tab2[frame_counter >> 3 & 3] << 8 | 0x32, ext = 0;
+      WorldMap_AddSprite(13, ext, (uint8)info, (uint8)(info >> 8), pt.x, pt.y);
+    }
+  endif_crystal1:;
+  }
+
+  if (!OverworldMap_CheckForPendant(2) && !OverworldMap_CheckForCrystal(2) && !sign16(kOwMapCrystal2_x[k])) {
+    link_x_coord_spexit = kOwMapCrystal2_x[k];
+    link_y_coord_spexit = kOwMapCrystal2_y[k];
+    uint8 t = kOwMapCrystal2_tab[k] >> 8;
+    if (t != 0) {
+      if (t != 100 && frame_counter & 0x10)
+        goto endif_crystal2;
+      link_x_coord_spexit -= 4, link_y_coord_spexit -= 4;
+    }
+    if (WorldMap_CalculateOamCoordinates(&pt)) {
+      uint16 info = kOwMapCrystal2_tab[k];
+      uint8 ext = 2;
+      if (!(info >> 8))
+        info = kOwMap_tab2[frame_counter >> 3 & 3] << 8 | 0x32, ext = 0;
+      WorldMap_AddSprite(12, ext, (uint8)info, (uint8)(info >> 8), pt.x, pt.y);
+    }
+  endif_crystal2:;
+  }
+
+  if (!OverworldMap_CheckForCrystal(3) && !sign16(kOwMapCrystal3_x[k])) {
+    link_x_coord_spexit = kOwMapCrystal3_x[k];
+    link_y_coord_spexit = kOwMapCrystal3_y[k];
+    uint8 t = kOwMapCrystal3_tab[k] >> 8;
+    if (t != 0) {
+      if (t != 100 && frame_counter & 0x10)
+        goto endif_crystal3;
+      link_x_coord_spexit -= 4, link_y_coord_spexit -= 4;
+    }
+    if (WorldMap_CalculateOamCoordinates(&pt)) {
+      uint16 info = kOwMapCrystal3_tab[k];
+      uint8 ext = 2;
+      if (!(info >> 8))
+        info = kOwMap_tab2[frame_counter >> 3 & 3] << 8 | 0x32, ext = 0;
+      WorldMap_AddSprite(11, ext, (uint8)info, (uint8)(info >> 8), pt.x, pt.y);
+    }
+  endif_crystal3:;
+  }
+
+  if (!OverworldMap_CheckForCrystal(4) && !sign16(kOwMapCrystal4_x[k])) {
+    link_x_coord_spexit = kOwMapCrystal4_x[k];
+    link_y_coord_spexit = kOwMapCrystal4_y[k];
+    uint8 t = kOwMapCrystal4_tab[k] >> 8;
+    if (t != 0) {
+      if (t != 100 && frame_counter & 0x10)
+        goto endif_crystal4;
+      link_x_coord_spexit -= 4, link_y_coord_spexit -= 4;
+    }
+    if (WorldMap_CalculateOamCoordinates(&pt)) {
+      uint16 info = kOwMapCrystal4_tab[k];
+      uint8 ext = 2;
+      if (!(info >> 8))
+        info = kOwMap_tab2[frame_counter >> 3 & 3] << 8 | 0x32, ext = 0;
+      WorldMap_AddSprite(10, ext, (uint8)info, (uint8)(info >> 8), pt.x, pt.y);
+    }
+  endif_crystal4:;
+  }
+
+  if (!OverworldMap_CheckForCrystal(5) && !sign16(kOwMapCrystal5_x[k])) {
+    link_x_coord_spexit = kOwMapCrystal5_x[k];
+    link_y_coord_spexit = kOwMapCrystal5_y[k];
+    uint8 t = kOwMapCrystal5_tab[k] >> 8;
+    if (t != 0) {
+      if (t != 100 && frame_counter & 0x10)
+        goto endif_crystal5;
+      link_x_coord_spexit -= 4, link_y_coord_spexit -= 4;
+    }
+    if (WorldMap_CalculateOamCoordinates(&pt)) {
+      uint16 info = kOwMapCrystal5_tab[k];
+      uint8 ext = 2;
+      if (!(info >> 8))
+        info = kOwMap_tab2[frame_counter >> 3 & 3] << 8 | 0x32, ext = 0;
+      WorldMap_AddSprite(9, ext, (uint8)info, (uint8)(info >> 8), pt.x, pt.y);
+    }
+  endif_crystal5:;
+  }
+
+  if (!OverworldMap_CheckForCrystal(6) && !sign16(kOwMapCrystal6_x[k])) {
+    link_x_coord_spexit = kOwMapCrystal6_x[k];
+    link_y_coord_spexit = kOwMapCrystal6_y[k];
+    uint8 t = kOwMapCrystal6_tab[k] >> 8;
+    if (t != 0) {
+      if (t != 100 && frame_counter & 0x10)
+        goto endif_crystal6;
+      link_x_coord_spexit -= 4, link_y_coord_spexit -= 4;
+    }
+    if (WorldMap_CalculateOamCoordinates(&pt)) {
+      uint16 info = kOwMapCrystal6_tab[k];
+      uint8 ext = 2;
+      if (!(info >> 8))
+        info = kOwMap_tab2[frame_counter >> 3 & 3] << 8 | 0x32, ext = 0;
+      WorldMap_AddSprite(8, ext, (uint8)info, (uint8)(info >> 8), pt.x, pt.y);
+    }
+  endif_crystal6:;
+  }
+
+out:
+  link_x_coord_spexit = xbak;
+  link_y_coord_spexit = ybak;
+}
+
+static bool WorldMap_CalculateOamCoordinates(Point16U *pt) {  // 8ac39f
+  if (overworld_map_flags == 0) {
+    int j = -(link_y_coord_spexit >> 4) + M7Y_copy + (link_y_coord_spexit >> 3 & 1) - 0xc0;
+    uint8 t0 = kOverworldMap_tab1[j];
+    uint8 yval = 13 * t0 >> 4;
+
+    uint8 at = link_x_coord_spexit >> 4;
+    bool below = at < 0x80;
+    at -= 0x80;
+    if (sign8(at)) at = ~at;
+
+    uint8 t1 = ((yval < 224 ? yval : 0) * 0x54 >> 8) + 0xb2;
+    uint8 t2 = at * t1 >> 8;
+    uint8 t3 = (below) ? 0x80 - t2 : t2 + 0x80;
+
+    pt->x = t3 - BG1HOFS_copy2 + 0x80;
+    pt->y = yval + 12;
+    return true;
+  } else {
+    uint16 t0 = -(link_y_coord_spexit >> 4) + M7Y_copy - 0x80;
+    if (t0 >= 0x100)
+      return false;
+    uint16 t1 = t0 * 37 >> 4;
+    if (t1 >= 333)
+      return false;
+    uint8 yval = kOverworldMap_tab1[t1];
+    uint16 t2 = link_x_coord_spexit;
+    bool below = t2 < 0x7F8;
+    t2 -= 0x7f8;
+    if (sign16(t2))
+      t2 = -t2;
+    uint8 t3 = yval < 226 ? yval : 0;
+    uint8 t4 = (t3 * 84 >> 8) + 178;  // r0
+    uint8 t5 = (uint8)t2 * t4 >> 8; // r1
+    uint16 t6 = (uint8)(t2 >> 8) * t4 + t5;
+    uint16 t7 = (below) ? 0x800 - t6 : t6 + 0x800;
+    bool below2 = t7 < 0x800;
+    t7 -= 0x800;
+    uint16 t8 = below2 ? -t7 : t7;
+    uint8 t9 = (uint8)t8 * 45 >> 8;
+    uint16 t10 = ((t8 >> 8) * 45) + t9;
+    uint16 t11 = below2 ? 0x80 - t10 : t10 + 0x80;
+    uint16 xval = t11 - BG1HOFS_copy2;
+    int xt = enhanced_features0 & kFeatures0_ExtendScreen64 ? 0x48 : 0;
+    if ((uint16)(xval + 0x80 + xt) >= (0x100 + xt * 2))
+      return false;
+    pt->x = xval + 0x81;
+    pt->y = yval + 16;
+    return true;
+  }
+}
+
+static void WorldMap_AddSprite(int spr, uint8 big, uint8 flags, uint8 ch, uint16 x, uint16 y) {  // 8ac51c
+  if (!(frame_counter & 0x10) && ch == 100) {
+    assert(spr >= 8);
+    ch = kOverworldMapData[spr - 8];
+    flags = 0x32;
+    big = 0;
+  } else {
+    x -= 4;
+    y -= 4;
+  }
+  if (enhanced_features0 & kFeatures0_ExtendScreen64)
+    big |= (x >> 8 & 1);
+  SetOamPlain(&oam_buf[spr], x, y, ch, flags, big);
+}
+
+bool OverworldMap_CheckForPendant(int k) {  // 8ac5a9
+  return (savegame_map_icons_indicator == 3) && (link_which_pendants & kPendantBitMask[k]) != 0;
+}
+
+bool OverworldMap_CheckForCrystal(int k) {  // 8ac5c6
+  return (savegame_map_icons_indicator == 7) && (link_has_crystals & kCrystalBitMask[k]) != 0;
+}
+
+void Module0E_03_DungeonMap() {  // 8ae0b0
+  kDungMapSubmodules[overworld_map_state]();
+}
+
+void Module0E_03_01_DrawMap() {  // 8ae0dc
+  kDungMapInit[dungmap_init_state]();
+}
+
+void Module0E_03_01_00_PrepMapGraphics() {  // 8ae0e4
+  uint8 hdmaen_bak = HDMAEN_copy;
+  HDMAEN_copy = 0;
+  mapbak_main_tile_theme_index = main_tile_theme_index;
+  mapbak_sprite_graphics_index = sprite_graphics_index;
+  mapbak_aux_tile_theme_index = aux_tile_theme_index;
+  mapbak_TM = TM_copy;
+  mapbak_TS = TS_copy;
+  main_tile_theme_index = 32;
+  sprite_graphics_index = 0x80 | BYTE(cur_palace_index_x2) >> 1;
+  aux_tile_theme_index = 64;
+  TM_copy = 0x16;
+  TS_copy = 1;
+  EraseTileMaps_dungeonmap();
+  InitializeTilesets();
+  overworld_palette_aux_or_main = 0x200;
+  Palette_Load_DungeonMapBG();
+  Palette_Load_DungeonMapSprite();
+  hud_palette = 1;
+  Palette_Load_HUD();
+  LoadActualGearPalettes();
+  flag_update_cgram_in_nmi++;
+  dungmap_init_state++;
+  HDMAEN_copy = hdmaen_bak;
+  nmi_load_bg_from_vram = 9;
+  nmi_disable_core_updates = 9;
+}
+
+void Module0E_03_01_01_DrawLEVEL() {  // 8ae1a4
+  // Display FLOOR instead of MAP
+  int i = kDungMap_Tab0[cur_palace_index_x2 >> 1] >> 1;
+  if (i >= 0) {
+    uint8 *dst = (uint8 *)&vram_upload_data[0];
+    dst[32] = 0xff;
+    WORD(dst[14   ]) = kDungMap_Tab1[i];
+    WORD(dst[14+16]) = kDungMap_Tab2[i];
+    for (int i = 13; i >= 0; i--) {
+      dst[i] = kDungMap_Tab3[i];
+      dst[i+16] = kDungMap_Tab4[i];
+    }
+    nmi_load_bg_from_vram = 1;
+  }
+  dungmap_init_state++;
+}
+
+void Module0E_03_01_02_DrawFloorsBackdrop() {  // 8ae1f3
+  int offs = 0;
+  uint16 t5 = kDungMap_Tab5[cur_palace_index_x2 >> 1];
+  if (t5 & 0x100) {
+    for (int i = 0; i < 21; i++)
+      vram_upload_data[offs++] = kDungMap_Tab6[i];
+    uint16 t = 0x1123;
+    for (int i = 0; i < 16; i++, t += 0x20, offs += 3) {
+      vram_upload_data[offs + 0] = swap16(t);
+      vram_upload_data[offs + 1] = 0xE40;
+      vram_upload_data[offs + 2] = 0x1B2E;
+    }
+  }
+  int t7 = kDungMap_Tab7[(uint8)t5 >= 0x50 ? (((uint8)t5 >> 4) - 4) : (t5 & 0xf) >= 5 ? (t5 & 0xf) : 0], t7_org = t7;
+  int j = 0;
+  do {
+    vram_upload_data[offs++] = swap16(t7);
+    vram_upload_data[offs++] = 0xe40;
+    vram_upload_data[offs++] = kDungMap_Tab8[j] + (t5 & 0x200 ? 0x400 : 0);
+    j += (j != 6);
+  } while (t7 += 0x20, t7 < 0x1360);
+  vram_upload_offset = offs * 2;
+  DungeonMap_BuildFloorListBoxes(t5, t7_org);
+  ((uint8 *)vram_upload_data)[vram_upload_offset] = 0xff;
+  dungmap_init_state++;
+  nmi_load_bg_from_vram = 1;
+}
+
+void DungeonMap_BuildFloorListBoxes(uint8 t5, uint16 r14) {  // 8ae2f5
+  int n = (t5 & 0xf) + (t5 >> 4);
+  r14 -= 0x40 - 2;
+  r14 += (t5 & 0xf) * 0x40;
+  int offs = vram_upload_offset >> 1;
+  int i = 0;
+  do {
+    int x = 0;
+loop2:
+    vram_upload_data[offs++] = swap16(r14);
+    vram_upload_data[offs++] = 0x700;
+    do {
+      vram_upload_data[offs++] = kDungMap_Tab9[x++];
+      if (x == 4) {
+        r14 += 0x20;
+        goto loop2;
+      }
+    } while (x != 8);
+
+    r14 -= 0x40 + 0x20;
+  } while (++i < n);
+  vram_upload_offset = offs * 2;
+}
+
+void Module0E_03_01_03_DrawRooms() {  // 8ae384
+  dungmap_var2 = 0;
+  dungmap_idx = 0;
+  uint8 t = -(kDungMap_Tab5[cur_palace_index_x2 >> 1] & 0xf);
+  if (WORD(dung_cur_floor) != t) {
+    dungmap_cur_floor = dung_cur_floor;
+  } else {
+    dungmap_cur_floor = WORD(dung_cur_floor) + 1;
+    dungmap_idx += 2;
+  }
+  DungeonMap_DrawFloorNumbersByRoom(0, ~0x1000);
+  DungeonMap_DrawBorderForRooms(0, ~0x1000);
+  DungeonMap_DrawDungeonLayout(0);
+  BYTE(dungmap_cur_floor)--;
+  DungeonMap_DrawFloorNumbersByRoom(0x300, ~0x1000);
+  DungeonMap_DrawBorderForRooms(0x300, ~0x1000);
+  DungeonMap_DrawDungeonLayout(0x300);
+  dungmap_cur_floor++;
+  WORD(g_ram[6]) = 0;
+  WORD(g_ram[10]) = 0;
+  nmi_subroutine_index = 8;
+  BYTE(nmi_load_target_addr) = 0x22;
+  dungmap_init_state++;
+}
+
+void DungeonMap_DrawBorderForRooms(uint16 pd, uint16 mask) {  // 8ae449
+  for (int i = 0; i != 4; i++)
+    messaging_buf[((kDungMap_Tab10[i] + pd) & 0xfff) >> 1] = kDungMap_Tab11[i] & mask;
+  for (int i = 0; i != 2; i++) {
+    int r4 = kDungMap_Tab12[i] + pd;
+    for (int j = 0; j != 20; j+=2)
+      messaging_buf[((r4 + j) & 0xfff) >> 1] = kDungMap_Tab13[i] & mask;
+  }
+
+  for (int i = 0; i != 2; i++) {
+    int r4 = kDungMap_Tab14[i] + pd;
+    for (int j = 0; j != 0x280; j+=0x40)
+      messaging_buf[((r4 + j) & 0xfff) >> 1] = kDungMap_Tab15[i] & mask;
+  }
+}
+
+void DungeonMap_DrawFloorNumbersByRoom(uint16 pd, uint16 r8) {  // 8ae4f9
+  uint16 p = 0xDE;
+  do {
+    int t = ((p + pd) & 0xfff) >> 1;
+    messaging_buf[t] = 0xf00;
+    messaging_buf[t+1] = 0xf00;
+  } while (p += 0x40, p != 0x39e);
+  int t = ((0x35e + pd) & 0xfff) >> 1;
+  uint16 q1 = (dungmap_cur_floor & 0x80) ? 0x1F1C : kDungMap_Tab16[dungmap_cur_floor & 0xf];
+  uint16 q2 = (dungmap_cur_floor & 0x80) ? kDungMap_Tab16[(uint8)~dungmap_cur_floor] : 0x1F1D;
+  messaging_buf[t+0] = q1 & r8;
+  messaging_buf[t+1] = q2 & r8;
+}
+
+void DungeonMap_DrawDungeonLayout(int pd) {  // 8ae579
+  for (int i = 0; i < 5; i++)
+    DungeonMap_DrawSingleRowOfRooms(i, ((292 + 128 * i + pd) & 0xfff) >> 1);
+}
+
+void DungeonMap_DrawSingleRowOfRooms(int i, int arg_x) {  // 8ae5bc
+  uint16 t5 = kDungMap_Tab5[cur_palace_index_x2 >> 1];
+  int dungmask = kUpperBitmasks[cur_palace_index_x2 >> 1];
+
+  for (int j = 0; j < 5; j++, arg_x += 2) {
+    int r14 = (uint8)(dungmap_cur_floor + (t5 & 0xf));
+    const uint8 *curp = GetDungmapFloorLayout();
+    uint8 v = curp[r14 * 25 + i * 5 + j];
+    uint16 yv, av;
+    if (v == 0xf) {
+      yv = 0x51;
+    } else {
+      r14 = save_dung_info[v] & 0xf;
+      int k = 0, count = 0;
+      for(; curp[k] != v; k++)
+        count += (curp[k] != 0xf);
+      yv = GetOtherDungmapInfo(count);
+    }
+
+    uint16 r12 = kDungMap_Tab23[yv * 4 + 0], r12_org = r12;
+    if (r12 != 0xB00 && (r14 & 8) == 0) {
+      if (!(r12 & 0x1000)) {
+        r12 = 0x400;
+      } else if (link_dungeon_map & dungmask) {
+        av = (r12 & ~0x1c00) | 0xc00;
+        goto write_3;
+      } else {
+        r12 = 0;
+      }
+    } else {
+      r12 = 0;
+    }
+    av = ((link_dungeon_map & dungmask) || (r14 & 8)) ? r12 + r12_org : 0xb00;
+  write_3:
+    messaging_buf[arg_x] = av;
+
+    r12 = kDungMap_Tab23[yv * 4 + 1], r12_org = r12;
+    if (r12 != 0xB00 && (r14 & 4) == 0) {
+      if (!(r12 & 0x1000)) {
+        r12 = 0x400;
+      } else if (link_dungeon_map & dungmask) {
+        av = (r12 & ~0x1c00) | 0xc00;
+        goto write_4;
+      } else {
+        r12 = 0;
+      }
+    } else {
+      r12 = 0;
+    }
+    av = ((link_dungeon_map & dungmask) || (r14 & 4)) ? r12 + r12_org : 0xb00;
+  write_4:
+    messaging_buf[arg_x + 1] = av;
+
+    r12 = kDungMap_Tab23[yv * 4 + 2], r12_org = r12;
+    if (r12 != 0xB00 && (r14 & 2) == 0) {
+      if (!(r12 & 0x1000)) {
+        r12 = 0x400;
+      } else if (link_dungeon_map & dungmask) {
+        av = (r12 & ~0x1c00) | 0xc00;
+        goto write_5;
+      } else {
+        r12 = 0;
+      }
+    } else {
+      r12 = 0;
+    }
+    av = ((link_dungeon_map & dungmask) || (r14 & 2)) ? r12 + r12_org : 0xb00;
+  write_5:
+    messaging_buf[arg_x + 32] = av;
+
+    r12 = kDungMap_Tab23[yv * 4 + 3], r12_org = r12;
+    if (r12 != 0xB00 && (r14 & 1) == 0) {
+      if (!(r12 & 0x1000)) {
+        r12 = 0x400;
+      } else if (link_dungeon_map & dungmask) {
+        av = (r12 & ~0x1c00) | 0xc00;
+        goto write_6;
+      } else {
+        r12 = 0;
+      }
+    } else {
+      r12 = 0;
+    }
+    av = ((link_dungeon_map & dungmask) || (r14 & 1)) ? r12 + r12_org : 0xb00;
+  write_6:
+    messaging_buf[arg_x + 33] = av;
+  }
+}
+
+void DungeonMap_DrawRoomMarkers() {  // 8ae823
+  int dung = cur_palace_index_x2 >> 1;
+  uint8 t5 = (kDungMap_Tab5[dung] & 0xf);
+  uint8 floor1 = t5 + dung_cur_floor;
+
+  uint16 room = dungeon_room_index;
+  for (int i = 0; i != 3; i++) {
+    if (room == kDungMap_Tab21[i])
+      room = kDungMap_Tab22[i];
+  }
+  const uint8 *roomp = GetDungmapFloorLayout();
+  const uint8 *curp = &roomp[floor1 * 25];
+  int i;
+
+  uint8 xcoord = 0, ycoord = 0;
+  for(i = 0; i < 25 && *curp++ != (uint8)room; i++) {
+    if (xcoord < 64)
+      xcoord += 16;
+    else
+      xcoord = 0, ycoord += 16;
+  }
+  dungmap_var3 = xcoord + 0x90;
+  dungmap_var3 += (link_x_coord & 0x1e0) >> 5;
+
+  dungmap_var6 = ycoord;
+
+  dungmap_var5 = ycoord + kDungMap_Tab24[dungmap_idx >> 1];
+  dungmap_var5 += (link_y_coord & 0x1e0) >> 5;
+
+  uint8 floor2 = t5 + kDungMap_Tab28[dung];
+  curp = &roomp[floor2 * 25];
+
+  dungmap_var8 = dungmap_var7 = 0x40;
+
+  uint8 lookfor = kDungMap_Tab25[dung];
+  for (int j = 24; j >= 0; j--) {
+    if (curp[j] != 0xf && curp[j] == lookfor)
+      break;
+    if ((int16)(dungmap_var7 -= 0x10) < 0) {
+      dungmap_var7 = 0x40;
+      BYTE(dungmap_var8) -= 0x10;
+    }
+  }
+
+  int8 floor3 = dungmap_cur_floor - kDungMap_Tab28[dung];
+  dungmap_var8 += 0x60 * floor3;
+  dungmap_var8 += kDungMap_Tab24[0];
+  overworld_map_state++;
+  INIDISP_copy = 0;
+  dungmap_init_state = 0;
+}
+
+void DungeonMap_HandleInputAndSprites() {  // 8ae954
+  DungeonMap_HandleInput();
+  DungeonMap_DrawSprites();
+}
+
+static inline bool WantExitDungeonMap() {
+  if (hud_cur_item_x != 0)
+    return filtered_joypad_H & 0x20;  // Select
+  else
+    return filtered_joypad_L & 0x40;  // X
+}
+
+void DungeonMap_HandleInput() {  // 8ae95b
+  if (WantExitDungeonMap()) {
+    overworld_map_state += 2;
+    dungmap_init_state = 0;
+  } else {
+    DungeonMap_HandleMovementInput();
+  }
+}
+
+void DungeonMap_HandleMovementInput() {  // 8ae979
+  DungeonMap_HandleFloorSelect();
+  if (dungmap_var2)
+    DungeonMap_ScrollFloors();
+}
+
+void DungeonMap_HandleFloorSelect() {  // 8ae986
+  uint8 r2 = (kDungMap_Tab5[cur_palace_index_x2 >> 1] >> 4 & 0xf);
+  uint8 r3 = (kDungMap_Tab5[cur_palace_index_x2 >> 1] & 0xf);
+  if (r2 + r3 < 3 || dungmap_var2 || !(joypad1H_last & 0xc))
+    return;
+  dungmap_cur_floor &= 0xff;
+  uint16 r6 = WORD(g_ram[6]);
+  if (joypad1H_last & 8) {
+    if (r2 - 1 == dungmap_cur_floor)
+      return;
+    dungmap_cur_floor++;
+    r6 = (r6 - 0x300) & 0xfff;
+  } else {
+    if ((uint8)(-r3 + 1) == dungmap_cur_floor)
+      return;
+    dungmap_cur_floor -= 2;
+    r6 = (r6 + 0x600) & 0xfff;
+  }
+  DungeonMap_DrawFloorNumbersByRoom(r6, ~0x1000);
+  DungeonMap_DrawBorderForRooms(r6, ~0x1000);
+  DungeonMap_DrawDungeonLayout(r6);
+  dungmap_var2++;
+  WORD(g_ram[10]) = joypad1H_last;
+  int x = joypad1H_last >> 3 & 1;
+  dungmap_var4 = BG2VOFS_copy2 + kDungMap_Tab26[x];
+  if (!x) {
+    r6 = (r6 - 0x300) & 0xfff;
+    dungmap_cur_floor++;
+  }
+  WORD(g_ram[6]) = r6;
+  nmi_subroutine_index = 8;
+}
+
+void DungeonMap_ScrollFloors() {  // 8aea7f
+  int x = WORD(g_ram[10]) >> 3 & 1;
+  dungmap_var5 += kDungMap_Tab39[x];
+  dungmap_var8 += kDungMap_Tab39[x];
+  BG2VOFS_copy2 += kDungMap_Tab40[x];
+  if (BG2VOFS_copy2 == dungmap_var4)
+    dungmap_var2 = 0;
+}
+
+void DungeonMap_DrawSprites() {  // 8aeab2
+  int dung = cur_palace_index_x2 >> 1;
+  uint8 r2 = (kDungMap_Tab5[dung] & 0xf);
+  uint8 floor = r2 + dung_cur_floor;
+
+  int spr_pos = 0;
+  uint8 r14 = 0;
+  DungeonMap_DrawLinkPointing(spr_pos++, r2, floor);
+  do {
+    spr_pos = DungeonMap_DrawLocationMarker(spr_pos, r14);
+    r14 += 1;
+  } while (spr_pos != 9);
+  spr_pos = DungeonMap_DrawBlinkingIndicator(spr_pos);
+  spr_pos = DungeonMap_DrawBossIcon(spr_pos);
+  spr_pos = DungeonMap_DrawFloorNumberObjects(spr_pos);
+  DungeonMap_DrawFloorBlinker();
+}
+
+void DungeonMap_DrawLinkPointing(int spr_pos, uint8 r2, uint8 r3) {  // 8aeaf0
+  int dung = cur_palace_index_x2 >> 1;
+  uint8 t5 = kDungMap_Tab5[dung];
+  if (4 - r2 >= 0) {
+    r3 += 4 - r2;
+    int8 a = (t5 >> 4) - 4;
+    if (a >= 0)
+      r3 -= a;
+  }
+  SetOamPlain(&oam_buf[spr_pos], 0x19, kDungMap_Tab33[r3] - 4, 0, palette_swap_flag ? 0x30 : 0x3e, 2);
+}
+
+int DungeonMap_DrawBlinkingIndicator(int spr_pos) {  // 8aeb50
+  SetOamPlain(&oam_buf[spr_pos], dungmap_var3 - 3, ((dungmap_var5 < 256) ? dungmap_var5 : 0xf0) - 3, 0x34, kDungMap_Tab38[frame_counter >> 2 & 3], 0);
+  return spr_pos + 1;
+}
+
+int DungeonMap_DrawLocationMarker(int spr_pos, uint16 r14) {  // 8aeba8
+  for (int i = 3; i >= 0; i--, spr_pos++) {
+    uint8 r15 = dungmap_var6 + kDungMap_Tab24[r14];
+    int fr = (frame_counter >> 2) & 1;
+    if ((dungmap_var5 + 1 & 0xf0) == r15 + 1 && dungmap_var5 < 256)
+      fr += 2;
+    SetOamPlain(&oam_buf[spr_pos], kDungMap_Tab29[i] + (dungmap_var3 & 0xf0),
+                r15 + kDungMap_Tab30[i],
+                0, kDungMap_Tab32[fr] | kDungMap_Tab31[i], 2);
+  }
+  return spr_pos;
+}
+
+int DungeonMap_DrawFloorNumberObjects(int spr_pos) {  // 8aec0a
+  uint8 r2 = (kDungMap_Tab5[cur_palace_index_x2 >> 1] >> 4 & 0xf);
+  uint8 r3 = (kDungMap_Tab5[cur_palace_index_x2 >> 1] & 0xf);
+  uint8 yv = 7;
+  if (r2 + r3 != 8 && r2 < 4) {
+    yv = 6;
+    for (int i = 3; i != 0 && i != r2; i--)
+      yv--;
+    if (r3 >= 5) {
+      for (int i = 5; i != r3 && r3 != 8; i++)
+        yv++;
+    }
+  }
+
+  uint8 r4 = kDungMap_Tab33[yv] + 1;
+  r2--;
+  r3 = -r3;
+  do {
+    SetOamPlain(&oam_buf[spr_pos + 0], 0x30, r4, sign8(r2) ? 0x1c : kDungMap_Tab34[r2], 0x3d, 0);
+    SetOamPlain(&oam_buf[spr_pos + 1], 0x38, r4, sign8(r2) ? kDungMap_Tab34[r2 ^ 0xff] : 0x1d, 0x3d, 0);
+    r4 += 16;
+  } while (spr_pos += 2, r2-- != r3);
+  return spr_pos;
+}
+
+void DungeonMap_DrawFloorBlinker() {  // 8aeccf
+  uint8 floor = dungmap_cur_floor;
+  uint8 t5 = kDungMap_Tab5[cur_palace_index_x2 >> 1];
+  uint8 flag = ((t5 >> 4 & 0xf) + (t5 & 0xf) != 1);
+  floor -= flag;
+  uint8 r0;
+  uint8 i = flag;
+  do {
+    r0 = floor + (t5 & 0xf);
+    int8 a = 4 - (t5 & 0xf);
+    if (a >= 0) {
+      r0 += a;
+      a = (t5 >> 4) - 4;
+      if (a >= 0)
+        r0 -= a;
+    }
+    floor += 1;
+  } while (i--);
+  if (!(frame_counter & 0x10))
+    return;
+  uint8 y = kDungMap_Tab33[r0] - 4;
+  do {
+    uint8 x = 40;
+    int spr_pos = 0x40 + kDungMap_Tab35[flag];
+    for (int i = 3; i >= 0; i--, spr_pos++) {
+      uint8 t = 0x3d | (i ? 0 : 0x40);
+      SetOamPlain(&oam_buf[spr_pos + 0], x, y + flag * 16 + 0, kDungMap_Tab36[i], t, 0);
+      SetOamPlain(&oam_buf[spr_pos + 4], x, y + flag * 16 + 8, kDungMap_Tab36[i], t | 0x80, 0);
+      x += 8;
+    }
+  } while (flag--);
+}
+
+int DungeonMap_DrawBossIcon(int spr_pos) {  // 8aede4
+  int dung = cur_palace_index_x2 >> 1;
+  if (save_dung_info[kDungMap_Tab25[dung]] & 0x800 || !(link_compass & kUpperBitmasks[dung]) || kDungMap_Tab28[dung] < 0)
+    return spr_pos;
+  spr_pos = DungeonMap_DrawBossIconByFloor(spr_pos);
+  if ((frame_counter & 0xf) >= 10)
+    return spr_pos;
+  uint16 xy = kDungMap_Tab37[dung];
+  SetOamPlain(&oam_buf[spr_pos], (xy >> 8) + dungmap_var7 + 0x90, (dungmap_var8 < 256) ? xy + dungmap_var8 : 0xf0, 0x31, 0x33, 0);
+  return spr_pos + 1;
+}
+
+int DungeonMap_DrawBossIconByFloor(int spr_pos) {  // 8aee95
+  int dung = cur_palace_index_x2 >> 1;
+  uint8 t5 = kDungMap_Tab5[dung];
+  uint8 r2 = t5 & 0xf;
+  uint8 r3 = r2 + kDungMap_Tab28[dung];
+  if (4 - r2 >= 0) {
+    r3 += 4 - r2;
+    int8 a = (t5 >> 4) - 4;
+    if (a >= 0)
+      r3 -= a;
+  }
+  if ((frame_counter & 0xf) >= 10)
+    return spr_pos;
+  SetOamPlain(&oam_buf[spr_pos], 0x4c, kDungMap_Tab33[r3], 0x31, 0x33, 0);
+  return spr_pos + 1;
+}
+
+void DungeonMap_RecoverGFX() {  // 8aef19
+  uint8 hdmaen_bak = HDMAEN_copy;
+  HDMAEN_copy = 0;
+  EraseTileMaps_normal();
+
+  TM_copy = mapbak_TM;
+  TS_copy = mapbak_TS;
+  main_tile_theme_index = mapbak_main_tile_theme_index;
+  sprite_graphics_index = mapbak_sprite_graphics_index;
+  aux_tile_theme_index = mapbak_aux_tile_theme_index;
+  InitializeTilesets();
+  overworld_palette_aux_or_main = 0;
+  hud_palette = 0;
+  Hud_Rebuild();
+
+  overworld_screen_transition = 0;
+  dung_cur_quadrant_upload = 0;
+  do {
+    WaterFlood_BuildOneQuadrantForVRAM();
+    NMI_UploadTilemap();
+    Dungeon_PrepareNextRoomQuadrantUpload();
+    NMI_UploadTilemap();
+  } while (dung_cur_quadrant_upload != 0x10);
+
+  nmi_subroutine_index = 0;
+  subsubmodule_index = 0;
+  HDMAEN_copy = hdmaen_bak;
+
+  memcpy(main_palette_buffer, mapbak_palette, sizeof(uint16) * 256);
+  COLDATA_copy0 |= overworld_fixed_color_plusminus;
+  COLDATA_copy1 |= overworld_fixed_color_plusminus;
+  COLDATA_copy2 |= overworld_fixed_color_plusminus;
+
+  sound_effect_2 = 16;
+  music_control = 0xf3;
+  RecoverPegGFXFromMapping();
+  flag_update_cgram_in_nmi++;
+  overworld_map_state++;
+  INIDISP_copy = 0;
+  nmi_disable_core_updates = 0;
+}
+
+void ToggleStarTilesAndAdvance() {  // 8aefc9
+  Dungeon_RestoreStarTileChr();
+  overworld_map_state++;
+}
+
+void Death_InitializeGameOverLetters() {  // 8afe20
+  flag_for_boomerang_in_place = 0;
+  for (int i = 0; i < 8; i++) {
+    ancilla_x_lo[i] = 0xb0;
+    ancilla_x_hi[i] = 0;
+  }
+  ancilla_type[0] = 1;
+  hookshot_effect_index = 6;
+}
+
+void CopySaveToWRAM() {  // 8ccfbb
+  int k = 0xf;
+  bird_travel_x_hi[k] = 0;
+  bird_travel_y_hi[k] = 0;
+  bird_travel_x_lo[k] = 0;
+  bird_travel_y_lo[k] = 0;
+  birdtravel_var1[k] = 0;
+
+  memcpy(save_dung_info, &g_zenv.sram[WORD(g_ram[0])], 0x500);
+
+  bg_tile_animation_countdown = 7;
+  word_7EC013 = 7;
+  word_7EC00F = 0;
+  word_7EC015 = 0;
+  word_7E0219 = 0x6040;
+  word_7E021D = 0x4841;
+  word_7E021F = 0x7f;
+  word_7E0221 = 0xffff;
+
+  // If you save / quit in the middle of a mosaic effect, such as
+  // being electrocuted by a buzz blob, the resumed game will skip
+  // the location prompt and start in the sanctuary.
+  if (enhanced_features0 & kFeatures0_MiscBugFixes)
+    mosaic_level = 0;
+
+  hud_var1 = 128;
+  main_module_index = 5;
+  submodule_index = 0;
+  which_entrance = 0;
+  nmi_disable_core_updates = 0;
+  hud_palette = 0;
+}
+
+void RenderText() {  // 8ec440
+  kMessaging_Text[messaging_module]();
+}
+
+void RenderText_PostDeathSaveOptions() {  // 8ec455
+  dialogue_message_index = 3;
+  Text_Initialize_initModuleStateLoop();
+  text_msgbox_topleft = 0x61e8;
+  text_render_state = 2;
+  for (int i = 0; i < 5; i++)
+    Text_Render();
+}
+
+void Text_Initialize() {  // 8ec483
+  if (main_module_index == 20)
+    ResetHUDPalettes4and5();
+  Attract_DecompressStoryGFX();
+  Text_Initialize_initModuleStateLoop();
+}
+
+void Text_Initialize_initModuleStateLoop() {  // 8ec493
+  memcpy(&text_msgbox_topleft_copy, kText_InitializationData, 32);
+  Text_InitVwfState();
+  RenderText_SetDefaultWindowPosition();
+  text_tilemap_cur = 0x3980;
+  Text_LoadCharacterBuffer();
+  memset(messaging_buf, 0, 0x7e0);
+  nmi_subroutine_index = 2;
+  nmi_disable_core_updates = 2;
+}
+
+void Text_InitVwfState() {  // 8ec4c9
+  vwf_curline = 0;
+  vwf_flag_next_line = 0;
+  vwf_var1 = 0;
+  vwf_line_ptr = 0;
+}
+
+enum {
+  kTextCommandStart_US = 0x67,
+  kTextDictBase = 0x88,
+
+  kTextCmd_NextPic = 0,
+  kTextCmd_Choose = 1,
+  kTextCmd_Item = 2,
+  kTextCmd_Name = 3,
+  kTextCmd_Window = 4,  // Only used with 2
+  kTextCmd_Number = 5,
+  kTextCmd_Position = 6,
+  kTextCmd_ScrollSpd = 7,
+  kTextCmd_Selchg = 8,
+  kTextCmd_Choose3 = 10,
+  kTextCmd_Choose2 = 11,
+  kTextCmd_Scroll = 12,
+  kTextCmd_1 = 13,
+  kTextCmd_2 = 14,
+  kTextCmd_3 = 15,
+  kTextCmd_Color = 16,
+  kTextCmd_Wait = 17,
+  kTextCmd_Sound = 18,
+  kTextCmd_Speed = 19,
+  kTextCmd_Mark = 20,     // Unused
+  kTextCmd_Mark2 = 21,    // Unused
+  kTextCmd_Clear = 22,    // Unused
+  kTextCmd_Waitkey = 23,
+  kTextCmd_EndMessage = 24,
+
+  kTextCmd_IsLetter = 25, // Pseudo cmd
+};
+
+enum {
+  kTextCmd_EU_Scroll = 0x80,  // frequency 875
+  kTextCmd_EU_Waitkey = 0x81, // frequency 362
+  kTextCmd_EU_1 = 0x82,       // frequency 25
+  kTextCmd_EU_2 = 0x83,       // frequency 496
+  kTextCmd_EU_3 = 0x84,       // frequency 347
+  kTextCmd_EU_Name = 0x85,    // frequency 64
+  kTextCmd_EU_Rest = 0x87,    
+};
+
+#define TEXTCMD_MULTIBYTE(a) ((a) & 1)
+#define TEXTCMD_CMD(a) (((a) >> 1) & 0x1f)
+#define TEXTCMD_PARAM(a) ((a) >> 6)
+#define TEXTCMD_MK(c, x, m) ((c) << 6 | (x) << 1 | (m))
+
+uint32 Text_DecodeCmd(uint8 a, const uint8 *src) {
+  if ((g_zenv.dialogue_flags & 1) == 0) {
+    // US encoding
+    if (a < kTextCommandStart_US)
+      return TEXTCMD_MK(a, kTextCmd_IsLetter, 0);
+    if (a >= 0x80)
+      return TEXTCMD_MK(26, kTextCmd_IsLetter, 0); // could happen when loading snapshots
+    assert(a < 0x80);
+    static const uint8 kText_CommandLengths_US[] = { 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0 };
+    if (kText_CommandLengths_US[a - kTextCommandStart_US])
+      return TEXTCMD_MK(*src, a - kTextCommandStart_US, 1);
+    else
+      return TEXTCMD_MK(0, a - kTextCommandStart_US, 0);
+  } else {
+    // EU encoding
+    if (a < 0x7f)
+      return TEXTCMD_MK(a, kTextCmd_IsLetter, 0);
+    static const uint8 kSoundLut[] = {45};
+    static const uint8 kReturns_Simple[] = {
+      TEXTCMD_MK(0, kTextCmd_EndMessage, 0),
+      TEXTCMD_MK(0, kTextCmd_Scroll, 0),
+      TEXTCMD_MK(0, kTextCmd_Waitkey, 0),
+      TEXTCMD_MK(0, kTextCmd_1, 0),
+      TEXTCMD_MK(0, kTextCmd_2, 0),
+      TEXTCMD_MK(0, kTextCmd_3, 0),
+      TEXTCMD_MK(0, kTextCmd_Name, 0),
+      TEXTCMD_MK(0, kTextCmd_Name, 0), // Unused
+    };
+    if (a < kTextCmd_EU_Rest)
+      return kReturns_Simple[a - 0x7f];
+    a = *src;
+    switch (a >> 4) {
+    case 0: return TEXTCMD_MK(a & 0xF, kTextCmd_Wait, 1);
+    case 1: return TEXTCMD_MK(a & 0xF, kTextCmd_Color, 1);
+    case 2: return TEXTCMD_MK(a & 0xF, kTextCmd_Number, 1);
+    case 3: return TEXTCMD_MK(a & 0xF, kTextCmd_Speed, 1);
+    case 4: return TEXTCMD_MK(kSoundLut[a & 0xF], kTextCmd_Sound, 1);
+    case 8: {
+      static const uint8 kReturns_Ext[] = {
+        TEXTCMD_MK(0, kTextCmd_Choose, 1),
+        TEXTCMD_MK(0, kTextCmd_Choose2, 1),
+        TEXTCMD_MK(0, kTextCmd_Choose3, 1),
+        TEXTCMD_MK(0, kTextCmd_Selchg, 1),
+        TEXTCMD_MK(0, kTextCmd_Item, 1),
+        TEXTCMD_MK(0, kTextCmd_NextPic, 1),
+        TEXTCMD_MK(2, kTextCmd_Window, 1),
+        TEXTCMD_MK(0, kTextCmd_Position, 1),
+        TEXTCMD_MK(1, kTextCmd_Position, 1),
+      };
+      return kReturns_Ext[a - 0x80];
+    }
+    default:
+      assert(0);
+      return TEXTCMD_MK(26, kTextCmd_IsLetter, 0);
+    }
+  }
+}
+
+// Perform initial parsing of the string, expanding words, processing some commands, etc.
+void Text_LoadCharacterBuffer() {  // 8ec4e2
+  MemBlk dictionary = FindIndexInMemblk(g_zenv.dialogue_blk, 0);
+  MemBlk dialogue = FindIndexInMemblk(g_zenv.dialogue_blk, 1);
+  MemBlk text_str = FindIndexInMemblk(dialogue, dialogue_message_index);
+  const uint8 *src = text_str.ptr, *src_end = src + text_str.size, *src_org = src;
+  uint8 *dst = messaging_text_buffer;
+  while (src < src_end) {
+    uint8 c = *src++;
+    if (c >= kTextDictBase) {
+      MemBlk blk = FindIndexInMemblk(dictionary, c - kTextDictBase);
+      memcpy(dst, blk.ptr, blk.size);
+      dst += blk.size;
+      continue;
+    }
+    // Decode the next byte or multibyte character (in case we support that in the future)
+    // This is dependent on the current language cause US / PAL encode commands differently
+    uint32 cmd = Text_DecodeCmd(c, src);
+    switch (TEXTCMD_CMD(cmd)) {
+    case kTextCmd_Name: dst = Text_WritePlayerName(dst); break;
+    case kTextCmd_Window:  // RenderText_ExtendedCommand_SetWindowType
+      text_render_state = TEXTCMD_PARAM(cmd);
+      break;
+    case kTextCmd_Number: {  // Text_WritePreloadedNumber
+      uint8 t = TEXTCMD_PARAM(cmd);
+      uint8 v = dialogue_number[t >> 1];
+      *dst++ = 0x34 + ((t & 1) ? v >> 4 : v & 0xf);
+      break;
+    }
+    case kTextCmd_Position:
+      text_msgbox_topleft = kText_Positions[TEXTCMD_PARAM(cmd)];
+      break;
+    case kTextCmd_Color:
+      text_tilemap_cur = ((0x387F & 0xe300) | 0x180) | (TEXTCMD_PARAM(cmd) << 10) & 0x3c00;
+      break;
+    default:
+      // This combination is handled when rendering instead of here
+      *dst++ = c;
+      if (TEXTCMD_MULTIBYTE(cmd))
+        *dst++ = *src;
+      break;
+    }
+    src += TEXTCMD_MULTIBYTE(cmd);
+  }
+  *dst = 0x7f;
+  dialogue_msg_read_pos = 0;
+}
+
+uint8 *Text_WritePlayerName(uint8 *p) {  // 8ec5b3
+  uint8 slot = srm_var1;
+  int offs = ((slot>>1) - 1) * 0x500;
+  for (int i = 0; i < 6; i++) {
+    uint8 *pp = &g_zenv.sram[0x3d9 + offs + i * 2];
+    uint16 a = WORD(*pp);
+    p[i] = Text_FilterPlayerNameCharacters(a & 0xf | (a >> 1) & 0xf0);
+  }
+  int i = 6;
+  while (i && p[i - 1] == 0x59)
+    i--;
+  return p + i;
+}
+
+uint8 Text_FilterPlayerNameCharacters(uint8 a) {  // 8ec639
+  if (a >= 0x5f) {
+    if (a >= 0x76)
+      a -= 0x42;
+    else if (a == 0x5f)
+      a = 8;
+    else if (a == 0x60)
+      a = 0x22;
+    else if (a == 0x61)
+      a = 0x3e;
+  }
+  return a;
+}
+
+void Text_Render() {  // 8ec8d9
+  kText_Render[text_render_state]();
+}
+
+void RenderText_Draw_Border() {  // 8ec8ea
+  RenderText_DrawBorderInitialize();
+  uint16 *d = RenderText_DrawBorderRow(vram_upload_data, 0);
+  for(int i = 0; i != 6; i++)
+    d = RenderText_DrawBorderRow(d, 6);
+  d = RenderText_DrawBorderRow(d, 12);
+  nmi_load_bg_from_vram = 1;
+  text_render_state = 2;
+}
+
+void RenderText_Draw_BorderIncremental() {  // 8ec919
+  nmi_load_bg_from_vram = 1;
+  uint8 a = text_incremental_state;
+  uint16 *d = vram_upload_data;
+  if (a)
+    a = (a < 7) ? 1 : 2;
+  switch (a) {
+  case 0:
+    RenderText_DrawBorderInitialize();
+    d = RenderText_DrawBorderRow(d, 0);
+    text_incremental_state++;
+    break;
+  case 1:
+    d = RenderText_DrawBorderRow(d, 6);
+    text_incremental_state++;
+    break;
+  case 2:
+    text_render_state = 2;
+    d = RenderText_DrawBorderRow(d, 12);
+    text_incremental_state++;
+    break;
+  }
+}
+
+void RenderText_Draw_CharacterTilemap() {  // 8ec97d
+  Text_BuildCharacterTilemap();
+  text_render_state++;
+}
+
+void RenderText_Draw_MessageCharacters() {  // 8ec984
+RESTART:;
+  uint32 cmd = Text_DecodeCmd(messaging_text_buffer[dialogue_msg_read_pos],
+      &messaging_text_buffer[dialogue_msg_read_pos + 1]);
+
+  switch (TEXTCMD_CMD(cmd)) {
+  case kTextCmd_IsLetter:
+    if (vwf_line_speed_cur >= 2) {
+      vwf_line_speed_cur--;
+      break;
+    }
+    VWF_RenderSingle(TEXTCMD_PARAM(cmd));
+    dialogue_msg_read_pos += 1 + TEXTCMD_MULTIBYTE(cmd);
+    if (vwf_line_speed_cur == 0)
+      goto RESTART;
+    break;
+  case kTextCmd_NextPic:  // RenderText_Draw_NextImage
+    if (main_module_index == 20) {
+      PaletteFilterHistory();
+      if (!BYTE(palette_filter_countdown))
+        goto COMMAND_DONE;
+    } else {
+      goto COMMAND_DONE;
+    }
+    break;
+  case kTextCmd_Choose:  // RenderText_Draw_Choose2LowOr3
+    RenderText_Draw_Choose2LowOr3();
+    break;
+  case kTextCmd_Item:  // RenderText_Draw_ChooseItem
+    RenderText_Draw_ChooseItem();
+    break;
+  case kTextCmd_Name:
+  case kTextCmd_Window:
+  case kTextCmd_Number:
+  case kTextCmd_Position:
+  case kTextCmd_Color:
+    // These get handled in Text_LoadCharacterBuffer
+    assert(0);
+    break;
+  // These are unused
+  case kTextCmd_Mark:
+  case kTextCmd_Mark2:
+  case kTextCmd_Clear:
+    assert(0);
+    break;
+  case kTextCmd_ScrollSpd:
+    dialogue_scroll_speed = TEXTCMD_PARAM(cmd);
+    goto COMMAND_DONE;
+  case kTextCmd_Selchg:   // RenderText_Draw_Choose2HiOr3
+    RenderText_Draw_Choose2HiOr3();
+    break;
+  case kTextCmd_Choose3:  // RenderText_Draw_Choose3
+    RenderText_Draw_Choose3();
+    break;
+  case kTextCmd_Choose2:  // RenderText_Draw_Choose1Or2
+    RenderText_Draw_Choose1Or2();
+    break;
+  case kTextCmd_Scroll:  // RenderText_Draw_Scroll
+    if (RenderText_Draw_Scroll())
+      goto COMMAND_DONE;
+    break;
+  case kTextCmd_1:  //
+  case kTextCmd_2:  //
+  case kTextCmd_3:  // VWF_SetLine
+    vwf_curline = kVWF_RowPositions[TEXTCMD_CMD(cmd) - kTextCmd_1];
+    vwf_flag_next_line = 1;
+    goto COMMAND_DONE;
+  case kTextCmd_Wait:  // RenderText_Draw_Wait
+    switch (joypad1L_last & 0x80 ? 1 : text_wait_countdown) {
+    case 0:
+      text_wait_countdown = kText_WaitDurations[TEXTCMD_PARAM(cmd)] - 1;
+      break;
+    case 1:
+      BYTE(text_wait_countdown) = 0;
+      goto COMMAND_DONE;
+    default:
+      text_wait_countdown--;
+      break;
+    }
+    break;
+  case kTextCmd_Sound:  // RenderText_Draw_PlaySfx
+    sound_effect_2 = TEXTCMD_PARAM(cmd);
+    goto COMMAND_DONE;
+  case kTextCmd_Speed:  // RenderText_Draw_SetSpeed
+    vwf_line_speed = vwf_line_speed_cur = TEXTCMD_PARAM(cmd);
+    goto COMMAND_DONE;
+  case kTextCmd_Waitkey:  // RenderText_Draw_PauseForInput
+    if (text_wait_countdown2 != 0) {
+      if (--text_wait_countdown2 == 1)
+        sound_effect_2 = 36;
+    } else {
+      if ((filtered_joypad_H | filtered_joypad_L) & 0xc0) {
+        text_wait_countdown2 = 28;
+        goto COMMAND_DONE;
+      }
+    }
+    break;
+  case kTextCmd_EndMessage:  // RenderText_Draw_Terminate
+    if (text_wait_countdown2 != 0) {
+      if (--text_wait_countdown2 == 1)
+        sound_effect_2 = 36;
+    } else {
+      if ((filtered_joypad_H | filtered_joypad_L)) {
+        text_render_state = 4;
+        text_wait_countdown2 = 28;
+      }
+    }
+    break;
+  }
+  if (0) COMMAND_DONE: {
+    dialogue_msg_read_pos += 1 + TEXTCMD_MULTIBYTE(cmd);
+  }
+  nmi_subroutine_index = 2;
+  nmi_disable_core_updates = 2;
+}
+
+void RenderText_Draw_Finish() {  // 8eca35
+  RenderText_DrawBorderInitialize();
+  uint16 *d = vram_upload_data;
+  d[0] = swap16(text_msgbox_topleft_copy);
+  d[1] = 0x2E42;
+  d[2] = 0x387F;
+  d[3] = 0xffff;
+  nmi_load_bg_from_vram = 1;
+  messaging_module = 0;
+  submodule_index = 0;
+  main_module_index = saved_module_for_menu;
+}
+
+void VWF_RenderSingle(int c) {  // 8ecab8
+  if (c != 0x59)
+    sound_effect_2 = 12;
+  vwf_line_speed_cur = vwf_line_speed;
+
+  if (vwf_flag_next_line) {
+    vwf_line_ptr = kVWF_RenderCharacter_renderPos[vwf_curline>>1];
+    vwf_var1 = kVWF_RenderCharacter_linePositions[vwf_curline>>1];
+    vwf_flag_next_line = 0;
+  }
+  
+  const uint8 *kFontData = FindIndexInMemblk(g_zenv.dialogue_font_blk, 0).ptr;
+  uint8 width = FindIndexInMemblk(g_zenv.dialogue_font_blk, 1).ptr[c];
+  assert(width <= 8);
+
+  int i = vwf_var1++;
+  uint8 arrval = vwf_arr[i];
+  vwf_arr[i + 1] = arrval + width;
+  uint16 r10 = (c & 0x70) * 2 + (c & 0xf);
+  uint16 r0 = arrval * 2;
+  const uint16 *src2 = (uint16*)(kFontData + r10 * 16);
+  uint8 *mbuf = (uint8 *)messaging_buf;
+  for (int i = 0; i != 16; i += 2) {
+    uint16 r4 = *src2++;
+    int y = r0 + vwf_line_ptr;
+    int x = (y & 0xff0) + i;
+    y = (y >> 1) & 7;
+    uint8 r3 = width;
+    do {
+      if (r4 & 0x0080)
+        mbuf[x + 0] ^= kVWF_RenderCharacter_setMasks[y];
+      else
+        mbuf[x + 0] &= ~kVWF_RenderCharacter_setMasks[y];
+      if (r4 & 0x8000)
+        mbuf[x + 1] ^= kVWF_RenderCharacter_setMasks[y];
+      else
+        mbuf[x + 1] &= ~kVWF_RenderCharacter_setMasks[y];
+      r4 = (r4 & ~0x8080) << 1;
+      //r4 <<= 1;
+    } while (--r3 && ++y != 8);
+    x += 16;
+    if (r4 != 0)
+      WORD(mbuf[x + 0]) = r4;
+  }
+  uint16 r8 = vwf_line_ptr + 0x150;
+  const uint16 *src3 = (uint16*)(kFontData + (r10 + 16) * 16);
+  for (int i = 0; i != 16; i += 2) {
+    uint16 r4 = *src3++;
+    int y = r8 + r0;
+    int x = (y & 0xff0) + i;
+    y = (y >> 1) & 7;
+    uint8 r3 = width;
+    do {
+      if (r4 & 0x0080)
+        mbuf[x + 0] ^= kVWF_RenderCharacter_setMasks[y];
+      else
+        mbuf[x + 0] &= ~kVWF_RenderCharacter_setMasks[y];
+      if (r4 & 0x8000)
+        mbuf[x + 1] ^= kVWF_RenderCharacter_setMasks[y];
+      else
+        mbuf[x + 1] &= ~kVWF_RenderCharacter_setMasks[y];
+      //r4 <<= 1;
+      r4 = (r4 & ~0x8080) << 1;
+    } while (--r3 && ++y != 8);
+    x += 16;
+    if (r4 != 0)
+      WORD(mbuf[x + 0]) = r4;
+  }
+}
+
+void RenderText_Draw_Choose2LowOr3() {  // 8ecd1a
+  if (text_wait_countdown2 != 0) {
+    if (--text_wait_countdown2 == 1)
+      sound_effect_2 = 36;
+  } else if ((filtered_joypad_H | filtered_joypad_L) & 0xc0) {
+    sound_effect_1 = 43;
+    text_render_state = 4;
+  } else if (filtered_joypad_H & 12) {
+    int t = filtered_joypad_H & 8 ? 0 : 1;
+    if (choice_in_multiselect_box == t)
+      return;
+    choice_in_multiselect_box = t;
+    sound_effect_2 = 32;
+    dialogue_message_index = t + 1;
+    Text_LoadCharacterBuffer();
+    Text_InitVwfState();
+  }
+}
+
+void RenderText_Draw_ChooseItem() {  // 8ecd88
+  if (text_wait_countdown2 != 0) {
+    if (--text_wait_countdown2 == 1)
+      RenderText_FindYItem_Next();
+  } else if ((filtered_joypad_H | filtered_joypad_L) & 0xc0) {
+    text_render_state = 4;
+  } else {
+    if (filtered_joypad_H & 5) {
+      choice_in_multiselect_box++;
+    } else if (filtered_joypad_H & 10) {
+      choice_in_multiselect_box--;
+      RenderText_FindYItem_Previous();
+      RenderText_Refresh();
+      return;
+    }
+    RenderText_FindYItem_Next();
+    RenderText_Refresh();
+  }
+}
+
+void RenderText_FindYItem_Previous() {  // 8ecdc8
+  for (;;) {
+    uint8 x = choice_in_multiselect_box;
+    if (sign8(x))
+      choice_in_multiselect_box = x = 31;
+    if (x != 15 && ((&link_item_bow)[x] || x == 32 && (&link_item_bow)[x + 1]))
+      break;
+    choice_in_multiselect_box--;
+  }
+  RenderText_DrawSelectedYItem();
+}
+
+void RenderText_FindYItem_Next() {  // 8ecded
+  for (;;) {
+    uint8 x = choice_in_multiselect_box;
+    if (x >= 32)
+      choice_in_multiselect_box = x = 0;
+    if (x != 15 && ((&link_item_bow)[x] || x == 32 && (&link_item_bow)[x + 1]))
+      break;
+    choice_in_multiselect_box++;
+  }
+  RenderText_DrawSelectedYItem();
+}
+
+void RenderText_DrawSelectedYItem() {  // 8ece14
+  int item = choice_in_multiselect_box;
+  const uint16 *p = Hud_GetItemBoxPtr(item);
+  p += ((item == 3 || item == 32) ? 1 : (&link_item_bow)[item]) * 4;
+  uint8 *vwf300 = &g_ram[0x1300];
+  memcpy(vwf300 + 0xc2, p, 4);
+  memcpy(vwf300 + 0xec, p + 2, 4);
+}
+
+void RenderText_Draw_Choose2HiOr3() {  // 8ece83
+  if (text_wait_countdown2 != 0) {
+    if (--text_wait_countdown2 == 1)
+      sound_effect_2 = 36;
+  } else if ((filtered_joypad_H | filtered_joypad_L) & 0xc0) {
+    sound_effect_1 = 43;
+    text_render_state = 4;
+  } else if (filtered_joypad_H & 12) {
+    int t = filtered_joypad_H & 8 ? 0 : 1;
+    if (choice_in_multiselect_box == t)
+      return;
+    choice_in_multiselect_box = t;
+    sound_effect_2 = 32;
+    dialogue_message_index = t + 11;
+    Text_LoadCharacterBuffer();
+    Text_InitVwfState();
+  }
+}
+
+void RenderText_Draw_Choose3() {  // 8ecef7
+  uint8 y;
+  if (text_wait_countdown2 != 0) {
+    if (--text_wait_countdown2 == 1)
+      sound_effect_2 = 36;
+  } else if ((y = filtered_joypad_L & 0xc0 | filtered_joypad_H) & 0xd0) {
+    sound_effect_1 = 43;
+    text_render_state = 4;
+  } else if (y & 12) {
+    int choice = choice_in_multiselect_box;
+    if (y & 8)
+      choice = (choice == 0) ? 2 : choice - 1;
+    else
+      choice = (choice == 2) ? 0 : choice + 1;
+    choice_in_multiselect_box = choice;
+    sound_effect_2 = 32;
+    dialogue_message_index = choice + 6;
+    Text_LoadCharacterBuffer();
+    Text_InitVwfState();
+  }
+}
+
+void RenderText_Draw_Choose1Or2() {  // 8ecf72
+  uint8 y;
+  if (text_wait_countdown2 != 0) {
+    if (--text_wait_countdown2 == 1)
+      sound_effect_2 = 36;
+  } else if ((y = filtered_joypad_L & 0xc0 | filtered_joypad_H) & 0xd0) {
+    sound_effect_1 = 43;
+    text_render_state = 4;
+  } else if (y & 12) {
+    int t = y & 8 ? 0 : 1;
+    if (choice_in_multiselect_box == t)
+      return;
+    choice_in_multiselect_box = t;
+    sound_effect_2 = 32;
+    dialogue_message_index = t + 9;
+    Text_LoadCharacterBuffer();
+    Text_InitVwfState();
+  }
+}
+
+bool RenderText_Draw_Scroll() {  // 8ecfe2
+  uint8 r2 = dialogue_scroll_speed;
+  do {
+    for (int i = 0; i < 0x7e0; i += 16) {
+      uint16 *p = (uint16 *)((uint8 *)messaging_buf + i);
+      p[0] = p[1];
+      p[1] = p[2];
+      p[2] = p[3];
+      p[3] = p[4];
+      p[4] = p[5];
+      p[5] = p[6];
+      p[6] = p[7];
+      p[7] = p[168];
+    }
+    uint16 *p = messaging_buf;
+    for (int i = 0x34f; i <= 0x3ef; i += 8)
+      p[i] = 0;
+
+    if ((++byte_7E1CDF & 0xf) == 0) {
+      vwf_curline = 4;
+      vwf_flag_next_line = 1;
+      return true;
+    }
+  } while (r2--);
+  return false;
+}
+
+void RenderText_SetDefaultWindowPosition() {  // 8ed280
+  uint16 y = link_y_coord - BG2VOFS_copy2;
+  int flag = (y < 0x78);
+  text_msgbox_topleft = kText_Positions[flag];
+}
+
+void RenderText_DrawBorderInitialize() {  // 8ed29c
+  text_msgbox_topleft_copy = text_msgbox_topleft;
+}
+
+uint16 *RenderText_DrawBorderRow(uint16 *d, int y) {  // 8ed2ab
+  y >>= 1;
+  *d++ = swap16(text_msgbox_topleft_copy);
+  text_msgbox_topleft_copy += 0x20;
+  *d++ = 0x2F00;
+  *d++ = kText_BorderTiles[y];
+  for(int i = 0; i < 22; i++)
+    *d++ = kText_BorderTiles[y+1];
+  *d++ = kText_BorderTiles[y+2];
+  *d = 0xffff;
+  return d;
+}
+
+void Text_BuildCharacterTilemap() {  // 8ed2ec
+  uint16 *vwf300 = (uint16 *)&g_ram[0x1300];
+  for (int i = 0; i < 126; i++)
+    vwf300[i] = text_tilemap_cur++;
+  RenderText_Refresh();
+}
+
+void RenderText_Refresh() {  // 8ed307
+  RenderText_DrawBorderInitialize();
+  text_msgbox_topleft_copy += 0x21;
+  uint16 *d = vram_upload_data;
+  uint16 *s = (uint16 *)&g_ram[0x1300];
+  for (int j = 0; j != 6; j++) {
+    *d++ = swap16(text_msgbox_topleft_copy);
+    text_msgbox_topleft_copy += 0x20;
+    *d++ = 0x2900;
+    for (int i = 0; i != 21; i++)
+      *d++ = *s++;
+  }
+  *d = 0xffff;
+  nmi_load_bg_from_vram = 1;
+}
+
+
+void Text_GenerateMessagePointers() {  // 8ed3eb
+  // This is not actually used. Only for ram compat.
+  MemBlk dialogue = FindIndexInMemblk(g_zenv.dialogue_blk, 1);
+  uint32 p = 0x1c8000;
+  uint8 *dst = kTextDialoguePointers;
+  for (int i = 0; i < 398; i++) {
+    if (i == 359)
+      p = 0xedf40;
+    WORD(dst[0]) = p;
+    dst[2] = p >> 16;
+    dst += 3;
+    p += (uint32)FindIndexInMemblk(dialogue, i).size + 1;
+  }
+}
+
+void DungMap_LightenUpMap() {  // 8ed940
+  if (++INIDISP_copy == 0xf)
+    overworld_map_state++;
+}
+
+void DungMap_Backup() {  // 8ed94c
+  if (--INIDISP_copy)
+    return;
+  MOSAIC_copy = 3;
+  mapbak_HDMAEN = HDMAEN_copy;
+  EnableForceBlank();
+  overworld_map_state++;
+  dungmap_init_state = 0;
+  COLDATA_copy0 = 0x20;
+  COLDATA_copy1 = 0x40;
+  COLDATA_copy2 = 0x80;
+  link_dma_graphics_index = 0x250;
+  memcpy(mapbak_palette, main_palette_buffer, sizeof(uint16) * 256);
+  mapbak_bg1_x_offset = bg1_x_offset;
+  mapbak_bg1_y_offset = bg1_y_offset;
+  bg1_x_offset = 0;
+  bg1_y_offset = 0;
+  mapbak_BG1HOFS_copy2 = BG1HOFS_copy2;
+  mapbak_BG2HOFS_copy2 = BG2HOFS_copy2;
+  mapbak_BG1VOFS_copy2 = BG1VOFS_copy2;
+  mapbak_BG2VOFS_copy2 = BG2VOFS_copy2;
+  BG1HOFS_copy2 = BG1VOFS_copy2 = 0;
+  BG2HOFS_copy2 = BG2VOFS_copy2 = 0;
+  BG3HOFS_copy2 = BG3VOFS_copy2 = 0;
+  mapbak_CGWSEL = WORD(CGWSEL_copy);
+  CGWSEL_copy = 0x02;
+  CGADSUB_copy = 0x20;
+  for (int i = 0; i < 2048; i++)
+    messaging_buf[i] = 0x300;
+  sound_effect_2 = 16;
+  music_control = 0xf2;
+}
+
+void DungMap_FadeMapToBlack() {  // 8eda37
+  if (--INIDISP_copy)
+    return;
+  EnableForceBlank();
+  overworld_map_state++;
+  WORD(CGWSEL_copy) = mapbak_CGWSEL;
+  BG1HOFS_copy2 =  mapbak_BG1HOFS_copy2;
+  BG2HOFS_copy2 =  mapbak_BG2HOFS_copy2;
+  BG1VOFS_copy2 =  mapbak_BG1VOFS_copy2;
+  BG2VOFS_copy2 =  mapbak_BG2VOFS_copy2;
+  BG3VOFS_copy2 = BG3HOFS_copy2 = 0;
+  bg1_x_offset = mapbak_bg1_x_offset;
+  bg1_y_offset = mapbak_bg1_y_offset;
+  flag_update_cgram_in_nmi++;
+}
+
+void DungMap_RestoreOld() {  // 8eda79
+  OrientLampLightCone();
+  if (++INIDISP_copy != 0xf)
+    return;
+  main_module_index = saved_module_for_menu;
+  submodule_index = 0;
+  overworld_map_state = 0;
+  subsubmodule_index = 0;
+  INIDISP_copy = 0xf;
+  HDMAEN_copy = mapbak_HDMAEN;
+}
+
+void Death_PlayerSwoon() {  // 8ff5e3
+  int k = link_var30d;
+  if (sign8(--some_animation_timer)) {
+    k++;
+    if (k == 15)
+      return;
+    if (k == 14)
+      submodule_index++;
+    link_var30d = k;
+    some_animation_timer_steps = kDeath_AnimCtr0[k];
+    some_animation_timer = kDeath_AnimCtr1[k];
+  }
+  if (k != 13 || link_visibility_status == 12)
+    return;
+  uint8 y = link_y_coord + 16 - BG2VOFS_copy2;
+  uint8 x = link_x_coord + 7 - BG2HOFS_copy2;
+  SetOamPlain(&oam_buf[0x74], x, y, 0xaa, kDeath_SprFlags[link_is_on_lower_level] | 2, 2);
+}
+
+void Death_PrepFaint() {  // 8ffa6f
+  link_direction_facing = 2;
+  player_unk1 = 1;
+  link_var30d = 0;
+  some_animation_timer_steps = 0;
+  some_animation_timer = 5;
+  link_hearts_filler = 0;
+  link_health_current = 0;
+  Link_ResetProperties_C();
+  player_on_somaria_platform = 0;
+  draw_water_ripples_or_grass = 0;
+  link_is_bunny_mirror = 0;
+  bitmask_of_dragstate = 0;
+  flag_is_ancilla_to_pick_up = 0;
+  link_auxiliary_state = 0;
+  link_incapacitated_timer = 0;
+  link_give_damage = 0;
+  link_is_transforming = 0;
+  link_speed_setting = 0;
+  link_need_for_poof_for_transform = 0;
+  if (link_item_moon_pearl)
+    link_is_bunny = 0;
+  link_timer_tempbunny = 0;
+  //bugfix: dying as permabunny doesn't restore link palette during death animation
+  if (enhanced_features0 & kFeatures0_MiscBugFixes)
+    LoadActualGearPalettes();
+  sound_effect_1 = 0x27 | Link_CalculateSfxPan();
+  for (int i = 0; i != 4; i++) {
+    if (link_bottle_info[i] == 6)
+      return;
+  }
+  index_of_changable_dungeon_objs[0] = index_of_changable_dungeon_objs[1] = 0;
+}
+
+
+
+void DisplaySelectMenu() {
+  choice_in_multiselect_box_bak = choice_in_multiselect_box;
+  dialogue_message_index = 0x186;
+  uint8 bak = main_module_index;
+  Main_ShowTextMessage();
+  main_module_index = bak;
+  subsubmodule_index = 0;
+  submodule_index = 11;
+  saved_module_for_menu = main_module_index;
+  main_module_index = 14;
+}
--- /dev/null
+++ b/src/messaging.h
@@ -1,0 +1,133 @@
+#pragma once
+#include "types.h"
+
+const uint8 *GetDungmapFloorLayout();
+uint8 GetOtherDungmapInfo(int count);
+void DungMap_4();
+void Module_Messaging_6();
+void OverworldMap_SetupHdma();
+const uint8 *GetLightOverworldTilemap();
+void SaveGameFile();
+void TransferMode7Characters();
+void Module0E_Interface();
+void Module_Messaging_0();
+void Module0E_05_DesertPrayer();
+void Module0E_04_RedPotion();
+void Module0E_08_GreenPotion();
+void Module0E_09_BluePotion();
+void Module0E_0B_SaveMenu();
+void Module1B_SpawnSelect();
+void CleanUpAndPrepDesertPrayerHDMA();
+void DesertPrayer_InitializeIrisHDMA();
+void DesertPrayer_BuildIrisHDMATable();
+Pair16U DesertHDMA_CalculateIrisShapeLine();
+void Animate_GAMEOVER_Letters();
+void GameOverText_SweepLeft();
+void GameOverText_UnfurlRight();
+void Module12_GameOver();
+void GameOver_AdvanceImmediately();
+void Death_Func1();
+void GameOver_DelayBeforeIris();
+void GameOver_IrisWipe();
+void GameOver_SplatAndFade();
+void Death_Func6();
+void Death_Func4();
+void Animate_GAMEOVER_Letters_bounce();
+void GameOver_Finalize_GAMEOVR();
+void GameOver_SaveAndOrContinue();
+void Death_Func15(bool count_as_death);
+void GameOver_AnimateChoiceFairy();
+void GameOver_InitializeRevivalFairy();
+void RevivalFairy_Main_bounce();
+void GameOver_RiseALittle();
+void GameOver_Restore0D();
+void GameOver_Restore0E();
+void GameOver_ResituateLink();
+void Module0E_0A_FluteMenu();
+void FluteMenu_HandleSelection();
+void FluteMenu_LoadSelectedScreen();
+void Overworld_LoadOverlayAndMap();
+void FluteMenu_FadeInAndQuack();
+void BirdTravel_Finish_Doit();
+void Messaging_OverworldMap();
+void WorldMap_FadeOut();
+void WorldMap_LoadLightWorldMap();
+void WorldMap_LoadDarkWorldMap();
+void WorldMap_LoadSpriteGFX();
+void WorldMap_Brighten();
+void WorldMap_PlayerControl();
+void WorldMap_RestoreGraphics();
+void Attract_SetUpConclusionHDMA();
+void WorldMap_ExitMap();
+void WorldMap_SetUpHDMA();
+void WorldMap_FillTilemapWithEF();
+void WorldMap_HandleSprites();
+bool OverworldMap_CheckForPendant(int k);
+bool OverworldMap_CheckForCrystal(int k);
+void Module0E_03_DungeonMap();
+void Module0E_03_01_DrawMap();
+void Module0E_03_01_00_PrepMapGraphics();
+void Module0E_03_01_01_DrawLEVEL();
+void Module0E_03_01_02_DrawFloorsBackdrop();
+void DungeonMap_BuildFloorListBoxes(uint8 t5, uint16 r14);
+void Module0E_03_01_03_DrawRooms();
+void DungeonMap_DrawBorderForRooms(uint16 pd, uint16 mask);
+void DungeonMap_DrawFloorNumbersByRoom(uint16 pd, uint16 r8);
+void DungeonMap_DrawDungeonLayout(int pd);
+void DungeonMap_DrawSingleRowOfRooms(int i, int arg_x);
+void DungeonMap_DrawRoomMarkers();
+void DungeonMap_HandleInputAndSprites();
+void DungeonMap_HandleInput();
+void DungeonMap_HandleMovementInput();
+void DungeonMap_HandleFloorSelect();
+void DungeonMap_ScrollFloors();
+void DungeonMap_DrawSprites();
+void DungeonMap_DrawLinkPointing(int spr_pos, uint8 r2, uint8 r3);
+int DungeonMap_DrawBlinkingIndicator(int spr_pos);
+int DungeonMap_DrawLocationMarker(int spr_pos, uint16 r14);
+int DungeonMap_DrawFloorNumberObjects(int spr_pos);
+void DungeonMap_DrawFloorBlinker();
+int DungeonMap_DrawBossIcon(int spr_pos);
+int DungeonMap_DrawBossIconByFloor(int spr_pos);
+void DungeonMap_RecoverGFX();
+void ToggleStarTilesAndAdvance();
+void Death_InitializeGameOverLetters();
+void CopySaveToWRAM();
+void RenderText();
+void RenderText_PostDeathSaveOptions();
+void Text_Initialize();
+void Text_Initialize_initModuleStateLoop();
+void Text_InitVwfState();
+void Text_LoadCharacterBuffer();
+uint8 *Text_WritePlayerName(uint8 *p);
+uint8 Text_FilterPlayerNameCharacters(uint8 a);
+void Text_Render();
+void RenderText_Draw_Border();
+void RenderText_Draw_BorderIncremental();
+void RenderText_Draw_CharacterTilemap();
+void RenderText_Draw_MessageCharacters();
+void RenderText_Draw_Finish();
+void VWF_RenderSingle();
+void RenderText_Draw_Choose2LowOr3();
+void RenderText_Draw_ChooseItem();
+void RenderText_FindYItem_Previous();
+void RenderText_FindYItem_Next();
+void RenderText_DrawSelectedYItem();
+void RenderText_Draw_Choose2HiOr3();
+void RenderText_Draw_Choose3();
+void RenderText_Draw_Choose1Or2();
+bool RenderText_Draw_Scroll();
+void RenderText_SetDefaultWindowPosition();
+void RenderText_DrawBorderInitialize();
+uint16 *RenderText_DrawBorderRow(uint16 *d, int y);
+void Text_BuildCharacterTilemap();
+void RenderText_Refresh();
+void Text_GenerateMessagePointers();
+void DungMap_LightenUpMap();
+void DungMap_Backup();
+void DungMap_FadeMapToBlack();
+void DungMap_RestoreOld();
+void Death_PlayerSwoon();
+void Death_PrepFaint();
+void DisplaySelectMenu();
+bool DidPressButtonForMap();
--- /dev/null
+++ b/src/misc.c
@@ -1,0 +1,960 @@
+#include "misc.h"
+#include "variables.h"
+#include "hud.h"
+#include "dungeon.h"
+#include "overworld.h"
+#include "load_gfx.h"
+#include "sprite.h"
+#include "poly.h"
+#include "ancilla.h"
+#include "select_file.h"
+#include "tile_detect.h"
+#include "player.h"
+#include "player_oam.h"
+#include "messaging.h"
+#include "ending.h"
+#include "attract.h"
+#include "snes/snes_regs.h"
+#include "assets.h"
+
+static void KillAgahnim_LoadMusic();
+static void KillAghanim_Init();
+static void KillAghanim_Func2();
+static void KillAghanim_Func3();
+static void KillAghanim_Func4();
+static void KillAghanim_Func5();
+static void KillAghanim_Func6();
+static void KillAghanim_Func7();
+static void KillAghanim_Func8();
+static void KillAghanim_Func12();
+static uint8 PlaySfx_SetPan(uint8 a);
+
+const uint8 kReceiveItem_Tab1[76] = {
+  0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0, 2, 2, 2,
+  2, 2, 2, 0, 2, 0, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2,
+  2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2,
+  2, 2, 2, 2, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+  2, 2, 0, 0, 2, 0, 2, 2, 2, 0, 2, 2,
+};
+static const int8 kReceiveItem_Tab2[76] = {
+  -5, -5, -5, -5, -5, -4, -4, -5, -5, -4, -4, -4, -2, -4, -4, -4,
+  -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4,
+  -4, -4, -4, -5, -4, -4, -4, -4, -4, -4, -2, -4, -4, -4, -4, -4,
+  -4, -4, -4, -4, -2, -2, -2, -4, -4, -4, -4, -4, -4, -4, -4, -4,
+  -4, -4, -2, -2, -4, -2, -4, -4, -4, -5, -4, -4,
+};
+static const uint8 kReceiveItem_Tab3[76] = {
+  4, 4, 4, 4, 4, 0, 0, 4, 4, 4, 4, 4, 5, 0, 0, 0,
+  0, 0, 0, 4, 0, 4, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 4, 4, 0, 4, 0, 0, 0, 4, 0, 0,
+};
+const uint8 kReceiveItemGfx[76] = {
+  6, 0x18, 0x18, 0x18, 0x2d, 0x20, 0x2e,    9,    9,  0xa,    8,    5, 0x10,  0xb, 0x2c, 0x1b,
+  0x1a, 0x1c, 0x14, 0x19,  0xc,    7, 0x1d, 0x2f,    7, 0x15, 0x12,  0xd,  0xd,  0xe, 0x11, 0x17,
+  0x28, 0x27,    4,    4,  0xf, 0x16,    3, 0x13,    1, 0x1e, 0x10,    0,    0,    0,    0,    0,
+  0, 0x30, 0x22, 0x21, 0x24, 0x24, 0x24, 0x23, 0x23, 0x23, 0x29, 0x2a, 0x2c, 0x2b,    3,    3,
+  0x34, 0x35, 0x31, 0x33,    2, 0x32, 0x36, 0x37, 0x2c,    6,  0xc, 0x38,
+};
+const uint16 kMemoryLocationToGiveItemTo[76] = {
+  0xf359, 0xf359, 0xf359, 0xf359,
+  0xf35a, 0xf35a, 0xf35a, 0xf345,
+  0xf346, 0xf34b, 0xf342, 0xf340,
+  0xf341, 0xf344, 0xf35c, 0xf347,
+  0xf348, 0xf349, 0xf34a, 0xf34c,
+  0xf34c, 0xf350, 0xf35c, 0xf36b,
+  0xf351, 0xf352, 0xf353, 0xf354,
+  0xf354, 0xf34e, 0xf356, 0xf357,
+  0xf37a, 0xf34d, 0xf35b, 0xf35b,
+  0xf36f, 0xf364, 0xf36c, 0xf375,
+  0xf375, 0xf344, 0xf341, 0xf35c,
+  0xf35c, 0xf35c, 0xf36d, 0xf36e,
+  0xf36e, 0xf375, 0xf366, 0xf368,
+  0xf360, 0xf360, 0xf360, 0xf374,
+  0xf374, 0xf374, 0xf340, 0xf340,
+  0xf35c, 0xf35c, 0xf36c, 0xf36c,
+  0xf360, 0xf360, 0xf372, 0xf376,
+  0xf376, 0xf373, 0xf360, 0xf360,
+  0xf35c, 0xf359, 0xf34c, 0xf355,
+};
+static const int8 kValueToGiveItemTo[76] = {
+     1,   2,   3,  4,
+     1,   2,   3,  1,
+     1,   1,   1,  1,
+     1,   2,  -1,  1,
+     1,   1,   1,  1,
+     2,   1,  -1, -1,
+     1,   1,   2,  1,
+     2,   1,   1,  1,
+    -1,   1,  -1,  2,
+    -1,  -1,  -1, -1,
+    -1,  -1,   2, -1,
+    -1,  -1,  -1, -1,
+    -1,  -1,  -1, -1,
+    -1,  -5, -20, -1,
+    -1,  -1,   1,  3,
+    -1,  -1,  -1, -1,
+  -100, -50,  -1,  1,
+    10,  -1,  -1, -1,
+    -1,   1,   3,  1,
+};
+static const uint8 kDungeon_DefaultAttr[384] = {
+  1, 1, 1, 0, 2, 1, 2, 0, 1, 1, 2, 2, 2, 2, 2, 2,
+  2, 2, 2, 0, 0, 1, 0, 0, 2, 0, 0, 2, 2, 2, 2, 2,
+  2, 2, 2, 2, 1, 1, 1, 2, 2, 2, 2, 2, 1, 1, 0, 0,
+  2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 1, 1, 0, 0,
+  0, 0, 0, 0x2a, 1, 0x20, 1, 1, 4, 1, 1, 0x18, 1, 2, 0x1c, 1,
+  0x28, 0x28, 0x2a, 0x2a, 1, 2, 1, 1, 4, 0, 0, 0, 0x28, 1, 0xa, 0,
+  1, 1, 0xc, 0xc, 2, 2, 2, 2, 0x28, 0x2a, 0x20, 0x20, 0x20, 2, 8, 0,
+  4, 4, 1, 1, 1, 2, 2, 2, 0, 0, 0x20, 0x20, 0, 2, 0, 0,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0x18, 0x10, 0x10, 1, 1, 1,
+  1, 1, 4, 4, 4, 4, 4, 4, 1, 2, 2, 0, 0, 0, 0, 0,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x62, 0x62,
+  0, 0, 0x24, 0x24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x62, 0x62,
+  0x27, 2, 2, 2, 0x27, 0x27, 1, 0, 0, 0, 0, 0x24, 0, 0, 0, 0,
+  0x27, 0x27, 0x27, 0x27, 0x27, 0x10, 2, 1, 0, 0, 0, 0x24, 0, 0, 0, 0,
+  0x27, 2, 2, 2, 0x27, 0x27, 0x27, 0x27, 2, 2, 2, 0x24, 0, 0, 0, 0,
+  0x27, 0x27, 0x27, 0x27, 0x27, 0x20, 2, 2, 1, 2, 2, 0x23, 2, 0, 0, 0,
+  0x27, 0x27, 0x27, 0x27, 0x27, 0x20, 2, 0x27, 2, 0x54, 0, 0, 0x27, 2, 2, 2,
+  0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 2, 0x27, 2, 0x54, 0, 0, 0x27, 2, 2, 2,
+  0x27, 0x27, 0, 0x27, 0x60, 0x60, 1, 1, 1, 1, 2, 2, 0xd, 0, 0, 0x4b,
+  0x67, 0x67, 0x67, 0x67, 0x66, 0x66, 0x66, 0x66, 0, 0, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x27, 0x63, 0x27, 0x55, 0x55, 1, 0x44, 0, 1, 0x20, 2, 2, 0x1c, 0x3a, 0x3b, 0,
+  0x27, 0x63, 0x27, 0x53, 0x53, 1, 0x44, 1, 0xd, 0, 0, 0, 9, 9, 9, 9,
+};
+static PlayerHandlerFunc *const kModule_BossVictory[6] = {
+  &BossVictory_Heal,
+  &Dungeon_StartVictorySpin,
+  &Dungeon_RunVictorySpin,
+  &Dungeon_CloseVictorySpin,
+  &Dungeon_PrepExitWithSpotlight,
+  &Spotlight_ConfigureTableAndControl,
+};
+static PlayerHandlerFunc *const kModule_KillAgahnim[13] = {
+  &KillAgahnim_LoadMusic,
+  &KillAghanim_Init,
+  &KillAghanim_Func2,
+  &KillAghanim_Func3,
+  &KillAghanim_Func4,
+  &KillAghanim_Func5,
+  &KillAghanim_Func6,
+  &KillAghanim_Func7,
+  &KillAghanim_Func8,
+  &BossVictory_Heal,
+  &Dungeon_StartVictorySpin,
+  &Dungeon_RunVictorySpin,
+  &KillAghanim_Func12,
+};
+static PlayerHandlerFunc *const kMainRouting[28] = {
+  &Module00_Intro,
+  &Module01_FileSelect,
+  &Module02_CopyFile,
+  &Module03_KILLFile,
+  &Module04_NameFile,
+  &Module05_LoadFile,
+  &Module_PreDungeon,
+  &Module07_Dungeon,
+  &Module08_OverworldLoad,
+  &Module09_Overworld,
+  &Module08_OverworldLoad,
+  &Module09_Overworld,
+  &Module_Unknown0,
+  &Module_Unknown1,
+  &Module0E_Interface,
+  &Module0F_SpotlightClose,
+  &Module10_SpotlightOpen,
+  &Module11_DungeonFallingEntrance,
+  &Module12_GameOver,
+  &Module13_BossVictory_Pendant,
+  &Module14_Attract,
+  &Module15_MirrorWarpFromAga,
+  &Module16_BossVictory_Crystal,
+  &Module17_SaveAndQuit,
+  &Module18_GanonEmerges,
+  &Module19_TriforceRoom,
+  &Module1A_Credits,
+  &Module1B_SpawnSelect,
+};
+
+const uint16 *SrcPtr(uint16 src) {
+  return &kPredefinedTileData[src >> 1];
+}
+
+uint8 Ancilla_Sfx2_Near(uint8 a) {
+  return sound_effect_1 = PlaySfx_SetPan(a);
+}
+
+void Ancilla_Sfx3_Near(uint8 a) {
+  sound_effect_2 = PlaySfx_SetPan(a);
+}
+
+void LoadDungeonRoomRebuildHUD() {
+  mosaic_level = 0;
+  MOSAIC_copy = 7;
+  Hud_SearchForEquippedItem();
+  Hud_Rebuild();
+  Hud_UpdateEquippedItem();
+  Module_PreDungeon();
+}
+
+void Module_Unknown0() {
+  assert(0);
+}
+
+void Module_Unknown1() {
+  assert(0);
+}
+
+static void KillAgahnim_LoadMusic() {
+  nmi_disable_core_updates = 0;
+  overworld_map_state++;
+  submodule_index++;
+  LoadOWMusicIfNeeded();
+}
+
+static void KillAghanim_Init() {
+  music_control = 8;
+  BYTE(overworld_screen_trans_dir_bits) = 8;
+  InitializeMirrorHDMA();
+  overworld_map_state = 0;
+  PaletteFilter_InitializeWhiteFilter();
+  Overworld_LoadGFXAndScreenSize();
+  submodule_index++;
+  link_player_handler_state = kPlayerState_Mirror;
+  bg1_x_offset = 0;
+  bg1_y_offset = 0;
+  dung_savegame_state_bits = 0;
+  WORD(link_y_vel) = 0;
+  main_palette_buffer[0] = 0x7fff;
+  main_palette_buffer[32] = 0x7fff;
+  Ancilla_TerminateSelectInteractives(0);
+  Link_ResetProperties_A();
+}
+
+static void KillAghanim_Func2() {
+  HDMAEN_copy = 192;
+  MirrorWarp_BuildWavingHDMATable();
+  submodule_index++;
+  subsubmodule_index = 0;
+}
+
+static void KillAghanim_Func3() {
+  MirrorWarp_BuildWavingHDMATable();
+  if (subsubmodule_index) {
+    subsubmodule_index = 0;
+    submodule_index++;
+  }
+}
+
+static void KillAghanim_Func4() {
+  MirrorWarp_BuildDewavingHDMATable();
+  if (subsubmodule_index) {
+    subsubmodule_index = 0;
+    submodule_index++;
+  }
+}
+
+static void KillAghanim_Func5() {
+  HdmaSetup(0, 0xf2fb, 0x41, 0, (uint8)WH0, 0);
+  for (int i = 0; i < 240; i++)
+    hdma_table_dynamic[i] = 0xff00;
+  palette_filter_countdown = 0;
+  darkening_or_lightening_screen = 0;
+  dialogue_message_index = 0x35;
+  Main_ShowTextMessage();
+  ReloadPreviouslyLoadedSheets();
+  Hud_RebuildIndoor();
+  HDMAEN_copy = 0x80;
+  main_module_index = 21;
+  submodule_index = 6;
+  subsubmodule_index = 24;
+}
+
+static void KillAghanim_Func6() {
+  if (!--subsubmodule_index) {
+    submodule_index++;
+    sound_effect_ambient = 9;
+  }
+}
+
+static void KillAghanim_Func7() {
+  RenderText();
+  if (!submodule_index) {
+    overworld_map_state = 0;
+    sound_effect_ambient = 5;
+    if (!link_item_moon_pearl) {
+      dialogue_message_index = 0x36;
+      Main_ShowTextMessage();
+      sound_effect_ambient = 0;
+      main_module_index = 21;
+      submodule_index = 8;
+    } else {
+      submodule_index = 9;
+    }
+  }
+}
+
+static void KillAghanim_Func8() {
+  RenderText();
+  if (!submodule_index) {
+    subsubmodule_index = 32;
+    submodule_index = 12;
+  }
+}
+
+static void KillAghanim_Func12() {
+  if (--subsubmodule_index)
+    return;
+  ResetAncillaAndCutscene();
+  Overworld_SetSongList();
+  save_ow_event_info[0x1b] |= 32;
+  BYTE(cur_palace_index_x2) = 255;
+  submodule_index = 0;
+  overworld_map_state = 0;
+  nmi_disable_core_updates = 0;
+  main_module_index = 9;
+  BYTE(BG1VOFS_copy2) = 0;
+  music_control = link_item_moon_pearl ? 9 : 4;
+  savegame_map_icons_indicator = 6;
+}
+
+void Module_MainRouting() {  // 8080b5
+  kMainRouting[main_module_index]();
+}
+
+void NMI_PrepareSprites() {  // 8085fc
+  static const uint16 kLinkDmaSources1[303] = {
+    0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x8040, 0x8040, 0x8040, 0x8040, 0x8040, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000,
+    0x9440, 0x8080, 0x8080, 0x8080, 0x9400, 0x8040, 0x80c0, 0x80c0, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000,
+    0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x8040, 0x8040, 0x8040, 0x8040, 0x8040, 0x8000, 0xa8c0, 0xa900, 0x8000, 0xa8c0, 0xa900,
+    0x9100, 0x8080, 0x8080, 0x90c0, 0x8040, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x9a00, 0x9140, 0x9180, 0x8000, 0x9500,
+    0x9480, 0x94c0, 0x94c0, 0x9ae0, 0x8080, 0x8080, 0x9a60, 0x80c0, 0x80c0, 0x9aa0, 0x8000, 0x8000, 0x9aa0, 0x8000, 0x8000, 0x8080,
+    0x8080, 0x8100, 0x8100, 0x85c0, 0x8000, 0x8000, 0x85c0, 0x8000, 0x8000, 0xadc0, 0xadc0, 0xadc0, 0xadc0, 0xadc0, 0xad40, 0xad40,
+    0xad40, 0xad40, 0xad40, 0xad80, 0xad80, 0xad80, 0xad80, 0xad80, 0xad80, 0x8040, 0x9400, 0x8040, 0x8000, 0x8080, 0x8080, 0x9440,
+    0x8000, 0x8000, 0x8000, 0x8000, 0x8080, 0x8040, 0x8040, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0xc440, 0x8140, 0x8140,
+    0xca40, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8040, 0x85c0, 0x8040, 0x85c0, 0x8100, 0x80c0, 0x91c0, 0x8080, 0x8080,
+    0x8040, 0x8040, 0x8000, 0x8000, 0x8000, 0x8000, 0x8080, 0x8080, 0x9100, 0xa0c0, 0xa100, 0xa100, 0xa1c0, 0xa400, 0xa440, 0xa1c0,
+    0xa400, 0xa440, 0x8080, 0xc480, 0x8080, 0x8040, 0x8040, 0xca80, 0xca80, 0xca00, 0xc400, 0xca00, 0xc400, 0x81c0, 0x8080, 0x8080,
+    0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x8040, 0x8040, 0x8040, 0x8040, 0x8040, 0x8040, 0x8040, 0x8000, 0xa8c0, 0xa900,
+    0x8000, 0x8000, 0xa8c0, 0xa900, 0x8000, 0xa8c0, 0xa900, 0x8000, 0x8000, 0xa8c0, 0xa900, 0x8040, 0x8040, 0x8040, 0x8080, 0x8080,
+    0x8040, 0x8040, 0x8040, 0x8040, 0x8000, 0x8000, 0x8000, 0x8000, 0xd080, 0x8080, 0x90c0, 0xd000, 0x9080, 0xd040, 0x9080, 0xd040,
+    0xd080, 0xd080, 0xd080, 0xd080, 0xd080, 0xd000, 0xd000, 0xd000, 0xd000, 0xd000, 0xd040, 0xd040, 0xd040, 0xd040, 0xd040, 0xd040,
+    0x8040, 0xd000, 0x85c0, 0x85c0, 0x85c0, 0xdc40, 0xdc40, 0xdc40, 0x85c0, 0x85c0, 0x85c0, 0xdc40, 0xdc40, 0xdc40, 0xe1c0, 0xd000,
+    0x8000, 0xe400, 0xe400, 0xe440, 0x90c0, 0x90c0, 0xd000, 0x8000, 0x8000, 0xd040, 0x8000, 0x8000, 0xd040, 0xe400, 0xe400, 0xe400,
+    0x9080, 0xa5c0, 0xac40, 0xe480, 0x8180, 0x90c0, 0x80c0, 0xe180, 0xd000, 0xe4c0, 0xe4c0, 0xe840, 0xe840, 0xe840, 0xe540, 0xe540,
+    0xe540, 0xe900, 0xe900, 0xe900, 0xe900, 0x8080, 0x8080, 0x8000, 0xa9c0, 0x8080, 0x8140, 0x91c0, 0x8040, 0xa800, 0xa840,
+  };
+  static const uint16 kLinkDmaSources2[303] = {
+    0x8840, 0x8800, 0x8580, 0x8800, 0x8580, 0x84c0, 0x8500, 0x8540, 0x8500, 0x8540, 0x8400, 0x8440, 0x8480, 0x8400, 0x8440, 0x8480,
+    0x9640, 0x8c40, 0x8c80, 0xad00, 0x9600, 0x8980, 0x8c00, 0xacc0, 0x8880, 0x88c0, 0x8900, 0x8940, 0x8880, 0x88c0, 0x8900, 0x8940,
+    0xb0c0, 0xb100, 0xb140, 0xb100, 0xb140, 0xb000, 0xb040, 0xb080, 0xec80, 0xecc0, 0xb180, 0xd440, 0xb1c0, 0xb180, 0xd440, 0xb1c0,
+    0x8c80, 0xad00, 0x95c0, 0x99c0, 0xb440, 0x9580, 0xb480, 0xb4c0, 0x9580, 0xb480, 0xb4c0, 0x9c20, 0x8000, 0x8000, 0x8000, 0x9700,
+    0x9680, 0x96c0, 0x96c0, 0x9ce0, 0x8c80, 0xb540, 0x9c60, 0xb580, 0x8c00, 0x9ca0, 0x8900, 0xb500, 0x9ca0, 0x8900, 0xb500, 0x8c40,
+    0xec40, 0x8c00, 0xec00, 0x8dc0, 0x9540, 0x89c0, 0x8dc0, 0x9540, 0x89c0, 0xb940, 0xb980, 0xb9c0, 0xb980, 0xb9c0, 0xb5c0, 0xb800,
+    0xb840, 0xb800, 0xb840, 0xb880, 0xb8c0, 0xb900, 0xb880, 0xb8c0, 0xb900, 0x8980, 0x9600, 0xbcc0, 0x8400, 0xbc80, 0x8c40, 0x9640,
+    0xa040, 0xa080, 0xa000, 0xbc40, 0xbd40, 0x8500, 0xbd00, 0xbd80, 0xbd80, 0x88c0, 0x8900, 0xe9c0, 0x8900, 0xc640, 0xc040, 0xc000,
+    0xcc40, 0x8940, 0x88c0, 0x8900, 0xe9c0, 0x8900, 0x8940, 0x8d40, 0x8d80, 0x8d40, 0x8d80, 0xbd00, 0xb000, 0xb000, 0xa480, 0xa480,
+    0xa480, 0xa480, 0xac00, 0xac00, 0xac00, 0xac00, 0xa140, 0xa180, 0xa180, 0xa4c0, 0xa4c0, 0xa500, 0x9d40, 0x9d80, 0x9dc0, 0x9d40,
+    0x9d80, 0x9dc0, 0x8d00, 0xc680, 0xc180, 0xc140, 0x8c00, 0xcc80, 0xcc80, 0xcc00, 0xc600, 0xcc00, 0xc600, 0xbd00, 0x8580, 0x8800,
+    0xc9c0, 0xccc0, 0xcdc0, 0xcd00, 0xcd40, 0xcd80, 0x8500, 0x8540, 0xc940, 0xc980, 0x8540, 0xc940, 0xc980, 0x8440, 0x8480, 0xc1c0,
+    0xc900, 0xc580, 0xc5c0, 0xc8c0, 0x8440, 0x8480, 0xc1c0, 0xc900, 0xc580, 0xc5c0, 0xc8c0, 0xbd00, 0xacc0, 0xc040, 0xd540, 0xd580,
+    0xd4c0, 0xd500, 0xd4c0, 0xd500, 0xd440, 0xd480, 0xd440, 0xd480, 0xd1c0, 0xd400, 0xd100, 0xd100, 0xd140, 0xd180, 0xd140, 0xd180,
+    0xb0c0, 0xb100, 0xb140, 0xb100, 0xb140, 0xdd40, 0xdd80, 0xddc0, 0xdd80, 0xddc0, 0xdc80, 0xdcc0, 0xdd00, 0xdc80, 0xdcc0, 0xdd00,
+    0xd100, 0xd100, 0xe000, 0xe040, 0xe080, 0xe0c0, 0xe100, 0xe140, 0xe000, 0xe040, 0xe080, 0xe0c0, 0xe100, 0xe140, 0x8000, 0xd0c0,
+    0x8000, 0xb940, 0xb980, 0xb940, 0xdd40, 0xdd80, 0xdd40, 0xdc80, 0xdcc0, 0xc0c0, 0xdc80, 0xdcc0, 0xc0c0, 0xb9c0, 0xb980, 0xb9c0,
+    0xa560, 0xa5a0, 0xac80, 0xed00, 0x8000, 0x8cc0, 0xbd00, 0xe380, 0xbdc0, 0xe500, 0xe500, 0xe880, 0xe8c0, 0xe8c0, 0xe800, 0xe5c0,
+    0xe5c0, 0xe940, 0xe980, 0xe940, 0xe980, 0xbd40, 0x8c80, 0xa080, 0x8000, 0xa980, 0xbd00, 0xbdc0, 0xb400, 0xa880, 0xedc0,
+  };
+  static const uint16 kLinkDmaSources3[27] = {
+    0x9a40, 0x9e00, 0x9d20, 0x9f20, 0x9b20, 0xbc20, 0xbc20, 0xbe20, 0xbe20, 0xbe00, 0xbe00, 0xbe00, 0xbe00, 0xa540, 0xa540, 0xa540,
+    0xa540, 0xbc00, 0xbc00, 0xbc00, 0xbc00, 0xa740, 0xa740, 0xa740, 0xa740, 0xe780, 0xe780,
+  };
+  static const uint16 kLinkDmaSources4[8] = { 0x9000, 0x9020, 0x9060, 0x91e0, 0x90a0, 0x90c0, 0x9100, 0x9140 };
+  static const uint16 kLinkDmaSources5[3] = { 0x9300, 0x9340, 0x9380 };
+  static const uint16 kLinkDmaSources6[128] = {
+    0x9480, 0x94c0, 0x94e0, 0x95c0, 0x9500, 0x9520, 0x9540, 0x9480, 0x9640, 0x9680, 0x96a0, 0x9780, 0x96c0, 0x96e0, 0x9700, 0x9480,
+    0x9800, 0x9840, 0x98a0, 0x9480, 0x9480, 0x9480, 0x9480, 0x9480, 0x9ac0, 0x9b00, 0x9480, 0x9480, 0x9480, 0x9480, 0x9480, 0x9480,
+    0x9bc0, 0x9c00, 0x9c40, 0x9c80, 0x9cc0, 0x9d00, 0x9d40, 0x9480, 0x9f40, 0x9f80, 0x9fc0, 0x9fe0, 0xa000, 0x9480, 0x9480, 0x9480,
+    0xa100, 0x9480, 0x9480, 0x9480, 0x9480, 0x9480, 0x9480, 0x9480, 0x9480, 0x9480, 0x9480, 0x9480, 0x9480, 0x9480, 0x9480, 0x9480,
+    0x98c0, 0x9900, 0x99c0, 0x99e0, 0x9a00, 0x9a20, 0x9a40, 0x9a60, 0x9480, 0x9480, 0x9480, 0x9480, 0x9480, 0x9480, 0x9480, 0x9480,
+    0x9a80, 0x9480, 0x9480, 0x9480, 0x9480, 0x9480, 0x9480, 0x9480, 0x9480, 0x9480, 0x9480, 0x9480, 0x9480, 0x9480, 0x9480, 0x9480,
+    0x9480, 0x9480, 0x9480, 0x9480, 0x9480, 0x9480, 0x9480, 0x9480, 0x9480, 0x9480, 0x9480, 0x9480, 0x9480, 0x9480, 0x9480, 0x9480,
+    0x9480, 0x9480, 0x9480, 0x9480, 0x9480, 0x9480, 0x9480, 0x9480, 0x9480, 0x9480, 0x9480, 0x9480, 0x9480, 0x9480, 0x9480, 0x9480,
+  };
+  static const uint16 kLinkDmaSources7[16] = { 0xe0, 0xe0, 0x60, 0x80, 0x1c0, 0xe0, 0x40, 0, 0x80, 0, 0x40, 0, 0, 0, 0, 0 };
+  static const uint16 kLinkDmaCtrs0[6] = { 14, 4, 6, 16, 6, 8 };
+  static const uint16 kLinkDmaSources9[15] = { 0, 0x20, 0x40, 0, 0x20, 0x40, 0, 0x40, 0x80, 0, 0x40, 0x80, 0xb340, 0xb400, 0xb4c0 };
+  static const uint16 kLinkDmaSources8[4] = { 0xa480, 0xa4c0, 0xa500, 0xa540 };
+
+  for (int i = 0; i < 32; i++) {
+    extended_oam[i] = bytewise_extended_oam[3 + 4 * i] << 6 |
+      bytewise_extended_oam[2 + 4 * i] << 4 |
+      bytewise_extended_oam[1 + 4 * i] << 2 |
+      bytewise_extended_oam[0 + 4 * i] << 0;
+  }
+
+  dma_source_addr_3 = kLinkDmaSources1[link_dma_graphics_index >> 1];
+  dma_source_addr_0 = dma_source_addr_3 + 0x200;
+  dma_source_addr_4 = kLinkDmaSources2[link_dma_graphics_index >> 1];
+  dma_source_addr_1 = dma_source_addr_4 + 0x200;
+  dma_source_addr_5 = kLinkDmaSources3[link_dma_var1 >> 1];
+  dma_source_addr_2 = kLinkDmaSources3[link_dma_var2 >> 1];
+
+
+  dma_source_addr_6 = kLinkDmaSources4[link_dma_var3 >> 1];
+  dma_source_addr_11 = dma_source_addr_6 + 0x180;
+
+  if (link_dma_var4 == 0x8b) {
+    dma_source_addr_7 = 0xe099;
+  } else {
+    dma_source_addr_7 = kLinkDmaSources5[link_dma_var4 >> 1];
+  }
+  dma_source_addr_12 = dma_source_addr_7 + 0xc0;
+
+
+  int j = (link_dma_var5 & 0xf8) >> 3;
+  dma_source_addr_8 = kLinkDmaSources6[link_dma_var5];
+  dma_source_addr_13 = dma_source_addr_8 + kLinkDmaSources7[j];
+  dma_source_addr_10 = kLinkDmaSources8[pushedblocks_some_index & 3];
+  dma_source_addr_15 = dma_source_addr_10 + 0x100;
+
+  if (--bg_tile_animation_countdown == 0) {
+    bg_tile_animation_countdown = (BYTE(overlay_index) == 0xb5 || BYTE(overlay_index) == 0xbc) ? 0x17 : 9;
+
+    uint16 t = word_7EC00F + 0x400;
+    if (t == 0xc00)
+      t = 0;
+    word_7EC00F = t;
+    animated_tile_data_src = 0xa680 + word_7EC00F;
+  }
+
+  if (--word_7EC013 == 0) {
+    int t = word_7EC015 + 2;
+    if (t == 12)
+      t = 0;
+    word_7EC015 = t;
+    word_7EC013 = kLinkDmaCtrs0[t >> 1];
+    dma_source_addr_9 = kLinkDmaSources9[t >> 1] + 0xb280;
+    dma_source_addr_14 = dma_source_addr_9 + 0x60;
+  }
+
+  dma_source_addr_16 = 0xB940 + dma_var6 * 2;
+  dma_source_addr_18 = dma_source_addr_16 + 0x200;
+
+  dma_source_addr_17 = 0xB940 + dma_var7 * 2;
+  dma_source_addr_19 = dma_source_addr_17 + 0x200;
+
+  dma_source_addr_20 = 0xB540 + flag_travel_bird * 2;
+  dma_source_addr_21 = dma_source_addr_20 + 0x200;
+}
+
+void Sound_LoadIntroSongBank() {  // 808901
+  LoadSongBank(kSoundBank_intro);
+}
+
+void LoadOverworldSongs() {  // 808913
+  LoadSongBank(kSoundBank_intro);
+}
+
+void LoadDungeonSongs() {  // 808925
+  LoadSongBank(kSoundBank_indoor);
+}
+
+void LoadCreditsSongs() {  // 808931
+  LoadSongBank(kSoundBank_ending);
+}
+
+void Dungeon_LightTorch() {  // 81f3ec
+  if ((byte_7E0333 & 0xf0) != 0xc0) {
+    byte_7E0333 = 0;
+    return;
+  }
+  uint8 r8 = (uint8)dungeon_room_index == 0 ? 0x80 : 0xc0;
+
+  int i = (byte_7E0333 & 0xf) + (dung_index_of_torches_start >> 1);
+  int opos = dung_object_pos_in_objdata[i];
+  if (dung_object_tilemap_pos[i] & 0x8000)
+    return;
+  dung_object_tilemap_pos[i] |= 0x8000;
+  if (r8 == 0)
+    dung_torch_data[opos] = dung_object_tilemap_pos[i];
+
+  uint16 x = dung_object_tilemap_pos[i] & 0x3fff;
+  RoomDraw_AdjustTorchLightingChange(x, 0xeca, x);
+
+  sound_effect_1 = 42 | CalculateSfxPan_Arbitrary((x & 0x7f) * 2);
+
+  nmi_copy_packets_flag = 1;
+  if (dung_want_lights_out) {
+    if (dung_num_lit_torches++ < 3) {
+      TS_copy = 0;
+      overworld_fixed_color_plusminus = kLitTorchesColorPlus[dung_num_lit_torches];
+      submodule_index = 10;
+      subsubmodule_index = 0;
+    }
+  }
+
+  dung_torch_timers[byte_7E0333 & 0xf] = r8;
+  byte_7E0333 = 0;
+}
+
+void RoomDraw_AdjustTorchLightingChange(uint16 x, uint16 y, uint16 r8) {  // 81f746
+  const uint16 *ptr = SrcPtr(y);
+  x >>= 1;
+  overworld_tileattr[x + 0] = ptr[0];
+  overworld_tileattr[x + 64] = ptr[1];
+  overworld_tileattr[x + 1] = ptr[2];
+  overworld_tileattr[x + 65] = ptr[3];
+  Dungeon_PrepOverlayDma_nextPrep(0, r8);
+}
+
+int Dungeon_PrepOverlayDma_nextPrep(int dst, uint16 r8) {  // 81f764
+  uint16 r6 = 0x880 + ((r8 & 0x3f) >= 0x3a);
+  return Dungeon_PrepOverlayDma_watergate(dst, r8, r6, 4);
+}
+
+int Dungeon_PrepOverlayDma_watergate(int dst, uint16 r8, uint16 r6, int loops) {  // 81f77c
+  for (int k = 0; k < loops; k++) {
+    int x = r8 >> 1;
+    vram_upload_tile_buf[dst + 0] = ((r8 & 0x40) << 4) | ((r8 & 0x303f) >> 1) | ((r8 & 0xf80) >> 2);
+    vram_upload_tile_buf[dst + 1] = r6;
+    vram_upload_tile_buf[dst + 2] = overworld_tileattr[x + 0];
+    if (!(r6 & 1)) {
+      vram_upload_tile_buf[dst + 3] = overworld_tileattr[x + 1];
+      vram_upload_tile_buf[dst + 4] = overworld_tileattr[x + 2];
+      vram_upload_tile_buf[dst + 5] = overworld_tileattr[x + 3];
+      r8 += 128;
+    } else {
+      vram_upload_tile_buf[dst + 3] = overworld_tileattr[x + 64];
+      vram_upload_tile_buf[dst + 4] = overworld_tileattr[x + 128];
+      vram_upload_tile_buf[dst + 5] = overworld_tileattr[x + 192];
+      r8 += 2;
+    }
+    dst += 6;
+  }
+  vram_upload_tile_buf[dst] = 0xffff;
+  return dst;
+}
+
+void Module05_LoadFile() {  // 828136
+  EnableForceBlank();
+  overworld_map_state = 0;
+  dung_unk6 = 0;
+  byte_7E02D4 = 0;
+  byte_7E02D7 = 0;
+  tagalong_var5 = 0;
+  byte_7E0379 = 0;
+  byte_7E03FD = 0;
+  EraseTileMaps_normal();
+  LoadDefaultGraphics();
+  Sprite_LoadGraphicsProperties();
+  Init_LoadDefaultTileAttr();
+  DecompressSwordGraphics();
+  DecompressShieldGraphics();
+  Link_Initialize();
+  LoadFollowerGraphics();
+  sprite_gfx_subset_0 = 70;
+  sprite_gfx_subset_1 = 70;
+  sprite_gfx_subset_2 = 70;
+  sprite_gfx_subset_3 = 70;
+  word_7E02CD = 0x200;
+  virq_trigger = 48;
+  if (savegame_is_darkworld) {
+    if (player_is_indoors) {
+      LoadDungeonRoomRebuildHUD();
+      return;
+    }
+    Hud_SearchForEquippedItem();
+    Hud_Rebuild();
+    Hud_UpdateEquippedItem();
+    death_var5 = 0;
+    dungeon_room_index = 32;
+    main_module_index = 8;
+    submodule_index = 0;
+    subsubmodule_index = 0;
+    death_var4 = 0;
+  } else {
+    if (mosaic_level || death_var5 != 0 && !death_var4 || sram_progress_indicator < 2 || which_starting_point == 5) {
+      LoadDungeonRoomRebuildHUD();
+      return;
+    }
+    dialogue_message_index = (link_item_mirror == 2) ? 0x185 : 0x184;
+    Main_ShowTextMessage();
+    Dungeon_LoadPalettes();
+    INIDISP_copy = 15;
+    TM_copy = 4;
+    TS_copy = 0;
+    main_module_index = 27;
+  }
+}
+
+void Module13_BossVictory_Pendant() {  // 829c4a
+  kModule_BossVictory[submodule_index]();
+  Sprite_Main();
+  LinkOam_Main();
+}
+
+void BossVictory_Heal() {  // 829c59
+  if (!Hud_RefillMagicPower())
+    overworld_map_state++;
+  if (!Hud_RefillHealth())
+    overworld_map_state++;
+  if (!overworld_map_state) {
+    button_mask_b_y &= ~0x40;
+    Dungeon_ResetTorchBackgroundAndPlayerInner();
+    link_direction_facing = 2;
+    link_direction_last = 2 << 1;
+    flag_update_hud_in_nmi++;
+    submodule_index++;
+    subsubmodule_index = 16;
+    flag_is_link_immobilized++;
+  }
+  overworld_map_state = 0;
+  Hud_RefillLogic();
+}
+
+void Dungeon_StartVictorySpin() {  // 829c93
+  if (--subsubmodule_index)
+    return;
+  flag_is_link_immobilized = 0;
+  link_direction_facing = 2;
+  Link_AnimateVictorySpin();
+  Ancilla_TerminateSelectInteractives(0);
+  AncillaAdd_VictorySpin();
+  submodule_index++;
+}
+
+void Dungeon_RunVictorySpin() {  // 829cad
+  Link_Main();
+  if (link_player_handler_state != 0)
+    return;
+  if (link_sword_type + 1 & 0xfe)
+    sound_effect_1 = 0x2C;
+  link_force_hold_sword_up = 1;
+  subsubmodule_index = 32;
+  submodule_index++;
+}
+
+void Dungeon_CloseVictorySpin() {  // 829cd1
+  if (--subsubmodule_index)
+    return;
+  submodule_index++;
+  link_y_vel = 0;
+  link_x_vel = 0;
+  overworld_fixed_color_plusminus = 0;
+}
+
+void Module15_MirrorWarpFromAga() {  // 829cfc
+  kModule_KillAgahnim[submodule_index]();
+  if (submodule_index < 2 || submodule_index >= 5) {
+    Sprite_Main();
+    LinkOam_Main();
+  }
+}
+
+void Module16_BossVictory_Crystal() {  // 829e8a
+  switch (submodule_index) {
+  case 0: BossVictory_Heal(); break;
+  case 1: Dungeon_StartVictorySpin(); break;
+  case 2: Dungeon_RunVictorySpin(); break;
+  case 3: Dungeon_CloseVictorySpin(); break;
+  case 4: Module16_04_FadeAndEnd(); break;
+  }
+  Sprite_Main();
+  LinkOam_Main();
+}
+
+void Module16_04_FadeAndEnd() {  // 829e9a
+  if (--INIDISP_copy)
+    return;
+  bg1_x_offset = 0;
+  bg1_y_offset = 0;
+  link_y_vel = 0;
+  flag_is_link_immobilized = 0;
+  Palette_RevertTranslucencySwap();
+  link_player_handler_state = kPlayerState_Ground;
+  link_receiveitem_index = 0;
+  link_pose_for_item = 0;
+  link_disable_sprite_damage = 0;
+  main_module_index = saved_module_for_menu;
+  submodule_index = 0;
+  subsubmodule_index = 0;
+  OpenSpotlight_Next2();
+}
+
+static uint8 PlaySfx_SetPan(uint8 a) {  // 878036
+  byte_7E0CF8 = a;
+  return a | Link_CalculateSfxPan();
+}
+
+void TriforceRoom_LinkApproachTriforce() {  // 87f49c
+  uint8 y = link_y_coord;
+  if (y < 152) {
+    link_animation_steps = 0;
+    link_direction = 0;
+    link_direction_last = 0;
+    if (!--link_delay_timer_spin_attack) {
+      link_pose_for_item = 2;
+      subsubmodule_index++;
+    }
+  } else {
+    if (y < 169)
+      link_speed_setting = 0x14;
+    link_direction = 8;
+    link_direction_last = 8;
+    link_direction_facing = 0;
+    link_delay_timer_spin_attack = 64;
+  }
+}
+
+void AncillaAdd_ItemReceipt(uint8 ain, uint8 yin, int chest_pos) {  // 8985e8
+  int ancilla = Ancilla_AddAncilla(ain, yin);
+  if (ancilla < 0)
+    return;
+
+  flag_is_link_immobilized = (link_receiveitem_index == 0x20) ? 2 : 1;
+  uint8 t;
+
+  int j = link_receiveitem_index;
+  if (j == 0) {
+    g_ram[kMemoryLocationToGiveItemTo[4]] = kValueToGiveItemTo[0];
+  }
+
+  uint8 v = kValueToGiveItemTo[j];
+  uint8 *p = &g_ram[kMemoryLocationToGiveItemTo[j]];
+  if (!sign8(v))
+    *p = v;
+
+  if (j == 0x1f)
+    link_is_bunny = 0;
+  else if (j == 0x4b || j == 0x1e)
+    link_ability_flags |= (j == 0x4b) ? 4 : 2;
+
+  if (j == 0x1b || j == 0x1c) {
+    Palette_UpdateGlovesColor();
+  } else if ((t = 4, j == 0x37) || (t = 1, j == 0x38) || (t = 2, j == 0x39)) {
+    *p |= t;
+    if ((*p & 7) == 7)
+      savegame_map_icons_indicator = 4;
+    overworld_map_state++;
+  } else if (j == 0x22) {
+    if (*p == 0)
+      *p = 1;
+  } else if (j == 0x25 || j == 0x32 || j == 0x33) {
+    WORD(*p) |= 0x8000 >> (BYTE(cur_palace_index_x2) >> 1);
+  } else if (j == 0x3e) {
+    if (link_state_bits & 0x80)
+      link_picking_throw_state = 2;
+  } else if (j == 0x20) {
+    overworld_map_state++;
+    for (int i = 4; i >= 0; i--) {
+      if (ancilla_type[i] == 7 || ancilla_type[i] == 0x2c) {
+        ancilla_type[i] = 0;
+        link_state_bits = 0;
+        link_picking_throw_state = 0;
+      }
+    }
+    if (link_cape_mode) {
+      link_bunny_transform_timer = 32;
+      link_disable_sprite_damage = 0;
+      link_cape_mode = 0;
+      AncillaAdd_CapePoof(0x23, 4);
+      sound_effect_1 = 0x15 | Link_CalculateSfxPan();
+    }
+  } else if (j == 0x29) {
+    if (link_item_mushroom != 2) {
+      *p = 1;
+      Hud_RefreshIcon();
+    }
+  } else if ((t = 1, j == 0x24) || item_receipt_method != 2 && (j == 0x27 || (t = 3, j == 0x28) || (t = 10, j == 0x31))) {
+    *p += t;
+    if (*p > 99)
+      *p = 99;
+    Hud_RefreshIcon();
+  } else if (j == 0x17) {
+    *p = (*p + 1) & 3;
+    sound_effect_2 = 0x2d | Link_CalculateSfxPan();
+  } else if (j == 1) {
+    Overworld_SetSongList();
+  } else {
+    ItemReceipt_GiveBottledItem(j);
+  }
+
+  uint8 gfx = kReceiveItemGfx[j];
+  if (gfx == 0xff) {
+    gfx = 0;
+  } else if (gfx == 0x20 || gfx == 0x2d || gfx == 0x2e) {
+    DecompressShieldGraphics();
+    Palette_Load_Shield();
+  }
+  DecodeAnimatedSpriteTile_variable(gfx);
+
+  if ((gfx == 6 || gfx == 0x18) && j != 0) {
+    DecompressSwordGraphics();
+    Palette_Load_Sword();
+  }
+
+  ancilla_item_to_link[ancilla] = j;
+  ancilla_arr1[ancilla] = 0;
+
+  if (j == 1 && item_receipt_method != 2) {
+    ancilla_timer[ancilla] = 160;
+    submodule_index = 43;
+    BYTE(palette_filter_countdown) = 0;
+    AncillaAdd_MSCutscene(0x35, 4);
+    ancilla_arr3[ancilla] = 2;
+  } else {
+    ancilla_arr3[ancilla] = 9;
+  }
+  ancilla_arr4[ancilla] = 5;
+  ancilla_step[ancilla] = item_receipt_method;
+
+  ancilla_aux_timer[ancilla] =
+    (j == 0x20 || j == 0x37 || j == 0x38 || j == 0x39) ? 0x68 :
+    (j == 0x26) ? 0x2 : (item_receipt_method ? 0x38 : 0x60);
+
+  int x, y;
+
+  if (item_receipt_method == 1) {
+    y = (chest_pos & 0x1f80) >> 4;
+    x = (chest_pos & 0x7e) << 2;
+    y += dung_loade_bgoffs_v_copy & ~0xff;
+    x += dung_loade_bgoffs_h_copy & ~0xff;
+    y += kReceiveItem_Tab2[j];
+    x += kReceiveItem_Tab3[j];
+  } else {
+    if (ancilla_step[ancilla] == 0 && j == 1) {
+      sound_effect_1 = Link_CalculateSfxPan() | 0x2c;
+    } else if (j == 0x20 || j == 0x37 || j == 0x38 || j == 0x39) {
+      music_control = Link_CalculateSfxPan() | 0x13;
+    } else if (j != 0x3e && j != 0x17) {
+      sound_effect_2 = Link_CalculateSfxPan() | 0xf;
+    }
+    int method = item_receipt_method == 3 ? 0 : item_receipt_method;
+    x = (method != 0) ? kReceiveItem_Tab3[j] :
+      (kReceiveItem_Tab1[j] == 0) ? 10 : (j == 0x20) ? 0 : 6;
+    x += link_x_coord;
+    y = method ? kReceiveItem_Tab2[j] : -14;
+    y += link_y_coord + ((method == 2) ? -8 : 0);
+  }
+  Ancilla_SetXY(ancilla, x, y);
+}
+
+void ItemReceipt_GiveBottledItem(uint8 item) {  // 89893e
+  static const uint8 kBottleList[7] = { 0x16, 0x2b, 0x2c, 0x2d, 0x3d, 0x3c, 0x48 };
+  static const uint8 kPotionList[5] = { 0x2e, 0x2f, 0x30, 0xff, 0xe };
+  int j;
+  if ((j = FindInByteArray(kBottleList, item, 7)) >= 0) {
+    for (int i = 0; i != 4; i++) {
+      if (link_bottle_info[i] < 2) {
+        link_bottle_info[i] = j + 2;
+        return;
+      }
+    }
+  }
+  if ((j = FindInByteArray(kPotionList, item, 5)) >= 0) {
+    for (int i = 0; i != 4; i++) {
+      if (link_bottle_info[i] == 2) {
+        link_bottle_info[i] = j + 3;
+        return;
+      }
+    }
+  }
+}
+
+void Module17_SaveAndQuit() {  // 89f79f
+  switch (submodule_index) {
+  case 0:
+    submodule_index++;
+  case 1:
+    if (!--INIDISP_copy) {
+      MOSAIC_copy = 15;
+      subsubmodule_index = 1;
+      Death_Func15(false);
+    }
+    break;
+  }
+  Sprite_Main();
+  LinkOam_Main();
+}
+
+void WallMaster_SendPlayerToLastEntrance() {  // 8bffa8
+  SaveDungeonKeys();
+  Dungeon_FlagRoomData_Quadrants();
+  Sprite_ResetAll();
+  death_var4 = 0;
+  main_module_index = 17;
+  submodule_index = 0;
+  nmi_load_bg_from_vram = 0;
+  ResetSomeThingsAfterDeath(17);  // wtf: argument?
+}
+
+uint8 GetRandomNumber() {  // 8dba71
+  uint8 t = byte_7E0FA1 + frame_counter;
+  t = (t & 1) ? (t >> 1) : (t >> 1) ^ 0xb8;
+  byte_7E0FA1 = t;
+  return t;
+}
+
+uint8 Link_CalculateSfxPan() {  // 8dbb67
+  return CalculateSfxPan(link_x_coord);
+}
+
+void SpriteSfx_QueueSfx1WithPan(int k, uint8 a) {  // 8dbb6e
+  if (sound_effect_ambient == 0)
+    sound_effect_ambient = a | Sprite_CalculateSfxPan(k);
+}
+
+void SpriteSfx_QueueSfx2WithPan(int k, uint8 a) {  // 8dbb7c
+  if (sound_effect_1 == 0)
+    sound_effect_1 = a | Sprite_CalculateSfxPan(k);
+}
+
+void SpriteSfx_QueueSfx3WithPan(int k, uint8 a) {  // 8dbb8a
+  if (sound_effect_2 == 0)
+    sound_effect_2 = a | Sprite_CalculateSfxPan(k);
+}
+
+uint8 Sprite_CalculateSfxPan(int k) {  // 8dbba1
+  return CalculateSfxPan(Sprite_GetX(k));
+}
+
+uint8 CalculateSfxPan(uint16 x) {  // 8dbba8
+  static const uint8 kPanTable[] = { 0, 0x80, 0x40 };
+  int o = 0;
+  x -= BG2HOFS_copy2 + 80;
+  if (x >= 80)
+    o = 1 + ((int16)x >= 0);
+  return kPanTable[o];
+}
+
+uint8 CalculateSfxPan_Arbitrary(uint8 a) {  // 8dbbd0
+  static const uint8 kTorchPans[] = { 0x80, 0x80, 0x80, 0, 0, 0x40, 0x40, 0x40 };
+  return kTorchPans[((a - BG2HOFS_copy2) >> 5) & 7];
+}
+
+void Init_LoadDefaultTileAttr() {  // 8e97d9
+  memcpy(attributes_for_tile, kDungeon_DefaultAttr, 0x140);
+  memcpy(attributes_for_tile + 0x1c0, kDungeon_DefaultAttr + 0x140, 64);
+}
+
+void Main_ShowTextMessage() {  // 8ffdaa
+  if (main_module_index != 14) {
+    byte_7E0223 = 0;
+    messaging_module = 0;
+    submodule_index = 2;
+    saved_module_for_menu = main_module_index;
+    main_module_index = 14;
+  }
+}
+
+uint8 HandleItemTileAction_Overworld(uint16 x, uint16 y) {  // 9bbd7a
+  if (player_is_indoors)
+    return HandleItemTileAction_Dungeon(x, y);
+  else
+    return Overworld_ToolAndTileInteraction(x, y);
+}
+
--- /dev/null
+++ b/src/misc.h
@@ -1,0 +1,76 @@
+#include "types.h"
+#include "variables.h"
+#include "zelda_rtl.h"
+
+#pragma once
+
+
+
+
+
+
+
+
+
+static inline OamEnt *GetOamCurPtr() {
+  return (OamEnt *)&g_ram[oam_cur_ptr];
+}
+
+static inline int FindInByteArray(const uint8 *data, uint8 lookfor, size_t size) {
+  for (size_t i = size; i--;)
+    if (data[i] == lookfor)
+      return (int)i;
+  return -1;
+}
+
+static inline int FindInWordArray(const uint16 *data, uint16 lookfor, size_t size) {
+  for (size_t i = size; i--;)
+    if (data[i] == lookfor)
+      return (int)i;
+  return -1;
+}
+
+
+extern const uint16 kMemoryLocationToGiveItemTo[76];
+
+const uint16 *SrcPtr(uint16 src);
+uint8 Ancilla_Sfx2_Near(uint8 a);
+void Ancilla_Sfx3_Near(uint8 a);
+void LoadDungeonRoomRebuildHUD();
+void Module_Unknown0();
+void Module_Unknown1();
+void Module_MainRouting();
+void NMI_PrepareSprites();
+void Sound_LoadIntroSongBank();
+void LoadOverworldSongs();
+void LoadDungeonSongs();
+void LoadCreditsSongs();
+void Dungeon_LightTorch();
+void RoomDraw_AdjustTorchLightingChange(uint16 x, uint16 y, uint16 r8);
+int Dungeon_PrepOverlayDma_nextPrep(int dst, uint16 r8);
+int Dungeon_PrepOverlayDma_watergate(int dst, uint16 r8, uint16 r6, int loops);
+void Module05_LoadFile();
+void Module13_BossVictory_Pendant();
+void BossVictory_Heal();
+void Dungeon_StartVictorySpin();
+void Dungeon_RunVictorySpin();
+void Dungeon_CloseVictorySpin();
+void Module15_MirrorWarpFromAga();
+void Module16_BossVictory_Crystal();
+void Module16_04_FadeAndEnd();
+void TriforceRoom_LinkApproachTriforce();
+void AncillaAdd_ItemReceipt(uint8 ain, uint8 yin, int chest_pos);
+void ItemReceipt_GiveBottledItem(uint8 item);
+void Module17_SaveAndQuit();
+void WallMaster_SendPlayerToLastEntrance();
+uint8 GetRandomNumber();
+uint8 Link_CalculateSfxPan();
+void SpriteSfx_QueueSfx1WithPan(int k, uint8 a);
+void SpriteSfx_QueueSfx2WithPan(int k, uint8 a);
+void SpriteSfx_QueueSfx3WithPan(int k, uint8 a);
+uint8 Sprite_CalculateSfxPan(int k);
+uint8 CalculateSfxPan(uint16 x);
+uint8 CalculateSfxPan_Arbitrary(uint8 a);
+void Init_LoadDefaultTileAttr();
+void Main_ShowTextMessage();
+uint8 HandleItemTileAction_Overworld(uint16 x, uint16 y);
--- /dev/null
+++ b/src/nmi.c
@@ -1,0 +1,461 @@
+#include "nmi.h"
+#include "zelda_rtl.h"
+#include "variables.h"
+#include "messaging.h"
+#include "snes/snes_regs.h"
+#include "snes/ppu.h"
+#include "assets.h"
+#include "audio.h"
+
+static const uint8 kNmiVramAddrs[] = {
+  0, 0, 4, 8, 12, 8, 12, 0, 4, 0, 8, 4, 12, 4, 12, 0,
+  8, 16, 20, 24, 28, 24, 28, 16, 20, 16, 24, 20, 28, 20, 28, 16,
+  24, 96, 104,
+};
+static PlayerHandlerFunc *const kNmiSubroutines[25] = {
+  &NMI_UploadTilemap_doNothing,
+  &NMI_UploadTilemap,
+  &NMI_UploadBG3Text,
+  &NMI_UpdateOWScroll,
+  &NMI_UpdateSubscreenOverlay,
+  &NMI_UpdateBG1Wall,
+  &NMI_TileMapNothing,
+  &NMI_UpdateLoadLightWorldMap,
+  &NMI_UpdateBG2Left,
+  &NMI_UpdateBGChar3and4,
+  &NMI_UpdateBGChar5and6,
+  &NMI_UpdateBGCharHalf,
+  &NMI_UploadSubscreenOverlayLatter,
+  &NMI_UploadSubscreenOverlayFormer,
+  &NMI_UpdateBGChar0,
+  &NMI_UpdateBGChar1,
+  &NMI_UpdateBGChar2,
+  &NMI_UpdateBGChar3,
+  &NMI_UpdateObjChar0,
+  &NMI_UpdateObjChar2,
+  &NMI_UpdateObjChar3,
+  &NMI_UploadDarkWorldMap,
+  &NMI_UploadGameOverText,
+  &NMI_UpdatePegTiles,
+  &NMI_UpdateStarTiles,
+};
+void NMI_UploadSubscreenOverlayFormer() {
+  NMI_HandleArbitraryTileMap(&g_ram[0x12000], 0, 0x40);
+}
+
+void NMI_UploadSubscreenOverlayLatter() {
+  NMI_HandleArbitraryTileMap(&g_ram[0x13000], 0x40, 0x80);
+}
+
+static void CopyToVram(uint32 dstv, const uint8 *src, int len) {
+  memcpy(&g_zenv.vram[dstv], src, len);
+}
+
+static void CopyToVramVertical(uint32 dstv, const uint8 *src, int len) {
+  assert(!(len & 1));
+  uint16 *dst = &g_zenv.vram[dstv];
+  for (int i = 0, i_end = len >> 1; i < i_end; i++, dst += 32, src += 2)
+    *dst = WORD(*src);
+}
+
+static void CopyToVramLow(const uint8 *src, uint32 addr, int num) {
+  uint16 *dst = &g_zenv.vram[addr];
+  for (int i = 0; i < num; i++)
+    dst[i] = (dst[i] & ~0xff) | src[i];
+}
+
+void WritePpuRegisters() {
+  zelda_ppu_write(W12SEL, W12SEL_copy);
+  zelda_ppu_write(W34SEL, W34SEL_copy);
+  zelda_ppu_write(WOBJSEL, WOBJSEL_copy);
+  zelda_ppu_write(CGWSEL, CGWSEL_copy);
+  zelda_ppu_write(CGADSUB, CGADSUB_copy);
+  zelda_ppu_write(COLDATA, COLDATA_copy0);
+  zelda_ppu_write(COLDATA, COLDATA_copy1);
+  zelda_ppu_write(COLDATA, COLDATA_copy2);
+  zelda_ppu_write(TM, TM_copy);
+  zelda_ppu_write(TS, TS_copy);
+  zelda_ppu_write(TMW, TMW_copy);
+  zelda_ppu_write(TSW, TSW_copy);
+  zelda_ppu_write(BG1HOFS, BG1HOFS_copy);
+  zelda_ppu_write(BG1HOFS, BG1HOFS_copy >> 8);
+  zelda_ppu_write(BG1VOFS, BG1VOFS_copy);
+  zelda_ppu_write(BG1VOFS, BG1VOFS_copy >> 8);
+  zelda_ppu_write(BG2HOFS, BG2HOFS_copy);
+  zelda_ppu_write(BG2HOFS, BG2HOFS_copy >> 8);
+  zelda_ppu_write(BG2VOFS, BG2VOFS_copy);
+  zelda_ppu_write(BG2VOFS, BG2VOFS_copy >> 8);
+  zelda_ppu_write(BG3HOFS, BG3HOFS_copy2);
+  zelda_ppu_write(BG3HOFS, BG3HOFS_copy2 >> 8);
+  zelda_ppu_write(BG3VOFS, BG3VOFS_copy2);
+  zelda_ppu_write(BG3VOFS, BG3VOFS_copy2 >> 8);
+  zelda_ppu_write(INIDISP, INIDISP_copy);
+  zelda_ppu_write(MOSAIC, MOSAIC_copy);
+  zelda_ppu_write(BGMODE, BGMODE_copy);
+  if ((BGMODE_copy & 7) == 7) {
+    zelda_ppu_write(M7B, 0);
+    zelda_ppu_write(M7B, 0);
+    zelda_ppu_write(M7C, 0);
+    zelda_ppu_write(M7C, 0);
+    zelda_ppu_write(M7X, M7X_copy);
+    zelda_ppu_write(M7X, M7X_copy >> 8);
+    zelda_ppu_write(M7Y, M7Y_copy);
+    zelda_ppu_write(M7Y, M7Y_copy >> 8);
+  }
+  zelda_ppu_write(BG12NBA, 0x22);
+  zelda_ppu_write(BG34NBA, 7);
+}
+
+static void Interrupt_NMI_AudioParts_Locked() {
+  if (music_control == 0) {
+//    if (zelda_apu_read(APUI00) == last_music_control)
+//      zelda_apu_write(APUI00, 0);
+    // Zelda causes unwanted music change when going in a portal. last_music_control doesn't hold the 
+    // song but the last applied effect
+  } else if (!ZeldaIsPlayingMusicTrackWithBug(music_control)) {
+    last_music_control = music_control;
+    ZeldaPlayMsuAudioTrack(music_control);
+    if (music_control < 0xf2)
+      music_unk1 = music_control;
+    music_control = 0;
+  }
+
+  if (sound_effect_ambient == 0) {
+    if (zelda_apu_read(APUI01) == sound_effect_ambient_last)
+      zelda_apu_write(APUI01, 0);
+  } else {
+    sound_effect_ambient_last = sound_effect_ambient;
+    zelda_apu_write(APUI01, sound_effect_ambient);
+    sound_effect_ambient = 0;
+  }
+  zelda_apu_write(APUI02, sound_effect_1);
+  zelda_apu_write(APUI03, sound_effect_2);
+  sound_effect_1 = 0;
+  sound_effect_2 = 0;
+
+}
+
+void Interrupt_NMI(uint16 joypad_input) {  // 8080c9
+
+  Interrupt_NMI_AudioParts_Locked();
+
+  if (!nmi_boolean) {
+    nmi_boolean = true;
+    NMI_DoUpdates();
+    NMI_ReadJoypads(joypad_input);
+  }
+
+  if (is_nmi_thread_active) {
+    NMI_UpdateIRQGFX();
+    thread_other_stack = (thread_other_stack != 0x1f31) ? 0x1f31 : 0x1f2;
+  }
+  WritePpuRegisters();
+}
+
+void NMI_ReadJoypads(uint16 joypad_input) {  // 8083d1
+  uint16 both = joypad_input;
+  uint16 reversed = 0;
+  for (int i = 0; i < 16; i++, both >>= 1)
+    reversed = reversed * 2 + (both & 1);
+  uint8 r0 = reversed;
+  uint8 r1 = reversed >> 8;
+
+  joypad1L_last = r0;
+  filtered_joypad_L = (r0 ^ joypad1L_last2) & r0;
+  joypad1L_last2 = r0;
+
+  joypad1H_last = r1;
+  filtered_joypad_H = (r1 ^ joypad1H_last2) & r1;
+  joypad1H_last2 = r1;
+}
+
+void NMI_DoUpdates() {  // 8089e0
+  if (!nmi_disable_core_updates) {
+    memcpy(&g_zenv.vram[0x4100], &kLinkGraphics[dma_source_addr_0 - 0x8000], 0x40);
+    memcpy(&g_zenv.vram[0x4120], &kLinkGraphics[dma_source_addr_1 - 0x8000], 0x40);
+    memcpy(&g_zenv.vram[0x4140], &kLinkGraphics[dma_source_addr_2 - 0x8000], 0x20);
+
+    memcpy(&g_zenv.vram[0x4000], &kLinkGraphics[dma_source_addr_3 - 0x8000], 0x40);
+    memcpy(&g_zenv.vram[0x4020], &kLinkGraphics[dma_source_addr_4 - 0x8000], 0x40);
+    memcpy(&g_zenv.vram[0x4040], &kLinkGraphics[dma_source_addr_5 - 0x8000], 0x20);
+
+    memcpy(&g_zenv.vram[0x4050], &g_ram[dma_source_addr_6], 0x40);
+    memcpy(&g_zenv.vram[0x4070], &g_ram[dma_source_addr_7], 0x40);
+    memcpy(&g_zenv.vram[0x4090], &g_ram[dma_source_addr_8], 0x40);
+    memcpy(&g_zenv.vram[0x40b0], &g_ram[dma_source_addr_9], 0x20);
+    memcpy(&g_zenv.vram[0x40c0], &g_ram[dma_source_addr_10], 0x40);
+    memcpy(&g_zenv.vram[0x4150], &g_ram[dma_source_addr_11], 0x40);
+    memcpy(&g_zenv.vram[0x4170], &g_ram[dma_source_addr_12], 0x40);
+    memcpy(&g_zenv.vram[0x4190], &g_ram[dma_source_addr_13], 0x40);
+    memcpy(&g_zenv.vram[0x41b0], &g_ram[dma_source_addr_14], 0x20);
+    memcpy(&g_zenv.vram[0x41c0], &g_ram[dma_source_addr_15], 0x40);
+    memcpy(&g_zenv.vram[0x4200], &g_ram[dma_source_addr_16], 0x40);
+    memcpy(&g_zenv.vram[0x4220], &g_ram[dma_source_addr_17], 0x40);
+    memcpy(&g_zenv.vram[0x4240], &g_ram[0xbd40], 0x40);
+    memcpy(&g_zenv.vram[0x4300], &g_ram[dma_source_addr_18], 0x40);
+    memcpy(&g_zenv.vram[0x4320], &g_ram[dma_source_addr_19], 0x40);
+    memcpy(&g_zenv.vram[0x4340], &g_ram[0xbd80], 0x40);
+
+    if (BYTE(flag_travel_bird)) {
+      memcpy(&g_zenv.vram[0x40e0], &g_ram[dma_source_addr_20], 0x40);
+      memcpy(&g_zenv.vram[0x41e0], &g_ram[dma_source_addr_21], 0x40);
+    }
+
+    memcpy(&g_zenv.vram[animated_tile_vram_addr], &g_ram[animated_tile_data_src], 0x400);
+  }
+
+  if (flag_update_hud_in_nmi) {
+    memcpy(&g_zenv.vram[word_7E0219], hud_tile_indices_buffer, 165 * sizeof(uint16));
+  }
+
+  if (flag_update_cgram_in_nmi) {
+    memcpy(g_zenv.ppu->cgram, main_palette_buffer, 0x200);
+  }
+
+  flag_update_hud_in_nmi = 0;
+  flag_update_cgram_in_nmi = 0;
+
+  memcpy(g_zenv.ppu->oam, &g_ram[0x800], 0x220);
+
+  if (nmi_load_bg_from_vram) {
+    const uint8 *p;
+    switch (nmi_load_bg_from_vram) {
+    case 1: p = g_ram + 0x1002; break;
+    case 2: p = g_ram + 0x1000; break;
+    case 3: p = kBgTilemap_0; break;
+    case 4: p = g_ram + 0x21b; break;
+    case 5: p = kBgTilemap_1; break;
+    case 6: p = kBgTilemap_2; break;
+    case 7: p = kBgTilemap_3; break;
+    case 8: p = kBgTilemap_4; break;
+    case 9: p = kBgTilemap_5; break;
+    default: assert(0);
+    }
+    HandleStripes14(p);
+    if (nmi_load_bg_from_vram == 1)
+      vram_upload_offset = 0;
+    nmi_load_bg_from_vram = 0;
+  }
+
+  if (nmi_update_tilemap_dst) {
+    memcpy(&g_zenv.vram[nmi_update_tilemap_dst * 256], &g_ram[0x10000 + nmi_update_tilemap_src], 0x200);
+    nmi_update_tilemap_dst = 0;
+  }
+
+  if (nmi_copy_packets_flag) {
+    uint8 *p = (uint8 *)uvram.data;
+    do {
+      int dst = WORD(p[0]);
+      int vmain = p[2];
+      int len = p[3];
+      p += 4;
+      if (vmain == 0x80) {
+        // plain copy
+        memcpy(&g_zenv.vram[dst], p, len);
+      } else if (vmain == 0x81) {
+        // copy with other increment
+        assert((len & 1) == 0);
+        uint16 *dp = &g_zenv.vram[dst];
+        for (int i = 0; i < len; i += 2, dp += 32)
+          *dp = WORD(p[i]);
+      } else {
+        assert(0);
+      }
+      p += len;
+    } while (WORD(p[0]) != 0xffff);
+    nmi_copy_packets_flag = 0;
+    nmi_disable_core_updates = 0;
+  }
+
+  int idx = nmi_subroutine_index;
+  nmi_subroutine_index = 0;
+  kNmiSubroutines[idx]();
+}
+
+void NMI_UploadTilemap() {  // 808cb0
+  memcpy(&g_zenv.vram[kNmiVramAddrs[BYTE(nmi_load_target_addr)] << 8], &g_ram[0x1000], 0x800);
+
+  *(uint16 *)&g_ram[0x1000] = 0;
+  nmi_disable_core_updates = 0;
+}
+
+void NMI_UploadTilemap_doNothing() {  // 808ce3
+}
+
+void NMI_UploadBG3Text() {  // 808ce4
+  memcpy(&g_zenv.vram[0x7c00], &g_ram[0x10000], 0x7e0);
+  nmi_disable_core_updates = 0;
+}
+
+void NMI_UpdateOWScroll() {  // 808d13
+  uint8 *src = (uint8 *)uvram.data;
+  int f = WORD(src[0]);
+  int step = (f & 0x8000) ? 32 : 1;
+  int len = f & 0x3fff;
+  src += 2;
+  do {
+    uint16 *dst = &g_zenv.vram[WORD(src[0])];
+    src += 2;
+    for (int i = 0, i_end = len >> 1; i < i_end; i++, dst += step, src += 2)
+      *dst = WORD(*src);
+  } while (!(src[1] & 0x80));
+  nmi_disable_core_updates = 0;
+}
+
+void NMI_UpdateSubscreenOverlay() {  // 808d62
+  NMI_HandleArbitraryTileMap(&g_ram[0x12000], 0, 0x80);
+}
+
+void NMI_HandleArbitraryTileMap(const uint8 *src, int i, int i_end) {  // 808dae
+  uint16 *r10 = &word_7F4000;
+  do {
+    memcpy(&g_zenv.vram[r10[i >> 1]], src, 0x80);
+    src += 0x80;
+  } while ((i += 2) != i_end);
+  nmi_disable_core_updates = 0;
+}
+
+void NMI_UpdateBG1Wall() {  // 808e09
+  // Secret Wall Right
+  CopyToVramVertical(nmi_load_target_addr, &g_ram[0xc880], 0x40);
+  CopyToVramVertical(nmi_load_target_addr + 0x800, &g_ram[0xc8c0], 0x40);
+}
+
+void NMI_TileMapNothing() {  // 808e4b
+}
+
+void NMI_UpdateLoadLightWorldMap() {  // 808e54
+  static const uint16 kLightWorldTileMapDsts[4] = { 0, 0x20, 0x1000, 0x1020 };
+  const uint8 *src = GetLightOverworldTilemap();
+  for (int j = 0; j != 4; j++) {
+    int t = kLightWorldTileMapDsts[j];
+    for (int i = 0x20; i; i--) {
+      CopyToVramLow(src, t, 0x20);
+      src += 32;
+      t += 0x80;
+    }
+  }
+}
+
+void NMI_UpdateBG2Left() {  // 808ea9
+  CopyToVram(0, &g_ram[0x10000], 0x800);
+  CopyToVram(0x800, &g_ram[0x10800], 0x800);
+}
+
+void NMI_UpdateBGChar3and4() {  // 808ee7
+  memcpy(&g_zenv.vram[0x2c00], &g_ram[0x10000], 0x1000);
+  nmi_disable_core_updates = 0;
+}
+
+void NMI_UpdateBGChar5and6() {  // 808f16
+  memcpy(&g_zenv.vram[0x3400], &g_ram[0x11000], 0x1000);
+  nmi_disable_core_updates = 0;
+}
+
+void NMI_UpdateBGCharHalf() {  // 808f45
+  memcpy(&g_zenv.vram[BYTE(nmi_load_target_addr) * 256], &g_ram[0x11000], 0x400);
+}
+
+void NMI_UpdateBGChar0() {  // 808f72
+  NMI_RunTileMapUpdateDMA(0x2000);
+}
+
+void NMI_UpdateBGChar1() {  // 808f79
+  NMI_RunTileMapUpdateDMA(0x2800);
+}
+
+void NMI_UpdateBGChar2() {  // 808f80
+  NMI_RunTileMapUpdateDMA(0x3000);
+}
+
+void NMI_UpdateBGChar3() {  // 808f87
+  NMI_RunTileMapUpdateDMA(0x3800);
+}
+
+void NMI_UpdateObjChar0() {  // 808f8e
+  CopyToVram(0x4400, &g_ram[0x10000], 0x800);
+  nmi_disable_core_updates = 0;
+}
+
+void NMI_UpdateObjChar2() {  // 808fbd
+  NMI_RunTileMapUpdateDMA(0x5000);
+}
+
+void NMI_UpdateObjChar3() {  // 808fc4
+  NMI_RunTileMapUpdateDMA(0x5800);
+}
+
+void NMI_RunTileMapUpdateDMA(int dst) {  // 808fc9
+  CopyToVram(dst, &g_ram[0x10000], 0x1000);
+  nmi_disable_core_updates = 0;
+}
+
+void NMI_UploadDarkWorldMap() {  // 808ff3
+  const uint8 *src = g_ram + 0x1000;
+  int t = 0x810;
+  for (int i = 0x20; i; i--) {
+    CopyToVramLow(src, t, 0x20);
+    src += 32;
+    t += 0x80;
+  }
+}
+
+void NMI_UploadGameOverText() {  // 809038
+  CopyToVram(0x7800, &g_ram[0x2000], 0x800);
+  CopyToVram(0x7d00, &g_ram[0x3400], 0x600);
+}
+
+void NMI_UpdatePegTiles() {  // 80908b
+  CopyToVram(0x3d00, &g_ram[0x10000], 0x100);
+}
+
+void NMI_UpdateStarTiles() {  // 8090b7
+  CopyToVram(0x3ed0, &g_ram[0x10000], 0x40);
+}
+
+void HandleStripes14(const uint8 *p) {  // 8092a1
+  while (!(p[0] & 0x80)) {
+    uint16 vmem_addr = swap16(WORD(p[0]));
+    uint8 vram_incr_amount = (p[2] & 0x80) >> 7;
+    uint8 is_memset = p[2] & 0x40;  // Cpu BUS Address Step  (0=Increment, 2=Decrement, 1/3=Fixed) (DMA only)
+    int len = (swap16(WORD(p[2])) & 0x3fff) + 1;
+    p += 4;
+
+    if (vram_incr_amount == 0) {
+      uint16 *dst = &g_zenv.vram[vmem_addr];
+      if (is_memset) {
+        uint16 v = p[0] | p[1] << 8;
+        len = (len + 1) >> 1;
+        for (int i = 0; i < len; i++)
+          dst[i] = v;
+        p += 2;
+      } else {
+        memcpy(dst, p, len);
+        p += len;
+      }
+    } else {
+      // increment vram by 32 instead of 1
+      uint16 *dst = &g_zenv.vram[vmem_addr];
+      if (is_memset) {
+        uint16 v = p[0] | p[1] << 8;
+        len = (len + 1) >> 1;
+        for (int i = 0; i < len; i++, dst += 32)
+          *dst = v;
+        p += 2;
+      } else {
+        assert((len & 1) == 0);
+        len >>= 1;
+        for (int i = 0; i < len; i++, dst += 32, p += 2)
+          WORD(*dst) = WORD(*p);
+      }
+    }
+  }
+}
+
+void NMI_UpdateIRQGFX() {  // 809347
+  if (nmi_flag_update_polyhedral) {
+    memcpy(&g_zenv.vram[0x5800], &g_ram[0xe800], 0x800);
+    nmi_flag_update_polyhedral = 0;
+  }
+}
+
--- /dev/null
+++ b/src/nmi.h
@@ -1,0 +1,35 @@
+#pragma once
+#include "types.h"
+
+void NMI_UploadSubscreenOverlayFormer();
+void NMI_UploadSubscreenOverlayLatter();
+void Interrupt_NMI(uint16 joypad_input);
+void NMI_ReadJoypads(uint16 joypad_input);
+void NMI_DoUpdates();
+void NMI_UploadTilemap();
+void NMI_UploadTilemap_doNothing();
+void NMI_UploadBG3Text();
+void NMI_UpdateOWScroll();
+void NMI_UpdateSubscreenOverlay();
+void NMI_HandleArbitraryTileMap(const uint8 *src, int i, int i_end);
+void NMI_UpdateBG1Wall();
+void NMI_TileMapNothing();
+void NMI_UpdateLoadLightWorldMap();
+void NMI_UpdateBG2Left();
+void NMI_UpdateBGChar3and4();
+void NMI_UpdateBGChar5and6();
+void NMI_UpdateBGCharHalf();
+void NMI_UpdateBGChar0();
+void NMI_UpdateBGChar1();
+void NMI_UpdateBGChar2();
+void NMI_UpdateBGChar3();
+void NMI_UpdateObjChar0();
+void NMI_UpdateObjChar2();
+void NMI_UpdateObjChar3();
+void NMI_RunTileMapUpdateDMA(int dst);
+void NMI_UploadDarkWorldMap();
+void NMI_UploadGameOverText();
+void NMI_UpdatePegTiles();
+void NMI_UpdateStarTiles();
+void HandleStripes14(const uint8 *p);
+void NMI_UpdateIRQGFX();
--- /dev/null
+++ b/src/opengl.c
@@ -1,0 +1,266 @@
+#include "third_party/gl_core/gl_core_3_1.h"
+#include <SDL.h>
+#include <stdio.h>
+#include <stdbool.h>
+#include "types.h"
+#include "util.h"
+#include "glsl_shader.h"
+#include "config.h"
+
+#define CODE(...) #__VA_ARGS__
+
+static SDL_Window *g_window;
+static uint8 *g_screen_buffer;
+static size_t g_screen_buffer_size;
+static int g_draw_width, g_draw_height;
+static unsigned int g_program, g_VAO;
+static GlTextureWithSize g_texture;
+static GlslShader *g_glsl_shader;
+static bool g_opengl_es;
+
+static void GL_APIENTRY MessageCallback(GLenum source,
+                GLenum type,
+                GLuint id,
+                GLenum severity,
+                GLsizei length,
+                const GLchar *message,
+                const void *userParam) {
+  if (type == GL_DEBUG_TYPE_OTHER)
+    return;
+
+  fprintf(stderr, "GL CALLBACK: %s type = 0x%x, severity = 0x%x, message = %s\n",
+          (type == GL_DEBUG_TYPE_ERROR ? "** GL ERROR **" : ""),
+          type, severity, message);
+  if (type == GL_DEBUG_TYPE_ERROR)
+    Die("OpenGL error!\n");
+}
+
+static bool OpenGLRenderer_Init(SDL_Window *window) {
+  g_window = window;
+  SDL_GLContext context = SDL_GL_CreateContext(window);
+  (void)context;
+
+  SDL_GL_SetSwapInterval(1);
+  ogl_LoadFunctions();
+
+  if (!g_opengl_es) {
+    if (!ogl_IsVersionGEQ(3, 3))
+      Die("You need OpenGL 3.3");
+  } else {
+    int majorVersion = 0, minorVersion = 0;
+    SDL_GL_GetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, &majorVersion);
+    SDL_GL_GetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, &minorVersion);
+    if (majorVersion < 3)
+      Die("You need OpenGL ES 3.0");
+
+  }
+
+  if (kDebugFlag) {
+    glEnable(GL_DEBUG_OUTPUT);
+    glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
+    glDebugMessageCallback(MessageCallback, 0);
+  }
+
+  glGenTextures(1, &g_texture.gl_texture);
+
+  static const float kVertices[] = {
+    // positions          // texture coords
+    -1.0f,  1.0f, 0.0f,   0.0f, 0.0f, // top left
+    -1.0f, -1.0f, 0.0f,   0.0f, 1.0f, // bottom left
+     1.0f,  1.0f, 0.0f,   1.0f, 0.0f, // top right
+     1.0f, -1.0f, 0.0f,   1.0f, 1.0f,  // bottom right
+  };
+
+  // create a vertex buffer object
+  unsigned int vbo;
+  glGenBuffers(1, &vbo);
+
+  // vertex array object
+  glGenVertexArrays(1, &g_VAO);
+  // 1. bind Vertex Array Object
+  glBindVertexArray(g_VAO);
+  // 2. copy our vertices array in a buffer for OpenGL to use
+  glBindBuffer(GL_ARRAY_BUFFER, vbo);
+  glBufferData(GL_ARRAY_BUFFER, sizeof(kVertices), kVertices, GL_STATIC_DRAW);
+  // position attribute
+  glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void *)0);
+  glEnableVertexAttribArray(0);
+  // texture coord attribute
+  glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void *)(3 * sizeof(float)));
+  glEnableVertexAttribArray(1);
+
+  // vertex shader
+  const GLchar *vs_code_core = "#version 330 core\n" CODE(
+  layout(location = 0) in vec3 aPos;
+  layout(location = 1) in vec2 aTexCoord;
+  out vec2 TexCoord;
+  void main() {
+    gl_Position = vec4(aPos, 1.0);
+    TexCoord = vec2(aTexCoord.x, aTexCoord.y);
+  }
+);
+
+  const GLchar *vs_code_es = "#version 300 es\n" CODE(
+  layout(location = 0) in vec3 aPos;
+  layout(location = 1) in vec2 aTexCoord;
+  out vec2 TexCoord;
+  void main() {
+    gl_Position = vec4(aPos, 1.0);
+    TexCoord = vec2(aTexCoord.x, aTexCoord.y);
+  }
+);
+
+  const GLchar *vs_code = g_opengl_es ? vs_code_es : vs_code_core;
+  unsigned int vs = glCreateShader(GL_VERTEX_SHADER);
+  glShaderSource(vs, 1, &vs_code, NULL);
+  glCompileShader(vs);
+
+  int success;
+  char infolog[512];
+  glGetShaderiv(vs, GL_COMPILE_STATUS, &success);
+  if (!success) {
+    glGetShaderInfoLog(vs, 512, NULL, infolog);
+    printf("%s\n", infolog);
+  }
+
+  // fragment shader
+  const GLchar *fs_code_core = "#version 330 core\n" CODE(
+  out vec4 FragColor;
+  in vec2 TexCoord;
+  // texture samplers
+  uniform sampler2D texture1;
+  void main() {
+    FragColor = texture(texture1, TexCoord);
+  }
+);
+
+  const GLchar *fs_code_es = "#version 300 es\n" CODE(
+  precision mediump float;
+  out vec4 FragColor;
+  in vec2 TexCoord;
+  // texture samplers
+  uniform sampler2D texture1;
+  void main() {
+    FragColor = texture(texture1, TexCoord);
+  }
+);
+
+
+  const GLchar *fs_code = g_opengl_es ? fs_code_es : fs_code_core;
+  unsigned int fs = glCreateShader(GL_FRAGMENT_SHADER);
+  glShaderSource(fs, 1, &fs_code, NULL);
+  glCompileShader(fs);
+
+  glGetShaderiv(fs, GL_COMPILE_STATUS, &success);
+  if (!success) {
+    glGetShaderInfoLog(fs, 512, NULL, infolog);
+    printf("%s\n", infolog);
+  }
+
+  // create program
+  int program = g_program = glCreateProgram();
+  glAttachShader(program, vs);
+  glAttachShader(program, fs);
+  glLinkProgram(program);
+  glGetProgramiv(program, GL_LINK_STATUS, &success);
+
+  if (!success) {
+    glGetProgramInfoLog(program, 512, NULL, infolog);
+    printf("%s\n", infolog);
+  }
+
+  if (g_config.shader)
+    g_glsl_shader = GlslShader_CreateFromFile(g_config.shader, g_opengl_es);
+  
+  return true;
+}
+
+static void OpenGLRenderer_Destroy() {
+}
+
+static void OpenGLRenderer_BeginDraw(int width, int height, uint8 **pixels, int *pitch) {
+  int size = width * height;
+
+  if (size > g_screen_buffer_size) {
+    g_screen_buffer_size = size;
+    free(g_screen_buffer);
+    g_screen_buffer = malloc(size * 4);
+  }
+
+  g_draw_width = width;
+  g_draw_height = height;
+  *pixels = g_screen_buffer;
+  *pitch = width * 4;
+}
+
+static void OpenGLRenderer_EndDraw() {
+  int drawable_width, drawable_height;
+
+  SDL_GL_GetDrawableSize(g_window, &drawable_width, &drawable_height);
+  
+  int viewport_width = drawable_width, viewport_height = drawable_height;
+
+  if (!g_config.ignore_aspect_ratio) {
+    if (viewport_width * g_draw_height < viewport_height * g_draw_width)
+      viewport_height = viewport_width * g_draw_height / g_draw_width;  // limit height
+    else
+      viewport_width = viewport_height * g_draw_width / g_draw_height;  // limit width
+  }
+
+  int viewport_x = (drawable_width - viewport_width) >> 1;
+  int viewport_y = (viewport_height - viewport_height) >> 1;
+
+  glBindTexture(GL_TEXTURE_2D, g_texture.gl_texture);
+  if (g_draw_width == g_texture.width && g_draw_height == g_texture.height) {
+    if (!g_opengl_es)
+      glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, g_draw_width, g_draw_height, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, g_screen_buffer);
+    else
+      glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, g_draw_width, g_draw_height, GL_BGRA, GL_UNSIGNED_BYTE, g_screen_buffer);
+  } else {
+    g_texture.width = g_draw_width;
+    g_texture.height = g_draw_height;
+    if (!g_opengl_es)
+      glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, g_draw_width, g_draw_height, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, g_screen_buffer);
+    else
+      glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, g_draw_width, g_draw_height, 0, GL_BGRA, GL_UNSIGNED_BYTE, g_screen_buffer);
+  }
+
+  glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
+  glClear(GL_COLOR_BUFFER_BIT);
+
+  if (g_glsl_shader == NULL) {
+    glViewport(viewport_x, viewport_y, viewport_width, viewport_height);
+    glUseProgram(g_program);
+    int filter = g_config.linear_filtering ? GL_LINEAR : GL_NEAREST;
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter);
+    glBindVertexArray(g_VAO);
+    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+  } else {
+    GlslShader_Render(g_glsl_shader, &g_texture, viewport_x, viewport_y, viewport_width, viewport_height);
+  }
+
+  SDL_GL_SwapWindow(g_window);
+}
+
+static const struct RendererFuncs kOpenGLRendererFuncs = {
+  &OpenGLRenderer_Init,
+  &OpenGLRenderer_Destroy,
+  &OpenGLRenderer_BeginDraw,
+  &OpenGLRenderer_EndDraw,
+};
+
+void OpenGLRenderer_Create(struct RendererFuncs *funcs, bool use_opengl_es) {
+  g_opengl_es = use_opengl_es;
+  if (!g_opengl_es) {
+    SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
+    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
+    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
+  } else {
+    SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
+    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
+    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
+  }
+  *funcs = kOpenGLRendererFuncs;
+}
+
--- /dev/null
+++ b/src/overlord.c
@@ -1,0 +1,653 @@
+#include "overlord.h"
+#include "sprite.h"
+#include "misc.h"
+#include "sprite_main.h"
+
+uint16 Overlord_GetX(int k) { return (overlord_x_lo[k] | overlord_x_hi[k] << 8); }
+uint16 Overlord_GetY(int k) { return (overlord_y_lo[k] | overlord_y_hi[k] << 8); }
+static HandlerFuncK *const kOverlordFuncs[26] = {
+  &Overlord01_PositionTarget,
+  &Overlord02_FullRoomCannons,
+  &Overlord03_VerticalCannon,
+  &Overlord_StalfosFactory,
+  &Overlord05_FallingStalfos,
+  &Overlord06_BadSwitchSnake,
+  &Overlord07_MovingFloor,
+  &Overlord08_BlobSpawner,
+  &Overlord09_WallmasterSpawner,
+  &Overlord0A_FallingSquare,
+  &Overlord0A_FallingSquare,
+  &Overlord0A_FallingSquare,
+  &Overlord0A_FallingSquare,
+  &Overlord0A_FallingSquare,
+  &Overlord0A_FallingSquare,
+  &Overlord10_PirogusuSpawner_left,
+  &Overlord10_PirogusuSpawner_left,
+  &Overlord10_PirogusuSpawner_left,
+  &Overlord10_PirogusuSpawner_left,
+  &Overlord14_TileRoom,
+  &Overlord15_WizzrobeSpawner,
+  &Overlord16_ZoroSpawner,
+  &Overlord17_PotTrap,
+  &Overlord18_InvisibleStalfos,
+  &Overlord19_ArmosCoordinator_bounce,
+  &Overlord06_BadSwitchSnake,
+};
+static inline uint8 ArmosMult(uint16 a, uint8 b);
+static inline int8 ArmosSin(uint16 a, uint8 b);
+void Overlord_StalfosFactory(int k) {
+  // unused
+  assert(0);
+}
+
+void Overlord_SetX(int k, uint16 v) {
+  overlord_x_lo[k] = v;
+  overlord_x_hi[k] = v >> 8;
+}
+
+void Overlord_SetY(int k, uint16 v) {
+  overlord_y_lo[k] = v;
+  overlord_y_hi[k] = v >> 8;
+}
+
+static inline uint8 ArmosMult(uint16 a, uint8 b) {
+  if (a >= 256)
+    return b;
+  int p = a * b;
+  return (p >> 8) + (p >> 7 & 1);
+}
+
+static inline int8 ArmosSin(uint16 a, uint8 b) {
+  uint8 t = ArmosMult(kSinusLookupTable[a & 0xff], b);
+  return (a & 0x100) ? -t : t;
+}
+
+void Overlord_SpawnBoulder() {  // 89b714
+  if (player_is_indoors || !byte_7E0FFD || (submodule_index | flag_unk1) || ++byte_7E0FFE & 63)
+    return;
+
+  if (sign8((BG2VOFS_copy2 >> 8) - (sprcoll_y_base >> 8) - 2))
+    return;
+
+  SpriteSpawnInfo info;
+  int j = Sprite_SpawnDynamically(0, 0xc2, &info);
+  if (j >= 0) {
+    Sprite_SetX(j, BG2HOFS_copy2 + (GetRandomNumber() & 127) + 64);
+    Sprite_SetY(j, BG2VOFS_copy2 - 0x30);
+    sprite_floor[j] = 0;
+    sprite_D[j] = 0;
+    sprite_z[j] = 0;
+  }
+}
+
+void Overlord_Main() {  // 89b773
+  Overlord_ExecuteAll();
+  Overlord_SpawnBoulder();
+}
+
+void Overlord_ExecuteAll() {  // 89b77e
+  if (submodule_index | flag_unk1)
+    return;
+  for (int i = 7; i >= 0; i--) {
+    if (overlord_type[i])
+      Overlord_ExecuteSingle(i);
+  }
+}
+
+void Overlord_ExecuteSingle(int k) {  // 89b793
+  int j = overlord_type[k];
+  Overlord_CheckIfActive(k);
+  kOverlordFuncs[j - 1](k);
+}
+
+void Overlord19_ArmosCoordinator_bounce(int k) {  // 89b7dc
+  static const uint8 kArmosCoordinator_BackWallX[6] = { 49, 77, 105, 131, 159, 187 };
+
+  if (overlord_gen2[k])
+    overlord_gen2[k]--;
+  switch (overlord_gen1[k]) {
+  case 0:  // wait for knight activation
+    if (sprite_A[0]) {
+      overlord_x_lo[k] = 120;
+      overlord_floor[k] = 255;
+      overlord_x_lo[2] = 64;
+      overlord_x_lo[0] = 192;
+      overlord_x_lo[1] = 1;
+      ArmosCoordinator_RotateKnights(k);
+    }
+    break;
+  case 1:  // wait knight under coercion
+    if (ArmosCoordinator_CheckKnights()) {
+      overlord_gen1[k]++;
+      overlord_gen2[k] = 0xff;
+    }
+    break;
+  case 2:  // timed rotate then transition
+  case 4:
+    ArmosCoordinator_RotateKnights(k);
+    break;
+  case 3:  // radial contraction
+    if (--overlord_x_lo[2] == 32) {
+      overlord_gen1[k]++;
+      overlord_gen2[k] = 64;
+    }
+    ArmosCoordinator_Rotate(k);
+    break;
+  case 5:  // radial dilation
+    if (++overlord_x_lo[2] == 64) {
+      overlord_gen1[k]++;
+      overlord_gen2[k] = 64;
+    }
+    ArmosCoordinator_Rotate(k);
+    break;
+  case 6:  // order knights to back wall
+    if (overlord_gen2[k])
+      return;
+    ArmosCoordinator_DisableCoercion(k);
+    for (int j = 5; j >= 0; j--) {
+      overlord_x_hi[j] = kArmosCoordinator_BackWallX[j];
+      overlord_gen2[j] = 48;
+    }
+    overlord_gen1[k]++;
+    overlord_gen2[k] = 255;
+    break;
+  case 7:  // cascade knights to front wall
+    if (overlord_gen2[k])
+      return;
+    for (int j = 5; j >= 0; j--) {
+      if (++overlord_gen2[j] == 192) {
+        overlord_gen1[k] = 1;
+        overlord_floor[k] = -overlord_floor[k];
+        ArmosCoordinator_DisableCoercion(k);
+        ArmosCoordinator_Rotate(k);
+        return;
+      }
+    }
+    break;
+  }
+}
+
+void Overlord18_InvisibleStalfos(int k) {  // 89b7f5
+  static const int8 kRedStalfosTrap_X[4] = { 0, 0, -48, 48 };
+  static const int8 kRedStalfosTrap_Y[4] = { -40, 56, 8, 8 };
+  static const uint8 kRedStalfosTrap_Delay[4] = { 0x30, 0x50, 0x70, 0x90 };
+
+  uint16 x = (overlord_x_lo[k] | overlord_x_hi[k] << 8);
+  uint16 y = (overlord_y_lo[k] | overlord_y_hi[k] << 8);
+  if ((uint16)(x - link_x_coord + 24) >= 48 || (uint16)(y - link_y_coord + 24) >= 48)
+    return;
+  overlord_type[k] = 0;
+  tmp_counter = 3;
+  do {
+    SpriteSpawnInfo info;
+    int j = Sprite_SpawnDynamicallyEx(k, 0xa7, &info, 12);
+    if (j < 0)
+      return;
+    Sprite_SetX(j, link_x_coord + kRedStalfosTrap_X[tmp_counter]);
+    Sprite_SetY(j, link_y_coord + kRedStalfosTrap_Y[tmp_counter]);
+    sprite_delay_main[j] = kRedStalfosTrap_Delay[tmp_counter];
+    sprite_floor[j] = overlord_floor[k];
+    sprite_E[j] = 1;
+    sprite_flags2[j] = 3;
+    sprite_D[j] = 2;
+  } while (!sign8(--tmp_counter));
+}
+
+void Overlord17_PotTrap(int k) {  // 89b884
+  uint16 x = (overlord_x_lo[k] | overlord_x_hi[k] << 8);
+  uint16 y = (overlord_y_lo[k] | overlord_y_hi[k] << 8);
+  if ((uint16)(x - link_x_coord + 32) < 64 &&
+      (uint16)(y - link_y_coord + 32) < 64) {
+    overlord_type[k] = 0;
+    byte_7E0B9E++;
+  }
+}
+
+void Overlord16_ZoroSpawner(int k) {  // 89b8d1
+  static const int8 kOverlordZoroFactory_X[8] = { -4, -2, 0, 2, 4, 6, 8, 12 };
+  overlord_gen2[k]--;
+  uint16 x = Overlord_GetX(k) + 8;
+  uint16 y = Overlord_GetY(k) + 8;
+  if (GetTileAttribute(overlord_floor[k], &x, y) != 0x82)
+    return;
+  if (overlord_gen2[k] >= 0x18 || (overlord_gen2[k] & 3) != 0)
+    return;
+  SpriteSpawnInfo info;
+  int j = Sprite_SpawnDynamicallyEx(k, 0x9c, &info, 12);
+  if (j >= 0) {
+    Sprite_SetX(j, info.r5_overlord_x + kOverlordZoroFactory_X[GetRandomNumber() & 7] + 8);
+    sprite_y_lo[j] = info.r7_overlord_y + 8;
+    sprite_y_hi[j] = info.r7_overlord_y >> 8;
+    sprite_floor[j] = overlord_floor[k];
+    sprite_flags4[j] = 1;
+    sprite_E[j] = 1;
+    sprite_ignore_projectile[j] = 1;
+    sprite_y_vel[j] = 16;
+    sprite_flags2[j] = 32;
+    sprite_oam_flags[j] = 13;
+    sprite_subtype2[j] = GetRandomNumber();
+    sprite_delay_main[j] = 48;
+    sprite_bump_damage[j] = 3;
+  }
+}
+
+void Overlord15_WizzrobeSpawner(int k) {  // 89b986
+  static const int8 kOverlordWizzrobe_X[4] = { 48, -48, 0, 0 };
+  static const int8 kOverlordWizzrobe_Y[4] = { 16, 16, 64, -32 };
+  static const uint8 kOverlordWizzrobe_Delay[4] = { 0, 16, 32, 48 };
+  if (overlord_gen2[k] != 128) {
+    if (frame_counter & 1)
+      overlord_gen2[k]--;
+    return;
+  }
+  overlord_gen2[k] = 127;
+  for (int i = 3; i >= 0; i--) {
+    SpriteSpawnInfo info;
+    int j = Sprite_SpawnDynamicallyEx(k, 0x9b, &info, 12);
+    if (j >= 0) {
+      Sprite_SetX(j, link_x_coord + kOverlordWizzrobe_X[i]);
+      Sprite_SetY(j, link_y_coord + kOverlordWizzrobe_Y[i]);
+      sprite_delay_main[j] = kOverlordWizzrobe_Delay[i];
+      sprite_floor[j] = overlord_floor[k];
+      sprite_B[j] = 1;
+    }
+  }
+  tmp_counter = 0xff;
+}
+
+void Overlord14_TileRoom(int k) {  // 89b9e8
+  uint16 x = (overlord_x_lo[k] | overlord_x_hi[k] << 8) - BG2HOFS_copy2;
+  uint16 y = (overlord_y_lo[k] | overlord_y_hi[k] << 8) - BG2VOFS_copy2;
+  if (x & 0xff00 || y & 0xff00)
+    return;
+  if (--overlord_gen2[k] != 0x80)
+    return;
+  int j = TileRoom_SpawnTile(k);
+  if (j < 0) {
+    overlord_gen2[k] = 0x81;
+    return;
+  }
+  if (++overlord_gen1[k] != 22)
+    overlord_gen2[k] = 0xE0;
+  else
+    overlord_type[k] = 0;
+}
+
+int TileRoom_SpawnTile(int k) {  // 89ba56
+  static const uint8 kSpawnFlyingTile_X[22] = {
+    0x70, 0x80, 0x60, 0x90, 0x90, 0x60, 0x70, 0x80, 0x80, 0x70, 0x50, 0xa0, 0xa0, 0x50, 0x50, 0xa0,
+    0xa0, 0x50, 0x70, 0x80, 0x80, 0x70,
+  };
+  static const uint8 kSpawnFlyingTile_Y[22] = {
+    0x80, 0x80, 0x70, 0x90, 0x70, 0x90, 0x60, 0xa0, 0x60, 0xa0, 0x60, 0xb0, 0x60, 0xb0, 0x80, 0x90,
+    0x80, 0x90, 0x70, 0x90, 0x70, 0x90,
+  };
+  SpriteSpawnInfo info;
+  int j = Sprite_SpawnDynamically(k, 0x94, &info);
+  if (j < 0)
+    return j;
+  sprite_E[j] = 1;
+  int i = overlord_gen1[k];
+  sprite_x_lo[j] = kSpawnFlyingTile_X[i];
+  sprite_y_lo[j] = kSpawnFlyingTile_Y[i] - 8;
+  sprite_y_hi[j] = overlord_y_hi[k];
+  sprite_x_hi[j] = overlord_x_hi[k];
+  sprite_floor[j] = overlord_floor[k];
+  sprite_health[j] = 4;
+  sprite_flags5[j] = 0;
+  sprite_health[j] = 0;
+  sprite_defl_bits[j] = 8;
+  sprite_flags2[j] = 4;
+  sprite_oam_flags[j] = 1;
+  sprite_bump_damage[j] = 4;
+  return j;
+}
+
+void Overlord10_PirogusuSpawner_left(int k) {  // 89baac
+  static const uint8 kOverlordPirogusu_A[4] = { 2, 3, 0, 1 };
+
+  tmp_counter = overlord_type[k] - 16;
+  if (overlord_gen2[k] != 128) {
+    overlord_gen2[k]--;
+    return;
+  }
+  overlord_gen2[k] = (GetRandomNumber() & 31) + 96;
+  int n = 0;
+  for (int i = 0; i != 16; i++) {
+    if (sprite_state[i] != 0 && sprite_type[i] == 0x10)
+      n++;
+  }
+  if (n >= 5)
+    return;
+  SpriteSpawnInfo info;
+  int j = Sprite_SpawnDynamicallyEx(k, 0x94, &info, 12);
+  if (j >= 0) {
+    Sprite_SetX(j, info.r5_overlord_x);
+    Sprite_SetY(j, info.r7_overlord_y);
+    sprite_floor[j] = overlord_floor[k];
+    sprite_delay_main[j] = 32;
+    sprite_D[j] = tmp_counter;
+    sprite_A[j] = kOverlordPirogusu_A[tmp_counter];
+  }
+}
+
+void Overlord0A_FallingSquare(int k) {  // 89bbb2
+  static const uint8 kCrumbleTilePathData[108 + 1] = {
+    2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 3, 3, 3,
+    3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 3, 1, 3, 0, 3, 1,
+    3, 0, 3, 1, 3, 0, 3, 1, 3, 0, 3, 1, 3, 0, 3, 1,
+    3, 0, 3, 1, 3, 0, 3, 1, 3, 0, 3, 1, 3, 0, 3, 1,
+    3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2,
+    2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0xff
+  };
+  static const uint8 kCrumbleTilePathOffs[7] = {
+    0, 25, 66, 77, 87, 98, 108
+  };
+  static const int8 kCrumbleTilePath_X[4] = { 16, -16, 0, 0 };
+  static const int8 kCrumbleTilePath_Y[4] = { 0, 0, 16, -16 };
+  if (overlord_gen2[k]) {
+    if (overlord_gen3[k]) {
+      overlord_gen2[k]--;
+      return;
+    }
+    uint16 x = Overlord_GetX(k) - BG2HOFS_copy2;
+    uint16 y = Overlord_GetY(k) - BG2VOFS_copy2;
+    if (!(x & 0xff00 || y & 0xff00))
+      overlord_gen3[k]++;
+    return;
+  }
+
+  overlord_gen2[k] = 16;
+  SpawnFallingTile(k);
+  int j = overlord_type[k] - 10;
+  int i = overlord_gen1[k]++;
+  if (i == kCrumbleTilePathOffs[j + 1] - kCrumbleTilePathOffs[j]) {
+    overlord_type[k] = 0;
+  }
+  int t = kCrumbleTilePathData[kCrumbleTilePathOffs[j] + i];
+  if (t == 0xff) {
+    Overlord_SetX(k, Overlord_GetX(k) + 0xc1a);
+    Overlord_SetY(k, Overlord_GetY(k) + 0xbb66);
+  } else {
+    Overlord_SetX(k, Overlord_GetX(k) + kCrumbleTilePath_X[t]);
+    Overlord_SetY(k, Overlord_GetY(k) + kCrumbleTilePath_Y[t]);
+  }
+}
+
+void SpawnFallingTile(int k) {  // 89bc31
+  int j = GarnishAlloc();
+  if (j >= 0) {
+    garnish_type[j] = 3;
+    garnish_x_hi[j] = overlord_x_hi[k];
+    garnish_x_lo[j] = overlord_x_lo[k];
+    sound_effect_1 = CalculateSfxPan_Arbitrary(garnish_x_lo[j]) | 0x1f;
+    int y = Overlord_GetY(k) + 16;
+    garnish_y_lo[j] = y;
+    garnish_y_hi[j] = y >> 8;
+    garnish_countdown[j] = 31;
+    garnish_active = 31;
+  }
+}
+
+void Overlord09_WallmasterSpawner(int k) {  // 89bc7b
+  if (overlord_gen2[k] != 128) {
+    if (!(frame_counter & 1))
+      overlord_gen2[k]--;
+    return;
+  }
+  overlord_gen2[k] = 127;
+  SpriteSpawnInfo info;
+  int j = Sprite_SpawnDynamicallyEx(k, 0x90, &info, 12);
+  if (j < 0)
+    return;
+  Sprite_SetX(j, link_x_coord);
+  Sprite_SetY(j, link_y_coord);
+  sprite_z[j] = 208;
+  SpriteSfx_QueueSfx2WithPan(j, 0x20);
+  sprite_floor[j] = link_is_on_lower_level;
+}
+
+void Overlord08_BlobSpawner(int k) {  // 89bcc3
+  if (overlord_gen2[k]) {
+    overlord_gen2[k]--;
+    return;
+  }
+  overlord_gen2[k] = 0xa0;
+  int n = 0;
+  for (int i = 0; i != 16; i++) {
+    if (sprite_state[i] != 0 && sprite_type[i] == 0x8f)
+      n++;
+  }
+  if (n >= 5)
+    return;
+
+  SpriteSpawnInfo info;
+  int j = Sprite_SpawnDynamicallyEx(k, 0x8f, &info, 12);
+  if (j >= 0) {
+    static const int8 kOverlordZol_X[4] = { 0, 0, -48, 48 };
+    static const int8 kOverlordZol_Y[4] = { -40, 56, 8, 8 };
+    int i = link_direction_facing >> 1;
+    Sprite_SetX(j, link_x_coord + kOverlordZol_X[i]);
+    Sprite_SetY(j, link_y_coord + kOverlordZol_Y[i]);
+    sprite_z[j] = 192;
+    sprite_floor[j] = link_is_on_lower_level;
+    sprite_ai_state[j] = 2;
+    sprite_E[j] = 2;
+    sprite_C[j] = 2;
+    sprite_head_dir[j] = GetRandomNumber() & 31 | 16;
+  }
+}
+
+void Overlord07_MovingFloor(int k) {  // 89bd3f
+  if (sprite_state[0] == 4) {
+    overlord_type[k] = 0;
+    BYTE(dung_floor_move_flags) = 1;
+    return;
+  }
+  if (!overlord_gen1[k]) {
+    if (++overlord_gen2[k] == 32) {
+      overlord_gen2[k] = 0;
+      BYTE(dung_floor_move_flags) = (GetRandomNumber() & (overlord_x_lo[k] ? 3 : 1)) * 2;
+      overlord_gen2[k] = (GetRandomNumber() & 127) + 128;
+      overlord_gen1[k]++;
+    } else {
+      BYTE(dung_floor_move_flags) = 1;
+    }
+  } else {
+    if (!--overlord_gen2[k])
+      overlord_gen1[k] = 0;
+  }
+}
+
+void Sprite_Overlord_PlayFallingSfx(int k) {  // 89bdfd
+  SpriteSfx_QueueSfx2WithPan(k, 0x20);
+}
+
+void Overlord05_FallingStalfos(int k) {  // 89be0f
+  static const uint8 kStalfosTrap_Trigger[8] = { 255, 224, 192, 160, 128, 96, 64, 32 };
+
+  uint16 x = (overlord_x_lo[k] | overlord_x_hi[k] << 8) - BG2HOFS_copy2;
+  uint16 y = (overlord_y_lo[k] | overlord_y_hi[k] << 8) - BG2VOFS_copy2;
+  if (x & 0xff00 || y & 0xff00)
+    return;
+  if (overlord_gen1[k] == 0) {
+    if (byte_7E0B9E)
+      overlord_gen1[k]++;
+    return;
+  }
+  if (overlord_gen1[k]++ == kStalfosTrap_Trigger[k]) {
+    overlord_type[k] = 0;
+    SpriteSpawnInfo info;
+    int j = Sprite_SpawnDynamicallyEx(k, 0x85, &info, 12);
+    if (j < 0)
+      return;
+    Sprite_SetX(j, info.r5_overlord_x);
+    Sprite_SetY(j, info.r7_overlord_y);
+    sprite_z[j] = 224;
+    sprite_floor[j] = overlord_floor[k];
+    sprite_D[j] = 0; // zelda bug: unitialized
+    Sprite_Overlord_PlayFallingSfx(j);
+  }
+}
+
+void Overlord06_BadSwitchSnake(int k) {  // 89be75
+  static const uint8 kSnakeTrapOverlord_Tab1[8] = { 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80, 0x90 };
+
+  uint8 a = overlord_gen1[k];
+  if (a == 0) {
+    if (activate_bomb_trap_overlord != 0)
+      overlord_gen1[k] = 1;
+    return;
+  }
+  overlord_gen1[k] = a + 1;
+
+  if (a != kSnakeTrapOverlord_Tab1[k])
+    return;
+
+  SpriteSpawnInfo info;
+  int j = Sprite_SpawnDynamically(k, 0x6e, &info);
+  if (j < 0)
+    return;
+  Sprite_SetX(j, info.r5_overlord_x);
+  Sprite_SetY(j, info.r7_overlord_y);
+
+  sprite_z[j] = 192;
+  sprite_E[j] = 192;
+
+  sprite_flags3[j] |= 0x10;
+  sprite_floor[j] = overlord_floor[k];
+  SpriteSfx_QueueSfx2WithPan(j, 0x20);
+  uint8 type = overlord_type[k];
+  overlord_type[k] = 0;
+  if (type == 26) {
+    sprite_type[j] = 74;
+    Sprite_TransmuteToBomb(j);
+    sprite_delay_aux1[j] = 112;
+  }
+}
+
+void Overlord02_FullRoomCannons(int k) {  // 89bf09
+  static const uint8 kAllDirectionMetalBallFactory_Idx[16] = { 2, 2, 2, 2, 1, 1, 1, 1, 3, 3, 3, 3, 0, 0, 0, 0 };
+  static const uint8 kAllDirectionMetalBallFactory_X[16] = { 64, 96, 144, 176, 240, 240, 240, 240, 176, 144, 96, 64, 0, 0, 0, 0 };
+  static const uint8 kAllDirectionMetalBallFactory_Y[16] = { 16, 16, 16, 16, 64, 96, 160, 192, 240, 240, 240, 240, 192, 160, 96, 64 };
+  uint16 x = (overlord_x_lo[k] | overlord_x_hi[k] << 8) - BG2HOFS_copy2;
+  uint16 y = (overlord_y_lo[k] | overlord_y_hi[k] << 8) - BG2VOFS_copy2;
+  if ((x | y) & 0xff00 || frame_counter & 0xf)
+    return;
+
+  byte_7E0FB6 = 0;
+  int j = GetRandomNumber() & 15;
+  tmp_counter = kAllDirectionMetalBallFactory_Idx[j];
+  overlord_x_lo[k] = kAllDirectionMetalBallFactory_X[j];
+  overlord_x_hi[k] = byte_7E0FB0;
+  overlord_y_lo[k] = kAllDirectionMetalBallFactory_Y[j];
+  overlord_y_hi[k] = byte_7E0FB1 + 1;
+  Overlord_SpawnCannonBall(k, 0);
+}
+
+void Overlord03_VerticalCannon(int k) {  // 89bf5b
+  uint16 x = (overlord_x_lo[k] | overlord_x_hi[k] << 8) - BG2HOFS_copy2;
+  if (x & 0xff00) {
+    overlord_gen2[k] = 255;
+    return;
+  }
+  if (!(frame_counter & 1) && overlord_gen2[k])
+    overlord_gen2[k]--;
+  tmp_counter = 2;
+  byte_7E0FB6 = 0;
+  if (!sign8(--overlord_gen1[k]))
+    return;
+  overlord_gen1[k] = 56;
+  int xd;
+  if (!overlord_gen2[k]) {
+    overlord_gen2[k] = 160;
+    byte_7E0FB6 = 160;
+    xd = 8;
+  } else {
+    xd = (GetRandomNumber() & 2) * 8;
+  }
+  Overlord_SpawnCannonBall(k, xd);
+}
+
+void Overlord_SpawnCannonBall(int k, int xd) {  // 89bfaf
+  static const int8 kOverlordSpawnBall_Xvel[4] = { 24, -24, 0, 0 };
+  static const int8 kOverlordSpawnBall_Yvel[4] = { 0, 0, 24, -24 };
+  SpriteSpawnInfo info;
+  int j = Sprite_SpawnDynamically(k, 0x50, &info);
+  if (j < 0)
+    return;
+
+  Sprite_SetX(j, info.r5_overlord_x + xd);
+  Sprite_SetY(j, info.r7_overlord_y - 1);
+
+  sprite_x_vel[j] = kOverlordSpawnBall_Xvel[tmp_counter];
+  sprite_y_vel[j] = kOverlordSpawnBall_Yvel[tmp_counter];
+  sprite_floor[j] = overlord_floor[k];
+  if (byte_7E0FB6) {
+    sprite_ai_state[j] = byte_7E0FB6;
+    sprite_y_lo[j] = sprite_y_lo[j] + 8;
+    sprite_flags2[j] = 3;
+    sprite_flags4[j] = 9;
+  }
+  sprite_delay_aux2[j] = 64;
+  SpriteSfx_QueueSfx3WithPan(j, 0x7);
+}
+
+void Overlord01_PositionTarget(int k) {  // 89c01e
+  byte_7E0FDE = k;
+}
+
+void Overlord_CheckIfActive(int k) {  // 89c08d
+  static const int16 kOverlordInRangeOffs[2] = { 0x130, -0x40 };
+  if (player_is_indoors)
+    return;
+  int j = frame_counter & 1;
+  uint16 x = BG2HOFS_copy2 + kOverlordInRangeOffs[j] - (overlord_x_lo[k] | overlord_x_hi[k] << 8);
+  uint16 y = BG2VOFS_copy2 + kOverlordInRangeOffs[j] - (overlord_y_lo[k] | overlord_y_hi[k] << 8);
+  if ((x >> 15) != j || (y >> 15) != j) {
+    overlord_type[k] = 0;
+    uint16 blk = overlord_offset_sprite_pos[k];
+    if (blk != 0xffff) {
+      uint8 loadedmask = (0x80 >> (blk & 7));
+      overworld_sprite_was_loaded[blk >> 3] &= ~loadedmask;
+    }
+  }
+}
+
+void ArmosCoordinator_RotateKnights(int k) {  // 9deccc
+  if (!overlord_gen2[k])
+    overlord_gen1[k]++;
+  ArmosCoordinator_Rotate(k);
+}
+
+void ArmosCoordinator_Rotate(int k) {  // 9decd4
+  static const uint16 kArmosCoordinator_Tab0[6] = { 0, 425, 340, 255, 170, 85 };
+
+  WORD(overlord_x_lo[0]) += (int8)overlord_floor[k];
+  for (int i = 0; i != 6; i++) {
+    int t0 = WORD(overlord_x_lo[0]) + kArmosCoordinator_Tab0[i];
+    uint8 size = overlord_x_lo[2];
+    int tx = (overlord_x_lo[k] | overlord_x_hi[k] << 8) + ArmosSin(t0, size);
+    overlord_x_hi[i] = tx;
+    overlord_y_hi[i] = tx >> 8;
+    int ty = (overlord_y_lo[k] | overlord_y_hi[k] << 8) + ArmosSin(t0 + 0x80, size);
+    overlord_gen2[i] = ty;
+    overlord_floor[i] = ty >> 8;
+  }
+  tmp_counter = 6;
+}
+
+bool ArmosCoordinator_CheckKnights() {  // 9dedb8
+  for (int j = 5; j >= 0; j--) {
+    if (sprite_state[j] && sprite_ai_state[j] == 0)
+      return false;
+  }
+  return true;
+}
+
+void ArmosCoordinator_DisableCoercion(int k) {  // 9dedcb
+  for (int j = 5; j >= 0; j--)
+    sprite_ai_state[j] = 0;
+}
+
--- /dev/null
+++ b/src/overlord.h
@@ -1,0 +1,35 @@
+#pragma once
+#include "types.h"
+
+void Overlord_StalfosFactory(int k);
+void Overlord_SetX(int k, uint16 v);
+void Overlord_SetY(int k, uint16 v);
+void Overlord_SpawnBoulder();
+void Overlord_Main();
+void Overlord_ExecuteAll();
+void Overlord_ExecuteSingle(int k);
+void Overlord19_ArmosCoordinator_bounce(int k);
+void Overlord18_InvisibleStalfos(int k);
+void Overlord17_PotTrap(int k);
+void Overlord16_ZoroSpawner(int k);
+void Overlord15_WizzrobeSpawner(int k);
+void Overlord14_TileRoom(int k);
+int TileRoom_SpawnTile(int k);
+void Overlord10_PirogusuSpawner_left(int k);
+void Overlord0A_FallingSquare(int k);
+void SpawnFallingTile(int k);
+void Overlord09_WallmasterSpawner(int k);
+void Overlord08_BlobSpawner(int k);
+void Overlord07_MovingFloor(int k);
+void Sprite_Overlord_PlayFallingSfx(int k);
+void Overlord05_FallingStalfos(int k);
+void Overlord06_BadSwitchSnake(int k);
+void Overlord02_FullRoomCannons(int k);
+void Overlord03_VerticalCannon(int k);
+void Overlord_SpawnCannonBall(int k, int xd);
+void Overlord01_PositionTarget(int k);
+void Overlord_CheckIfActive(int k);
+void ArmosCoordinator_RotateKnights(int k);
+void ArmosCoordinator_Rotate(int k);
+bool ArmosCoordinator_CheckKnights();
+void ArmosCoordinator_DisableCoercion(int k);
--- /dev/null
+++ b/src/overworld.c
@@ -1,0 +1,4093 @@
+#include "overworld.h"
+#include "hud.h"
+#include "load_gfx.h"
+#include "dungeon.h"
+#include "tagalong.h"
+#include "sprite.h"
+#include "ancilla.h"
+#include "player.h"
+#include "misc.h"
+#include "messaging.h"
+#include "player_oam.h"
+#include "snes/snes_regs.h"
+#include "assets.h"
+
+const uint16 kOverworld_OffsetBaseX[64] = {
+  0,     0, 0x400, 0x600, 0x600, 0xa00, 0xa00, 0xe00,
+  0,     0, 0x400, 0x600, 0x600, 0xa00, 0xa00, 0xe00,
+  0, 0x200, 0x400, 0x600, 0x800, 0xa00, 0xc00, 0xe00,
+  0,     0, 0x400, 0x600, 0x600, 0xa00, 0xc00, 0xc00,
+  0,     0, 0x400, 0x600, 0x600, 0xa00, 0xc00, 0xc00,
+  0, 0x200, 0x400, 0x600, 0x800, 0xa00, 0xc00, 0xe00,
+  0,     0, 0x400, 0x600, 0x800, 0xa00, 0xa00, 0xe00,
+  0,     0, 0x400, 0x600, 0x800, 0xa00, 0xa00, 0xe00,
+};
+const uint16 kOverworld_OffsetBaseY[64] = {
+      0,     0,     0,     0,     0,     0,     0,     0,
+      0,     0, 0x200,     0,     0,     0,     0, 0x200,
+  0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400, 0x400,
+  0x600, 0x600, 0x600, 0x600, 0x600, 0x600, 0x600, 0x600,
+  0x600, 0x600, 0x800, 0x600, 0x600, 0x800, 0x600, 0x600,
+  0xa00, 0xa00, 0xa00, 0xa00, 0xa00, 0xa00, 0xa00, 0xa00,
+  0xc00, 0xc00, 0xc00, 0xc00, 0xc00, 0xc00, 0xc00, 0xc00,
+  0xc00, 0xc00, 0xe00, 0xe00, 0xe00, 0xc00, 0xc00, 0xe00,
+};
+static const uint16 kOverworld_UpDownScrollTarget[64] = {
+  0xff20, 0xff20, 0xff20, 0xff20, 0xff20, 0xff20, 0xff20, 0xff20,
+  0xff20, 0xff20,  0x120, 0xff20, 0xff20, 0xff20, 0xff20,  0x120,
+   0x320,  0x320,  0x320,  0x320,  0x320,  0x320,  0x320,  0x320,
+   0x520,  0x520,  0x520,  0x520,  0x520,  0x520,  0x520,  0x520,
+   0x520,  0x520,  0x720,  0x520,  0x520,  0x720,  0x520,  0x520,
+   0x920,  0x920,  0x920,  0x920,  0x920,  0x920,  0x920,  0x920,
+   0xb20,  0xb20,  0xb20,  0xb20,  0xb20,  0xb20,  0xb20,  0xb20,
+   0xb20,  0xb20,  0xd20,  0xd20,  0xd20,  0xb20,  0xb20,  0xd20,
+};
+static const uint16 kOverworld_LeftRightScrollTarget[64] = {
+  0xff00, 0xff00, 0x300, 0x500, 0x500, 0x900, 0x900, 0xd00,
+  0xff00, 0xff00, 0x300, 0x500, 0x500, 0x900, 0x900, 0xd00,
+  0xff00,  0x100, 0x300, 0x500, 0x700, 0x900, 0xb00, 0xd00,
+  0xff00, 0xff00, 0x300, 0x500, 0x500, 0x900, 0xb00, 0xb00,
+  0xff00, 0xff00, 0x300, 0x500, 0x500, 0x900, 0xb00, 0xb00,
+  0xff00,  0x100, 0x300, 0x500, 0x700, 0x900, 0xb00, 0xd00,
+  0xff00, 0xff00, 0x300, 0x500, 0x700, 0x900, 0x900, 0xd00,
+  0xff00, 0xff00, 0x300, 0x500, 0x700, 0x900, 0x900, 0xd00,
+};
+#if 0
+static const uint16 kSpExit_Top[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0x200, 0x200, 0, 0, 0, 0, 0, 0 };
+static const uint16 kSpExit_Bottom[16] = { 0x120, 0x20, 0x320, 0x20, 0, 0, 0x320, 0x320, 0x320, 0x220, 0, 0, 0, 0, 0x320, 0x320 };
+static const uint16 kSpExit_Left[16] = { 0, 0x100, 0x200, 0x600, 0x600, 0xa00, 0xc00, 0xc00, 0, 0x100, 0x200, 0x600, 0x600, 0xa00, 0xc00, 0xc00 };
+static const uint16 kSpExit_Right[16] = { 0, 0x100, 0x500, 0x600, 0x600, 0xa00, 0xc00, 0xc00, 0, 0x100, 0x400, 0x600, 0x600, 0xa00, 0xc00, 0xc00 };
+static const uint16 kSpExit_Tab4[16] = { 0xff20, 0xff20, 0xff20, 0xff20, 0xff20, 0xff20, 0xff20, 0xff20, 0xff20, 0xff20, 0x120, 0xff20, 0xff20, 0xff20, 0xff20, 0x120 };
+static const int16 kSpExit_Tab6[16] = { -4, 0x100, 0x300, 0x100, 0x500, 0x900, 0xb00, 0xb00, -4, 0x100, 0x300, 0x500, 0x500, 0x900, 0xb00, 0xb00 };
+static const int16 kSpExit_Tab5[16] = { -0xe0, -0xe0, -0xe0, -0xe0, -0xe0, -0xe0, 0x400, 0x400, -0xe0, -0xe0, 0x120, -0xe0, -0xe0, -0xe0, 0x400, 0x400 };
+static const uint16 kSpExit_Tab7[16] = { 4, 0x104, 0x300, 0x100, 0x500, 0x900, 0xb00, 0xb00, 4, 0x104, 0x300, 0x100, 0x500, 0x900, 0xb00, 0xb00 };
+static const uint16 kSpExit_LeftEdgeOfMap[16] = { 0, 0, 0x200, 0x600, 0x600, 0xa00, 0xc00, 0xc00, 0, 0, 0x200, 0x600, 0x600, 0xa00, 0xc00, 0xc00 };
+static const uint8 kSpExit_Dir[16] = { 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+static const uint8 kSpExit_SprGfx[16] = { 0xc, 0xc, 0xe, 0xe, 0xe, 0x10, 0x10, 0x10, 0xe, 0xe, 0xe, 0xe, 0x10, 0x10, 0x10, 0x10 };
+static const uint8 kSpExit_AuxGfx[16] = { 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f };
+static const uint8 kSpExit_PalBg[16] = { 0xa, 0xa, 0xa, 0xa, 2, 2, 2, 0xa, 2, 2, 0xa, 2, 2, 2, 2, 0xa };
+static const uint8 kSpExit_PalSpr[16] = { 1, 8, 8, 8, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 2 };
+#endif
+#define turtlerock_ctr (some_menu_ctr)
+#define ganonentrance_ctr (some_menu_ctr)
+static PlayerHandlerFunc *const kOverworld_EntranceSequence[5] = {
+  &Overworld_AnimateEntrance_PoD,
+  &Overworld_AnimateEntrance_Skull,
+  &Overworld_AnimateEntrance_Mire,
+  &Overworld_AnimateEntrance_TurtleRock,
+  &Overworld_AnimateEntrance_GanonsTower,
+};
+#ifndef map16_decode_0
+#define map16_decode_0 ((uint8*)(g_ram+0x14400))
+#define map16_decode_1 ((uint8*)(g_ram+0x14410))
+#define map16_decode_2 ((uint8*)(g_ram+0x14420))
+#define map16_decode_3 ((uint8*)(g_ram+0x14430))
+#define map16_decode_last (*(uint16*)(g_ram+0x14440))
+#define map16_decode_tmp (*(uint16*)(g_ram+0x14442))
+#endif
+static const uint16 kSecondaryOverlayPerOw[128] = {
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0x1c0c, 0x1c0c, 0, 0, 0, 0, 0, 0, 0x1c0c, 0x1c0c, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0x3b0, 0x180c, 0x180c, 0x288, 0, 0, 0, 0, 0, 0x180c, 0x180c, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1ab6, 0x1ab6, 0, 0xe2e, 0xe2e, 0, 0, 0,
+  0x1ab6, 0x1ab6, 0, 0xe2e, 0xe2e, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x3b0, 0, 0, 0x288,
+  0, 0, 0, 0, 0, 0, 0, 0,
+};
+#define XY(x, y) ((y)*64+(x))
+// this alternate entry point is for scrolling OW area loads
+// b/c drawing a door only applies to when you transition from a dungeon to the OW
+// the exceptioon is OW areas 0x80 and above which are handled similar to entrances
+static const uint16 kOverworld_DrawStrip_Tab[3] = { 0x3d0, 0x410, 0xf410 };
+static const uint16 kOverworld_Func2_Tab[4] = { 8, 4, 2, 1 };
+static const uint16 kOverworld_Entrance_Tab0[44] = {
+  0xfe, 0xc5, 0xfe, 0x114, 0x115, 0x175, 0x156, 0xf5, 0xe2, 0x1ef, 0x119, 0xfe, 0x172, 0x177, 0x13f, 0x172, 0x112, 0x161, 0x172, 0x14c, 0x156, 0x1ef, 0xfe, 0xfe, 0xfe, 0x10b, 0x173, 0x143, 0x149, 0x175, 0x103, 0x100,
+  0x1cc, 0x15e, 0x167, 0x128, 0x131, 0x112, 0x16d, 0x163, 0x173, 0xfe, 0x113, 0x177,
+};
+static const uint16 kOverworld_Entrance_Tab1[44] = {
+  0x14a, 0xc4, 0x14f, 0x115, 0x114, 0x174, 0x155, 0xf5, 0xee, 0x1eb, 0x118, 0x146, 0x171, 0x155, 0x137, 0x174, 0x173, 0x121, 0x164, 0x155, 0x157, 0x128, 0x114, 0x123, 0x113, 0x109, 0x118, 0x161, 0x149, 0x117, 0x174, 0x101,
+  0x1cc, 0x131, 0x51, 0x14e, 0x131, 0x112, 0x17a, 0x163, 0x172, 0x1bd, 0x152, 0x167,
+};
+static const uint16 kDwPaletteAnim[35] = {
+  0x884, 0xcc7, 0x150a, 0x154d, 0x7ff6, 0x5944, 0x7ad1,
+  0x884, 0xcc7, 0x150a, 0x154d, 0x5bff, 0x7ad1, 0x21af,
+  0x1084, 0x48c0, 0x6186, 0x7e6d, 0x7fe0, 0x5944, 0x7e20,
+  0x1084, 0x000e, 0x1059, 0x291f, 0x7fe0, 0x5944, 0x7e20,
+  0x1084, 0x1508, 0x196c, 0x21af, 0x7ff6, 0x1d4c, 0x7ad1,
+};
+static const uint16 kDwPaletteAnim2[40] = {
+  0x7fff, 0x884, 0x1cc8, 0x1dce, 0x3694, 0x4718, 0x1d4a, 0x18ac,
+  0x7fff, 0x1908, 0x2d2f, 0x3614, 0x4eda, 0x471f, 0x1d4a, 0x390f,
+  0x7fff, 0x34cd, 0x5971, 0x5635, 0x7f1b, 0x7fff, 0x1d4a, 0x3d54,
+  0x7fff, 0x1908, 0x2d2f, 0x3614, 0x4eda, 0x471f, 0x1d4a, 0x390f,
+  0x7fff, 0x884, 0x52a, 0x21ef, 0x3ab5, 0x4b39, 0x1d4c, 0x18ac,
+};
+static const uint16 kSpecialSwitchArea_Map8[4] = { 0x105, 0x1e4, 0xad, 0xb9 };
+static const uint16 kSpecialSwitchArea_Screen[4] = { 0, 45, 15, 129 };
+static const uint8 kSpecialSwitchArea_Direction[4] = { 8, 2, 8, 8 };
+static const uint16 kSpecialSwitchArea_Exit[4] = { 0x180, 0x181, 0x182, 0x189 };
+const uint8 kVariousPacks[16] = {
+  0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x5b, 0x01, 0x5a,
+  0x42, 0x43, 0x44, 0x45, 0x3f, 0x59, 0x0b, 0x5a
+};
+static const uint16 kSpecialSwitchAreaB_Map8[3] = { 0x17c, 0x1e4, 0xad };
+static const uint16 kSpecialSwitchAreaB_Screen[3] = { 0x80, 0x80, 0x81 };
+static const uint16 kSpecialSwitchAreaB_Direction[3] = { 4, 1, 4 };
+static const int16 kSwitchAreaTab0[4] = { 0xf80, 0xf80, 0x3f, 0x3f };
+static const int16 kSwitchAreaTab1[256] = {
+  0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x1060, 0x1060, 0x1060, 0x1060, 0x60,
+  0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60,
+  0x60, 0x60, 0x60, 0x1060, 0x1060, 0x60, 0x1060, 0x1060, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60,
+  0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x1060, 0x1060, 0x60,
+  0x80, 0x80, 0x40, 0x80, 0x80, 0x80, 0x80, 0x40, 0x1080, 0x1080, 0x40, 0x1080, 0x1080, 0x1080, 0x1080, 0x40,
+  0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x80, 0x80, 0x40, 0x80, 0x80, 0x40, 0x80, 0x80,
+  0x1080, 0x1080, 0x40, 0x1080, 0x1080, 0x40, 0x1080, 0x1080, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
+  0x80, 0x80, 0x40, 0x40, 0x40, 0x80, 0x80, 0x40, 0x1080, 0x1080, 0x40, 0x40, 0x40, 0x1080, 0x1080, 0x40,
+  0x1800, 0x1840, 0x1800, 0x1800, 0x1840, 0x1800, 0x1840, 0x1800, 0x1800, 0x1840, 0x1800, 0x1800, 0x1840, 0x1800, 0x1840, 0x1800,
+  0x1800, 0x1800, 0x1800, 0x1800, 0x1800, 0x1800, 0x1800, 0x1800, 0x1800, 0x1840, 0x1800, 0x1800, 0x1840, 0x1800, 0x1800, 0x1840,
+  0x1800, 0x1840, 0x1800, 0x1800, 0x1840, 0x1800, 0x1800, 0x1840, 0x1800, 0x1800, 0x1800, 0x1800, 0x1800, 0x1800, 0x1800, 0x1800,
+  0x1800, 0x1840, 0x1800, 0x1800, 0x1800, 0x1800, 0x1840, 0x1800, 0x1800, 0x1840, 0x1800, 0x1800, 0x1800, 0x1800, 0x1840, 0x1800,
+  0x2000, 0x2040, 0x1000, 0x2000, 0x2040, 0x2000, 0x2040, 0x1000, 0x2000, 0x2040, 0x1000, 0x2000, 0x2040, 0x2000, 0x2040, 0x1000,
+  0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x2000, 0x2040, 0x1000, 0x2000, 0x2040, 0x1000, 0x2000, 0x2040,
+  0x2000, 0x2040, 0x1000, 0x2000, 0x2040, 0x1000, 0x2000, 0x2040, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000,
+  0x2000, 0x2040, 0x1000, 0x1000, 0x1000, 0x2000, 0x2040, 0x1000, 0x2000, 0x2040, 0x1000, 0x1000, 0x1000, 0x2000, 0x2040, 0x1000,
+};
+static const int16 kSwitchAreaTab3[4] = { 2, -2, 16, -16 };
+// kOverworldAreaHeads[i] != i for subregions of a big area
+static const uint8 kOverworldAreaHeads[64] = {
+  0,  0,  2,  3,  3,  5,  5,  7,
+  0,  0, 10,  3,  3,  5,  5, 15,
+  16, 17, 18, 19, 20, 21, 22, 23,
+  24, 24, 26, 27, 27, 29, 30, 30,
+  24, 24, 34, 27, 27, 37, 30, 30,
+  40, 41, 42, 43, 44, 45, 46, 47,
+  48, 48, 50, 51, 52, 53, 53, 55,
+  48, 48, 58, 59, 60, 53, 53, 63,
+};
+static const uint16 kOverworld_Size1[2] = { 0x11e, 0x31e };
+static const uint16 kOverworld_Size2[2] = { 0x100, 0x300 };
+static const uint16 kOverworld_UpDownScrollSize[2] = { 0x2e0, 0x4e0 };
+static const uint16 kOverworld_LeftRightScrollSize[2] = { 0x300, 0x500 };
+static const int16 kOverworld_Func6B_Tab1[4] = { -8, 8, -8, 8 };
+static const int16 kOverworld_Func6B_Tab2[4] = { 27, 27, 30, 30 };
+static const int16 kOverworld_Func6B_Tab3[4] = { -0x70, 0x70, -0x70, 0x70 };
+static const int16 kOverworld_Func6B_AreaDelta[4] = { -8, 8, -1, 1 };
+static const uint8 kOverworld_Func8_tab[4] = { 0xe0, 8, 0xe0, 0x10 };
+static const uint16 kDoorAnimTiles[56] = {
+  0xda8, 0xda9, 0xdaa, 0xdab,
+  0xdac, 0xdad, 0xdae, 0xdaf,
+  0xdb0, 0xdb1, 0xdb2, 0xdb3,
+  0xdb6, 0xdb7, 0xdb8, 0xdb9,
+  0xdba, 0xdbb, 0xdbc, 0xdbd,
+  0xdcd, 0xdce, 0xdcf, 0xdd0,
+  0xdd3, 0xdd4, 0xdd5, 0xdd6,
+  0xdd7, 0xdd8, 0xdd9, 0xdda,
+  0xdd1, 0xdd2, 0xdd3, 0xdd4,
+  0xdd1, 0xdd2, 0xdd7, 0xdd8,
+  0x918, 0x919, 0x91a, 0x91b,
+  0xddb, 0xddc, 0xddd, 0xdde,
+  0xdd1, 0xdd2, 0xddb, 0xddc,
+  0xe21, 0xe22, 0xe23, 0xe24,
+};
+static PlayerHandlerFunc *const kOverworldSubmodules[48] = {
+  &Module09_00_PlayerControl,
+  &Module09_LoadAuxGFX,
+  &Overworld_FinishTransGfx,
+  &Module09_LoadNewMapAndGFX,
+  &Module09_LoadNewSprites,
+  &Overworld_StartScrollTransition,
+  &Overworld_RunScrollTransition,
+  &Overworld_EaseOffScrollTransition,
+  &Overworld_FinalizeEntryOntoScreen,
+  &Module09_09_OpenBigDoorFromExiting,
+  &Module09_0A_WalkFromExiting_FacingDown,
+  &Module09_0B_WalkFromExiting_FacingUp,
+  &Module09_0C_OpenBigDoor,
+  &Overworld_StartMosaicTransition,
+  &PreOverworld_LoadOverlays,
+  &Module09_LoadAuxGFX,
+  &Overworld_FinishTransGfx,
+  &Module09_LoadNewMapAndGFX,
+  &Module09_LoadNewSprites,
+  &Overworld_StartScrollTransition,
+  &Overworld_RunScrollTransition,
+  &Overworld_EaseOffScrollTransition,
+  &Module09_FadeBackInFromMosaic,
+  &Overworld_StartMosaicTransition,
+  &Overworld_Func18,
+  &Overworld_Func19,
+  &Module09_LoadAuxGFX,
+  &Overworld_FinishTransGfx,
+  &Overworld_Func1C,
+  &Overworld_Func1D,
+  &Overworld_Func1E,
+  &Overworld_Func1F,
+  &Overworld_LoadOverlays2,
+  &Overworld_LoadAmbientOverlayFalse,
+  &Overworld_Func22,
+  &Module09_MirrorWarp,
+  &Overworld_StartMosaicTransition,
+  &Overworld_LoadOverlays,
+  &Module09_LoadAuxGFX,
+  &Overworld_FinishTransGfx,
+  &Overworld_LoadAndBuildScreen,
+  &Module09_FadeBackInFromMosaic,
+  &Module09_2A_RecoverFromDrowning,
+  &Overworld_Func2B,
+  &Module09_MirrorWarp,
+  &Overworld_WeathervaneExplosion,
+  &Module09_2E_Whirlpool,
+  &Overworld_Func2F,
+};
+static PlayerHandlerFunc *const kModule_PreOverworld[3] = {
+  &PreOverworld_LoadProperties,
+  &PreOverworld_LoadOverlays,
+  &Module08_02_LoadAndAdvance,
+};
+const uint8 *GetMap8toTileAttr() {
+  return kMap8DataToTileAttr;
+}
+
+const uint16 *GetMap16toMap8Table() {
+  return kMap16ToMap8;
+}
+
+bool LookupInOwEntranceTab(uint16 r0, uint16 r2) {
+  for (int i = countof(kOverworld_Entrance_Tab0) - 1; i >= 0; i--) {
+    if (r0 == kOverworld_Entrance_Tab0[i] && r2 == kOverworld_Entrance_Tab1[i])
+      return true;
+  }
+  return false;
+}
+
+int LookupInOwEntranceTab2(uint16 pos) {
+  for (int i = 128; i >= 0; i--) {
+    if (pos == kOverworld_Entrance_Pos[i] && overworld_area_index == kOverworld_Entrance_Area[i])
+      return i;
+  }
+  return -1;
+}
+
+bool CanEnterWithTagalong(int e) {
+  uint8 t = follower_indicator;
+  return t == 0 || t == 5 || t == 14 || t == 1 || (t == 7 || t == 8) && e >= 59;
+}
+
+int DirToEnum(int dir) {
+  int xx = 3;
+  while (!(dir & 1))
+    xx--, dir >>= 1;
+  return xx;
+}
+
+void Overworld_ResetMosaicDown() {
+  if (palette_filter_countdown & 1)
+    mosaic_level -= 0x10;
+  BGMODE_copy = 9;
+  MOSAIC_copy = mosaic_level | 7;
+}
+
+void Overworld_Func1D() {
+  assert(0);
+}
+
+void Overworld_Func1E() {
+  assert(0);
+}
+
+uint16 Overworld_GetSignText(int area) {
+  return kOverworld_SignText[area];
+}
+
+const uint8 *GetOverworldSpritePtr(int area) {
+  int base = (sram_progress_indicator == 3) ? 2 :
+    (sram_progress_indicator == 2) ? 1 : 0;
+  return kOverworldSprites + kOverworldSpriteOffs[area + base * 144];
+}
+
+uint8 GetOverworldBgPalette(int idx) {
+  return kOverworldBgPalettes[idx];
+}
+
+void Sprite_LoadGraphicsProperties() {  // 80fc41
+  memcpy(overworld_sprite_gfx + 64, kOverworldSpriteGfx + 0xc0, 64);
+  memcpy(overworld_sprite_palettes + 64, kOverworldSpritePalettes + 0xc0, 64);
+  Sprite_LoadGraphicsProperties_light_world_only();
+}
+
+void Sprite_LoadGraphicsProperties_light_world_only() {  // 80fc62
+  int i = sram_progress_indicator < 2 ? 0 :
+    sram_progress_indicator != 3 ? 1 : 2;
+  memcpy(overworld_sprite_gfx, kOverworldSpriteGfx + i * 64, 64);
+  memcpy(overworld_sprite_palettes, kOverworldSpritePalettes + i * 64, 64);
+}
+
+void InitializeMirrorHDMA() {  // 80fdee
+  HDMAEN_copy = 0;
+
+  mirror_vars.var0 = 0;
+  mirror_vars.var6 = 0;
+  mirror_vars.var5 = 0;
+  mirror_vars.var7 = 0;
+  mirror_vars.var8 = 0;
+
+  mirror_vars.var10 = mirror_vars.var11 = 8;
+  mirror_vars.var9 = 21;
+  mirror_vars.var1[0] = -0x200;
+  mirror_vars.var1[1] = 0x200;
+  mirror_vars.var3[0] = -0x40;
+  mirror_vars.var3[1] = 0x40;
+
+  HdmaSetup(0xF2FB, 0xF2FB, 0x42, (uint8)BG1HOFS, (uint8)BG2HOFS, 0);
+
+  uint16 v = BG2HOFS_copy2;
+  for (int i = 0; i < 240; i++)
+    hdma_table_dynamic[i] = v;
+  HDMAEN_copy = 0xc0;
+}
+
+void MirrorWarp_BuildWavingHDMATable() {  // 80fe64
+  MirrorWarp_RunAnimationSubmodules();
+  if (frame_counter & 1)
+    return;
+
+  int y = 240 - 8;
+  do {
+    hdma_table_dynamic[y] = hdma_table_dynamic[y + 2] = hdma_table_dynamic[y + 4] = hdma_table_dynamic[y + 6] = hdma_table_dynamic[y - 8];
+    y -= 8;
+  } while (y != 0);
+
+  int i = mirror_vars.var0 >> 1;
+  int t = mirror_vars.var6 + mirror_vars.var3[i];
+  if (!sign16(t - mirror_vars.var1[i] ^ mirror_vars.var1[i])) {
+    t = mirror_vars.var1[i];
+    mirror_vars.var5 = 0;
+    mirror_vars.var7 = 0;
+    mirror_vars.var0 ^= 2;
+  }
+  mirror_vars.var6 = t;
+  t += mirror_vars.var7;
+  mirror_vars.var7 = t & 0xff;
+  if (sign16(t))
+    t |= 0xff;
+  else
+    t &= ~0xff;
+  t = mirror_vars.var5 + swap16(t);
+  mirror_vars.var5 = t;
+  if (palette_filter_countdown >= 0x30 && !(t & ~7)) {
+    mirror_vars.var1[0] = -0x100;
+    mirror_vars.var1[1] = 0x100;
+    subsubmodule_index++;
+    t = 0;
+  }
+  hdma_table_dynamic[0] = hdma_table_dynamic[2] = hdma_table_dynamic[4] = hdma_table_dynamic[6] = t + BG2HOFS_copy2;
+}
+
+void MirrorWarp_BuildDewavingHDMATable() {  // 80ff2f
+  MirrorWarp_RunAnimationSubmodules();
+  if (frame_counter & 1)
+    return;
+  int y = 240 - 8;
+  do {
+    hdma_table_dynamic[y] = hdma_table_dynamic[y + 2] = hdma_table_dynamic[y + 4] = hdma_table_dynamic[y + 6] = hdma_table_dynamic[y - 8];
+    y -= 8;
+  } while (y != 0);
+
+  uint16 t = hdma_table_dynamic[0xc0] | hdma_table_dynamic[0xc8] | hdma_table_dynamic[0xd0] | hdma_table_dynamic[0xd8];
+  if (t == BG2HOFS_copy2) {
+    HDMAEN_copy = 0;
+    subsubmodule_index++;
+    Overworld_SetFixedColAndScroll();
+    if ((overworld_screen_index & 0x3f) != 0x1b) {
+      BG1HOFS_copy2 = BG1HOFS_copy = BG2HOFS_copy = BG2HOFS_copy2;
+      BG1VOFS_copy2 = BG1VOFS_copy = BG2VOFS_copy = BG2VOFS_copy2;
+    }
+  }
+}
+
+void TakeDamageFromPit() {  // 81ffd9
+  link_visibility_status = 12;
+  submodule_index = player_is_indoors ? 20 : 42;
+  link_health_current -= 8;
+  if (link_health_current >= 0xa8)
+    link_health_current = 0;
+}
+
+void Module08_OverworldLoad() {  // 8283bf
+  kModule_PreOverworld[submodule_index]();
+}
+
+void PreOverworld_LoadProperties() {  // 8283c7
+  CGWSEL_copy = 0x82;
+  dung_unk6 = 0;
+  AdjustLinkBunnyStatus();
+  if (main_module_index == 8)
+    LoadOverworldFromDungeon();
+  else
+    LoadOverworldFromSpecialOverworld();
+  Overworld_SetSongList();
+  link_num_keys = 0xff;
+  Hud_RefillLogic();
+
+  uint8 sc = overworld_screen_index, dr = dungeon_room_index;
+  uint8 ow_anim_tiles = 0x58;
+  uint8 xt = 2;
+
+  if (sc == 3 || sc == 5 || sc == 7) {
+    xt = 2;
+  } else if (sc == 0x43 || sc == 0x45 || sc == 0x47) {
+    xt = 9;
+  } else if (ow_anim_tiles = 0x5a, sc >= 0x40) {
+    goto dark;
+  } else if (dr == 0xe3 || dr == 0x18 || dr == 0x2f || dr == 0x1f && sc == 0x18) {
+    xt = sram_progress_indicator < 3 ? 7 : 2;
+  } else {
+    xt = savegame_has_master_sword_flags & 0x40 ? 2 : 5;
+    if (dr != 0 && dr != 0xe1) {
+dark:
+      xt = 0xf3;
+      if (queued_music_control == 0xf2)
+        goto setsong;
+      xt = sram_progress_indicator < 2 ? 3 : 2;
+    }
+  }
+  if (savegame_is_darkworld) {
+    xt = sc == 0x40 || sc == 0x43 || sc == 0x45 || sc == 0x47 ? 13 : 9;
+    if (!link_item_moon_pearl)
+      xt = 4;
+  }
+setsong:
+  queued_music_control = xt;
+  DecompressAnimatedOverworldTiles(ow_anim_tiles);
+  InitializeTilesets();
+  OverworldLoadScreensPaletteSet();
+  Overworld_LoadPalettes(kOverworldBgPalettes[sc], overworld_sprite_palettes[sc]);
+  Palette_SetOwBgColor();
+  if (main_module_index == 8) {
+    Overworld_LoadPalettesInner();
+  } else {
+    SpecialOverworld_CopyPalettesToCache();
+  }
+  Overworld_SetFixedColAndScroll();
+  overworld_fixed_color_plusminus = 0;
+  Follower_Initialize();
+
+  if (!(BYTE(overworld_screen_index) & 0x3f))
+    DecodeAnimatedSpriteTile_variable(0x1e);
+  saved_module_for_menu = 9;
+  Sprite_ReloadAll_Overworld();
+  if (!(overworld_screen_index & 0x40))
+    Sprite_InitializeMirrorPortal();
+  sound_effect_ambient = sram_progress_indicator < 2 ? 1 : 5;
+  if (follower_indicator == 6)
+    follower_indicator = 0;
+
+  is_standing_in_doorway = 0;
+  button_mask_b_y = 0;
+  button_b_frames = 0;
+  link_cant_change_direction = 0;
+  link_speed_setting = 0;
+  draw_water_ripples_or_grass = 0;
+  Dungeon_ResetTorchBackgroundAndPlayerInner();
+  if (!link_item_moon_pearl && savegame_is_darkworld) {
+    link_is_bunny = link_is_bunny_mirror = 1;
+    link_player_handler_state = kPlayerState_PermaBunny;
+    LoadGearPalettes_bunny();
+  }
+  BGMODE_copy = 9;
+  dung_want_lights_out = 0;
+  dung_hdr_collision = 0;
+  link_is_on_lower_level = 0;
+  link_is_on_lower_level_mirror = 0;
+  submodule_index++;
+  flag_update_hud_in_nmi++;
+  dung_savegame_state_bits = 0;
+  LoadOWMusicIfNeeded();
+}
+
+void AdjustLinkBunnyStatus() {  // 82856a
+  if (link_item_moon_pearl)
+    ForceNonbunnyStatus();
+}
+
+void ForceNonbunnyStatus() {  // 828570
+  link_player_handler_state = kPlayerState_Ground;
+  link_timer_tempbunny = 0;
+  link_need_for_poof_for_transform = 0;
+  link_is_bunny = 0;
+  link_is_bunny_mirror = 0;
+
+  if (enhanced_features0 & kFeatures0_TurnWhileDashing)
+    link_is_running = 0;
+}
+
+void RecoverPositionAfterDrowning() {  // 829583
+  link_x_coord = link_x_coord_cached;
+  link_y_coord = link_y_coord_cached;
+  ow_scroll_vars0.ystart = room_scroll_vars_y_vofs1_cached;
+  ow_scroll_vars0.xstart = room_scroll_vars_y_vofs2_cached;
+  ow_scroll_vars1.ystart = room_scroll_vars_x_vofs1_cached;
+  ow_scroll_vars1.xstart = room_scroll_vars_x_vofs2_cached;
+
+  up_down_scroll_target = up_down_scroll_target_cached;
+  up_down_scroll_target_end = up_down_scroll_target_end_cached;
+  left_right_scroll_target = left_right_scroll_target_cached;
+  left_right_scroll_target_end = left_right_scroll_target_end_cached;
+
+  if (player_is_indoors) {
+    camera_y_coord_scroll_low = camera_y_coord_scroll_low_cached;
+    camera_y_coord_scroll_hi = camera_y_coord_scroll_low + 2;
+    camera_x_coord_scroll_low = camera_x_coord_scroll_low_cached;
+    camera_x_coord_scroll_hi = camera_x_coord_scroll_low + 2;
+  }
+  WORD(quadrant_fullsize_x) = WORD(quadrant_fullsize_x_cached);
+  WORD(link_quadrant_x) = WORD(link_quadrant_x_cached);
+  if (!player_is_indoors) {
+    camera_y_coord_scroll_hi = camera_y_coord_scroll_low - 2;
+    camera_x_coord_scroll_hi = camera_x_coord_scroll_low - 2;
+  }
+
+  link_direction_facing = link_direction_facing_cached;
+  link_is_on_lower_level = link_is_on_lower_level_cached;
+  link_is_on_lower_level_mirror = link_is_on_lower_level_mirror_cached;
+  is_standing_in_doorway = is_standing_in_doorway_cahed;
+  dung_cur_floor = dung_cur_floor_cached;
+  link_visibility_status = 0;
+  countdown_for_blink = 0x90;
+  Dungeon_PlayBlipAndCacheQuadrantVisits();
+  link_disable_sprite_damage = 0;
+  Link_ResetStateAfterDamagingPit();
+  tagalong_var5 = 0;
+  Follower_Initialize();
+  dung_flag_statechange_waterpuzzle = 0;
+  overworld_map_state = 0;
+  subsubmodule_index = 0;
+  overworld_screen_transition = 0;
+  submodule_index = 0;
+  if (!link_health_current) {
+    mapbak_TM = TM_copy;
+    mapbak_TS = TS_copy;
+    saved_module_for_menu = main_module_index;
+    main_module_index = 18;
+    submodule_index = 1;
+    countdown_for_blink = 0;
+  }
+}
+
+void Module0F_SpotlightClose() {  // 829982
+  static const uint8 kTab[4] = { 8, 4, 2, 1 };
+  Sprite_Main();
+  if (submodule_index == 0)
+    Dungeon_PrepExitWithSpotlight();
+  else
+    Spotlight_ConfigureTableAndControl();
+
+  if (!player_is_indoors) {
+    if (BYTE(overworld_screen_index) == 0xf)
+      draw_water_ripples_or_grass = 1;
+    link_speed_setting = 6;
+    Link_HandleVelocity();
+    link_x_vel = link_y_vel = 0;
+  }
+
+  int i = link_direction_facing >> 1;
+  if (!player_is_indoors)
+    i = (which_entrance == 0x43) ? 1 : 0;
+
+  link_direction = link_direction_last = kTab[i];
+  Link_HandleMovingAnimation_FullLongEntry();
+  LinkOam_Main();
+}
+
+void Dungeon_PrepExitWithSpotlight() {  // 8299ca
+  is_nmi_thread_active = 0;
+  nmi_flag_update_polyhedral = 0;
+  if (!player_is_indoors) {
+    Ancilla_TerminateWaterfallSplashes();
+    link_y_coord_exit = link_y_coord;
+  }
+  uint8 m = ZeldaGetEntranceMusicTrack(which_entrance);
+  if (m != 3 || (m = sram_progress_indicator) >= 2) {
+    if (m != 0xf2)  // fade to 0x40
+      m = 0xf1;  // fade to zero
+    else if (music_unk1 == 12)
+      m = 7;
+    music_control = m;
+  }
+  hud_floor_changed_timer = 0;
+  Hud_FloorIndicator();
+  flag_update_hud_in_nmi++;
+  IrisSpotlight_close();
+  submodule_index++;
+}
+
+void Spotlight_ConfigureTableAndControl() {  // 829a19
+  IrisSpotlight_ConfigureTable();
+  is_nmi_thread_active = 0;
+  nmi_flag_update_polyhedral = 0;
+  if (submodule_index)
+    return;
+  if (main_module_index == 6)
+    link_y_coord = link_y_coord_exit;
+  OpenSpotlight_Next2();
+}
+
+void OpenSpotlight_Next2() {  // 829a37
+  if (main_module_index != 9) {
+    EnableForceBlank();
+    Link_ItemReset_FromOverworldThings();
+  }
+
+  if (main_module_index == 9) {
+    if (dungeon_room_index != 0x20)
+      submodule_index = link_direction_facing ? 0xa : 0xb;
+
+    ow_countdown_transition = 16;
+    if ((BYTE(ow_entrance_value) | BYTE(big_rock_starting_address)) && HIBYTE(big_rock_starting_address)) { // wtf
+      BYTE(door_open_closed_counter) = (big_rock_starting_address & 0x8000) ? 0x18 : 0;
+      big_rock_starting_address &= 0x7fff;
+      BYTE(door_animation_step_indicator) = 0;
+      submodule_index = 9;
+      subsubmodule_index = 0;
+      sound_effect_2 = 21;
+    }
+  }
+  W12SEL_copy = 0;
+  W34SEL_copy = 0;
+  WOBJSEL_copy = 0;
+  TMW_copy = 0;
+  TSW_copy = 0;
+  link_force_hold_sword_up = 0;
+
+  uint8 sc = overworld_screen_index;
+  if (sc == 3 || sc == 5 || sc == 7) {
+    COLDATA_copy0 = 0x26;
+    COLDATA_copy1 = 0x4c;
+    COLDATA_copy2 = 0x8c;
+  } else if (sc == 0x43 || sc == 0x45 || sc == 0x47) {
+    COLDATA_copy0 = 0x26;
+    COLDATA_copy1 = 0x4a;
+    COLDATA_copy2 = 0x87;
+  }
+}
+
+void Module10_SpotlightOpen() {  // 829ad7
+  Sprite_Main();
+  if (submodule_index == 0)
+    Module10_00_OpenIris();
+  else
+    Spotlight_ConfigureTableAndControl();
+  LinkOam_Main();
+}
+
+void Module10_00_OpenIris() {  // 829ae6
+  Spotlight_open();
+  submodule_index++;
+}
+
+void SetTargetOverworldWarpToPyramid() {  // 829e5f
+  if (main_module_index != 21)
+    return;
+  LoadOverworldFromDungeon();
+  DecompressAnimatedOverworldTiles(0x5a);
+  ResetAncillaAndCutscene();
+}
+
+void ResetAncillaAndCutscene() {  // 829e6e
+  Ancilla_TerminateSelectInteractives(0);
+  link_disable_sprite_damage = 0;
+  button_b_frames = 0;
+  button_mask_b_y = 0;
+  link_force_hold_sword_up = 0;
+  flag_is_link_immobilized = 0;
+}
+
+void Module09_Overworld() {  // 82a475
+  kOverworldSubmodules[submodule_index]();
+
+  int bg2x = BG2HOFS_copy2;
+  int bg2y = BG2VOFS_copy2;
+  int bg1x = BG1HOFS_copy2;
+  int bg1y = BG1VOFS_copy2;
+
+  BG2HOFS_copy2 = BG2HOFS_copy = bg2x + bg1_x_offset;
+  BG2VOFS_copy2 = BG2VOFS_copy = bg2y + bg1_y_offset;
+  BG1HOFS_copy2 = BG1HOFS_copy = bg1x + bg1_x_offset;
+  BG1VOFS_copy2 = BG1VOFS_copy = bg1y + bg1_y_offset;
+
+  Sprite_Main();
+
+  BG2HOFS_copy2 = bg2x;
+  BG2VOFS_copy2 = bg2y;
+  BG1HOFS_copy2 = bg1x;
+  BG1VOFS_copy2 = bg1y;
+
+  LinkOam_Main();
+  Hud_RefillLogic();
+  OverworldOverlay_HandleRain();
+}
+
+void OverworldOverlay_HandleRain() {  // 82a4cd
+  static const uint8 kOverworld_DrawBadWeather_X[4] = { 1, 0, 1, 0 };
+  static const uint8 kOverworld_DrawBadWeather_Y[4] = { 0, 17, 0, 17 };
+  if (BYTE(overworld_screen_index) != 0x70 && sram_progress_indicator >= 2 || (save_ow_event_info[0x70] & 0x20))
+    return;
+  if (frame_counter == 3 || frame_counter == 88) {
+    CGADSUB_copy = 0x32;
+  } else if (frame_counter == 5 || frame_counter == 44 || frame_counter == 90) {
+    CGADSUB_copy = 0x72;
+  } else if (frame_counter == 36) {
+    sound_effect_1 = 54;
+    CGADSUB_copy = 0x32;
+  }
+  if (frame_counter & 3)
+    return;
+  int i = (move_overlay_ctr + 1) & 3;
+  move_overlay_ctr = i;
+  BG1HOFS_copy2 += kOverworld_DrawBadWeather_X[i] << 8;
+  BG1VOFS_copy2 += kOverworld_DrawBadWeather_Y[i] << 8;
+}
+
+void Module09_00_PlayerControl() {  // 82a53c
+  if (!(flag_custom_spell_anim_active | flag_is_link_immobilized | flag_block_link_menu | trigger_special_entrance)) {
+    if (filtered_joypad_H & 0x10) {
+      overworld_map_state = 0;
+      submodule_index = 1;
+      saved_module_for_menu = main_module_index;
+      main_module_index = 14;
+      return;
+    }
+
+    if (DidPressButtonForMap()) {
+      overworld_map_state = 0;
+      submodule_index = 7;
+      saved_module_for_menu = main_module_index;
+      main_module_index = 14;
+      return;
+    }
+    if (joypad1H_last & 0x20) {
+      DisplaySelectMenu();
+      return;
+    }
+    Hud_HandleItemSwitchInputs();
+  }
+  if (trigger_special_entrance)
+    Overworld_AnimateEntrance();
+  Link_Main();
+  if (super_bomb_indicator_unk2 != 0xff)
+    Hud_SuperBombIndicator();
+  current_area_of_player = (link_y_coord & 0x1e00) >> 5 | (link_x_coord & 0x1e00) >> 8;
+  Graphics_LoadChrHalfSlot();
+  Overworld_OperateCameraScroll();
+  if (main_module_index != 11) {
+    Overworld_UseEntrance();
+    Overworld_DwDeathMountainPaletteAnimation();
+    OverworldHandleTransitions();
+  } else {
+    ScrollAndCheckForSOWExit();
+  }
+}
+
+void OverworldHandleTransitions() {  // 82a9c4
+  if (BYTE(overworld_screen_trans_dir_bits2))
+    OverworldHandleMapScroll();
+  int dir;
+  uint16 x, y, t;
+  if (link_y_vel != 0) {
+    dir = link_direction & 12;
+    t = link_y_coord - kOverworld_OffsetBaseY[BYTE(current_area_of_player) >> 1];
+    if ((y = 6, x = 8, t < 4) || (y = 4, x = 4, t >= overworld_right_bottom_bound_for_scroll))
+      goto compare;
+  }
+  if (link_x_vel != 0) {
+    dir = link_direction & 3;
+    t = link_x_coord - kOverworld_OffsetBaseX[BYTE(current_area_of_player) >> 1];
+    if ((y = 2, x = 2, t < 6) || (y = 0, x = 1, t >= (uint16)(overworld_right_bottom_bound_for_scroll + 4))) {
+compare:
+      if (x == dir && !Link_CheckForEdgeScreenTransition())
+        goto after;
+    }
+  }
+  Overworld_CheckSpecialSwitchArea();
+  return;
+after:
+  y >>= 1;
+  Dungeon_ResetTorchBackgroundAndPlayerInner();
+  map16_load_src_off &= kSwitchAreaTab0[y];
+  int pushed = ((current_area_of_player + kSwitchAreaTab3[y]) >> 1) & 0x3f;
+  map16_load_src_off += kSwitchAreaTab1[y * 64 + pushed];
+
+  uint8 old_screen = overworld_screen_index;
+  if (old_screen == 0x2a)
+    sound_effect_ambient = 0x80;
+
+  uint8 new_area = kOverworldAreaHeads[pushed] | savegame_is_darkworld;
+  BYTE(overworld_screen_index) = new_area;
+  BYTE(overworld_area_index) = new_area;
+  if (!savegame_is_darkworld || link_item_moon_pearl) {
+    uint8 music = overworld_music[new_area];
+    if ((music & 0xf0) == 0)
+      sound_effect_ambient = 5;
+    if (!ZeldaIsPlayingMusicTrack(music & 0xf))
+      music_control = 0xf1;
+  }
+  Overworld_LoadGFXAndScreenSize();
+  submodule_index = 1;
+  BYTE(overworld_screen_trans_dir_bits) = dir;
+  BYTE(overworld_screen_trans_dir_bits2) = dir;
+  byte_7E069C = overworld_screen_transition = DirToEnum(dir);
+  BYTE(ow_entrance_value) = 0;
+  BYTE(big_rock_starting_address) = 0;
+  transition_counter = 0;
+
+  if (!(old_screen & 0x3f) || !(overworld_screen_index & 0xbf)) {
+    subsubmodule_index = 0;
+    submodule_index = 13;
+    MOSAIC_copy = 0;
+    mosaic_level = 0;
+  } else {
+    uint8 sc = overworld_screen_index;
+    Overworld_LoadPalettes(kOverworldBgPalettes[sc], overworld_sprite_palettes[sc]);
+    Overworld_CopyPalettesToCache();
+  }
+}
+
+void Overworld_LoadGFXAndScreenSize() {  // 82ab08
+  int i = BYTE(overworld_screen_index);
+  incremental_counter_for_vram = 0;
+  sprite_graphics_index = overworld_sprite_gfx[i];
+  aux_tile_theme_index = kOverworldAuxTileThemeIndexes[i];
+
+  overworld_area_is_big_backup = overworld_area_is_big;
+  BYTE(overworld_area_is_big) = kOverworldMapIsSmall[i & 0x3f] ? 0 : 0x20;
+  ((uint8 *)&overworld_right_bottom_bound_for_scroll)[1] = kOverworldMapIsSmall[i & 0x3f] ? 1 : 3;
+  main_tile_theme_index = overworld_screen_index & 0x40 ? 0x21 : 0x20;
+  misc_sprites_graphics_index = kVariousPacks[6 + (overworld_screen_index & 0x40 ? 8 : 0)];
+
+  int j = overworld_screen_index & 0xbf;
+  overworld_offset_base_y = kOverworld_OffsetBaseY[j];
+  overworld_offset_base_x = kOverworld_OffsetBaseX[j] >> 3;
+
+  int m = overworld_area_is_big ? 0x3f0 : 0x1f0;
+  overworld_offset_mask_y = m;
+  overworld_offset_mask_x = m >> 3;
+}
+
+void ScrollAndCheckForSOWExit() {  // 82ab7b
+  if (BYTE(overworld_screen_trans_dir_bits2))
+    OverworldHandleMapScroll();
+
+  const uint16 *map8 = Overworld_GetMap16OfLink_Mult8();
+  int a = map8[0] & 0x1ff;
+  for (int i = 2; i >= 0; i--) {
+    if (kSpecialSwitchAreaB_Map8[i] == a && kSpecialSwitchAreaB_Screen[i] == overworld_screen_index) {
+      link_direction = kSpecialSwitchAreaB_Direction[i];
+      byte_7E069C = overworld_screen_transition = DirToEnum(link_direction);
+      submodule_index = 36;
+      subsubmodule_index = 0;
+      BYTE(dungeon_room_index) = 0;
+      break;
+    }
+  }
+}
+
+void Module09_LoadAuxGFX() {  // 82ab88
+  save_ow_event_info[0x3b] &= ~0x20;
+  save_ow_event_info[0x7b] &= ~0x20;
+  save_dung_info[267] &= ~0x80;
+  save_dung_info[40] &= ~0x100;
+  LoadTransAuxGFX();
+  PrepTransAuxGfx();
+  nmi_disable_core_updates = nmi_subroutine_index = 9;
+  submodule_index++;
+}
+
+void Overworld_FinishTransGfx() {  // 82abbc
+  nmi_disable_core_updates = nmi_subroutine_index = 10;
+  submodule_index++;
+}
+
+void Module09_LoadNewMapAndGFX() {  // 82abc6
+  word_7E04C8 = 0;
+  SomeTileMapChange();
+  nmi_disable_core_updates++;
+  CreateInitialNewScreenMapToScroll();
+  LoadNewSpriteGFXSet();
+}
+
+void Overworld_RunScrollTransition() {  // 82abda
+  Link_HandleMovingAnimation_FullLongEntry();
+  Graphics_IncrementalVRAMUpload();
+  uint8 rv = OverworldScrollTransition();
+  if (!(rv & 0xf)) {
+    BYTE(overworld_screen_trans_dir_bits2) = BYTE(overworld_screen_trans_dir_bits);
+    OverworldTransitionScrollAndLoadMap();
+    BYTE(overworld_screen_trans_dir_bits2) = 0;
+  }
+}
+
+void Module09_LoadNewSprites() {  // 82abed
+  if (overworld_screen_transition == 1) {
+    BG2VOFS_copy2 += 2;
+    link_y_coord += 2;
+  }
+  Sprite_OverworldReloadAll_justLoad();
+  num_memorized_tiles = 0;
+  if (sram_progress_indicator >= 2 && submodule_index != 18)
+    Overworld_SetFixedColAndScroll();
+  Overworld_StartScrollTransition();
+}
+
+void Overworld_StartScrollTransition() {  // 82ac27
+  submodule_index++;
+  if (BYTE(overworld_screen_trans_dir_bits) >= 4) {
+    BYTE(overworld_screen_trans_dir_bits2) = BYTE(overworld_screen_trans_dir_bits);
+    OverworldTransitionScrollAndLoadMap();
+    BYTE(overworld_screen_trans_dir_bits2) = 0;
+  }
+}
+
+void Overworld_EaseOffScrollTransition() {  // 82ac3a
+  if (kOverworldMapIsSmall[BYTE(overworld_screen_index)]) {
+    BYTE(overworld_screen_trans_dir_bits2) = BYTE(overworld_screen_trans_dir_bits);
+    OverworldTransitionScrollAndLoadMap();
+    BYTE(overworld_screen_trans_dir_bits2) = 0;
+  }
+  if (++subsubmodule_index < 8)
+    return;
+  if ((BYTE(overworld_screen_trans_dir_bits) == 8 || BYTE(overworld_screen_trans_dir_bits) == 2) && subsubmodule_index < 9)
+    return;
+
+  subsubmodule_index = 0;
+  BYTE(overworld_screen_trans_dir_bits) = 0;
+
+  if (kOverworldMapIsSmall[BYTE(overworld_screen_index)]) {
+    map16_load_src_off = orange_blue_barrier_state;
+    map16_load_dst_off = word_7EC174;
+    map16_load_var2 = word_7EC176;
+  }
+  submodule_index++;
+  Follower_Disable();
+}
+
+void Module09_0A_WalkFromExiting_FacingDown() {  // 82ac8f
+  link_direction_last = 4;
+  Link_HandleMovingAnimation_FullLongEntry();
+  link_y_coord += 1;
+  if (--ow_countdown_transition)
+    return;
+  submodule_index = 0;
+  link_y_coord += 3;
+  link_y_vel = 3;
+  Overworld_OperateCameraScroll();
+  if (BYTE(overworld_screen_trans_dir_bits2))
+    OverworldHandleMapScroll();
+}
+
+void Module09_0B_WalkFromExiting_FacingUp() {  // 82acc2
+  Link_HandleMovingAnimation_FullLongEntry();
+  link_y_coord -= 1;
+  if (--ow_countdown_transition)
+    return;
+  submodule_index = 0;
+}
+
+void Module09_09_OpenBigDoorFromExiting() {  // 82ad4a
+  if (BYTE(door_animation_step_indicator) != 3) {
+    Overworld_DoMapUpdate32x32_conditional();
+    return;
+  }
+  ow_countdown_transition = 36;
+  BYTE(overworld_screen_trans_dir_bits2) = 0;
+  submodule_index++;
+}
+
+void Overworld_DoMapUpdate32x32_B() {  // 82ad5c
+  Overworld_DoMapUpdate32x32();
+  BYTE(door_open_closed_counter) = 0;
+}
+
+void Module09_0C_OpenBigDoor() {  // 82ad6c
+  if (BYTE(door_animation_step_indicator) != 3) {
+    Overworld_DoMapUpdate32x32_conditional();
+    return;
+  }
+  submodule_index = 0;
+  subsubmodule_index = 0;
+  BYTE(overworld_screen_trans_dir_bits2) = 0;
+}
+
+void Overworld_DoMapUpdate32x32_conditional() {  // 82ad7b
+  if (door_open_closed_counter & 7)
+    BYTE(door_open_closed_counter)++;
+  else
+    Overworld_DoMapUpdate32x32();
+}
+
+void Overworld_DoMapUpdate32x32() {  // 82ad85
+  int i = num_memorized_tiles >> 1;
+  int j = door_open_closed_counter >> 1;
+  uint16 pos, tile;
+
+  memorized_tile_addr[i] = pos = big_rock_starting_address;
+  memorized_tile_value[i] = tile = kDoorAnimTiles[j + 0];
+  Overworld_DrawMap16_Persist(pos, tile);
+
+  memorized_tile_addr[i + 1] = pos = big_rock_starting_address + 2;
+  memorized_tile_value[i + 1] = tile = kDoorAnimTiles[j + 1];
+  Overworld_DrawMap16_Persist(pos, tile);
+
+  memorized_tile_addr[i + 2] = pos = big_rock_starting_address + 0x80;
+  memorized_tile_value[i + 2] = tile = kDoorAnimTiles[j + 2];
+  Overworld_DrawMap16_Persist(pos, tile);
+
+  memorized_tile_addr[i + 3] = pos = big_rock_starting_address + 0x82;
+  memorized_tile_value[i + 3] = tile = kDoorAnimTiles[j + 3];
+  Overworld_DrawMap16_Persist(pos, tile);
+  vram_upload_data[vram_upload_offset >> 1] = 0xffff;
+  num_memorized_tiles += 8;
+  door_animation_step_indicator += (door_open_closed_counter == 32) ? 2 : 1;
+  nmi_load_bg_from_vram = 1;
+  BYTE(door_open_closed_counter)++;
+}
+
+void Overworld_StartMosaicTransition() {  // 82ae5e
+  ConditionalMosaicControl();
+  switch (subsubmodule_index) {
+  case 0:
+    if (BYTE(overworld_screen_index) != 0x80) {
+      if (!ZeldaIsPlayingMusicTrack(overworld_music[BYTE(overworld_screen_index)] & 0xf))
+        music_control = 0xf1;
+    }
+    ResetTransitionPropsAndAdvance_ResetInterface();
+    break;
+  case 1:
+    ApplyPaletteFilter_bounce();
+    break;
+  default:
+    INIDISP_copy = 0x80;
+    subsubmodule_index = 0;
+    if (!(overworld_screen_index & 0x3f))
+      DecodeAnimatedSpriteTile_variable(0x1e);
+    if (BYTE(overworld_area_index) != 0 && main_module_index != 11) {
+      TM_copy = 0x16;
+      TS_copy = 1;
+      CGWSEL_copy = 0x82;
+      CGADSUB_copy = 0x20;
+      submodule_index++;
+      return;
+    }
+    if (submodule_index == 36) {
+      LoadOverworldFromSpecialOverworld();
+      if (!(overworld_screen_index & 0x3f))
+        DecodeAnimatedSpriteTile_variable(0x1e);
+    }
+    submodule_index++;
+    break;
+  }
+}
+
+void Overworld_LoadOverlays() {  // 82af0b
+  Sprite_InitializeSlots();
+  Sprite_ReloadAll_Overworld();
+  link_state_bits = 0;
+  link_picking_throw_state = 0;
+  sound_effect_ambient = 5;
+  Overworld_LoadOverlays2();
+
+}
+
+void PreOverworld_LoadOverlays() {  // 82af19
+  sound_effect_ambient = 5;
+  Overworld_LoadOverlays2();
+}
+
+void Overworld_LoadOverlays2() {  // 82af1e
+  uint16 xv;
+
+  overworld_screen_index_prev = overworld_screen_index;
+  map16_load_src_off_prev = map16_load_src_off;
+  map16_load_var2_prev = map16_load_var2;
+  map16_load_dst_off_prev = map16_load_dst_off;
+  overworld_screen_transition_prev = overworld_screen_transition;
+  overworld_screen_trans_dir_bits_prev = overworld_screen_trans_dir_bits;
+  overworld_screen_trans_dir_bits2_prev = overworld_screen_trans_dir_bits2;
+
+  overlay_index = 0;
+  BG1VOFS_subpixel = 0;
+  BG1HOFS_subpixel = 0;
+
+  int si = overworld_screen_index;
+  if (si >= 0x80) {
+    xv = 0x97;
+    if (dungeon_room_index == 0x180) {
+      if (save_ow_event_info[0x80] & 0x40)
+        goto getout; // master sword retrieved?
+      goto load_overlay;
+    }
+    if ((xv = 0x94, dungeon_room_index == 0x181) ||
+        (xv = 0x93, dungeon_room_index == 0x189))
+      goto load_overlay;
+
+    if (dungeon_room_index == 0x182 || dungeon_room_index == 0x183)
+      sound_effect_ambient = 1;  // zora falls
+getout:
+    TS_copy = 0;
+    submodule_index++;
+    return;
+  }
+
+  if ((si & 0x3f) == 0) {
+    xv = (!(si & 0x40) && save_ow_event_info[0x80] & 0x40) ? 0x9e : 0x9d;  // forest
+    goto load_overlay;
+  }
+
+  if ((xv = 0x95, si == 0x3 || si == 0x5 || si == 0x7) ||
+      (xv = 0x9c, si == 0x43 || si == 0x45 || si == 0x47))
+    goto load_overlay;
+  if (si == 0x70) {
+    if (!(save_ow_event_info[0x70] & 0x20))
+      xv = 0x9f; // rain
+  } else {
+    xv = (sram_progress_indicator < 2) ? 0x9f : 0x96;
+  }
+load_overlay:
+  map16_load_src_off = 0x390;
+  overlay_index = overworld_screen_index = xv;
+  map16_load_var2 = (map16_load_src_off - 0x400 & 0xf80) >> 7;
+  map16_load_dst_off = (map16_load_src_off - 0x10 & 0x3e) >> 1;
+  overworld_screen_transition = 0;
+  overworld_screen_trans_dir_bits = 0;
+  overworld_screen_trans_dir_bits2 = 0;
+  CGWSEL_copy = 0x82;
+  TM_copy = 0x16;
+  TS_copy = 1;
+  sound_effect_ambient = overworld_music[BYTE(overworld_screen_index)] >> 4;
+
+  if (xv == 0x97 || xv == 0x94 || xv == 0x93 || xv == 0x9d || xv == 0x9e || xv == 0x9f)
+    CGADSUB_copy = 0x72;
+  else if (xv == 0x95 || xv == 0x9c || BYTE(overworld_screen_index_prev) == 0x5b ||
+           BYTE(overworld_screen_index_prev) == 0x1b && (submodule_index == 35 || submodule_index == 44))
+    CGADSUB_copy = 0x20;
+  else
+    TS_copy = 0, CGADSUB_copy = 0x20;
+
+  LoadOverworldOverlay();
+  if (BYTE(overlay_index) == 0x94)
+    BG1VOFS_copy2 |= 0x100;
+
+  overworld_screen_index = overworld_screen_index_prev;
+  map16_load_src_off = map16_load_src_off_prev;
+  map16_load_var2 = map16_load_var2_prev;
+  map16_load_dst_off = map16_load_dst_off_prev;
+  overworld_screen_transition = overworld_screen_transition_prev;
+  overworld_screen_trans_dir_bits = overworld_screen_trans_dir_bits_prev;
+  overworld_screen_trans_dir_bits2 = overworld_screen_trans_dir_bits2_prev;
+}
+
+void Module09_FadeBackInFromMosaic() {  // 82b0d2
+  Overworld_ResetMosaicDown();
+  switch (subsubmodule_index) {
+  case 0: {
+    uint8 sc = overworld_screen_index;
+    Overworld_LoadPalettes(kOverworldBgPalettes[sc], overworld_sprite_palettes[sc]);
+    OverworldMosaicTransition_LoadSpriteGraphicsAndSetMosaic();
+    break;
+  }
+  case 1:
+    Graphics_IncrementalVRAMUpload();
+    ApplyPaletteFilter_bounce();
+    break;
+  default:
+    last_music_control = music_unk1;
+    if (BYTE(overworld_screen_index) != 0x80 && BYTE(overworld_screen_index) != 0x2a) {
+      uint8 m = overworld_music[BYTE(overworld_screen_index)];
+      sound_effect_ambient = (m >> 4) ? (m >> 4) : 5;
+      if (!ZeldaIsPlayingMusicTrack(m & 0xf))
+        music_control = (m & 0xf);
+    }
+    submodule_index = 8;
+    subsubmodule_index = 0;
+    if (main_module_index == 11) {
+      main_module_index = 9;
+      submodule_index = 31;
+      ow_countdown_transition = 12;
+    }
+  }
+}
+
+void Overworld_Func1C() {  // 82b150
+  Overworld_ResetMosaicDown();
+  switch (subsubmodule_index) {
+  case 0:
+    OverworldMosaicTransition_LoadSpriteGraphicsAndSetMosaic();
+    break;
+  case 1:
+    Graphics_IncrementalVRAMUpload();
+    ApplyPaletteFilter_bounce();
+    break;
+  default:
+    if (BYTE(overworld_screen_index) < 0x80)
+      music_control = (overworld_screen_index & 0x3f) ? 2 : 5;
+    submodule_index = 8;
+    subsubmodule_index = 0;
+    break;
+  }
+}
+
+void OverworldMosaicTransition_LoadSpriteGraphicsAndSetMosaic() {  // 82b171
+  LoadNewSpriteGFXSet();
+  INIDISP_copy = 0xf;
+  HDMAEN_copy = 0x80;
+  BYTE(palette_filter_countdown) = mosaic_target_level - 1;
+  mosaic_target_level = 0;
+  BYTE(darkening_or_lightening_screen) = 2;
+  subsubmodule_index++;
+}
+
+void Overworld_Func22() {  // 82b1bb
+  if (++INIDISP_copy == 15) {
+    submodule_index = 0;
+    subsubmodule_index = 0;
+  }
+}
+
+void Overworld_Func18() {  // 82b1c8
+  link_maybe_swim_faster = 0;
+  uint8 m = main_module_index;
+  uint8 sub = submodule_index;
+  Overworld_EnterSpecialArea();
+  Overworld_LoadOverlays();
+  submodule_index = sub + 1;
+  main_module_index = m;
+}
+
+void Overworld_Func19() {  // 82b1df
+  uint8 m = main_module_index;
+  uint8 sub = submodule_index;
+  Module08_02_LoadAndAdvance();
+  submodule_index = sub + 1;
+  main_module_index = m;
+}
+
+void Module09_MirrorWarp() {  // 82b1fa
+  nmi_disable_core_updates++;
+  switch (subsubmodule_index) {
+  case 0:
+    if (BYTE(overworld_screen_index) >= 0x80) {
+      submodule_index = 0;
+      subsubmodule_index = 0;
+      overworld_map_state = 0;
+      return;
+    }
+    music_control = 8;
+    flag_overworld_area_did_change = 8;
+    countdown_for_blink = 0x90;
+    InitializeMirrorHDMA();
+    savegame_is_darkworld ^= 0x40;
+    word_7E04C8 = 0;
+    BYTE(overworld_screen_index) = BYTE(overworld_area_index) = (overworld_screen_index & 0x3f) | savegame_is_darkworld;
+    overworld_map_state = 0;
+    PaletteFilter_InitializeWhiteFilter();
+    Overworld_LoadGFXAndScreenSize();
+    subsubmodule_index++;
+    break;
+  case 1:
+    subsubmodule_index++;
+    HDMAEN_copy = 0xc0;
+  case 2:
+    MirrorWarp_BuildWavingHDMATable();
+    break;
+  case 3:
+    MirrorWarp_BuildDewavingHDMATable();
+    break;
+  default:
+    MirrorWarp_FinalizeAndLoadDestination();
+    break;
+  }
+}
+
+void MirrorWarp_FinalizeAndLoadDestination() {  // 82b260
+  HdmaSetup(0, 0xf2fb, 0x41, 0, (uint8)WH0, 0);
+  IrisSpotlight_ResetTable();
+  palette_filter_countdown = 0;
+  darkening_or_lightening_screen = 0;
+  ReloadPreviouslyLoadedSheets();
+  Overworld_SetSongList();
+  HDMAEN_copy = 0x80;
+  uint8 m = overworld_music[BYTE(overworld_screen_index)];
+  music_control = m & 0xf;
+  sound_effect_ambient = m >> 4;
+  if (BYTE(overworld_screen_index) >= 0x40 && !link_item_moon_pearl)
+    music_control = 4;
+
+  saved_module_for_menu = submodule_index;
+  submodule_index = 0;
+  subsubmodule_index = 0;
+  overworld_map_state = 0;
+  nmi_disable_core_updates = 0;
+}
+
+void Overworld_DrawScreenAtCurrentMirrorPosition() {  // 82b2e6
+  uint16 bak1 = map16_load_src_off;
+  uint16 bak2 = map16_load_dst_off;
+  uint16 bak3 = map16_load_var2;
+  if (kOverworldMapIsSmall[BYTE(overworld_screen_index)]) {
+    map16_load_src_off = 0x390;
+    map16_load_var2 = (0x390 - 0x400 & 0xf80) >> 7;
+    map16_load_dst_off = (0x390 - 0x10 & 0x3e) >> 1;
+  }
+  Overworld_DrawQuadrantsAndOverlays();
+  if (submodule_index == 44)
+    MirrorBonk_RecoverChangedTiles();
+  map16_load_var2 = bak3;
+  map16_load_dst_off = bak2;
+  map16_load_src_off = bak1;
+}
+
+void MirrorWarp_LoadSpritesAndColors() {  // 82b334
+  countdown_for_blink = 0x90;
+  uint16 bak1 = map16_load_src_off;
+  uint16 bak2 = map16_load_dst_off;
+  uint16 bak3 = map16_load_var2;
+  if (kOverworldMapIsSmall[BYTE(overworld_screen_index)]) {
+    map16_load_src_off = 0x390;
+    map16_load_var2 = (0x390 - 0x400 & 0xf80) >> 7;
+    map16_load_dst_off = (0x390 - 0x10 & 0x3e) >> 1;
+  }
+  Map16ToMap8(&g_ram[0x2000], 0);
+  map16_load_var2 = bak3;
+  map16_load_dst_off = bak2;
+  map16_load_src_off = bak1;
+  OverworldLoadScreensPaletteSet();
+  uint8 sc = overworld_screen_index;
+  Overworld_LoadPalettes(kOverworldBgPalettes[sc], overworld_sprite_palettes[sc]);
+  Palette_SpecialOw();
+  Overworld_SetFixedColAndScroll();
+  if (BYTE(overworld_screen_index) == 0x1b || BYTE(overworld_screen_index) == 0x5b)
+    TS_copy = 1;
+  for (int i = 0; i < 16 * 6; i++)
+    main_palette_buffer[32 + i] = 0x7fff;
+  main_palette_buffer[0] = 0x7fff;
+  if (overworld_screen_index == 0x5b) {
+    main_palette_buffer[0] = 0;
+    main_palette_buffer[32] = 0;
+  }
+  Sprite_ResetAll();
+  Sprite_ReloadAll_Overworld();
+  Link_ItemReset_FromOverworldThings();
+  Dungeon_ResetTorchBackgroundAndPlayerInner();
+  link_player_handler_state = kPlayerState_Mirror;
+  if (!(overworld_screen_index & 0x40))
+    Sprite_InitializeMirrorPortal();
+}
+
+void Overworld_Func2B() {  // 82b40a
+  Palette_AnimGetMasterSword();
+}
+
+void Overworld_WeathervaneExplosion() {  // 82b40e
+  // empty
+}
+
+void Module09_2E_Whirlpool() {  // 82b40f
+  // this is called when entering the whirlpool
+  nmi_disable_core_updates++;
+  switch (subsubmodule_index) {
+  case 0:
+    sound_effect_1 = 0x34;
+    sound_effect_ambient = 5;
+    overworld_map_state = 0;
+    palette_filter_countdown = 0;
+    subsubmodule_index++;
+    break;
+  case 1:
+    PaletteFilter_WhirlpoolBlue();
+    break;
+  case 2:
+    PaletteFilter_IsolateWhirlpoolBlue();
+    break;
+  case 3:
+    COLDATA_copy2 = 0x9f;
+    overworld_palette_aux_or_main = 0;
+    hud_palette = 0;
+    FindPartnerWhirlpoolExit();
+    BYTE(dung_draw_width_indicator) = 0;
+    Overworld_LoadOverlays2();
+    submodule_index--;
+    nmi_subroutine_index = 12;
+    flag_update_cgram_in_nmi = 0;
+    COLDATA_copy2 = 0x80;
+    INIDISP_copy = 0xf;
+    nmi_disable_core_updates++;
+    subsubmodule_index++;
+    break;
+  case 4: case 6:
+    nmi_subroutine_index = 13;
+    nmi_disable_core_updates++;
+    subsubmodule_index++;
+    break;
+  case 5:
+    Overworld_LoadOverlayAndMap();
+    nmi_subroutine_index = 12;
+    INIDISP_copy = 0xf;
+    nmi_disable_core_updates++;
+    subsubmodule_index++;
+    break;
+  case 7:
+    Module09_LoadAuxGFX();
+    submodule_index--;
+    subsubmodule_index++;
+    break;
+  case 8:
+    Overworld_FinishTransGfx();
+    INIDISP_copy = 0xf;
+    nmi_disable_core_updates++;
+    submodule_index--;
+    subsubmodule_index++;
+    break;
+  case 9: {
+    overworld_palette_aux_or_main = 0;
+    Palette_Load_SpriteMain();
+    Palette_Load_SpriteEnvironment();
+    Palette_Load_Sp0L();
+    Palette_Load_HUD();
+    Palette_Load_OWBGMain();
+    uint8 sc = overworld_screen_index;
+    Overworld_LoadPalettes(kOverworldBgPalettes[sc], overworld_sprite_palettes[sc]);
+    Palette_SetOwBgColor();
+    Overworld_SetFixedColAndScroll();
+    LoadNewSpriteGFXSet();
+    COLDATA_copy2 = 0x80;
+    INIDISP_copy = 0xf;
+    nmi_disable_core_updates++;
+    subsubmodule_index++;
+    break;
+  }
+  case 10:
+    PaletteFilter_WhirlpoolRestoreRedGreen();
+    if (BYTE(palette_filter_countdown))
+      PaletteFilter_WhirlpoolRestoreRedGreen();
+    break;
+  case 11:
+    Graphics_IncrementalVRAMUpload();
+    PaletteFilter_WhirlpoolRestoreBlue();
+    break;
+  case 12:
+    countdown_for_blink = 144;
+    ReloadPreviouslyLoadedSheets();
+    HDMAEN_copy = 0x80;
+    sound_effect_ambient = overworld_music[BYTE(overworld_screen_index)] >> 4;
+    music_control = savegame_is_darkworld ? 9 : 2;
+    submodule_index = 0;
+    subsubmodule_index = 0;
+    overworld_map_state = 0;
+    nmi_disable_core_updates = 0;
+    break;
+  }
+}
+
+void Overworld_Func2F() {  // 82b521
+  dung_bg2[0x720 / 2] = 0x212;
+  Overworld_Memorize_Map16_Change(0x720, 0x212);
+  Overworld_DrawMap16(0x720, 0x212);
+  nmi_load_bg_from_vram = 1;
+  submodule_index = 0;
+}
+
+void Module09_2A_RecoverFromDrowning() {  // 82b528
+  // this is called for example when entering water without swim capability
+  switch (subsubmodule_index) {
+  case 0:  Module09_2A_00_ScrollToLand(); break;
+  default: RecoverPositionAfterDrowning(); break;
+  }
+}
+
+void Module09_2A_00_ScrollToLand() {  // 82b532
+  uint16 x = link_x_coord, xd = 0;
+  if (x != link_x_coord_cached) {
+    int16 d = (x > link_x_coord_cached) ? -1 : 1;
+    if ((x += d) != link_x_coord_cached)
+      x += d;
+    xd = x - link_x_coord;
+    link_x_coord = x;
+  }
+  uint16 y = link_y_coord, yd = 0;
+  if (y != link_y_coord_cached) {
+    int16 d = (y > link_y_coord_cached) ? -1 : 1;
+    if ((y += d) != link_y_coord_cached)
+      y += d;
+    yd = y - link_y_coord;
+    link_y_coord = y;
+  }
+  link_y_vel = yd;
+  link_x_vel = xd;
+  if (y == link_y_coord_cached && x == link_x_coord_cached) {
+    subsubmodule_index++;
+    link_incapacitated_timer = 0;
+    set_when_damaging_enemies = 0;
+  }
+  Overworld_OperateCameraScroll();
+  if (BYTE(overworld_screen_trans_dir_bits2))
+    OverworldHandleMapScroll();
+}
+
+void Overworld_OperateCameraScroll() {  // 82bb90
+  int z = (allow_scroll_z && link_z_coord != 0xffff) ? link_z_coord : 0;
+  uint16 y = link_y_coord - z + 12;
+
+  if (link_y_vel != 0) {
+    int vy = sign8(link_y_vel) ? -1 : 1;
+    int av = sign8(link_y_vel) ? (link_y_vel ^ 0xff) + 1 : link_y_vel;
+    uint16 r4 = 0, subp;
+    do {
+      if (sign8(link_y_vel)) {
+        if (y <= camera_y_coord_scroll_low)
+          r4 += OverworldCameraBoundaryCheck(6, 0, vy, 0);
+      } else {
+        if (y >= camera_y_coord_scroll_hi)
+          r4 += OverworldCameraBoundaryCheck(6, 2, vy, 0);
+      }
+    } while (--av);
+    WORD(byte_7E069E[0]) = r4;
+    uint8 oi = BYTE(overlay_index);
+    if (oi != 0x97 && oi != 0x9d && r4 != 0) {
+      if (oi == 0xb5 || oi == 0xbe) {
+        subp = (r4 & 3) << 14;
+        r4 >>= 2;
+        if (r4 >= 0x3000)
+          r4 |= 0xf000;
+      } else {
+        subp = (r4 & 1) << 15;
+        r4 >>= 1;
+        if (r4 >= 0x7000)
+          r4 |= 0xf000;
+      }
+      uint32 tmp = BG1VOFS_subpixel | BG1VOFS_copy2 << 16;
+      tmp += subp | r4 << 16;
+      BG1VOFS_subpixel = (uint16)(tmp);
+      BG1VOFS_copy2 = (uint16)(tmp >> 16);
+      if ((overworld_screen_index & 0x3f) == 0x1b) {
+        if (BG1VOFS_copy2 <= 0x600)
+          BG1VOFS_copy2 = 0x600;
+        else if (BG1VOFS_copy2 >= 0x6c0)
+          BG1VOFS_copy2 = 0x6c0;
+      }
+    }
+  }
+
+  uint16 x = link_x_coord + 8;
+  if (link_x_vel != 0) {
+    int vx = sign8(link_x_vel) ? -1 : 1;
+    int ax = sign8(link_x_vel) ? (link_x_vel ^ 0xff) + 1 : link_x_vel;
+    uint16 r4 = 0, subp;
+    do {
+      if (sign8(link_x_vel)) {
+        if (x <= camera_x_coord_scroll_low)
+          r4 += OverworldCameraBoundaryCheck(0, 4, vx, 4);
+      } else {
+        if (x >= camera_x_coord_scroll_hi)
+          r4 += OverworldCameraBoundaryCheck(0, 6, vx, 4);
+      }
+    } while (--ax);
+    WORD(byte_7E069E[1]) = r4;
+    uint8 oi = BYTE(overlay_index);
+    if (oi != 0x97 && oi != 0x9d && r4 != 0) {
+      if (oi == 0x95 || oi == 0x9e) {
+        subp = (r4 & 3) << 14;
+        r4 >>= 2;
+        if (r4 >= 0x3000)
+          r4 |= 0xf000;
+      } else {
+        subp = (r4 & 1) << 15;
+        r4 >>= 1;
+        if (r4 >= 0x7000)
+          r4 |= 0xf000;
+      }
+      uint32 tmp = BG1HOFS_subpixel | BG1HOFS_copy2 << 16;
+      tmp += subp | r4 << 16;
+      BG1HOFS_subpixel = (uint16)(tmp), BG1HOFS_copy2 = (uint16)(tmp >> 16);
+    }
+  }
+  if (BYTE(overworld_screen_index) != 0x47) {
+    if (BYTE(overlay_index) == 0x9c) {
+      uint32 tmp = BG1VOFS_subpixel | BG1VOFS_copy2 << 16;
+      tmp -= 0x2000;
+      BG1VOFS_subpixel = (uint16)(tmp), BG1VOFS_copy2 = (uint16)(tmp >> 16) + WORD(byte_7E069E[0]);
+      BG1HOFS_copy2 = BG2HOFS_copy2;
+    } else if (BYTE(overlay_index) == 0x97 || BYTE(overlay_index) == 0x9d) {
+      uint32 tmp = BG1VOFS_subpixel | BG1VOFS_copy2 << 16;
+      tmp += 0x2000;
+      BG1VOFS_subpixel = (uint16)(tmp), BG1VOFS_copy2 = (uint16)(tmp >> 16);
+      tmp = BG1HOFS_subpixel | BG1HOFS_copy2 << 16;
+      tmp += 0x2000;
+      BG1HOFS_subpixel = (uint16)(tmp), BG1HOFS_copy2 = (uint16)(tmp >> 16);
+    }
+  }
+
+  if (dungeon_room_index == 0x181) {
+    BG1VOFS_copy2 = BG2VOFS_copy2 | 0x100;
+    BG1HOFS_copy2 = BG2HOFS_copy2;
+  }
+}
+
+int OverworldCameraBoundaryCheck(int xa, int ya, int vd, int r8) {  // 82bd62
+  ya >>= 1, r8 >>= 1;
+
+  uint16 *xp = (xa ? &BG2VOFS_copy2 : &BG2HOFS_copy2);
+  uint16 *yp = &(&ow_scroll_vars0.ystart)[ya];
+  if (*xp == *yp) {
+    (&overworld_unk1)[ya] = 0;
+    (&overworld_unk1)[ya ^ 1] = 0;
+    return 0;
+  }
+  *xp += vd;
+
+  int tt = vd + (&camera_y_coord_scroll_hi)[r8];
+  (&camera_y_coord_scroll_hi)[r8] = tt;
+  (&camera_y_coord_scroll_low)[r8] = tt + 2;
+  uint16 *op = (&overworld_unk1) + ya;
+  if (!sign16(++(*op) - 0x10)) {
+    (*op) -= 0x10;
+    overworld_screen_trans_dir_bits2 |= kOverworld_Func2_Tab[ya];
+  }
+  (&overworld_unk1)[ya ^ 1] = -(&overworld_unk1)[ya];
+  return vd;
+}
+
+int OverworldScrollTransition() {  // 82c001
+  transition_counter++;
+  int y = overworld_screen_transition;
+  int d = kOverworld_Func6B_Tab1[y], rv;
+  if (y < 2) {
+    byte_7E069E[0] = d;
+    rv = (BG2VOFS_copy2 += d);
+    if (BYTE(overworld_screen_index) != 0x1b && BYTE(overworld_screen_index) != 0x5b)
+      BG1VOFS_copy2 = BG2VOFS_copy2;
+    if (transition_counter >= kOverworld_Func6B_Tab2[y])
+      link_y_coord += d;
+    if (rv != (&up_down_scroll_target)[y])
+      return rv;
+    if (y == 0)
+      BG2VOFS_copy2 -= 2;
+    link_y_coord &= ~7;
+    camera_y_coord_scroll_hi = link_y_coord + kOverworld_Func6B_Tab3[y] + 11;
+    camera_y_coord_scroll_low = camera_y_coord_scroll_hi + 2;
+    overworld_unk1 = overworld_unk1_neg = 0;
+  } else {
+    byte_7E069E[1] = d;
+    rv = (BG2HOFS_copy2 += d);
+    if (BYTE(overworld_screen_index) != 0x1b && BYTE(overworld_screen_index) != 0x5b)
+      BG1HOFS_copy2 = BG2HOFS_copy2;
+    if (transition_counter >= kOverworld_Func6B_Tab2[y])
+      link_x_coord += d;
+    if (rv != (&up_down_scroll_target)[y])
+      return rv;
+    link_x_coord &= ~7;
+    camera_x_coord_scroll_hi = link_x_coord + kOverworld_Func6B_Tab3[y] + 11;
+    camera_x_coord_scroll_low = camera_x_coord_scroll_hi + 2;
+    overworld_unk3 = overworld_unk3_neg = 0;
+  }
+  Overworld_SetCameraBoundaries(overworld_area_is_big != 0, (current_area_of_player >> 1) + kOverworld_Func6B_AreaDelta[y]);
+
+  flag_overworld_area_did_change = 1;
+  submodule_index += 1;
+  subsubmodule_index = 0;
+  transition_counter = 0;
+  Sprite_InitializeSlots();
+  return rv;
+}
+
+void Overworld_SetCameraBoundaries(int big, int area) {  // 82c0c3
+  ow_scroll_vars0.ystart = kOverworld_OffsetBaseY[area];
+  ow_scroll_vars0.yend = ow_scroll_vars0.ystart + kOverworld_Size1[big];
+  ow_scroll_vars0.xstart = kOverworld_OffsetBaseX[area];
+  ow_scroll_vars0.xend = ow_scroll_vars0.xstart + kOverworld_Size2[big];
+  up_down_scroll_target = kOverworld_UpDownScrollTarget[area];
+  up_down_scroll_target_end = up_down_scroll_target + kOverworld_UpDownScrollSize[big];
+  left_right_scroll_target = kOverworld_LeftRightScrollTarget[area];
+  left_right_scroll_target_end = left_right_scroll_target + kOverworld_LeftRightScrollSize[big];
+}
+
+void Overworld_FinalizeEntryOntoScreen() {  // 82c242
+  Link_HandleMovingAnimation_FullLongEntry();
+  int d = (byte_7E069C & 1) ? 2 : -2;
+  if (byte_7E069C & 2)
+    link_x_coord = (d += link_x_coord);
+  else
+    link_y_coord = (d += link_y_coord);
+  if ((d & 0xfe) == kOverworld_Func8_tab[byte_7E069C]) {
+    submodule_index = 0;
+    subsubmodule_index = 0;
+    uint8 m = overworld_music[BYTE(overworld_screen_index)];
+    sound_effect_ambient = m >> 4;
+    if (music_unk1 == 0xf1)
+      music_control = m & 0xf;
+  }
+  Overworld_OperateCameraScroll();
+  if (BYTE(overworld_screen_trans_dir_bits2))
+    OverworldHandleMapScroll();
+}
+
+void Overworld_Func1F() {  // 82c2a4
+  Link_HandleMovingAnimation_FullLongEntry();
+  int8 vel = byte_7E069C & 1 ? 1 : -1;
+  if (byte_7E069C & 2) {
+    link_x_coord += vel;
+    link_x_vel = vel;
+  } else {
+    link_y_coord += vel;
+    link_y_vel = vel;
+  }
+  if (!--ow_countdown_transition) {
+    main_module_index = 9;
+    subsubmodule_index = submodule_index = 0;
+  }
+  Overworld_OperateCameraScroll();
+}
+
+void ConditionalMosaicControl() {  // 82c2e4
+  if (palette_filter_countdown & 1)
+    mosaic_level += 0x10;
+  BGMODE_copy = 9;
+  MOSAIC_copy = mosaic_level | 7;
+}
+
+void Overworld_ResetMosaic_alwaysIncrease() {  // 82c2eb
+  mosaic_level += 0x10;
+  BGMODE_copy = 9;
+  MOSAIC_copy = mosaic_level | 7;
+}
+
+void Overworld_SetSongList() {  // 82c463
+  uint8 r0 = 2, y = 0xc0;
+  if (sram_progress_indicator < 3) {
+    y = 0x80;
+    if (link_sword_type < 2) {
+      r0 = 5;
+      y = 0x40;
+      if (sram_progress_indicator < 2)
+        y = 0;
+    }
+  }
+  memcpy(overworld_music, &kOwMusicSets[y], 64);
+  memcpy(overworld_music + 64, kOwMusicSets2, 96);
+  overworld_music[128] = r0;
+}
+
+void LoadOverworldFromDungeon() {  // 82e4a3
+  player_is_indoors = 0;
+  hdr_dungeon_dark_with_lantern = 0;
+  WORD(overworld_fixed_color_plusminus) = 0;
+  cur_palace_index_x2 = 0xff;
+  num_memorized_tiles = 0;
+
+  if (dungeon_room_index != 0x104 && dungeon_room_index < 0x180 && dungeon_room_index >= 0x100) {
+    LoadCachedEntranceProperties();
+  } else {
+
+    int k = 79;
+    do k--; while (kExitDataRooms[k] != dungeon_room_index);
+    BG1VOFS_copy2 = BG2VOFS_copy2 = BG1VOFS_copy = BG2VOFS_copy = kExitData_ScrollY[k];
+    BG1HOFS_copy2 = BG2HOFS_copy2 = BG1HOFS_copy = BG2HOFS_copy = kExitData_ScrollX[k];
+    link_y_coord = kExitData_YCoord[k];
+    link_x_coord = kExitData_XCoord[k];
+    map16_load_src_off = kExitData_Map16LoadSrcOff[k];
+    map16_load_var2 = (map16_load_src_off - 0x400 & 0xf80) >> 7;
+    map16_load_dst_off = (map16_load_src_off - 0x10 & 0x3e) >> 1;
+    camera_y_coord_scroll_low = kExitData_CameraYScroll[k];
+    camera_y_coord_scroll_hi = camera_y_coord_scroll_low - 2;
+    camera_x_coord_scroll_low = kExitData_CameraXScroll[k];
+    camera_x_coord_scroll_hi = camera_x_coord_scroll_low - 2;
+    WORD(link_direction_facing) = 2;
+    ow_entrance_value = kExitData_NormalDoor[k];
+    big_rock_starting_address = kExitData_FancyDoor[k];
+    overworld_area_index = overworld_screen_index = kExitData_ScreenIndex[k];
+    overworld_unk1 = kExitData_Unk1[k];
+    overworld_unk3 = kExitData_Unk3[k];
+    overworld_unk1_neg = -overworld_unk1;
+    overworld_unk3_neg = -overworld_unk3;
+  }
+  Overworld_LoadNewScreenProperties();
+}
+
+void Overworld_LoadNewScreenProperties() {  // 82e58b
+  tilemap_location_calc_mask = ~7;
+  Overworld_LoadGFXAndScreenSize();
+  BYTE(overworld_right_bottom_bound_for_scroll) = 0xe4;
+  overworld_area_is_big &= 0xff;
+  Overworld_SetCameraBoundaries(overworld_area_is_big != 0, overworld_screen_index & 0x3f);
+  link_quadrant_x = 0;
+  link_quadrant_y = 2;
+  quadrant_fullsize_x = 2;
+  quadrant_fullsize_y = 2;
+  player_oam_x_offset = player_oam_y_offset = 0x80;
+  link_direction_mask_a = link_direction_mask_b = 0xf;
+  BYTE(link_z_coord) = 0xff;
+  link_actual_vel_z = 0xff;
+}
+
+void LoadCachedEntranceProperties() {  // 82e5d4
+  overworld_area_index = overworld_area_index_exit;
+  WORD(TM_copy) = WORD(TM_copy_exit);
+  BG2VOFS_copy2 = BG2VOFS_copy = BG1VOFS_copy2 = BG1VOFS_copy = BG2VOFS_copy2_exit;
+  BG2HOFS_copy2 = BG2HOFS_copy = BG1HOFS_copy2 = BG1HOFS_copy = BG2HOFS_copy2_exit;
+  link_x_coord = link_x_coord_exit;
+  link_y_coord = link_y_coord_exit;
+  if (dungeon_room_index < 0x124)
+    link_y_coord -= 0x10;
+  WORD(link_direction_facing) = 2;
+  if (ow_entrance_value == 0xffff) {
+    link_y_coord += 0x20;
+    WORD(link_direction_facing) = 0;
+  }
+  overworld_screen_index = overworld_screen_index_exit;
+  map16_load_src_off = map16_load_src_off_exit;
+  map16_load_var2 = (map16_load_src_off - 0x400 & 0xf80) >> 7;
+  map16_load_dst_off = (map16_load_src_off - 0x10 & 0x3e) >> 1;
+  camera_y_coord_scroll_low = camera_y_coord_scroll_low_exit;
+  camera_y_coord_scroll_hi = camera_y_coord_scroll_low - 2;
+  camera_x_coord_scroll_low = camera_x_coord_scroll_low_exit;
+  camera_x_coord_scroll_hi = camera_x_coord_scroll_low - 2;
+  ow_scroll_vars0 = ow_scroll_vars0_exit;
+  up_down_scroll_target = up_down_scroll_target_exit;
+  up_down_scroll_target_end = up_down_scroll_target_end_exit;
+  left_right_scroll_target = left_right_scroll_target_exit;
+  left_right_scroll_target_end = left_right_scroll_target_end_exit;
+  overworld_unk1 = overworld_unk1_exit;
+  overworld_unk1_neg = overworld_unk1_neg_exit;
+  overworld_unk3 = overworld_unk3_exit;
+  overworld_unk3_neg = overworld_unk3_neg_exit;
+  byte_7E0AA0 = byte_7EC164;
+  main_tile_theme_index = main_tile_theme_index_exit;
+  aux_tile_theme_index = aux_tile_theme_index_exit;
+  sprite_graphics_index = sprite_graphics_index_exit;
+
+}
+
+void Overworld_EnterSpecialArea() {  // 82e851
+  num_memorized_tiles = 0;
+  overworld_area_index_spexit = overworld_area_index;
+  WORD(TM_copy_spexit) = WORD(TM_copy);
+  BG2VOFS_copy2_spexit = BG2VOFS_copy2;
+  BG2HOFS_copy2_spexit = BG2HOFS_copy2;
+
+  link_x_coord_spexit = link_x_coord;
+  link_y_coord_spexit = link_y_coord;
+
+  camera_y_coord_scroll_low_spexit = camera_y_coord_scroll_low;
+  camera_x_coord_scroll_low_spexit = camera_x_coord_scroll_low;
+  overworld_screen_index_spexit = overworld_screen_index;
+  map16_load_src_off_spexit = map16_load_src_off;
+  room_scroll_vars0_ystart_spexit = ow_scroll_vars0.ystart;
+  room_scroll_vars0_yend_spexit = ow_scroll_vars0.yend;
+  room_scroll_vars0_xstart_spexit = ow_scroll_vars0.xstart;
+  room_scroll_vars0_xend_spexit = ow_scroll_vars0.xend;
+
+  up_down_scroll_target_spexit = up_down_scroll_target;
+  up_down_scroll_target_end_spexit = up_down_scroll_target_end;
+  left_right_scroll_target_spexit = left_right_scroll_target;
+  left_right_scroll_target_end_spexit = left_right_scroll_target_end;
+  overworld_unk1_spexit = overworld_unk1;
+  overworld_unk1_neg_spexit = overworld_unk1_neg;
+  overworld_unk3_spexit = overworld_unk3;
+  overworld_unk3_neg_spexit = overworld_unk3_neg;
+  byte_7EC124 = byte_7E0AA0;
+  main_tile_theme_index_spexit = main_tile_theme_index;
+  aux_tile_theme_index_spexit = aux_tile_theme_index;
+  sprite_graphics_index_spexit = sprite_graphics_index;
+  LoadOverworldFromDungeon();
+  if (dungeon_room_index == 0x1010)
+    dungeon_room_index = 0x182;
+
+  uint8 roombak = dungeon_room_index;
+  int i = (BYTE(dungeon_room_index) -= 0x80);
+  link_direction_facing = kSpExit_Dir[i];
+  incremental_counter_for_vram = 0;
+  sprite_graphics_index = kSpExit_SprGfx[i];
+  aux_tile_theme_index = kSpExit_AuxGfx[i];
+  Overworld_LoadPalettes(kSpExit_PalBg[i], kSpExit_PalSpr[i]);
+
+  int j = dungeon_room_index & 0x3f;
+  overworld_offset_base_y = kSpExit_Top[j];
+  overworld_offset_base_x = kSpExit_LeftEdgeOfMap[j] >> 3;
+  overworld_offset_mask_y = 0x3f0;
+  overworld_offset_mask_x = 0x3f0 >> 3;
+
+  int k = dungeon_room_index & 0x7f;
+  ow_scroll_vars0.ystart = kSpExit_Top[k];
+  ow_scroll_vars0.yend = kSpExit_Bottom[k];
+  ow_scroll_vars0.xstart = kSpExit_Left[k];
+  ow_scroll_vars0.xend = kSpExit_Right[k];
+  up_down_scroll_target = kSpExit_Tab4[k];
+  up_down_scroll_target_end = kSpExit_Tab5[k];
+  left_right_scroll_target = kSpExit_Tab6[k];
+  left_right_scroll_target_end = kSpExit_Tab7[k];
+
+  BYTE(dungeon_room_index) = roombak;
+  Palette_SpecialOw();
+}
+
+void LoadOverworldFromSpecialOverworld() {  // 82e9bc
+  num_memorized_tiles = 0;
+  overworld_area_index = overworld_area_index_spexit;
+   WORD(TM_copy) = WORD(TM_copy_spexit);
+  BG2VOFS_copy2 = BG2VOFS_copy = BG1VOFS_copy2 = BG1VOFS_copy = BG2VOFS_copy2_spexit;
+  BG2HOFS_copy2 = BG2HOFS_copy = BG1HOFS_copy2 = BG1HOFS_copy = BG2HOFS_copy2_spexit;
+  link_x_coord = link_x_coord_spexit;
+  link_y_coord = link_y_coord_spexit;
+  overworld_screen_index = overworld_screen_index_spexit;
+  map16_load_src_off = map16_load_src_off_spexit;
+  map16_load_var2 = (map16_load_src_off - 0x400 & 0xf80) >> 7;
+  map16_load_dst_off = (map16_load_src_off - 0x10 & 0x3e) >> 1;
+  camera_y_coord_scroll_low = camera_y_coord_scroll_low_spexit;
+  camera_y_coord_scroll_hi = camera_y_coord_scroll_low - 2;
+  camera_x_coord_scroll_low = camera_x_coord_scroll_low_spexit;
+  camera_x_coord_scroll_hi = camera_x_coord_scroll_low - 2;
+  ow_scroll_vars0.ystart = room_scroll_vars0_ystart_spexit;
+  ow_scroll_vars0.yend = room_scroll_vars0_yend_spexit;
+  ow_scroll_vars0.xstart = room_scroll_vars0_xstart_spexit;
+  ow_scroll_vars0.xend = room_scroll_vars0_xend_spexit;
+  up_down_scroll_target = up_down_scroll_target_spexit;
+  up_down_scroll_target_end = up_down_scroll_target_end_spexit;
+  left_right_scroll_target = left_right_scroll_target_spexit;
+  left_right_scroll_target_end = left_right_scroll_target_end_spexit;
+  overworld_unk1 = overworld_unk1_spexit;
+  overworld_unk1_neg = overworld_unk1_neg_spexit;
+  overworld_unk3 = overworld_unk3_spexit;
+  overworld_unk3_neg = overworld_unk3_neg_spexit;
+  byte_7E0AA0 = byte_7EC124;
+  main_tile_theme_index = main_tile_theme_index_spexit;
+  aux_tile_theme_index = aux_tile_theme_index_spexit;
+  sprite_graphics_index = sprite_graphics_index_spexit;
+  uint8 sc = overworld_screen_index;
+  Overworld_LoadPalettes(kOverworldBgPalettes[sc], overworld_sprite_palettes[sc]);
+  Palette_SpecialOw();
+  link_quadrant_x = 0;
+  link_quadrant_y = 2;
+  quadrant_fullsize_x = 2;
+  quadrant_fullsize_y = 2;
+  player_oam_x_offset = player_oam_y_offset = 0x80;
+  link_direction_mask_a = link_direction_mask_b = 0xf;
+  BYTE(link_z_coord) = 0xff;
+  link_actual_vel_z = 0xff;
+  Link_ResetSwimmingState();
+  Overworld_LoadGFXAndScreenSize();
+  BYTE(overworld_right_bottom_bound_for_scroll) = 228;
+  overworld_area_is_big &= 0xff;
+}
+
+void FluteMenu_LoadTransport() {  // 82ec39
+  num_memorized_tiles = 0;
+  int k = birdtravel_var1[0];
+  WORD(birdtravel_var1[0]) <<= 1;
+  Overworld_LoadBirdTravelPos(k);
+}
+
+void Overworld_LoadBirdTravelPos(int k) {  // 82ec47
+  BG1VOFS_copy2 = BG2VOFS_copy2 = BG1VOFS_copy = BG2VOFS_copy = kBirdTravel_ScrollY[k];
+  BG1HOFS_copy2 = BG2HOFS_copy2 = BG1HOFS_copy = BG2HOFS_copy = kBirdTravel_ScrollX[k];
+  link_y_coord = kBirdTravel_LinkYCoord[k];
+  link_x_coord = kBirdTravel_LinkXCoord[k];
+  overworld_unk1 = kBirdTravel_Unk1[k];
+  overworld_unk3 = kBirdTravel_Unk3[k];
+  overworld_unk1_neg = -overworld_unk1;
+  overworld_unk3_neg = -overworld_unk3;
+  overworld_area_index = overworld_screen_index = kBirdTravel_ScreenIndex[k];
+
+  map16_load_src_off = kBirdTravel_Map16LoadSrcOff[k];
+  map16_load_var2 = (map16_load_src_off - 0x400 & 0xf80) >> 7;
+  map16_load_dst_off = (map16_load_src_off - 0x10 & 0x3e) >> 1;
+  camera_y_coord_scroll_low = kBirdTravel_CameraYScroll[k];
+  camera_y_coord_scroll_hi = camera_y_coord_scroll_low - 2;
+  camera_x_coord_scroll_low = kBirdTravel_CameraXScroll[k];
+  camera_x_coord_scroll_hi = camera_x_coord_scroll_low - 2;
+  ow_entrance_value = 0;
+  big_rock_starting_address = 0;
+  Overworld_LoadNewScreenProperties();
+  Sprite_ResetAll();
+  Sprite_ReloadAll_Overworld();
+  is_standing_in_doorway = 0;
+  Dungeon_ResetTorchBackgroundAndPlayerInner();
+}
+
+void FluteMenu_LoadSelectedScreenPalettes() {  // 82ecdd
+  OverworldLoadScreensPaletteSet();
+  uint8 sc = overworld_screen_index;
+  Overworld_LoadPalettes(kOverworldBgPalettes[sc], overworld_sprite_palettes[sc]);
+  Palette_SetOwBgColor();
+  Overworld_LoadPalettesInner();
+}
+
+void FindPartnerWhirlpoolExit() {  // 82ed08
+  int j = FindInWordArray(kWhirlpoolAreas, overworld_screen_index, kWhirlpoolAreas_SIZE / 2);
+  if (j >= 0) {
+    num_memorized_tiles = 0;
+    Overworld_LoadBirdTravelPos(j + 9);
+  }
+}
+
+void Overworld_LoadAmbientOverlay(bool load_map_data) {  // 82ed25
+  uint16 bak1 = map16_load_src_off;
+  uint16 bak2 = map16_load_dst_off;
+  uint16 bak3 = map16_load_var2;
+
+  if (kOverworldMapIsSmall[BYTE(overworld_screen_index)]) {
+    map16_load_src_off = 0x390;
+    map16_load_var2 = (0x390 - 0x400 & 0xf80) >> 7;
+    map16_load_dst_off = (0x390 - 0x10 & 0x3e) >> 1;
+  }
+
+  if (load_map_data)
+    Overworld_DrawQuadrantsAndOverlays();
+
+  Map16ToMap8(&g_ram[0x2000], 0);
+  map16_load_var2 = bak3;
+  map16_load_dst_off = bak2;
+  map16_load_src_off = bak1;
+
+  nmi_subroutine_index = 4;
+  nmi_disable_core_updates = 4;
+  submodule_index++;
+  INIDISP_copy = 0;
+}
+
+void Overworld_LoadAmbientOverlayFalse() {  // 82ed24
+  Overworld_LoadAmbientOverlay(false);
+}
+
+void Overworld_LoadAndBuildScreen() {  // 82ed59
+  Overworld_LoadAmbientOverlay(true);
+}
+
+void Module08_02_LoadAndAdvance() {  // 82edb9
+  Overworld_LoadAndBuildScreen();
+  main_module_index = 16;
+  submodule_index = 0;
+  subsubmodule_index = 0;
+}
+
+void Overworld_DrawQuadrantsAndOverlays() {  // 82eec5
+  Overworld_DecompressAndDrawAllQuadrants();
+  for (int i = 0; i < 16 * 4; i++)
+    dung_bg1[i] = 0xdc4;
+  uint16 pos = ow_entrance_value;
+  if (pos != 0 && pos != 0xffff) {
+    if (pos < 0x8000) {
+      dung_bg2[pos >> 1] = 0xDA4;
+      Overworld_Memorize_Map16_Change(pos, 0xda4);
+      dung_bg2[(pos + 2) >> 1] = 0xda6;
+      Overworld_Memorize_Map16_Change(pos + 2, 0xda6);
+    } else {
+      pos &= 0x1fff;
+      dung_bg2[pos >> 1] = 0xdb4;
+      Overworld_Memorize_Map16_Change(pos, 0xdb4);
+      dung_bg2[(pos + 2) >> 1] = 0xdb5;
+      Overworld_Memorize_Map16_Change(pos + 2, 0xdb5);
+    }
+    ow_entrance_value = 0;
+  }
+  Overworld_HandleOverlaysAndBombDoors();
+}
+
+void Overworld_HandleOverlaysAndBombDoors() {  // 82ef29
+  if (overworld_screen_index == 0x33)
+    dung_bg2[340] = 0x20f;
+  else if (overworld_screen_index == 0x2f)
+    dung_bg2[1497] = 0x20f;
+  if (BYTE(overworld_screen_index) < 0x80 && save_ow_event_info[BYTE(overworld_screen_index)] & 0x20)
+    Overworld_LoadEventOverlay();
+  if (save_ow_event_info[BYTE(overworld_screen_index)] & 2) {
+    int pos = kSecondaryOverlayPerOw[overworld_screen_index] >> 1;
+    dung_bg2[pos + 0] = 0xdb4;
+    dung_bg2[pos + 1] = 0xdb5;
+  }
+}
+
+void TriggerAndFinishMapLoadStripe_Y(int n) {  // 82ef7a
+  BYTE(overworld_screen_trans_dir_bits2) = 8;
+  nmi_subroutine_index = 3;
+  uint16 *dst = uvram.data;
+  *dst++ = 0x80;
+  do {
+    dst = BufferAndBuildMap16Stripes_Y(dst);
+    map16_load_src_off -= 0x80;
+    map16_load_var2 = (map16_load_var2 - 1) & 0x1f;
+  } while (--n);
+  *dst = 0xffff;
+}
+
+void TriggerAndFinishMapLoadStripe_X(int n) {  // 82efb3
+  BYTE(overworld_screen_trans_dir_bits2) = 2;
+  nmi_subroutine_index = 3;
+  uint16 *dst = uvram.data;
+  *dst++ = 0x8040;
+  do {
+    dst = BufferAndBuildMap16Stripes_X(dst);
+    map16_load_src_off -= 2;
+    map16_load_dst_off = (map16_load_dst_off - 1) & 0x1f;
+  } while (--n);
+  *dst = 0xffff;
+}
+
+void SomeTileMapChange() {  // 82efe8
+  Overworld_DecompressAndDrawAllQuadrants();
+  for (int i = 0; i < 64; i++)
+    dung_bg1[i] = 0xdc4;
+  Overworld_HandleOverlaysAndBombDoors();
+  submodule_index++;
+}
+
+void CreateInitialNewScreenMapToScroll() {  // 82f031
+  if (!kOverworldMapIsSmall[BYTE(overworld_screen_index)]) {
+    switch (BYTE(overworld_screen_trans_dir_bits2)) {
+    case 1: CreateInitialOWScreenView_Big_East(); break;
+    case 2: CreateInitialOWScreenView_Big_West(); break;
+    case 4: CreateInitialOWScreenView_Big_South(); break;
+    case 8: CreateInitialOWScreenView_Big_North(); break;
+    default:
+      assert(0);
+      submodule_index = 0;
+    }
+  } else {
+    switch (BYTE(overworld_screen_trans_dir_bits2)) {
+    case 1: CreateInitialOWScreenView_Small_East(); break;
+    case 2: CreateInitialOWScreenView_Small_West(); break;
+    case 4: CreateInitialOWScreenView_Small_South(); break;
+    case 8: CreateInitialOWScreenView_Small_North(); break;
+    default:
+      assert(0);
+      submodule_index = 0;
+    }
+  }
+}
+
+void CreateInitialOWScreenView_Big_North() {  // 82f06b
+  map16_load_src_off += 0x380;
+  map16_load_var2 = 31;
+  TriggerAndFinishMapLoadStripe_Y(7);
+}
+
+void CreateInitialOWScreenView_Big_South() {  // 82f087
+  uint16 pos = map16_load_src_off;
+  while (pos >= 0x80)
+    pos -= 0x80;
+  map16_load_src_off = pos + 0x780;
+  map16_load_var2 = 7;
+  TriggerAndFinishMapLoadStripe_Y(8);
+  map16_load_var2 = (map16_load_var2 + 9) & 0x1f;
+  map16_load_src_off -= 0xB80;
+}
+
+void CreateInitialOWScreenView_Big_West() {  // 82f0c0
+  map16_load_src_off += 14;
+  map16_load_dst_off = 31;
+  TriggerAndFinishMapLoadStripe_X(7);
+}
+
+void CreateInitialOWScreenView_Big_East() {  // 82f0dc
+  map16_load_src_off = map16_load_src_off - 0x60 + 0x1e;
+  map16_load_dst_off = 7;
+  TriggerAndFinishMapLoadStripe_X(8);
+  map16_load_dst_off = (map16_load_dst_off + 9) & 0x1f;
+  map16_load_src_off -= 0x2e;
+}
+
+void CreateInitialOWScreenView_Small_North() {  // 82f10f
+  orange_blue_barrier_state = map16_load_src_off - 0x700;
+  word_7EC174 = map16_load_dst_off;
+  word_7EC176 = 10;
+  map16_load_src_off = 0x1390;
+  map16_load_dst_off = 0;
+  map16_load_var2 = 31;
+  TriggerAndFinishMapLoadStripe_Y(7);
+}
+
+void CreateInitialOWScreenView_Small_South() {  // 82f141
+  orange_blue_barrier_state = BYTE(map16_load_src_off);
+  word_7EC174 = map16_load_dst_off;
+  word_7EC176 = 24;
+  map16_load_src_off = 0x790;
+  map16_load_dst_off = 0;
+  map16_load_var2 = 7;
+  TriggerAndFinishMapLoadStripe_Y(8);
+  map16_load_var2 = (map16_load_var2 + 9) & 0x1f;
+  map16_load_src_off -= 0xB80;
+}
+
+void CreateInitialOWScreenView_Small_West() {  // 82f185
+  orange_blue_barrier_state = map16_load_src_off - 0x20;
+  word_7EC174 = 8;
+  word_7EC176 = map16_load_var2;
+  map16_load_src_off = 0x44e;
+  map16_load_var2 = 0;
+  map16_load_dst_off = 31;
+  TriggerAndFinishMapLoadStripe_X(7);
+}
+
+void CreateInitialOWScreenView_Small_East() {  // 82f1b7
+  orange_blue_barrier_state = map16_load_src_off - 0x60;
+  word_7EC174 = 0x18;
+  word_7EC176 = map16_load_var2;
+  map16_load_src_off = 0x41e;
+  map16_load_var2 = 0;
+  map16_load_dst_off = 7;
+  TriggerAndFinishMapLoadStripe_X(8);
+  map16_load_dst_off = (map16_load_dst_off + 9) & 0x1f;
+  map16_load_src_off -= 0x2e;
+}
+
+void OverworldTransitionScrollAndLoadMap() {  // 82f20e
+  uint16 *dst = uvram.data;
+  switch (BYTE(overworld_screen_trans_dir_bits2)) {
+  case 1: dst = BuildFullStripeDuringTransition_East(dst); break;
+  case 2: dst = BuildFullStripeDuringTransition_West(dst); break;
+  case 4: dst = BuildFullStripeDuringTransition_South(dst); break;
+  case 8: dst = BuildFullStripeDuringTransition_North(dst); break;
+  default:
+    assert(0);
+    submodule_index = 0;
+  }
+  dst[0] = dst[1] = 0xffff;
+  if (dst != uvram.data)
+    nmi_subroutine_index = 3;
+}
+
+uint16 *BuildFullStripeDuringTransition_North(uint16 *dst) {  // 82f218
+  *dst++ = 0x80;
+  dst = BufferAndBuildMap16Stripes_Y(dst);
+  map16_load_src_off -= 0x80;
+  map16_load_var2 = (map16_load_var2 - 1) & 0x1f;
+  return dst;
+}
+
+uint16 *BuildFullStripeDuringTransition_South(uint16 *dst) {  // 82f238
+  *dst++ = 0x80;
+  dst = BufferAndBuildMap16Stripes_Y(dst);
+  map16_load_src_off += 0x80;
+  map16_load_var2 = (map16_load_var2 + 1) & 0x1f;
+  return dst;
+}
+
+uint16 *BuildFullStripeDuringTransition_West(uint16 *dst) {  // 82f241
+  *dst++ = 0x8040;
+  dst = BufferAndBuildMap16Stripes_X(dst);
+  map16_load_src_off -= 2;
+  map16_load_dst_off = (map16_load_dst_off - 1) & 0x1f;
+  return dst;
+}
+
+uint16 *BuildFullStripeDuringTransition_East(uint16 *dst) {  // 82f24a
+  *dst++ = 0x8040;
+  dst = BufferAndBuildMap16Stripes_X(dst);
+  map16_load_src_off += 2;
+  map16_load_dst_off = (map16_load_dst_off + 1) & 0x1f;
+  return dst;
+}
+
+void OverworldHandleMapScroll() {  // 82f273
+  uint16 *dst = uvram.data;
+  switch (BYTE(overworld_screen_trans_dir_bits2)) {
+  case 1:
+    dst = CheckForNewlyLoadedMapAreas_East(dst);
+    BYTE(overworld_screen_trans_dir_bits2) = 0;
+    break;
+  case 2:
+    dst = CheckForNewlyLoadedMapAreas_West(dst);
+    BYTE(overworld_screen_trans_dir_bits2) = 0;
+    break;
+  case 4:
+    dst = CheckForNewlyLoadedMapAreas_South(dst);
+    BYTE(overworld_screen_trans_dir_bits2) = 0;
+    break;
+  case 5:
+  case 6:
+    dst = CheckForNewlyLoadedMapAreas_South(dst);
+    BYTE(overworld_screen_trans_dir_bits2) &= 3;
+    break;
+  case 8:
+    dst = CheckForNewlyLoadedMapAreas_North(dst);
+    BYTE(overworld_screen_trans_dir_bits2) = 0;
+    break;
+  case 9:
+  case 10:
+    dst = CheckForNewlyLoadedMapAreas_North(dst);
+    BYTE(overworld_screen_trans_dir_bits2) &= 3;
+    break;
+  default:
+    assert(0);
+    submodule_index = 0;
+  }
+  dst[0] = dst[1] = 0xffff;
+  if (dst != uvram.data)
+    nmi_subroutine_index = 3;
+  overworld_screen_transition = overworld_screen_trans_dir_bits2;
+}
+
+uint16 *CheckForNewlyLoadedMapAreas_North(uint16 *dst) {  // 82f2dd
+  if (sign16(map16_load_src_off - 0x80))
+    return dst;
+  if (!kOverworldMapIsSmall[overworld_screen_index]) {
+    *dst++ = 0x80;
+    dst = BufferAndBuildMap16Stripes_Y(dst);
+  }
+  map16_load_src_off -= 0x80;
+  map16_load_var2 = (map16_load_var2 - 1) & 0x1f;
+  return dst;
+}
+
+uint16 *CheckForNewlyLoadedMapAreas_South(uint16 *dst) {  // 82f311
+  if (map16_load_src_off >= 0x1800)
+    return dst;
+  if (!kOverworldMapIsSmall[overworld_screen_index]) {
+    *dst++ = 0x80;
+    dst = BufferAndBuildMap16Stripes_Y(dst);
+  }
+  map16_load_src_off += 0x80;
+  map16_load_var2 = (map16_load_var2 + 1) & 0x1f;
+  return dst;
+}
+
+uint16 *CheckForNewlyLoadedMapAreas_West(uint16 *dst) {  // 82f345
+  uint16 pos = map16_load_src_off;
+  while (pos >= 0x80)
+    pos -= 0x80;
+  if (pos == 0)
+    return dst;
+  if (!kOverworldMapIsSmall[overworld_screen_index]) {
+    *dst++ = 0x8040;
+    dst = BufferAndBuildMap16Stripes_X(dst);
+  }
+  map16_load_src_off -= 2;
+  map16_load_dst_off = (map16_load_dst_off - 1) & 0x1f;
+  return dst;
+}
+
+uint16 *CheckForNewlyLoadedMapAreas_East(uint16 *dst) {  // 82f37f
+  uint16 pos = map16_load_src_off;
+  while (pos >= 0x80)
+    pos -= 0x80;
+  if (pos >= 0x60)
+    return dst;
+  if (!kOverworldMapIsSmall[overworld_screen_index]) {
+    *dst++ = 0x8040;
+    dst = BufferAndBuildMap16Stripes_X(dst);
+  }
+  map16_load_src_off += 2;
+  map16_load_dst_off = (map16_load_dst_off + 1) & 0x1f;
+  return dst;
+}
+
+uint16 *BufferAndBuildMap16Stripes_X(uint16 *dst) {  // 82f3b9
+  uint16 pos = map16_load_src_off - kOverworld_DrawStrip_Tab[overworld_screen_trans_dir_bits2 >> 1 & 1];
+  int d = map16_load_var2;
+  uint16 *tmp = dung_replacement_tile_state;
+  for (int i = 0; i < 32; i++) {
+    tmp[d] = (pos >= 0x2000) ? 0 : dung_bg2[pos >> 1];
+    d = (d + 1) & 0x1f, pos += 128;
+  }
+  const uint16 *map8 = GetMap16toMap8Table();
+  uint16 r0 = 0, of = map16_load_dst_off;
+  if (of >= 0x10)
+    of &= 0xf, r0 = 0x400;
+  r0 += of * 2;
+  for (int i = 0; i < 2; i++, r0 += 0x800) {
+    dst[0] = r0;
+    dst[33] = r0 + 1;
+    dst++;
+    for (int j = 0; j < 16; j++) {
+      int k = *tmp++;
+      assert(k < 0xea8);
+      const uint16 *s = map8 + k * 4;
+      dst[0] = s[0];
+      dst[33] = s[1];
+      dst[1] = s[2];
+      dst[34] = s[3];
+      dst += 2;
+    }
+    dst += 33;
+  }
+  return dst;
+}
+
+uint16 *BufferAndBuildMap16Stripes_Y(uint16 *dst) {  // 82f482
+  uint16 pos = map16_load_src_off - kOverworld_DrawStrip_Tab[1 + (overworld_screen_trans_dir_bits2 >> 2 & 1)];
+  int d = map16_load_dst_off;
+  uint16 *tmp = dung_replacement_tile_state;
+  for (int i = 0; i < 32; i++) {
+    tmp[d] = (pos >= 0x2000) ? 0 : dung_bg2[pos >> 1]; // fixed bug warning. can go negative
+    pos += 2;
+    d = (d + 1) & 0x1f;
+  }
+  const uint16 *map8 = GetMap16toMap8Table();
+  uint16 r0 = 0, of = map16_load_var2;
+  if (of >= 0x10)
+    of &= 0xf, r0 = 0x800;
+  r0 += of * 64;
+  for (int i = 0; i < 2; i++, r0 += 0x400) {
+    *dst++ = r0;
+    for (int j = 0; j < 16; j++) {
+      int k = *tmp++;
+      assert(k < 0xea8);
+      const uint16 *s = map8 + k * 4;
+      dst[0] = s[0];
+      dst[32] = s[2];
+      dst[1] = s[1];
+      dst[33] = s[3];
+      dst += 2;
+    }
+    dst += 32;
+  }
+  return dst;
+}
+
+void Overworld_DecompressAndDrawAllQuadrants() {  // 82f54a
+  int si = overworld_screen_index;
+  Overworld_DecompressAndDrawOneQuadrant((uint16 *)&g_ram[0x2000], si + 0);
+  Overworld_DecompressAndDrawOneQuadrant((uint16 *)&g_ram[0x2040], si + 1);
+  Overworld_DecompressAndDrawOneQuadrant((uint16 *)&g_ram[0x3000], si + 8);
+  Overworld_DecompressAndDrawOneQuadrant((uint16 *)&g_ram[0x3040], si + 9);
+}
+
+static const uint8 *GetOverworldHibytes(int i) {
+  return kOverworld_Hibytes_Comp(i).ptr;
+}
+
+static const uint8 *GetOverworldLobytes(int i) {
+  return kOverworld_Lobytes_Comp(i).ptr;
+}
+
+
+void Overworld_DecompressAndDrawOneQuadrant(uint16 *dst, int screen) {  // 82f595
+  Decompress_bank02(&g_ram[0x14400], GetOverworldHibytes(screen));
+  for (int i = 0; i < 256; i++)
+    g_ram[0x14001 + i * 2] = g_ram[0x14400 + i];
+
+  Decompress_bank02(&g_ram[0x14400], GetOverworldLobytes(screen));
+  for (int i = 0; i < 256; i++)
+    g_ram[0x14000 + i * 2] = g_ram[0x14400 + i];
+
+  map16_decode_last = 0xffff;
+
+  uint16 *src = (uint16 *)&g_ram[0x14000];
+  for (int j = 0; j < 16; j++) {
+    for (int i = 0; i < 16; i++) {
+      Overworld_ParseMap32Definition(dst, *src++ * 2);
+      dst += 2;
+    }
+    dst += 96;
+  }
+}
+
+void Overworld_ParseMap32Definition(uint16 *dst, uint16 input) {  // 82f691
+  uint16 a = input & ~7;
+  if (a != map16_decode_last) {
+    map16_decode_last = a;
+    map16_decode_tmp = a >> 1;
+    int x = (a >> 1) + (a >> 2);
+    const uint8 *ov;
+    ov = kMap32ToMap16_0 + x;
+
+    map16_decode_0[0] = ov[0];
+    map16_decode_0[2] = ov[1];
+    map16_decode_0[4] = ov[2];
+    map16_decode_0[6] = ov[3];
+    map16_decode_0[1] = ov[4] >> 4;
+    map16_decode_0[3] = ov[4] & 0xf;
+    map16_decode_0[5] = ov[5] >> 4;
+    map16_decode_0[7] = ov[5] & 0xf;
+    ov = kMap32ToMap16_1 + x;
+    map16_decode_1[0] = ov[0];
+    map16_decode_1[2] = ov[1];
+    map16_decode_1[4] = ov[2];
+    map16_decode_1[6] = ov[3];
+    map16_decode_1[1] = ov[4] >> 4;
+    map16_decode_1[3] = ov[4] & 0xf;
+    map16_decode_1[5] = ov[5] >> 4;
+    map16_decode_1[7] = ov[5] & 0xf;
+    ov = kMap32ToMap16_2 + x;
+    map16_decode_2[0] = ov[0];
+    map16_decode_2[2] = ov[1];
+    map16_decode_2[4] = ov[2];
+    map16_decode_2[6] = ov[3];
+    map16_decode_2[1] = ov[4] >> 4;
+    map16_decode_2[3] = ov[4] & 0xf;
+    map16_decode_2[5] = ov[5] >> 4;
+    map16_decode_2[7] = ov[5] & 0xf;
+    ov = kMap32ToMap16_3 + x;
+    map16_decode_3[0] = ov[0];
+    map16_decode_3[2] = ov[1];
+    map16_decode_3[4] = ov[2];
+    map16_decode_3[6] = ov[3];
+    map16_decode_3[1] = ov[4] >> 4;
+    map16_decode_3[3] = ov[4] & 0xf;
+    map16_decode_3[5] = ov[5] >> 4;
+    map16_decode_3[7] = ov[5] & 0xf;
+  }
+  dst[0] = WORD(map16_decode_0[input & 7]);
+  dst[64] = WORD(map16_decode_2[input & 7]);
+  dst[1] = WORD(map16_decode_1[input & 7]);
+  dst[65] = WORD(map16_decode_3[input & 7]);
+}
+
+void OverworldLoad_LoadSubOverlayMap32() {  // 82f7cb
+  int si = overworld_screen_index;
+  Overworld_DecompressAndDrawOneQuadrant((uint16 *)&g_ram[0x4000], si);
+}
+
+void LoadOverworldOverlay() {  // 82fd0d
+  OverworldLoad_LoadSubOverlayMap32();
+  Map16ToMap8(&g_ram[0x4000], 0x1000);
+  nmi_subroutine_index = nmi_disable_core_updates = 4;
+  submodule_index++;
+}
+
+void Map16ToMap8(const uint8 *src, int r20) {  // 82fd46
+  map16_load_src_off += 0x1000;
+  int n = 32;
+  int r14 = 0;
+  uint16 *r10 = &word_7F4000;
+  do {
+    OverworldCopyMap16ToBuffer(src, r20, r14, r10);
+    r14 += 0x100, r10 += 2;
+    map16_load_src_off -= 0x80;
+    map16_load_var2 = (map16_load_var2 - 1) & 0x1f;
+  } while (--n);
+}
+
+void OverworldCopyMap16ToBuffer(const uint8 *src, uint16 r20, int r14, uint16 *r10) {  // 82fd87
+  const uint16 *map8 = GetMap16toMap8Table();
+
+  int yr = map16_load_src_off - 0x410 & 0x1fff;
+  int xr = map16_load_dst_off;
+  uint16 *tmp = (uint16 *)(g_ram + 0x500);
+  int n = 32;
+  do {
+    WORD(tmp[xr]) = WORD(src[yr]);
+    xr = (xr + 1) & 0x1f;
+    yr = (yr + 2) & 0x1fff;
+  } while (--n);
+
+  uint16 r0 = 0, of = map16_load_var2;
+  if (of >= 0x10)
+    of &= 0xf, r0 = 0x800;
+  r0 += of * 64;
+
+  for (int i = 0; i < 2; i++, r0 += 0x400, r14 += 0x40) {
+    *r10++ = r0 | r20;
+    for (int j = 0; j < 16; j++, r14 += 4) {
+      const uint16 *m = map8 + 4 * *tmp++;
+      WORD(dung_bg2_attr_table[r14]) = WORD(m[0]);
+      WORD(dung_bg2_attr_table[r14 + 64]) = WORD(m[2]);
+      WORD(dung_bg2_attr_table[r14 + 2]) = WORD(m[1]);
+      WORD(dung_bg2_attr_table[r14 + 66]) = WORD(m[3]);
+    }
+  }
+
+}
+
+void MirrorBonk_RecoverChangedTiles() {  // 82fe47
+  for (int i = 0, i_end = num_memorized_tiles >> 1; i != i_end; i++) {
+    uint16 pos = memorized_tile_addr[i];
+    dung_bg2[pos >> 1] = memorized_tile_value[i];
+  }
+}
+
+void DecompressEnemyDamageSubclasses() {  // 82fe71
+  uint8 *tmp = &g_ram[0x14000];
+  memcpy(tmp, kEnemyDamageData, kEnemyDamageData_SIZE);
+  for (int i = 0; i < 0x1000; i += 2) {
+    uint8 t = *tmp++;
+    enemy_damage_data[i + 0] = t >> 4;
+    enemy_damage_data[i + 1] = t & 0xf;
+  }
+}
+
+int Decompress_bank02(uint8 *dst, const uint8 *src) {  // 82febb
+  uint8 *dst_org = dst;
+  int len;
+  for (;;) {
+    uint8 cmd = *src++;
+    if (cmd == 0xff)
+      return dst - dst_org;
+    if ((cmd & 0xe0) != 0xe0) {
+      len = (cmd & 0x1f) + 1;
+      cmd &= 0xe0;
+    } else {
+      len = *src++;
+      len += ((cmd & 3) << 8) + 1;
+      cmd = (cmd << 3) & 0xe0;
+    }
+    //printf("%d: %d,%d\n", (int)(dst - dst_org), cmd, len);
+    if (cmd == 0) {
+      do {
+        *dst++ = *src++;
+      } while (--len);
+    } else if (cmd & 0x80) {
+      uint32 offs = *src++ << 8;
+      offs |= *src++;
+      do {
+        *dst++ = dst_org[offs++];
+      } while (--len);
+    } else if (!(cmd & 0x40)) {
+      uint8 v = *src++;
+      do {
+        *dst++ = v;
+      } while (--len);
+    } else if (!(cmd & 0x20)) {
+      uint8 lo = *src++;
+      uint8 hi = *src++;
+      do {
+        *dst++ = lo;
+        if (--len == 0)
+          break;
+        *dst++ = hi;
+      } while (--len);
+    } else {
+      // copy bytes with the byte incrementing by 1 in between
+      uint8 v = *src++;
+      do {
+        *dst++ = v;
+      } while (v++, --len);
+    }
+  }
+}
+
+uint8 Overworld_ReadTileAttribute(uint16 x, uint16 y) {  // 85faa2
+  int t = ((x - overworld_offset_base_x) & overworld_offset_mask_x);
+  t |= ((y - overworld_offset_base_y) & overworld_offset_mask_y) << 3;
+  return kSomeTileAttr[dung_bg2[t >> 1]];
+}
+
+void Overworld_SetFixedColAndScroll() {  // 8bfe70
+  TS_copy = 0;
+  uint16 p = 0x19C6;
+  uint16 si = overworld_screen_index;
+  if (si == 0x80) {
+    if (dungeon_room_index == 0x181) {
+      TS_copy = 1;
+      p = si & 0x40 ? 0x2A32 : 0x2669;
+    }
+  } else if (si != 0x81) {
+    p = 0;
+    if (si != 0x5b && (si & 0xbf) != 3 && (si & 0xbf) != 5 && (si & 0xbf) != 7)
+      p = si & 0x40 ? 0x2A32 : 0x2669;
+  }
+  main_palette_buffer[0] = p;
+  aux_palette_buffer[0] = p;
+  main_palette_buffer[32] = p;
+  aux_palette_buffer[32] = p;
+
+  COLDATA_copy0 = 0x20;
+  COLDATA_copy1 = 0x40;
+  COLDATA_copy2 = 0x80;
+
+  uint32 cv;
+
+  if (si != 0 && si != 0x40 && si != 0x5b) {
+    if (si == 0x70)
+      goto getout;
+    cv = 0x8c4c26;
+    if (si != 3 && si != 5 && si != 7) {
+      cv = 0x874a26;
+      if (si != 0x43 && si != 0x45) {
+        flag_update_cgram_in_nmi += 1;
+        return;
+      }
+    }
+    COLDATA_copy0 = (uint8)(cv);
+    COLDATA_copy1 = (uint8)(cv >> 8);
+    COLDATA_copy2 = (uint8)(cv >> 16);
+  }
+
+  if (submodule_index != 4) {
+    BG1VOFS_copy2 = BG2VOFS_copy2;
+    BG1HOFS_copy2 = BG2HOFS_copy2;
+    if ((si & 0x3f) == 0x1b) {
+      int16 y = (int16)(BG2HOFS_copy2 - 0x778) >> 1;
+      BG1HOFS_copy2 = BG2HOFS_copy2 - y;
+      uint16 a = BG1VOFS_copy2;
+      if (a >= 0x6C0) {
+        a = (a - 0x600) & 0x3ff;
+        BG1VOFS_copy2 = (a < 0x180) ? (a >> 1) | 0x600 : 0x6c0;
+      } else {
+        BG1VOFS_copy2 = (a & 0xff) >> 1 | 0x600;
+      }
+    }
+  } else {
+    if ((si & 0x3f) == 0x1b) {
+      BG1HOFS_copy2 = (BYTE(overworld_screen_trans_dir_bits) != 8) ? 0x838 : BG2HOFS_copy2;
+      BG1VOFS_copy2 = 0x6c0;
+    }
+  }
+getout:
+  TS_copy = 1;
+  flag_update_cgram_in_nmi++;
+}
+
+void Overworld_Memorize_Map16_Change(uint16 pos, uint16 value) {  // 8edd40
+  if (value == 0xdc5 || value == 0xdc9)
+    return;
+
+  int x = num_memorized_tiles;
+  memorized_tile_value[x >> 1] = value;
+  memorized_tile_addr[x >> 1] = pos;
+  num_memorized_tiles = x + 2;
+}
+
+void HandlePegPuzzles(uint16 pos) {  // 8edd67
+  static const uint16 kLwTurtleRockPegPositions[3] = { 0x826, 0x5a0, 0x81a };
+
+  if (overworld_screen_index == 7) {
+    if (save_ow_event_info[7] & 0x20)
+      return;
+    if (word_7E04C8 != 0xffff && kLwTurtleRockPegPositions[word_7E04C8 >> 1] == pos) {
+      WORD(sound_effect_1) = 0x2d00;
+      word_7E04C8 += 2;
+      if (word_7E04C8 == 6) {
+        WORD(sound_effect_1) = 0x1b00;
+        save_ow_event_info[7] |= 0x20;
+        submodule_index = 47;
+      }
+    } else {
+      WORD(sound_effect_1) = 0x3c;
+      word_7E04C8 = 0xffff;
+    }
+  } else if (overworld_screen_index == 98) {
+    if (++word_7E04C8 == 22) {
+      save_ow_event_info[0x62] |= 0x20;
+      sound_effect_2 = 27;
+      door_open_closed_counter = 0x50;
+      big_rock_starting_address = 0xd20;
+      Overworld_DoMapUpdate32x32_B();
+    }
+  }
+  //assert(0);
+}
+
+void GanonTowerEntrance_Func1() {  // 8eddfc
+  if (!subsubmodule_index) {
+    sound_effect_1 = 0x2e;
+    Palette_AnimGetMasterSword2();
+  } else {
+    PaletteFilter_BlindingWhite();
+    if (darkening_or_lightening_screen == 255) {
+      palette_filter_countdown = 255;
+      subsubmodule_index++;
+    } else {
+      Palette_AnimGetMasterSword3();
+    }
+  }
+}
+
+void Overworld_CheckSpecialSwitchArea() {  // 8ede49
+  const uint16 *map8 = Overworld_GetMap16OfLink_Mult8();
+  int a = map8[0] & 0x1ff;
+  for (int i = 3; i >= 0; i--) {
+    if (kSpecialSwitchArea_Map8[i] == a && kSpecialSwitchArea_Screen[i] == overworld_screen_index) {
+      dungeon_room_index = kSpecialSwitchArea_Exit[i];
+      BYTE(overworld_screen_trans_dir_bits) = BYTE(overworld_screen_trans_dir_bits2) = link_direction = kSpecialSwitchArea_Direction[i];
+      WORD(byte_7E069C) = WORD(overworld_screen_transition) = DirToEnum(link_direction);
+      submodule_index = 23;
+      main_module_index = 11;
+      break;
+    }
+  }
+}
+
+const uint16 *Overworld_GetMap16OfLink_Mult8() {  // 8ede9a
+  const uint16 *map8 = GetMap16toMap8Table();
+  uint16 xc = (link_x_coord + 8) >> 3, yc = link_y_coord + 12;
+  uint16 pos = ((yc - overworld_offset_base_y) & overworld_offset_mask_y) * 8 +
+               ((xc - overworld_offset_base_x) & overworld_offset_mask_x);
+  return map8 + dung_bg2[pos >> 1] * 4;
+}
+
+void Palette_AnimGetMasterSword() {  // 8ef400
+  if (subsubmodule_index == 0) {
+    Palette_AnimGetMasterSword2();
+  } else {
+    PaletteFilter_BlindingWhite();
+    if (darkening_or_lightening_screen == 0xff) {
+      for (int i = 0; i < 8; i++)
+        main_palette_buffer[0x58 + i] = aux_palette_buffer[0x58 + i] = 0;
+      palette_filter_countdown = 0;
+      darkening_or_lightening_screen = 0;
+      submodule_index = 0;
+    } else {
+      Palette_AnimGetMasterSword3();
+    }
+  }
+}
+
+void Palette_AnimGetMasterSword2() {  // 8ef404
+  memcpy(mapbak_palette, aux_palette_buffer, 512);
+  for (int i = 0; i < 256; i++)
+    aux_palette_buffer[i] = 0x7fff;
+  main_palette_buffer[32] = main_palette_buffer[0];
+  palette_filter_countdown = 0;
+  darkening_or_lightening_screen = 2;
+  subsubmodule_index++;
+}
+
+void Palette_AnimGetMasterSword3() {  // 8ef48c
+  if (darkening_or_lightening_screen != 0 || palette_filter_countdown != 31)
+    return;
+  memcpy(aux_palette_buffer, mapbak_palette, 512);
+  TS_copy = 0;
+}
+
+void Overworld_DwDeathMountainPaletteAnimation() {  // 8ef582
+  if (trigger_special_entrance)
+    return;
+  uint8 sc = overworld_screen_index;
+  if (sc != 0x43 && sc != 0x45 && sc != 0x47)
+    return;
+  uint8 fc = frame_counter;
+  if (fc == 5 || fc == 44 || fc == 90) {
+    for (int i = 1; i < 8; i++) {
+      main_palette_buffer[0x30 + i] = aux_palette_buffer[0x30 + i];
+      main_palette_buffer[0x38 + i] = aux_palette_buffer[0x38 + i];
+      main_palette_buffer[0x48 + i] = aux_palette_buffer[0x48 + i];
+      main_palette_buffer[0x70 + i] = aux_palette_buffer[0x70 + i];
+      main_palette_buffer[0x78 + i] = aux_palette_buffer[0x78 + i];
+    }
+  } else if (fc == 3 || fc == 36 || fc == 88) {
+    if (fc == 36)
+      sound_effect_1 = 54;
+    for (int i = 1; i < 8; i++) {
+      main_palette_buffer[0x30 + i] = kDwPaletteAnim[i - 1 + 0];
+      main_palette_buffer[0x38 + i] = kDwPaletteAnim[i - 1 + 7];
+      main_palette_buffer[0x48 + i] = kDwPaletteAnim[i - 1 + 14];
+      main_palette_buffer[0x70 + i] = kDwPaletteAnim[i - 1 + 21];
+      main_palette_buffer[0x78 + i] = kDwPaletteAnim[i - 1 + 28];
+    }
+  }
+  flag_update_cgram_in_nmi++;
+  int yy = 32;
+  if (sc == 0x43 || sc == 0x45) {
+    if (save_ow_event_info[0x43] & 0x20)
+      return;
+    yy = (frame_counter & 0xc) * 2;
+  }
+  for (int i = 0; i < 8; i++)
+    main_palette_buffer[0x68 + i] = kDwPaletteAnim2[yy + i];
+}
+
+void Overworld_LoadEventOverlay() {  // 8ef652
+  int x;
+  uint16 *dst = dung_bg2;
+  switch (overworld_screen_index) {
+  case 0: case 1: case 2:
+    dst[XY(11, 16)] = 0xe32;
+    dst[XY(12, 16)] = 0xe32;
+    dst[XY(13, 16)] = 0xe32;
+    dst[XY(14, 16)] = 0xe32;
+    dst[XY(11, 17)] = 0xe32;
+    dst[XY(14, 17)] = 0xe32;
+    dst[XY(12, 17)] = 0xe33;
+    dst[XY(13, 17)] = 0xe34;
+    dst[XY(11, 18)] = 0xe35;
+    dst[XY(12, 18)] = 0xe36;
+    dst[XY(13, 18)] = 0xe37;
+    dst[XY(14, 18)] = 0xe38;
+    dst[XY(11, 19)] = 0xe39;
+    dst[XY(12, 19)] = 0xe3a;
+    dst[XY(13, 19)] = 0xe3b;
+    dst[XY(14, 19)] = 0xe3c;
+    dst[XY(12, 20)] = 0xe3d;
+    dst[XY(13, 20)] = 0xe3e;
+    break;
+  case 3: case 4: case 5: case 6: case 7:
+    dst[XY(16, 14)] = 0x212;
+    break;
+  case 8: case 9: case 10: case 11: case 12: case 13: case 14: case 15: case 16: case 17: case 18: case 19:
+    x = XY(3, 10);
+loc_8EF7B4:
+    dst[x + XY(0, 0)] = 0x918;
+    dst[x + XY(1, 0)] = 0x919;
+    dst[x + XY(0, 1)] = 0x91a;
+    dst[x + XY(1, 1)] = 0x91b;
+    break;
+  case 20:
+    dst[XY(25, 10)] = 0xdd1;
+    dst[XY(26, 10)] = 0xdd2;
+    dst[XY(25, 11)] = 0xdd7;
+    dst[XY(26, 11)] = 0xdd8;
+    dst[XY(25, 12)] = 0xdd9;
+    dst[XY(26, 12)] = 0xdda;
+    break;
+  case 21: case 22: case 23: case 24: case 25: case 32: case 33:
+    dst[XY(31, 24)] = 0xe21;
+    dst[XY(33, 24)] = 0xe21;
+    dst[XY(32, 24)] = 0xe22;
+    dst[XY(31, 25)] = 0xe23;
+    dst[XY(32, 25)] = 0xe24;
+    dst[XY(33, 25)] = 0xe25;
+    break;
+  case 26: case 27: case 28: case 35: case 36:
+    dst[XY(30, 39)] = 0xdc1;
+    dst[XY(31, 39)] = 0xdc2;
+    dst[XY(30, 40)] = 0xdbe;
+    dst[XY(31, 40)] = 0xdbf;
+    dst[XY(32, 39)] = 0xdc2;
+    dst[XY(33, 39)] = 0xdc3;
+    dst[XY(32, 40)] = 0xdbf;
+    dst[XY(33, 40)] = 0xdc0;
+    break;
+  case 29: case 30: case 31: case 34: case 37: case 38: case 39: case 40: case 41: case 42: case 43: case 107:
+    x = XY(24, 6);
+    goto loc_8EF7B4;
+  case 44: case 45: case 46: case 47: case 48: case 49: case 56: case 57:
+    x = XY(44, 6);
+    goto loc_8EF7B4;
+  case 50: case 51: case 52: case 53: case 54: case 55: case 119:
+    x = XY(6, 8);
+    goto loc_8EF7B4;
+  case 58:
+    x = XY(15, 20);
+    goto loc_8EF7B4;
+  case 59: case 123:
+    dst[XY(22, 7)] = 0xddf;
+    dst[XY(18, 8)] = 0xddf;
+    dst[XY(16, 9)] = 0xddf;
+    dst[XY(15, 10)] = 0xddf;
+    dst[XY(14, 12)] = 0xddf;
+    dst[XY(26, 14)] = 0xddf;
+    dst[XY(23, 7)] = 0xde0;
+    dst[XY(17, 9)] = 0xde0;
+    dst[XY(24, 7)] = 0xde1;
+    dst[XY(28, 8)] = 0xde1;
+    dst[XY(29, 9)] = 0xde1;
+    dst[XY(21, 11)] = 0xde1;
+    dst[XY(29, 14)] = 0xde1;
+    dst[XY(19, 8)] = 0xde2;
+    dst[XY(20, 8)] = 0xde2;
+    dst[XY(21, 8)] = 0xde2;
+    dst[XY(25, 8)] = 0xde2;
+    dst[XY(26, 8)] = 0xde2;
+    dst[XY(27, 8)] = 0xde2;
+    dst[XY(22, 8)] = 0xde3;
+    dst[XY(18, 9)] = 0xde3;
+    dst[XY(16, 10)] = 0xde3;
+    dst[XY(15, 12)] = 0xde3;
+    dst[XY(23, 8)] = 0xde4;
+    dst[XY(19, 9)] = 0xde4;
+    dst[XY(20, 9)] = 0xde4;
+    dst[XY(24, 9)] = 0xde4;
+    dst[XY(27, 9)] = 0xde4;
+    dst[XY(17, 10)] = 0xde4;
+    dst[XY(18, 10)] = 0xde4;
+    dst[XY(19, 10)] = 0xde4;
+    dst[XY(28, 10)] = 0xde4;
+    dst[XY(16, 11)] = 0xde4;
+    dst[XY(17, 11)] = 0xde4;
+    dst[XY(18, 11)] = 0xde4;
+    dst[XY(19, 11)] = 0xde4;
+    dst[XY(16, 12)] = 0xde4;
+    dst[XY(17, 12)] = 0xde4;
+    dst[XY(15, 13)] = 0xde4;
+    dst[XY(16, 13)] = 0xde4;
+    dst[XY(15, 14)] = 0xde4;
+    dst[XY(16, 14)] = 0xde4;
+    dst[XY(19, 16)] = 0xde4;
+    dst[XY(19, 17)] = 0xde4;
+    dst[XY(20, 17)] = 0xde4;
+    dst[XY(19, 18)] = 0xde4;
+    dst[XY(24, 8)] = 0xde5;
+    dst[XY(28, 9)] = 0xde5;
+    dst[XY(20, 11)] = 0xde5;
+    dst[XY(21, 12)] = 0xde5;
+    dst[XY(21, 9)] = 0xde6;
+    dst[XY(25, 9)] = 0xde6;
+    dst[XY(20, 10)] = 0xde6;
+    dst[XY(28, 11)] = 0xde6;
+    dst[XY(21, 17)] = 0xde6;
+    dst[XY(20, 18)] = 0xde6;
+    dst[XY(22, 9)] = 0xde7;
+    dst[XY(24, 10)] = 0xde7;
+    dst[XY(15, 15)] = 0xde7;
+    dst[XY(16, 15)] = 0xde7;
+    dst[XY(19, 19)] = 0xde7;
+    dst[XY(28, 19)] = 0xde7;
+    dst[XY(23, 9)] = 0xde8;
+    dst[XY(26, 9)] = 0xde8;
+    dst[XY(27, 10)] = 0xde8;
+    dst[XY(17, 15)] = 0xde8;
+    dst[XY(18, 16)] = 0xde8;
+    dst[XY(23, 10)] = 0xde9;
+    dst[XY(26, 10)] = 0xde9;
+    dst[XY(14, 15)] = 0xde9;
+    dst[XY(17, 16)] = 0xde9;
+    dst[XY(26, 18)] = 0xde9;
+    dst[XY(27, 19)] = 0xde9;
+    dst[XY(29, 10)] = 0xdea;
+    dst[XY(28, 12)] = 0xdea;
+    dst[XY(28, 13)] = 0xdea;
+    dst[XY(29, 18)] = 0xdea;
+    dst[XY(15, 11)] = 0xdeb;
+    dst[XY(27, 11)] = 0xdeb;
+    dst[XY(27, 12)] = 0xdeb;
+    dst[XY(14, 13)] = 0xdeb;
+    dst[XY(27, 13)] = 0xdeb;
+    dst[XY(14, 14)] = 0xdeb;
+    dst[XY(18, 17)] = 0xdeb;
+    dst[XY(18, 18)] = 0xdeb;
+    dst[XY(18, 12)] = 0xdec;
+    dst[XY(17, 13)] = 0xdec;
+    dst[XY(19, 12)] = 0xded;
+    dst[XY(20, 12)] = 0xdee;
+    dst[XY(18, 13)] = 0xdef;
+    dst[XY(27, 15)] = 0xdef;
+    dst[XY(19, 13)] = 0xdf0;
+    dst[XY(19, 14)] = 0xdf0;
+    dst[XY(20, 14)] = 0xdf0;
+    dst[XY(21, 14)] = 0xdf0;
+    dst[XY(21, 15)] = 0xdf0;
+    dst[XY(27, 16)] = 0xdf0;
+    dst[XY(28, 16)] = 0xdf0;
+    dst[XY(20, 13)] = 0xdf1;
+    dst[XY(28, 15)] = 0xdf1;
+    dst[XY(21, 13)] = 0xdf2;
+    dst[XY(17, 14)] = 0xdf3;
+    dst[XY(18, 15)] = 0xdf3;
+    dst[XY(20, 16)] = 0xdf3;
+    dst[XY(18, 14)] = 0xdf4;
+    dst[XY(19, 15)] = 0xdf5;
+    dst[XY(20, 15)] = 0xdf6;
+    dst[XY(27, 17)] = 0xdf6;
+    dst[XY(26, 15)] = 0xdf7;
+    dst[XY(29, 15)] = 0xdf8;
+    dst[XY(21, 16)] = 0xdf9;
+    dst[XY(26, 16)] = 0xdfa;
+    dst[XY(29, 16)] = 0xdfb;
+    dst[XY(26, 17)] = 0xdfc;
+    dst[XY(28, 17)] = 0xdfd;
+    dst[XY(29, 17)] = 0xdfe;
+    dst[XY(27, 18)] = 0xdff;
+    dst[XY(28, 18)] = 0xe00;
+    dst[XY(21, 10)] = 0xe01;
+    dst[XY(25, 10)] = 0xe01;
+    dst[XY(21, 18)] = 0xe01;
+    dst[XY(29, 11)] = 0xe02;
+    dst[XY(20, 19)] = 0xe02;
+    dst[XY(29, 19)] = 0xe02;
+    dst[XY(18, 19)] = 0xe03;
+    dst[XY(27, 14)] = 0xe04;
+    dst[XY(28, 14)] = 0xe05;
+    break;
+  case 60: case 61: case 62: case 63: case 64: case 65: case 72: case 73:
+    dst[XY(8, 11)] = 0xe13;
+    dst[XY(11, 11)] = 0xe14;
+    dst[XY(8, 12)] = 0xe15;
+    dst[XY(9, 12)] = 0xe16;
+    dst[XY(10, 12)] = 0xe17;
+    dst[XY(11, 12)] = 0xe18;
+    dst[XY(9, 13)] = 0xe19;
+    dst[XY(10, 13)] = 0xe1a;
+    dst[XY(9, 16)] = 0xe06;
+    dst[XY(10, 16)] = 0xe06;
+    dst[XY(8, 14)] = 0xe07;
+    dst[XY(8, 15)] = 0xe07;
+    dst[XY(9, 14)] = 0xe08;
+    dst[XY(9, 15)] = 0xe08;
+    dst[XY(10, 14)] = 0xe09;
+    dst[XY(10, 15)] = 0xe09;
+    dst[XY(11, 14)] = 0xe0a;
+    dst[XY(11, 15)] = 0xe0a;
+    break;
+  case 66: case 67: case 68: case 75: case 76:
+    dst[XY(47, 8)] = 0xe96;
+    dst[XY(48, 8)] = 0xe97;
+    dst[XY(47, 9)] = 0xe9c;
+    dst[XY(47, 10)] = 0xe9c;
+    dst[XY(48, 9)] = 0xe9d;
+    dst[XY(48, 10)] = 0xe9d;
+    dst[XY(47, 11)] = 0xe9a;
+    dst[XY(48, 11)] = 0xe9b;
+    break;
+  case 69: case 70: case 77: case 78:
+    x = XY(52, 16);
+    goto loc_8EF7B4;
+  case 71:
+    dst[XY(15, 19)] = 0xe78;
+    dst[XY(16, 19)] = 0xe79;
+    dst[XY(17, 19)] = 0xe7a;
+    dst[XY(18, 19)] = 0xe7b;
+    dst[XY(15, 20)] = 0xe7c;
+    dst[XY(16, 20)] = 0xe7d;
+    dst[XY(17, 20)] = 0xe7e;
+    dst[XY(18, 20)] = 0xe7f;
+    dst[XY(15, 21)] = 0xe80;
+    dst[XY(16, 21)] = 0xe81;
+    dst[XY(17, 21)] = 0xe82;
+    dst[XY(18, 21)] = 0xe83;
+    dst[XY(15, 22)] = 0xe84;
+    dst[XY(16, 22)] = 0xe85;
+    dst[XY(17, 22)] = 0xe86;
+    dst[XY(18, 22)] = 0xe87;
+    break;
+  case 74: case 79: case 80: case 81: case 82: case 83: case 84: case 85: case 86: case 87: case 88: case 89: case 96: case 97:
+    dst[XY(31, 26)] = 0xe1b;
+    dst[XY(32, 26)] = 0xe1c;
+    dst[XY(31, 27)] = 0xe1d;
+    dst[XY(32, 27)] = 0xe1e;
+    dst[XY(31, 28)] = 0xe1f;
+    dst[XY(32, 28)] = 0xe20;
+    break;
+  case 90: case 91: case 92: case 99: case 100:
+    dst[XY(30, 7)] = 0xe3f;
+    dst[XY(31, 7)] = 0xe40;
+    dst[XY(32, 7)] = 0xe41;
+    dst[XY(30, 8)] = 0xe42;
+    dst[XY(31, 8)] = 0xe43;
+    dst[XY(32, 8)] = 0xe44;
+    dst[XY(30, 9)] = 0xe45;
+    dst[XY(31, 9)] = 0xe46;
+    dst[XY(32, 9)] = 0xe47;
+    break;
+  case 93: case 94: case 95: case 102: case 103:
+    dst[XY(51, 3)] = 0xe31;
+    dst[XY(53, 4)] = 0xe2d;
+    dst[XY(53, 5)] = 0xe2e;
+    dst[XY(53, 6)] = 0xe2f;
+    break;
+  case 98:
+    x = XY(16, 26);
+    goto loc_8EF7B4;
+  case 101: case 104: case 105: case 106: case 108: case 109: case 110: case 111: case 112: case 113: case 120: case 121:
+    dst[XY(17, 10)] = 0xe64;
+    dst[XY(18, 10)] = 0xe65;
+    dst[XY(19, 10)] = 0xe66;
+    dst[XY(20, 10)] = 0xe67;
+    dst[XY(17, 11)] = 0xe68;
+    dst[XY(18, 11)] = 0xe69;
+    dst[XY(19, 11)] = 0xe6a;
+    dst[XY(20, 11)] = 0xe6b;
+    dst[XY(17, 12)] = 0xe6c;
+    dst[XY(18, 12)] = 0xe6d;
+    dst[XY(19, 12)] = 0xe6e;
+    dst[XY(20, 12)] = 0xe6f;
+    dst[XY(17, 13)] = 0xe70;
+    dst[XY(18, 13)] = 0xe71;
+    dst[XY(19, 13)] = 0xe72;
+    dst[XY(20, 13)] = 0xe73;
+    dst[XY(17, 14)] = 0xe74;
+    dst[XY(18, 14)] = 0xe75;
+    dst[XY(19, 14)] = 0xe76;
+    dst[XY(20, 14)] = 0xe77;
+    break;
+  case 114: case 115: case 116: case 117: case 118: case 122: case 124: case 125: case 126: case 127:
+    assert(0);
+  }
+}
+
+void Ancilla_TerminateWaterfallSplashes() {  // 8ffd3c
+  uint8 t = BYTE(overworld_screen_index);
+  if (t == 0xf) {
+    for (int i = 4; i >= 0; i--) {
+      if (ancilla_type[i] == 0x41)
+        ancilla_type[i] = 0;
+    }
+  }
+}
+
+void Overworld_GetPitDestination() {  // 9bb860
+  uint16 x = (link_x_coord & ~7);
+  uint16 y = (link_y_coord & ~7);
+  uint16 pos = ((y - overworld_offset_base_y) & overworld_offset_mask_y) << 3;
+  pos += (((x >> 3) - overworld_offset_base_x) & overworld_offset_mask_x);
+
+
+  int i = 36 / 2;
+  for (;;) {
+    if (kFallHole_Pos[i] == pos && kFallHole_Area[i] == overworld_area_index)
+      break;
+    if (--i < 0) {
+      savegame_is_darkworld = 0;
+      // Chris Houlihan's room
+      which_entrance = 130;
+      byte_7E010F = 0;
+      return;
+    }
+  }
+  which_entrance = kFallHole_Entrances[i];
+  byte_7E010F = 0;
+}
+
+void Overworld_UseEntrance() {  // 9bbbf4
+  uint16 xc = link_x_coord >> 3, yc = link_y_coord + 7;
+  uint16 pos = ((yc - overworld_offset_base_y) & overworld_offset_mask_y) * 8 +
+    ((xc - overworld_offset_base_x) & overworld_offset_mask_x);
+
+  int x = dung_bg2[pos >> 1] * 4;
+  const uint16 *map8p = GetMap16toMap8Table();
+
+  if (!link_direction_facing) {
+    uint16 a = map8p[x + 1] & 0x41ff;
+    if (a == 0xe9)
+      goto do_draw;
+
+    if (a == 0x149 || a == 0x169)
+      goto is_149_or_169;
+
+    x = dung_bg2[(pos >> 1) + 1] * 4;
+    a = map8p[x] & 0x41ff;
+    if (a == 0x40e9) {
+      pos -= 2;
+do_draw:
+      Overworld_DrawMap16_Persist(pos + 0, 0xDA4);
+      Overworld_DrawMap16_Persist(pos + 2, 0xDA6);
+      sound_effect_2 = 21;
+      nmi_load_bg_from_vram = 1;
+      return;
+    }
+    if (a == 0x4149 || a == 0x4169) {
+      pos -= 2;
+is_149_or_169:
+      door_open_closed_counter = 0;
+      if (a & 0x20) {
+        // 0x169
+        if ((sram_progress_indicator & 0xf) >= 3)
+          goto after;
+        door_open_closed_counter = 24;
+      }
+      big_rock_starting_address = pos - 0x80;
+      sound_effect_2 = 21;
+      subsubmodule_index = 0;
+      BYTE(door_animation_step_indicator) = 0;
+      submodule_index = 12;
+      return;
+    }
+  }
+after:
+  if (!LookupInOwEntranceTab(map8p[x + 2] & 0x1ff, map8p[x + 3] & 0x1ff)) {
+    big_key_door_message_triggered = 0;
+    return;
+  }
+
+  int lx = LookupInOwEntranceTab2(pos);
+  if (lx < 0)
+    return;
+
+  if (!follower_dropped && (link_pose_for_item == 1 || !CanEnterWithTagalong(kOverworld_Entrance_Id[lx] - 1))) {
+    if (!big_key_door_message_triggered) {
+      big_key_door_message_triggered = 1;
+      dialogue_message_index = 5;
+      Main_ShowTextMessage();
+    }
+  } else {
+    which_entrance = kOverworld_Entrance_Id[lx];
+    link_auxiliary_state = 0;
+    link_incapacitated_timer = 0;
+    main_module_index = 15;
+    saved_module_for_menu = 6;
+    submodule_index = 0;
+    subsubmodule_index = 0;
+  }
+}
+
+uint16 Overworld_ToolAndTileInteraction(uint16 x, uint16 y) {  // 9bbd82
+  word_7E04B2 = 0;
+  index_of_interacting_tile = 0;
+  uint16 pos = ((y - overworld_offset_base_y) & overworld_offset_mask_y) * 8 +
+    ((x - overworld_offset_base_x) & overworld_offset_mask_x);
+  uint16 attr = overworld_tileattr[pos >> 1], yv;
+
+  if (!(link_item_in_hand & 2)) {
+    if (!(link_item_in_hand & 0x40)) {
+      if (attr == 0x34 || attr == 0x71 || attr == 0x35 || attr == 0x10d ||
+          attr == 0x10f || attr == 0xe1 || attr == 0xe2 || attr == 0xda ||
+          attr == 0xf8 || attr == 0x10e) {  // shovelable
+        if (link_position_mode != 1)
+          return attr;
+        if (overworld_screen_index == 0x2a && pos == 0x492)
+          word_7E04B2 = pos;
+        yv = 0xdc9;
+        goto check_secret;
+      } else if (attr == 0x37e) {  // isThickGrass
+        if (link_position_mode == 1)
+          return attr;
+        scratch_0 = x * 8 - 8;
+        scratch_1 = (y - 8) & ~7;
+        index_of_interacting_tile = 3;
+        yv = 0xdc5;
+        goto check_secret;
+      }
+    }
+    if ((yv = 2, attr == 0x36) || (yv = 4, attr == 0x72a)) {
+      // is_bush
+      if (link_position_mode != 1) {
+        scratch_0 = (x & ~1) * 8;
+        scratch_1 = y & ~0xf;
+        index_of_interacting_tile = yv;
+        yv = (attr == 0x72a) ? 0xdc8 : 0xdc7;
+        uint32 result;
+check_secret:
+        result = Overworld_RevealSecret(pos);
+        if (result != 0)
+          yv = result;
+memoize_getout:
+        overworld_tileattr[pos >> 1] = yv;
+        Overworld_Memorize_Map16_Change(pos, yv);
+        Overworld_DrawMap16(pos, yv);
+        nmi_load_bg_from_vram = 1;
+      }
+      uint16 t;
+      t = GetMap16toMap8Table()[attr * 4 + ((y & 8) >> 2) + (x & 1)];
+      attr = kMap8DataToTileAttr[t & 0x1ff];
+      if (index_of_interacting_tile) {
+        Sprite_SpawnImmediatelySmashedTerrain(index_of_interacting_tile, scratch_0, scratch_1);
+        AncillaAdd_BushPoof(scratch_0, scratch_1);
+      }
+      return attr;
+    }
+    return attr;
+  } else {  // else_1
+    if (attr == 0x21b) {
+      sound_effect_1 = 17;
+      HandlePegPuzzles(pos);
+      yv = 0xdcb;
+      goto memoize_getout;
+    } else { // else_3
+      Overworld_PickHammerSfx(attr);
+      return attr;
+    }
+  }
+
+  return 0;
+}
+
+void Overworld_PickHammerSfx(uint16 a) {  // 9bbf1e
+  uint16 attr = kMap8DataToTileAttr[GetMap16toMap8Table()[a * 4] & 0x1ff];
+  uint8 y;
+  if (attr < 0x50) {
+    return;
+  } else if (attr < 0x52) {
+    y = 26;
+  } else if (attr < 0x54) {
+    y = 17;
+  } else if (attr < 0x58) {
+    y = 5;
+  } else {
+    return;
+  }
+  sound_effect_1 = y;
+}
+
+uint16 Overworld_GetLinkMap16Coords(Point16U *xy) {  // 9bbf64
+  uint16 x = (link_x_coord + kGetBestActionToPerformOnTile_x[link_direction_facing >> 1]) & ~0xf;
+  uint16 y = (link_y_coord + kGetBestActionToPerformOnTile_y[link_direction_facing >> 1]) & ~0xf;
+  xy->x = x;
+  xy->y = y;
+  uint16 rv = ((y - overworld_offset_base_y) & overworld_offset_mask_y) << 3;
+  return rv + (((x >> 3) - overworld_offset_base_x) & overworld_offset_mask_x);
+}
+
+uint8 Overworld_HandleLiftableTiles(Point16U *pt_arg) {  // 9bbf9d
+  uint16 pos = Overworld_GetLinkMap16Coords(pt_arg);
+  Point16U pt = *pt_arg;
+  uint16 a = overworld_tileattr[pos >> 1], y;
+  if ((y = 0, a == 0x36d) || (y = 1, a == 0x36e) || (y = 2, a == 0x374) || (y = 3, a == 0x375) ||
+      (y = 0, a == 0x23b) || (y = 1, a == 0x23c) || (y = 2, a == 0x23d) || (y = 3, a == 0x23e)) {
+    return SmashRockPile_fromLift(a, pos, y, pt);
+  } else if ((y = 0xdc7, a == 0x36) || (y = 0xdc8, a == 0x72a) || (y = 0xdca, a == 0x20f) || (y = 0xdca, a == 0x239) || (y = 0xdc6, a == 0x101)) {
+    return Overworld_LiftingSmallObj(a, pos, y, pt);
+  } else {
+    uint16 t = a * 4 + (pt.x & 8 ? 2 : 0) + (pt.y & 8 ? 1 : 0);
+    return kMap8DataToTileAttr[GetMap16toMap8Table()[t] & 0x1ff];
+  }
+}
+
+uint8 Overworld_LiftingSmallObj(uint16 a, uint16 pos, uint16 y, Point16U pt) {  // 9bc008
+  uint16 secret = Overworld_RevealSecret(pos);
+  if (secret != 0)
+    y = secret;
+  overworld_tileattr[pos >> 1] = y;
+  Overworld_Memorize_Map16_Change(pos, y);
+  Overworld_DrawMap16(pos, y);
+  nmi_load_bg_from_vram = 1;
+  uint16 t = a * 4 + (pt.x & 8 ? 2 : 0) + (pt.y & 8 ? 1 : 0);
+  return kMap8DataToTileAttr[GetMap16toMap8Table()[t] & 0x1ff];
+}
+
+int Overworld_SmashRockPile(bool down_one_tile, Point16U *pt) {  // 9bc055
+  uint16 bak = link_y_coord;
+  link_y_coord += down_one_tile ? 8 : 0;
+  uint16 pos = Overworld_GetLinkMap16Coords(pt);
+  link_y_coord = bak;
+  uint16 a = dung_bg2[pos >> 1];
+  uint8 y = 0;
+  if ((y = 0, a == 0x226) || (y = 1, a == 0x227) || (y = 2, a == 0x228) || (y = 3, a == 0x229)) {
+    return SmashRockPile_fromLift(a, pos, y, *pt);
+  } else if (a == 0x36) {
+    return Overworld_LiftingSmallObj(a, pos, 0xDC7, *pt);
+  } else {
+    return -1;
+  }
+}
+
+uint8 SmashRockPile_fromLift(uint16 a, uint16 pos, uint16 y, Point16U pt) {  // 9bc09f
+  static const int8 kBigRockTab1[] = { 0, -1, -64, -65 };
+  static const int8 kBigRockTabY[] = { 0, 0, -64, -64 };
+  static const int8 kBigRockTabX[] = { 0, -1, 0, -1 };
+  pos = 2 * ((pos >> 1) + kBigRockTab1[y]);
+  big_rock_starting_address = pos;
+  door_open_closed_counter = 40;
+
+  *(uint16 *)&g_ram[0] = pt.y;
+  *(uint16 *)&g_ram[2] = pt.x;
+
+  uint16 secret = Overworld_RevealSecret(pos);
+  pt.y = *(uint16 *)&g_ram[0];
+  pt.x = *(uint16 *)&g_ram[2];
+
+  if (secret == 0xffff) {
+    save_ow_event_info[overworld_screen_index] |= 0x20;
+    sound_effect_2 = 27;
+    door_open_closed_counter = 80;
+  }
+  pt.x += kBigRockTabX[y] * 2;
+  pt.y += kBigRockTabY[y] * 2;
+
+  Overworld_DoMapUpdate32x32_B(); // WARNING: The original destroys ram[0] and ram[2]
+
+  uint16 t = a * 4 + (pt.x & 8 ? 2 : 0) + (pt.y & 8 ? 1 : 0);
+  return kMap8DataToTileAttr[GetMap16toMap8Table()[t] & 0x1ff];
+}
+
+void Overworld_BombTiles32x32(uint16 x, uint16 y) {  // 9bc0f8
+  x = (x - 23) & ~7;
+  y = (y - 20) & ~7;
+
+  for (int yy = 3; yy != 0; yy--, y += 16) {
+    for (int xx = 3, xt = x; xx != 0; xx--, xt += 16) {
+      Overworld_BombTile(xt, y);
+    }
+  }
+  word_7E0486 = x, word_7E0488 = y;
+}
+
+void Overworld_BombTile(int x, int y) {  // 9bc155
+  int a, j, k;
+
+  int pos = ((y - overworld_offset_base_y & overworld_offset_mask_y) << 3) +
+    ((x >> 3) - overworld_offset_base_x & overworld_offset_mask_x);
+
+  if (follower_indicator == 13)
+    goto label_a;
+
+  a = dung_bg2[pos >> 1];
+
+  if (a == 0x36) {
+    k = 2, j = 0xdc7;
+  } else if (a == 0x72a) {
+    k = 4, j = 0xdc8;
+  } else if (a == 0x37e) {
+    k = 3, j = 0xdc5;
+  } else {
+    goto label_a;
+  }
+  a = Overworld_RevealSecret(pos);
+  if (a == 0)
+    a = j;
+  dung_bg2[pos >> 1] = a;
+  Overworld_Memorize_Map16_Change(pos, a);
+  Overworld_DrawMap16(pos, a);
+
+  Sprite_SpawnImmediatelySmashedTerrain(k, x & ~7, y & ~7);
+  nmi_load_bg_from_vram = 1;
+  return;
+
+label_a:
+  a = Overworld_RevealSecret(pos);
+  if (a == 0xdb4) {
+    dung_bg2[pos >> 1] = a;
+    Overworld_Memorize_Map16_Change(pos, a);
+    Overworld_DrawMap16(pos, a);
+
+    dung_bg2[(pos >> 1) + 1] = 0xDB5;
+    Overworld_Memorize_Map16_Change(pos, 0xDB5);  // wtf
+    Overworld_DrawMap16(pos + 2, 0xDB5);
+    nmi_load_bg_from_vram = 1;
+    save_ow_event_info[overworld_screen_index] |= 2;
+  }
+}
+
+void Overworld_AlterWeathervane() {  // 9bc21d
+  door_open_closed_counter = 0x68;
+  big_rock_starting_address = 0xc3e;
+  Overworld_DoMapUpdate32x32_B();
+  Overworld_DrawMap16_Persist(0xc42, 0xe21);
+  Overworld_DrawMap16_Persist(0xcc2, 0xe25);
+
+  save_ow_event_info[0x18] |= 0x20;
+  nmi_load_bg_from_vram = 1;
+}
+
+void OpenGargoylesDomain() {  // 9bc264
+  Overworld_DrawMap16_Persist(0xd3e, 0xe1b);
+  Overworld_DrawMap16_Persist(0xd40, 0xe1c);
+  Overworld_DrawMap16_Persist(0xdbe, 0xe1d);
+  Overworld_DrawMap16_Persist(0xdc0, 0xe1e);
+  Overworld_DrawMap16_Persist(0xe3e, 0xe1f);
+  Overworld_DrawMap16_Persist(0xe40, 0xe20);
+  save_ow_event_info[0x58] |= 0x20;
+  sound_effect_2 = 0x1b;
+  nmi_load_bg_from_vram = 1;
+}
+
+void CreatePyramidHole() {  // 9bc2a7
+  Overworld_DrawMap16_Persist(0x3bc, 0xe3f);
+  Overworld_DrawMap16_Persist(0x3be, 0xe40);
+  Overworld_DrawMap16_Persist(0x3c0, 0xe41);
+  Overworld_DrawMap16_Persist(0x43c, 0xe42);
+  Overworld_DrawMap16_Persist(0x43e, 0xe43);
+  Overworld_DrawMap16_Persist(0x440, 0xe44);
+  Overworld_DrawMap16_Persist(0x4bc, 0xe45);
+  Overworld_DrawMap16_Persist(0x4be, 0xe46);
+  Overworld_DrawMap16_Persist(0x4c0, 0xe47);
+  WORD(sound_effect_ambient) = 0x3515;
+  save_ow_event_info[0x5b] |= 0x20;
+  sound_effect_2 = 3;
+  nmi_load_bg_from_vram = 1;
+}
+
+// Strange return value in Carry/R14
+uint16 Overworld_RevealSecret(uint16 pos) {  // 9bc8a4
+  BYTE(dung_secrets_unk1) = 0;
+
+  if (overworld_screen_index >= 0x80) {
+fail:
+    AdjustSecretForPowder();
+    return 0;
+  }
+
+  const uint8 *ptr = kOverworldSecrets + kOverworldSecrets_Offs[overworld_screen_index];
+  for (;;) {
+    uint16 x = *(uint16 *)ptr;
+    if (x == 0xffff)
+      goto fail;
+    if ((x & 0x7fff) == pos)
+      break;
+    ptr += 3;
+  }
+  uint8 data = ptr[2];
+  if (data && data < 0x80)
+    BYTE(dung_secrets_unk1) |= data;
+  if (data < 0x80) {
+    AdjustSecretForPowder();
+    return 0; // carry set
+  }
+
+  BYTE(dung_secrets_unk1) = 0xff;
+  if (data != 0x84 && !(save_ow_event_info[overworld_screen_index] & 2)) {
+    if (overworld_screen_index == 0x5b && follower_indicator != 13)
+      goto fail;
+    sound_effect_2 = 0x1b;
+  // The discovery chime is missing when lifting the rock covering the magic portal leading to the Ice Temple
+  } else if (data == 0x82 && (enhanced_features0 & kFeatures0_MiscBugFixes)) {
+    sound_effect_2 = 0x1b;
+  }
+  static const uint16 kTileBelow[4] = { 0xDCC, 0x212, 0xFFFF, 0xDB4 };
+  AdjustSecretForPowder();
+  return kTileBelow[(data & 0xf) >> 1];
+
+}
+
+void AdjustSecretForPowder() {  // 9bc943
+  if (link_item_in_hand & 0x40)
+    dung_secrets_unk1 = 4;
+}
+
+void Overworld_DrawMap16_Persist(uint16 pos, uint16 value) {  // 9bc97c
+  dung_bg2[pos >> 1] = value;
+  Overworld_DrawMap16(pos, value);
+}
+
+void Overworld_DrawMap16(uint16 pos, uint16 value) {  // 9bc980
+  pos = Overworld_FindMap16VRAMAddress(pos);
+  uint16 *dst = &vram_upload_data[vram_upload_offset >> 1];
+  const uint16 *src = GetMap16toMap8Table() + value * 4;
+  dst[0] = swap16(pos);
+  dst[1] = 0x300;
+  dst[2] = src[0];
+  dst[3] = src[1];
+  dst[4] = swap16(pos + 0x20);
+  dst[5] = 0x300;
+  dst[6] = src[2];
+  dst[7] = src[3];
+  dst[8] = 0xffff;
+  vram_upload_offset += 16;
+}
+
+void Overworld_AlterTileHardcore(uint16 pos, uint16 value) {  // 9bc9de
+  dung_bg2[pos >> 1] = value;
+  pos = Overworld_FindMap16VRAMAddress(pos);
+  uint16 *dst = &vram_upload_data[vram_upload_offset >> 1];
+  const uint16 *src = GetMap16toMap8Table() + value * 4;
+  dst[0] = swap16(pos);
+  dst[1] = 0x300;
+  dst[2] = src[0];
+  dst[3] = src[1];
+  dst[4] = swap16(pos + 0x20);
+  dst[5] = 0x300;
+  dst[6] = src[2];
+  dst[7] = src[3];
+  dst[8] = 0xffff;
+  vram_upload_offset += 16;
+}
+
+uint16 Overworld_FindMap16VRAMAddress(uint16 addr) {  // 9bca69
+  return (((addr & 0x3f) >= 0x20) ? 0x400 : 0) + (((addr & 0xfff) >= 0x800) ? 0x800 : 0) + (addr & 0x1f) + ((addr & 0x780) >> 1);
+}
+
+void Overworld_AnimateEntrance() {  // 9bcac4
+  uint8 j = trigger_special_entrance;
+  flag_is_link_immobilized = j;
+  flag_unk1 = j;
+  nmi_disable_core_updates = j;
+  kOverworld_EntranceSequence[j - 1]();
+}
+
+void Overworld_AnimateEntrance_PoD() {  // 9bcade
+  switch (subsubmodule_index) {
+  case 0:
+    if (++overworld_entrance_sequence_counter != 0x40)
+      return;
+    OverworldEntrance_AdvanceAndBoom();
+    save_ow_event_info[0x5e] |= 0x20;
+    Overworld_DrawMap16_Persist(0x1e6, 0xe31);
+    Overworld_DrawMap16_Persist(0x2ea, 0xe30);
+    Overworld_DrawMap16_Persist(0x26a, 0xe26);
+    Overworld_DrawMap16_Persist(0x2ea, 0xe27);
+    nmi_load_bg_from_vram = 1;
+    break;
+  case 1:
+    if (++overworld_entrance_sequence_counter != 0x20)
+      return;
+    OverworldEntrance_AdvanceAndBoom();
+    Overworld_DrawMap16_Persist(0x26a, 0xe28);
+    Overworld_DrawMap16_Persist(0x2ea, 0xe29);
+    nmi_load_bg_from_vram = 1;
+    break;
+  case 2:
+    if (++overworld_entrance_sequence_counter != 0x20)
+      return;
+    OverworldEntrance_AdvanceAndBoom();
+    Overworld_DrawMap16_Persist(0x26a, 0xe2a);
+    Overworld_DrawMap16_Persist(0x2ea, 0xe2b);
+    Overworld_DrawMap16_Persist(0x36a, 0xe2c);
+    nmi_load_bg_from_vram = 1;
+    break;
+  case 3:
+    if (++overworld_entrance_sequence_counter != 0x20)
+      return;
+    OverworldEntrance_AdvanceAndBoom();
+    Overworld_DrawMap16_Persist(0x26a, 0xe2d);
+    Overworld_DrawMap16_Persist(0x2ea, 0xe2e);
+    Overworld_DrawMap16_Persist(0x36a, 0xe2f);
+    nmi_load_bg_from_vram = 1;
+    break;
+  case 4:
+    if (++overworld_entrance_sequence_counter != 0x20)
+      return;
+    OverworldEntrance_PlayJingle();
+    break;
+  }
+}
+
+// Dark Forest Palace
+void Overworld_AnimateEntrance_Skull() {  // 9bcba6
+  switch (subsubmodule_index) {
+  case 0:
+    if (++overworld_entrance_sequence_counter != 4)
+      return;
+    overworld_entrance_sequence_counter = 0;
+    subsubmodule_index++;
+    Overworld_DrawMap16_Persist(0x409 * 2, 0xe06);
+    Overworld_DrawMap16_Persist(0x40a * 2, 0xe06);
+    save_ow_event_info[BYTE(overworld_screen_index)] |= 0x20;
+    nmi_load_bg_from_vram = 1;
+    sound_effect_2 = 0x16;
+    break;
+  case 1:
+    if (++overworld_entrance_sequence_counter != 12)
+      return;
+    overworld_entrance_sequence_counter = 0;
+    subsubmodule_index++;
+    Overworld_DrawMap16_Persist(0x3c8 * 2, 0xe07);
+    Overworld_DrawMap16_Persist(0x3c9 * 2, 0xe08);
+    Overworld_DrawMap16_Persist(0x3ca * 2, 0xe09);
+    Overworld_DrawMap16_Persist(0x3cb * 2, 0xe0a);
+    nmi_load_bg_from_vram = 1;
+    sound_effect_2 = 0x16;
+    break;
+  case 2:
+    if (++overworld_entrance_sequence_counter != 12)
+      return;
+    overworld_entrance_sequence_counter = 0;
+    subsubmodule_index++;
+    Overworld_DrawMap16_Persist(0x388 * 2, 0xe07);
+    Overworld_DrawMap16_Persist(0x389 * 2, 0xe08);
+    Overworld_DrawMap16_Persist(0x38a * 2, 0xe09);
+    Overworld_DrawMap16_Persist(0x38b * 2, 0xe0a);
+    nmi_load_bg_from_vram = 1;
+    sound_effect_2 = 0x16;
+    break;
+  case 3:
+    if (++overworld_entrance_sequence_counter != 12)
+      return;
+    overworld_entrance_sequence_counter = 0;
+    subsubmodule_index++;
+    Overworld_DrawMap16_Persist(0x2c8 * 2, 0xe11);
+    Overworld_DrawMap16_Persist(0x2cb * 2, 0xe12);
+    Overworld_DrawMap16_Persist(0x308 * 2, 0xe0d);
+    Overworld_DrawMap16_Persist(0x309 * 2, 0xe0e);
+    Overworld_DrawMap16_Persist(0x30a * 2, 0xe0f);
+    Overworld_DrawMap16_Persist(0x30b * 2, 0xe10);
+    Overworld_DrawMap16_Persist(0x349 * 2, 0xe0b);
+    Overworld_DrawMap16_Persist(0x34a * 2, 0xe0c);
+    nmi_load_bg_from_vram = 1;
+    sound_effect_2 = 0x16;
+    break;
+  case 4:
+    if (++overworld_entrance_sequence_counter != 12)
+      return;
+    overworld_entrance_sequence_counter = 0;
+    subsubmodule_index++;
+    Overworld_DrawMap16_Persist(0x2c8 * 2, 0xe13);
+    Overworld_DrawMap16_Persist(0x2cb * 2, 0xe14);
+    Overworld_DrawMap16_Persist(0x308 * 2, 0xe15);
+    Overworld_DrawMap16_Persist(0x309 * 2, 0xe16);
+    Overworld_DrawMap16_Persist(0x30a * 2, 0xe17);
+    Overworld_DrawMap16_Persist(0x30b * 2, 0xe18);
+    Overworld_DrawMap16_Persist(0x349 * 2, 0xe19);
+    Overworld_DrawMap16_Persist(0x34a * 2, 0xe1a);
+    nmi_load_bg_from_vram = 1;
+    sound_effect_2 = 0x16;
+    OverworldEntrance_PlayJingle();
+    break;
+  }
+}
+
+void Overworld_AnimateEntrance_Mire() {  // 9bccd4
+  static const uint8 kMiseryMireEntranceBits[26] = {
+    0xff, 0xf7, 0xf7, 0xfb, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+    0xaa, 0x88, 0x88, 0x88, 0x88, 0x80, 0x80, 0x80, 0x80, 0x80,
+  };
+
+  int j;
+  if (subsubmodule_index >= 2) {
+    bg1_x_offset = frame_counter & 1 ? -1 : 1;
+    bg1_y_offset = -bg1_x_offset;
+  }
+  switch (subsubmodule_index) {
+  case 0:
+    if ((j = ++overworld_entrance_sequence_counter) < 32)
+      break;
+    j -= 32;
+    if (j == 207)
+      subsubmodule_index = 1, overworld_entrance_sequence_counter = 0;
+    TS_copy = (kMiseryMireEntranceBits[j >> 3] & (0x80 >> (j & 7))) != 0;
+    break;
+  case 1: case 2:
+    if ((j = ++overworld_entrance_sequence_counter) == 16) {
+      subsubmodule_index++;
+      sound_effect_ambient = 7;
+    }
+    if (j != 72)
+      break;
+    OverworldEntrance_AdvanceAndBoom();
+    save_ow_event_info[BYTE(overworld_screen_index)] |= 0x20;
+    j = 0xe48;
+draw_misery_2:
+    Overworld_DrawMap16_Persist(0x622, j++);
+    Overworld_DrawMap16_Persist(0x624, j++);
+    Overworld_DrawMap16_Persist(0x626, j++);
+    Overworld_DrawMap16_Persist(0x628, j++);
+    Overworld_DrawMap16_Persist(0x6a2, j++);
+    Overworld_DrawMap16_Persist(0x6a4, j++);
+    Overworld_DrawMap16_Persist(0x6a6, j++);
+    Overworld_DrawMap16_Persist(0x6a8, j++);
+    Overworld_DrawMap16_Persist(0x722, j++);
+    Overworld_DrawMap16_Persist(0x724, j++);
+    Overworld_DrawMap16_Persist(0x726, j++);
+    Overworld_DrawMap16_Persist(0x728, j++);
+    nmi_load_bg_from_vram = 1;
+    break;
+  case 3:
+    if ((j = ++overworld_entrance_sequence_counter) != 72)
+      break;
+    OverworldEntrance_AdvanceAndBoom();
+    j = 0xe54;
+draw_misery_3:
+    Overworld_DrawMap16_Persist(0x5a2, j++);
+    Overworld_DrawMap16_Persist(0x5a4, j++);
+    Overworld_DrawMap16_Persist(0x5a6, j++);
+    Overworld_DrawMap16_Persist(0x5a8, j++);
+    goto draw_misery_2;
+  case 4:
+    if ((j = ++overworld_entrance_sequence_counter) != 80)
+      break;
+    OverworldEntrance_AdvanceAndBoom();
+    j = 0xe64;
+    Overworld_DrawMap16_Persist(0x522, j++);
+    Overworld_DrawMap16_Persist(0x524, j++);
+    Overworld_DrawMap16_Persist(0x526, j++);
+    Overworld_DrawMap16_Persist(0x528, j++);
+    goto draw_misery_3;
+  case 5:
+    if ((j = ++overworld_entrance_sequence_counter) != 128)
+      break;
+    OverworldEntrance_PlayJingle();
+    sound_effect_ambient = 5;
+    break;
+  }
+}
+
+void Overworld_AnimateEntrance_TurtleRock() {  // 9bce28
+  bg1_x_offset = frame_counter & 1 ? -1 : 1;
+  bg1_y_offset = -bg1_x_offset;
+
+  switch (subsubmodule_index) {
+  case 0:
+    save_ow_event_info[overworld_screen_index] |= 0x20;
+    Dungeon_ApproachFixedColor_variable(0);
+    vram_upload_data[0] = 0x10;
+common:
+    vram_upload_data[1] = 0xfe47;
+    vram_upload_data[2] = 0x1e3;
+    BYTE(vram_upload_data[3]) = 0xff;
+    subsubmodule_index++;
+    nmi_load_bg_from_vram = 1;
+    break;
+  case 1:
+    vram_upload_data[0] = 0x14;
+    goto common;
+  case 2:
+    vram_upload_data[0] = 0x18;
+    goto common;
+  case 3:
+    vram_upload_data[0] = 0x1c;
+    goto common;
+  case 4:
+    for (int i = 0; i < 8; i++)
+      main_palette_buffer[0x58 + i] = aux_palette_buffer[0x68 + i] = 0;
+    BG1VOFS_copy2 = BG2VOFS_copy2;
+    BG1HOFS_copy2 = BG2HOFS_copy2;
+    subsubmodule_index++;
+    flag_update_cgram_in_nmi++;
+    break;
+  case 5: {
+    OverworldEntrance_DrawManyTR();
+    TS_copy = 1;
+    CGWSEL_copy = 2;
+    CGADSUB_copy = 0x22;
+    uint16 *vram = vram_upload_data, *vram_end = vram + (vram_upload_offset >> 1);
+    do {
+      vram[0] |= 0x10;
+      if (vram[2] == 0x8aa)
+        vram[2] = 0x1e3;
+      if (vram[3] == 0x8aa)
+        vram[3] = 0x1e3;
+    } while ((vram += 4) != vram_end);
+    turtlerock_ctr = 0;
+    subsubmodule_index++;
+    break;
+  }
+  case 6:
+    if (!(frame_counter & 1)) {
+      if (!(turtlerock_ctr & 7)) {
+        PaletteFilter_RestoreAdditive(0xb0, 0xc0);
+        PaletteFilter_RestoreSubtractive(0xd0, 0xe0);
+        flag_update_cgram_in_nmi++;
+        sound_effect_2 = 2;
+      }
+      if (!--turtlerock_ctr) {
+        turtlerock_ctr = 0x30;
+        subsubmodule_index++;
+      }
+    }
+    break;
+  case 7:
+    if (!(frame_counter & 1) && !(turtlerock_ctr & 7))
+      sound_effect_2 = 2;
+    if (!--turtlerock_ctr) {
+      OverworldEntrance_DrawManyTR();
+      TS_copy = 0;
+      CGWSEL_copy = 0x82;
+      CGADSUB_copy = 0x20;
+      subsubmodule_index++;
+      sound_effect_ambient = 5;
+    }
+    break;
+  case 8:
+    OverworldEntrance_PlayJingle();
+    break;
+  }
+}
+
+void OverworldEntrance_PlayJingle() {  // 9bcf40
+  sound_effect_2 = 27;
+  trigger_special_entrance = 0;
+  subsubmodule_index = 0;
+  nmi_disable_core_updates = 0;
+  flag_is_link_immobilized = 0;
+  flag_unk1 = 0;
+  bg1_x_offset = 0;
+  bg1_y_offset = 0;
+}
+
+void OverworldEntrance_DrawManyTR() {  // 9bcf60
+  int j = 0xe78;
+  Overworld_DrawMap16_Persist(0x99e, j++);
+  Overworld_DrawMap16_Persist(0x9a0, j++);
+  Overworld_DrawMap16_Persist(0x9a2, j++);
+  Overworld_DrawMap16_Persist(0x9a4, j++);
+
+  Overworld_DrawMap16_Persist(0xa1e, j++);
+  Overworld_DrawMap16_Persist(0xa20, j++);
+  Overworld_DrawMap16_Persist(0xa22, j++);
+  Overworld_DrawMap16_Persist(0xa24, j++);
+
+  Overworld_DrawMap16_Persist(0xa9e, j++);
+  Overworld_DrawMap16_Persist(0xaa0, j++);
+  Overworld_DrawMap16_Persist(0xaa2, j++);
+  Overworld_DrawMap16_Persist(0xaa4, j++);
+
+  Overworld_DrawMap16_Persist(0xb1e, j++);
+  Overworld_DrawMap16_Persist(0xb20, j++);
+  Overworld_DrawMap16_Persist(0xb22, j++);
+  Overworld_DrawMap16_Persist(0xb24, j++);
+  nmi_load_bg_from_vram = 1;
+  nmi_disable_core_updates = 1;
+}
+
+void Overworld_AnimateEntrance_GanonsTower() {  // 9bcfd9
+  switch (subsubmodule_index) {
+  case 0:
+  case 1:
+    save_ow_event_info[BYTE(overworld_screen_index)] |= 0x20;
+    GanonTowerEntrance_Func1();
+    break;
+  case 2:
+    GanonTowerEntrance_Func1();
+    if (!TS_copy) {
+      TS_copy = 1;
+      if (++ganonentrance_ctr == 3) {
+        ganonentrance_ctr = 0;
+        sound_effect_ambient = 7;
+      } else {
+        subsubmodule_index = 0;
+      }
+    }
+    break;
+  case 3:
+    if (++ganonentrance_ctr != 48)
+      return;
+    OverworldEntrance_AdvanceAndBoom();
+    Overworld_DrawMap16_Persist(0x45e, 0xe88);
+    Overworld_DrawMap16_Persist(0x460, 0xe89);
+    Overworld_DrawMap16_Persist(0x4de, 0xea2);
+    Overworld_DrawMap16_Persist(0x4e0, 0xea3);
+    Overworld_DrawMap16_Persist(0x55e, 0xe8a);
+    Overworld_DrawMap16_Persist(0x560, 0xe8b);
+    nmi_load_bg_from_vram = 1;
+    break;
+  case 4:
+    if (++ganonentrance_ctr != 48)
+      return;
+    OverworldEntrance_AdvanceAndBoom();
+    Overworld_DrawMap16_Persist(0x45e, 0xe8c);
+    Overworld_DrawMap16_Persist(0x460, 0xe8d);
+    Overworld_DrawMap16_Persist(0x4de, 0xe8e);
+    Overworld_DrawMap16_Persist(0x4e0, 0xe8f);
+    Overworld_DrawMap16_Persist(0x55e, 0xe90);
+    Overworld_DrawMap16_Persist(0x560, 0xe91);
+    nmi_load_bg_from_vram = 1;
+    break;
+  case 5:
+    if (++ganonentrance_ctr != 52)
+      return;
+    OverworldEntrance_AdvanceAndBoom();
+    Overworld_DrawMap16_Persist(0x45e, 0xe92);
+    Overworld_DrawMap16_Persist(0x460, 0xe93);
+    Overworld_DrawMap16_Persist(0x4de, 0xe94);
+    Overworld_DrawMap16_Persist(0x4e0, 0xe94);
+    Overworld_DrawMap16_Persist(0x55e, 0xe95);
+    Overworld_DrawMap16_Persist(0x560, 0xe95);
+    nmi_load_bg_from_vram = 1;
+    break;
+  case 6:
+    if (++ganonentrance_ctr != 32)
+      return;
+    OverworldEntrance_AdvanceAndBoom();
+    Overworld_DrawMap16_Persist(0x45e, 0xe96);
+    Overworld_DrawMap16_Persist(0x460, 0xe97);
+    Overworld_DrawMap16_Persist(0x4de, 0xe98);
+    Overworld_DrawMap16_Persist(0x4e0, 0xe99);
+    nmi_load_bg_from_vram = 1;
+    break;
+  case 7:
+    if (++ganonentrance_ctr != 32)
+      return;
+    OverworldEntrance_AdvanceAndBoom();
+    Overworld_DrawMap16_Persist(0x4de, 0xe9a);
+    Overworld_DrawMap16_Persist(0x4e0, 0xe9b);
+    nmi_load_bg_from_vram = 1;
+    break;
+  case 8:
+    if (++ganonentrance_ctr != 32)
+      return;
+    OverworldEntrance_AdvanceAndBoom();
+    Overworld_DrawMap16_Persist(0x4de, 0xe9c);
+    Overworld_DrawMap16_Persist(0x4e0, 0xe9d);
+    Overworld_DrawMap16_Persist(0x55e, 0xe9e);
+    Overworld_DrawMap16_Persist(0x560, 0xe9f);
+    nmi_load_bg_from_vram = 1;
+    break;
+  case 9:
+    if (++ganonentrance_ctr != 32)
+      return;
+    OverworldEntrance_AdvanceAndBoom();
+    Overworld_DrawMap16_Persist(0x55e, 0xe9a);
+    Overworld_DrawMap16_Persist(0x560, 0xe9b);
+    nmi_load_bg_from_vram = 1;
+    break;
+  case 10:
+    if (++ganonentrance_ctr != 32)
+      return;
+    OverworldEntrance_AdvanceAndBoom();
+    Overworld_DrawMap16_Persist(0x55e, 0xe9c);
+    Overworld_DrawMap16_Persist(0x560, 0xe9d);
+    Overworld_DrawMap16_Persist(0x5de, 0xea0);
+    Overworld_DrawMap16_Persist(0x5e0, 0xea1);
+    nmi_load_bg_from_vram = 1;
+    break;
+  case 11:
+    if (++ganonentrance_ctr != 32)
+      return;
+    sound_effect_ambient = 5;
+    OverworldEntrance_AdvanceAndBoom();
+    Overworld_DrawMap16_Persist(0x5de, 0xe9a);
+    Overworld_DrawMap16_Persist(0x5e0, 0xe9b);
+    nmi_load_bg_from_vram = 1;
+    break;
+  case 12:
+    if (++ganonentrance_ctr != 72)
+      return;
+    OverworldEntrance_PlayJingle();
+    ganonentrance_ctr = 0;
+    music_control = 13;
+    sound_effect_ambient = 9;
+    break;
+  }
+}
+
+void OverworldEntrance_AdvanceAndBoom() {  // 9bd00e
+  subsubmodule_index++;
+  overworld_entrance_sequence_counter = 0;
+  sound_effect_1 = 12;
+  sound_effect_2 = 7;
+}
+
--- /dev/null
+++ b/src/overworld.h
@@ -1,0 +1,175 @@
+#pragma once
+#include "zelda_rtl.h"
+#include "variables.h"
+
+const uint8 *GetMap8toTileAttr();
+const uint16 *GetMap16toMap8Table();
+bool LookupInOwEntranceTab(uint16 r0, uint16 r2);
+int LookupInOwEntranceTab2(uint16 pos);
+bool CanEnterWithTagalong(int e);
+int DirToEnum(int dir);
+void Overworld_ResetMosaicDown();
+void Overworld_Func1D();
+void Overworld_Func1E();
+uint16 Overworld_GetSignText(int area);
+const uint8 *GetOverworldSpritePtr(int area);
+uint8 GetOverworldBgPalette(int idx);
+void Sprite_LoadGraphicsProperties();
+void Sprite_LoadGraphicsProperties_light_world_only();
+void InitializeMirrorHDMA();
+void MirrorWarp_BuildWavingHDMATable();
+void MirrorWarp_BuildDewavingHDMATable();
+void TakeDamageFromPit();
+void Module08_OverworldLoad();
+void PreOverworld_LoadProperties();
+void AdjustLinkBunnyStatus();
+void ForceNonbunnyStatus();
+void RecoverPositionAfterDrowning();
+void Module0F_SpotlightClose();
+void Dungeon_PrepExitWithSpotlight();
+void Spotlight_ConfigureTableAndControl();
+void OpenSpotlight_Next2();
+void Module10_SpotlightOpen();
+void Module10_00_OpenIris();
+void SetTargetOverworldWarpToPyramid();
+void ResetAncillaAndCutscene();
+void Module09_Overworld();
+void OverworldOverlay_HandleRain();
+void Module09_00_PlayerControl();
+void OverworldHandleTransitions();
+void Overworld_LoadGFXAndScreenSize();
+void ScrollAndCheckForSOWExit();
+void Module09_LoadAuxGFX();
+void Overworld_FinishTransGfx();
+void Module09_LoadNewMapAndGFX();
+void Overworld_RunScrollTransition();
+void Module09_LoadNewSprites();
+void Overworld_StartScrollTransition();
+void Overworld_EaseOffScrollTransition();
+void Module09_0A_WalkFromExiting_FacingDown();
+void Module09_0B_WalkFromExiting_FacingUp();
+void Module09_09_OpenBigDoorFromExiting();
+void Overworld_DoMapUpdate32x32_B();
+void Module09_0C_OpenBigDoor();
+void Overworld_DoMapUpdate32x32_conditional();
+void Overworld_DoMapUpdate32x32();
+void Overworld_StartMosaicTransition();
+void Overworld_LoadOverlays();
+void PreOverworld_LoadOverlays();
+void Overworld_LoadOverlays2();
+void Module09_FadeBackInFromMosaic();
+void Overworld_Func1C();
+void OverworldMosaicTransition_LoadSpriteGraphicsAndSetMosaic();
+void Overworld_Func22();
+void Overworld_Func18();
+void Overworld_Func19();
+void Module09_MirrorWarp();
+void MirrorWarp_FinalizeAndLoadDestination();
+void Overworld_DrawScreenAtCurrentMirrorPosition();
+void MirrorWarp_LoadSpritesAndColors();
+void Overworld_Func2B();
+void Overworld_WeathervaneExplosion();
+void Module09_2E_Whirlpool();
+void Overworld_Func2F();
+void Module09_2A_RecoverFromDrowning();
+void Module09_2A_00_ScrollToLand();
+void Overworld_OperateCameraScroll();
+int OverworldCameraBoundaryCheck(int xa, int ya, int vd, int r8);
+int OverworldScrollTransition();
+void Overworld_SetCameraBoundaries(int big, int area);
+void Overworld_FinalizeEntryOntoScreen();
+void Overworld_Func1F();
+void ConditionalMosaicControl();
+void Overworld_ResetMosaic_alwaysIncrease();
+void Overworld_SetSongList();
+void LoadOverworldFromDungeon();
+void Overworld_LoadNewScreenProperties();
+void LoadCachedEntranceProperties();
+void Overworld_EnterSpecialArea();
+void LoadOverworldFromSpecialOverworld();
+void FluteMenu_LoadTransport();
+void Overworld_LoadBirdTravelPos(int k);
+void FluteMenu_LoadSelectedScreenPalettes();
+void FindPartnerWhirlpoolExit();
+void Overworld_LoadAmbientOverlay(bool load_map_data);
+void Overworld_LoadAmbientOverlayFalse();
+void Overworld_LoadAndBuildScreen();
+void Module08_02_LoadAndAdvance();
+void Overworld_DrawQuadrantsAndOverlays();
+void Overworld_HandleOverlaysAndBombDoors();
+void TriggerAndFinishMapLoadStripe_Y(int n);
+void TriggerAndFinishMapLoadStripe_X(int n);
+void SomeTileMapChange();
+void CreateInitialNewScreenMapToScroll();
+void CreateInitialOWScreenView_Big_North();
+void CreateInitialOWScreenView_Big_South();
+void CreateInitialOWScreenView_Big_West();
+void CreateInitialOWScreenView_Big_East();
+void CreateInitialOWScreenView_Small_North();
+void CreateInitialOWScreenView_Small_South();
+void CreateInitialOWScreenView_Small_West();
+void CreateInitialOWScreenView_Small_East();
+void OverworldTransitionScrollAndLoadMap();
+uint16 *BuildFullStripeDuringTransition_North(uint16 *dst);
+uint16 *BuildFullStripeDuringTransition_South(uint16 *dst);
+uint16 *BuildFullStripeDuringTransition_West(uint16 *dst);
+uint16 *BuildFullStripeDuringTransition_East(uint16 *dst);
+void OverworldHandleMapScroll();
+uint16 *CheckForNewlyLoadedMapAreas_North(uint16 *dst);
+uint16 *CheckForNewlyLoadedMapAreas_South(uint16 *dst);
+uint16 *CheckForNewlyLoadedMapAreas_West(uint16 *dst);
+uint16 *CheckForNewlyLoadedMapAreas_East(uint16 *dst);
+uint16 *BufferAndBuildMap16Stripes_X(uint16 *dst);
+uint16 *BufferAndBuildMap16Stripes_Y(uint16 *dst);
+void Overworld_DecompressAndDrawAllQuadrants();
+void Overworld_DecompressAndDrawOneQuadrant(uint16 *dst, int screen);
+void Overworld_ParseMap32Definition(uint16 *dst, uint16 input);
+void OverworldLoad_LoadSubOverlayMap32();
+void LoadOverworldOverlay();
+void Map16ToMap8(const uint8 *src, int r20);
+void OverworldCopyMap16ToBuffer(const uint8 *src, uint16 r20, int r14, uint16 *r10);
+void MirrorBonk_RecoverChangedTiles();
+void DecompressEnemyDamageSubclasses();
+int Decompress_bank02(uint8 *dst, const uint8 *src);
+uint8 Overworld_ReadTileAttribute(uint16 x, uint16 y);
+void Overworld_SetFixedColAndScroll();
+void Overworld_Memorize_Map16_Change(uint16 pos, uint16 value);
+void HandlePegPuzzles(uint16 pos);
+void GanonTowerEntrance_Func1();
+void Overworld_CheckSpecialSwitchArea();
+const uint16 *Overworld_GetMap16OfLink_Mult8();
+void Palette_AnimGetMasterSword();
+void Palette_AnimGetMasterSword2();
+void Palette_AnimGetMasterSword3();
+void Overworld_DwDeathMountainPaletteAnimation();
+void Overworld_LoadEventOverlay();
+void Ancilla_TerminateWaterfallSplashes();
+void Overworld_GetPitDestination();
+void Overworld_UseEntrance();
+uint16 Overworld_ToolAndTileInteraction(uint16 x, uint16 y);
+void Overworld_PickHammerSfx(uint16 a);
+uint16 Overworld_GetLinkMap16Coords(Point16U *xy);
+uint8 Overworld_HandleLiftableTiles(Point16U *pt_arg);
+uint8 Overworld_LiftingSmallObj(uint16 a, uint16 pos, uint16 y, Point16U pt);
+int Overworld_SmashRockPile(bool down_one_tile, Point16U *pt);
+uint8 SmashRockPile_fromLift(uint16 a, uint16 pos, uint16 y, Point16U pt);
+void Overworld_BombTiles32x32(uint16 x, uint16 y);
+void Overworld_BombTile(int x, int y);
+void Overworld_AlterWeathervane();
+void OpenGargoylesDomain();
+void CreatePyramidHole();
+uint16 Overworld_RevealSecret(uint16 pos);
+void AdjustSecretForPowder();
+void Overworld_DrawMap16_Persist(uint16 pos, uint16 value);
+void Overworld_DrawMap16(uint16 pos, uint16 value);
+void Overworld_AlterTileHardcore(uint16 pos, uint16 value);
+uint16 Overworld_FindMap16VRAMAddress(uint16 addr);
+void Overworld_AnimateEntrance();
+void Overworld_AnimateEntrance_PoD();
+void Overworld_AnimateEntrance_Skull();
+void Overworld_AnimateEntrance_Mire();
+void Overworld_AnimateEntrance_TurtleRock();
+void OverworldEntrance_PlayJingle();
+void OverworldEntrance_DrawManyTR();
+void Overworld_AnimateEntrance_GanonsTower();
+void OverworldEntrance_AdvanceAndBoom();
--- /dev/null
+++ b/src/platform/switch/.gitignore
@@ -1,0 +1,4 @@
+/bin
+/*.nacp
+/*.nro
+/*.elf
\ No newline at end of file
--- /dev/null
+++ b/src/platform/switch/Makefile
@@ -1,0 +1,224 @@
+#---------------------------------------------------------------------------------
+.SUFFIXES:
+#---------------------------------------------------------------------------------
+
+ifeq ($(strip $(DEVKITPRO)),)
+$(error "Please set DEVKITPRO in your environment. export DEVKITPRO=<path to>/devkitpro")
+endif
+
+TOPDIR ?= $(CURDIR)
+include $(DEVKITPRO)/libnx/switch_rules
+
+#---------------------------------------------------------------------------------
+# TARGET is the name of the output
+# BUILD is the directory where object files & intermediate files will be placed
+# SOURCES is a list of directories containing source code
+# DATA is a list of directories containing data files
+# INCLUDES is a list of directories containing header files
+# ROMFS is the directory containing data to be added to RomFS, relative to the Makefile (Optional)
+#
+# NO_ICON: if set to anything, do not use icon.
+# NO_NACP: if set to anything, no .nacp file is generated.
+# APP_TITLE is the name of the app stored in the .nacp file (Optional)
+# APP_AUTHOR is the author of the app stored in the .nacp file (Optional)
+# APP_VERSION is the version of the app stored in the .nacp file (Optional)
+# APP_TITLEID is the titleID of the app stored in the .nacp file (Optional)
+# ICON is the filename of the icon (.jpg), relative to the project folder.
+#   If not set, it attempts to use one of the following (in this order):
+#     - <Project name>.jpg
+#     - icon.jpg
+#     - <libnx folder>/default_icon.jpg
+#
+# CONFIG_JSON is the filename of the NPDM config file (.json), relative to the project folder.
+#   If not set, it attempts to use one of the following (in this order):
+#     - <Project name>.json
+#     - config.json
+#   If a JSON file is provided or autodetected, an ExeFS PFS0 (.nsp) is built instead
+#   of a homebrew executable (.nro). This is intended to be used for sysmodules.
+#   NACP building is skipped as well.
+#---------------------------------------------------------------------------------
+SRC_DIR     := ../..
+TARGET		:=	zelda3
+BUILD		:=	bin
+SOURCES		:=  $(SRC_DIR) $(SRC_DIR)/snes $(SRC_DIR)/third_party/gl_core $(SRC_DIR)/third_party/opus-1.3.1-stripped
+
+CFILES := $(wildcard $(SRC_DIR)/*.c $(SRC_DIR)/snes/*.c) $(SRC_DIR)/third_party/gl_core/gl_core_3_1.c $(SRC_DIR)/third_party/opus-1.3.1-stripped/opus_decoder_amalgam.c
+
+INCLUDES	:=	include
+APP_TITLE   :=  The Legend of Zelda: A Link to the Past
+APP_AUTHOR  :=  snesrev & Lywx
+APP_VERSION :=  $(shell git rev-parse --short HEAD) $(shell git rev-parse --abbrev-ref HEAD)
+
+#---------------------------------------------------------------------------------
+# options for code generation
+#---------------------------------------------------------------------------------
+ARCH	:=	-march=armv8-a+crc+crypto -mtune=cortex-a57 -mtp=soft -fPIE
+
+CFLAGS	:=	-g -Wall -O2 -ffunction-sections -Wno-parentheses \
+			$(ARCH) $(DEFINES)
+
+CFLAGS	+=	-D__SWITCH__ $(INCLUDE) -DSTBI_NO_THREAD_LOCALS `sdl2-config --cflags`
+
+CXXFLAGS	:= $(CFLAGS) -fno-rtti -fno-exceptions
+CFLAGS += -std=gnu11
+
+ASFLAGS	:=	-g $(ARCH)
+LDFLAGS	=	-specs=$(DEVKITPRO)/libnx/switch.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map)
+
+LIBS :=  `$(PREFIX)pkg-config --libs sdl2` -lnx -lm
+
+#---------------------------------------------------------------------------------
+# list of directories containing libraries, this must be the top level containing
+# include and lib
+#---------------------------------------------------------------------------------
+LIBDIRS	:= $(PORTLIBS) $(LIBNX)
+
+#---------------------------------------------------------------------------------
+# no real need to edit anything past this point unless you need to add additional
+# rules for different file extensions
+#---------------------------------------------------------------------------------
+ifneq ($(BUILD),$(notdir $(CURDIR)))
+#---------------------------------------------------------------------------------
+
+export OUTPUT	:=	$(CURDIR)/$(TARGET)
+export TOPDIR	:=	$(CURDIR)
+
+export VPATH	:=	$(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \
+			$(foreach dir,$(DATA),$(CURDIR)/$(dir)) \
+
+
+export DEPSDIR	:=	$(CURDIR)/$(BUILD)
+
+#CFILES		:=	$(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
+#CFILES    :=  $(wildcard ../../*.c ../../snes/*.c) ../../third_party/gl_core/gl_core_3_1.c ../../third_party/opus-1.3.1-stripped/opus_decoder_amalgam.c
+#CPPFILES	:=	$(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp)))
+#SFILES		:=	$(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
+BINFILES	:=	$(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*)))
+
+#---------------------------------------------------------------------------------
+# use CXX for linking C++ projects, CC for standard C
+#---------------------------------------------------------------------------------
+export LD	:=	$(CXX)
+#---------------------------------------------------------------------------------
+
+export OFILES_BIN	:=	$(addsuffix .o,$(BINFILES))
+export OFILES_SRC	:=	$(CPPFILES:.cpp=.o) $(notdir $(CFILES:.c=.o)) $(SFILES:.s=.o)
+export OFILES 		:=	$(OFILES_BIN) $(OFILES_SRC)
+export HFILES_BIN	:=	$(addsuffix .h,$(subst .,_,$(BINFILES)))
+
+export INCLUDE	:=	$(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
+			$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
+			-I$(CURDIR)/$(BUILD)
+
+export LIBPATHS	:=	$(foreach dir,$(LIBDIRS),-L$(dir)/lib)
+
+$(info $(OFILES))
+
+ifeq ($(strip $(CONFIG_JSON)),)
+	jsons := $(wildcard *.json)
+	ifneq (,$(findstring $(TARGET).json,$(jsons)))
+		export APP_JSON := $(TOPDIR)/$(TARGET).json
+	else
+		ifneq (,$(findstring config.json,$(jsons)))
+			export APP_JSON := $(TOPDIR)/config.json
+		endif
+	endif
+else
+	export APP_JSON := $(TOPDIR)/$(CONFIG_JSON)
+endif
+
+ifeq ($(strip $(ICON)),)
+	icons := $(wildcard *.jpg)
+	ifneq (,$(findstring $(TARGET).jpg,$(icons)))
+		export APP_ICON := $(TOPDIR)/$(TARGET).jpg
+	else
+		ifneq (,$(findstring icon.jpg,$(icons)))
+			export APP_ICON := $(TOPDIR)/icon.jpg
+		endif
+	endif
+else
+	export APP_ICON := $(TOPDIR)/$(ICON)
+endif
+
+ifeq ($(strip $(NO_ICON)),)
+	export NROFLAGS += --icon=$(APP_ICON)
+endif
+
+ifeq ($(strip $(NO_NACP)),)
+	export NROFLAGS += --nacp=$(CURDIR)/$(TARGET).nacp
+endif
+
+ifneq ($(APP_TITLEID),)
+	export NACPFLAGS += --titleid=$(APP_TITLEID)
+endif
+
+ifneq ($(ROMFS),)
+	export NROFLAGS += --romfsdir=$(CURDIR)/$(ROMFS)
+endif
+
+.PHONY: $(BUILD) clean all
+
+#---------------------------------------------------------------------------------
+all: $(BUILD)
+
+$(BUILD):
+	@echo $(CFILES) ...
+	@[ -d $@ ] || mkdir -p $@
+	@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
+
+#---------------------------------------------------------------------------------
+clean:
+	@echo clean ...
+ifeq ($(strip $(APP_JSON)),)
+	@rm -fr $(BUILD) $(TARGET).nro $(TARGET).nacp $(TARGET).elf
+else
+	@rm -fr $(BUILD) $(TARGET).nsp $(TARGET).nso $(TARGET).npdm $(TARGET).elf
+endif
+
+
+#---------------------------------------------------------------------------------
+else
+.PHONY:	all
+
+DEPENDS	:=	$(OFILES:.o=.d)
+
+#---------------------------------------------------------------------------------
+# main targets
+#---------------------------------------------------------------------------------
+ifeq ($(strip $(APP_JSON)),)
+
+all	:	$(OUTPUT).nro
+
+ifeq ($(strip $(NO_NACP)),)
+$(OUTPUT).nro	:	$(OUTPUT).elf $(OUTPUT).nacp
+else
+$(OUTPUT).nro	:	$(OUTPUT).elf
+endif
+
+else
+
+all	:	$(OUTPUT).nsp
+
+$(OUTPUT).nsp	:	$(OUTPUT).nso $(OUTPUT).npdm
+
+$(OUTPUT).nso	:	$(OUTPUT).elf
+
+endif
+
+$(OUTPUT).elf	:	$(OFILES)
+
+$(OFILES_SRC)	: $(HFILES_BIN)
+
+#---------------------------------------------------------------------------------
+# you need a rule like this for each extension you use as binary data
+#---------------------------------------------------------------------------------
+%.bin.o	%_bin.h :	%.bin
+#---------------------------------------------------------------------------------
+	@echo $(notdir $<)
+	@$(bin2o)
+
+-include $(DEPENDS)
+
+#---------------------------------------------------------------------------------------
+endif
+#---------------------------------------------------------------------------------------
binary files /dev/null b/src/platform/switch/icon.jpg differ
--- /dev/null
+++ b/src/platform/switch/zelda3.ini
@@ -1,0 +1,126 @@
+[General]
+# Automatically save state on quit and reload on start
+Autosave = 0
+DisplayPerfInTitle = 0
+
+# Extended aspect ratio, either 16:9, 16:10, or 18:9. 4:3 means normal aspect ratio.
+# Add ", unchanged_sprites" to avoid changing sprite spawn/die behavior. Without this
+# replays will be incompatible.
+# Add ", no_visual_fixes" to avoid fixing some graphics glitches (for example with Cape).
+# It won't affect replays/game behavior but the memory compare will not work.
+# Add "extend_y, " right before the aspect radio specifier to display 240 lines instead of 224.
+ExtendedAspectRatio = 16:9
+
+
+[Graphics]
+# Window size ( Auto or WidthxHeight )
+WindowSize = 1280x720
+# Fullscreen mode (0=windowed, 1=desktop fullscreen, 2=fullscreen w/mode change)
+Fullscreen = 0
+# Window scale (1=100%, 2=200%, 3=300%, etc.)
+WindowScale = 1
+NewRenderer = 1
+EnhancedMode7 = 1
+IgnoreAspectRatio = 0
+
+# Enable this option to remove the sprite limits per scan line
+NoSpriteLimits = 1
+
+# Change the appearance of Link by loading a ZSPR file
+# See all sprites here: https://snesrev.github.io/sprites-gfx/snes/zelda3/link/
+# Download the files with "git clone https://github.com/snesrev/sprites-gfx.git"
+# LinkGraphics = sprites-gfx/snes/zelda3/link/sheets/megaman-x.2.zspr
+
+
+[Sound]
+EnableAudio = 1
+
+# DSP frequency in samples per second (e.g. 48000, 44100, 32000, 22050, 11025)
+AudioFreq = 44100
+# number of separate sound channels (1=mono, 2=stereo)
+AudioChannels = 2
+# Audio buffer size in samples (power of 2; e.g., 4096, 2048, 1024) [try 1024 if sound is crackly]. The higher the more lag before you hear sounds.
+AudioSamples = 1024
+
+# Enable MSU support for audio. Files need to be in a subfolder, msu/alttp_msu-*.pcm
+# Only works with 44100 hz and 2 channels
+EnableMSU = 0
+
+
+[Features]
+# Item switch on L/R. Also allows reordering of items in inventory by pressing Y+direction
+# Hold X inside of the item selection screen to reassign the X key into a separate item slot.
+# When X is assigned to an item, the Select key is used to enter the map. Press Select inside
+# of the Start menu to see the old select options.
+ItemSwitchLR = 0
+
+# Allow turning while dashing
+TurnWhileDashing = 0
+
+# Allow mirror to be used to warp to the Dark World
+MirrorToDarkworld = 0
+
+# Collect items (like hearts) with sword instead of having to touch them
+CollectItemsWithSword = 0
+
+# Level 2-4 sword can be used to break pots
+BreakPotsWithSword = 0
+
+# Disable the low health beep
+DisableLowHealthBeep = 0
+
+# Avoid waiting too much at the start
+SkipIntroOnKeypress = 0
+
+# Display max rupees/bombs/arrows with orange/yellow color
+ShowMaxItemsInYellow = 0
+
+# Allows up to four bombs active at a time instead of two.
+MoreActiveBombs = 0
+
+# Can carry 9999 rupees instead of 999
+CarryMoreRupees = 0
+
+# Enable various zelda bug fixes
+MiscBugFixes = 0
+
+# Enable some more advanced zelda bugfixes that change game behavior
+GameChangingBugFixes = 0
+
+# Allow bird travel to be cancelled by hitting the X key
+CancelBirdTravel = 0
+
+
+[KeyMap]
+# Change what keyboard keys map to the joypad
+# Order: Up, Down, Left, Right, Select, Start, A, B, X, Y, L, R
+
+# This default is suitable for QWERTY keyboards.
+Controls = Up, Down, Left, Right, Right Shift, Return, x, z, s, a, c, v
+
+# This default is suitable for QWERTZ keyboards.
+#Controls = Up, Down, Left, Right, Right Shift, Return, x, y, s, a, c, v
+
+# This one is suitable for AZERTY keyboards.
+#Controls = Up, Down, Left, Right, Right Shift, Return, x, w, s, q, c, v
+
+CheatLife = w
+CheatKeys = o
+CheatWalkThroughWalls = Ctrl+e
+ClearKeyLog = k
+StopReplay = l
+Fullscreen = Alt+Return
+Reset = Ctrl+r
+Pause = Shift+p
+PauseDimmed = p
+Turbo = Tab
+ReplayTurbo = t
+WindowBigger = Ctrl+Up
+WindowSmaller = Ctrl+Down
+
+Load =      F1,     F2,     F3,     F4,     F5,     F6,     F7,     F8,     F9,     F10
+Save = Shift+F1,Shift+F2,Shift+F3,Shift+F4,Shift+F5,Shift+F6,Shift+F7,Shift+F8,Shift+F9,Shift+F10
+Replay= Ctrl+F1,Ctrl+F2,Ctrl+F3,Ctrl+F4,Ctrl+F5,Ctrl+F6,Ctrl+F7,Ctrl+F8,Ctrl+F9,Ctrl+F10
+
+LoadRef = 1,2,3,4,5,6,7,8,9,0,-,=,Backspace
+ReplayRef = Ctrl+1,Ctrl+2,Ctrl+3,Ctrl+4,Ctrl+5,Ctrl+6,Ctrl+7,Ctrl+8,Ctrl+9,Ctrl+0,Ctrl+-,Ctrl+=,Ctrl+Backspace
--- /dev/null
+++ b/src/platform/win32/resource.h
@@ -1,0 +1,16 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by zelda3.rc
+//
+#define IDI_ICON1                       101
+
+// Next default values for new objects
+// 
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE        102
+#define _APS_NEXT_COMMAND_VALUE         40001
+#define _APS_NEXT_CONTROL_VALUE         1001
+#define _APS_NEXT_SYMED_VALUE           101
+#endif
+#endif
binary files /dev/null b/src/platform/win32/triforce.ico differ
--- /dev/null
+++ b/src/platform/win32/volume_control.c
@@ -1,0 +1,82 @@
+#include "volume_control.h"
+
+#define COBJMACROS
+#define CINTERFACE
+
+#define MICROSOFT_WINDOWS_WINBASE_H_DEFINE_INTERLOCKED_CPLUSPLUS_OVERLOADS 0
+
+#include <initguid.h>
+#include <audioclient.h>
+#include <audiopolicy.h>
+#include <mmdeviceapi.h>
+
+static ISimpleAudioVolume *GetSimpleAudioVolume();
+
+DEFINE_GUID(IID_IMMDeviceEnumerator, 0XA95664D2, 0X9614, 0X4F35, 0XA7, 0X46, 0XDE, 0X8D, 0XB6, 0X36, 0X17, 0XE6);
+DEFINE_GUID(CLSID_MMDeviceEnumerator, 0XBCDE0395, 0XE52F, 0X467C, 0X8E, 0X3D, 0XC4, 0X57, 0X92, 0X91, 0X69, 0X2E);
+DEFINE_GUID(IID_IAudioSessionManager, 0X77AA99A0, 0X1BD6, 0X484F, 0X8B, 0XC7, 0X2C, 0X65, 0X4C, 0X9A, 0X9B, 0X6F);
+
+static void InitializeCom() {
+  static bool com_initialized;
+  if (!com_initialized)
+    com_initialized = SUCCEEDED(CoInitialize(NULL));
+}
+
+int GetApplicationVolume() {
+  ISimpleAudioVolume *simple_audio_volume = GetSimpleAudioVolume();
+  if (!simple_audio_volume)
+    return false;
+  float volume_level = -1;
+  HRESULT result = ISimpleAudioVolume_GetMasterVolume(simple_audio_volume, &volume_level);
+  ISimpleAudioVolume_Release(simple_audio_volume);
+  return (int)(volume_level * 100);
+}
+
+bool SetApplicationVolume(int volume_level) {
+  ISimpleAudioVolume *simple_audio_volume = GetSimpleAudioVolume();
+  if (!simple_audio_volume)
+    return false;
+  HRESULT result = ISimpleAudioVolume_SetMasterVolume(simple_audio_volume, (float)(volume_level / 100.0), NULL);
+  ISimpleAudioVolume_Release(simple_audio_volume);
+  return SUCCEEDED(result);
+}
+
+bool SetApplicationMuted(bool muted) {
+  ISimpleAudioVolume *simple_audio_volume = GetSimpleAudioVolume();
+  if (!simple_audio_volume)
+    return false;
+  HRESULT result = ISimpleAudioVolume_SetMute(simple_audio_volume, muted, NULL);
+  ISimpleAudioVolume_Release(simple_audio_volume);
+  return SUCCEEDED(result);
+}
+
+static ISimpleAudioVolume *GetSimpleAudioVolume() {
+  HRESULT result;
+  IMMDeviceEnumerator *device_enumerator = NULL;
+  IMMDevice *device = NULL;
+  IAudioSessionManager *audio_session_manager = NULL;
+  ISimpleAudioVolume *simple_audio_volume = NULL;
+
+  InitializeCom();
+  
+  result = CoCreateInstance(&CLSID_MMDeviceEnumerator,
+      NULL, CLSCTX_INPROC_SERVER, &IID_IMMDeviceEnumerator, &device_enumerator);
+  if (FAILED(result) || device_enumerator == NULL)
+    goto done;
+  
+  result = IMMDeviceEnumerator_GetDefaultAudioEndpoint(device_enumerator, eRender, eConsole, &device);
+  if (FAILED(result) || device == NULL)
+    goto done;
+  
+  result = IMMDevice_Activate(device, &IID_IAudioSessionManager, CLSCTX_INPROC_SERVER, NULL, &audio_session_manager);
+  if (FAILED(result) || audio_session_manager == NULL)
+    goto done;
+  result = IAudioSessionManager_GetSimpleAudioVolume(audio_session_manager, &GUID_NULL, 0, &simple_audio_volume);
+
+done:
+  if (device_enumerator) IMMDeviceEnumerator_Release(device_enumerator);
+  if (device) IMMDevice_Release(device);
+  if (audio_session_manager) IAudioSessionManager_Release(audio_session_manager);
+
+  return simple_audio_volume;
+}
--- /dev/null
+++ b/src/platform/win32/volume_control.h
@@ -1,0 +1,14 @@
+#ifndef ZELDA3_PLATFORM_WIN32_VOLUME_CONTROL_H_
+#define ZELDA3_PLATFORM_WIN32_VOLUME_CONTROL_H_
+
+#include <stdbool.h>
+
+#ifndef SYSTEM_VOLUME_MIXER_AVAILABLE
+#define SYSTEM_VOLUME_MIXER_AVAILABLE 1
+#endif  // SYSTEM_VOLUME_MIXER_AVAILABLE
+
+int GetApplicationVolume();
+bool SetApplicationVolume(int volume_level);
+bool SetApplicationMuted(bool muted);
+
+#endif // ZELDA3_PLATFORM_WIN32_VOLUME_CONTROL_H_
--- /dev/null
+++ b/src/platform/win32/zelda3.rc
@@ -1,0 +1,71 @@
+// Microsoft Visual C++ generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "winres.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (United States) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE 
+BEGIN
+    "src\\platform\\win32\\resource.h\0"
+END
+
+2 TEXTINCLUDE 
+BEGIN
+    "#include ""winres.h""\r\n"
+    "\0"
+END
+
+3 TEXTINCLUDE 
+BEGIN
+    "\r\n"
+    "\0"
+END
+
+#endif    // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+IDI_ICON1               ICON                    "src\\platform\\win32\\triforce.ico"
+
+#endif    // English (United States) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif    // not APSTUDIO_INVOKED
+
--- /dev/null
+++ b/src/player.c
@@ -1,0 +1,6664 @@
+#include "player.h"
+#include "zelda_rtl.h"
+#include "variables.h"
+#include "tile_detect.h"
+#include "ancilla.h"
+#include "sprite.h"
+#include "load_gfx.h"
+#include "hud.h"
+#include "overworld.h"
+#include "tagalong.h"
+#include "dungeon.h"
+#include "misc.h"
+#include "player_oam.h"
+#include "sprite_main.h"
+
+static bool g_ApplyLinksMovementToCamera_called;
+
+static const uint8 kSpinAttackDelays[] = { 1, 0, 0, 0, 0, 3, 0, 0, 1, 0, 3, 3, 3, 3, 4, 4, 1, 5 };
+static const uint8 kFireBeamSounds[] = { 1, 2, 3, 4, 0, 9, 18, 27 };
+static const int8 kTagalongArr1[] = { -1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+static const int8 kTagalongArr2[] = { -1, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+static const uint8 kLinkSpinGraphicsByDir[] = {
+  10, 11, 10, 6, 7, 8, 9, 2, 3, 4, 5, 10, 0, 1, 0, 2, 3, 4, 5, 6, 7, 8, 9, 0, 12, 13, 12, 4, 5, 6, 7, 8, 9, 2, 3, 12, 14, 15, 14, 8, 9, 2, 3, 4, 5, 6, 7, 14
+};
+static const uint8 kLinkSpinDelays[] = { 1, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5 };
+static const uint8 kGrabWallDirs[] = { 4, 8, 1, 2 };
+static const uint8 kGrabWall_AnimSteps[] = { 0, 1, 2, 3, 1, 2, 3 };
+static const uint8 kGrabWall_AnimTimer[] = { 0, 5, 5, 12, 5, 5, 12 };
+static const uint8 kCapeDepletionTimers[] = { 4, 8, 8 };
+static const int8 kAvoidJudder1[] = { 0, 1, 2, 3, 4, 5, 6, 7, 7, 6, 5, 4, 3, 2, 1, 0, 7, 6, 5, 4, 3, 2, 1, 0, 0, 1, 2, 3, 4, 5, 6, 7 };
+static const int8 kLink_DoMoveXCoord_Outdoors_Helper2_y[2] = { -8, 8 };
+static const int8 kLink_DoMoveXCoord_Outdoors_Helper2_y2[2] = { -16, 16 };
+static const uint8 kLink_DoMoveXCoord_Outdoors_Helper2_velz[8] = { 32, 32, 32, 40, 48, 56, 64, 72 };
+static const uint8 kLink_DoMoveXCoord_Outdoors_Helper2_velx[8] = { 16, 28, 28, 28, 28, 28, 28, 28 };
+static const uint8 kLink_Lift_tab[9] = { 0x54, 0x52, 0x50, 0xFF, 0x51, 0x53, 0x55, 0x56, 0x57 };
+static const uint8 kLink_Move_Helper6_tab0[] = { 8, 8, 23, 23, 8, 23, 8, 23 };
+static const uint8 kLink_Move_Helper6_tab1[] = { 0, 15, 0, 15, 0, 0, 15, 15 };
+static const uint8 kLink_Move_Helper6_tab2[] = { 23, 23, 8, 8, 8, 23, 8, 23 };
+static const uint8 kLink_Move_Helper6_tab3[] = { 0, 15, 0, 15, 15, 15, 0, 0 };
+const uint8 kSwimmingTab1[4] = { 2, 0, 1, 0 };
+const uint8 kSwimmingTab2[2] = { 32, 8 };
+static PlayerHandlerFunc *const kPlayerHandlers[31] = {
+  &LinkState_Default,
+  &LinkState_Pits,
+  &LinkState_Recoil,
+  &LinkState_SpinAttack,
+  &PlayerHandler_04_Swimming,
+  &LinkState_OnIce,
+  &LinkState_Recoil,
+  &LinkState_Zapped,
+  &LinkState_UsingEther,
+  &LinkState_UsingBombos,
+  &LinkState_UsingQuake,
+  &LinkHop_HoppingSouthOW,
+  &LinkState_HoppingHorizontallyOW,
+  &LinkState_HoppingDiagonallyUpOW,
+  &LinkState_HoppingDiagonallyDownOW,
+  &LinkState_0F,
+  &LinkState_0F,
+  &LinkState_Dashing,
+  &LinkState_ExitingDash,
+  &LinkState_Hookshotting,
+  &LinkState_CrossingWorlds,
+  &PlayerHandler_15_HoldItem,
+  &LinkState_Sleeping,
+  &PlayerHandler_17_Bunny,
+  &LinkState_HoldingBigRock,
+  &LinkState_ReceivingEther,
+  &LinkState_ReceivingBombos,
+  &LinkState_ReadingDesertTablet,
+  &LinkState_TemporaryBunny,
+  &LinkState_TreePull,
+  &LinkState_SpinAttack,
+};
+// forwards
+static const uint8 kLinkItem_MagicCosts[] = { 16, 8, 4, 32, 16, 8, 8, 4, 2, 8, 4, 2, 8, 4, 2, 16, 8, 4, 4, 2, 2, 8, 4, 2, 16, 8, 4 };
+static const uint8 kBombosAnimDelays[] = { 5, 5, 5, 5, 5, 5, 5, 5, 3, 3, 3, 3, 3, 7, 1, 1, 1, 1, 1, 13 };
+static const uint8 kBombosAnimStates[] = { 0, 1, 2, 3, 0, 1, 2, 3, 8, 9, 10, 11, 12, 10, 8, 13, 14, 15, 16, 17 };
+static const uint8 kEtherAnimDelays[] = { 5, 5, 5, 5, 5, 5, 5, 5, 7, 7, 3, 3 };
+static const uint8 kEtherAnimDelaysNoFlash[] = { 5, 5, 5, 5, 5, 5, 5, 5, 7, 7, 24, 24 };
+static const uint8 kEtherAnimStates[] = { 0, 1, 2, 3, 0, 1, 2, 3, 4, 5, 6, 7 };
+static const uint8 kQuakeAnimDelays[] = { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 19 };
+static const uint8 kQuakeAnimStates[] = { 0, 1, 2, 3, 0, 1, 2, 3, 18, 19, 20, 22 };
+static inline uint8 BitSum4(uint8 t);
+static inline uint8 BitSum4(uint8 t) {
+  return (t & 1) + ((t >> 1) & 1) + ((t >> 2) & 1) + ((t >> 3) & 1);
+}
+
+void Dungeon_HandleLayerChange() {  // 81ff05
+  link_is_on_lower_level_mirror = 1;
+  if (kind_of_in_room_staircase == 0)
+    BYTE(dungeon_room_index) += 16;
+  if (kind_of_in_room_staircase != 2)
+    link_is_on_lower_level = 1;
+  about_to_jump_off_ledge = 0;
+  SetAndSaveVisitedQuadrantFlags();
+}
+
+void CacheCameraProperties() {  // 81ff28
+  BG2HOFS_copy2_cached = BG2HOFS_copy2;
+  BG2VOFS_copy2_cached = BG2VOFS_copy2;
+  link_y_coord_cached = link_y_coord;
+  link_x_coord_cached = link_x_coord;
+  room_scroll_vars_y_vofs1_cached = room_bounds_y.a0;
+  room_scroll_vars_y_vofs2_cached = room_bounds_y.a1;
+  room_scroll_vars_x_vofs1_cached = room_bounds_x.a0;
+  room_scroll_vars_x_vofs2_cached = room_bounds_x.a1;
+  up_down_scroll_target_cached = up_down_scroll_target;
+  up_down_scroll_target_end_cached = up_down_scroll_target_end;
+  left_right_scroll_target_cached = left_right_scroll_target;
+  left_right_scroll_target_end_cached = left_right_scroll_target_end;
+  camera_y_coord_scroll_low_cached = camera_y_coord_scroll_low;
+  camera_x_coord_scroll_low_cached = camera_x_coord_scroll_low;
+  quadrant_fullsize_x_cached = quadrant_fullsize_x;
+  quadrant_fullsize_y_cached = quadrant_fullsize_y;
+  link_quadrant_x_cached = link_quadrant_x;
+  link_quadrant_y_cached = link_quadrant_y;
+  link_direction_facing_cached = link_direction_facing;
+  link_is_on_lower_level_cached = link_is_on_lower_level;
+  link_is_on_lower_level_mirror_cached = link_is_on_lower_level_mirror;
+  is_standing_in_doorway_cahed = is_standing_in_doorway;
+  dung_cur_floor_cached = dung_cur_floor;
+}
+
+void CheckAbilityToSwim() {  // 81ffb6
+  if (!link_is_bunny_mirror && link_item_flippers)
+    return;
+  if (link_item_moon_pearl)
+    link_is_bunny_mirror = 0;
+  link_visibility_status = 0xc;
+  submodule_index = player_is_indoors ? 20 : 42;
+}
+
+void Link_Main() {  // 878000
+//  RunEmulatedFunc(0x878000, 0, 0, 0, true, true, -2, 0);
+//  return;
+
+
+
+  link_x_coord_prev = link_x_coord;
+  link_y_coord_prev = link_y_coord;
+  flag_unk1 = 0;
+  if (!flag_is_link_immobilized)
+    Link_ControlHandler();
+  HandleSomariaAndGraves();
+}
+
+void Link_ControlHandler() {  // 87807f
+  if (link_give_damage) {
+    if (link_cape_mode) {
+      link_give_damage = 0;
+      link_auxiliary_state = 0;
+      link_incapacitated_timer = 0;
+    } else {
+      if (!link_disable_sprite_damage) {
+        uint8 dmg = link_give_damage;
+        link_give_damage = 0;
+        if (ancilla_type[0] == 5 && player_handler_timer == 0 && link_delay_timer_spin_attack) {
+          ancilla_type[0] = 0;
+          flag_for_boomerang_in_place = 0;
+        }
+        if (countdown_for_blink == 0)
+          countdown_for_blink = 58;
+        Ancilla_Sfx2_Near(38);
+        number_of_times_hurt_by_sprites++;
+        uint8 new_dmg = link_health_current - dmg;
+        if (new_dmg == 0 || new_dmg >= 0xa8) {
+          mapbak_TM = TM_copy;
+          mapbak_TS = TS_copy;
+          saved_module_for_menu = main_module_index;
+          main_module_index = 18;
+          submodule_index = 1;
+          countdown_for_blink = 0;
+          link_hearts_filler = 0;
+          new_dmg = 0;
+        }
+        link_health_current = new_dmg;
+      }
+    }
+  }
+  if (link_player_handler_state)
+    Player_CheckHandleCapeStuff();
+  kPlayerHandlers[link_player_handler_state]();
+}
+
+void LinkState_Default() {  // 878109
+  CacheCameraPropertiesIfOutdoors();
+  if (Link_HandleBunnyTransformation()) {
+    if (link_player_handler_state == 23)
+      PlayerHandler_17_Bunny();
+    return;
+  }
+  fallhole_var2 = 0;
+  if (link_auxiliary_state)
+    HandleLink_From1D();
+  else
+    PlayerHandler_00_Ground_3();
+}
+
+void HandleLink_From1D() {  // 878130
+  link_item_in_hand = 0;
+  link_position_mode = 0;
+  link_debug_value_1 = 0;
+  link_debug_value_2 = 0;
+  link_var30d = 0;
+  link_var30e = 0;
+  some_animation_timer_steps = 0;
+  bitfield_for_a_button = 0;
+  button_mask_b_y &= ~0x40;
+  link_state_bits = 0;
+  link_picking_throw_state = 0;
+  link_grabbing_wall = 0;
+  bitmask_of_dragstate = 0;
+  Link_ResetSwimmingState();
+  link_cant_change_direction &= ~1;
+  link_z_coord &= 0xff;
+  if (link_electrocute_on_touch != 0) {
+    if (link_cape_mode)
+      Link_ForceUnequipCape_quietly();
+    Link_ResetSwordAndItemUsage();
+    link_disable_sprite_damage = 1;
+    player_handler_timer = 0;
+    link_delay_timer_spin_attack = 2;
+    link_animation_steps = 0;
+    link_direction &= ~0xf;
+    Ancilla_Sfx3_Near(43);
+    link_player_handler_state = 7;
+    LinkState_Zapped();
+  } else {
+    link_moving_against_diag_tile = 0;
+    link_player_handler_state = 2;
+    LinkState_Recoil();
+  }
+}
+
+void PlayerHandler_00_Ground_3() {  // 8781a0
+  g_ApplyLinksMovementToCamera_called = false;
+
+  link_z_coord = 0xffff;
+  link_actual_vel_z = 0xff;
+  link_recoilmode_timer = 0;
+
+  if (!Link_HandleToss()) {
+    Link_HandleAPress();
+    if ((link_state_bits | link_grabbing_wall) == 0 && link_unk_master_sword == 0 && link_player_handler_state != kPlayerState_StartDash) {
+      Link_HandleYItem();
+      // Ensure we're not handling potions. Things further
+      // down don't assume this and change the module indexes randomly.
+      // This also fixes a bug where bombos, ether, quake get aborted if you use spin attack at the same time.
+      if ((enhanced_features0 & kFeatures0_MiscBugFixes) && (
+          main_module_index == 14 && submodule_index != 2 ||
+          link_player_handler_state == kPlayerState_Bombos ||
+          link_player_handler_state == kPlayerState_Ether ||
+          link_player_handler_state == kPlayerState_Quake))
+        goto getout_clear_vel;
+      if (sram_progress_indicator != 0) {
+        Link_HandleSwordCooldown();
+        if (link_player_handler_state == 3)
+          goto getout_clear_vel;
+      }
+    }
+  }
+
+  Link_HandleCape_passive_LiftCheck();
+  if (link_incapacitated_timer) {
+    link_moving_against_diag_tile = 0;
+    link_var30d = 0;
+    link_var30e = 0;
+    some_animation_timer_steps = 0;
+    bitfield_for_a_button = 0;
+    link_picking_throw_state = 0;
+    link_state_bits = 0;
+    link_grabbing_wall = 0;
+    if (!(button_mask_b_y & 0x80))
+      link_cant_change_direction &= ~1;
+    Link_HandleRecoilAndTimer(false);
+    return;
+  }
+
+  if (link_unk_master_sword) {
+    link_direction = 0;
+  } else if (!link_is_transforming && (link_grabbing_wall & ~2) == 0 && (link_state_bits & 0x7f) == 0 &&
+             ((link_state_bits & 0x80) == 0 || (link_picking_throw_state & 1) == 0) && !link_item_in_hand && !link_position_mode &&
+             (button_b_frames >= 9 || (button_mask_b_y & 0x20) != 0 || (button_mask_b_y & 0x80) == 0)) {
+    // if_4
+
+    if (link_flag_moving) {
+      swimcoll_var9[0] = swimcoll_var9[1] = 0x180;
+      Link_HandleSwimMovements();
+      return;
+    }
+    ResetAllAcceleration();
+    uint8 dir;
+
+    if ((dir = (force_move_any_direction & 0xf)) == 0) {
+      if (link_grabbing_wall & 2)
+        goto endif_3;
+      if ((dir = (joypad1H_last & kJoypadH_AnyDir)) == 0) {
+        link_x_vel = 0;
+        link_y_vel = 0;
+        link_direction = 0;
+        link_direction_last = 0;
+        link_animation_steps = 0;
+        bitmask_of_dragstate &= ~0xf;
+        link_timer_push_get_tired = 32;
+        link_timer_jump_ledge = 19;
+        goto endif_3;
+      }
+    }
+    link_direction = dir;
+    if (dir != link_direction_last) {
+      link_direction_last = dir;
+      link_subpixel_x = link_subpixel_y = 0;
+      link_moving_against_diag_tile = 0;
+      bitmask_of_dragstate = 0;
+      link_timer_push_get_tired = 32;
+      link_timer_jump_ledge = 19;
+    }
+  }
+  // endif_3
+endif_3:
+  Link_HandleDiagonalCollision();
+  Link_HandleVelocity();
+  Link_HandleCardinalCollision();
+  Link_HandleMovingAnimation_FullLongEntry();
+  if (link_unk_master_sword) getout_clear_vel: {
+    link_y_vel = link_x_vel = 0;
+  }
+
+  fallhole_var1 = 0;
+
+  // HandleIndoorCameraAndDoors must not be called twice in the same frame,
+  // this might mess up camera positioning. For example when using spin attack
+  // in between bumpers.
+  if (g_ApplyLinksMovementToCamera_called && (enhanced_features0 & kFeatures0_MiscBugFixes))
+    return;
+
+  HandleIndoorCameraAndDoors();
+}
+
+bool Link_HandleBunnyTransformation() {  // 8782da
+  if (!link_timer_tempbunny)
+    return false;
+
+  if (!link_need_for_poof_for_transform) {
+    if (link_player_handler_state == kPlayerState_PermaBunny || link_player_handler_state == kPlayerState_TempBunny) {
+      link_timer_tempbunny = 0;
+      return false;
+    }
+    if (link_picking_throw_state & 2)
+      link_state_bits = 0;
+    uint8 bak = link_state_bits & 0x80;
+    Link_ResetProperties_A();
+    link_state_bits = bak;
+
+    for (int i = 4; i >= 0; i--) {
+      if (ancilla_type[i] == 0x30 || ancilla_type[i] == 0x31)
+        ancilla_type[i] = 0;
+    }
+    Link_CancelDash();
+    AncillaAdd_CapePoof(0x23, 4);
+    Ancilla_Sfx2_Near(0x14);
+    link_bunny_transform_timer = 20;
+    link_disable_sprite_damage = 1;
+    link_need_for_poof_for_transform = 1;
+    link_visibility_status = 12;
+  }
+  if (sign8(--link_bunny_transform_timer)) {
+    link_player_handler_state = kPlayerState_TempBunny;
+    link_is_bunny_mirror = 1;
+    link_is_bunny = 1;
+    LoadGearPalettes_bunny();
+    link_visibility_status = 0;
+    link_disable_sprite_damage = 0;
+    link_need_for_poof_for_transform = 0;
+  }
+  return true;
+}
+
+void LinkState_TemporaryBunny() {  // 878365
+  if (!link_timer_tempbunny) {
+    AncillaAdd_CapePoof(0x23, 4);
+    Ancilla_Sfx2_Near(0x15);
+    link_bunny_transform_timer = 32;
+    link_player_handler_state = 0;
+    Link_ResetProperties_C();
+    link_need_for_poof_for_transform = 0;
+    link_is_bunny = 0;
+    link_is_bunny_mirror = 0;
+    LoadActualGearPalettes();
+    link_need_for_poof_for_transform = 0;
+    LinkState_Default();
+  } else {
+    link_timer_tempbunny--;
+    PlayerHandler_17_Bunny();
+  }
+}
+
+void PlayerHandler_17_Bunny() {  // 8783a1
+  CacheCameraPropertiesIfOutdoors();
+  fallhole_var2 = 0;
+  if (!link_is_in_deep_water) {
+    if (link_auxiliary_state == 0) {
+      Link_TempBunny_Func2();
+      return;
+    }
+    if (link_item_moon_pearl)
+      link_is_bunny_mirror = 0;
+  }
+  LinkState_Bunny_recache();
+}
+
+void LinkState_Bunny_recache() {  // 8783c7
+  link_need_for_poof_for_transform = 0;
+  link_timer_tempbunny = 0;
+  if (link_item_moon_pearl) {
+    link_is_bunny = 0;
+    link_auxiliary_state = 0;
+  }
+  link_animation_steps = 0;
+  link_is_transforming = 0;
+  link_cant_change_direction = 0;
+  Link_ResetSwimmingState();
+  link_player_handler_state = kPlayerState_RecoilWall;
+  if (link_item_moon_pearl) {
+    link_player_handler_state = kPlayerState_Ground;
+    LoadActualGearPalettes();
+  }
+}
+
+void Link_TempBunny_Func2() {  // 8783fa
+  if (link_incapacitated_timer != 0) {
+    Link_HandleRecoilAndTimer(false);
+    return;
+  }
+  link_z_coord = 0xffff;
+  link_actual_vel_z = 0xff;
+  link_recoilmode_timer = 0;
+  if (link_flag_moving) {
+    swimcoll_var9[0] = swimcoll_var9[1] = 0x180;
+    Link_HandleSwimMovements();
+    return;
+  }
+
+  ResetAllAcceleration();
+  Link_HandleYItem();
+  uint8 dir;
+  if (!(dir = force_move_any_direction & 0xf) && !(dir = joypad1H_last & kJoypadH_AnyDir)) {
+    link_x_vel = link_y_vel = 0;
+    link_direction = link_direction_last = 0;
+    link_animation_steps = 0;
+    bitmask_of_dragstate &= ~9;
+    link_timer_push_get_tired = 32;
+    link_timer_jump_ledge = 19;
+  } else {
+    link_direction = dir;
+    if (dir != link_direction_last) {
+      link_direction_last = dir;
+      link_subpixel_x = 0;
+      link_subpixel_y = 0;
+      link_moving_against_diag_tile = 0;
+      bitmask_of_dragstate = 0;
+      link_timer_push_get_tired = 32;
+      link_timer_jump_ledge = 19;
+    }
+  }
+  Link_HandleDiagonalCollision();
+  Link_HandleVelocity();
+  Link_HandleCardinalCollision();
+  Link_HandleMovingAnimation_FullLongEntry();
+  fallhole_var1 = 0;
+  HandleIndoorCameraAndDoors();
+}
+
+void LinkState_HoldingBigRock() {  // 878481
+  if (link_auxiliary_state) {
+    link_item_in_hand = 0;
+    link_position_mode = 0;
+    link_debug_value_1 = 0;
+    link_debug_value_2 = 0;
+    link_var30d = 0;
+    link_var30e = 0;
+    some_animation_timer_steps = 0;
+    bitfield_for_a_button = 0;
+    link_state_bits = 0;
+    link_picking_throw_state = 0;
+    link_grabbing_wall = 0;
+    bitmask_of_dragstate = 0;
+    link_cant_change_direction &= ~1;
+    link_z_coord &= ~0xff;
+    if (link_electrocute_on_touch) {
+      Link_ResetSwordAndItemUsage();
+      link_disable_sprite_damage = 1;
+      player_handler_timer = 0;
+      link_delay_timer_spin_attack = 2;
+      link_animation_steps = 0;
+      link_direction &= ~0xf;
+      Ancilla_Sfx3_Near(43);
+      link_player_handler_state = kPlayerState_Electrocution;
+      LinkState_Zapped();
+    } else {
+      link_player_handler_state = kPlayerState_RecoilWall;
+      LinkState_Recoil();
+    }
+    return;
+  }
+
+  link_z_coord = 0xffff;
+  link_actual_vel_z = 0xff;
+  link_recoilmode_timer = 0;
+  if (link_incapacitated_timer) {
+    link_var30d = 0;
+    link_var30e = 0;
+    some_animation_timer_steps = 0;
+    bitfield_for_a_button = 0;
+    link_state_bits = 0;
+    link_picking_throw_state = 0;
+    link_grabbing_wall = 0;
+    if (!(button_mask_b_y & 0x80))
+      link_cant_change_direction &= ~1;
+    Link_HandleRecoilAndTimer(false);
+    return;
+  }
+
+  Link_HandleAPress();
+  if (!(joypad1H_last & kJoypadH_AnyDir)) {
+    link_y_vel = 0;
+    link_x_vel = 0;
+    link_direction = 0;
+    link_direction_last = 0;
+    link_animation_steps = 0;
+    bitmask_of_dragstate &= ~9;
+    link_timer_push_get_tired = 32;
+    link_timer_jump_ledge = 19;
+  } else {
+    link_direction = joypad1H_last & kJoypadH_AnyDir;
+    if (link_direction != link_direction_last) {
+      link_direction_last = link_direction;
+      link_subpixel_x = 0;
+      link_subpixel_y = 0;
+      link_moving_against_diag_tile = 0;
+      bitmask_of_dragstate = 0;
+      link_timer_push_get_tired = 32;
+      link_timer_jump_ledge = 19;
+    }
+  }
+  Link_HandleMovingAnimation_FullLongEntry();
+  fallhole_var1 = 0;
+  HandleIndoorCameraAndDoors();
+}
+
+void EtherTablet_StartCutscene() {  // 87855a
+  button_b_frames = 0xc0;
+  link_delay_timer_spin_attack = 0;
+  link_player_handler_state = kPlayerState_ReceivingEther;
+  link_disable_sprite_damage = 1;
+  flag_block_link_menu = 1;
+}
+
+void LinkState_ReceivingEther() {  // 878570
+  link_auxiliary_state = 0;
+  link_incapacitated_timer = 0;
+  link_give_damage = 0;
+  int i = --WORD(button_b_frames);
+  if (sign16(i)) {
+    button_b_frames = 0;
+    link_delay_timer_spin_attack = 0;
+  } else if (i == 0xbf) {
+    link_force_hold_sword_up = 1;
+  } else if (i == 160) {
+    uint16 x = link_x_coord, y = link_y_coord;
+    link_x_coord = 0x6b0;
+    link_y_coord = 0x37;
+    AncillaAdd_EtherSpell(0x18, 0);
+    link_x_coord = x, link_y_coord = y;
+  } else if (i == 0) {
+    AncillaAdd_FallingPrize(0x29, 0, 4);
+    flag_is_link_immobilized = 1;
+    flag_block_link_menu = 0;
+  }
+}
+
+void BombosTablet_StartCutscene() {  // 8785e5
+  button_b_frames = 0xe0;
+  link_delay_timer_spin_attack = 0;
+  link_player_handler_state = kPlayerState_ReceivingBombos;
+  link_disable_sprite_damage = 1;
+  flag_custom_spell_anim_active = 1;
+}
+
+void LinkState_ReceivingBombos() {  // 8785fb
+  link_auxiliary_state = 0;
+  link_incapacitated_timer = 0;
+  link_give_damage = 0;
+  int i = --WORD(button_b_frames);
+  if (sign16(i)) {
+    button_b_frames = 0;
+    link_delay_timer_spin_attack = 0;
+  } else if (i == 223) {
+    link_force_hold_sword_up = 1;
+  } else if (i == 160) {
+    uint16 x = link_x_coord, y = link_y_coord;
+    link_x_coord = 0x378;
+    link_y_coord = 0xeb0;
+    AncillaAdd_BombosSpell(0x19, 0);
+    link_x_coord = x, link_y_coord = y;
+  } else if (i == 0) {
+    AncillaAdd_FallingPrize(0x29, 5, 4);
+    flag_is_link_immobilized = 1;
+  }
+}
+
+void LinkState_ReadingDesertTablet() {  // 87867b
+  if (!--button_b_frames) {
+    link_player_handler_state = kPlayerState_Ground;
+    Link_PerformDesertPrayer();
+  }
+}
+
+void HandleSomariaAndGraves() {  // 878689
+  if (!player_is_indoors && link_something_with_hookshot) {
+    int i = 4;
+    do {
+      if (ancilla_type[i] == 0x24)
+        Gravestone_Move(i);
+    } while (--i >= 0);
+  }
+  int i = 4;
+  do {
+    if (ancilla_type[i] == 0x2C) {
+      SomariaBlock_HandlePlayerInteraction(i);
+      return;
+    }
+  } while (--i >= 0);
+}
+
+void LinkState_Recoil() {  // 8786b5
+  link_y_coord_safe_return_lo = link_y_coord;
+  link_y_coord_safe_return_hi = link_y_coord >> 8;
+  link_x_coord_safe_return_lo = link_x_coord;
+  link_x_coord_safe_return_hi = link_x_coord >> 8;
+  Link_HandleChangeInZVelocity();
+  link_cant_change_direction = 0;
+  draw_water_ripples_or_grass = 0;
+  if (!sign8(link_z_coord) || !sign8(link_actual_vel_z)) {
+    Link_HandleRecoilAndTimer(false);
+    return;
+  }
+  TileDetect_MainHandler(5);
+  if (tiledetect_deepwater & 1) {
+    link_player_handler_state = kPlayerState_Swimming;
+    Link_SetToDeepWater();
+    Link_ResetSwordAndItemUsage();
+    AncillaAdd_Splash(21, 0);
+    Link_HandleRecoilAndTimer(true);
+  } else {
+    if (++link_recoilmode_timer != 4) {
+      uint8 t = link_actual_vel_z_copy, s = link_recoilmode_timer;
+      do {
+        t >>= 1;
+      } while (!--s); // wtf?
+      link_actual_vel_z = t;
+    } else {
+      link_recoilmode_timer = 3;
+    }
+    Link_HandleRecoilAndTimer(false);
+  }
+}
+
+void Link_HandleRecoilAndTimer(bool jump_into_middle) {  // 878711
+  if (jump_into_middle)
+    goto lbl_jump_into_middle;
+
+  link_x_page_movement_delta = 0;
+  link_y_page_movement_delta = 0;
+  link_num_orthogonal_directions = 0;
+  Link_HandleRecoiling();  // not
+  if (--link_incapacitated_timer == 0) {
+    link_incapacitated_timer = 1;
+    int8 z;
+    z = link_z_coord & 0xfe;
+    if (z <= 0 && (int8)link_actual_vel_z < 0) {
+      if (link_auxiliary_state != 0) {
+        link_disable_sprite_damage = 0;
+        scratch_0 = link_player_handler_state;
+        if (link_player_handler_state != 6) {
+          button_b_frames = 0;
+          button_mask_b_y = 0;
+          link_delay_timer_spin_attack = 0;
+          link_spin_attack_step_counter = 0;
+        }
+        Link_SplashUponLanding();
+        if (!link_is_bunny_mirror || !link_is_in_deep_water) {
+          if (link_want_make_noise_when_dashed) {
+            link_want_make_noise_when_dashed = 0;
+            Ancilla_Sfx2_Near(33);
+          } else if (scratch_0 != 2 && link_player_handler_state != 4) {
+            Ancilla_Sfx2_Near(33);
+          }
+          if (link_player_handler_state == 4) {
+            Link_ForceUnequipCape_quietly();
+            if (player_is_indoors && scratch_0 != 2 && link_item_flippers) {
+              link_is_on_lower_level = 1;
+            }
+            AncillaAdd_Splash(21, 0);
+          }
+          TileDetect_MainHandler(0);
+          if (tiledetect_thick_grass & 1)
+            Ancilla_Sfx2_Near(26);
+          if (tiledetect_shallow_water & 1 && sound_effect_1 != 36)
+            Ancilla_Sfx2_Near(28);
+
+          if (tiledetect_deepwater & 1) {
+            link_player_handler_state = kPlayerState_Swimming;
+            Link_SetToDeepWater();
+            Link_ResetSwordAndItemUsage();
+            AncillaAdd_Splash(21, 0);
+          }
+
+          // OMG something jumps to here...
+lbl_jump_into_middle:
+          if (link_is_on_lower_level == 2)
+            link_is_on_lower_level = 0;
+          if (about_to_jump_off_ledge)
+            Dungeon_HandleLayerChange();
+        }
+        link_z_coord = 0;
+        link_auxiliary_state = 0;
+        link_speed_setting = 0;
+        link_cant_change_direction = 0;
+        link_item_in_hand = 0;
+        link_position_mode = 0;
+        player_handler_timer = 0;
+        link_disable_sprite_damage = 0;
+        link_electrocute_on_touch = 0;
+        link_actual_vel_x = 0;
+        link_actual_vel_y = 0;
+      }
+      link_animation_steps = 0;
+      link_incapacitated_timer = 0;
+    }
+  }
+
+  if (link_player_handler_state != 5 && link_incapacitated_timer >= 33) {
+    if (!sign8(--byte_7E02C5))
+      goto timer_running;
+    byte_7E02C5 = link_incapacitated_timer >> 4;
+  }
+
+  Flag67WithDirections();
+  if (link_player_handler_state != 6) {
+    Link_HandleDiagonalCollision();  // not
+    if ((link_direction & 3) == 0)
+      link_actual_vel_x = 0;
+    if ((link_direction & 0xc) == 0)
+      link_actual_vel_y = 0;
+  }
+  Link_MovePosition(); // not
+timer_running:
+  if (link_player_handler_state != 6) {
+    Link_HandleCardinalCollision(); // not
+    fallhole_var1 = 0;
+  }
+  HandleIndoorCameraAndDoors();
+  if (BYTE(link_z_coord) == 0 || BYTE(link_z_coord) >= 0xe0) {
+    Player_TileDetectNearby();
+    if ((tiledetect_pit_tile & 0xf) == 0xf) {
+      link_player_handler_state = kPlayerState_FallingIntoHole;
+      link_speed_setting = 4;
+    }
+  }
+  HIBYTE(link_z_coord) = 0;
+}
+
+void LinkState_OnIce() {  // 878872
+  assert(0);
+}
+
+void Link_HandleChangeInZVelocity() {  // 878926
+  Player_ChangeZ(link_player_handler_state == kPlayerState_TurtleRock ? 1 : 2);
+}
+
+void Player_ChangeZ(uint8 zd) {  // 878932
+  if (sign8(link_actual_vel_z)) {
+    if (!(uint8)link_z_coord)
+      return;
+    if (sign8(link_z_coord)) {
+      link_z_coord = 0xffff;
+      link_actual_vel_z = 0xff;
+      return;
+    }
+  }
+  link_actual_vel_z -= zd;
+}
+
+void LinkHop_HoppingSouthOW() {  // 87894e
+  link_last_direction_moved_towards = 1;
+  link_cant_change_direction = 0;
+  link_actual_vel_x = 0;
+  link_actual_vel_y = 0;
+  draw_water_ripples_or_grass = 0;
+  if (!link_incapacitated_timer && !link_actual_vel_z_mirror) {
+    Ancilla_Sfx2_Near(32);
+    LinkHop_FindTileToLandOnSouth();
+    if (!player_is_indoors)
+      link_is_on_lower_level = 2;
+  }
+  link_actual_vel_z = link_actual_vel_z_mirror;
+  link_actual_vel_z_copy = link_actual_vel_z_copy_mirror;
+  link_z_coord = link_z_coord_mirror;
+  link_actual_vel_z -= 2;
+  Link_MovePosition();
+  if (sign8(link_actual_vel_z)) {
+    if (link_actual_vel_z < 0xa0)
+      link_actual_vel_z = 0xa0;
+    if (link_z_coord >= 0xfff0) {
+      link_z_coord = 0;
+      Link_SplashUponLanding();
+      // This is the place that caused the water walking bug after bonk, 
+      // player_near_pit_state was not reset.
+      if (player_near_pit_state)
+        link_player_handler_state = kPlayerState_FallingIntoHole;
+      if (link_player_handler_state != kPlayerState_Swimming &&
+          link_player_handler_state != kPlayerState_FallingIntoHole && !link_is_in_deep_water)
+        Ancilla_Sfx2_Near(33);
+      link_disable_sprite_damage = 0;
+      allow_scroll_z = 0;
+      link_auxiliary_state = 0;
+      link_actual_vel_z = 0xff;
+      link_z_coord = 0xffff;
+      link_incapacitated_timer = 0;
+      if (!player_is_indoors)
+        link_is_on_lower_level = 0;
+    } else {
+      link_y_vel = link_z_coord_mirror - link_z_coord;
+    }
+  } else {
+    link_y_vel = link_z_coord_mirror - link_z_coord;
+  }
+  link_actual_vel_z_mirror = link_actual_vel_z;
+  link_actual_vel_z_copy_mirror = link_actual_vel_z_copy;
+  link_z_coord_mirror = link_z_coord;
+}
+
+void LinkState_HandlingJump() {  // 878a05
+  link_actual_vel_z = link_actual_vel_z_mirror;
+  link_actual_vel_z_copy = link_actual_vel_z_copy_mirror;
+  BYTE(link_z_coord) = link_z_coord_mirror;
+  link_actual_vel_z -= 2;
+  Link_MovePosition();
+  if (sign8(link_actual_vel_z)) {
+    if (link_actual_vel_z < 0xa0)
+      link_actual_vel_z = 0xa0;
+    if ((uint8)link_z_coord >= 0xf0) {
+      link_z_coord = 0;
+      if (link_player_handler_state == kPlayerState_FallOfLeftRightLedge || link_player_handler_state == kPlayerState_JumpOffLedgeDiag) {
+        TileDetect_MainHandler(0);
+        if (tiledetect_deepwater & 1) {
+          link_player_handler_state = kPlayerState_Swimming;
+          Link_SetToDeepWater();
+          Link_ResetSwordAndItemUsage();
+          AncillaAdd_Splash(21, 0);
+        } else if (tiledetect_pit_tile & 1) {
+          byte_7E005C = 9;
+          link_this_controls_sprite_oam = 0;
+          player_near_pit_state = 1;
+          link_player_handler_state = kPlayerState_FallingIntoHole;
+          goto after_pit;
+        }
+      }
+      Link_SplashUponLanding();
+      if (link_player_handler_state != kPlayerState_Swimming && !link_is_in_deep_water)
+        Ancilla_Sfx2_Near(33);
+after_pit:
+      if (link_player_handler_state != kPlayerState_Swimming || !link_is_bunny_mirror)
+        link_disable_sprite_damage = 0;
+
+      allow_scroll_z = 0;
+      link_auxiliary_state = 0;
+      link_actual_vel_z = 0xff;
+      link_z_coord = 0xffff;
+      link_incapacitated_timer = 0;
+      if (!player_is_indoors)
+        link_is_on_lower_level = 0;
+    } else {
+      link_y_vel = link_z_coord_mirror - link_z_coord;
+    }
+  } else {
+    link_y_vel = link_z_coord_mirror - link_z_coord;
+  }
+  link_actual_vel_z_mirror = link_actual_vel_z;
+  link_actual_vel_z_copy_mirror = link_actual_vel_z_copy;
+  BYTE(link_z_coord_mirror) = link_z_coord;
+}
+
+void LinkHop_FindTileToLandOnSouth() {  // 878ad1
+  link_y_coord_original = link_y_coord;
+  link_y_vel = link_y_coord - link_y_coord_safe_return_lo;
+  for (;;) {
+    link_y_coord += kLink_DoMoveXCoord_Outdoors_Helper2_y[link_last_direction_moved_towards];
+    TileDetect_Movement_Y(link_last_direction_moved_towards);
+    uint8 k = tiledetect_normal_tiles | tiledetect_pit_tile | tiledetect_destruction_aftermath | tiledetect_thick_grass | tiledetect_deepwater;
+    if ((k & 7) == 7)
+      break;
+  }
+  if (tiledetect_deepwater & 7) {
+    link_is_in_deep_water = 1;
+    if (link_auxiliary_state != 4)
+      link_auxiliary_state = 2;
+    link_some_direction_bits = link_direction_last;
+    Link_ResetSwimmingState();
+    link_grabbing_wall = 0;
+    link_speed_setting = 0;
+  }
+  if (tiledetect_pit_tile & 7) {
+    byte_7E005C = 9;
+    link_this_controls_sprite_oam = 0;
+    player_near_pit_state = 1;
+  }
+  link_y_coord += kLink_DoMoveXCoord_Outdoors_Helper2_y2[link_last_direction_moved_towards];
+  link_y_coord_safe_return_lo = link_y_coord;
+  link_y_coord_safe_return_hi = link_y_coord >> 8;
+  link_incapacitated_timer = 1;
+  uint8 z = link_z_coord;
+  if (z >= 0xf0)
+    z = 0;
+  link_z_coord = link_z_coord_mirror = link_y_coord - link_y_coord_original + z;
+}
+
+// used on right ledges
+void LinkState_HoppingHorizontallyOW() {  // 878b74
+  link_direction = sign8(link_actual_vel_x) ? 6 : 5;
+  link_cant_change_direction = 0;
+  link_actual_vel_y = 0;
+  draw_water_ripples_or_grass = 0;
+  LinkState_HandlingJump();
+}
+
+void Link_HoppingHorizontally_FindTile_Y() {  // 878b9b
+  link_y_coord_original = link_y_coord;
+  link_y_vel = link_y_coord - link_y_coord_safe_return_lo;
+
+  link_y_coord += kLink_DoMoveXCoord_Outdoors_Helper2_y[link_last_direction_moved_towards];
+  TileDetect_Movement_Y(link_last_direction_moved_towards);
+
+  uint8 tt = tiledetect_normal_tiles | tiledetect_destruction_aftermath | tiledetect_thick_grass |
+    tiledetect_deepwater;
+
+  if ((tt & 7) != 7) {
+    link_y_coord = link_y_coord_original;
+    link_incapacitated_timer = 1;
+
+    int8 velx = link_actual_vel_x, org_velx = velx;
+    if (velx < 0) velx = -velx;
+    velx >>= 4;
+    link_actual_vel_z_mirror = link_actual_vel_z_copy_mirror = kLink_DoMoveXCoord_Outdoors_Helper2_velz[velx];
+
+    uint8 xt = kLink_DoMoveXCoord_Outdoors_Helper2_velx[velx];
+    if (org_velx < 0) xt = -xt;
+    link_actual_vel_x = xt;
+  } else {  // else_1
+    link_y_coord += kLink_DoMoveXCoord_Outdoors_Helper2_y2[link_last_direction_moved_towards];
+    link_y_coord_safe_return_lo = link_y_coord;
+    link_y_coord_safe_return_hi = link_y_coord >> 8;
+    link_incapacitated_timer = 1;
+    uint8 z = link_z_coord;
+    if (z == 255) z = 0;
+    link_z_coord_mirror = link_z_coord = link_y_coord - link_y_coord_original + z;
+  }  // endif_1
+
+  if (tiledetect_deepwater & 7) {
+    link_auxiliary_state = 2;
+    Link_SetToDeepWater();
+  }
+}
+
+void Link_SetToDeepWater() {  // 878c44
+  link_is_in_deep_water = 1;
+  link_some_direction_bits = link_direction_last;
+  Link_ResetSwimmingState();
+  link_grabbing_wall = 0;
+  link_speed_setting = 0;
+}
+
+void LinkState_0F() {  // 878c69
+  assert(0);
+}
+
+uint8 Link_HoppingHorizontally_FindTile_X(uint8 o) {  // 878d2b
+  assert(o == 0 || o == 2);
+  link_y_coord_original = link_x_coord;
+  int i = 7;
+  static const int8 kLink_DoMoveXCoord_Outdoors_Helper1_tab1[2] = { -8, 8 };
+  static const int8 kLink_DoMoveXCoord_Outdoors_Helper1_tab2[2] = { -32, 32 };
+  static const int8 kLink_DoMoveXCoord_Outdoors_Helper1_tab3[2] = { -16, 16 };
+  static const uint8 kLink_DoMoveXCoord_Outdoors_Helper1_velx[24] = { 20, 20, 20, 24, 24, 24, 24, 28, 28, 36, 36, 36, 36, 36, 36, 38, 38, 38, 38, 38, 38, 38, 40, 40 };
+  static const uint8 kLink_DoMoveXCoord_Outdoors_Helper1_velz[24] = { 20, 20, 20, 20, 20, 20, 20, 24, 24, 32, 32, 32, 36, 36, 36, 38, 38, 38, 38, 38, 38, 38, 40, 40 };
+  do {
+    link_x_coord += kLink_DoMoveXCoord_Outdoors_Helper1_tab1[o >> 1];
+    TileDetect_Movement_X(link_last_direction_moved_towards);
+
+    uint8 tt = tiledetect_normal_tiles | tiledetect_destruction_aftermath | tiledetect_thick_grass |
+      tiledetect_deepwater | tiledetect_pit_tile;
+
+    if ((tt & 7) == 7) {
+      if ((tiledetect_deepwater & 7) == 7) {
+        link_is_in_deep_water = 1;
+        link_auxiliary_state = 2;
+        link_some_direction_bits = link_direction_last;
+        swimming_countdown = 0;
+        link_speed_setting = 0;
+        link_grabbing_wall = 0;
+        ResetAllAcceleration();
+      }
+      goto finish;
+    }
+  } while (--i >= 0);
+
+  link_x_coord = link_y_coord_original + kLink_DoMoveXCoord_Outdoors_Helper1_tab2[o >> 1];
+finish:
+  link_x_coord += kLink_DoMoveXCoord_Outdoors_Helper1_tab3[o >> 1];
+  int16 xt = link_y_coord_original - link_x_coord;
+  if (xt < 0) xt = -xt;
+  xt >>= 3;
+  uint8 velx = kLink_DoMoveXCoord_Outdoors_Helper1_velx[xt];
+  if (o != 2) velx = -velx;
+  link_actual_vel_x = velx;
+  link_actual_vel_z_mirror = link_actual_vel_z_copy_mirror = kLink_DoMoveXCoord_Outdoors_Helper1_velz[xt];
+
+  return i;
+}
+
+// used on diag ledges
+void LinkState_HoppingDiagonallyUpOW() {  // 878dc6
+  draw_water_ripples_or_grass = 0;
+  Player_ChangeZ(2);
+  Link_MovePosition();
+  if (sign8(link_z_coord)) {
+    Link_SplashUponLanding();
+    if (link_player_handler_state != kPlayerState_Swimming && !link_is_in_deep_water)
+      Ancilla_Sfx2_Near(33);
+    link_disable_sprite_damage = 0;
+    link_auxiliary_state = 0;
+    link_actual_vel_z = 0xff;
+    link_z_coord = 0xffff;
+    link_incapacitated_timer = 0;
+    link_cant_change_direction = 0;
+  }
+}
+
+void LinkState_HoppingDiagonallyDownOW() {  // 878e15
+  uint8 dir = sign8(link_actual_vel_x) ? 2 : 3;
+  link_last_direction_moved_towards = dir;
+  link_cant_change_direction = 0;
+  link_actual_vel_y = 0;
+  draw_water_ripples_or_grass = 0;
+  if (!link_incapacitated_timer && !link_actual_vel_z_mirror) {
+    link_last_direction_moved_towards = 1;
+    uint16 old_x = link_x_coord;
+    Ancilla_Sfx2_Near(32);
+    LinkHop_FindLandingSpotDiagonallyDown();
+    link_x_coord = old_x;
+
+    static const uint8 kLedgeVelX[] = { 
+      4, 4, 4, 10, 10, 10, 11, 18,
+      18, 18, 20, 20, 20, 20, 22, 22,
+      26, 26, 26, 26, 28, 28, 28, 28
+    };
+
+    int t = (uint16)(link_y_coord - link_y_coord_original);
+    // Fix out of bounds read
+    int8 velx = kLedgeVelX[IntMin(t >> 3, 23)];
+    link_actual_vel_x = (dir != 2) ? velx : -velx;
+    if (!player_is_indoors)
+      link_is_on_lower_level = 2;
+  }
+  LinkState_HandlingJump();
+}
+
+void LinkHop_FindLandingSpotDiagonallyDown() {  // 878e7b
+  static const int8 kLink_Ledge_Func1_dx[2] = { -8, 8 };
+  static const int8 kLink_Ledge_Func1_dy[2] = { -9, 9 };
+  static const uint8 kLink_Ledge_Func1_bits[2] = { 6, 3 };
+  static const int8 kLink_Ledge_Func1_dy2[2] = { -24, 24 };
+  link_y_coord_original = link_y_coord;
+  link_y_vel = link_y_coord - link_y_coord_safe_return_lo;
+
+  uint8 scratch;
+  for (;;) {
+    int o = sign8(link_actual_vel_x) ? 0 : 1;
+
+    link_x_coord += kLink_Ledge_Func1_dx[o];
+    link_y_coord += kLink_Ledge_Func1_dy[link_last_direction_moved_towards];
+    TileDetect_Movement_Y(link_last_direction_moved_towards);
+    scratch = kLink_Ledge_Func1_bits[o];
+    uint8 k = tiledetect_normal_tiles | tiledetect_destruction_aftermath | tiledetect_thick_grass | tiledetect_deepwater;
+    if ((k & scratch) == scratch)
+      break;
+  }
+
+  if (tiledetect_deepwater & scratch) {
+    link_is_in_deep_water = 1;
+    link_auxiliary_state = 2;
+    link_some_direction_bits = link_direction_last;
+    Link_ResetSwimmingState();
+    link_speed_setting = 0;
+    link_grabbing_wall = 0;
+  }
+
+  link_y_coord += kLink_Ledge_Func1_dy2[link_last_direction_moved_towards];
+  link_y_coord_safe_return_lo = link_y_coord;
+  link_y_coord_safe_return_hi = link_y_coord >> 8;
+  link_incapacitated_timer = 1;
+  link_z_coord_mirror = link_y_coord - link_y_coord_original + (uint8)link_z_coord;
+  link_z_coord = link_z_coord_mirror;
+}
+
+void Link_SplashUponLanding() {  // 878f1d
+  if (link_is_bunny_mirror) {
+    if (link_is_in_deep_water) {
+      AncillaAdd_Splash(21, 0);
+      LinkState_Bunny_recache();
+      return;
+    }
+    link_player_handler_state = (link_item_moon_pearl) ? kPlayerState_TempBunny : kPlayerState_PermaBunny;
+  } else if (link_is_in_deep_water) {
+    if (link_player_handler_state != kPlayerState_RecoilOther)
+      AncillaAdd_Splash(21, 0);
+    Link_ForceUnequipCape_quietly();
+    link_player_handler_state = kPlayerState_Swimming;
+  } else {
+    link_player_handler_state = kPlayerState_Ground;
+  }
+}
+
+void LinkState_Dashing() {  // 878f86
+  CacheCameraPropertiesIfOutdoors();
+  if (Link_HandleBunnyTransformation()) {
+    if (link_player_handler_state == 23)
+      PlayerHandler_17_Bunny();
+    return;
+  }
+  if (!link_is_running) {
+    link_disable_sprite_damage = 0;
+    link_countdown_for_dash = 0;
+    link_speed_setting = 0;
+    link_player_handler_state = kPlayerState_Ground;
+    link_cant_change_direction = 0;
+    return;
+  }
+
+  if (button_mask_b_y & 0x80) {
+    if (button_b_frames >= 9)
+      button_b_frames = 9;
+  }
+  fallhole_var2 = 0;
+
+  if (link_auxiliary_state) {
+    link_disable_sprite_damage = 0;
+    link_countdown_for_dash = 0;
+    link_speed_setting = 0;
+    link_cant_change_direction = 0;
+    link_is_running = 0;
+    bitmask_of_dragstate = 0;
+    if (link_electrocute_on_touch) {
+      if (link_cape_mode)
+        Link_ForceUnequipCape_quietly();
+      Link_ResetSwordAndItemUsage();
+      link_disable_sprite_damage = 1;
+      player_handler_timer = 0;
+      link_delay_timer_spin_attack = 2;
+      link_animation_steps = 0;
+      link_direction &= ~0xf;
+      Ancilla_Sfx3_Near(43);
+      link_player_handler_state = kPlayerState_Electrocution;
+      LinkState_Zapped();
+    } else {
+      link_player_handler_state = kPlayerState_RecoilWall;
+      LinkState_Recoil();
+    }
+    return;
+  }
+  static const uint8 kDashTab1[] = { 7, 15, 15 };
+  static const uint8 kDashTab2[] = { 8, 4, 2, 1 };
+  uint8 a = link_countdown_for_dash;
+  if (a == 0)
+    a = index_of_dashing_sfx--;
+  if (!(kDashTab1[link_countdown_for_dash >> 4] & a))
+    Ancilla_Sfx2_Near(35);
+  if (sign8(--link_countdown_for_dash)) {
+    link_countdown_for_dash = 0;
+    if (follower_indicator == kTagalongArr1[follower_indicator])
+      follower_indicator = kTagalongArr2[follower_indicator];
+  } else {
+    index_of_dashing_sfx = 0;
+    if (!(joypad1L_last & kJoypadL_A)) {
+      link_animation_steps = 0;
+      link_countdown_for_dash = 0;
+      link_speed_setting = 0;
+      link_player_handler_state = kPlayerState_Ground;
+      link_is_running = 0;
+      if (!(button_mask_b_y & 0x80))
+        link_cant_change_direction = 0;
+      return;
+    }
+    AncillaAdd_DashDust_charging(30, 0);
+    link_x_vel = link_y_vel = 0;
+    link_dash_ctr = 64;
+    link_speed_setting = 16;
+    uint8 dir;
+    if (button_mask_b_y & 0x80 || is_standing_in_doorway || (dir = joypad1H_last & kJoypadH_AnyDir) == 0)
+      dir = kDashTab2[link_direction_facing >> 1];
+    link_some_direction_bits = link_direction = link_direction_last = dir;
+    link_moving_against_diag_tile = 0;
+    Link_HandleMovingAnimation_FullLongEntry();
+    uint16 org_x = link_x_coord, org_y = link_y_coord;
+    link_y_coord_safe_return_lo = link_y_coord;
+    link_y_coord_safe_return_hi = link_y_coord >> 8;
+    link_x_coord_safe_return_lo = link_x_coord;
+    link_x_coord_safe_return_hi = link_x_coord >> 8;
+    Link_HandleMovingFloor();
+    Link_ApplyConveyor();
+    if (player_on_somaria_platform)
+      Link_HandleVelocityAndSandDrag(org_x, org_y);
+    link_y_vel = link_y_coord - link_y_coord_safe_return_lo;
+    link_x_vel = link_x_coord - link_x_coord_safe_return_lo;
+    Link_HandleCardinalCollision();
+    HandleIndoorCameraAndDoors();
+    return;
+  }
+
+  if (link_animation_steps >= 6)
+    link_animation_steps = 0;
+
+  link_dash_ctr--;
+  if (link_dash_ctr < 32)
+    link_dash_ctr = 32;
+
+  AncillaAdd_DashDust(30, 0);
+  link_spin_attack_step_counter = 0;
+
+  if ((uint8)(link_sword_type + 1) & 0xfe)
+    TileDetect_MainHandler(7);
+
+  if (sram_progress_indicator) {
+    button_mask_b_y |= 0x80;
+    button_b_frames = 9;
+  }
+
+  link_incapacitated_timer = 0;
+
+  bool want_stop_dash = false;
+
+  if (enhanced_features0 & kFeatures0_TurnWhileDashing) {
+    if (!(joypad1L_last & kJoypadL_A)) {
+      link_countdown_for_dash = 0x11;
+      want_stop_dash = true;
+    } else {
+      static const uint8 kDashCtrlsToDir[16] = { 0, 1, 2, 0, 4, 4, 4, 0, 8, 8, 8, 0, 0, 0, 0, 0 };
+      uint8 t = kDashCtrlsToDir[joypad1H_last & kJoypadH_AnyDir];
+      if (t != 0 && t != link_direction_last) {
+        link_direction = link_direction_last = t;
+        link_some_direction_bits = t;
+        Link_HandleMovingAnimation_FullLongEntry();
+      }
+    }
+  } else {
+    want_stop_dash = (joypad1H_last & kJoypadH_AnyDir) && (joypad1H_last & kJoypadH_AnyDir) != kDashTab2[link_direction_facing >> 1];
+  }
+
+  if (want_stop_dash) {
+    link_player_handler_state = kPlayerState_StopDash;
+    button_mask_b_y &= ~0x80;
+    button_b_frames = 0;
+    link_delay_timer_spin_attack = 0;
+    LinkState_ExitingDash();
+    return;
+  }
+
+  if (link_speed_setting == 0 && (enhanced_features0 & kFeatures0_TurnWhileDashing))
+    link_speed_setting = 16;
+
+  uint8 dir = force_move_any_direction & 0xf;
+  if (dir == 0)
+    dir = kDashTab2[link_direction_facing >> 1];
+  link_direction = link_direction_last = dir;
+  Link_HandleDiagonalCollision();
+  Link_HandleVelocity();
+  Link_HandleCardinalCollision();
+  Link_HandleMovingAnimation_FullLongEntry();
+  fallhole_var1 = 0;
+  HandleIndoorCameraAndDoors();
+}
+
+void LinkState_ExitingDash() {  // 87915e
+  CacheCameraPropertiesIfOutdoors();
+  if (joypad1H_last & kJoypadH_AnyDir || link_countdown_for_dash >= 16) {
+    link_countdown_for_dash = 0;
+    link_speed_setting = 0;
+    link_player_handler_state = kPlayerState_Ground;
+    link_is_running = 0;
+    swimcoll_var5[0] &= 0xff00;
+    if (button_b_frames < 9)
+      link_cant_change_direction = 0;
+  } else {
+    link_countdown_for_dash++;
+  }
+  Link_HandleMovingAnimation_FullLongEntry();
+}
+
+void Link_CancelDash() {  // 879195
+  if (link_is_running) {
+    int i = 4;
+    do {
+      if (ancilla_type[i] == 0x1e)
+        ancilla_type[i] = 0;
+    } while (--i >= 0);
+    link_countdown_for_dash = 0;
+    link_speed_setting = 0;
+    link_is_running = 0;
+    link_cant_change_direction = 0;
+    swimcoll_var5[0] = 0;
+  }
+}
+
+void RepelDash() {  // 8791f1
+  if (link_is_running && link_dash_ctr != 64) {
+    Link_ResetSwimmingState();
+    AncillaAdd_DashTremor(29, 1);
+    Prepare_ApplyRumbleToSprites();
+    if ((sound_effect_2 & 0x3f) != 27 && (sound_effect_2 & 0x3f) != 50)
+      Ancilla_Sfx3_Near(3);
+    LinkApplyTileRebound();
+  }
+}
+
+void LinkApplyTileRebound() {  // 879222
+  static const int8 kDashTab6Y[] = { 24, -24, 0, 0 };
+  static const int8 kDashTab6X[] = { 0, 0, 24, -24 };
+  static const int8 kDashTabSw11Y[] = { 1, 0, 0, 0 };
+  static const int8 kDashTabSw11X[] = { 0, 0, 1, 0 };
+  static const uint16 kDashTabSw7Y[] = { 384, 384, 0, 0, 256, 256, 0, 0 };
+  static const uint16 kDashTabSw7X[] = { 0, 0, 384, 384, 0, 0, 256, 256 };
+  static const uint8 kDashTabDir[] = { 8,4,2,1 };
+
+  link_actual_vel_y = kDashTab6Y[link_last_direction_moved_towards];
+  link_actual_vel_x = kDashTab6X[link_last_direction_moved_towards];
+  link_incapacitated_timer = 24;
+  link_actual_vel_z = link_actual_vel_z_copy = 36;
+  if (link_flag_moving) {
+    link_some_direction_bits = link_direction = kDashTabDir[link_last_direction_moved_towards];
+    swimcoll_var11[0] = kDashTabSw11Y[link_last_direction_moved_towards];
+    swimcoll_var11[1] = kDashTabSw11X[link_last_direction_moved_towards];
+
+    int i = (link_flag_moving - 1) * 4 + link_last_direction_moved_towards;
+    swimcoll_var7[0] = kDashTabSw7Y[i];
+    swimcoll_var7[1] = kDashTabSw7X[i];
+  }
+  link_auxiliary_state = 1;
+  link_want_make_noise_when_dashed = 1;
+  BYTE(scratch_1) = 0;
+  link_electrocute_on_touch = 0;
+  link_speed_setting = 0;
+  link_cant_change_direction = 0;
+  link_moving_against_diag_tile = 0;
+  if (link_last_direction_moved_towards & 2)
+    link_y_vel = 0;
+  else
+    link_x_vel = 0;
+}
+
+void Sprite_RepelDash() {  // 879291
+  link_last_direction_moved_towards = link_direction_facing >> 1;
+  RepelDash();
+}
+
+void Flag67WithDirections() {  // 8792a0
+  link_direction = 0;
+  if (link_actual_vel_y)
+    link_direction |= sign8(link_actual_vel_y) ? 8 : 4;
+  if (link_actual_vel_x)
+    link_direction |= sign8(link_actual_vel_x) ? 2 : 1;
+}
+
+void LinkState_Pits() {  // 8792d3
+  link_direction = 0;
+  if (fallhole_var1 && ++fallhole_var2 == 0x20) {
+    fallhole_var2 = 31;
+  } else {
+    if (!link_is_running)
+      goto aux_state;
+    // If you use a turbo controller to perfectly spam the dash button,
+    // the check for Link being in a hole is endlessly skipped and you
+    // can levitate across chasms.
+    // Fix this by ensuring that the dash button is held down before proceeding to the dash state.
+    if (link_countdown_for_dash &&
+        (!(enhanced_features0 & kFeatures0_MiscBugFixes) || (joypad1L_last & kJoypadL_A))) {
+      LinkState_Dashing();
+      return;
+    }
+    if (joypad1H_last & kJoypadH_AnyDir && !(joypad1H_last & kJoypadH_AnyDir & link_direction)) {
+      Link_CancelDash();
+aux_state:
+      if (link_auxiliary_state != 1)
+        link_direction = joypad1H_last & kJoypadH_AnyDir;
+    }
+  }
+  TileDetect_MainHandler(4);
+  if (!(tiledetect_pit_tile & 1)) {
+    // Reset player_near_pit_state if we're no longer near a hole.
+    // This fixes a bug where you could walk on water
+    if (enhanced_features0 & kFeatures0_MiscBugFixes)
+      player_near_pit_state = 0;
+
+    if (link_is_running) {
+      LinkState_Dashing();
+      return;
+    }
+    link_speed_setting = 0;
+    Link_CancelDash();
+    if (!(button_mask_b_y & 0x80))
+      link_cant_change_direction &= ~1;
+    player_near_pit_state = 0;
+    link_player_handler_state = !link_is_bunny_mirror ? kPlayerState_Ground :
+      link_item_moon_pearl ? kPlayerState_TempBunny : kPlayerState_PermaBunny;
+    if (link_player_handler_state == kPlayerState_PermaBunny)
+      PlayerHandler_17_Bunny();
+    else if (link_player_handler_state == kPlayerState_TempBunny)
+      LinkState_TemporaryBunny();
+    else
+      LinkState_Default();
+    return;
+  }
+
+  Player_TileDetectNearby();
+  link_speed_setting = 4;
+  if (!(tiledetect_pit_tile & 0xf)) {
+    player_near_pit_state = 0;
+    link_speed_setting = 0;
+    link_player_handler_state = !link_is_bunny_mirror ? kPlayerState_Ground :
+      link_item_moon_pearl ? kPlayerState_TempBunny : kPlayerState_PermaBunny;
+    Link_CancelDash();
+    if (!(button_mask_b_y & 0x80))
+      link_cant_change_direction &= ~1;
+    return;
+  }
+
+  static const uint8 kFallHolePitDirs[] = { 12, 3, 10, 5 };
+  static const uint8 kFallHoleDirs[] = { 5, 6, 9, 10, 4, 8, 1, 2 };
+  static const uint8 kFallHoleDirs2[] = { 10, 9, 6, 5, 8, 4, 2, 1 };
+
+  if ((tiledetect_pit_tile & 0xf) != 0xf) {
+    int i = 3;
+    do {
+      if ((tiledetect_pit_tile & 0xf) == kFallHolePitDirs[i]) {
+        i += 4;
+        goto endif_1;
+      }
+    } while (--i >= 0);
+
+    i = 3;
+    uint8 pit_tile;
+    pit_tile= tiledetect_pit_tile;
+    while (!(pit_tile & 1)) {
+      i -= 1;
+      pit_tile >>= 1;
+    }
+    assert(i >= 0);
+endif_1:
+    byte_7E02C9 = i;
+    if (link_direction & kFallHoleDirs[i]) {
+      link_direction_last = link_direction;
+      link_speed_setting = 6;
+      Link_HandleMovingAnimation_FullLongEntry();
+    } else {
+      uint8 old_dir = link_direction;
+      link_direction |= kFallHoleDirs2[byte_7E02C9];
+      if (old_dir)
+        Link_HandleMovingAnimation_FullLongEntry();
+    }
+    Link_HandleDiagonalCollision();
+    Link_HandleVelocity();
+    Link_HandleCardinalCollision();
+    ApplyLinksMovementToCamera();
+    return;
+  }
+
+  // Initiate fall down
+  if (player_near_pit_state != 2) {
+    if (link_item_moon_pearl) {
+      link_need_for_poof_for_transform = 0;
+      link_is_bunny = 0;
+      link_is_bunny_mirror = 0;
+      link_timer_tempbunny = 0;
+    }
+    link_direction = 0;
+    player_near_pit_state = 2;
+    link_disable_sprite_damage = 1;
+    button_mask_b_y = 0;
+    button_b_frames = 0;
+    link_item_in_hand = 0;
+    link_position_mode = 0;
+    link_incapacitated_timer = 0;
+    link_auxiliary_state = 0;
+    Ancilla_Sfx3_Near(31);
+  }
+
+  link_cant_change_direction = 0;
+  link_incapacitated_timer = 0;
+  link_z_coord = 0;
+  link_actual_vel_z = 0;
+  link_auxiliary_state = 0;
+  link_give_damage = 0;
+  link_is_transforming = 0;
+  Link_ForceUnequipCape_quietly();
+  link_disable_sprite_damage++;
+  if (!sign8(--byte_7E005C))
+    return;
+  uint8 x = ++link_this_controls_sprite_oam;
+  byte_7E005C = 9;
+  if (follower_indicator != 13 && x == 1)
+    tagalong_var5 = x;
+
+  if (x == 6) {
+    Link_CancelDash();
+    submodule_index = 7;
+    link_this_controls_sprite_oam = 6;
+    player_near_pit_state = 3;
+    link_visibility_status = 12;
+    link_speed_modifier = 16;
+    uint16 y = (uint8)(link_y_coord - BG2VOFS_copy2);
+    link_state_bits = 0;
+    link_picking_throw_state = 0;
+    link_grabbing_wall = 0;
+    some_animation_timer = 0;
+    if (player_is_indoors) {
+      BYTE(dungeon_room_index_prev) = dungeon_room_index;
+      Dungeon_FlagRoomData_Quadrants();
+      if (Dungeon_IsPitThatHurtsPlayer()) {
+        DungeonPitDoDamage();
+        return;
+      }
+    }
+    BYTE(dungeon_room_index_prev) = dungeon_room_index;
+    BYTE(dungeon_room_index) = dung_hdr_travel_destinations[0];
+    tiledetect_which_y_pos[0] = link_y_coord;
+    link_y_coord = link_y_coord - y - 0x10;
+    if (player_is_indoors) {
+      HandleLayerOfDestination();
+    } else {
+      if ((uint8)overworld_screen_index != 5) {
+        Overworld_GetPitDestination();
+        main_module_index = 17;
+        submodule_index = 0;
+        subsubmodule_index = 0;
+      } else {
+        TakeDamageFromPit();
+      }
+    }
+  }
+}
+
+void HandleLayerOfDestination() {  // 8794f1
+  link_is_on_lower_level_mirror = (dung_hdr_hole_teleporter_plane >= 1);
+  link_is_on_lower_level = (dung_hdr_hole_teleporter_plane >= 2);
+}
+
+void DungeonPitDoDamage() {  // 879502
+  submodule_index = 20;
+  link_health_current -= 8;
+  if (link_health_current >= 0xa8)
+    link_health_current = 0;
+}
+
+void HandleDungeonLandingFromPit() {  // 879520
+  LinkOam_Main();
+  link_x_coord_prev = link_x_coord;
+  link_y_coord_prev = link_y_coord;
+  if (submodule_index == 7)
+    link_visibility_status = 0;
+  if (!(frame_counter & 3) && ++link_this_controls_sprite_oam == 10)
+    link_this_controls_sprite_oam = 6;
+  link_direction = 4;
+  Link_HandleVelocity();
+  if (sign16(link_y_coord) && !sign16(tiledetect_which_y_pos[0])) {
+    if (!sign16(-link_y_coord + tiledetect_which_y_pos[0]))
+      return;
+  } else {
+    if (tiledetect_which_y_pos[0] >= link_y_coord)
+      return;
+  }
+  //exploration glitch could also be armed without quitting
+  //by jumping off a dungeon ledge into an access pit
+  if (enhanced_features0 & kFeatures0_MiscBugFixes) {
+    about_to_jump_off_ledge = 0;
+  }
+  link_y_coord = tiledetect_which_y_pos[0];
+  link_animation_steps = 0;
+  link_speed_modifier = 0;
+  link_this_controls_sprite_oam = 0;
+  player_near_pit_state = 0;
+  link_speed_setting = 0;
+  subsubmodule_index = 0;
+  submodule_index = 0;
+  link_disable_sprite_damage = 0;
+  if (follower_indicator != 0 && follower_indicator != 3) {
+    tagalong_var5 = 0;
+    if (follower_indicator == 13) {
+      follower_indicator = 0;
+      super_bomb_indicator_unk2 = 0;
+      super_bomb_indicator_unk1 = 0;
+      follower_dropped = 0;
+    } else {
+      Follower_Initialize();
+    }
+  }
+  TileDetect_MainHandler(0);
+  if (tiledetect_shallow_water & 1)
+    Ancilla_Sfx2_Near(0x24);
+  Player_TileDetectNearby();
+  if ((sound_effect_1 & 0x3f) != 0x24)
+    Ancilla_Sfx2_Near(0x21);
+
+  if (dung_hdr_collision_2 == 2 && (tiledetect_water_staircase & 0xf))
+    byte_7E0322 = 3;
+  if ((tiledetect_deepwater & 0xf) == 0xf) {
+    link_is_in_deep_water = 1;
+    link_some_direction_bits = link_direction_last;
+    Link_ResetSwimmingState();
+    link_is_on_lower_level = 1;
+    AncillaAdd_Splash(0x15, 1);
+    link_player_handler_state = kPlayerState_Swimming;
+    Link_ForceUnequipCape_quietly();
+    link_state_bits = 0;
+    link_picking_throw_state = 0;
+    link_grabbing_wall = 0;
+    link_speed_setting = 0;
+  } else {
+    link_player_handler_state = (tiledetect_pit_tile & 0xf) ? kPlayerState_FallingIntoHole : kPlayerState_Ground;
+  }
+}
+
+void PlayerHandler_04_Swimming() {  // 87963b
+  if (link_auxiliary_state) {
+    link_player_handler_state = kPlayerState_RecoilWall;
+    link_z_coord &= 0xff;
+    ResetAllAcceleration();
+    link_maybe_swim_faster = 0;
+    link_swim_hard_stroke = 0;
+    link_cant_change_direction &= ~1;
+    LinkState_Recoil();
+    return;
+  }
+
+  button_mask_b_y = 0;
+  button_b_frames = 0;
+  link_delay_timer_spin_attack = 0;
+  link_spin_attack_step_counter = 0;
+  link_state_bits = 0;
+  link_picking_throw_state = 0;
+  if (!link_item_flippers)
+    return;
+
+  if (!(swimcoll_var7[0] | swimcoll_var7[1])) {
+    if ((uint8)swimcoll_var5[0] != 2 && (uint8)swimcoll_var5[1] != 2)
+      ResetAllAcceleration();
+    link_animation_steps &= 1;
+    if (++link_counter_var1 >= 16) {
+      link_counter_var1 = 0;
+      byte_7E02CC = 0;
+      link_animation_steps = (link_animation_steps & 1) ^ 1;
+    }
+  } else {
+    if (++link_counter_var1 >= 8) {
+      link_counter_var1 = 0;
+      link_animation_steps = (link_animation_steps + 1) & 3;
+      byte_7E02CC = kSwimmingTab1[link_animation_steps];
+    }
+  }
+
+  if (!link_swim_hard_stroke) {
+    uint8 t;
+    if (!(swimcoll_var7[0] | swimcoll_var7[1]) || (t = ((filtered_joypad_L & kJoypadL_A) | filtered_joypad_H) & 0xc0) == 0) {
+      Link_HandleSwimMovements();
+      return;
+    }
+    link_swim_hard_stroke = t;
+    Ancilla_Sfx2_Near(37);
+    link_maybe_swim_faster = 1;
+    swimming_countdown = 7;
+    Link_HandleSwimAccels();
+  }
+  if (sign8(--swimming_countdown)) {
+    swimming_countdown = 7;
+    if (++link_maybe_swim_faster == 5) {
+      link_maybe_swim_faster = 0;
+      link_swim_hard_stroke &= ~0xC0;
+    }
+  }
+
+  Link_HandleSwimMovements();
+}
+
+void Link_HandleSwimMovements() {  // 879715
+  uint8 t;
+
+  if (!(t = force_move_any_direction & 0xf) && !(t = joypad1H_last & kJoypadH_AnyDir)) {
+    link_y_vel = link_x_vel = 0;
+    Link_FlagMaxAccels();
+    if (link_flag_moving) {
+      if (link_is_running) {
+        t = link_some_direction_bits;
+      } else {
+        if (!(swimcoll_var7[0] | swimcoll_var7[1])) {
+          bitmask_of_dragstate = 0;
+          Link_ResetSwimmingState();
+        }
+        goto out;
+      }
+    } else {
+      if (link_player_handler_state != kPlayerState_Swimming)
+        link_animation_steps = 0;
+      goto out;
+    }
+  }
+
+  if (t != link_some_direction_bits) {
+    link_some_direction_bits = t;
+    link_subpixel_x = link_subpixel_y = 0;
+    link_moving_against_diag_tile = 0;
+    bitmask_of_dragstate = 0;
+  }
+  Link_SetIceMaxAccel();
+  Link_SetMomentum();
+  Link_SetTheMaxAccel();
+out:
+  Link_HandleDiagonalCollision();
+  Link_HandleVelocity();
+  Link_HandleCardinalCollision();
+  Link_HandleMovingAnimation_FullLongEntry();
+  fallhole_var1 = 0;
+  HandleIndoorCameraAndDoors();
+}
+
+void Link_FlagMaxAccels() {  // 879785
+  if (!link_flag_moving)
+    return;
+  for (int i = 1; i >= 0; i--) {
+    if (swimcoll_var7[i]) {
+      swimcoll_var9[i] = swimcoll_var7[i];
+      swimcoll_var5[i] = 1;
+    }
+  }
+}
+
+void Link_SetIceMaxAccel() {  // 8797a6
+  if (!link_flag_moving)
+    return;
+  swimcoll_var9[0] = 0x180;
+  swimcoll_var9[1] = 0x180;
+}
+
+void Link_SetMomentum() {  // 8797c7
+  uint8 joy = joypad1H_last & kJoypadH_AnyDir;
+  uint8 mask = 12, bit = 8;
+  for (int i = 0; i < 2; i++, mask >>= 2, bit >>= 2) {
+    if (joy & mask) {
+      swimcoll_var3[i] = link_flag_moving ? kSwimmingTab2[link_flag_moving - 1] : 32;
+      if (((link_some_direction_bits | link_direction) & mask) == mask) {
+        swimcoll_var5[i] = 2;
+      } else {
+        swimcoll_var11[i] = (joy & bit) ? 0 : 1;
+        swimcoll_var5[i] = 0;
+      }
+      if (!swimcoll_var9[i])
+        swimcoll_var9[i] = 240;
+    }
+  }
+}
+
+void Link_ResetSwimmingState() {  // 87983a
+  swimming_countdown = 0;
+  link_swim_hard_stroke = 0;
+  link_maybe_swim_faster = 0;
+  ResetAllAcceleration();
+}
+
+void Link_ResetStateAfterDamagingPit() {  // 87984b
+  Link_ResetSwimmingState();
+  link_player_handler_state = link_is_bunny && !link_item_moon_pearl ?
+    kPlayerState_PermaBunny : kPlayerState_Ground;
+  link_direction_last = link_some_direction_bits;
+  link_is_in_deep_water = 0;
+  link_disable_sprite_damage = 0;
+  link_this_controls_sprite_oam = 0;
+  player_near_pit_state = 0;
+}
+
+void ResetAllAcceleration() {  // 879873
+  swimcoll_var1[0] = 0;
+  swimcoll_var1[1] = 0;
+  swimcoll_var3[0] = 0;
+  swimcoll_var3[1] = 0;
+  swimcoll_var5[0] = 0;
+  swimcoll_var5[1] = 0;
+  swimcoll_var7[0] = 0;
+  swimcoll_var7[1] = 0;
+  swimcoll_var9[0] = 0;
+  swimcoll_var9[1] = 0;
+}
+
+void Link_HandleSwimAccels() {  // 8798a8
+  static const  uint16 kSwimmingTab3[] = { 128, 160, 192, 224, 256, 288, 320, 352, 384 };
+  uint8 mask = 12;
+  for (int i = 0; i < 2; i++, mask >>= 2) {
+    if (joypad1H_last & mask) {
+      if (swimcoll_var7[i] && swimcoll_var9[i] >= 384) {
+        uint16 t;
+        for (int j = 0; j < 9 && (t = kSwimmingTab3[j]) < swimcoll_var7[i]; j++) {}
+        swimcoll_var9[i] = t;
+      } else {
+        uint16 t = swimcoll_var9[i];
+        if (t) {
+          t += 160;
+          if (t >= 384)
+            t = 384;
+          swimcoll_var9[i] = t;
+        } else {
+          swimcoll_var7[i] = 1;
+          swimcoll_var9[i] = 240;
+        }
+      }
+    }
+  }
+}
+
+void Link_SetTheMaxAccel() {  // 879903
+  if (link_flag_moving || link_swim_hard_stroke)
+    return;
+  uint8 mask = 12;
+  for (int i = 0; i < 2; i++, mask >>= 2) {
+    if ((joypad1H_last & mask) && swimcoll_var5[i] != 2) {
+      if (swimcoll_var1[i] || swimcoll_var7[i] >= 240 && swimcoll_var7[i] >= swimcoll_var9[i]) {
+        swimcoll_var5[i] = 0;
+        if (swimcoll_var7[i] >= 240) {
+          swimcoll_var1[i] = 1;
+          swimcoll_var5[i] = 1;
+        } else {
+          swimcoll_var9[i] = 240;
+          swimcoll_var1[i] = 0;
+        }
+      }
+    } else {
+      swimcoll_var9[i] = 240;
+      swimcoll_var1[i] = 0;
+    }
+  }
+}
+
+void LinkState_Zapped() {  // 87996c
+  CacheCameraPropertiesIfOutdoors();
+  LinkZap_HandleMosaic();
+  if (!sign8(--link_delay_timer_spin_attack))
+    return;
+  link_delay_timer_spin_attack = 2;
+  player_handler_timer++;
+  if (player_handler_timer & 1)
+    Palette_ElectroThemedGear();
+  else
+    LoadActualGearPalettes();
+  if (player_handler_timer == 8) {
+    player_handler_timer = 0;
+    link_player_handler_state = kPlayerState_Ground;
+    link_disable_sprite_damage = 0;
+    link_electrocute_on_touch = 0;
+    link_auxiliary_state = 0;
+    Player_SetCustomMosaicLevel(0);
+  }
+}
+
+void PlayerHandler_15_HoldItem() {  // 8799ac
+  // empty by design
+}
+
+void Link_ReceiveItem(uint8 item, int chest_position) {  // 8799ad
+  if (link_auxiliary_state) {
+    link_auxiliary_state = 0;
+    link_incapacitated_timer = 0;
+    countdown_for_blink = 0;
+    link_state_bits = 0;
+  }
+  link_receiveitem_index = item;
+  if (item == 0x3e)
+    Ancilla_Sfx3_Near(0x2e);
+  link_receiveitem_var1 = 0x60;
+  if (item_receipt_method == 0 || item_receipt_method == 3) {
+    link_state_bits = 0;
+    button_mask_b_y = 0;
+    bitfield_for_a_button = 0;
+    button_b_frames = 0;
+    link_speed_setting = 0;
+    link_cant_change_direction = 0;
+    link_item_in_hand = 0;
+    link_position_mode = 0;
+    player_handler_timer = 0;
+    link_player_handler_state = kPlayerState_HoldUpItem;
+    link_pose_for_item = 1;
+    link_disable_sprite_damage = 1;
+    if (item == 0x20)
+      link_pose_for_item = 2;
+  }
+  AncillaAdd_ItemReceipt(0x22, 4, chest_position);
+  if (item != 0x20 && item != 0x37 && item != 0x38 && item != 0x39)
+    Hud_RefreshIcon();
+  Link_CancelDash();
+}
+
+void Link_TuckIntoBed() {  // 879a2c
+  link_y_coord = 0x215a;
+  link_x_coord = 0x940;
+  link_player_handler_state = kPlayerState_AsleepInBed;
+  player_sleep_in_bed_state = 0;
+  link_pose_during_opening = 0;
+  link_countdown_for_dash = 3;
+  AncillaAdd_Blanket(0x20);
+}
+
+void LinkState_Sleeping() {  // 879a5a
+  switch (player_sleep_in_bed_state) {
+  case 0:
+    if (!(frame_counter & 0x1f))
+      AncillaAdd_Snoring(0x21, 1);
+    break;
+  case 1:
+    if (submodule_index == 0 && sign8(--link_countdown_for_dash)) {
+      link_countdown_for_dash = 0;
+      if (((filtered_joypad_H & 0xe0) | (filtered_joypad_H << 4) | filtered_joypad_L) & 0xf0) {
+        link_pose_during_opening++;
+        link_direction_facing = 6;
+        player_sleep_in_bed_state++;
+        link_countdown_for_dash = 4;
+      }
+    }
+    break;
+  case 2:
+    if (sign8(--link_countdown_for_dash)) {
+      link_actual_vel_y = 4;
+      link_actual_vel_x = 21;
+      link_actual_vel_z = 24;
+      link_actual_vel_z_copy = 24;
+      link_incapacitated_timer = 16;
+      link_auxiliary_state = 2;
+      link_player_handler_state = kPlayerState_RecoilOther;
+    }
+    break;
+  }
+}
+
+void Link_HandleSwordCooldown() {  // 879ac2
+  if (!sign8(--link_sword_delay_timer))
+    return;
+
+  link_sword_delay_timer = 0;
+  if (link_item_in_hand | link_position_mode)
+    return;
+
+  if (button_b_frames < 9) {
+    if (!link_is_running)
+      Link_CheckForSwordSwing();
+  } else {
+    HandleSwordControls();
+  }
+
+}
+
+void Link_HandleYItem() {  // 879b0e
+  if (button_b_frames && button_b_frames < 9)
+    return;
+
+  uint8 item = current_item_y;
+
+  if (link_is_bunny_mirror && (item != 11 && item != 20))
+    return;
+
+  if (is_archer_or_shovel_game && !link_is_bunny_mirror) {
+    if (is_archer_or_shovel_game == 2)
+      LinkItem_Bow();
+    else
+      LinkItem_Shovel();
+    return;
+  }
+
+  uint8 old_down = joypad1H_last, old_pressed = filtered_joypad_H, old_bottle = link_item_bottle_index;
+  if ((link_item_in_hand | link_position_mode) == 0 && !(old_down & kJoypadH_Y)) {
+    // Is any special key held down?
+    int btn_index = GetCurrentItemButtonIndex();
+    if (btn_index != 0) {
+      uint8 *cur_item_ptr = GetCurrentItemButtonPtr(btn_index);
+      if (*cur_item_ptr) {
+        if (*cur_item_ptr >= kHudItem_Bottle1)
+          link_item_bottle_index = *cur_item_ptr - kHudItem_Bottle1 + 1;
+        item = Hud_LookupInventoryItem(*cur_item_ptr);
+        // Pretend it's actually Y that's down
+        joypad1H_last = old_down | kJoypadH_Y;
+        static const uint8 kButtonIndexKeys[4] = { 0, kJoypadL_X, kJoypadL_L, kJoypadL_R };
+        filtered_joypad_H = old_pressed | ((filtered_joypad_L & kButtonIndexKeys[btn_index]) ? kJoypadH_Y : 0);
+      }
+    }
+  }
+
+  if (item != current_item_active) {
+    if (current_item_active == 8 && (link_item_flute & 2))
+      button_mask_b_y &= ~0x40;
+    if (current_item_active == 19 && link_cape_mode)
+      Link_ForceUnequipCape();
+  }
+
+
+  if ((link_item_in_hand | link_position_mode) == 0)
+    current_item_active = item;
+
+  if (current_item_active == 5 || current_item_active == 6)
+    eq_selected_rod = current_item_active - 5 + 1;
+
+  switch (current_item_active) {
+  case 0:
+    break;
+  case 1: LinkItem_Bombs(); break;
+  case 2: LinkItem_Boomerang(); break;
+  case 3: LinkItem_Bow(); break;
+  case 4: LinkItem_Hammer(); break;
+  case 5: LinkItem_Rod(); break;
+  case 6: LinkItem_Rod(); break;
+  case 7: LinkItem_Net(); break;
+  case 8: LinkItem_ShovelAndFlute(); break;
+  case 9: LinkItem_Lamp(); break;
+  case 10: LinkItem_Powder(); break;
+  case 11: LinkItem_Bottle(); break;
+  case 12: LinkItem_Book(); break;
+  case 13: LinkItem_CaneOfByrna(); break;
+  case 14: LinkItem_Hookshot(); break;
+  case 15: LinkItem_Bombos(); break;
+  case 16: LinkItem_Ether(); break;
+  case 17: LinkItem_Quake(); break;
+  case 18: LinkItem_CaneOfSomaria(); break;
+  case 19: LinkItem_Cape(); break;
+  case 20: LinkItem_Mirror(); break;
+  case 21: LinkItem_Shovel(); break;
+  default:
+    assert(0);
+  }
+
+  joypad1H_last = old_down;
+  filtered_joypad_H = old_pressed;
+  link_item_bottle_index = old_bottle;
+}
+
+void Link_HandleAPress() {  // 879baa
+  flag_is_sprite_to_pick_up_cached = 0;
+  if (link_item_in_hand || (link_position_mode & 0x1f) || byte_7E0379)
+    return;
+
+  if (button_b_frames < 9 && (button_mask_b_y & 0x80))
+    return;
+
+  uint8 action = tile_action_index;
+
+  if ((link_state_bits | link_grabbing_wall) == 0) {
+    if (!Link_CheckNewAPress()) {
+      bitfield_for_a_button = 0;
+      return;
+    }
+
+    if (link_need_for_pullforrupees_sprite && !link_direction_facing) {
+      action = 7;
+    } else if (link_is_near_moveable_statue) {
+      action = 6;
+    } else {
+      if (!flag_is_ancilla_to_pick_up) {
+        if (!flag_is_sprite_to_pick_up) {
+          action = Link_HandleLiftables();
+          goto attempt_action;
+        }
+        flag_is_sprite_to_pick_up_cached = flag_is_sprite_to_pick_up;
+      }
+
+      if (button_b_frames)
+        Link_ResetSwordAndItemUsage();
+
+      if (link_item_in_hand | link_position_mode) {
+        link_item_in_hand = 0;
+        link_position_mode = 0;
+        Link_ResetBoomerangYStuff();
+        flag_for_boomerang_in_place = 0;
+        if (ancilla_type[0] == 5)
+          ancilla_type[0] = 0;
+      }
+      action = 1;
+    }
+    static const uint8 kAbilityBitmasks[] = { 0xE0, 0x40, 4, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0 };
+attempt_action:
+    if (!(kAbilityBitmasks[action] & link_ability_flags)) {
+      bitfield_for_a_button = 0;
+      return;
+    }
+
+    tile_action_index = action;
+    Link_APress_PerformBasic(action * 2);
+  }
+
+  // actionInProgress
+  unused_2 = tile_action_index;
+  switch (tile_action_index) {
+  case 1: Link_APress_LiftCarryThrow(); break;
+  case 3: Link_APress_PullObject(); break;
+  case 6: Link_APress_StatueDrag(); break;
+  }
+}
+
+void Link_APress_PerformBasic(uint8 action_x2) {  // 879c5f
+  switch (action_x2 >> 1) {
+  case 0: Link_PerformDesertPrayer(); break;
+  case 1: Link_PerformThrow(); break;
+  case 2: Link_PerformDash(); break;
+  case 3: Link_PerformGrab(); break;
+  case 4: Link_PerformRead(); break;
+  case 5: Link_PerformOpenChest(); break;
+  case 6: Link_PerformStatueDrag(); break;
+  case 7: Link_PerformRupeePull(); break;
+  default:
+    assert(0);
+  }
+}
+
+void HandleSwordSfxAndBeam() {  // 879c66
+  link_direction &= ~0xf;
+  button_b_frames = 0;
+  link_spin_attack_step_counter = 0;
+
+  uint8 health = link_health_capacity - 4;
+  if (health < link_health_current && ((link_sword_type + 1) & 0xfe) && link_sword_type >= 2) {
+    int i = 4;
+    while (ancilla_type[i] != 0x31) {
+      if (--i < 0) {
+        AddSwordBeam(0);
+        break;
+      }
+    }
+  }
+  uint8 sword = link_sword_type - 1;
+  if (sword != 0xfe && sword != 0xff)
+    sound_effect_1 = kFireBeamSounds[sword] | Link_CalculateSfxPan();
+  link_delay_timer_spin_attack = 1;
+}
+
+void Link_CheckForSwordSwing() {  // 879cd9
+  if (bitfield_for_a_button & 0x10)
+    return;
+
+  if (!(button_mask_b_y & 0x80)) {
+    if (!(filtered_joypad_H & 0x80))
+      return;
+    if (is_standing_in_doorway) {
+      TileDetect_SwordSwingDeepInDoor(is_standing_in_doorway);
+      if ((R14 & 0x30) == 0x30)
+        return;
+    }
+    button_mask_b_y |= 0x80;
+    HandleSwordSfxAndBeam();
+    link_cant_change_direction |= 1;
+    link_animation_steps = 0;
+  }
+
+  if (!(joypad1H_last & kJoypadH_B))
+    button_mask_b_y |= 1;
+  HaltLinkWhenUsingItems();
+  link_direction &= ~0xf;
+  if (sign8(--link_delay_timer_spin_attack)) {
+    if (++button_b_frames >= 9) {
+      HandleSwordControls();
+      return;
+    }
+    link_delay_timer_spin_attack = kSpinAttackDelays[button_b_frames];
+    if (button_b_frames == 5) {
+      if (link_sword_type != 0 && link_sword_type != 1 && link_sword_type != 0xff)
+        AncillaAdd_SwordSwingSparkle(0x26, 4);
+      if (link_sword_type != 0 && link_sword_type != 0xff)
+        TileDetect_MainHandler(link_sword_type == 1 ? 1 : 6);
+    } else if (button_b_frames >= 4 && (button_mask_b_y & 1) && (joypad1H_last & kJoypadH_B)) {
+      button_mask_b_y &= ~1;
+      HandleSwordSfxAndBeam();
+      return;
+    }
+  }
+  CalculateSwordHitBox();
+}
+
+void HandleSwordControls() {  // 879d72
+  if (joypad1H_last & kJoypadH_B) {
+    Player_Sword_SpinAttackJerks_HoldDown();
+  } else {
+    if (link_spin_attack_step_counter < 48) {
+      Link_ResetSwordAndItemUsage();
+    } else {
+      Link_ResetSwordAndItemUsage();
+      link_spin_attack_step_counter = 0;
+      Link_ActivateSpinAttack();
+    }
+  }
+}
+
+void Link_ResetSwordAndItemUsage() {  // 879d84
+  link_speed_setting = 0;
+  bitmask_of_dragstate &= ~9;
+  link_delay_timer_spin_attack = 0;
+  button_b_frames = 0;
+  button_mask_b_y &= ~0x81;
+  link_cant_change_direction &= ~1;
+}
+
+void Player_Sword_SpinAttackJerks_HoldDown() {  // 879d9f
+  if ((bitmask_of_dragstate & 0x80) || (bitmask_of_dragstate & 9) == 0) {
+    if (set_when_damaging_enemies == 0) {
+      button_b_frames = 9;
+      link_cant_change_direction |= 1;
+      link_delay_timer_spin_attack = 0;
+      if (link_speed_setting != 4 && link_speed_setting != 16) {
+        link_speed_setting = 12;
+        if (!((uint8)(link_sword_type + 1) & ~1))
+          return;
+        int i = 4;
+        do {
+          if (ancilla_type[i] == 0x30 || ancilla_type[i] == 0x31)
+            return;
+        } while (--i >= 0);
+
+        if (link_spin_attack_step_counter >= 6 && (frame_counter & 3) == 0)
+          AncillaSpawn_SwordChargeSparkle();
+
+        if (link_spin_attack_step_counter < 64 && ++link_spin_attack_step_counter == 48) {
+          Ancilla_Sfx2_Near(55);
+          AncillaAdd_ChargedSpinAttackSparkle();
+        }
+      } else {
+        CalculateSwordHitBox();
+      }
+      return;
+    } else if (set_when_damaging_enemies == 1) {
+      Link_ResetSwordAndItemUsage();
+      return;
+    }
+  }
+  // endif_2
+  if (button_b_frames == 9) {
+    button_b_frames = 10;
+    link_delay_timer_spin_attack = kSpinAttackDelays[button_b_frames];
+  }
+
+  if (sign8(--link_delay_timer_spin_attack)) {
+    uint8 frames = button_b_frames + 1;
+    if (frames == 13) {
+      if ((uint8)(link_sword_type + 1) & ~1 && (bitmask_of_dragstate & 9)) {
+        AncillaAdd_WallTapSpark(27, 1);
+        Ancilla_Sfx2_Near((bitmask_of_dragstate & 8) ? 6 : 5);
+        TileDetect_MainHandler(1);
+      }
+      frames = 10;
+    }
+    button_b_frames = frames;
+    link_delay_timer_spin_attack = kSpinAttackDelays[button_b_frames];
+  }
+  CalculateSwordHitBox();
+}
+
+void LinkItem_Rod() {  // 879eef
+  static const uint8 kRodAnimDelays[] = { 3, 3, 5 };
+  if (!(button_mask_b_y & 0x40)) {
+    if (is_standing_in_doorway || !CheckYButtonPress())
+      return;
+    if (!LinkCheckMagicCost(0))
+      goto out;
+    link_debug_value_2 = 1;
+    if (eq_selected_rod == 1)
+      AncillaAdd_FireRodShot(2, 1);
+    else
+      AncillaAdd_IceRodShot(11, 1);
+    link_delay_timer_spin_attack = kRodAnimDelays[0];
+    link_animation_steps = 0;
+    player_handler_timer = 0;
+    link_item_in_hand = 1;
+  }
+  HaltLinkWhenUsingItems();
+  link_direction &= ~0xf;
+  if (!sign8(--link_delay_timer_spin_attack))
+    return;
+  player_handler_timer++;
+
+  link_delay_timer_spin_attack = kRodAnimDelays[player_handler_timer];
+  if (player_handler_timer != 3)
+    return;
+  link_debug_value_2 = 0;
+  link_speed_setting = 0;
+  player_handler_timer = 0;
+  link_delay_timer_spin_attack = 0;
+  link_item_in_hand &= ~1;
+out:
+  button_mask_b_y &= ~0x40;
+}
+
+void LinkItem_Hammer() {  // 879f7b
+  static const uint8 kHammerAnimDelays[] = { 3, 3, 16 };
+  if (link_item_in_hand & 0x10)
+    return;
+  if (!(button_mask_b_y & 0x40)) {
+    if (is_standing_in_doorway || !(filtered_joypad_H & kJoypadH_Y))
+      return;
+    button_mask_b_y |= 0x40;
+    link_delay_timer_spin_attack = kHammerAnimDelays[0];
+    link_cant_change_direction |= 1;
+    link_animation_steps = 0;
+    player_handler_timer = 0;
+    link_item_in_hand = 2;
+  }
+
+  HaltLinkWhenUsingItems();
+  link_direction &= ~0xf;
+  if (!sign8(--link_delay_timer_spin_attack))
+    return;
+  player_handler_timer++;
+
+  link_delay_timer_spin_attack = kHammerAnimDelays[player_handler_timer];
+  if (player_handler_timer == 1) {
+    TileDetect_MainHandler(3);
+    Ancilla_AddHitStars(22, 0);
+    if (sound_effect_1 == 0) {
+      Ancilla_Sfx2_Near(16);
+      SpawnHammerWaterSplash();
+    }
+  } else if (player_handler_timer == 3) {
+    player_handler_timer = 0;
+    link_delay_timer_spin_attack = 0;
+    button_mask_b_y &= ~0x40;
+    link_cant_change_direction &= ~1;
+    link_item_in_hand &= ~2;
+  }
+}
+
+void LinkItem_Bow() {  // 87a006
+  static const uint8 kBowDelays[] = { 3, 3, 8 };
+
+  if (!(button_mask_b_y & 0x40)) {
+    if (is_standing_in_doorway || !CheckYButtonPress())
+      return;
+    link_cant_change_direction |= 1;
+    link_delay_timer_spin_attack = kBowDelays[0];
+    link_animation_steps = 0;
+    player_handler_timer = 0;
+    link_item_in_hand = 16;
+  }
+  HaltLinkWhenUsingItems();
+  link_direction &= ~0xf;
+  if (!sign8(--link_delay_timer_spin_attack))
+    return;
+  player_handler_timer++;
+
+  link_delay_timer_spin_attack = kBowDelays[player_handler_timer];
+  if (player_handler_timer != 3)
+    return;
+
+  int obj = AncillaAdd_Arrow(9, link_direction_facing, 2, link_x_coord, link_y_coord);
+  if (obj >= 0) {
+    if (archery_game_arrows_left) {
+      archery_game_arrows_left--;
+      link_num_arrows += 2;
+    }
+    if (!archery_game_out_of_arrows && link_num_arrows) {
+      if (--link_num_arrows == 0)
+        Hud_RefreshIcon();
+    } else {
+      ancilla_type[obj] = 0;
+      Ancilla_Sfx2_Near(60);
+    }
+  }
+
+  player_handler_timer = 0;
+  link_delay_timer_spin_attack = 0;
+  button_mask_b_y &= ~0x40;
+  link_cant_change_direction &= ~1;
+  link_item_in_hand &= ~0x10;
+  if (button_b_frames >= 9)
+    button_b_frames = 9;
+}
+
+void LinkItem_Boomerang() {  // 87a0bb
+  if (!(button_mask_b_y & 0x40)) {
+    if (is_standing_in_doorway || !CheckYButtonPress() || flag_for_boomerang_in_place)
+      return;
+    link_animation_steps = 0;
+    link_item_in_hand = 0x80;
+    player_handler_timer = 0;
+    link_delay_timer_spin_attack = 7;
+
+    int s0 = AncillaAdd_Boomerang(5, 0);
+
+    if (button_b_frames >= 9) {
+      Link_ResetBoomerangYStuff();
+      return;
+    }
+
+    if (!s0) {
+      link_direction_last = joypad1H_last & kJoypadH_AnyDir;
+    } else {
+      link_cant_change_direction |= 1;
+    }
+  } else {
+    link_cant_change_direction |= 1;
+  }
+
+  if (link_item_in_hand) {
+    HaltLinkWhenUsingItems();
+    link_direction &= ~0xf;
+    if (!sign8(--link_delay_timer_spin_attack))
+      return;
+    link_delay_timer_spin_attack = 5;
+    if (++player_handler_timer != 2)
+      return;
+  }
+  Link_ResetBoomerangYStuff();
+}
+
+void Link_ResetBoomerangYStuff() {  // 87a11f
+  link_item_in_hand = 0;
+  player_handler_timer = 0;
+  link_delay_timer_spin_attack = 0;
+  button_mask_b_y &= ~0x40;
+  if (!(button_mask_b_y & 0x80))
+    link_cant_change_direction &= ~1;
+}
+
+void LinkItem_Bombs() {  // 87a138
+  if (is_standing_in_doorway || follower_indicator == 13 || !CheckYButtonPress())
+    return;
+  button_mask_b_y &= ~0x40;
+  AncillaAdd_Bomb(7, enhanced_features0 & kFeatures0_MoreActiveBombs ? 3 : 1);
+  link_item_in_hand = 0;
+}
+
+void LinkItem_Bottle() {  // 87a15b
+  if (!CheckYButtonPress())
+    return;
+  button_mask_b_y &= ~0x40;
+  int btidx = link_item_bottle_index - 1;
+  uint8 b = link_bottle_info[btidx];
+  if (b == 0)
+    return;
+  if (b < 3) {
+fail:
+    Ancilla_Sfx2_Near(60);
+  } else if (b == 3) {  // red potion
+    if (link_health_capacity == link_health_current)
+      goto fail;
+    link_bottle_info[btidx] = 2;
+    link_item_in_hand = 0;
+    submodule_index = 4;
+    saved_module_for_menu = main_module_index;
+    main_module_index = 14;
+    animate_heart_refill_countdown = 7;
+    Hud_Rebuild();
+  } else if (b == 4) { // green potion
+    if (link_magic_power == 128)
+      goto fail;
+    link_bottle_info[btidx] = 2;
+    link_item_in_hand = 0;
+    submodule_index = 8;
+    saved_module_for_menu = main_module_index;
+    main_module_index = 14;
+    animate_heart_refill_countdown = 7;
+    Hud_Rebuild();
+  } else if (b == 5) { // blue potion
+    if (link_health_capacity == link_health_current && link_magic_power == 128)
+      goto fail;
+    link_bottle_info[btidx] = 2;
+    link_item_in_hand = 0;
+    submodule_index = 9;
+    saved_module_for_menu = main_module_index;
+    main_module_index = 14;
+    animate_heart_refill_countdown = 7;
+    Hud_Rebuild();
+  } else if (b == 6) { // fairy
+    link_item_in_hand = 0;
+    if (ReleaseFairy() < 0)
+      goto fail;
+    link_bottle_info[btidx] = 2;
+    Hud_Rebuild();
+  } else if (b == 7 || b == 8) {  // bad/good bee
+    if (!ReleaseBeeFromBottle(btidx))
+      goto fail;
+    link_bottle_info[btidx] = 2;
+    Hud_Rebuild();
+  }
+}
+
+void LinkItem_Lamp() {  // 87a24d
+  if (is_standing_in_doorway || !CheckYButtonPress())
+    return;
+  if (link_item_torch && LinkCheckMagicCost(6)) {
+    AncillaAdd_MagicPowder(0x1a, 0);
+    Dungeon_LightTorch();
+    AncillaAdd_LampFlame(0x2f, 2);
+  }
+  link_item_in_hand = 0;
+  button_mask_b_y = 0;
+  button_b_frames = 0;
+  link_cant_change_direction = 0;
+  if (button_b_frames == 9)
+    link_speed_setting = 0;
+}
+
+void LinkItem_Powder() {  // 87a293
+  static const uint8 kMushroomTimer[] = { 2, 1, 1, 3, 2, 2, 2, 2, 6, 0 };
+
+  if (!(button_mask_b_y & 0x40)) {
+    if (is_standing_in_doorway || !CheckYButtonPress())
+      return;
+    if (link_item_mushroom != 2) {
+      Ancilla_Sfx2_Near(60);
+      goto out;
+    }
+    if (!LinkCheckMagicCost(2))
+      goto out;
+    link_delay_timer_spin_attack = kMushroomTimer[0];
+    player_handler_timer = 0;
+    link_animation_steps = 0;
+    link_direction &= ~0xf;
+    link_item_in_hand = 0x40;
+  }
+  link_x_vel = link_y_vel = 0;
+  link_direction = 0;
+  link_subpixel_x = link_subpixel_y = 0;
+  link_moving_against_diag_tile = 0;
+  if (!sign8(--link_delay_timer_spin_attack))
+    return;
+  player_handler_timer++;
+  link_delay_timer_spin_attack = kMushroomTimer[player_handler_timer];
+  if (player_handler_timer == 4)
+    AncillaAdd_MagicPowder(26, 0);
+  if (player_handler_timer != 9)
+    return;
+  if (submodule_index == 0)
+    TileDetect_MainHandler(1);
+out:
+  link_item_in_hand = 0;
+  player_handler_timer = 0;
+  button_mask_b_y &= ~0x40;
+}
+
+void LinkItem_ShovelAndFlute() {  // 87a313
+  if (link_item_flute == 1)
+    LinkItem_Shovel();
+  else if (link_item_flute != 0)
+    LinkItem_Flute();
+}
+
+void LinkItem_Shovel() {  // 87a32c
+  static const uint8 kShovelAnimDelay[] = { 7, 18, 16, 7, 18, 16 };
+  static const uint8 kShovelAnimDelay2[] = { 0, 1, 2, 0, 1, 2 };
+  if (!(button_mask_b_y & 0x40)) {
+    if (is_standing_in_doorway || !CheckYButtonPress())
+      return;
+
+    link_delay_timer_spin_attack = kShovelAnimDelay[0];
+    link_var30d = 0;
+    player_handler_timer = 0;
+    link_position_mode = 1;
+    link_cant_change_direction |= 1;
+    link_animation_steps = 0;
+  }
+  HaltLinkWhenUsingItems();
+  link_direction &= ~0xf;
+  if (!sign8(--link_delay_timer_spin_attack))
+    return;
+  link_var30d++;
+  link_delay_timer_spin_attack = kShovelAnimDelay[link_var30d];
+  player_handler_timer = kShovelAnimDelay2[link_var30d];
+
+  if (player_handler_timer == 1) {
+    TileDetect_MainHandler(2);
+    if (BYTE(word_7E04B2)) {
+      Ancilla_Sfx3_Near(27);
+      AncillaAdd_DugUpFlute(54, 0);
+    }
+
+    if (!((tiledetect_thick_grass | tiledetect_destruction_aftermath) & 1)) {
+      Ancilla_AddHitStars(22, 0); // hit stars
+      Ancilla_Sfx2_Near(5);
+    } else {
+      AncillaAdd_ShovelDirt(23, 0); // shovel dirt
+      if (is_archer_or_shovel_game)
+        DiggingGameGuy_AttemptPrizeSpawn();
+      Ancilla_Sfx2_Near(18);
+    }
+  }
+
+  if (link_var30d == 3) {
+    link_var30d = 0;
+    player_handler_timer = 0;
+    button_mask_b_y &= 0x80;
+    link_position_mode = 0;
+    link_cant_change_direction &= ~1;
+  }
+}
+
+void LinkItem_Flute() {  // 87a3db
+  if (button_mask_b_y & 0x40) {
+    if (--flute_countdown)
+      return;
+    button_mask_b_y &= ~0x40;
+  }
+  if (!CheckYButtonPress())
+    return;
+  flute_countdown = 128;
+  Ancilla_Sfx2_Near(19);
+  if (player_is_indoors || overworld_screen_index & 0x40 || main_module_index == 11)
+    return;
+  int i = 4;
+  do {
+    if (ancilla_type[i] == 0x27)
+      return;
+  } while (--i >= 0);
+  if (link_item_flute == 2) {
+    if (overworld_screen_index == 0x18 && link_y_coord >= 0x760 && link_y_coord < 0x7e0 && link_x_coord >= 0x1cf && link_x_coord < 0x230) {
+      submodule_index = 45;
+      AncillaAdd_ExplodingWeatherVane(55, 0);
+    }
+  } else {
+    AncillaAdd_Duck_take_off(39, 4);
+    link_need_for_pullforrupees_sprite = 0;
+  }
+}
+
+void LinkItem_Book() {  // 87a471
+  if (button_mask_b_y & 0x40 || is_standing_in_doorway || !CheckYButtonPress())
+    return;
+  button_mask_b_y &= ~0x40;
+  if (byte_7E02ED) {
+    Link_PerformDesertPrayer();
+  } else {
+    Ancilla_Sfx2_Near(60);
+  }
+}
+
+void LinkItem_Ether() {  // 87a494
+  if (!CheckYButtonPress())
+    return;
+  button_mask_b_y &= ~0x40;
+
+  if (is_standing_in_doorway || flag_block_link_menu || dung_savegame_state_bits & 0x8000 || !((uint8)(link_sword_type + 1) & ~1) ||
+      follower_dropped && follower_indicator == 13) {
+    Ancilla_Sfx2_Near(60);
+    return;
+  }
+
+  if (ancilla_type[0] | ancilla_type[1] | ancilla_type[2])
+    return;
+
+  if (!LinkCheckMagicCost(1))
+    return;
+  link_player_handler_state = kPlayerState_Ether;
+  link_cant_change_direction |= 1;
+  link_delay_timer_spin_attack = kEtherAnimDelays[0];
+  state_for_spin_attack = 0;
+  step_counter_for_spin_attack = 0;
+  byte_7E0324 = 0;
+  Ancilla_Sfx3_Near(35);
+}
+
+void LinkState_UsingEther() {  // 87a50f
+  flag_unk1++;
+  if (!sign8(--link_delay_timer_spin_attack))
+    return;
+
+  step_counter_for_spin_attack++;
+  if (step_counter_for_spin_attack == 4) {
+    Ancilla_Sfx3_Near(35);
+  } else if (step_counter_for_spin_attack == 9) {
+    Ancilla_Sfx2_Near(44);
+  } else if (step_counter_for_spin_attack == 12) {
+    step_counter_for_spin_attack = 10;
+  }
+  const uint8 *table = (enhanced_features0 & kFeatures0_DimFlashes) ? kEtherAnimDelaysNoFlash : kEtherAnimDelays;
+  link_delay_timer_spin_attack = table[step_counter_for_spin_attack];
+  state_for_spin_attack = kEtherAnimStates[step_counter_for_spin_attack];
+  if (!byte_7E0324 && step_counter_for_spin_attack == 10) {
+    byte_7E0324 = 1;
+    AncillaAdd_EtherSpell(24, 0);
+    link_auxiliary_state = 0;
+    link_incapacitated_timer = 0;
+  }
+}
+
+void LinkItem_Bombos() {  // 87a569
+  if (!CheckYButtonPress())
+    return;
+  button_mask_b_y &= ~0x40;
+
+  if (is_standing_in_doorway || flag_block_link_menu || dung_savegame_state_bits & 0x8000 || !((uint8)(link_sword_type + 1) & ~1) ||
+      follower_dropped && follower_indicator == 13) {
+    Ancilla_Sfx2_Near(60);
+    return;
+  }
+
+  if (ancilla_type[0] | ancilla_type[1] | ancilla_type[2])
+    return;
+
+  if (!LinkCheckMagicCost(1))
+    return;
+  link_player_handler_state = kPlayerState_Bombos;
+  link_cant_change_direction |= 1;
+  link_delay_timer_spin_attack = kBombosAnimDelays[0];
+  state_for_spin_attack = kBombosAnimStates[0];
+  step_counter_for_spin_attack = 0;
+  byte_7E0324 = 0;
+  Ancilla_Sfx3_Near(35);
+}
+
+void LinkState_UsingBombos() {  // 87a5f7
+  flag_unk1++;
+  if (!sign8(--link_delay_timer_spin_attack))
+    return;
+
+  step_counter_for_spin_attack++;
+  if (step_counter_for_spin_attack == 4) {
+    Ancilla_Sfx3_Near(35);
+  } else if (step_counter_for_spin_attack == 10) {
+    Ancilla_Sfx2_Near(44);
+  } else if (step_counter_for_spin_attack == 20) {
+    step_counter_for_spin_attack = 19;
+  }
+  link_delay_timer_spin_attack = kBombosAnimDelays[step_counter_for_spin_attack];
+  state_for_spin_attack = kBombosAnimStates[step_counter_for_spin_attack];
+  if (!byte_7E0324 && step_counter_for_spin_attack == 19) {
+    byte_7E0324 = 1;
+    AncillaAdd_BombosSpell(25, 0);
+    link_auxiliary_state = 0;
+    link_incapacitated_timer = 0;
+  }
+}
+
+void LinkItem_Quake() {  // 87a64b
+  if (!CheckYButtonPress())
+    return;
+  button_mask_b_y &= ~0x40;
+
+  if (is_standing_in_doorway || flag_block_link_menu || dung_savegame_state_bits & 0x8000 || !((uint8)(link_sword_type + 1) & ~1) ||
+      follower_dropped && follower_indicator == 13) {
+    Ancilla_Sfx2_Near(60);
+    return;
+  }
+
+  if (ancilla_type[0] | ancilla_type[1] | ancilla_type[2])
+    return;
+
+  if (!LinkCheckMagicCost(1))
+    return;
+  link_player_handler_state = kPlayerState_Quake;
+  link_cant_change_direction |= 1;
+  link_delay_timer_spin_attack = kQuakeAnimDelays[0];
+  state_for_spin_attack = kQuakeAnimStates[0];
+  step_counter_for_spin_attack = 0;
+  byte_7E0324 = 0;
+  link_actual_vel_z_mirror = 40;
+  link_actual_vel_z_copy_mirror = 40;
+  BYTE(link_z_coord_mirror) = 0;
+  Ancilla_Sfx3_Near(35);
+}
+
+void LinkState_UsingQuake() {  // 87a6d6
+  flag_unk1++;
+  link_actual_vel_x = link_actual_vel_y = 0;
+
+  if (step_counter_for_spin_attack == 10) {
+    link_actual_vel_z = link_actual_vel_z_mirror;
+    link_actual_vel_z_copy = link_actual_vel_z_copy_mirror;
+    BYTE(link_z_coord) = link_z_coord_mirror;
+    link_auxiliary_state = 2;
+    Player_ChangeZ(2);
+    Link_MovePosition();
+    link_actual_vel_z_mirror = link_actual_vel_z;
+    link_actual_vel_z_copy_mirror = link_actual_vel_z_copy;
+    BYTE(link_z_coord_mirror) = link_z_coord;
+    if (!sign8(link_z_coord)) {
+      state_for_spin_attack = sign8(link_actual_vel_z) ? 21 : 20;
+      return;
+    }
+  } else {
+    if (!sign8(--link_delay_timer_spin_attack))
+      return;
+  }
+
+  step_counter_for_spin_attack++;
+  if (step_counter_for_spin_attack == 4) {
+    Ancilla_Sfx3_Near(35);
+  } else if (step_counter_for_spin_attack == 10) {
+    Ancilla_Sfx2_Near(44);
+  } else if (step_counter_for_spin_attack == 11) {
+    Ancilla_Sfx2_Near(12);
+  } else if (step_counter_for_spin_attack == 12) {
+    step_counter_for_spin_attack = 11;
+  }
+  link_delay_timer_spin_attack = kQuakeAnimDelays[step_counter_for_spin_attack];
+  state_for_spin_attack = kQuakeAnimStates[step_counter_for_spin_attack];
+  if (!byte_7E0324 && step_counter_for_spin_attack == 11) {
+    byte_7E0324 = 1;
+    AncillaAdd_QuakeSpell(28, 0);
+    link_auxiliary_state = 0;
+    link_incapacitated_timer = 0;
+  }
+}
+
+void Link_ActivateSpinAttack() {  // 87a77a
+  AncillaAdd_SpinAttackInitSpark(42, 0, 0);
+  Link_AnimateVictorySpin();
+}
+
+void Link_AnimateVictorySpin() {  // 87a783
+  link_player_handler_state = 3;
+  link_spin_offsets = (link_direction_facing >> 1) * 12;
+  link_delay_timer_spin_attack = 3;
+  state_for_spin_attack = kLinkSpinGraphicsByDir[link_spin_offsets];
+  step_counter_for_spin_attack = 0;
+  button_b_frames = 144;
+  link_cant_change_direction |= 1;
+  button_mask_b_y = 0x80;
+  LinkState_SpinAttack();
+}
+
+void LinkState_SpinAttack() {  // 87a804
+  CacheCameraPropertiesIfOutdoors();
+
+  if (link_auxiliary_state) {
+    int i = 4;
+    do {
+      if (ancilla_type[i] == 0x2a || ancilla_type[i] == 0x2b)
+        ancilla_type[i] = 0;
+    } while (--i >= 0);
+    link_z_coord &= 0xff;
+    link_cant_change_direction &= ~1;
+    link_delay_timer_spin_attack = 0;
+    button_b_frames = 0;
+    button_mask_b_y = 0;
+    bitfield_for_a_button = 0;
+    state_for_spin_attack = 0;
+    step_counter_for_spin_attack = 0;
+    link_speed_setting = 0;
+    if (link_electrocute_on_touch) {
+      if (link_cape_mode)
+        Link_ForceUnequipCape_quietly();
+      Link_ResetSwordAndItemUsage();
+      link_disable_sprite_damage = 1;
+      player_handler_timer = 0;
+      link_delay_timer_spin_attack = 2;
+      link_animation_steps = 0;
+      link_direction &= ~0xf;
+      Ancilla_Sfx3_Near(43);
+      link_player_handler_state = kPlayerState_Electrocution;
+      LinkState_Zapped();
+    } else {
+      link_player_handler_state = kPlayerState_RecoilWall;
+      LinkState_Recoil();
+    }
+    return;
+  }
+
+  if (link_incapacitated_timer) {
+    Link_HandleRecoilAndTimer(false);
+  } else {
+    link_direction = 0;
+    Link_HandleVelocity();
+    Link_HandleCardinalCollision();
+    link_player_handler_state = kPlayerState_SpinAttacking;
+    fallhole_var1 = 0;
+    HandleIndoorCameraAndDoors();
+  }
+
+  if (!sign8(--link_delay_timer_spin_attack))
+    return;
+
+  step_counter_for_spin_attack++;
+
+  if (step_counter_for_spin_attack == 2)
+    Ancilla_Sfx3_Near(35);
+
+  if (step_counter_for_spin_attack == 12) {
+    link_cant_change_direction &= ~1;
+    link_delay_timer_spin_attack = 0;
+    button_b_frames = 0;
+    state_for_spin_attack = 0;
+    step_counter_for_spin_attack = 0;
+    if (link_player_handler_state != kPlayerState_SpinAttackMotion) {
+      button_mask_b_y = (button_b_frames) ? (joypad1H_last & kJoypadH_B) : 0; // wtf, it's zero,
+    }
+    link_player_handler_state = kPlayerState_Ground;
+  } else {
+    state_for_spin_attack = kLinkSpinGraphicsByDir[step_counter_for_spin_attack + link_spin_offsets];
+    link_delay_timer_spin_attack = kLinkSpinDelays[step_counter_for_spin_attack];
+    TileDetect_MainHandler(8);
+  }
+}
+
+void LinkItem_Mirror() {  // 87a91a
+  if (!(button_mask_b_y & 0x40)) {
+    if (!CheckYButtonPress())
+      return;
+
+    if (follower_indicator == 10) {
+      dialogue_message_index = 289;
+      Main_ShowTextMessage();
+      return;
+    }
+  }
+  button_mask_b_y &= ~0x40;
+
+  if (is_standing_in_doorway || 
+      !cheatWalkThroughWalls && !(enhanced_features0 & kFeatures0_MirrorToDarkworld) && 
+      !player_is_indoors && !(overworld_screen_index & 0x40)) {
+    Ancilla_Sfx2_Near(60);
+    return;
+  }
+
+  DoSwordInteractionWithTiles_Mirror();
+}
+
+void DoSwordInteractionWithTiles_Mirror() {  // 87a95c
+  if (player_is_indoors) {
+    if (flag_block_link_menu)
+      return;
+    Mirror_SaveRoomData();
+    if (sound_effect_1 != 60) {
+      index_of_changable_dungeon_objs[0] = 0;
+      index_of_changable_dungeon_objs[1] = 0;
+    }
+  } else if (main_module_index != 11) {
+    last_light_vs_dark_world = overworld_screen_index & 0x40;
+    if (last_light_vs_dark_world) {
+      bird_travel_y_lo[15] = link_y_coord;
+      bird_travel_y_hi[15] = link_y_coord >> 8;
+      bird_travel_x_lo[15] = link_x_coord;
+      bird_travel_x_hi[15] = link_x_coord >> 8;
+    }
+    submodule_index = 35;
+    link_need_for_pullforrupees_sprite = 0;
+    link_triggered_by_whirlpool_sprite = 1;
+    subsubmodule_index = 0;
+    link_actual_vel_x = link_actual_vel_y = 0;
+    link_player_handler_state = kPlayerState_Mirror;
+  }
+}
+
+void LinkState_CrossingWorlds() {  // 87a9b1
+  uint8 t;
+
+  Link_ResetProperties_B();
+  TileCheckForMirrorBonk();
+
+  if ((overworld_screen_index & 0x40) != last_light_vs_dark_world && ((t = R12 | R14) & 0xc) != 0 && BitSum4(t) >= 2)
+    goto do_mirror;
+
+  if (BitSum4(tiledetect_deepwater) >= 2) {
+    if (link_item_flippers) {
+      link_is_in_deep_water = 1;
+      link_some_direction_bits = link_direction_last;
+      Link_ResetSwimmingState();
+      link_player_handler_state = kPlayerState_Swimming;
+      Link_ForceUnequipCape_quietly();
+      link_speed_setting = 0;
+      return;
+    }
+    if ((overworld_screen_index & 0x40) != last_light_vs_dark_world) {
+do_mirror:
+      submodule_index = 44;
+      link_need_for_pullforrupees_sprite = 0;
+      link_triggered_by_whirlpool_sprite = 1;
+      subsubmodule_index = 0;
+      link_actual_vel_x = link_actual_vel_y = 0;
+      link_player_handler_state = kPlayerState_Mirror;
+      return;
+    }
+    CheckAbilityToSwim();
+  }
+
+  if (link_is_in_deep_water) {
+    link_is_in_deep_water = 0;
+    link_direction_last = link_some_direction_bits;
+  }
+
+  link_countdown_for_dash = 0;
+  link_is_running = 0;
+  link_speed_setting = 0;
+  button_mask_b_y = 0;
+  button_b_frames = 0;
+  link_cant_change_direction = 0;
+  swimcoll_var5[0] &= ~0xff;
+  link_actual_vel_y = 0;
+
+  if ((overworld_screen_index & 0x40) != last_light_vs_dark_world)
+    num_memorized_tiles = 0;
+
+  link_player_handler_state = (link_item_moon_pearl || !(overworld_screen_index & 0x40)) ? kPlayerState_Ground : kPlayerState_PermaBunny;
+}
+
+void Link_PerformDesertPrayer() {  // 87aa6c
+  submodule_index = 5;
+  saved_module_for_menu = main_module_index;
+  main_module_index = 14;
+  flag_unk1 = 1;
+  some_animation_timer = 22;
+  some_animation_timer_steps = 0;
+  link_state_bits = 2;
+  link_cant_change_direction |= 1;
+  link_animation_steps = 0;
+  link_direction &= ~0xf;
+  sound_effect_ambient = 17;
+  music_control = 242;
+}
+
+void HandleFollowersAfterMirroring() {  // 87aaa2
+  TileDetect_MainHandler(0);
+  link_animation_steps = 0;
+  if (follower_indicator == 12 || follower_indicator == 13) {
+    if (follower_indicator == 13) {
+      super_bomb_indicator_unk2 = 0xfe;
+      super_bomb_indicator_unk1 = 0;
+    }
+    if (follower_dropped) {
+      follower_dropped = 0;
+      follower_indicator = 0;
+    }
+  } else if (follower_indicator == 9 || follower_indicator == 10) {
+    follower_indicator = 0;
+  } else if (follower_indicator == 7 || follower_indicator == 8) {
+    follower_indicator ^= (7 ^ 8);
+    LoadFollowerGraphics();
+    AncillaAdd_DwarfPoof(0x40, 4);
+  }
+
+  if (!link_item_moon_pearl) {
+    AncillaAdd_BunnyPoof(0x23, 4);
+    Link_ForceUnequipCape_quietly();
+    link_bunny_transform_timer = 0;
+  } else if (link_cape_mode) {
+    Link_ForceUnequipCape();
+    link_bunny_transform_timer = 0;
+  }
+}
+
+void LinkItem_Hookshot() {  // 87ab25
+  if (button_mask_b_y & 0x40 || is_standing_in_doorway || bitmask_of_dragstate & 2 || !CheckYButtonPress())
+    return;
+
+  ResetAllAcceleration();
+  player_handler_timer = 0;
+  link_cant_change_direction |= 1;
+  link_delay_timer_spin_attack = 7;
+  link_animation_steps = 0;
+  link_direction &= ~0xf;
+  link_position_mode = 4;
+  link_player_handler_state = kPlayerState_Hookshot;
+  link_disable_sprite_damage = 1;
+  AncillaAdd_Hookshot(31, 3);
+}
+
+void LinkState_Hookshotting() {  // 87ab7c
+  static const int8 kHookshotArrA[4] = { -8, -16, 0, 0 };
+  static const int8 kHookshotArrB[4] = { 0, 0, 4, -12 };
+  static const int8 kHookshotArrC[4] = { -64, 64, 0, 0 };
+  static const int8 kHookshotArrD[4] = { 0, 0, -64, 64 };
+
+  link_give_damage = 0;
+  link_auxiliary_state = 0;
+  link_incapacitated_timer = 0;
+  int i = 4;
+  while (ancilla_type[i] != 0x1f) {
+    if (--i < 0) {
+      if (!sign8(--link_delay_timer_spin_attack))
+        return;
+      player_handler_timer = 0;
+      link_disable_sprite_damage = 0;
+      button_mask_b_y &= ~0x40;
+      link_cant_change_direction &= ~1;
+      link_position_mode &= ~4;
+      link_player_handler_state = kPlayerState_Ground;
+      if (button_b_frames >= 9)
+        button_b_frames = 9;
+      return;
+    }
+  }
+
+  if (sign8(--link_delay_timer_spin_attack))
+    link_delay_timer_spin_attack = 0;
+
+  if (!related_to_hookshot) {
+    link_y_coord_safe_return_lo = link_y_coord;
+    link_x_coord_safe_return_lo = link_x_coord;
+    link_y_vel = link_x_vel = 0;
+    Link_HandleCardinalCollision();
+    return;
+  }
+
+  player_on_somaria_platform = 0;
+
+  uint8 hei = hookshot_effect_index;
+  if (sign8(--ancilla_item_to_link[hei])) {
+    ancilla_item_to_link[hei] = 0;
+  } else {
+    uint16 x = ancilla_x_lo[hei] | (ancilla_x_hi[hei] << 8);
+    uint16 y = ancilla_y_lo[hei] | (ancilla_y_hi[hei] << 8);
+    int8 r4 = kHookshotArrA[ancilla_dir[hei]];
+    int8 r6 = kHookshotArrB[ancilla_dir[hei]];
+    link_actual_vel_x = link_actual_vel_y = 0;
+    int8 r8 = kHookshotArrC[ancilla_dir[hei]];
+    int8 r10 = kHookshotArrD[ancilla_dir[hei]];
+
+    uint16 yd = (int16)(y + r4 - link_y_coord);
+    if ((int16)yd < 0)
+      yd = -yd;
+    if (yd >= 2)
+      link_actual_vel_y = r8;
+
+    uint16 xd = (int16)(x + r6 - link_x_coord);
+    if ((int16)xd < 0)
+      xd = -xd;
+    if (xd >= 2)
+      link_actual_vel_x = r10;
+
+    if (link_actual_vel_x | link_actual_vel_y)
+      goto loc_87AD49;
+  }
+
+  ancilla_type[hei] = 0;
+  tagalong_var7 = tagalong_var1;
+  link_player_handler_state = kPlayerState_Ground;
+  player_handler_timer = 0;
+  link_delay_timer_spin_attack = 0;
+  related_to_hookshot = 0;
+  button_mask_b_y &= ~0x40;
+  link_cant_change_direction &= ~1;
+  link_position_mode &= ~4;
+  link_disable_sprite_damage = 0;
+
+  if (ancilla_arr1[hei]) {
+    link_is_on_lower_level_mirror ^= 1;
+    dung_cur_floor--;
+    if (kind_of_in_room_staircase == 0) {
+      BYTE(dungeon_room_index2) = dungeon_room_index;
+      BYTE(dungeon_room_index) += 0x10;
+    }
+    if (kind_of_in_room_staircase != 2) {
+      link_is_on_lower_level ^= 1;
+    }
+    Dungeon_FlagRoomData_Quadrants();
+  }
+  Player_TileDetectNearby();
+  if (tiledetect_deepwater & 0xf && !link_is_in_deep_water) {
+    link_is_in_deep_water = 1;
+    link_some_direction_bits = link_direction_last;
+    Link_ResetSwimmingState();
+    AncillaAdd_Splash(21, 0);
+    link_player_handler_state = kPlayerState_Swimming;
+    Link_ForceUnequipCape_quietly();
+    link_state_bits = 0;
+    link_picking_throw_state = 0;
+    link_grabbing_wall = 0;
+    link_speed_setting = 0;
+    if (player_is_indoors)
+      link_is_on_lower_level = 1;
+    if (button_b_frames >= 9)
+      button_b_frames = 9;
+  } else if (tiledetect_pit_tile & 0xf) {
+    byte_7E005C = 9;
+    link_this_controls_sprite_oam = 0;
+    player_near_pit_state = 1;
+    link_player_handler_state = kPlayerState_FallingIntoHole;
+    if (button_b_frames >= 9)
+      button_b_frames = 9;
+  } else {
+    link_y_coord_safe_return_lo = link_y_coord;
+    link_y_coord_safe_return_hi = link_y_coord >> 8;
+    link_x_coord_safe_return_lo = link_x_coord;
+    link_x_coord_safe_return_hi = link_x_coord >> 8;
+    Link_HandleCardinalCollision();
+    HandleIndoorCameraAndDoors();
+  }
+  return;
+loc_87AD49:
+  Link_MovePosition();
+  TileDetect_MainHandler(5);
+  if (player_is_indoors) {
+    uint8 x = tiledetect_vertical_ledge >> 4 | tiledetect_vertical_ledge | detection_of_ledge_tiles_horiz_uphoriz;
+    if (x & 1 && sign8(--hookshot_var1)) {
+      hookshot_var1 = 3;
+      related_to_hookshot ^= 2;
+    }
+  }
+  draw_water_ripples_or_grass = 0;
+  if (!(related_to_hookshot & 2)) {
+    if (tiledetect_thick_grass & 1) {
+      draw_water_ripples_or_grass = 2;
+      if (!Link_PermissionForSloshSounds())
+        Ancilla_Sfx2_Near(26);
+    } else if ((tiledetect_shallow_water | tiledetect_deepwater) & 1) {
+      draw_water_ripples_or_grass++;
+      Ancilla_Sfx2_Near((uint8)overworld_screen_index == 0x70 ? 27 : 28);
+    }
+  }
+
+  HandleIndoorCameraAndDoors();
+}
+
+void LinkItem_Cape() {  // 87adc1
+  if (!link_cape_mode) {
+    if (!sign8(--link_bunny_transform_timer)) {
+      link_direction &= ~0xf;
+      HaltLinkWhenUsingItems();
+      return;
+    }
+    link_bunny_transform_timer = 0;
+    if (is_standing_in_doorway || !CheckYButtonPress())
+      return;
+    button_mask_b_y &= ~0x40;
+    if (!link_magic_power) {
+      Ancilla_Sfx2_Near(60);
+      dialogue_message_index = 123;
+      Main_ShowTextMessage();
+      return;
+    }
+    player_handler_timer = 0;
+    link_cape_mode = 1;
+    cape_decrement_counter = kCapeDepletionTimers[link_magic_consumption];
+    link_bunny_transform_timer = 20;
+    AncillaAdd_CapePoof(35, 4);
+    Ancilla_Sfx2_Near(20);
+  } else {
+    link_disable_sprite_damage = 1;
+    HaltLinkWhenUsingItems();
+    link_direction &= ~0xf;
+    if (!--cape_decrement_counter) {
+      cape_decrement_counter = kCapeDepletionTimers[link_magic_consumption];
+      // Avoid magic underflow if an anti-fairy consumes magic.
+      if (link_magic_power == 0 && (enhanced_features0 & kFeatures0_MiscBugFixes) ||
+          !--link_magic_power) {
+        Link_ForceUnequipCape();
+        return;
+      }
+    }
+    if (sign8(--link_bunny_transform_timer)) {
+      link_bunny_transform_timer = 0;
+      if (filtered_joypad_H & kJoypadH_Y)
+        Link_ForceUnequipCape();
+    }
+  }
+}
+
+void Link_ForceUnequipCape() {  // 87ae47
+  AncillaAdd_CapePoof(35, 4);
+  Ancilla_Sfx2_Near(21);
+  Link_ForceUnequipCape_quietly();
+}
+
+void Link_ForceUnequipCape_quietly() {  // 87ae54
+  link_bunny_transform_timer = 32;
+  link_disable_sprite_damage = 0;
+  link_cape_mode = 0;
+  link_electrocute_on_touch = 0;
+}
+
+void HaltLinkWhenUsingItems() {  // 87ae65
+  if (dung_hdr_collision_2 == 2 && (byte_7E0322 & 3) == 3) {
+    link_y_vel = 0;
+    link_x_vel = 0;
+    link_direction = 0;
+    link_subpixel_y = 0;
+    link_subpixel_x = 0;
+    link_moving_against_diag_tile = 0;
+  }
+  if (player_on_somaria_platform)
+    link_direction = 0;
+}
+
+void Link_HandleCape_passive_LiftCheck() {  // 87ae88
+  //bugfix: grabbing or pulling while wearing cape didn't drain magic
+  if (link_state_bits & 0x80 || (enhanced_features0 & kFeatures0_MiscBugFixes && link_grabbing_wall))
+    Player_CheckHandleCapeStuff();
+}
+
+void Player_CheckHandleCapeStuff() {  // 87ae8f
+  if (link_cape_mode && current_item_active == 19) {
+    if (current_item_active == current_item_y) {
+      if (--cape_decrement_counter)
+        return;
+      cape_decrement_counter = kCapeDepletionTimers[link_magic_consumption];
+      if (!link_magic_power || --link_magic_power)
+        return;
+    }
+    Link_ForceUnequipCape();
+  }
+}
+
+void LinkItem_CaneOfSomaria() {  // 87aec0
+  static const uint8 kRodAnimDelays[] = { 3, 3, 5 };
+  if (!(button_mask_b_y & 0x40)) {
+    if (player_on_somaria_platform || is_standing_in_doorway || !CheckYButtonPress())
+      return;
+    int i = 4;
+    bool did_charge_magic = false;
+
+    while (ancilla_type[i] != 0x2c) {
+      if (--i < 0) {
+        if (!LinkCheckMagicCost(4)) {
+          // If you use the Cane of Somaria with an empty magic meter,
+          // then quickly switch to the mushroom or magic powder after
+          // the "no magic" prompt, you will automatically sprinkle magic powder
+          // despite pressing no button and having no magic.
+          if (enhanced_features0 & kFeatures0_MiscBugFixes)
+            goto out;
+          return;
+        }
+        did_charge_magic = true;
+        break;
+      }
+    }
+    link_debug_value_2 = 1;
+    if (AncillaAdd_SomariaBlock(0x2c, 1) < 0) {
+      // If you use the Cane of Somaria while two bombs and the boomerang are active,
+      // magic will be refunded instead of used.
+      if (did_charge_magic || !(enhanced_features0 & kFeatures0_MiscBugFixes))
+        Refund_Magic(4);
+    }
+    link_delay_timer_spin_attack = kRodAnimDelays[0];
+    link_animation_steps = 0;
+    player_handler_timer = 0;
+    link_item_in_hand = 0;
+    link_position_mode |= 8;
+  }
+
+  HaltLinkWhenUsingItems();
+  link_direction &= ~0xf;
+  if (!sign8(--link_delay_timer_spin_attack))
+    return;
+  player_handler_timer++;
+
+  link_delay_timer_spin_attack = kRodAnimDelays[player_handler_timer];
+  if (player_handler_timer != 3)
+    return;
+  link_speed_setting = 0;
+  player_handler_timer = 0;
+  link_delay_timer_spin_attack = 0;
+  link_debug_value_2 = 0;
+  link_position_mode &= ~8;
+out:
+  button_mask_b_y &= ~0x40;
+}
+
+void LinkItem_CaneOfByrna() {  // 87af3e
+  static const uint8 kByrnaDelays[] = { 19, 7, 13, 32 };
+  if (SearchForByrnaSpark())
+    return;
+  if (!(button_mask_b_y & 0x40)) {
+    if (is_standing_in_doorway || !CheckYButtonPress())
+      return;
+    if (!LinkCheckMagicCost(8))
+      goto out;
+    AncillaAdd_CaneOfByrnaInitSpark(48, 0);
+    link_spin_attack_step_counter = 0;
+    link_delay_timer_spin_attack = kByrnaDelays[0];
+    link_var30d = 0;
+    player_handler_timer = 0;
+    link_position_mode = 8;
+    link_cant_change_direction |= 1;
+    link_animation_steps = 0;
+  }
+  HaltLinkWhenUsingItems();
+  link_direction &= ~0xf;
+  if (!sign8(--link_delay_timer_spin_attack))
+    return;
+  player_handler_timer++;
+  link_delay_timer_spin_attack = kByrnaDelays[player_handler_timer];
+  if (player_handler_timer == 1) {
+    Ancilla_Sfx3_Near(42);
+  } else if (player_handler_timer == 3) {
+out:
+    link_var30d = 0;
+    player_handler_timer = 0;
+    button_mask_b_y &= 0x80;
+    link_position_mode = 0;
+    link_cant_change_direction &= ~1;
+  }
+}
+
+bool SearchForByrnaSpark() {  // 87afb5
+  if (link_position_mode & 8)
+    return false;
+  int i = 4;
+  do {
+    if (ancilla_type[i] == 0x31)
+      return true;
+  } while (--i >= 0);
+  return false;
+}
+
+void LinkItem_Net() {  // 87aff8
+  static const uint8 kBugNetTimers[] = { 11, 6, 7, 8, 1, 2, 3, 4, 5, 6, 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 9, 4, 5, 6, 7, 8, 1, 2, 3, 4, 10, 8, 1, 2, 3, 4, 5, 6, 7, 8 };
+  if (!(button_mask_b_y & 0x40)) {
+    if (is_standing_in_doorway || !CheckYButtonPress())
+      return;
+
+    player_handler_timer = kBugNetTimers[(link_direction_facing >> 1) * 10];
+    link_delay_timer_spin_attack = 3;
+    link_var30d = 0;
+    link_position_mode = 16;
+    link_cant_change_direction |= 1;
+    link_animation_steps = 0;
+    Ancilla_Sfx2_Near(50);
+  }
+
+  HaltLinkWhenUsingItems();
+  link_direction &= ~0xf;
+  if (!sign8(--link_delay_timer_spin_attack))
+    return;
+
+  link_var30d++;
+  link_delay_timer_spin_attack = 3;
+  player_handler_timer = kBugNetTimers[(link_direction_facing >> 1) * 10 + link_var30d];
+
+  if (link_var30d == 10) {
+    link_var30d = 0;
+    player_handler_timer = 0;
+    button_mask_b_y &= 0x80;
+    link_position_mode = 0;
+    link_cant_change_direction &= ~1;
+    player_oam_x_offset = 0x80;
+    player_oam_y_offset = 0x80;
+  }
+}
+
+bool CheckYButtonPress() {  // 87b073
+  if (button_mask_b_y & 0x40 || link_incapacitated_timer || !(filtered_joypad_H & kJoypadH_Y))
+    return false;
+  button_mask_b_y |= 0x40;
+  return true;
+}
+
+bool LinkCheckMagicCost(uint8 x) {  // 87b0ab
+  uint8 cost = kLinkItem_MagicCosts[x * 3 + link_magic_consumption];
+  uint8 a = link_magic_power;
+  if (a && (a -= cost) < 0x80) {
+    link_magic_power = a;
+    return true;
+  }
+  if (x != 3) {
+    Ancilla_Sfx2_Near(60);
+    dialogue_message_index = 123;
+    Main_ShowTextMessage();
+  }
+  return false;
+}
+
+void Refund_Magic(uint8 x) {  // 87b0e9
+  uint8 cost = kLinkItem_MagicCosts[x * 3 + link_magic_consumption];
+
+  int new_magic = link_magic_power + cost;
+  // Ensure magic can't overflow (for example the cane of somaria bug)
+  if (enhanced_features0 & kFeatures0_MiscBugFixes && new_magic >= 128)
+    new_magic = 128;
+  link_magic_power = new_magic;
+}
+
+void Link_ItemReset_FromOverworldThings() {  // 87b107
+  some_animation_timer_steps = 0;
+  bitfield_for_a_button = 0;
+  link_state_bits = 0;
+  link_picking_throw_state = 0;
+  link_grabbing_wall = 0;
+  link_cant_change_direction &= ~1;
+}
+
+void Link_PerformThrow() {  // 87b11c
+
+  if (!(flag_is_sprite_to_pick_up | flag_is_ancilla_to_pick_up)) {
+    Link_ResetSwordAndItemUsage();
+    bitfield_for_a_button = 0;
+    int i = 15;
+    while (sprite_state[i] != 0) {
+      if (--i < 0)
+        return;
+    }
+
+    if (interacting_with_liftable_tile_x1 == 5 || interacting_with_liftable_tile_x1 == 6) {
+      player_handler_timer = 1;
+    } else {
+      Point16U pt;
+      uint8 attr = player_is_indoors ? Dungeon_LiftAndReplaceLiftable(&pt) : Overworld_HandleLiftableTiles(&pt);
+
+      i = 8;
+      while (kLink_Lift_tab[i] != attr) {
+        if (--i < 0)
+          return;
+      }
+
+      flag_is_sprite_to_pick_up = 1;
+      Sprite_SpawnThrowableTerrain(i, pt.x, pt.y);
+      filtered_joypad_L &= ~kJoypadL_A;
+      player_handler_timer = 0;
+    }
+  } else {
+    player_handler_timer = 0;
+  }
+
+  button_mask_b_y = 0;
+  some_animation_timer = 6;
+  link_picking_throw_state = 1;
+  link_state_bits = 0x80;
+  some_animation_timer_steps = 0;
+  link_speed_setting = 12;
+  link_animation_steps = 0;
+  link_direction &= 0xf0;
+  link_cant_change_direction |= 1;
+}
+
+void Link_APress_LiftCarryThrow() {  // 87b1ca
+  if (!link_state_bits)
+    return;
+
+  // throwing?
+  if ((link_picking_throw_state & 2) && some_animation_timer >= 5)
+    some_animation_timer = 5;
+
+  // picking up?
+  if (link_picking_throw_state)
+    HaltLinkWhenUsingItems();
+
+  if (link_picking_throw_state & 1) {
+    link_animation_steps = 0;
+    link_counter_var1 = 0;
+    link_direction &= ~0xf;
+  }
+
+  if (--some_animation_timer)
+    return;
+
+  if (link_picking_throw_state & 2) {
+    link_state_bits = 0;
+    bitmask_of_dragstate = 0;
+    link_speed_setting = 0;
+    if (link_player_handler_state == 24)
+      link_player_handler_state = 0;
+  } else {
+    static const uint8 kLiftTab0[10] = { 8, 24, 8, 24, 8, 32, 6, 8, 13, 13 };
+    static const uint8 kLiftTab1[10] = { 0, 1, 0, 1, 0, 1, 0, 1, 2, 3 };
+    static const uint8 kLiftTab2[29] = { 6, 7, 7, 5, 10, 0, 23, 0, 18, 0, 18, 0, 8, 0, 8, 0, 254, 255, 17, 0, 
+        0x54, 0x52, 0x50, 0xFF, 0x51, 0x53, 0x55, 0x56, 0x57 };
+
+    if (player_handler_timer != 0) {
+      if (player_handler_timer + 1 != 9) {
+        player_handler_timer++;
+        some_animation_timer = kLiftTab0[player_handler_timer];
+        some_animation_timer_steps = kLiftTab1[player_handler_timer];
+        if (player_handler_timer == 6) {
+          BYTE(dung_secrets_unk1) = 0;
+          Point16U pt;
+          uint8 what = (player_is_indoors) ? Dungeon_LiftAndReplaceLiftable(&pt) : Overworld_HandleLiftableTiles(&pt);
+          link_player_handler_state = 24;
+          flag_is_sprite_to_pick_up = 1;
+          Sprite_SpawnThrowableTerrain((what & 0xf) + 1, pt.x, pt.y);
+          filtered_joypad_L &= ~kJoypadL_A;
+        }
+        return;
+      }
+    } else {
+      // fix OOB read triggered when lifting for too long
+      if (some_animation_timer_steps >= sizeof(kLiftTab2) - 1)
+        return;
+      some_animation_timer = kLiftTab2[++some_animation_timer_steps];
+      assert(some_animation_timer_steps < arraysize(kLiftTab2));
+      if (some_animation_timer_steps != 3)
+        return;
+    }
+  }
+
+  // stop animation
+  link_picking_throw_state = 0;
+  link_cant_change_direction &= ~1;
+}
+
+void Link_PerformDash() {  // 87b281
+  if (player_on_somaria_platform)
+    return;
+  if (flag_is_sprite_to_pick_up | flag_is_ancilla_to_pick_up)
+    return;
+  if (link_state_bits & 0x80)
+    return;
+  bitfield_for_a_button = 0;
+  link_countdown_for_dash = 29;
+  link_dash_ctr = 64;
+  link_player_handler_state = kPlayerState_StartDash;
+  link_is_running = 1;
+  button_mask_b_y &= 0x80;
+  link_state_bits = 0;
+  link_item_in_hand = 0;
+  bitmask_of_dragstate = 0;
+  link_moving_against_diag_tile = 0;
+
+  if (follower_indicator == kTagalongArr1[follower_indicator]) {
+    printf("Warning: Write to CART!\n");
+    link_speed_setting = 0;
+    timer_tagalong_reacquire = 64;
+  }
+}
+
+void Link_PerformGrab() {  // 87b2ee
+  if ((button_mask_b_y & 0x80) && button_b_frames >= 9)
+    return;
+
+  link_grabbing_wall = 1;
+  link_cant_change_direction |= 1;
+  link_animation_steps = 0;
+  some_animation_timer_steps = 0;
+  some_animation_timer = 0;
+  link_var30d = 0;
+}
+
+void Link_APress_PullObject() {  // 87b322
+  link_direction &= ~0xf;
+
+  if (!(kGrabWallDirs[link_direction_facing >> 1] & joypad1H_last)) {
+    link_var30d = 0;
+    goto set;
+  } else if (sign8(--some_animation_timer)) {
+    link_var30d = (link_var30d + 1 == 7) ? 1 : link_var30d + 1;
+set:
+    some_animation_timer_steps = kGrabWall_AnimSteps[link_var30d];
+    some_animation_timer = kGrabWall_AnimTimer[link_var30d];
+  }
+
+  if (!(joypad1L_last & kJoypadL_A)) {
+    link_var30d = 0;
+    some_animation_timer_steps = 0;
+    link_grabbing_wall = 0;
+    bitfield_for_a_button = 0;
+    link_cant_change_direction &= ~1;
+  }
+}
+
+void Link_PerformStatueDrag() {  // 87b371
+  link_grabbing_wall = 2;
+  link_cant_change_direction |= 1;
+  link_animation_steps = 0;
+  some_animation_timer_steps = 0;
+  some_animation_timer = kGrabWall_AnimTimer[0];
+  link_var30d = 0;
+}
+
+void Link_APress_StatueDrag() {  // 87b389
+  link_speed_setting = 20;
+  int j;
+  if (!(j = joypad1H_last & kGrabWallDirs[link_direction_facing >> 1])) {
+    link_direction = 0;
+    link_x_vel = link_y_vel = 0;
+    link_animation_steps = 0;
+    link_var30d = 0;
+  } else {
+    link_direction = j;
+    if (!sign8(--some_animation_timer))
+      goto skip_set;
+    link_var30d = (link_var30d + 1 == 7) ? 1 : link_var30d + 1;
+  }
+  some_animation_timer_steps = kGrabWall_AnimSteps[link_var30d];
+  some_animation_timer = kGrabWall_AnimTimer[link_var30d];
+skip_set:
+  if (!(joypad1L_last & kJoypadL_A)) {
+    link_speed_setting = 0;
+    link_is_near_moveable_statue = 0;
+    link_var30d = 0;
+    some_animation_timer_steps = 0;
+    link_grabbing_wall = 0;
+    bitfield_for_a_button = 0;
+    link_cant_change_direction &= ~1;
+  }
+}
+
+void Link_PerformRupeePull() {  // 87b3e5
+  if (link_direction_facing != 0)
+    return;
+  Link_ResetProperties_A();
+  link_grabbing_wall = 2;
+  link_cant_change_direction |= 2;
+
+  link_animation_steps = 0;
+  some_animation_timer_steps = 0;
+  some_animation_timer = kGrabWall_AnimTimer[0];
+  link_var30d = 0;
+  link_player_handler_state = kPlayerState_PullForRupees;
+  link_actual_vel_y = 0;
+  link_actual_vel_x = 0;
+  button_mask_b_y = 0;
+}
+
+void LinkState_TreePull() {  // 87b416
+  CacheCameraPropertiesIfOutdoors();
+  if (link_auxiliary_state) {
+    HandleLink_From1D();
+    return;
+  }
+
+  if (link_grabbing_wall) {
+    if (!button_mask_b_y) {
+      if (!(joypad1L_last & kJoypadL_A)) {
+        link_grabbing_wall = 0;
+        link_var30d = 0;
+        some_animation_timer = 2;
+        some_animation_timer_steps = 0;
+        link_cant_change_direction = 0;
+        link_player_handler_state = 0;
+        LinkState_Default();
+        return;
+      }
+      if (!(joypad1H_last & kJoypadH_Down))
+        goto out;
+      button_mask_b_y = 4;
+      Ancilla_Sfx2_Near(0x22);
+    }
+
+    if (!sign8(--some_animation_timer))
+      goto out;
+    int j = ++link_var30d;
+    some_animation_timer_steps = kGrabWall_AnimSteps[j];
+    some_animation_timer = kGrabWall_AnimTimer[j];
+    if (j != 7)
+      goto out;
+
+    link_grabbing_wall = 0;
+    link_var30d = 0;
+    some_animation_timer = 2;
+    some_animation_timer_steps = 0;
+    link_state_bits = 1;
+    link_picking_throw_state = 0;
+  }
+
+  if (bitmask_of_dragstate & 9) {
+reset_to_normal:
+    link_direction_facing = 0;
+    link_state_bits = 0;
+    link_cant_change_direction = 0;
+    link_player_handler_state = kPlayerState_Ground;
+    return;
+  }
+  if (link_var30d == 9) {
+    if (!(filtered_joypad_H & kJoypadH_AnyDir))
+      goto out2;
+    link_player_handler_state = kPlayerState_Ground;
+    LinkState_Default();
+    return;
+  }
+  AncillaAdd_DashDust_charging(0x1e, 0);
+  if (sign8(--some_animation_timer)) {
+    static const uint8 kGrabWall_AnimSteps2[10] = { 0, 1, 2, 3, 4, 0, 1, 2, 3, 0x20 };  // oob read
+    int j = ++link_var30d;
+    some_animation_timer_steps = kGrabWall_AnimSteps2[j];
+    some_animation_timer = 2;
+    link_actual_vel_y = 48;
+    if (j == 9)
+      goto reset_to_normal;
+  }
+  Flag67WithDirections();
+  if (!(link_direction & 3))
+    link_actual_vel_x = 0;
+  if (!(link_direction & 0xc))
+    link_actual_vel_y = 0;
+out:
+  Link_MovePosition();
+out2:
+  Link_HandleCardinalCollision();
+  HandleIndoorCameraAndDoors();
+}
+
+void Link_PerformRead() {  // 87b4f2
+  if (player_is_indoors) {
+    dialogue_message_index = Dungeon_GetTeleMsg(dungeon_room_index);
+  } else {
+    dialogue_message_index = (sram_progress_indicator < 2) ? 0x3A : Overworld_GetSignText(overworld_screen_index);
+  }
+  Main_ShowTextMessage();
+  bitfield_for_a_button = 0;
+}
+
+void Link_PerformOpenChest() {  // 87b574
+  static const uint8 kReceiveItemAlternates[] = { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 68, 255, 255, 255, 255, 255, 53, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 70, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 };
+  if (link_direction_facing || item_receipt_method || link_auxiliary_state)
+    return;
+  bitfield_for_a_button = 0;
+  int chest_position = -1;
+  uint8 item = OpenChestForItem(index_of_interacting_tile, &chest_position);
+  if (sign8(item)) {
+    item_receipt_method = 0;
+    return;
+  }
+  assert(chest_position != -1);
+  item_receipt_method = 1;
+  uint8 alt = kReceiveItemAlternates[item];
+  if (alt != 0xff) {
+    uint16 ram_addr = kMemoryLocationToGiveItemTo[item];
+    if (g_ram[ram_addr])
+      item = alt;
+  }
+
+  Link_ReceiveItem(item, chest_position);
+}
+
+bool Link_CheckNewAPress() {  // 87b5c0
+  if (bitfield_for_a_button & 0x80 || link_incapacitated_timer || !(filtered_joypad_L & kJoypadL_A))
+    return false;
+  bitfield_for_a_button |= 0x80;
+  return true;
+}
+
+bool Link_HandleToss() {  // 87b5d6
+  if (!(bitfield_for_a_button & 0x80) || !(filtered_joypad_L & kJoypadL_A) || (link_picking_throw_state & 1))
+    return false;
+  link_var30d = 0;
+  link_var30e = 0;
+  some_animation_timer_steps = 0;
+  bitfield_for_a_button = 0;
+  link_cant_change_direction &= ~1;
+  // debug stuff here
+  return true;
+}
+
+void Link_HandleDiagonalCollision() {  // 87b64f
+  if (CheckIfRoomNeedsDoubleLayerCheck()) {
+    Player_LimitDirections_Inner();
+    CreateVelocityFromMovingBackground();
+  }
+  link_direction &= 0xf;
+  Player_LimitDirections_Inner();
+}
+
+void Player_LimitDirections_Inner() {  // 87b660
+  link_direction_mask_a = 0xf;
+  link_direction_mask_b = 0xf;
+  link_num_orthogonal_directions = 0;
+
+  static const uint8 kMasks[4] = { 7, 0xB, 0xD, 0xE };
+
+  if (link_direction & 0xC) {
+    link_num_orthogonal_directions++;
+
+    link_last_direction_moved_towards = link_direction & 8 ? 0 : 1;
+    TileDetect_Movement_VerticalSlopes(link_last_direction_moved_towards);
+
+    if ((R14 & 0x30) && !(tiledetect_var1 & 2) && !(((R14 & 0x30) >> 4) & link_direction) && (link_direction & 3)) {
+      link_direction_mask_a = kMasks[(link_direction & 2) ? 2 : 3];
+    } else {
+      if (dung_hdr_collision == 0) {
+        if (link_auxiliary_state != 0 && (R12 & 3))
+          goto set_thingy;
+      }
+
+      if (R14 & 3) {
+        link_moving_against_diag_tile = 0;
+        if (link_flag_moving && (bitfield_spike_cactus_tiles & 3) == 0 && (link_direction & 3)) {
+          swimcoll_var1[0] = 0;
+          swimcoll_var5[0] = 0;
+          swimcoll_var7[0] = 0;
+          swimcoll_var9[0] = 0;
+        }
+set_thingy:
+        fallhole_var1 = 1;
+        link_direction_mask_a = kMasks[link_last_direction_moved_towards];
+      }
+    }
+
+    if (link_direction & 3) {
+      link_num_orthogonal_directions++;
+
+      link_last_direction_moved_towards = link_direction & 2 ? 2 : 3;
+      TileDetect_Movement_HorizontalSlopes(link_last_direction_moved_towards);
+
+      if ((R14 & 0x30) && (tiledetect_var1 & 2) && !(((R14 & 0x30) >> 2) & link_direction) && (link_direction & 0xC)) {
+        link_direction_mask_b = kMasks[(link_direction & 8) ? 0 : 1];
+      } else {
+        if (dung_hdr_collision == 0) {
+          if (link_auxiliary_state != 0 && (R12 & 3))
+            goto set_thingy_b;
+        }
+
+        if (R14 & 3) {
+          link_moving_against_diag_tile = 0;
+          if (link_flag_moving && (bitfield_spike_cactus_tiles & 3) == 0 && (link_direction & 0xC)) {
+            swimcoll_var1[1] = 0;
+            swimcoll_var5[1] = 0;
+            swimcoll_var7[1] = 0;
+            swimcoll_var9[1] = 0;
+          }
+set_thingy_b:
+          fallhole_var1 = 1;
+          link_direction_mask_b = kMasks[link_last_direction_moved_towards];
+        }
+      }
+
+      link_direction &= link_direction_mask_a & link_direction_mask_b;
+    }
+  }
+
+  // ending
+  if ((link_direction & 0xf) && (link_moving_against_diag_tile & 0xf))
+    link_direction = link_moving_against_diag_tile & 0xf;
+
+  if (link_num_orthogonal_directions == 2) {
+    link_num_orthogonal_directions = (link_direction_facing & 4) ? 2 : 1;
+  } else {
+    link_num_orthogonal_directions = 0;
+  }
+}
+
+void Link_HandleCardinalCollision() {  // 87b7c7
+  tiledetect_diag_state = 0;
+  tiledetect_diagonal_tile = 0;
+
+  if (((link_moving_against_diag_tile & 0x30) != 0 || (Link_HandleDiagonalKickback(), moving_against_diag_deadlocked == 0)) &&
+      CheckIfRoomNeedsDoubleLayerCheck()) {
+
+    if (dung_hdr_collision < 2 || dung_hdr_collision == 3)
+      goto yx;
+    tile_coll_flag = 2;
+    Player_TileDetectNearby();
+    byte_7E0316 = R14;
+    if (byte_7E0316 == 0)
+      goto yx;
+    link_y_vel += dung_floor_y_vel;
+    link_x_vel += dung_floor_x_vel;
+
+    uint8 a;
+    a = R14;
+    if (a == 12 || a == 3)
+      goto yx;
+    if (a == 10 || a == 5)
+      goto xy;
+    if ((a & 0xc) == 0 && (a & 3) == 0)
+      goto yx;
+
+    if (link_y_vel)
+      goto xy;
+    if (!link_x_vel)
+      goto yx;
+
+    if (sign8(dung_floor_y_vel)) {
+yx:   RunSlopeCollisionChecks_VerticalFirst();
+    } else {
+xy:   RunSlopeCollisionChecks_HorizontalFirst();
+    }
+    CreateVelocityFromMovingBackground();
+  } // endif_1
+
+  if (dung_hdr_collision == 2) {
+    Player_TileDetectNearby();
+    if ((R14 | byte_7E0316) == 0xf) {
+      if (!countdown_for_blink)
+        countdown_for_blink = 58;
+      if (link_direction == 0) {
+        if (BYTE(dung_floor_y_vel))
+          link_y_vel = -link_y_vel;
+        if (BYTE(dung_floor_x_vel))
+          link_x_vel = -link_x_vel;
+      }
+    }
+    tile_coll_flag = 1;
+    RunSlopeCollisionChecks_VerticalFirst();
+  } else if (dung_hdr_collision == 3) {
+    tile_coll_flag = 1;
+    RunSlopeCollisionChecks_HorizontalFirst();
+  } else if (dung_hdr_collision == 4 || (link_x_vel | link_y_vel) != 0) {
+    tile_coll_flag = 1;
+    RunSlopeCollisionChecks_VerticalFirst();
+  } else {
+    uint8 st = link_player_handler_state;
+    if (st != 19 && st != 8 && st != 9 && st != 10 && st != 3) {
+      Player_TileDetectNearby();
+      if (tiledetect_pit_tile & 0xf) {
+        link_player_handler_state = kPlayerState_FallingIntoHole;
+        if (!link_is_running)
+          link_speed_setting = 4;
+      }
+    }
+  }
+
+  TileDetect_MainHandler(0);
+  if (link_num_orthogonal_directions != 0)
+    link_moving_against_diag_tile = 0;
+
+  if (link_player_handler_state != 11) {
+    link_y_vel = link_y_coord - link_y_coord_safe_return_lo;
+    if (link_y_vel)
+      link_direction = (link_direction & 3) | (sign8(link_y_vel) ? 8 : 4);
+  }
+
+  link_x_vel = link_x_coord - link_x_coord_safe_return_lo;
+  if (link_x_vel)
+    link_direction = (link_direction & 0xC) | (sign8(link_x_vel) ? 2 : 1);
+
+  if (!player_is_indoors || dung_hdr_collision != 4 || link_player_handler_state != kPlayerState_Swimming)
+    return;
+
+  if (dung_floor_y_vel && (uint8)(link_y_vel - dung_floor_y_vel) == 0)
+    link_direction &= sign8(dung_floor_y_vel) ? ~8 : ~4;
+
+  if (dung_floor_x_vel && (uint8)(link_x_vel - dung_floor_x_vel) == 0)
+    link_direction &= sign8(dung_floor_x_vel) ? ~2 : ~1;
+}
+
+void RunSlopeCollisionChecks_VerticalFirst() {  // 87b956
+  if (!(link_moving_against_diag_tile & 0x20))
+    StartMovementCollisionChecks_Y();
+  if (!(link_moving_against_diag_tile & 0x10))
+    StartMovementCollisionChecks_X();
+}
+
+void RunSlopeCollisionChecks_HorizontalFirst() {  // 87b969
+  if (!(link_moving_against_diag_tile & 0x10))
+    StartMovementCollisionChecks_X();
+  if (!(link_moving_against_diag_tile & 0x20))
+    StartMovementCollisionChecks_Y();
+}
+
+bool CheckIfRoomNeedsDoubleLayerCheck() {  // 87b97c
+  if (dung_hdr_collision == 0 || dung_hdr_collision == 4)
+    return false;
+
+  if (dung_hdr_collision >= 2) {
+    link_y_coord += BG1VOFS_copy2 - BG2VOFS_copy2;
+    related_to_moving_floor_y = link_y_coord;
+    link_x_coord += BG1HOFS_copy2 - BG2HOFS_copy2;
+    related_to_moving_floor_x = link_x_coord;
+  }
+  link_is_on_lower_level = 1;
+  return true;
+}
+
+void CreateVelocityFromMovingBackground() {  // 87b9b3
+  if (dung_hdr_collision != 1) {
+    uint16 x = link_x_coord - related_to_moving_floor_x;
+    uint16 y = link_y_coord - related_to_moving_floor_y;
+    link_y_coord += BG2VOFS_copy2 - BG1VOFS_copy2;
+    link_x_coord += BG2HOFS_copy2 - BG1HOFS_copy2;
+    if (link_direction) {
+      link_x_vel += x;
+      link_y_vel += y;
+    }
+  }
+  link_is_on_lower_level = 0;
+}
+
+void StartMovementCollisionChecks_Y() {  // 87ba0a
+  if (!link_y_vel)
+    return;
+
+  if (is_standing_in_doorway == 1)
+    link_last_direction_moved_towards = (uint8)link_y_coord < 0x80 ? 0 : 1;
+  else
+    link_last_direction_moved_towards = sign8(link_y_vel) ? 0 : 1;
+  TileDetect_Movement_Y(link_last_direction_moved_towards);
+  if (player_is_indoors)
+    StartMovementCollisionChecks_Y_HandleIndoors();
+  else
+    StartMovementCollisionChecks_Y_HandleOutdoors();
+}
+
+void StartMovementCollisionChecks_Y_HandleIndoors() {  // 87ba35
+  if (sign8(link_state_bits) || link_incapacitated_timer != 0) {
+    R14 |= R14 >> 4;
+  } else {
+    if (is_standing_in_doorway == 2) {
+      if (link_num_orthogonal_directions == 0) {
+        if (dung_hdr_collision != 3 || link_is_on_lower_level == 0) {
+          Link_AddInVelocityY();
+          ChangeAxisOfPerpendicularDoorMovement_Y();
+          return;
+        }
+        goto label_3;
+      } else if (tiledetect_var1) {
+        Link_AddInVelocityY();
+        goto endif_1b;
+      }
+    } // else_3
+    if (R14 & 0x70) {
+      if ((R14 >> 8) & 7) {
+        force_move_any_direction = (sign8(link_y_vel)) ? 8 : 4;
+      } // endif_6
+
+      is_standing_in_doorway = 1;
+      link_on_conveyor_belt = 0;
+      if ((R14 & 0x70) != 0x70) {
+        if (R14 & 5) { // if_7
+          link_moving_against_diag_tile = 0;
+          Link_AddInVelocityYFalling();
+          CalculateSnapScratch_Y();
+          is_standing_in_doorway = 0;
+
+          if (R14 & 0x20 && (R14 & 1) == 0 && (link_x_coord & 7) == 1)
+            link_x_coord &= ~7;
+          goto else_7;
+        }
+        if (R14 & 0x20)
+          goto else_7;
+      } else { // else_7
+else_7:
+        if (!(tile_coll_flag & 2))
+          link_cant_change_direction &= ~2;
+        return;
+      }
+    }
+  } // endif_1
+
+  if (!(tile_coll_flag & 2)) {
+    is_standing_in_doorway = 0;
+  }
+
+endif_1b:
+  if (!(tile_coll_flag & 2)) {
+    link_cant_change_direction &= ~2;
+    room_transitioning_flags = 0;
+    force_move_any_direction = 0;
+  } // label_3
+
+label_3:
+
+  if ((R14 & 7) == 0 && (R12 & 5) != 0) {
+    link_on_conveyor_belt = 0;
+    FlagMovingIntoSlopes_Y();
+    if ((link_moving_against_diag_tile & 0xf) != 0)
+      return;
+  } // endif_9
+
+  link_moving_against_diag_tile = 0;
+  if (tiledetect_key_lock_gravestones & 0x20) {
+    uint16 bak = R14;
+    int dummy;
+    OpenChestForItem(tiledetect_tile_type, &dummy);
+    tiledetect_tile_type = 0;
+    R14 = bak;
+  }
+  if (!link_is_on_lower_level) {
+    if (tiledetect_water_staircase & 7) {
+      byte_7E0322 |= 1;
+    } else if ((bitfield_spike_cactus_tiles & 7) == 0 && (R14 & 2) == 0) { // else_11
+      byte_7E0322 &= ~1;
+    } // endif_11
+  } else { // else_10
+    if ((tiledetect_moving_floor_tiles & 7) != 0) {
+      byte_7E0322 |= 2;
+    } else {
+      byte_7E0322 &= ~2;
+    }
+  } // endif_11
+
+  if (tiledetect_misc_tiles & 0x2200) {
+    uint16 dy = tiledetect_misc_tiles & 0x2000 ? 8 : 0;
+
+    static const uint8 kLink_DoMoveXCoord_Indoors_dx[] = { 8, 8, 0, 15 };
+    static const uint8 kLink_DoMoveXCoord_Indoors_dy[] = { 8, 24, 16, 16 };
+
+    link_rupees_goal += 5;
+    uint16 y = link_y_coord + kLink_DoMoveXCoord_Indoors_dy[link_last_direction_moved_towards] - dy;
+    uint16 x = link_x_coord + kLink_DoMoveXCoord_Indoors_dx[link_last_direction_moved_towards];
+
+    Dungeon_DeleteRupeeTile(x, y);
+    Ancilla_Sfx3_Near(10);
+  }  // endif_12_norupee
+
+  if (tiledetect_var4 & 0x22) {
+    link_on_conveyor_belt = tiledetect_var4 & 0x20 ? 2 : 1;
+  } else if (tiledetect_var4 & 0x2200) {
+    link_on_conveyor_belt = tiledetect_var4 & 0x2000 ? 4 : 3;
+  } else {
+    if (!(bitfield_spike_cactus_tiles & 7) && !(R14 & 2))
+      link_on_conveyor_belt = 0;
+  } // endif_15
+
+  if ((tiledetect_vertical_ledge & 7) == 7 && RunLedgeHopTimer()) {
+    Link_CancelDash();
+    about_to_jump_off_ledge++;
+    link_disable_sprite_damage = 1;
+    link_auxiliary_state = 2;
+    Ancilla_Sfx2_Near(0x20);
+
+    goto endif_19;
+  } else if ((tiledetect_deepwater & 7) == 7 && link_is_in_deep_water == 0) {
+    // if_20
+    Link_CancelDash();
+    if (TS_copy == 0) {
+      Dungeon_HandleLayerChange();
+    } else {
+      link_is_in_deep_water = 1;
+      link_some_direction_bits = link_direction_last;
+      link_state_bits = 0;
+      link_picking_throw_state = 0;
+      link_grabbing_wall = 0;
+      link_speed_setting = 0;
+      Link_ResetSwimmingState();
+      Ancilla_Sfx2_Near(0x20);
+    }
+endif_19:
+    link_disable_sprite_damage = 1;
+    Link_HopInOrOutOfWater_Y();
+  } else {
+    // else_20
+    if ((tiledetect_normal_tiles & 2) && link_is_in_deep_water != 0) {
+      if (link_auxiliary_state != 0) {
+        R14 = 7;
+      } else {
+        Link_CancelDash();
+        link_direction_last = link_some_direction_bits;
+        link_is_in_deep_water = 0;
+        if (AncillaAdd_Splash(0x15, 0)) {
+          link_is_in_deep_water = 1;
+          R14 = 7;
+        } else {
+          link_disable_sprite_damage = 1;
+          Link_HopInOrOutOfWater_Y();
+        }
+      }
+    }
+  } // endif_21
+
+  if ((tiledetect_stair_tile & 7) == 7) {
+    if (link_incapacitated_timer) {
+      R14 &= ~0xff;
+      R14 |= tiledetect_stair_tile & 7;
+      HandlePushingBonkingSnaps_Y();
+      return;
+    }
+    if (tiledetect_inroom_staircase & 0x77) {
+      submodule_index = tiledetect_inroom_staircase & 0x70 ? 16 : 8;
+      main_module_index = 7;
+      Link_CancelDash();
+    } else if (enhanced_features0 & kFeatures0_TurnWhileDashing) {
+      // avoid weirdness in stairs
+      Link_CancelDash();
+    }
+
+    if ((link_last_direction_moved_towards & 2) == 0) {
+      link_speed_setting = 2;
+      link_speed_modifier = 1;
+      return;
+    }
+  }
+
+  if (link_speed_setting == 2)
+    link_speed_setting = link_is_running ? 16 : 0;
+
+  if (link_speed_modifier == 1)
+    link_speed_modifier = 2;
+
+  if (tiledetect_pit_tile & 5 && (R14 & 2) == 0) {
+    if (link_player_handler_state == 5 || link_player_handler_state == 2)
+      return;
+    byte_7E005C = 9;
+    link_this_controls_sprite_oam = 0;
+    player_near_pit_state = 1;
+    link_player_handler_state = kPlayerState_FallingIntoHole;
+    return;
+  } // endif_23
+
+  link_this_controls_sprite_oam = 0;
+
+  if (bitfield_spike_cactus_tiles & 7) {
+    if ((link_incapacitated_timer | countdown_for_blink | link_cape_mode) == 0) {
+      if (((link_last_direction_moved_towards == 0) ? (link_y_coord & 4) == 0 : ((link_y_coord & 4) != 0)) && (countdown_for_blink == 0)) {
+        link_give_damage = 8;
+        Link_CancelDash();
+        Link_ForceUnequipCape_quietly();
+        LinkApplyTileRebound();
+        return;
+      }
+    } else {
+      R14 &= ~0xFF;
+      R14 |= bitfield_spike_cactus_tiles & 7;
+    } // endif_24
+  } // endif_24
+  if (dung_hdr_collision == 0 || dung_hdr_collision == 4 || !link_is_on_lower_level) {
+    if (tiledetect_var2 && link_num_orthogonal_directions == 0) {
+      byte_7E02C2 = tiledetect_var2;
+      if (!sign8(--gravestone_push_timeout))
+        goto endif_26;
+      uint16 bits = tiledetect_var2;
+      int i = 15;
+      do {
+        if (bits & 0x8000) {
+          uint8 idx = FindFreeMovingBlockSlot(i);
+          if (idx == 0xff)
+            continue;
+          R14 = idx;
+          if (InitializePushBlock(idx, i * 2))
+            continue;
+          Sprite_Dungeon_DrawSinglePushBlock(idx * 2);
+          R14 = 4;  // Unwanted side effect
+          pushedblock_facing[idx] = link_last_direction_moved_towards * 2;
+          push_block_direction = link_last_direction_moved_towards * 2;
+          pushedblocks_target[idx] = (pushedblocks_y_lo[idx] - (link_last_direction_moved_towards == 1)) & 0xf;
+        }
+      } while (bits <<= 1, --i >= 0);
+    }
+    // endif_27
+    gravestone_push_timeout = 21;
+  }
+  // endif_26
+endif_26:
+  HandlePushingBonkingSnaps_Y();
+}
+
+void HandlePushingBonkingSnaps_Y() {  // 87bdb1
+  if (R14 & 7) {
+    if (link_player_handler_state == kPlayerState_Swimming) {
+      if ((uint8)dung_floor_y_vel == 0)
+        ResetAllAcceleration();
+
+      if (link_num_orthogonal_directions != 0) {
+        Link_AddInVelocityYFalling();
+        goto label_a;
+      }
+    }  // endif_2
+
+    if (R14 & 2 || (R14 & 5) == 5) {
+      uint16 bak = R14;
+      Link_BonkAndSmash();
+      RepelDash();
+      R14 = bak;
+    }
+
+    fallhole_var1 = 1;
+
+    if ((R14 & 2) == 2) {
+      Link_AddInVelocityYFalling();
+    } else {
+      if (link_num_orthogonal_directions == 1)
+        goto returnb;
+      Link_AddInVelocityYFalling();
+      if (link_num_orthogonal_directions == 2)
+        goto returnb;
+    } // endif_4
+
+label_a:
+
+    if ((R14 & 5) == 5) {
+      Link_BonkAndSmash();
+      RepelDash();
+    } else if (R14 & 4) {
+      uint8 tt = sign8(link_y_vel) ? link_y_vel : -link_y_vel;
+      uint8 r0 = sign8(tt) ? 0xff : 1;
+      if ((R14 & 2) == 0) {
+        if (link_x_coord & 7) {
+          link_x_coord += (int8)r0;
+          HandleNudging(r0);
+          return;
+        }
+        Link_BonkAndSmash();
+        RepelDash();
+      }
+    } else { // else_7
+      uint8 tt = sign8(link_y_vel) ? -link_y_vel : link_y_vel;
+      uint8 r0 = sign8(tt) ? 0xff : 1;
+      if ((R14 & 2) == 0) {
+        if (link_x_coord & 7) {
+          link_x_coord += (int8)r0;
+          HandleNudging(r0);
+          return;
+        }
+        Link_BonkAndSmash();
+        RepelDash();
+      }
+    }
+    // endif_10
+    if (link_last_direction_moved_towards * 2 == link_direction_facing) {
+      bitmask_of_dragstate |= (tile_coll_flag & 1) << 1;
+      if (button_b_frames == 0 && !sign8(--link_timer_push_get_tired))
+        return;
+
+      bitmask_of_dragstate |= (tiledetect_misc_tiles & 0x20) ? tile_coll_flag << 3 : tile_coll_flag;
+    }
+  } else {// else_1
+    if (link_is_on_lower_level)
+      return;
+    bitmask_of_dragstate &= ~9;
+  } // endif_1
+
+returnb:
+  link_timer_push_get_tired = 32;
+  bitmask_of_dragstate &= ~2;
+}
+
+void StartMovementCollisionChecks_Y_HandleOutdoors() {  // 87beaf
+  if (link_speed_setting == 2)
+    link_speed_setting = link_is_running ? 16 : 0;
+
+  if ((tiledetect_pit_tile & 5) != 0 && (R14 & 2) == 0) {
+    if (link_player_handler_state != 5 && link_player_handler_state != 2) {
+      // start fall into hole
+      byte_7E005C = 9;
+      link_this_controls_sprite_oam = 0;
+      player_near_pit_state = 1;
+      link_player_handler_state = kPlayerState_FallingIntoHole;
+    }
+    return;
+  }
+
+  if (tiledetect_read_something & 2) {
+    interacting_with_liftable_tile_x1 = interacting_with_liftable_tile_x2 >> 1;
+  } else {
+    interacting_with_liftable_tile_x1 = 0;
+  }  // endif_2
+
+  if ((tiledetect_deepwater & 2) && !link_is_in_deep_water && !link_auxiliary_state) {
+    Link_ResetSwordAndItemUsage();
+    Link_CancelDash();
+    link_is_in_deep_water = 1;
+    link_some_direction_bits = link_direction_last;
+    link_grabbing_wall = 0;
+    link_speed_setting = 0;
+    Link_ResetSwimmingState();
+    if ((draw_water_ripples_or_grass == 1) && (Link_ForceUnequipCape_quietly(), link_item_flippers != 0)) {
+      if (!link_is_bunny_mirror)
+        link_player_handler_state = kPlayerState_Swimming;
+    } else {
+      Ancilla_Sfx2_Near(0x20);
+      link_y_coord = (link_y_coord_safe_return_hi << 8) | link_y_coord_safe_return_lo;
+      link_x_coord = (link_x_coord_safe_return_hi << 8) | link_x_coord_safe_return_lo;
+      link_disable_sprite_damage = 1;
+      Link_HopInOrOutOfWater_Y();
+    }
+  }  // endif_afterSwimCheck
+
+  if (link_is_in_deep_water) {
+    if (tiledetect_vertical_ledge & 7) {
+      R14 = tiledetect_vertical_ledge & 7;
+      HandlePushingBonkingSnaps_Y();
+      return;
+    }
+    if ((tiledetect_stair_tile & 7) == 7 || (tiledetect_normal_tiles & 7) == 7) {
+      Link_CancelDash();
+      link_is_in_deep_water = 0;
+      if (link_auxiliary_state == 0) {
+        link_direction_last = link_some_direction_bits;
+        link_disable_sprite_damage = 1;
+        AncillaAdd_Splash(0x15, 0);
+        Link_HopInOrOutOfWater_Y();
+        return;
+      }
+    }
+  }
+
+  if (detection_of_ledge_tiles_horiz_uphoriz & 2 || detection_of_unknown_tile_types & 0x22) {
+    R14 = 7;
+    HandlePushingBonkingSnaps_Y();
+    return;
+  }
+
+  if (tiledetect_vertical_ledge & 0x70 && RunLedgeHopTimer()) {
+    Link_CancelDash();
+    link_disable_sprite_damage = 1;
+    allow_scroll_z = 1;
+    link_player_handler_state = 11;
+    link_incapacitated_timer = 0;
+    link_z_coord_mirror = -1;
+    bitmask_of_dragstate = 0;
+    link_speed_setting = 0;
+    link_actual_vel_z_copy_mirror = link_actual_vel_z_mirror = link_is_in_deep_water ? 14 : 20;
+    link_auxiliary_state = link_is_in_deep_water ? 4 : 2;
+    return;
+  }
+
+  if (tiledetect_vertical_ledge & 7 && RunLedgeHopTimer()) {
+    Ancilla_Sfx2_Near(0x20);
+    link_disable_sprite_damage = 1;
+    Link_CancelDash();
+    bitmask_of_dragstate = 0;
+    link_speed_setting = 0;
+    Link_FindValidLandingTile_North();
+    return;
+  }
+
+  if (!link_is_in_deep_water) {
+    if (tiledetect_ledges_down_leftright & 7 && !(tiledetect_vertical_ledge & 0x77)) {
+      uint8 xand = index_of_interacting_tile == 0x2f ? 4 : 1;
+      if ((tiledetect_ledges_down_leftright & xand) && RunLedgeHopTimer()) {
+        Link_CancelDash();
+        link_actual_vel_x = tiledetect_ledges_down_leftright & 4 ? 16 : -16;
+        link_disable_sprite_damage = 1;
+        bitmask_of_dragstate = 0;
+        link_speed_setting = 0;
+        allow_scroll_z = 1;
+        link_auxiliary_state = 2;
+        link_actual_vel_z_copy_mirror = link_actual_vel_z_mirror = 20;
+        link_z_coord_mirror |= 0xff;
+        link_incapacitated_timer = 0;
+        link_player_handler_state = 14;
+        return;
+      }
+    } // endif_6
+
+    if (detection_of_ledge_tiles_horiz_uphoriz & 0x70 && !(tiledetect_vertical_ledge & 0x77) && RunLedgeHopTimer()) {
+      Link_CancelDash();
+      Ancilla_Sfx2_Near(0x20);
+      link_last_direction_moved_towards = detection_of_ledge_tiles_horiz_uphoriz & 0x40 ? 3 : 2;
+      link_disable_sprite_damage = 1;
+      bitmask_of_dragstate = 0;
+      link_speed_setting = 0;
+      Link_FindValidLandingTile_DiagonalNorth();
+      return;
+    }
+  } // endif_7
+
+  if ((tiledetect_stair_tile & 7) == 7) {
+    if (link_incapacitated_timer != 0) {
+      R14 = tiledetect_stair_tile & 7;
+      HandlePushingBonkingSnaps_Y();
+      return;
+    } else if (!(link_last_direction_moved_towards & 2)) {
+      link_speed_setting = 2;
+      link_speed_modifier = 1;
+      return;
+    }
+  }  // endif_8
+
+  if (link_speed_setting == 2)
+    link_speed_setting = link_is_running ? 16 : 0;
+
+  if (link_speed_modifier == 1)
+    link_speed_modifier = 2;
+
+  if ((R14 & 7) == 0 && (R12 & 5) != 0) {
+    FlagMovingIntoSlopes_Y();
+    if ((link_moving_against_diag_tile & 0xf) != 0)
+      return;
+  }  // endif_11
+
+  link_moving_against_diag_tile = 0;
+  if (tiledetect_key_lock_gravestones & 2 && link_last_direction_moved_towards == 0) {
+    if (link_is_running || sign8(--gravestone_push_timeout)) {
+      uint16 bak = R14;
+      AncillaAdd_GraveStone(0x24, 4);
+      R14 = bak;
+      gravestone_push_timeout = 52;
+    }
+  } else {
+    gravestone_push_timeout = 52;
+  } // endif_12
+
+  if ((bitfield_spike_cactus_tiles & 7) != 0) {
+    if ((link_incapacitated_timer | countdown_for_blink | link_cape_mode) == 0) {
+      if (link_last_direction_moved_towards == 0 ? ((link_y_coord & 4) == 0) : ((link_y_coord & 4) != 0)) {
+        link_give_damage = 8;
+        Link_CancelDash();
+        Link_ForceUnequipCape_quietly();
+        LinkApplyTileRebound();
+        return;
+      }
+    } else {
+      R14 = bitfield_spike_cactus_tiles & 7;
+    }
+  }  // endif_13
+  HandlePushingBonkingSnaps_Y();
+}
+
+bool RunLedgeHopTimer() { // carry  // 87c16d
+  bool rv = false;
+  if (link_auxiliary_state != 1) {
+    if (!link_is_running) {
+      if (sign8(--link_timer_jump_ledge)) {
+        link_timer_jump_ledge = 19;
+        return true;
+      }
+    } else {
+      rv = true;
+    }
+  }
+  link_y_coord = link_y_coord_prev;
+  link_x_coord = link_x_coord_prev;
+  link_subpixel_y = link_subpixel_x = 0;
+  return rv;
+}
+
+void Link_BonkAndSmash() {  // 87c1a1
+  if (!link_is_running || (link_dash_ctr == 64) || !(bitmask_for_dashable_tiles & 0x70))
+    return;
+  for (int i = 0; i < 2; i++) {
+    Point16U pt;
+    int j = Overworld_SmashRockPile(i != 0, &pt);
+    if (j >= 0) {
+      int k = FindInByteArray(kLink_Lift_tab, (uint8)j, 9);
+      if (k >= 0) {
+        if (k == 2 || k == 4)
+          Ancilla_Sfx3_Near(0x32);
+        Sprite_SpawnImmediatelySmashedTerrain(k, pt.x, pt.y);
+      }
+    }
+  }
+}
+
+void Link_AddInVelocityYFalling() {  // 87c1e4
+  link_y_coord -= (tiledetect_which_y_pos[0] & 7) - (sign8(link_y_vel) ? 8 : 0);
+}
+
+// Adjust X coord to fit through door
+void CalculateSnapScratch_Y() {  // 87c1ff
+  uint8 yv = link_y_vel;
+  if (R14 & 4) {
+    if (!sign8(yv)) yv = -yv;
+  } else {
+    if (sign8(yv)) yv = -yv;
+  }
+  link_x_coord += !sign8(yv) ? 1 : -1;
+}
+
+void ChangeAxisOfPerpendicularDoorMovement_Y() {  // 87c23d
+  link_cant_change_direction |= 2;
+  uint8 t = (R14 | (R14 >> 4)) & 0xf;
+  if (!(t & 7)) {
+    is_standing_in_doorway = 0;
+    return;
+  }
+  int8 vel;
+  uint8 dir;
+
+  if ((uint8)link_x_coord >= 0x80) {
+    uint8 t = link_y_vel;
+    if (!sign8(t)) t = -t;
+    vel = sign8(t) ? -1 : 1;
+    dir = 4;
+  } else {
+    uint8 t = link_y_vel;
+    if (sign8(t)) t = -t;
+    vel = sign8(t) ? -1 : 1;
+    dir = 6;
+  }
+  if (!(link_cant_change_direction & 1))
+    link_direction_facing = dir;
+  link_x_coord += vel;
+}
+
+void Link_AddInVelocityY() {  // 87c29f
+  link_y_coord -= (int8)link_y_vel;
+}
+
+void Link_HopInOrOutOfWater_Y() {  // 87c2c3
+  static const uint8 kRecoilVelY[] = { 24, 16, 16 };
+  static const uint8 kRecoilVelZ[] = { 36, 24, 24 };
+
+  uint8 ts = !player_is_indoors ? 2 :
+    about_to_jump_off_ledge ? 0 : TS_copy;
+
+  int8 vel = kRecoilVelY[ts];
+  if (!link_last_direction_moved_towards)
+    vel = -vel;
+
+  link_actual_vel_y = vel;
+  link_actual_vel_x = 0;
+  link_actual_vel_z_copy = link_actual_vel_z = kRecoilVelZ[ts];
+  link_z_coord = 0;
+  link_incapacitated_timer = 16;
+  if (link_auxiliary_state != 2) {
+    link_auxiliary_state = 1;
+    link_electrocute_on_touch = 0;
+  }
+  link_player_handler_state = 6;
+}
+
+void Link_FindValidLandingTile_North() {  // 87c36c
+  uint16 y_coord_bak = link_y_coord;
+  link_y_coord_original = link_y_coord;
+
+  for (;;) {
+    link_y_coord -= 16;
+    TileDetect_Movement_Y(link_last_direction_moved_towards);
+    uint8 k = tiledetect_normal_tiles | tiledetect_destruction_aftermath | tiledetect_thick_grass | tiledetect_deepwater;
+    if ((k & 7) == 7)
+      break;
+  }
+
+  if (tiledetect_deepwater & 7) {
+    link_auxiliary_state = 1;
+    link_electrocute_on_touch = 0;
+    link_is_in_deep_water = 1;
+    link_some_direction_bits = link_direction_last;
+    Link_ResetSwimmingState();
+    link_grabbing_wall = 0;
+    link_speed_setting = 0;
+  }
+
+  link_y_coord -= 16;
+  link_y_coord_original -= link_y_coord;
+  link_y_coord = y_coord_bak;
+
+  uint8 o = (uint8)link_y_coord_original >> 3;
+
+  static const uint8 kLink_MoveY_RecoilOther_dy[32] = { 16, 16, 20, 20, 24, 24, 28, 28, 32, 32, 36, 36, 40, 40, 44, 44, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48 };
+  static const uint8 kLink_MoveY_RecoilOther_dz[32] = { 24, 24, 24, 24, 28, 28, 28, 28, 32, 32, 32, 32, 36, 36, 36, 36, 40, 40, 40, 40, 44, 44, 44, 44, 48, 48, 48, 48, 52, 52, 52, 52 };
+  static const uint8 kLink_MoveY_RecoilOther_timer[32] = { 16, 16, 20, 20, 24, 24, 28, 28, 32, 32, 36, 36, 40, 40, 44, 44, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48 };
+
+  int8 dy = kLink_MoveY_RecoilOther_dy[o];
+  link_actual_vel_y = (link_last_direction_moved_towards != 0) ? dy : -dy;
+  link_actual_vel_x = 0;
+  link_actual_vel_z_copy = link_actual_vel_z = kLink_MoveY_RecoilOther_dz[o];
+  link_z_coord = 0;
+  link_incapacitated_timer = kLink_MoveY_RecoilOther_timer[o];
+  link_auxiliary_state = 2;
+  link_electrocute_on_touch = 0;
+  link_player_handler_state = 6;
+}
+
+void Link_FindValidLandingTile_DiagonalNorth() {  // 87c46d
+  uint8 b0 = link_y_coord_safe_return_lo;
+  uint16 b1 = link_x_coord;
+  uint8 dir = link_last_direction_moved_towards;
+
+  link_actual_vel_x = (link_last_direction_moved_towards != 2 ? 1 : -1);
+  link_last_direction_moved_towards = 0;
+  LinkHop_FindLandingSpotDiagonallyDown();
+
+  link_x_coord = b1;
+  link_y_coord_safe_return_lo = b0;
+
+  uint16 o = (uint16)(link_y_coord_original - link_y_coord) >> 3;
+  link_y_coord = link_y_coord_original;
+
+  static const uint8 kLink_JumpOffLedgeUpDown_dx[32] = { 8, 8, 8, 8, 16, 16, 16, 16, 24, 24, 24, 24, 16, 16, 16, 16, 8, 20, 20, 20, 24, 24, 24, 24, 28, 28, 28, 28, 32, 32, 32, 32 };
+  static const uint8 kLink_JumpOffLedgeUpDown_dy[32] = { 8, 8, 8, 8, 16, 16, 20, 20, 24, 24, 24, 24, 32, 32, 32, 32, 8, 20, 20, 20, 24, 24, 24, 24, 28, 28, 28, 28, 32, 32, 32, 32 };
+  static const uint8 kLink_JumpOffLedgeUpDown_dz[32] = { 32, 32, 32, 32, 32, 32, 32, 32, 36, 36, 36, 36, 40, 40, 40, 40, 32, 40, 40, 40, 44, 44, 44, 44, 48, 48, 48, 48, 52, 52, 52, 52 };
+
+  link_actual_vel_y = -kLink_JumpOffLedgeUpDown_dy[o];
+  uint8 dx = kLink_JumpOffLedgeUpDown_dx[o];
+  link_actual_vel_x = (dir != 2) ? dx : -dx;
+  link_actual_vel_z_copy = link_actual_vel_z = kLink_JumpOffLedgeUpDown_dz[o];
+  link_z_coord = 0;
+  link_z_coord_mirror &= ~0xff;
+  link_auxiliary_state = 2;
+  link_electrocute_on_touch = 0;
+  link_player_handler_state = 13;
+}
+
+void StartMovementCollisionChecks_X() {  // 87c4d4
+  if (!link_x_vel)
+    return;
+
+  if (is_standing_in_doorway == 2)
+    link_last_direction_moved_towards = (uint8)link_x_coord < 0x80 ? 2 : 3;
+  else
+    link_last_direction_moved_towards = sign8(link_x_vel) ? 2 : 3;
+  TileDetect_Movement_X(link_last_direction_moved_towards);
+  if (player_is_indoors)
+    StartMovementCollisionChecks_X_HandleIndoors();
+  else
+    StartMovementCollisionChecks_X_HandleOutdoors();
+}
+
+void StartMovementCollisionChecks_X_HandleIndoors() {  // 87c4ff
+  if (sign8(link_state_bits) || link_incapacitated_timer != 0) {
+    R14 |= R14 >> 4;
+  } else {
+    if (link_num_orthogonal_directions == 0)
+      link_speed_modifier = 0;
+    if (is_standing_in_doorway == 1 && link_num_orthogonal_directions == 0) {
+      if (dung_hdr_collision != 3 || link_is_on_lower_level == 0) {
+        SnapOnX();
+        int8 spd = ChangeAxisOfPerpendicularDoorMovement_X();
+        HandleNudgingInADoor(spd);
+        return;
+      }
+      goto label_3;
+    } // else_3
+
+    if (R14 & 0x70) {
+      if ((R14 >> 8) & 7) {
+        force_move_any_direction = (sign8(link_x_vel)) ? 2 : 1;
+      } // endif_6
+
+      is_standing_in_doorway = 2;
+      link_on_conveyor_belt = 0;
+      if ((R14 & 0x70) != 0x70) {
+        if (R14 & 7) { // if_7
+          link_moving_against_diag_tile = 0;
+          is_standing_in_doorway = 0;
+          SnapOnX();
+          CalculateSnapScratch_X();
+          return;
+        }
+        if (R14 & 0x70)
+          goto else_7;
+      } else { // else_7
+else_7:
+        if (!(tile_coll_flag & 2))
+          link_cant_change_direction &= ~2;
+        return;
+      }
+    }
+  } // endif_1
+
+  if (!(tile_coll_flag & 2)) {
+    link_cant_change_direction &= ~2;
+    is_standing_in_doorway = 0;
+    room_transitioning_flags = 0;
+    force_move_any_direction = 0;
+  }  // label_3
+
+label_3:
+
+  if ((R14 & 2) == 0 && (R12 & 5) != 0) {
+    link_on_conveyor_belt = 0;
+    FlagMovingIntoSlopes_X();
+    if ((link_moving_against_diag_tile & 0xf) != 0)
+      return;
+  } // endif_9
+
+  link_moving_against_diag_tile = 0;
+  if (!link_is_on_lower_level) {
+    if (tiledetect_water_staircase & 7) {
+      byte_7E0322 |= 1;
+    } else if ((bitfield_spike_cactus_tiles & 7) == 0 && (R14 & 2) == 0) { // else_11
+      byte_7E0322 &= ~1;
+    } // endif_11
+  } else { // else_10
+    if ((tiledetect_moving_floor_tiles & 7) != 0) {
+      byte_7E0322 |= 2;
+    } else {
+      byte_7E0322 &= ~2;
+    }
+  } // endif_11
+
+  if (tiledetect_misc_tiles & 0x2200) {
+    uint16 dy = tiledetect_misc_tiles & 0x2000 ? 8 : 0;
+
+    static const uint8 kLink_DoMoveXCoord_Indoors_dx[] = { 8, 8, 0, 15 };
+    static const uint8 kLink_DoMoveXCoord_Indoors_dy[] = { 8, 24, 16, 16 };
+
+    link_rupees_goal += 5;
+    uint16 y = link_y_coord + kLink_DoMoveXCoord_Indoors_dy[link_last_direction_moved_towards] - dy;
+    uint16 x = link_x_coord + kLink_DoMoveXCoord_Indoors_dx[link_last_direction_moved_towards];
+
+    Dungeon_DeleteRupeeTile(x, y);
+    Ancilla_Sfx3_Near(10);
+  }  // endif_12_norupee
+
+  if (tiledetect_var4 & 0x22) {
+    link_on_conveyor_belt = tiledetect_var4 & 0x20 ? 2 : 1;
+  } else if (tiledetect_var4 & 0x2200) {
+    link_on_conveyor_belt = tiledetect_var4 & 0x2000 ? 4 : 3;
+  } else {
+    if (!(bitfield_spike_cactus_tiles & 7) && !(R14 & 2))
+      link_on_conveyor_belt = 0;
+  } // endif_15
+
+  if ((detection_of_ledge_tiles_horiz_uphoriz & 7) == 7 && RunLedgeHopTimer()) {
+    Link_CancelDash();
+    about_to_jump_off_ledge++;
+    link_auxiliary_state = 2;
+    goto endif_19;
+  } else if ((tiledetect_deepwater & 7) == 7 && link_is_in_deep_water == 0 && link_player_handler_state != 6) {
+    // if_20
+    link_y_coord = link_y_coord_safe_return_lo | link_y_coord_safe_return_hi << 8;
+    link_x_coord = link_x_coord_safe_return_lo | link_x_coord_safe_return_hi << 8;
+    Link_CancelDash();
+    if (TS_copy == 0) {
+      Dungeon_HandleLayerChange();
+    } else {
+      link_is_in_deep_water = 1;
+      link_some_direction_bits = link_direction_last;
+      link_state_bits = 0;
+      link_picking_throw_state = 0;
+      link_grabbing_wall = 0;
+      link_speed_setting = 0;
+      Link_ResetSwimmingState();
+    }
+endif_19:
+    link_disable_sprite_damage = 1;
+    Link_HopInOrOutOfWater_X();
+    Ancilla_Sfx2_Near(0x20);
+  } else {
+    // else_20
+    if ((tiledetect_normal_tiles & 7) == 7 && link_is_in_deep_water != 0) {
+      if (link_auxiliary_state != 0) {
+        R14 = 7;
+      } else {
+        Link_CancelDash();
+        if (link_auxiliary_state == 0) {
+          link_direction_last = link_some_direction_bits;
+          link_is_in_deep_water = 0;
+          AncillaAdd_Splash(0x15, 0);
+          link_disable_sprite_damage = 1;
+          Link_HopInOrOutOfWater_X();
+        }
+      }
+    }
+  } // endif_21
+
+  if (tiledetect_pit_tile & 5 && (R14 & 2) == 0) {
+    if (link_player_handler_state == 5 || link_player_handler_state == 2)
+      return;
+    byte_7E005C = 9;
+    link_this_controls_sprite_oam = 0;
+    player_near_pit_state = 1;
+    link_player_handler_state = kPlayerState_FallingIntoHole;
+    return;
+  } // endif_23
+
+  player_near_pit_state = 0;
+
+  if (bitfield_spike_cactus_tiles & 7) {
+    if ((link_incapacitated_timer | countdown_for_blink | link_cape_mode) == 0) {
+      if (((link_last_direction_moved_towards == 2) ? (link_x_coord & 4) == 0 : ((link_x_coord & 4) != 0)) && (countdown_for_blink == 0)) {
+        link_give_damage = 8;
+        Link_CancelDash();
+        Link_ForceUnequipCape_quietly();
+        LinkApplyTileRebound();
+        return;
+      }
+    } else {
+      R14 &= ~0xFF;
+      R14 |= bitfield_spike_cactus_tiles & 7;
+    } // endif_24
+  } // endif_24
+  if (dung_hdr_collision == 0 || dung_hdr_collision == 4 || !link_is_on_lower_level) {
+    if (tiledetect_var2 && link_num_orthogonal_directions == 0) {
+      byte_7E02C2 = tiledetect_var2;
+      if (!sign8(--gravestone_push_timeout))
+        goto endif_26;
+      uint16 bits = tiledetect_var2;
+      int i = 15;
+      do {
+        if (bits & 0x8000) {
+          uint8 idx = FindFreeMovingBlockSlot(i);
+          if (idx == 0xff)
+            continue;
+          R14 = idx;  // This seems like it's overwriting the tiledetector's stuff
+          if (InitializePushBlock(idx, i * 2))
+            continue;
+          Sprite_Dungeon_DrawSinglePushBlock(idx * 2);
+          R14 = 4;
+          pushedblock_facing[idx] = link_last_direction_moved_towards * 2;
+          push_block_direction = link_last_direction_moved_towards * 2;
+          pushedblocks_target[idx] = (pushedblocks_x_lo[idx] - (link_last_direction_moved_towards != 2)) & 0xf;
+        }
+      } while (bits <<= 1, --i >= 0);
+    }
+    // endif_27
+    gravestone_push_timeout = 21;
+  }
+  // endif_26
+endif_26:
+  if (link_num_orthogonal_directions == 0) {
+    link_speed_modifier = 0;
+    if (link_speed_setting == 2)
+      link_speed_setting = 0;
+  }
+  HandlePushingBonkingSnaps_X();
+}
+
+void HandlePushingBonkingSnaps_X() {  // 87c7fc
+  if (R14 & 7) {
+    if (link_player_handler_state == kPlayerState_Swimming && (uint8)dung_floor_x_vel == 0)
+      ResetAllAcceleration();
+
+    if (R14 & 2) {
+      uint16 bak = R14;
+      Link_BonkAndSmash();
+      RepelDash();
+      R14 = bak;
+    }
+
+    fallhole_var1 = 1;
+
+    if ((R14 & 7) == 7) {
+      SnapOnX();
+    } else {
+      if (link_num_orthogonal_directions == 2)
+        goto returnb;
+      SnapOnX();
+      if (link_num_orthogonal_directions == 1)
+        goto returnb;
+    } // endif_4
+
+    if ((R14 & 5) == 5) {
+      Link_BonkAndSmash();
+      RepelDash();
+    } else if (R14 & 4) {
+      uint8 tt = sign8(link_x_vel) ? link_x_vel : -link_x_vel;
+      uint8 r0 = sign8(tt) ? 0xff : 1;
+      if ((R14 & 2) == 0) {
+        if (link_y_coord & 7) {
+          link_y_coord += (int8)r0;
+          HandleNudging(r0);
+          return;
+        }
+        Link_BonkAndSmash();
+        RepelDash();
+      }
+    } else { // else_7
+      uint8 tt = sign8(link_x_vel) ? -link_x_vel : link_x_vel;
+      uint8 r0 = sign8(tt) ? 0xff : 1;
+      if ((R14 & 2) == 0) {
+        if (link_y_coord & 7) {
+          link_y_coord += (int8)r0;
+          HandleNudging(r0);
+          return;
+        }
+        Link_BonkAndSmash();
+        RepelDash();
+      }
+    }
+    // endif_10
+    if (link_last_direction_moved_towards * 2 == link_direction_facing) {
+      bitmask_of_dragstate |= (tile_coll_flag & 1) << 1;
+      if (button_b_frames == 0 && !sign8(--link_timer_push_get_tired))
+        return;
+
+      bitmask_of_dragstate |= (tiledetect_misc_tiles & 0x20) ? tile_coll_flag << 3 : tile_coll_flag;
+    }
+  } else {// else_1
+    if (link_is_on_lower_level)
+      return;
+    bitmask_of_dragstate &= ~9;
+  } // endif_1
+
+returnb:
+  link_timer_push_get_tired = 32;
+  bitmask_of_dragstate &= ~2;
+}
+
+void StartMovementCollisionChecks_X_HandleOutdoors() {  // 87c8e9
+  if (link_num_orthogonal_directions == 0) {
+    link_speed_modifier = 0;
+    if (link_speed_setting == 2)
+      link_speed_setting = 0;
+  }
+
+  if ((tiledetect_pit_tile & 5) != 0 && (R14 & 2) == 0) {
+    if (link_player_handler_state != 5 && link_player_handler_state != 2) {
+      // start fall into hole
+      byte_7E005C = 9;
+      link_this_controls_sprite_oam = 0;
+      player_near_pit_state = 1;
+      link_player_handler_state = kPlayerState_FallingIntoHole;
+    }
+    return;
+  }
+
+  if (tiledetect_read_something & 2) {
+    interacting_with_liftable_tile_x1b = interacting_with_liftable_tile_x2 >> 1;
+  } else {
+    interacting_with_liftable_tile_x1b = 0;
+  }  // endif_2
+
+  if ((tiledetect_deepwater & 4) && !link_is_in_deep_water && !link_auxiliary_state) {
+    Link_CancelDash();
+    Link_ResetSwordAndItemUsage();
+    link_is_in_deep_water = 1;
+    link_some_direction_bits = link_direction_last;
+    Link_ResetSwimmingState();
+    link_grabbing_wall = 0;
+    link_speed_setting = 0;
+    if ((draw_water_ripples_or_grass == 1) && (Link_ForceUnequipCape_quietly(), link_item_flippers != 0)) {
+      if (!link_is_bunny_mirror)
+        link_player_handler_state = kPlayerState_Swimming;
+    } else {
+      link_y_coord = (link_y_coord_safe_return_hi << 8) | link_y_coord_safe_return_lo;
+      link_x_coord = (link_x_coord_safe_return_hi << 8) | link_x_coord_safe_return_lo;
+      link_disable_sprite_damage = 1;
+      Link_HopInOrOutOfWater_X();
+      Ancilla_Sfx2_Near(0x20);
+    }
+  }  // endif_afterSwimCheck
+
+  if (link_is_in_deep_water ? ((detection_of_ledge_tiles_horiz_uphoriz & 7) == 7) : (tiledetect_vertical_ledge & 0x42)) {
+    // not implemented, jumps to another routine
+    R14 = 7;
+    HandlePushingBonkingSnaps_X();
+    return;
+  } // endif_3
+
+  if ((tiledetect_normal_tiles & 7) == 7 && link_is_in_deep_water) {
+    Link_CancelDash();
+    if (!link_auxiliary_state) {
+      link_direction_last = link_some_direction_bits;
+      link_is_in_deep_water = 0;
+      AncillaAdd_Splash(0x15, 0);
+      link_disable_sprite_damage = 1;
+      Link_HopInOrOutOfWater_X();
+      return;
+    }
+  }  // endif_4
+
+  if ((detection_of_ledge_tiles_horiz_uphoriz & 7) != 0 && RunLedgeHopTimer()) {
+    Ancilla_Sfx2_Near(0x20);
+    link_actual_vel_x = (link_last_direction_moved_towards & 1) ? 0x10 : -0x10;
+    Link_CancelDash();
+    link_auxiliary_state = 2;
+    link_actual_vel_z_mirror = link_actual_vel_z_copy_mirror = 20;
+    link_z_coord_mirror |= 0xff;
+    link_player_handler_state = kPlayerState_FallOfLeftRightLedge;
+    link_disable_sprite_damage = 1;
+    allow_scroll_z = 1;
+    bitmask_of_dragstate = 0;
+    link_speed_setting = 0;
+    if (!player_is_indoors)
+      link_is_on_lower_level = 2;
+
+    uint16 xbak = link_x_coord;
+    uint8 rv = Link_HoppingHorizontally_FindTile_X((link_last_direction_moved_towards & ~2) * 2);
+    link_last_direction_moved_towards = 1;
+    if (rv != 0xff) {
+      Link_HoppingHorizontally_FindTile_Y();
+    } else {
+      LinkHop_FindTileToLandOnSouth();
+    }
+    link_x_coord = xbak;
+    return;
+  }  // endif_5
+
+  if ((detection_of_unknown_tile_types & 0x77) != 0 && RunLedgeHopTimer()) {
+    uint8 sfx = Ancilla_Sfx2_Near(0x20);
+    link_player_handler_state = (sfx & 7) == 0 ? 16 : 15;
+    link_actual_vel_x = (link_last_direction_moved_towards & 1) ? 0x10 : -0x10;
+    Link_CancelDash();
+    link_auxiliary_state = 2;
+    link_actual_vel_z_mirror = link_actual_vel_z_copy_mirror = 20;
+    link_z_coord_mirror |= 0xff;
+    link_incapacitated_timer = 0;
+    link_disable_sprite_damage = 1;
+    allow_scroll_z = 1;
+    bitmask_of_dragstate = 0;
+    link_speed_setting = 0;
+    return;
+  }  // endif_6
+
+  if ((detection_of_ledge_tiles_horiz_uphoriz & 0x70) != 0 &&
+      (detection_of_ledge_tiles_horiz_uphoriz & 0x7) == 0 &&
+      (detection_of_unknown_tile_types & 0x77) == 0 &&
+      link_player_handler_state != 13 && RunLedgeHopTimer()) {
+    Ancilla_Sfx2_Near(0x20);
+    Link_CancelDash();
+    link_disable_sprite_damage = 1;
+    bitmask_of_dragstate = 0;
+    link_speed_setting = 0;
+    Link_FindValidLandingTile_DiagonalNorth();
+    return;
+  }  // endif_7
+
+  if ((tiledetect_ledges_down_leftright & 7) != 0 && (detection_of_ledge_tiles_horiz_uphoriz & 7) == 0 &&
+      (detection_of_unknown_tile_types & 0x77) == 0 && RunLedgeHopTimer()) {
+    link_actual_vel_x = (link_last_direction_moved_towards & 1) ? 0x10 : -0x10;
+    Link_CancelDash();
+    link_auxiliary_state = 2;
+    link_actual_vel_z_mirror = link_actual_vel_z_copy_mirror = 20;
+    link_z_coord_mirror |= 0xff;
+    link_player_handler_state = 14;
+    link_incapacitated_timer = 0;
+    link_disable_sprite_damage = 1;
+    allow_scroll_z = 1;
+    bitmask_of_dragstate = 0;
+    link_speed_setting = 0;
+    return;
+  } // endif_8
+
+  // If force facing down (hold B button), while turboing on the Run key, we'll never
+  // reach FlagMovingIntoSlopes_X causing a Dash Buffering glitch.
+  // Fix by always calling it, not sure why you wouldn't always want to call it.
+  if ((R14 & 2) == 0 && (R12 & 5) != 0) {
+    bool skip_check = link_is_running && !(link_direction_facing & 4);
+    if (!skip_check || (enhanced_features0 & kFeatures0_MiscBugFixes)) {
+      FlagMovingIntoSlopes_X();
+      if ((link_moving_against_diag_tile & 0xf) != 0)
+        return;
+    }  // endif_9
+  }
+
+  link_moving_against_diag_tile = 0;
+
+  if ((bitfield_spike_cactus_tiles & 7) != 0) {
+    if ((link_incapacitated_timer | countdown_for_blink | link_cape_mode) == 0) {
+      if (link_last_direction_moved_towards == 2 ? ((link_x_coord & 4) == 0) : ((link_x_coord & 4) != 0)) {
+        link_give_damage = 8;
+        Link_CancelDash();
+        LinkApplyTileRebound();
+        return;
+      }
+    } else {
+      R14 = bitfield_spike_cactus_tiles & 7;
+    }
+  }  // endif_10
+  HandlePushingBonkingSnaps_X();
+}
+
+void SnapOnX() {  // 87cb84
+  link_x_coord -= (link_x_coord & 7) - (sign8(link_x_vel) ? 8 : 0);
+}
+
+void CalculateSnapScratch_X() {  // 87cb9f
+  if (R14 & 4) {
+    int8 x = link_x_vel;
+    if (x >= 0) x = -x; // wtf
+    link_y_coord += x < 0 ? -1 : 1;
+  } else {
+    int8 x = link_x_vel;
+    if (x < 0) x = -x;
+    link_y_coord += x < 0 ? -1 : 1;
+  }
+}
+
+int8 ChangeAxisOfPerpendicularDoorMovement_X() {  // 87cbdd
+  link_cant_change_direction |= 2;
+  uint8 r0 = (R14 | (R14 >> 4)) & 0xf;
+  if ((r0 & 7) == 0) {
+    is_standing_in_doorway = 0;
+    return r0; // wtf?
+  }
+
+  int8 x_vel = link_x_vel;
+  uint8 dir;
+  if ((uint8)link_y_coord >= 0x80) {
+    if (x_vel >= 0) x_vel = -x_vel;
+    dir = 0;
+  } else {
+    if (x_vel < 0) x_vel = -x_vel;
+    dir = 2;
+  }
+  if (!(link_cant_change_direction & 1))
+    link_direction_facing = dir;
+  link_y_coord += x_vel;
+  return x_vel;
+}
+
+void Link_HopInOrOutOfWater_X() {  // 87cc3c
+  static const uint8 kRecoilVelX[] = { 28, 24, 16 };
+  static const uint8 kRecoilVelZ[] = { 32, 24, 24 };
+
+  uint8 ts = !player_is_indoors ? 2 :
+    about_to_jump_off_ledge ? 0 : TS_copy;
+
+  int8 vel = kRecoilVelX[ts];
+  if (!(link_last_direction_moved_towards & 1))
+    vel = -vel;
+  link_actual_vel_x = vel;
+  link_actual_vel_y = 0;
+  link_actual_vel_z_copy = link_actual_vel_z = kRecoilVelZ[ts];
+  link_incapacitated_timer = 16;
+  if (link_auxiliary_state != 2) {
+    link_auxiliary_state = 1;
+    link_electrocute_on_touch = 0;
+  }
+  link_player_handler_state = 6;
+}
+
+void Link_HandleDiagonalKickback() {  // 87ccab
+  if (link_x_vel && link_y_vel) {
+    link_y_coord_copy = link_y_coord;
+    link_x_coord_copy = link_x_coord;
+
+    TileDetect_Movement_X(sign8(link_x_vel) ? 2 : 3);
+    if ((R12 & 5) == 0)
+      goto noHorizOrNoVertical;
+    FlagMovingIntoSlopes_X();
+    if (!(link_moving_against_diag_tile & 0xf))
+      goto noHorizOrNoVertical;
+
+    int8 xd = link_x_coord - link_x_coord_copy;
+    link_x_coord = link_x_coord_copy;
+    link_x_vel = xd;
+
+    TileDetect_Movement_Y(sign8(link_y_vel) ? 0 : 1);
+    if ((R12 & 5) == 0)
+      goto noHorizOrNoVertical;
+    FlagMovingIntoSlopes_Y();
+    if (!(link_moving_against_diag_tile & 0xf))
+      goto noHorizOrNoVertical;
+
+    moving_against_diag_deadlocked = link_moving_against_diag_tile;
+
+    int8 yd = link_y_coord - link_y_coord_copy;
+    link_y_vel = yd;
+
+    static const int8 x0[] = { 0, 1, 1, 1, 2, 2, 2, 3, 3, 3 };
+    static const int8 x1[] = { 0, -1, -1, -1, -2, -2, -2, -3, -3, -3 };
+    link_x_coord += sign8(link_x_vel) ? x1[-(int8)link_x_vel] : x0[link_x_vel];
+
+    static const int8 y0[10] = { 0, 0, 0, 1, 1, 1, 2, 2, 2, 3 };
+    // Bug in zelda, might read index 15
+    static const int8 y1[16] = { 0, 1, 1, 2, 2, 2, 3, 3, 3, 3, 0xa5, 0x30, 0xf0, 0x04, 0xa5, 0x31 };
+    link_y_coord += sign8(link_y_vel) ? y1[-(int8)link_y_vel] : y0[link_y_vel];
+  } else {
+noHorizOrNoVertical:
+    moving_against_diag_deadlocked = 0;
+  }
+  link_moving_against_diag_tile = 0;
+}
+
+void TileDetect_MainHandler(uint8 item) {  // 87d077
+  tiledetect_pit_tile = 0;
+  TileDetect_ResetState();
+  uint16 o;
+
+  if (item == 8) {
+    int16 a = state_for_spin_attack - 2;
+    if (a < 0 || a >= 8)
+      return;
+    static const uint8 kDoSwordInteractionWithTiles_o[] = { 10, 6, 14, 2, 12, 4, 8, 0 };
+    o = kDoSwordInteractionWithTiles_o[a] + 0x40;
+  } else {
+    o = item * 8 + link_direction_facing;
+  }
+  o >>= 1;
+
+  static const int8 kDoSwordInteractionWithTiles_x[] = { 8, 8, 8, 8, 6, 8, -1, 22, 19, 19, 0, 19, 6, 8, -1, 22, 8, 8, 8, 8, 8, 8, 0, 15, 6, 8, -10, 29, 6, 8, -6, 22, 6, 8, -4, 22, -4, 22, -4, 22 };
+  static const int8 kDoSwordInteractionWithTiles_y[] = { 20, 20, 20, 20, 4, 28, 16, 16, 22, 22, 22, 22, 4, 24, 16, 16, 16, 16, 16, 16, 20, 20, 23, 23, -4, 36, 16, 16, 4, 28, 16, 16, 4, 28, 16, 16, 4, 4, 28, 28 };
+  uint16 x = ((link_x_coord + kDoSwordInteractionWithTiles_x[o]) & tilemap_location_calc_mask) >> 3;
+  uint16 y = ((link_y_coord + kDoSwordInteractionWithTiles_y[o]) & tilemap_location_calc_mask);
+
+  if (item == 1 || item == 2 || item == 3 || item == 6 || item == 7 || item == 8) {
+    TileBehavior_HandleItemAndExecute(x, y);
+    return;
+  }
+
+  TileDetection_Execute(x, y, 1);
+
+  if (item == 5)
+    return;
+
+  if (tiledetect_thick_grass & 0x10) {
+    uint8 tx = (link_x_coord + 0) & 0xf;
+    uint8 ty = (link_y_coord + 8) & 0xf;
+
+    if ((ty < 4 || ty >= 11) && (tx < 4 || tx >= 12) && countdown_for_blink == 0 && link_auxiliary_state == 0) {
+      if (player_is_indoors) {
+        Dungeon_FlagRoomData_Quadrants();
+        Ancilla_Sfx2_Near(0x33);
+        link_speed_setting = 0;
+        submodule_index = 21;
+        BYTE(dungeon_room_index_prev) = dungeon_room_index;
+        BYTE(dungeon_room_index) = dung_hdr_travel_destinations[0];
+        HandleLayerOfDestination();
+      } else if (!link_triggered_by_whirlpool_sprite) {
+        DoSwordInteractionWithTiles_Mirror();
+      }
+    }
+  } else {  // else_3
+    link_triggered_by_whirlpool_sprite = 0;
+    if (tiledetect_thick_grass & 1) {
+      draw_water_ripples_or_grass = 2;
+      if (!Link_PermissionForSloshSounds() && link_auxiliary_state == 0)
+        Ancilla_Sfx2_Near(26);
+      return;
+    }
+
+    if (tiledetect_shallow_water & 1) {
+      draw_water_ripples_or_grass = 1;
+
+      if (!player_is_indoors && link_is_in_deep_water && !link_is_bunny_mirror) {
+        if (link_item_flippers) {
+          link_is_in_deep_water = 0;
+          link_direction_last = link_some_direction_bits;
+          link_player_handler_state = 0;
+        }
+      } else if (!Link_PermissionForSloshSounds()) {
+        if ((uint8)overworld_screen_index == 0x70) {
+          Ancilla_Sfx2_Near(27);
+        } else if (link_auxiliary_state == 0) {
+          Ancilla_Sfx2_Near(28);
+        }
+      }
+      return;
+    }
+
+    if (!player_is_indoors && !link_is_in_deep_water && (tiledetect_deepwater & 1)) {
+      draw_water_ripples_or_grass = 1;
+      if (!Link_PermissionForSloshSounds()) {
+        if ((uint8)overworld_screen_index == 0x70) {
+          Ancilla_Sfx2_Near(27);
+        } else if (link_auxiliary_state == 0) {
+          Ancilla_Sfx2_Near(28);
+        }
+      }
+      return;
+    }
+  }
+  // else_6
+  draw_water_ripples_or_grass = 0;
+
+  if (tiledetect_spike_floor_and_tile_triggers & 1) {
+    byte_7E02ED = 1;
+    return;
+  }
+
+  byte_7E02ED = 0;
+
+  if (tiledetect_spike_floor_and_tile_triggers & 0x10) {
+    link_give_damage = 0;
+    if (!link_cape_mode && !SearchForByrnaSpark() && !countdown_for_blink) {
+      link_need_for_poof_for_transform = 0;
+      link_timer_tempbunny = 0;
+      if (link_item_moon_pearl) {
+        link_is_bunny = 0;
+        link_is_bunny_mirror = 0;
+      }
+      link_give_damage = 8;
+      Link_CancelDash();
+      return;
+    }
+  }
+
+  if (tiledetect_icy_floor & 0x11) {
+    if (link_flag_moving) {
+      if (link_num_orthogonal_directions)
+        link_direction_last = link_some_direction_bits;
+    } else { // else_11
+      if (link_direction & 0xC)
+        swimcoll_var7[0] = 0x180;
+      if (link_direction & 3)
+        swimcoll_var7[0] = 0x180;
+
+      link_flag_moving = (tiledetect_icy_floor & 1) ? 1 : 2;
+      link_some_direction_bits = link_direction_last;
+      Link_ResetSwimmingState();
+    }
+  } else {
+    if (link_player_handler_state != 4) {
+      if (link_flag_moving)
+        link_direction_last = link_some_direction_bits;
+      Link_ResetSwimmingState();
+    }
+    link_flag_moving = 0;
+  }
+
+  if ((bitfield_spike_cactus_tiles & 0x10) && countdown_for_blink == 0)
+    countdown_for_blink = 58;
+}
+
+bool Link_PermissionForSloshSounds() {  // 87d2c6
+  if (!(link_direction & 0xf))
+    return true;
+  if (link_player_handler_state != 17) {
+    return (frame_counter & 0xf) != 0;
+  } else {
+    return (frame_counter & 0x7) != 0;
+  }
+}
+
+bool PushBlock_AttemptToPushTheBlock(uint8 what, uint16 x, uint16 y) {  // 87d304
+  static const int8 kChangableDungeonObj_Func1B_y0[4] = { -4, 20, 4, 4 };
+  static const int8 kChangableDungeonObj_Func1B_y1[4] = { -4, 20, 12, 12 };
+  static const int8 kChangableDungeonObj_Func1B_x0[4] = { 4, 4, -4, 20 };
+  static const int8 kChangableDungeonObj_Func1B_x1[4] = { 12, 12, -4, 20 };
+  static const uint8 T[256] = {
+    0, 1, 2, 3, 2, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1,
+    0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1,
+    0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
+
+  };
+
+  uint8 idx = what * 4 + link_last_direction_moved_towards, xt;
+  uint16 new_x, new_y;
+
+  new_x = ((x + kChangableDungeonObj_Func1B_x0[idx]) & tilemap_location_calc_mask) >> 3;
+  new_y = ((y + kChangableDungeonObj_Func1B_y0[idx]) & tilemap_location_calc_mask);
+  xt = PushBlock_GetTargetTileFlag(new_x, new_y);
+  if (T[xt] != 0 && xt != 9)
+    return true;
+
+  new_x = ((x + kChangableDungeonObj_Func1B_x1[idx]) & tilemap_location_calc_mask) >> 3;
+  new_y = ((y + kChangableDungeonObj_Func1B_y1[idx]) & tilemap_location_calc_mask);
+  xt = PushBlock_GetTargetTileFlag(new_x, new_y);
+  if (T[xt] != 0 && xt != 9)
+    return true;
+
+  return false;
+}
+
+uint8 Link_HandleLiftables() {  // 87d383
+  static const uint8 kGetBestActionToPerformOnTile_a[7] = { 0, 1, 0, 0, 2, 1, 2 };
+  static const uint8 kGetBestActionToPerformOnTile_b[7] = { 2, 3, 1, 4, 0, 5, 6 };
+
+  tiledetect_pit_tile = 0;
+  TileDetect_ResetState();
+
+  uint16 y0 = (link_y_coord + kGetBestActionToPerformOnTile_y[link_direction_facing >> 1]) & tilemap_location_calc_mask;
+  uint16 y1 = (link_y_coord + 20) & tilemap_location_calc_mask;
+
+  uint16 x0 = ((link_x_coord + kGetBestActionToPerformOnTile_x[link_direction_facing >> 1]) & tilemap_location_calc_mask) >> 3;
+  uint16 x1 = ((link_x_coord + 8) & tilemap_location_calc_mask) >> 3;
+
+  TileDetection_Execute(x0, y0, 1);
+  TileDetection_Execute(x1, y1, 2);
+
+  uint8 action = ((R14 | tiledetect_vertical_ledge) & 1) ? 3 : 2;
+
+  if (player_is_indoors) {
+    uint8 a = Dungeon_CheckForAndIDLiftableTile();
+    if (a != 0xff) {
+      interacting_with_liftable_tile_x1 = kGetBestActionToPerformOnTile_b[a & 0xf];
+    } else {
+      if ((tiledetect_read_something & 1) && link_direction_facing == 0 && interacting_with_liftable_tile_x2 == 0)
+        action = 4;
+      goto getout;
+    }
+  } else {
+    if (!(tiledetect_read_something & 1))
+      goto getout;
+    if (link_direction_facing == 0 && interacting_with_liftable_tile_x2 == 0) {
+      action = 4;
+      goto getout;
+    }
+    interacting_with_liftable_tile_x1 = interacting_with_liftable_tile_x2 >> 1;
+  }
+  if (kGetBestActionToPerformOnTile_a[interacting_with_liftable_tile_x1] - link_item_gloves <= 0)
+    action = 1;
+getout:
+  if (tiledetect_chest & 1)
+    action = 5;
+  return action;
+}
+
+void HandleNudging(int8 arg_r0) {  // 87d485
+  uint8 p, o;
+
+  if ((link_last_direction_moved_towards & 2) == 0) {
+    p = (link_last_direction_moved_towards & 1) ? 4 : 0;
+    o = (R14 & 4) ? 0 : 2;
+  } else {
+    p = (link_last_direction_moved_towards & 1) ? 12 : 8;
+    o = (R14 & 4) ? 0 : 2;
+  }
+  o = (o + p) >> 1;
+
+  tiledetect_pit_tile = 0;
+  TileDetect_ResetState();
+
+  uint16 y0 = (link_y_coord + kLink_Move_Helper6_tab0[o]) & tilemap_location_calc_mask;
+  uint16 x0 = ((link_x_coord + kLink_Move_Helper6_tab1[o]) & tilemap_location_calc_mask) >> 3;
+
+  uint16 y1 = (link_y_coord + kLink_Move_Helper6_tab2[o]) & tilemap_location_calc_mask;
+  uint16 x1 = ((link_x_coord + kLink_Move_Helper6_tab3[o]) & tilemap_location_calc_mask) >> 3;
+
+  TileDetection_Execute(x0, y0, 1);
+  TileDetection_Execute(x1, y1, 2);
+
+  if ((R14 | detection_of_ledge_tiles_horiz_uphoriz) & 3 ||
+      (tiledetect_vertical_ledge | detection_of_unknown_tile_types) & 0x33) {
+
+    if (link_last_direction_moved_towards & 2)
+      link_y_coord -= arg_r0;
+    else
+      link_x_coord -= arg_r0;
+  }
+}
+
+void TileBehavior_HandleItemAndExecute(uint16 x, uint16 y) {  // 87dc4a
+  uint8 tile = HandleItemTileAction_Overworld(x, y);
+  TileDetect_ExecuteInner(tile, 0, 1, false);
+}
+
+uint8 PushBlock_GetTargetTileFlag(uint16 x, uint16 y) {  // 87e026
+  return dung_bg2_attr_table[(y & ~7) * 8 + (x & 0x3f) + (link_is_on_lower_level ? 0x1000 : 0)];
+}
+
+void FlagMovingIntoSlopes_Y() {  // 87e076
+  int8 y = (tiledetect_which_y_pos[0] & 7);
+  uint8 o = (tiledetect_diag_state * 4) + ((link_x_coord - ((R12 & 4) != 0)) & 7);
+
+  if (tiledetect_diagonal_tile & 5) {
+    int8 ym = tiledetect_which_y_pos[0] & 7;
+
+    if (enhanced_features0 & kFeatures0_MiscBugFixes) {
+      if (tiledetect_diag_state & 2) {
+        ym = -ym;
+      } else {
+        ym = kAvoidJudder1[o] - (8 - ym);
+      }
+    } else {
+      // This code is bad because it could cause the player
+      // to move up to 15 pixels, causing an array out bounds read.
+      // Not sure how it works, but changed it to look more like the X version.
+      if (!(tiledetect_diag_state & 2)) {
+        ym = 8 - ym; // 0 to 8
+      } else {
+        ym += 8; // 8 to 15
+      }
+      // -15 to 7
+      ym = kAvoidJudder1[o] - ym;
+    }
+
+    if (link_y_vel == 0)
+      return;
+    if (sign8(link_y_vel))
+      ym = -ym;
+    y = ym;
+  } else {  // else_1
+    y = kAvoidJudder1[o] - y;
+  } // endif_1
+
+  if (sign8(link_y_vel)) {
+    if (y <= 0)
+      return;
+    link_y_coord += y;
+    link_moving_against_diag_tile = 8;
+  } else {
+    if (y >= 0)
+      return;
+    link_y_coord += y;
+    link_moving_against_diag_tile = 4;
+  }
+  link_moving_against_diag_tile |= (R12 & 4) ? 0x10 + 2 : 0x10 + 1;
+}
+
+void FlagMovingIntoSlopes_X() {  // 87e112
+  int8 x = (link_x_coord - (tiledetect_diag_state == 6)) & 7;
+  uint8 o = (tiledetect_diag_state * 4) + (tiledetect_which_y_pos[(R12 & 4) ? 1 : 0] & 7);
+
+  if (tiledetect_diagonal_tile & 5) {
+    int8 xm = link_x_coord & 7;
+
+    if (tiledetect_diag_state != 4 && tiledetect_diag_state != 6) {
+      xm = -xm;
+    } else {
+      xm = kAvoidJudder1[o] - (8 - xm);
+    } // endif_5
+    if (link_x_vel == 0)
+      return;
+    if (sign8(link_x_vel))
+      xm = -xm;
+    x = xm;
+  } else {  // else_1
+    x = kAvoidJudder1[o] - x;
+  } //  endif_1
+
+  if (sign8(link_x_vel)) {
+    if (x <= 0)
+      return;
+    link_x_coord += x;
+    link_moving_against_diag_tile = 2;
+  } else {
+    if (x >= 0)
+      return;
+    link_x_coord += x;
+    link_moving_against_diag_tile = 1;
+  }
+  link_moving_against_diag_tile |= (tiledetect_diag_state & 2) ? 0x20 + 8 : 0x20 + 4;
+}
+
+void Link_HandleRecoiling() {  // 87e1be
+  link_direction = 0;
+  if (link_actual_vel_y) {
+    link_direction_last = (link_direction |= sign8(link_actual_vel_y) ? 8 : 4);
+    Player_HandleIncapacitated_Inner2();
+  }
+  if (link_actual_vel_x)
+    link_direction_last = (link_direction |= sign8(link_actual_vel_x) ? 2 : 1);
+  Player_HandleIncapacitated_Inner2();
+}
+
+void Player_HandleIncapacitated_Inner2() {  // 87e1d7
+  if ((link_moving_against_diag_tile & 0xc) && (link_moving_against_diag_tile & 3) && link_player_handler_state == 2) {
+    link_actual_vel_x = -link_actual_vel_x;
+    link_actual_vel_y = -link_actual_vel_y;
+  }
+  if (is_standing_in_doorway == 1) {
+    link_direction_last &= 0xc;
+    link_direction &= 0xc;
+    link_actual_vel_x = 0;
+  } else if (is_standing_in_doorway == 2) {
+    link_direction_last &= 3;
+    link_direction &= 3;
+    link_actual_vel_y = 0;
+  }
+}
+
+void Link_HandleVelocity() {  // 87e245
+  if (submodule_index == 2 && main_module_index == 14 || link_prevent_from_moving) {
+    link_y_coord_safe_return_lo = link_y_coord;
+    link_y_coord_safe_return_hi = link_y_coord >> 8;
+    link_x_coord_safe_return_lo = link_x_coord;
+    link_x_coord_safe_return_hi = link_x_coord >> 8;
+    Link_HandleVelocityAndSandDrag(link_x_coord, link_y_coord);
+    return;
+  }
+
+  if (link_player_handler_state == kPlayerState_Swimming) {
+    HandleSwimStrokeAndSubpixels();
+    return;
+  }
+  uint8 r0;
+
+  if (link_flag_moving) {
+    if (!link_is_running) {
+      HandleSwimStrokeAndSubpixels();
+      return;
+    }
+    r0 = 24;
+  } else {
+    if (link_is_running) {
+      link_speed_modifier = 0;
+      assert(link_dash_ctr >= 32);
+    }
+
+    if ((byte_7E0316 | byte_7E0317) == 0xf)
+      return;
+
+    r0 = link_speed_setting;
+    if (draw_water_ripples_or_grass) {
+      r0 = (link_speed_setting == 16) ? 22 :
+        (link_speed_setting == 12) ? 14 : 12;
+    }
+  }  // endif_4
+
+  link_actual_vel_x = link_actual_vel_y = 0;
+  link_y_page_movement_delta = link_x_page_movement_delta = 0;
+
+  r0 += ((link_direction & 0xC) != 0 && (link_direction & 3) != 0);
+
+  if (player_near_pit_state) {
+    if (player_near_pit_state == 3)
+      link_speed_modifier = (link_speed_modifier < 48) ? link_speed_modifier + 8 : 32;
+  } else {
+    if (link_speed_modifier) {
+      r0 = (submodule_index == 8 || submodule_index == 16) ? 10 : 2;
+      if (link_speed_modifier != 1) {
+        if (link_speed_modifier < 16) {
+          link_speed_modifier += 1;
+          r0 = 26; // kSpeedMod[26] is 0
+        } else {
+          link_speed_modifier = 0;
+          link_speed_setting = 0;
+        }
+      }
+    }
+  } // endif_7
+
+  static const uint8 kSpeedMod[27] = { 24, 16, 10, 24, 16, 8, 8, 4, 12, 16, 9, 25, 20, 13, 16, 8, 64, 42, 16, 8, 4, 2, 48, 24, 32, 21, 0 };
+
+  uint8 vel = link_speed_modifier + kSpeedMod[r0];
+  if (link_direction & 3)
+    link_actual_vel_x = (link_direction & 2) ? -vel : vel;
+  if (link_direction & 0xC)
+    link_actual_vel_y = (link_direction & 8) ? -vel : vel;
+
+  link_actual_vel_z = 0xff;
+  link_z_coord = 0xffff;
+  link_subpixel_z = 0;
+  Link_MovePosition();
+}
+
+void Link_MovePosition() {  // 87e370
+  uint16 x = link_x_coord, y = link_y_coord;
+  link_y_coord_safe_return_lo = link_y_coord;
+  link_y_coord_safe_return_hi = link_y_coord >> 8;
+  link_x_coord_safe_return_lo = link_x_coord;
+  link_x_coord_safe_return_hi = link_x_coord >> 8;
+
+  if (link_player_handler_state != 10 && player_on_somaria_platform == 2) {
+    Link_HandleVelocityAndSandDrag(x, y);
+    return;
+  }
+
+  uint32 tmp;
+  tmp = link_subpixel_x + (int8)link_actual_vel_x * 16 + link_x_coord * 256;
+  link_subpixel_x = (uint8)tmp, link_x_coord = (tmp >> 8);
+  tmp = link_subpixel_y + (int8)link_actual_vel_y * 16 + link_y_coord * 256;
+  link_subpixel_y = (uint8)tmp, link_y_coord = (tmp >> 8);
+  if (link_auxiliary_state) {
+    tmp = link_subpixel_z + (int8)link_actual_vel_z * 16 + link_z_coord * 256;
+    link_subpixel_z = (uint8)tmp, link_z_coord = (tmp >> 8);
+  }
+
+  Link_HandleMovingFloor();
+  Link_ApplyConveyor();
+  Link_HandleVelocityAndSandDrag(x, y);
+}
+
+void Link_HandleVelocityAndSandDrag(uint16 x, uint16 y) {  // 87e3e0
+  link_y_coord += drag_player_y;
+  link_x_coord += drag_player_x;
+  link_y_vel = link_y_coord - y;
+  link_x_vel = link_x_coord - x;
+}
+
+void HandleSwimStrokeAndSubpixels() {  // 87e42a
+  link_actual_vel_x = link_actual_vel_y = 0;
+
+  static const int8 kSwimmingTab4[] = { 8, -12, -8, -16, 4, -6, -12, -6, 10, -16, -12, -6 };
+  static const uint8 kSwimmingTab5[] = { ~0xc & 0xff, ~3 & 0xff };
+  static const uint8 kSwimmingTab6[] = { 8, 4, 2, 1 };
+  uint16 S[2];
+  for (int i = 1; i >= 0; i--) {
+    if ((int16)--swimcoll_var3[i] < 0) {
+      swimcoll_var3[i] = 0;
+      swimcoll_var5[i] = 1;
+    }
+    uint16 t = swimcoll_var5[i];
+    if (link_flag_moving)
+      t += link_flag_moving * 4;
+
+    uint16 sum = swimcoll_var7[i] + kSwimmingTab4[t];
+    if ((int16)sum <= 0) {
+      link_direction &= kSwimmingTab5[i];
+      link_direction_last = link_direction;
+      //link_actual_vel_y = link_y_page_movement_delta; // WTF bug?!
+      if (swimcoll_var5[i] == 2) {
+        swimcoll_var5[i] = 0;
+        swimcoll_var9[i] = 240;
+        swimcoll_var7[i] = 2;
+      } else {
+        swimcoll_var5[i] = 0;
+        swimcoll_var9[i] = 0;
+        swimcoll_var7[i] = 0;
+      }
+    } else {
+      link_direction |= kSwimmingTab6[swimcoll_var11[i] + i * 2];
+      if (sum >= swimcoll_var9[i])
+        sum = swimcoll_var9[i];
+      swimcoll_var7[i] = sum;
+    }
+    S[i] = swimcoll_var7[i];
+    if (link_num_orthogonal_directions | link_moving_against_diag_tile)
+      S[i] -= S[i] >> 2;
+    if (!swimcoll_var11[i])
+      S[i] = -S[i];
+  }
+
+  Player_SomethingWithVelocity_TiredOrSwim(S[1], S[0]);
+
+}
+
+void Player_SomethingWithVelocity_TiredOrSwim(uint16 xvel, uint16 yvel) {  // 87e4d3
+  uint16 org_x = link_x_coord, org_y = link_y_coord;
+  link_y_coord_safe_return_lo = link_y_coord;
+  link_y_coord_safe_return_hi = link_y_coord >> 8;
+  link_x_coord_safe_return_lo = link_x_coord;
+  link_x_coord_safe_return_hi = link_x_coord >> 8;
+
+  uint8 u;
+
+  uint32 tmp;
+  tmp = link_subpixel_x + (int16)xvel + link_x_coord * 256;
+  link_subpixel_x = (uint8)tmp, link_x_coord = (tmp >> 8);
+
+  u = xvel >> 8;
+  link_actual_vel_x = ((sign8(u) ? -u : u) << 4) | ((uint8)xvel >> 4);
+
+  tmp = link_subpixel_y + (int16)yvel + link_y_coord * 256;
+  link_subpixel_y = (uint8)tmp, link_y_coord = (tmp >> 8);
+  u = yvel >> 8;
+  link_actual_vel_y = ((sign8(u) ? -u : u) << 4) | ((uint8)yvel >> 4);
+
+  if (dung_hdr_collision == 4)
+    Link_ApplyMovingFloorVelocity();
+  link_x_page_movement_delta = 0;
+  link_y_page_movement_delta = 0;
+  Link_HandleVelocityAndSandDrag(org_x, org_y);
+}
+
+void Link_HandleMovingFloor() {  // 87e595
+  if (!dung_hdr_collision)
+    return;
+  if (BYTE(link_z_coord) != 0 && BYTE(link_z_coord) != 255)
+    return;
+  if (((byte_7E0322) & 3) != 3)
+    return;
+  if (link_player_handler_state == 19) // hookshot
+    return;
+
+  if (dung_floor_y_vel)
+    link_direction |= sign8(dung_floor_y_vel) ? 8 : 4;
+
+  if (dung_floor_x_vel)
+    link_direction |= sign8(dung_floor_x_vel) ? 2 : 1;
+
+  Link_ApplyMovingFloorVelocity();
+}
+
+void Link_ApplyMovingFloorVelocity() {  // 87e5cd
+  link_num_orthogonal_directions = 0;
+  link_y_coord += dung_floor_y_vel;
+  link_x_coord += dung_floor_x_vel;
+}
+
+void Link_ApplyConveyor() {  // 87e5f0
+  static const uint8 kMovePosDirFlag[4] = { 8, 4, 2, 1 };
+  static const int8 kMovingBeltY[4] = { -8, 8, 0, 0 };
+  static const int8 kMovingBeltX[4] = { 0, 0, -8, 8 };
+
+  if (!link_on_conveyor_belt)
+    return;
+  if (BYTE(link_z_coord) != 0 && BYTE(link_z_coord) != 0xff)
+    return;
+  if (link_grabbing_wall & 1 || link_player_handler_state == kPlayerState_Hookshot || link_auxiliary_state)
+    return;
+
+  int j = link_on_conveyor_belt - 1;
+  if (link_is_running && link_dash_ctr == 32 && (link_direction & kMovePosDirFlag[j]))
+    return;
+
+  link_num_orthogonal_directions = 0;
+  link_direction |= kMovePosDirFlag[j];
+
+  uint32 t = link_y_coord << 8 | dung_some_subpixel[0];
+  t += kMovingBeltY[j] << 4;
+  dung_some_subpixel[0] = t;
+  link_y_coord = t >> 8;
+
+  t = link_x_coord << 8 | dung_some_subpixel[1];
+  t += kMovingBeltX[j] << 4;
+  dung_some_subpixel[1] = t;
+  link_x_coord = t >> 8;
+}
+
+void Link_HandleMovingAnimation_FullLongEntry() {  // 87e6a6
+  if (link_player_handler_state == 4) {
+    Link_HandleMovingAnimationSwimming();
+    return;
+  }
+
+  static const uint8 kTab[4] = { 8, 4, 2, 1 };
+
+  uint8 r0 = link_direction_last;
+  uint8 y;
+  if (r0 == 0)
+    return;
+  if (link_flag_moving)
+    r0 = link_some_direction_bits;
+  if (link_cant_change_direction)
+    goto bail;
+  if (link_num_orthogonal_directions == 0)
+    goto not_diag;
+  if (is_standing_in_doorway) {
+    y = (is_standing_in_doorway * 2) & ~3;
+  } else {
+    if (r0 & kTab[link_direction_facing >> 1])
+      goto bail;
+not_diag:
+    y = (r0 & 0xc) ? 0 : 4;
+  }
+
+  if (y != 4) {
+    y += (r0 & 4) ? 2 : 0;
+  } else {
+    y += (r0 & 1) ? 2 : 0;
+  }
+  link_direction_facing = y;
+bail:
+  Link_HandleMovingAnimation_StartWithDash();
+}
+
+void Link_HandleMovingAnimation_StartWithDash() {  // 87e704
+  if (link_is_running) {
+    Link_HandleMovingAnimation_Dash();
+    return;
+  }
+
+  uint8 x = link_direction_facing >> 1;
+  if (link_speed_setting == 6) {
+    x += 4;
+  } else if (link_flag_moving) {
+    if (!(joypad1H_last & kJoypadH_AnyDir)) {
+      link_animation_steps = 0;
+      return;
+    }
+    x += 4;
+  }
+
+  static const uint8 tab2[16] = { 4, 4, 4, 4, 1, 1, 1, 1, 2, 2, 2, 2, 8, 8, 8, 8 };
+  static const uint8 tab3[24] = { 1, 2, 3, 2, 2, 2, 3, 2, 1, 1, 2, 1, 1, 1, 2, 1, 2, 2, 3, 2, 2, 2, 3, 2 };
+
+//bugfix: tempbunny animation steps are wrong due to missing check
+  if (link_player_handler_state == 23 || (enhanced_features0 & kFeatures0_MiscBugFixes && link_player_handler_state == 28)) {  // bunny states
+    if (link_animation_steps < 4 && player_on_somaria_platform != 2) {
+      if (++link_counter_var1 >= tab2[x]) {
+        link_counter_var1 = 0;
+        if (++link_animation_steps == 4)
+          link_animation_steps = 0;
+      }
+    } else {
+      link_animation_steps = 0;
+    }
+    return;
+  }
+
+  if (submodule_index == 18 || submodule_index == 19) {
+    x = 12;
+  } else if (submodule_index != kPlayerState_JumpOffLedgeDiag && (link_state_bits & 0x80) == 0) {
+    if (bitmask_of_dragstate & 0x8d) {
+      x = 12;
+    } else if (!draw_water_ripples_or_grass && !button_b_frames) {
+      // else_6
+      x = link_animation_steps;
+      if (link_speed_setting == 6)
+        x += 8;
+      if (link_flag_moving)
+        x += 8;
+      if (player_on_somaria_platform == 2)
+        return;
+      if (++link_counter_var1 >= tab3[x]) {
+        link_counter_var1 = 0;
+        if (++link_animation_steps == 9)
+          link_animation_steps = 1;
+      }
+      return;
+    }
+  }
+  // endif_4
+
+  if (link_animation_steps < 6 && player_on_somaria_platform != 2) {
+    if (++link_counter_var1 >= tab2[x]) {
+      link_counter_var1 = 0;
+      if (++link_animation_steps == 6)
+        link_animation_steps = 0;
+    }
+  } else {
+    link_animation_steps = 0;
+  }
+}
+
+void Link_HandleMovingAnimationSwimming() {  // 87e7fa
+  static const uint8 kTab[4] = { 8, 4, 2, 1 };
+  if (!link_some_direction_bits || link_cant_change_direction)
+    return;
+  uint8 y;
+
+  if (link_num_orthogonal_directions) {
+    if (is_standing_in_doorway) {
+      y = (is_standing_in_doorway * 2) & ~3;
+    } else {
+      if (link_some_direction_bits & kTab[link_direction_facing >> 1])
+        return;
+      y = link_some_direction_bits & 0xC ? 0 : 4;
+    }
+  } else {
+    y = link_some_direction_bits & 0xC ? 0 : 4;
+  }
+  if (y != 4) {
+    y += (link_some_direction_bits & 4) ? 2 : 0;
+  } else {
+    y += (link_some_direction_bits & 1) ? 2 : 0;
+  }
+  link_direction_facing = y;
+}
+
+void Link_HandleMovingAnimation_Dash() {  // 87e88f
+  static const uint8 kDashTab3[] = { 48, 36, 24, 16, 12, 8, 4 };
+  static const uint8 kDashTab4[] = { 3, 3, 5, 3, 3, 3, 5, 3, 2, 2, 4, 2, 2, 2, 4, 2, 2, 2, 3, 2, 2, 2, 3, 2, 1, 1, 2, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+  static const uint8 kDashTab5[] = { 1, 2, 2, 2, 2, 2, 2 };
+
+  uint8 t = 6;
+  while (link_countdown_for_dash >= kDashTab3[t] && t)
+    t--;
+
+  if (button_b_frames < 9 && !draw_water_ripples_or_grass) {
+    if (++link_counter_var1 >= kDashTab4[t * 8]) {
+      link_counter_var1 = 0;
+      link_animation_steps++;
+      if (link_animation_steps == 9)
+        link_animation_steps = 1;
+    }
+  } else {
+    if (++link_counter_var1 >= kDashTab5[t]) {
+      link_counter_var1 = 0;
+      link_animation_steps++;
+      if (link_animation_steps >= 6)
+        link_animation_steps = 0;
+    }
+  }
+}
+
+void HandleIndoorCameraAndDoors() {  // 87e8f0
+  if (player_is_indoors) {
+    if (is_standing_in_doorway)
+      HandleDoorTransitions();
+    else
+      ApplyLinksMovementToCamera();
+  }
+}
+
+void HandleDoorTransitions() {  // 87e901
+  uint16 t;
+
+  link_x_page_movement_delta = 0;
+  link_y_page_movement_delta = 0;
+
+  // Using a potion might have changed us into a different module, and the routines
+  // below just increment the submodule value, causing all kinds of havoc.
+  // There's an added return to catch the same behavior a bit up, but this one catches more cases,
+  // at the expense of link already having done his movement, so by returning here we might
+  // miss handling the door causing other kinds of issues.
+  if ((enhanced_features0 & kFeatures0_MiscBugFixes) && !(main_module_index == 7 && submodule_index == 0))
+    return;
+
+  if (link_direction_last & 0xC && is_standing_in_doorway == 1) {
+    if (link_direction_last & 4) {
+      if (((t = link_y_coord + 28) & 0xfc) == 0)
+        link_y_page_movement_delta = (t >> 8) - link_y_coord_safe_return_hi;
+    } else {
+      t = link_y_coord - 18;
+      link_y_page_movement_delta = (t >> 8) - link_y_coord_safe_return_hi;
+    }
+  }
+
+  if (link_direction_last & 3 && is_standing_in_doorway == 2) {
+    if (link_direction_last & 1) {
+      if (((t = link_x_coord + 21) & 0xfc) == 0)
+        link_x_page_movement_delta = (t >> 8) - link_x_coord_safe_return_hi;
+    } else {
+      t = link_x_coord - 8;
+      link_x_page_movement_delta = (t >> 8) - link_x_coord_safe_return_hi;
+    }
+  }
+
+  if (link_x_page_movement_delta) {
+    some_animation_timer = 0;
+    link_state_bits = 0;
+    link_picking_throw_state = 0;
+    link_grabbing_wall = 0;
+    if (sign8(link_x_page_movement_delta))
+      Dung_StartInterRoomTrans_Left_Plus();
+    else
+      HandleEdgeTransitionMovementEast_RightBy8();
+  } else if (link_y_page_movement_delta) {
+    some_animation_timer = 0;
+    link_state_bits = 0;
+    link_picking_throw_state = 0;
+    link_grabbing_wall = 0;
+    if (sign8(link_y_page_movement_delta))
+      Dungeon_StartInterRoomTrans_Up();
+    else
+      HandleEdgeTransitionMovementSouth_DownBy16();
+  }
+}
+
+void ApplyLinksMovementToCamera() {  // 87e9d3
+  // Sometimes, when using spin attack, this routine will end up getting
+  // called twice in the same frame, which messes up things.
+  g_ApplyLinksMovementToCamera_called = true;
+
+  link_y_page_movement_delta = (link_y_coord >> 8) - link_y_coord_safe_return_hi;
+  link_x_page_movement_delta = (link_x_coord >> 8) - link_x_coord_safe_return_hi;
+
+  if (link_x_page_movement_delta) {
+    if (sign8(link_x_page_movement_delta))
+      AdjustQuadrantAndCamera_left();
+    else
+      AdjustQuadrantAndCamera_right();
+  }
+
+  if (link_y_page_movement_delta) {
+    if (sign8(link_y_page_movement_delta))
+      AdjustQuadrantAndCamera_up();
+    else
+      AdjustQuadrantAndCamera_down();
+  }
+}
+
+uint8 FindFreeMovingBlockSlot(uint8 x) {  // 87ed2c
+  if (index_of_changable_dungeon_objs[1] == 0) {
+    index_of_changable_dungeon_objs[1] = x + 1;
+    return 1;
+  }
+  if (index_of_changable_dungeon_objs[0] == 0) {
+    index_of_changable_dungeon_objs[0] = x + 1;
+    return 0;
+  }
+  return 0xff;
+}
+
+bool InitializePushBlock(uint8 r14, uint8 idx) {  // 87ed3f
+  uint16 pos = dung_object_tilemap_pos[idx >> 1];
+  uint16 x = (pos & 0x007e) << 2;
+  uint16 y = (pos & 0x1f80) >> 4;
+
+  x += (dung_loade_bgoffs_h_copy & 0xff00);
+  y += (dung_loade_bgoffs_v_copy & 0xff00);
+
+  pushedblocks_x_lo[r14] = (uint8)x;
+  pushedblocks_x_hi[r14] = (uint8)(x >> 8);
+  pushedblocks_y_lo[r14] = (uint8)y;
+  pushedblocks_y_hi[r14] = (uint8)(y >> 8);
+  pushedblocks_target[r14] = 0;
+  pushedblocks_subpixel[r14] = 0;
+
+  if (dung_hdr_tag[0] != 38 && dung_replacement_tile_state[idx >> 1] == 0) {
+    if (!PushBlock_AttemptToPushTheBlock(0, x, y)) {
+      Ancilla_Sfx2_Near(0x22);
+      dung_replacement_tile_state[idx >> 1] = 1;
+      return false;
+    }
+  }
+
+  index_of_changable_dungeon_objs[r14] = 0;
+  return true;
+}
+
+void Sprite_Dungeon_DrawSinglePushBlock(int j) {  // 87f0d9
+  static const uint8 kPushedBlock_Tab1[9] = { 0, 1, 2, 3, 4, 0, 0, 0, 0 };
+  static const uint8 kPushedblock_Char[4] = { 0xc, 0xc, 0xc, 0xff };
+  j >>= 1;
+  Oam_AllocateFromRegionB(4);
+  OamEnt *oam = GetOamCurPtr();
+  int y = (uint8)pushedblocks_y_lo[j] | (uint8)pushedblocks_y_hi[j] << 8;
+  int x = (uint8)pushedblocks_x_lo[j] | (uint8)pushedblocks_x_hi[j] << 8;
+  y -= BG2VOFS_copy2 + 1;
+  x -= BG2HOFS_copy2;
+  uint8 ch = kPushedblock_Char[kPushedBlock_Tab1[pushedblocks_some_index]];
+  if (ch != 0xff)
+    SetOamPlain(oam, x, y, ch, 0x20, 2);
+}
+
+void Link_Initialize() {  // 87f13c
+  link_direction_facing = 2;
+  link_direction_last = 0;
+  link_item_in_hand = 0;
+  link_position_mode = 0;
+  link_debug_value_1 = 0;
+  link_debug_value_2 = 0;
+  link_var30d = 0;
+  link_var30e = 0;
+  some_animation_timer_steps = 0;
+  link_is_transforming = 0;
+  bitfield_for_a_button = 0;
+  button_mask_b_y &= ~0x40;
+  link_state_bits = 0;
+  link_picking_throw_state = 0;
+  link_grabbing_wall = 0;
+  Link_ResetSwimmingState();
+  link_cant_change_direction &= ~1;
+  link_z_coord &= 0xff;
+  link_auxiliary_state = 0;
+  link_incapacitated_timer = 0;
+  countdown_for_blink = 0;
+  link_electrocute_on_touch = 0;
+  link_pose_for_item = 0;
+  link_cape_mode = 0;
+  Link_ForceUnequipCape_quietly();
+  Link_ResetSwordAndItemUsage();
+  link_disable_sprite_damage = 0;
+  player_handler_timer = 0;
+  link_direction &= ~0xf;
+  player_on_somaria_platform = 0;
+  link_spin_attack_step_counter = 0;
+
+  if (enhanced_features0 & kFeatures0_MiscBugFixes) {
+    // If you quit while jumping from a ledge and get hit on a platform you can go under solid layers
+    about_to_jump_off_ledge = 0;
+ 
+    // If you use the mirror near a moveable statue you can pull thin air and glitch the camera
+    link_is_near_moveable_statue = 0;
+
+    // If you use the mirror on a conveyor belt you will retain momentum and clip into the entrance wall
+    link_on_conveyor_belt = 0;
+    
+    // bugfix: you use the mirror on ice, you retain momentum
+    link_flag_moving = 0;
+
+    // If you quit in the middle of red armos knight stomp the lumberjack tree will fall on its own
+    bg1_y_offset = bg1_x_offset = 0;
+      //bugfix: if you die in a dungeon as a permabunny and continue, you revert back to link
+      if (!link_item_moon_pearl && savegame_is_darkworld) {
+        link_player_handler_state = kPlayerState_PermaBunny;
+        link_is_bunny = 1;
+        link_is_bunny_mirror = 1;
+        LoadGearPalettes_bunny();
+      }
+  }
+}
+
+void Link_ResetProperties_A() {  // 87f1a3
+  link_direction_last = 0;
+  link_direction = 0;
+  link_flag_moving = 0;
+  Link_ResetSwimmingState();
+  link_is_transforming = 0;
+  countdown_for_blink = 0;
+  ancilla_arr24[0] = 0;
+  link_is_bunny = 0;
+  link_is_bunny_mirror = 0;
+  BYTE(link_timer_tempbunny) = 0;
+  link_need_for_poof_for_transform = 0;
+  is_archer_or_shovel_game = 0;
+  link_need_for_pullforrupees_sprite = 0;
+  BYTE(bit9_of_xcoord) = 0;
+  link_something_with_hookshot = 0;
+  link_give_damage = 0;
+  link_spin_offsets = 0;
+  tagalong_event_flags = 0;
+  link_want_make_noise_when_dashed = 0;
+  BYTE(tiledetect_tile_type) = 0;
+  item_receipt_method = 0;
+  link_triggered_by_whirlpool_sprite = 0;
+  Link_ResetProperties_B();
+}
+
+void Link_ResetProperties_B() {  // 87f1e6
+  player_on_somaria_platform = 0;
+  link_spin_attack_step_counter = 0;
+  fallhole_var1 = 0;
+  flag_is_sprite_to_pick_up_cached = 0;
+  bitmask_of_dragstate = 0;
+  link_this_controls_sprite_oam = 0;
+  player_near_pit_state = 0;
+  Link_ResetProperties_C();
+}
+
+void Link_ResetProperties_C() {  // 87f1fa
+  if (enhanced_features0 & kFeatures0_MiscBugFixes) {
+    // Fix save menu lockout when dying after medallion cast (#126)
+    flag_custom_spell_anim_active = 0;
+  }
+
+  tile_action_index = 0;
+  state_for_spin_attack = 0;
+  step_counter_for_spin_attack = 0;
+  tile_coll_flag = 0;
+  link_force_hold_sword_up = 0;
+  link_sword_delay_timer = 0;
+  tiledetect_misc_tiles = 0;
+  link_item_in_hand = 0;
+  link_position_mode = 0;
+  link_debug_value_1 = 0;
+  link_debug_value_2 = 0;
+  link_var30d = 0;
+  link_var30e = 0;
+  some_animation_timer_steps = 0;
+  bitfield_for_a_button = 0;
+  button_mask_b_y = 0;
+  button_b_frames = 0;
+  link_state_bits = 0;
+  link_picking_throw_state = 0;
+  link_grabbing_wall = 0;
+  link_cant_change_direction = 0;
+  link_auxiliary_state = 0;
+  link_incapacitated_timer = 0;
+  link_electrocute_on_touch = 0;
+  link_pose_for_item = 0;
+  link_cape_mode = 0;
+  Link_ResetSwordAndItemUsage();
+  link_disable_sprite_damage = 0;
+  player_handler_timer = 0;
+  related_to_hookshot = 0;
+  flag_is_ancilla_to_pick_up = 0;
+  flag_is_sprite_to_pick_up = 0;
+  link_need_for_pullforrupees_sprite = 0;
+  link_is_near_moveable_statue = 0;
+}
+
+bool Link_CheckForEdgeScreenTransition() {  // 87f439
+  uint8 st = link_player_handler_state;
+  if (st == 3 || st == 8 || st == 9 || st == 10 || !link_incapacitated_timer)
+    return false;
+  link_actual_vel_x = link_actual_vel_y = 0;
+  link_recoilmode_timer = 3;
+  link_x_coord = link_x_coord_prev;
+  link_y_coord = link_y_coord_prev;
+  return true;
+}
+
+void CacheCameraPropertiesIfOutdoors() {  // 87f514
+  if (!player_is_indoors)
+    CacheCameraProperties();
+}
+
+void SomariaBlock_HandlePlayerInteraction(int k) {  // 88e7e6
+  cur_object_index = k;
+  if (ancilla_G[k])
+    return;
+
+  if (!ancilla_H[k]) {
+    if (link_auxiliary_state || (link_state_bits & 1) || ancilla_z[k] != 0 && ancilla_z[k] != 0xff || ancilla_K[k] || ancilla_L[k])
+      return;
+    if (!(joypad1H_last & kJoypadH_AnyDir)) {
+      ancilla_arr3[k] = 0;
+      bitmask_of_dragstate = 0;
+      ancilla_A[k] = 255;
+      if (!link_is_running) {
+        link_speed_setting = 0;
+        return;
+      }
+    } else if ((joypad1H_last & kJoypadH_AnyDir) == ancilla_arr3[k]) {
+      if (link_speed_setting == 18)
+        bitmask_of_dragstate |= 0x81;
+    } else {
+      ancilla_arr3[k] = (joypad1H_last & kJoypadH_AnyDir);
+      link_speed_setting = 0;
+    }
+
+    CheckPlayerCollOut coll_out;
+    if (!Ancilla_CheckLinkCollision(k, 4, &coll_out) || ancilla_floor[k] != link_is_on_lower_level)
+      return;
+
+    if (!link_is_running || link_dash_ctr == 64) {
+      uint8 t;
+      ancilla_x_vel[k] = 0;
+      ancilla_y_vel[k] = 0;
+      ancilla_arr3[k] = t = joypad1H_last & kJoypadH_AnyDir;
+      if (t & 3) {
+        ancilla_x_vel[k] = t & 1 ? 16 : -16;
+        ancilla_dir[k] = t & 1 ? 3 : 2;
+      } else {
+        ancilla_y_vel[k] = t & 8 ? -16 : 16;
+        ancilla_dir[k] = t & 8 ? 0 : 1;
+      }
+      if (link_actual_vel_y == 0 || link_actual_vel_x == 0) {
+        if (!Ancilla_CheckTileCollision_Class2(k)) {
+          Ancilla_MoveY(k);
+          Ancilla_MoveX(k);
+          if (!(link_state_bits & 0x80) && !(++ancilla_A[k] & 7))
+            Ancilla_Sfx2_Pan(k, 0x22);
+        }
+        bitmask_of_dragstate = 0x81;
+        link_speed_setting = 0x12;
+      }
+      Sprite_NullifyHookshotDrag();
+      return;
+    }
+    static const int8 kSomarianBlock_Yvel[4] = { -40, 40, 0, 0 };
+    static const int8 kSomarianBlock_Xvel[4] = { 0, 0, -40, 40 };
+    if (flag_is_ancilla_to_pick_up == k + 1)
+      flag_is_ancilla_to_pick_up = 0;
+    Link_CancelDash();
+    Ancilla_Sfx3_Pan(k, 0x32);
+    int j = link_direction_facing >> 1;
+    ancilla_dir[k] = j;
+    ancilla_y_vel[k] = kSomarianBlock_Yvel[j];
+    ancilla_x_vel[k] = kSomarianBlock_Xvel[j];
+    ancilla_z_vel[k] = 48;
+    ancilla_H[k] = 1;
+    ancilla_z[k] = 0;
+  }
+
+  ancilla_z_vel[k] -= 2;
+  Ancilla_MoveY(k);
+  Ancilla_MoveX(k);
+  Ancilla_MoveZ(k);
+  if (ancilla_z[k] && ancilla_z[k] < 252)
+    return;
+
+  Ancilla_Sfx2_Pan(k, 0x21);
+  ancilla_z[k] = 0;
+  int j = ancilla_H[k]++;
+  if (j == 3) {
+    ancilla_arr4[k] = 0;
+    ancilla_H[k] = 0;
+  } else {
+    static const int8 kSomarianBlock_Zvel[4] = { 48, 24, 16, 8 };
+    ancilla_z_vel[k] = kSomarianBlock_Zvel[j - 1];
+    ancilla_y_vel[k] = (int8)ancilla_y_vel[k] / 2;
+    ancilla_x_vel[k] = (int8)ancilla_x_vel[k] / 2;
+  }
+}
+
+void Gravestone_Move(int k) {  // 88ed89
+  if (submodule_index)
+    return;
+  ancilla_y_vel[k] = -8;
+  Ancilla_MoveY(k);
+
+  Gravestone_ActAsBarrier(k);
+  uint16 y_target = ancilla_B[k] << 8 | ancilla_A[k];
+  uint16 y_cur = Ancilla_GetY(k);
+
+  if (y_cur >= y_target)
+    return;
+
+  ancilla_type[k] = 0;
+  link_something_with_hookshot = 0;
+  bitmask_of_dragstate &= ~4;
+  BYTE(scratch_0) = ((uint8 *)door_debris_y)[k];
+  HIBYTE(scratch_0) = ((uint8 *)door_debris_x)[k];
+  big_rock_starting_address = scratch_0;
+
+  door_open_closed_counter = big_rock_starting_address == 0x532 ? 0x48 :
+    big_rock_starting_address == 0x488 ? 0x60 : 0x40;
+  Overworld_DoMapUpdate32x32_B();
+}
+
+void Gravestone_ActAsBarrier(int k) {  // 88ee57
+  uint16 x = Ancilla_GetX(k);
+  uint16 y = Ancilla_GetY(k);
+  uint16 r4 = y + 0x18;
+  uint16 r6 = x + 0x20;
+  uint16 lx = link_x_coord + 8;
+  uint16 ly = link_y_coord + 8;
+  if (ly >= y && ly < r4 &&
+      lx >= x && lx < r6) {
+    uint16 r10 = abs16(ly - r4);
+    link_y_coord += r10;
+    link_y_vel += r10;
+    bitmask_of_dragstate |= 4;
+  }
+  if (link_direction_facing)
+    link_direction_facing &= ~4;
+}
+
+void AncillaAdd_DugUpFlute(uint8 a, uint8 y) {  // 898c73
+  int k = Ancilla_AddAncilla(a, y);
+  if (k < 0)
+    return;
+  ancilla_step[k] = 0;
+  ancilla_z[k] = 0;
+  ancilla_z_vel[k] = 24;
+  ancilla_x_vel[k] = link_direction_facing == 4 ? -8 : 8;
+  DecodeAnimatedSpriteTile_variable(12);
+  Ancilla_SetXY(k, 0x490, 0xa8a);
+}
+
+void AncillaAdd_CaneOfByrnaInitSpark(uint8 a, uint8 y) {  // 898ee0
+  for (int k = 4; k >= 0; k--) {
+    if (ancilla_type[k] == 0x31)
+      ancilla_type[k] = 0;
+  }
+  int k = Ancilla_AddAncilla(a, y);
+  if (k >= 0) {
+    ancilla_item_to_link[k] = 0;
+    ancilla_aux_timer[k] = 9;
+    link_disable_sprite_damage = 1;
+    ancilla_arr3[k] = 2;
+  }
+}
+
+void AncillaAdd_ShovelDirt(uint8 a, uint8 y) {  // 898f5b
+  int k = Ancilla_AddAncilla(a, y);
+  if (k >= 0) {
+    ancilla_item_to_link[k] = 0;
+    ancilla_timer[k] = 20;
+    Ancilla_SetXY(k, link_x_coord, link_y_coord);
+  }
+}
+
+void AncillaAdd_Hookshot(uint8 a, uint8 y) {  // 899b10
+  static const int8 kHookshot_Yvel[4] = { -64, 64, 0, 0 };
+  static const int8 kHookshot_Xvel[4] = { 0, 0, -64, 64 };
+  static const int8 kHookshot_Yd[4] = { 4, 20, 8, 8 };
+  static const int8 kHookshot_Xd[4] = { 0, 0, -4, 11 };
+
+  int k = Ancilla_AddAncilla(a, y);
+  if (k >= 0) {
+    ancilla_aux_timer[k] = 3;
+    ancilla_item_to_link[k] = 0;
+    ancilla_step[k] = 0;
+    ancilla_L[k] = 0;
+    related_to_hookshot = 0;
+    hookshot_effect_index = k;
+    ancilla_K[k] = 0;
+    ancilla_G[k] = 255;
+    ancilla_arr1[k] = 0;
+    ancilla_timer[k] = 0;
+    int j = link_direction_facing >> 1;
+    ancilla_dir[k] = j;
+    ancilla_x_vel[k] = kHookshot_Xvel[j];
+    ancilla_y_vel[k] = kHookshot_Yvel[j];
+    Ancilla_SetXY(k, link_x_coord + kHookshot_Xd[j], link_y_coord + kHookshot_Yd[j]);
+  }
+}
+
+void ResetSomeThingsAfterDeath(uint8 a) {  // 8bffbf
+  link_is_in_deep_water = 0;
+  link_speed_setting = a;
+  link_on_conveyor_belt = 0;
+  byte_7E0322 = 0;
+  flag_is_link_immobilized = 0;
+  palette_swap_flag = 0;
+  player_unk1 = 0;
+  link_give_damage = 0;
+  link_actual_vel_y = 0;
+  link_actual_vel_x = 0;
+  link_actual_vel_z = 0;
+  BYTE(link_z_coord) = 0;
+  draw_water_ripples_or_grass = 0;
+  byte_7E0316 = 0;
+  countdown_for_blink = 0;
+  link_player_handler_state = 0;
+  link_visibility_status = 0;
+  Ancilla_TerminateSelectInteractives(0);
+  Link_ResetProperties_A();
+}
+
+void SpawnHammerWaterSplash() {  // 9aff3c
+  static const int8 kItem_Hammer_SpawnWater_X[4] = { 0, 12, -8, 24 };
+  static const int8 kItem_Hammer_SpawnWater_Y[4] = { 8, 32, 24, 24 };
+  if (submodule_index | flag_is_link_immobilized | flag_unk1)
+    return;
+  int i = link_direction_facing >> 1;
+  uint16 x = link_x_coord + kItem_Hammer_SpawnWater_X[i];
+  uint16 y = link_y_coord + kItem_Hammer_SpawnWater_Y[i];
+  uint8 tiletype;
+  if (player_is_indoors) {
+    int t = (link_is_on_lower_level >= 1) ? 0x1000 : 0;
+    t += (x & 0x1f8) >> 3;
+    t += (y & 0x1f8) << 3;
+    tiletype = dung_bg2_attr_table[t];
+  } else {
+    tiletype = Overworld_ReadTileAttribute(x >> 3, y);
+  }
+
+  if (tiletype == 8 || tiletype == 9) {
+    int j = Sprite_SpawnSmallSplash(0);
+    if (j >= 0) {
+      Sprite_SetX(j, x - 8);
+      Sprite_SetY(j, y - 16);
+      sprite_floor[j] = link_is_on_lower_level;
+      sprite_z[j] = 0;
+    }
+  }
+}
+
+void DiggingGameGuy_AttemptPrizeSpawn() {  // 9dfd5c
+  static const int8 kDiggingGameGuy_Xvel[2] = { -16, 16 };
+  static const int8 kDiggingGameGuy_X[2] = { 0, 19 };
+  static const uint8 kDiggingGameGuy_Items[4] = { 0xdb, 0xda, 0xd9, 0xdf };
+
+  beamos_x_hi[1]++;
+  if (link_y_coord >= 0xb18)
+    return;
+  int j = GetRandomNumber() & 7;
+  uint8 item_to_spawn;
+  switch (j) {
+  case 0: case 1: case 2: case 3:
+    item_to_spawn = kDiggingGameGuy_Items[j];
+    break;
+  case 4:
+    if (beamos_x_hi[1] < 25 || beamos_x_hi[0] || GetRandomNumber() & 3)
+      return;
+    item_to_spawn = beamos_x_hi[0] = 0xeb;
+    break;
+  default:
+    return;
+  }
+  SpriteSpawnInfo info;
+  j = Sprite_SpawnDynamically(4, item_to_spawn, &info); // zelda bug: 4 wtf...
+  if (j >= 0) {
+    int i = link_direction_facing != 4;
+    sprite_x_vel[j] = kDiggingGameGuy_Xvel[i];
+    sprite_y_vel[j] = 0;
+    sprite_z_vel[j] = 24;
+    sprite_stunned[j] = 255;
+    sprite_delay_aux4[j] = 48;
+    Sprite_SetX(j, (link_x_coord + kDiggingGameGuy_X[i]) & ~0xf);
+    Sprite_SetY(j, (link_y_coord + 22) & ~0xf);
+    sprite_floor[j] = 0;
+    SpriteSfx_QueueSfx3WithPan(j, 0x30);
+  }
+}
+
--- /dev/null
+++ b/src/player.h
@@ -1,0 +1,242 @@
+#pragma once
+#include "types.h"
+
+extern const uint8 kSwimmingTab1[4];
+extern const uint8 kSwimmingTab2[2];
+
+enum {
+  kPlayerState_Ground = 0,
+  kPlayerState_FallingIntoHole = 1,
+  kPlayerState_RecoilWall = 2,
+  kPlayerState_SpinAttacking = 3,
+  kPlayerState_Swimming = 4,
+  kPlayerState_TurtleRock = 5,
+  kPlayerState_RecoilOther = 6,
+  kPlayerState_Electrocution = 7,
+  kPlayerState_Ether = 8,
+  kPlayerState_Bombos = 9,
+  kPlayerState_Quake = 10,
+  kPlayerState_FallOfLeftRightLedge = 12,
+  kPlayerState_JumpOffLedgeDiag = 14,
+  kPlayerState_StartDash = 17,
+  kPlayerState_StopDash = 18,
+  kPlayerState_Hookshot = 19,
+  kPlayerState_Mirror = 20,
+  kPlayerState_HoldUpItem = 21,
+  kPlayerState_AsleepInBed = 22,
+  kPlayerState_PermaBunny = 23,
+  kPlayerState_ReceivingEther = 25,
+  kPlayerState_ReceivingBombos = 26,
+  kPlayerState_OpeningDesertPalace = 27,
+  kPlayerState_TempBunny = 28,
+  kPlayerState_PullForRupees = 29,
+  kPlayerState_SpinAttackMotion = 30,
+};
+
+
+
+
+
+
+void Dungeon_HandleLayerChange();
+void CacheCameraProperties();
+void CheckAbilityToSwim();
+void Link_Main();
+void Link_ControlHandler();
+void LinkState_Default();
+void HandleLink_From1D();
+void PlayerHandler_00_Ground_3();
+bool Link_HandleBunnyTransformation();
+void LinkState_TemporaryBunny();
+void PlayerHandler_17_Bunny();
+void LinkState_Bunny_recache();
+void Link_TempBunny_Func2();
+void LinkState_HoldingBigRock();
+void EtherTablet_StartCutscene();
+void LinkState_ReceivingEther();
+void BombosTablet_StartCutscene();
+void LinkState_ReceivingBombos();
+void LinkState_ReadingDesertTablet();
+void HandleSomariaAndGraves();
+void LinkState_Recoil();
+void Link_HandleRecoilAndTimer(bool jump_into_middle);
+void LinkState_OnIce();
+void Link_HandleChangeInZVelocity();
+void Player_ChangeZ(uint8 zd);
+void LinkHop_HoppingSouthOW();
+void LinkState_HandlingJump();
+void LinkHop_FindTileToLandOnSouth();
+void LinkState_HoppingHorizontallyOW();
+void Link_HoppingHorizontally_FindTile_Y();
+void Link_SetToDeepWater();
+void LinkState_0F();
+uint8 Link_HoppingHorizontally_FindTile_X(uint8 o);
+void LinkState_HoppingDiagonallyUpOW();
+void LinkState_HoppingDiagonallyDownOW();
+void LinkHop_FindLandingSpotDiagonallyDown();
+void Link_SplashUponLanding();
+void LinkState_Dashing();
+void LinkState_ExitingDash();
+void Link_CancelDash();
+void RepelDash();
+void LinkApplyTileRebound();
+void Sprite_RepelDash();
+void Flag67WithDirections();
+void LinkState_Pits();
+void HandleLayerOfDestination();
+void DungeonPitDoDamage();
+void HandleDungeonLandingFromPit();
+void PlayerHandler_04_Swimming();
+void Link_HandleSwimMovements();
+void Link_FlagMaxAccels();
+void Link_SetIceMaxAccel();
+void Link_SetMomentum();
+void Link_ResetSwimmingState();
+void Link_ResetStateAfterDamagingPit();
+void ResetAllAcceleration();
+void Link_HandleSwimAccels();
+void Link_SetTheMaxAccel();
+void LinkState_Zapped();
+void PlayerHandler_15_HoldItem();
+void Link_ReceiveItem(uint8 item, int chest_position);
+void Link_TuckIntoBed();
+void LinkState_Sleeping();
+void Link_HandleSwordCooldown();
+void Link_HandleYItem();
+void Link_HandleAPress();
+void Link_APress_PerformBasic(uint8 action_x2);
+void HandleSwordSfxAndBeam();
+void Link_CheckForSwordSwing();
+void HandleSwordControls();
+void Link_ResetSwordAndItemUsage();
+void Player_Sword_SpinAttackJerks_HoldDown();
+void LinkItem_Rod();
+void LinkItem_Hammer();
+void LinkItem_Bow();
+void LinkItem_Boomerang();
+void Link_ResetBoomerangYStuff();
+void LinkItem_Bombs();
+void LinkItem_Bottle();
+void LinkItem_Lamp();
+void LinkItem_Powder();
+void LinkItem_ShovelAndFlute();
+void LinkItem_Shovel();
+void LinkItem_Flute();
+void LinkItem_Book();
+void LinkItem_Ether();
+void LinkState_UsingEther();
+void LinkItem_Bombos();
+void LinkState_UsingBombos();
+void LinkItem_Quake();
+void LinkState_UsingQuake();
+void Link_ActivateSpinAttack();
+void Link_AnimateVictorySpin();
+void LinkState_SpinAttack();
+void LinkItem_Mirror();
+void DoSwordInteractionWithTiles_Mirror();
+void LinkState_CrossingWorlds();
+void Link_PerformDesertPrayer();
+void HandleFollowersAfterMirroring();
+void LinkItem_Hookshot();
+void LinkState_Hookshotting();
+void LinkItem_Cape();
+void Link_ForceUnequipCape();
+void Link_ForceUnequipCape_quietly();
+void HaltLinkWhenUsingItems();
+void Link_HandleCape_passive_LiftCheck();
+void Player_CheckHandleCapeStuff();
+void LinkItem_CaneOfSomaria();
+void LinkItem_CaneOfByrna();
+bool SearchForByrnaSpark();
+void LinkItem_Net();
+bool CheckYButtonPress();
+bool LinkCheckMagicCost(uint8 x);
+void Refund_Magic(uint8 x);
+void Link_ItemReset_FromOverworldThings();
+void Link_PerformThrow();
+void Link_APress_LiftCarryThrow();
+void Link_PerformDash();
+void Link_PerformGrab();
+void Link_APress_PullObject();
+void Link_PerformStatueDrag();
+void Link_APress_StatueDrag();
+void Link_PerformRupeePull();
+void LinkState_TreePull();
+void Link_PerformRead();
+void Link_PerformOpenChest();
+bool Link_CheckNewAPress();
+bool Link_HandleToss();
+void Link_HandleDiagonalCollision();
+void Player_LimitDirections_Inner();
+void Link_HandleCardinalCollision();
+void RunSlopeCollisionChecks_VerticalFirst();
+void RunSlopeCollisionChecks_HorizontalFirst();
+bool CheckIfRoomNeedsDoubleLayerCheck();
+void CreateVelocityFromMovingBackground();
+void StartMovementCollisionChecks_Y();
+void StartMovementCollisionChecks_Y_HandleIndoors();
+void HandlePushingBonkingSnaps_Y();
+void StartMovementCollisionChecks_Y_HandleOutdoors();
+bool RunLedgeHopTimer(); // carry
+void Link_BonkAndSmash();
+void Link_AddInVelocityYFalling();
+void CalculateSnapScratch_Y();
+void ChangeAxisOfPerpendicularDoorMovement_Y();
+void Link_AddInVelocityY();
+void Link_HopInOrOutOfWater_Y();
+void Link_FindValidLandingTile_North();
+void Link_FindValidLandingTile_DiagonalNorth();
+void StartMovementCollisionChecks_X();
+void StartMovementCollisionChecks_X_HandleIndoors();
+void HandlePushingBonkingSnaps_X();
+void StartMovementCollisionChecks_X_HandleOutdoors();
+void SnapOnX();
+void CalculateSnapScratch_X();
+int8 ChangeAxisOfPerpendicularDoorMovement_X();
+void Link_HopInOrOutOfWater_X();
+void Link_HandleDiagonalKickback();
+void TileDetect_MainHandler(uint8 item);
+bool Link_PermissionForSloshSounds();
+bool PushBlock_AttemptToPushTheBlock(uint8 what, uint16 x, uint16 y);
+uint8 Link_HandleLiftables();
+void HandleNudging(int8 arg_r0);
+void TileBehavior_HandleItemAndExecute(uint16 x, uint16 y);
+uint8 PushBlock_GetTargetTileFlag(uint16 x, uint16 y);
+void FlagMovingIntoSlopes_Y();
+void FlagMovingIntoSlopes_X();
+void Link_HandleRecoiling();
+void Player_HandleIncapacitated_Inner2();
+void Link_HandleVelocity();
+void Link_MovePosition();
+void Link_HandleVelocityAndSandDrag(uint16 x, uint16 y);
+void HandleSwimStrokeAndSubpixels();
+void Player_SomethingWithVelocity_TiredOrSwim(uint16 xvel, uint16 yvel);
+void Link_HandleMovingFloor();
+void Link_ApplyMovingFloorVelocity();
+void Link_ApplyConveyor();
+void Link_HandleMovingAnimation_FullLongEntry();
+void Link_HandleMovingAnimation_StartWithDash();
+void Link_HandleMovingAnimationSwimming();
+void Link_HandleMovingAnimation_Dash();
+void HandleIndoorCameraAndDoors();
+void HandleDoorTransitions();
+void ApplyLinksMovementToCamera();
+uint8 FindFreeMovingBlockSlot(uint8 x);
+bool InitializePushBlock(uint8 r14, uint8 idx);
+void Sprite_Dungeon_DrawSinglePushBlock(int j);
+void Link_Initialize();
+void Link_ResetProperties_A();
+void Link_ResetProperties_B();
+void Link_ResetProperties_C();
+bool Link_CheckForEdgeScreenTransition();
+void CacheCameraPropertiesIfOutdoors();
+void SomariaBlock_HandlePlayerInteraction(int k);
+void Gravestone_Move(int k);
+void Gravestone_ActAsBarrier(int k);
+void AncillaAdd_DugUpFlute(uint8 a, uint8 y);
+void AncillaAdd_CaneOfByrnaInitSpark(uint8 a, uint8 y);
+void AncillaAdd_ShovelDirt(uint8 a, uint8 y);
+void AncillaAdd_Hookshot(uint8 a, uint8 y);
+void ResetSomeThingsAfterDeath(uint8 a);
+void SpawnHammerWaterSplash();
+void DiggingGameGuy_AttemptPrizeSpawn();
--- /dev/null
+++ b/src/player_oam.c
@@ -1,0 +1,1289 @@
+#include "player_oam.h"
+#include "zelda_rtl.h"
+#include "variables.h"
+#include "snes/snes_regs.h"
+#include "player.h"
+#include "misc.h"
+
+static const int8 kPlayerOam_StairsOffsY[] = {
+  0, -2, -3, 0, -2, -3, 0, 0, 0, 0, 0, 0, 0, -2, -3, 0,
+  -2, -3, 0, 0, 0, 0, 0, 0,
+};
+static const uint16 kPlayerOam_FloorOamPrio[] = {0x2000, 0x1000, 0x3000, 0x2000};
+static const uint16 kPlayerOam_SortSpritesOffs[] = {0x190, 0xe0};
+static const int8 kPlayerOam_Tab1[9] = {0, 1, 2, 0, 1, 2, 0, 1, 2};
+static const int8 kPlayerOam_Tab2[8] = {6, 6, 6, 6, 7, 7, 8, 9};
+static const int8 kPlayerOam_Tab3[6] = {12, 11, 32, 34, 35, 37};
+static const int8 kPlayerOam_Tab4[8] = {38, 11, 11, 12, 11, 11, 11, 13};
+static const uint8 kPlayerOam_Tab5[7] = {4, 16, 18, 21, 23, 24, 39};
+static const uint16 kSwordTipSomething[] = { 0xFFFF, 0xFFFF, 0x6A3E, 0x6A2F, 0x6A2F, 0x2A05, 0x2A2F, 0x2A3E, 0xFFFF, 0xFFFF, 0xFFFF, 0xAA3E, 0xAA2F, 0xAA2F, 0xAA05, 0xEA2F, 0xEA3E, 0xFFFF, 0xFFFF, 0xFFFF, 0x2A3E, 0x2A3F, 0x2A3F, 0x2A05, 0xAA3F, 0xAA3E, 0xFFFF, 0xFFFF, 0xFFFF, 0x6A3E, 0x6A3F, 0x6A3F, 0x6A05, 0xEA3F, 0xEA3E, 0xFFFF };
+static const int8 kSwordOamYOffs_Good[] = {-1, -1, -5, -13, -15, -21, -13, -5, -1, -1, -1, 22, 27, 29, 35, 27, 24, -1, -1, -1, -1, 2, 5, 12, 20, 26, -1, -1, -1, -1, 2, 5, 12, 20, 26, -1};
+static const int8 kSwordOamXOffs_Good[] = {-1, -1, 15, 13, 8, -1, -10, -14, -1, -1, -1, -6, -3, 1, 8, 16, 21, -1, -1, -1, -11, -15, -18, -24, -17, -12, -1, -1, -1, 19, 23, 26, 32, 25, 20, -1};
+static const uint16 kPlayerOamOtherOffs[] = { 0, 36, 72, 96, 108, 118, 122, 134, 36, 146, 154, 178, 185, 188, 212, 236, 252, 264, 272, 288, 300, 316, 339, 363, 374, 390, 396, 402, 408, 420, 421, 422, 424, 428, 444, 456, 468, 469, 470, 475, 9, 45, 78, 99, 108, 119, 125, 137, 45, 148, 160, 178, 185, 194, 218, 236, 255, 266, 276, 291, 304, 316, 345, 363, 378, 393, 399, 402, 411, 420, 421, 422, 425, 432, 447, 456, 468, 469, 470, 484, 18, 54, 84, 102, 108, 120, 128, 140, 54, 150, 166, 178, 182, 200, 224, 236, 258, 268, 280, 294, 308, 316, 351, 363, 382, 390, 396, 402, 414, 420, 421, 422, 426, 436, 450, 456, 468, 469, 470, 493, 27, 63, 90, 105, 108, 121, 131, 143, 63, 152, 172, 178, 185, 206, 230, 236, 261, 270, 284, 297, 312, 316, 357, 363, 386, 393, 399, 402, 417, 420, 421, 422, 427, 440, 453, 456, 468, 469, 470, 502 };
+static const int8 kSwordOamYOffs[511] = {
+  -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128,
+  -128, -128, -128, -128, 9, 5, -2, -6, -8, -5, -3, 7, 9, 11, 15, 21, 25, 27, 25, 23, 13, 11, -2, 2, 3, 12, 12, 15, 22, 27, 27, -2,
+  2, 3, 12, 12, 15, 22, 27, 27, -5, -4, -3, -5, -4, -3, 24, 25, 26, 24, 25, 26, 13, 14, 15, 13, 14, 15, 13, 14, 15, 13, 14, 15,
+  -3, -7, 2, 20, 26, 24, 10, 13, 15, 10, 13, 15, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -7, -1, -2, -3, 10, 26,
+  -2, 3, 14, -2, 3, 14, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128,
+  -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128,
+  -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128,
+  -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -4, -8, 6, 15, 26, 26, 14, 6, -7, -7, 22, 26, 16, 8, 5, 12, -128, -128, -128, -128,
+  -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128,
+  -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, 24, 16, -5, 16,
+  13, -4, -5, -5, -1, -5, -5, -5, -5, 11, 15, 21, 25, 27, 13, -3, -7, 26, 18, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128,
+  -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128,
+  -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128,
+  -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128,
+  -128, -128, -128, -128, -128, -128, -128, -128, -4, -5, 4, 14, 20, 15, 8, -3, -8, 14, -3, 15, -128, -128, -128, -128, -128, -128, -128, 9, 5, -3, -9, -11,
+  -15, -9, -4, 8, 11, 14, 20, 25, 27, 31, 25, 23, 13, -2, -1, 0, 8, 9, 12, 16, 24, 30, -2, -1, 0, 8, 9, 12, 16, 24, 30,
+};
+static const int8 kSwordOamXOffs[511] = {
+  -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128,
+  -128, -128, -128, -128, 19, 18, 14, 10, 0, -4, -10, -13, -15, -8, -6, -5, 5, 8, 12, 18, 22, 23, 3, -2, -7, -11, -14, -11, -9, 1, 3, 5,
+  10, 15, 19, 22, 19, 17, 7, 5, 0, 0, 0, 0, 0, 0, 7, 7, 7, 7, 7, 7, -10, -10, -10, -10, -10, -10, 18, 18, 18, 18, 18, 18,
+  -3, 2, -3, 10, 7, 10, -16, -24, -20, 16, 24, 20, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -2, -2, -2, 10, 10, 10,
+  1, -10, -11, 7, 18, 19, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128,
+  -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128,
+  -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128,
+  -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, 13, 6, 22, 22, 8, -1, -14, -14, -1, 9, -5, 3, 18, 21, -11, -12, -128, -128, -128, -128,
+  -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128,
+  -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, 7, -9, 0, 17,
+  22, 14, 10, 10, 14, 11, 8, 8, 8, 23, 22, 20, 12, 8, 23, 14, 10, 12, 12, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128,
+  -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128,
+  -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128,
+  -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128,
+  -128, -128, -128, -128, -128, -128, -128, -128, 13, 13, 16, 11, 2, -11, -16, -9, 0, 11, -9, -11, -128, -128, -128, -128, -128, -128, -128, 19, 17, 15, 14, 3,
+  -1, -5, -11, -14, -8, -7, -6, 3, 5, 8, 12, 18, 22, 3, -2, -8, -13, -16, -20, -15, -12, 1, 5, 10, 16, 21, 24, 28, 23, 20, 7,
+};
+static const int8 kPlayerOam_Main_SwordStuff_array1[511] = {
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, 1, 5, 14, 26, 6, 8, 16, 20, 0, 0, 2, 13,
+  25, 7, 11, 19, 23, 1, 6, 8, 16, 20, 0, 2, 13, 25, 7, 6,
+  10, 18, 22, 1, 4, 15, 27, 7, 10, 10, 10, 10, 10, 10, 9, 9,
+  9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1,
+  6, 10, 6, 7, 9, 7, 0, 0, 0, 1, 1, 1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, 8, 10, 10, 8, 32, 29, 33, 29, 34, 30,
+  31, 37, 38, 31, 35, 36, 42, 39, 39, 41, 40, 40, 44, 42, 42, 45,
+  41, 41, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, 49, 49, 50, 47, 47, 48, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 10, 8, 5, 4,
+  11, 9, 2, 3, 8, 10, 9, 11, 4, 5, 3, 2, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 3, 3,
+  -1, 1, 5, 5, -1, 0, 3, 3, -1, 1, 5, 5, 9, 2, 6, 4,
+  4, 10, 6, 6, 10, 6, 8, 8, 8, 1, 4, 15, 11, 7, 4, 10,
+  6, 7, 28, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, 51, 52, 53, 54, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 68, 68, 70, 68,
+  68, 67, 71, 68, 74, 73, 69, 72, 55, 55, 56, 57, 58, 59, 60, 61,
+  62, 63, 64, 65, 6, 75, -1, -1, -1, -1, -1, 1, 5, 14, 26, 10,
+  6, 8, 16, 20, 0, 2, 13, 25, 9, 7, 11, 19, 23, 6, 8, 16,
+  20, 3, 0, 2, 13, 25, 6, 10, 18, 22, 5, 1, 4, 15, 27,
+};
+static const uint8 kPlayerOam_Main_SwordStuff_array2[76] = {
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2,
+  2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0,
+  0, 0, 0, 2, 0, 2, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2,
+  0, 2, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+  2, 2, 2, 0, 0, 0, 0, 2, 0, 2, 0, 2,
+};
+static const uint8 kPlayerOam_Main_SwordStuff_array3[76] = {
+  6, 6, 4, 4, 4, 4, 0, 0, 8, 8, 8, 8, 2, 2, 2, 2,
+  10, 10, 10, 10, 12, 12, 12, 12, 14, 14, 14, 14, 0, 9, 12, 9,
+  12, 14, 10, 8, 13, 8, 13, 18, 18, 17, 17, 16, 16, 16, 16, 64,
+  65, 64, 65, 24, 24, 25, 25, 36, 33, 37, 35, 34, 32, 38, 35, 37,
+  38, 34, 40, 42, 41, 41, 44, 40, 43, 40, 43, 48,
+};
+static const uint8 kPlayerOam_Main_SwordStuff_array4[10] = {1, 4, 1, 4, 6, 2, 0, 5, 0, 5};
+static const int8 kPlayerOam_ShieldStuff_array1[511] = {
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2,
+  2, 2, 2, 2, 0, 0, 0, 0, 2, 2, 2, 2, 2, 1, 1, 1,
+  1, 3, 3, 3, 3, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3,
+  3, 3, 3, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  2, 2, 2, 3, 3, 3, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, 1, 0, 1, 1, 2, 2, 2, 3, 3, 3,
+  1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, 1, 2, 0, 3, 3, 1, 2, 1, 1, 1, 1, 1, 1, 1,
+  0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2,
+  2, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 3, 1, 2,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 0, 0,
+  3, 0, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, 3, -1, -1, -1, 2, 3, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 2, 2, 2, 2, 2,
+  2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+};
+static const uint8 kPlayerOam_ShieldStuff_array2[18] = {
+  0, 2, 4, 4, 4, 4, 4, 4, 9, 12, 9, 12, 14, 10, 8, 13,
+  8, 13,
+};
+static const uint8 kPlayerOam_ShieldStuff_array3[10] = {1, 4, 1, 4, 6, 2, 0, 5, 0, 5};
+static const uint8 kPlayerOamSpriteLocs[511] = {
+  2, 2, 2, 2, 2, 2, 2, 2, 2, 10, 10, 10, 10, 10, 10, 10, 10, 10, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+  2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 1, 0, 0, 0, 0, 11, 11, 11, 11, 11, 2, 2, 2, 2, 2, 2, 0, 0, 0, 2,
+  2, 2, 2, 2, 2, 0, 0, 0, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  3, 3, 3, 6, 6, 6, 5, 5, 5, 5, 5, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 0, 0, 0, 3, 3, 6, 6, 6,
+  0, 0, 0, 0, 0, 0, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 2, 0, 2, 0, 2, 2, 2, 2, 2, 2,
+  10, 10, 10, 10, 10, 10, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 1, 1, 2, 1, 1, 2, 4, 4, 4, 4,
+  4, 4, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3,
+  2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 5, 5, 5, 5, 5, 2, 2, 5, 5, 5, 5, 2, 5, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 7, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9,
+  0, 0, 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 1,
+  1, 1, 1, 1, 1, 3, 3, 10, 10, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+  2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+  2, 2, 2, 2, 1, 1, 2, 2, 3, 6, 5, 5, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 2, 2,
+  0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 2, 2, 0, 2, 0, 5, 2, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3,
+  3, 3, 3, 3, 0, 11, 11, 11, 11, 11, 11, 11, 11, 2, 2, 2, 2, 2, 0, 0, 0, 0, 2, 2, 2, 2, 2, 0, 0, 0, 0,
+};
+static const uint16 kPlayerOam_Tab6[28] = {0, 10, 22, 38, 61, 72, 88, 0, 13, 26, 38, 61, 76, 97, 0, 16, 30, 38, 61, 80, 106, 0, 19, 34, 38, 61, 84, 115};
+static const int8 kPlayerOam_Spr1Bank[124] = {
+  0, -1, -1, 2, 3, 4, -1, -1, -1, -1, -1, 21, 23, -1, 21, 23, -1, 22, 24, -1, 21, 23, 19, 11, 15, -1, 17, 9, 13, -1, 9, 18,
+  13, -1, 10, 17, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 4, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 23, 23,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, 23, 23, -1, -1, 21, 21, -1, -1, 24, 24, -1, -1, 23, 23, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 26, 26, 26, -1, -1, -1, -1, -1, -1, 25, 25, 25, -1, -1,
+};
+static const int8 kPlayerOam_Spr2Bank[124] = {
+  1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 22, 24, -1, 22, 24, -1, -1, -1, -1, -1, -1, 20, 12, 16, -1, 18, 10, 14, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 24, 24,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, 24, 24, -1, -1, 22, 22, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+};
+static const uint8 kPlayerOam_Tab19B[12] = {20, 28, 8, 16, 16, 20, 28, 16, 8, 8, 8, 20};
+static const uint8 kPlayerOam_Tab19A[12] = {0, 8, 0, 8, 8, 12, 20, 8, 8, 0, 0, 0};
+static const int8 kPlayerOam_Spr1X[124] = {
+  8, -1, -1, 4, 4, 4, -1, -1, -1, -1, -1, -7, -9, -1, -8, -10, -1, 13, 16, -1, -5, -8, -2, -6, -5, -1, -1, -5, -6, -1, -3, 4,
+  9, -1, 11, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 4, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -5, -8,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -5, -8, -1, -1, -5, -8, -1, -1, 15, 17, -1, -1, -7, -9, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -3, -7, -3, -1, -1, -1, -1, -1, -1, 11, 15, 11, -1, -1,
+};
+static const int8 kPlayerOam_Spr1Y[124] = {
+  0, -1, -1, 8, 8, 8, -1, -1, -1, -1, -1, 7, 10, -1, 5, 8, -1, 8, 12, -1, 8, 12, 2, 7, 13, -1, 20, 14, 7, -1, 20, 21,
+  20, -1, 20, 21, 20, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -8, -8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 5, 11,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, 5, 11, -1, -1, 6, 1, -1, -1, 13, 15, -1, -1, 13, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 12, 12, 12, -1, -1, -1, -1, -1, -1, 12, 12, 12, -1, -1,
+};
+static const int8 kPlayerOam_Spr2X[124] = {
+  -8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 15, 17, -1, 16, 18, -1, -1, -1, -1, -1, -1, 10, 14, 13, -1, 9, 14, 14, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 13, 16,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, 13, 16, -1, -1, 13, 16, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+};
+static const int8 kPlayerOam_Spr2Y[124] = {
+  16, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 7, 10, -1, 5, 8, -1, -1, -1, -1, -1, -1, 2, 7, 13, -1, 20, 14, 7, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 5, 11,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, 5, 11, -1, -1, 6, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+};
+static const uint8 kPlayerOam_Tab20A[12] = {4, 12, 4, 12, 12, 16, 24, 12, 12, 12, 4, 4};
+static const uint8 kPlayerOam_Tab20B[12] = {24, 32, 12, 20, 20, 24, 32, 20, 12, 20, 12, 24};
+static const uint8 kPlayerOam_Prio[15] = {0x0, 0x0, 0x0, 0x0, 0x40, 0x40, 0x48, 0xc0, 0x48, 0xc0, 0x48, 0xc0, 0x48, 0xc0, 0x40};
+static const int8 kDrawSword_y[511] = {
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, 9, 5, -2, -6, -8, -5, -3, -1, 9, 11, 15, 13, 17, 19, 17, 15, 13, 11, -2, 2, 3, 4, 12, 15, 14, 19, 19, -2,
+  2, 3, 4, 12, 15, 14, 19, 19, -5, -4, -3, -5, -4, -3, 16, 17, 18, 16, 17, 18, 13, 14, 15, 13, 14, 15, 13, 14, 15, 13, 14, 15,
+  -3, -7, 2, 12, 18, 16, 15, 13, 10, 15, 13, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 2, 3, 6, 6, -8, -3, -3, -3, 10, 18,
+  -2, 2, 14, -2, 2, 14, 5, 9, 9, 9, 13, 13, 10, 7, 7, 10, 7, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 10, 11, -4, 10, 11, -4, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -4, -8, 6, 15, 18, 18, 14, 6, -7, -7, 14, 17, 16, 8, 5, 12, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 8, 6, 10, -1, 8, 6, 10, -1, 8, 6, 10, -1, 8, 6, 10, 16, 16, -5, 16,
+  13, -4, -5, -5, -1, -5, -5, -5, -5, 11, 15, 13, 17, 19, 13, -3, -7, 18, 18, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, 2, 17, 12, 12, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 5, -2, -9, -7,
+  -2, 16, 2, -2, 12, 2, -2, 12, -4, -5, 4, 14, 20, 15, 8, -3, -8, 14, -3, 15, -5, 0, -1, -1, -1, -1, -1, 9, 5, -3, -9, -11,
+  -15, -9, -4, 0, 11, 14, 12, 17, 19, 23, 17, 15, 13, -2, -1, 0, 0, 9, 12, 16, 16, 19, -2, -1, 0, 0, 9, 12, 16, 16, 19,
+};
+static const int8 kDrawSword_x[511] = {
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, 11, 10, 6, 2, 0, -4, -10, -13, -15, -8, -6, -5, -3, 8, 12, 10, 14, 15, 3, -2, -7, -11, -14, -11, -9, -7, 3, 5,
+  10, 7, 11, 14, 11, 9, 7, 5, 0, 0, 0, 0, 0, 0, 7, 7, 7, 7, 7, 7, -10, -10, -10, -10, -10, -10, 10, 10, 10, 10, 10, 10,
+  -3, 2, -3, 10, 7, 10, -12, -16, -8, 12, 16, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -4, 12, 8, 0, -2, -2, -2, 10, 10, 9,
+  1, -10, -11, 7, 10, 11, -2, -5, -5, 9, 2, 2, -2, -3, -3, 2, 11, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -3, -7, 8, 3, 7, 0, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 13, 6, 14, 14, 8, -1, -14, -14, -1, 9, -5, 3, 10, 13, -11, -12, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -14, -13, -12, -1, 14, 13, 12, -1, -14, -13, -12, -1, 14, 13, 12, 7, -9, 0, 9,
+  14, 14, 10, 10, 14, 11, 8, 8, 8, 15, 14, 12, 12, 8, 15, 14, 10, 4, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, 4, 4, -7, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -3, -3, 9,
+  12, 8, 10, 3, -13, -10, 5, 13, 13, 13, 16, 11, 2, -11, -16, -9, 0, 8, -9, -11, 12, -7, -1, -1, -1, -1, -1, 11, 9, 7, 6, 3,
+  -1, -5, -11, -14, -8, -7, -6, -5, 5, 8, 12, 10, 14, 3, -2, -8, -13, -16, -20, -15, -12, -7, 5, 10, 8, 13, 16, 20, 15, 12, 7,
+};
+static const int8 kPlayerOam_Rod[3] = {0x2, 0x4, 0x4};
+static const uint16 kSwordTiledata[228] = {
+  0x2a05, 0x2a06, 0xffff,
+  0x6a06, 0x6a05, 0xffff,
+  0xaa05, 0xaa06, 0xffff,
+  0x2a05, 0x2a06, 0xffff,
+  0xea06, 0xea05, 0xffff,
+  0x6a06, 0x6a05, 0xffff,
+  0x2a05, 0xffff, 0x2a15,
+  0xaa15, 0xffff, 0xaa05,
+  0x2a05, 0xffff, 0x2a15,
+  0xaa15, 0xffff, 0xaa05,
+  0x6a05, 0xffff, 0x6a15,
+  0xea15, 0xffff, 0xea05,
+  0x2a05, 0xffff, 0xffff,
+  0xaa05, 0xffff, 0xffff,
+  0x6a05, 0xffff, 0xffff,
+  0xea05, 0xffff, 0xffff,
+  0x2a05, 0xffff, 0xffff,
+  0xaa05, 0xffff, 0xffff,
+  0x6a05, 0xffff, 0xffff,
+  0xea05, 0xffff, 0xffff,
+  0x2a05, 0xffff, 0xffff,
+  0xaa05, 0xffff, 0xffff,
+  0x6a05, 0xffff, 0xffff,
+  0xea05, 0xffff, 0xffff,
+  0x2a05, 0xffff, 0xffff,
+  0xaa05, 0xffff, 0xffff,
+  0x6a05, 0xffff, 0xffff,
+  0xea05, 0xffff, 0xffff,
+  0xaa15, 0xffff, 0xffff,
+  0x2209, 0xffff, 0x2219,
+  0x2209, 0xffff, 0x2219,
+  0x221a, 0xffff, 0x2219,
+  0xa219, 0xffff, 0xa209,
+  0x2209, 0xffff, 0x2219,
+  0x2209, 0xffff, 0xffff,
+  0x2209, 0xffff, 0xffff,
+  0x2219, 0x2209, 0xffff,
+  0x6209, 0xffff, 0xffff,
+  0x6209, 0x6219, 0xffff,
+  0xa209, 0xe209, 0xffff,
+  0x2209, 0x6209, 0xffff,
+  0x6209, 0xffff, 0xe209,
+  0x2209, 0xffff, 0xa209,
+  0xa209, 0xffff, 0xffff,
+  0x6209, 0xffff, 0xffff,
+  0x2209, 0xffff, 0xffff,
+  0xe209, 0xffff, 0xffff,
+  0x2209, 0xffff, 0xffff,
+  0x2209, 0xffff, 0xffff,
+  0x6209, 0xffff, 0xffff,
+  0x6209, 0xffff, 0xffff,
+  0x221a, 0xffff, 0xffff,
+  0x221a, 0xffff, 0xffff,
+  0x221a, 0xffff, 0xffff,
+  0x221a, 0xffff, 0xffff,
+  0x2209, 0xffff, 0xffff,
+  0x2209, 0xffff, 0xffff,
+  0x2209, 0xffff, 0xffff,
+  0xe209, 0xffff, 0xffff,
+  0x2209, 0xffff, 0xffff,
+  0x2209, 0xffff, 0xffff,
+  0x2209, 0xffff, 0xffff,
+  0x2209, 0xffff, 0xffff,
+  0x2209, 0xffff, 0xffff,
+  0x2209, 0xffff, 0xffff,
+  0x2209, 0xffff, 0xffff,
+  0x2209, 0xffff, 0x2219,
+  0x2209, 0xffff, 0x2219,
+  0x2209, 0xffff, 0x2219,
+  0x6209, 0xffff, 0x6219,
+  0x2209, 0xffff, 0x2219,
+  0x2209, 0xffff, 0xffff,
+  0xa219, 0xa209, 0xffff,
+  0x6209, 0xffff, 0xffff,
+  0xe209, 0xe219, 0xffff,
+  0x2809, 0xffff, 0xffff,
+};
+static const int8 kShieldStuff_x[511] = {
+  5, 5, 5, 5, 5, 5, 5, 5, 5, -4, -4, -4, -4, -4, -4, -4, -4, -4, -8, -8, -8, -8, -8, -8, -8, -8, -8, 8, 8, 8, 8, 8,
+  8, 8, 8, 8, 6, 6, 8, 8, 10, 10, 10, 10, 10, -5, -5, -7, -7, -10, -10, -10, -10, -10, 1, 1, 1, 1, 0, 0, 0, 0, 0, -1,
+  -1, -1, -1, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, -9, -9, -9, -9, -9, -9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  10, 10, 10, -10, -10, -10, 0, -1, 0, 0, 1, 0, -4, -1, -1, -1, -1, -1, -1, -1, -1, -1, 8, -4, 2, -3, 9, 9, 9, -10, -10, -10,
+  0, 0, 0, 0, 0, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 5, 9, -4, -10, 0, 0, 8, 0, 5, 5, 5, 5, 5, 5,
+  -4, -4, -4, -4, -4, -4, -8, -8, -8, -8, -8, -8, 8, 8, 8, 8, 8, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -4, -8, 5, 8,
+  -4, -4, -4, -4, -5, -5, -5, -5, -5, -10, -10, -10, -10, -10, -5, -5, -7, -4, -4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 9, 9, 9, -10, -10, -10, -1, -1,
+  -1, -1, -1, -1, -6, -1, -1, -1, 10, -10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 10, 10, 10, 10, 10,
+  10, 10, 10, 10, -9, -9, -9, -9, -10, -10, -10, -10, -10, 1, 1, 1, 2, 2, 2, 1, 2, 2, -1, -1, -1, -2, -2, -2, -1, -2, -2,
+};
+static const int8 kShieldStuff_y[511] = {
+  5, 5, 4, 3, 5, 5, 4, 3, 5, 9, 10, 9, 7, 8, 10, 9, 7, 8, 5, 5, 4, 3, 4, 5, 4, 3, 4, 5, 5, 4, 3, 4,
+  5, 4, 3, 4, 12, 12, 8, 8, 6, 6, 6, 6, 6, 1, 1, 3, 3, 7, 7, 7, 7, 7, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+  5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 7, 5, 6, 7, 6, 7, 8, 6, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  7, 5, 7, 7, 8, 7, 5, 5, 5, 5, 5, 5, 16, -1, -1, -1, -1, -1, -1, -1, -1, -1, 5, 8, 7, 7, 6, 5, 5, 7, 7, 7,
+  5, 5, 5, 5, 5, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 6, 6, 11, 7, 4, 8, 4, 8, 4, 5, 6, 4, 5, 6,
+  10, 11, 12, 10, 11, 12, 5, 6, 7, 5, 6, 7, 5, 6, 7, 5, 6, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 10, 5, 4, 5,
+  10, 10, 10, 10, 10, 10, 10, 10, 10, 7, 7, 7, 7, 7, 10, 10, 1, 10, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 5, 5, 5, 7, 7, 7, -1, -1,
+  -1, -1, -1, -1, 9, -1, -1, -1, 5, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 8, 8, 6, 6, 4,
+  2, 5, 6, 6, 1, 1, 4, 4, 6, 8, 6, 6, 6, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+};
+static const uint8 kShieldStuff_oam_index_ptrs_1[12] = {36, 20, 36, 8, 32, 36, 20, 36, 36, 36, 16, 28};
+static const uint8 kShieldStuff_oam_index_ptrs_0[12] = {28, 0, 28, 0, 24, 28, 12, 28, 36, 28, 8, 8};
+static const uint16 kShieldStuff_OamData[54] = {
+  0x2a07, 0xffff, 0xffff,
+  0x2a07, 0xffff, 0xffff,
+  0x2a07, 0xffff, 0xffff,
+  0x6a07, 0xffff, 0xffff,
+  0x2a07, 0xffff, 0xffff,
+  0x6a07, 0xffff, 0xffff,
+  0x2a07, 0xffff, 0xffff,
+  0x6a07, 0xffff, 0xffff,
+  0x2809, 0xffff, 0x2819,
+  0x2809, 0xffff, 0x2819,
+  0x281a, 0xffff, 0x2819,
+  0xa819, 0xffff, 0xa809,
+  0x2809, 0xffff, 0x2819,
+  0x2809, 0xffff, 0xffff,
+  0x2809, 0xffff, 0xffff,
+  0x2819, 0x2809, 0xffff,
+  0x6809, 0xffff, 0xffff,
+  0x6809, 0x6819, 0xffff,
+};
+static const uint8 kLinkBody_oam_index_0[12] = {20, 28, 8, 16, 0, 20, 24, 0, 16, 4, 16, 28};
+static const uint8 kLinkBody_oam_index_1[12] = {28, 36, 16, 24, 8, 28, 36, 8, 16, 12, 24, 36};
+static const uint16 kLinkDmaGraphicsIndices[511] = {
+  0, 174, 175, 176, 177, 178, 179, 180, 181, 5, 182, 183, 184, 185, 182, 186, 187, 188, 10, 10, 189, 190, 191, 192, 193, 194, 195, 13, 13, 196, 197, 198,
+  199, 200, 201, 202, 16, 16, 17, 17, 18, 18, 19, 19, 19, 20, 20, 21, 21, 22, 22, 23, 23, 23, 24, 24, 25, 25, 26, 26, 27, 27, 27, 28,
+  28, 29, 29, 30, 30, 31, 31, 31, 32, 33, 34, 32, 35, 36, 37, 38, 39, 37, 40, 41, 42, 43, 44, 42, 43, 44, 45, 46, 47, 45, 46, 47,
+  49, 48, 50, 52, 51, 52, 54, 53, 55, 57, 56, 58, 59, 60, 61, 62, 62, 62, 0, 13, 5, 10, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72,
+  73, 74, 75, 76, 77, 78, 0, 33, 116, 5, 117, 118, 42, 26, 119, 45, 30, 120, 163, 164, 165, 166, 167, 26, 168, 30, 0, 206, 207, 0, 162, 36,
+  5, 208, 209, 5, 210, 211, 10, 212, 213, 10, 212, 213, 13, 214, 215, 13, 214, 215, 125, 126, 127, 128, 83, 84, 85, 86, 87, 88, 89, 90, 91, 89,
+  92, 93, 94, 95, 96, 94, 97, 98, 99, 100, 101, 99, 100, 101, 102, 103, 104, 102, 103, 104, 32, 33, 34, 32, 35, 36, 37, 38, 39, 37, 40, 41,
+  42, 43, 44, 42, 43, 44, 45, 46, 47, 45, 46, 47, 105, 106, 107, 107, 108, 108, 109, 109, 13, 13, 110, 111, 112, 113, 114, 115, 216, 217, 217, 218,
+  219, 219, 220, 221, 221, 222, 223, 223, 142, 143, 144, 145, 146, 147, 148, 149, 152, 150, 151, 150, 155, 153, 154, 153, 158, 156, 157, 156, 161, 159, 160, 159,
+  150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 171, 171, 172, 172, 169, 169, 170, 170, 171, 171, 172, 172, 169, 169, 170, 170, 37, 42, 32, 45,
+  107, 173, 173, 173, 107, 203, 203, 203, 203, 204, 204, 204, 166, 166, 107, 203, 94, 205, 205, 224, 225, 226, 224, 227, 228, 229, 230, 231, 229, 232, 233, 234,
+  235, 236, 234, 235, 236, 237, 238, 239, 237, 238, 239, 257, 279, 279, 279, 279, 240, 241, 255, 94, 219, 255, 257, 279, 279, 279, 260, 280, 280, 280, 263, 281,
+  281, 281, 266, 282, 282, 282, 245, 246, 247, 242, 243, 244, 251, 252, 253, 248, 249, 250, 5, 10, 0, 13, 272, 273, 0, 33, 116, 5, 117, 118, 42, 26,
+  119, 45, 30, 120, 274, 275, 276, 277, 18, 22, 26, 30, 283, 284, 283, 285, 286, 287, 286, 288, 289, 290, 289, 290, 291, 292, 291, 292, 111, 293, 294, 106,
+  203, 72, 113, 99, 26, 295, 102, 30, 105, 203, 107, 10, 10, 109, 109, 13, 13, 112, 114, 110, 203, 297, 299, 300, 301, 302, 63, 16, 16, 79, 79, 294,
+  80, 294, 19, 19, 20, 20, 21, 21, 81, 82, 81, 23, 23, 24, 24, 25, 130, 131, 132, 133, 134, 134, 28, 28, 29, 121, 122, 123, 124, 129, 129,
+};
+typedef struct LinkSpriteBody {
+  int8 y, x;
+  uint8 tile;
+} LinkSpriteBody;
+static const LinkSpriteBody kLinkSpriteBodys[303] = {
+  { 0,  0, 0x00},
+  { 1,  0, 0x00},
+  { 2,  0, 0x00},
+  { 1,  0, 0x04},
+  { 2,  0, 0x04},
+  { 0,  0, 0x00},
+  { 1,  0, 0x00},
+  { 2,  0, 0x00},
+  { 1,  0, 0x04},
+  { 2,  0, 0x04},
+  { 0,  1, 0x44},
+  { 1,  1, 0x44},
+  { 2,  2, 0x44},
+  { 0, -1, 0x00},
+  { 1, -1, 0x00},
+  { 2, -2, 0x00},
+  { 0,  0, 0x00},
+  { 0,  0, 0x00},
+  {-1,  0, 0x00},
+  { 0,  0, 0x00},
+  { 0,  0, 0x00},
+  { 1,  0, 0x00},
+  { 1,  0, 0x00},
+  { 1,  0, 0x00},
+  { 1,  1, 0x44},
+  { 1,  1, 0x44},
+  { 1,  0, 0x44},
+  { 1,  1, 0x44},
+  { 1, -1, 0x00},
+  { 1, -1, 0x00},
+  { 1,  0, 0x00},
+  { 1, -1, 0x00},
+  { 0,  0, 0x00},
+  { 1,  0, 0x00},
+  { 2,  0, 0x00},
+  { 1,  0, 0x04},
+  { 2,  0, 0x04},
+  { 0,  0, 0x00},
+  { 1,  0, 0x00},
+  { 2,  0, 0x00},
+  { 1,  0, 0x00},
+  { 2,  0, 0x00},
+  { 0,  1, 0x44},
+  { 1,  1, 0x44},
+  { 2,  1, 0x44},
+  { 0, -1, 0x00},
+  { 1, -1, 0x00},
+  { 2, -1, 0x00},
+  {-1,  0, 0x00},
+  { 0,  0, 0x00},
+  { 0,  0, 0x00},
+  { 2,  0, 0x00},
+  { 1,  0, 0x00},
+  { 2, -1, 0x44},
+  { 1,  1, 0x44},
+  { 1,  1, 0x44},
+  { 2,  1, 0x00},
+  { 1, -1, 0x00},
+  { 1, -1, 0x00},
+  { 0, -8, 0x00},
+  { 4,  0, 0x0f},
+  { 4,  0, 0x0f},
+  { 0,  0, 0xff},
+  { 0,  0, 0x00},
+  { 0,  0, 0x00},
+  { 0,  0, 0x44},
+  { 0,  0, 0x00},
+  { 0,  0, 0x00},
+  {-1,  0, 0x00},
+  {-1,  0, 0x00},
+  { 0,  0, 0x00},
+  { 1,  0, 0x00},
+  { 2,  0, 0x00},
+  { 0,  0, 0x44},
+  { 1,  0, 0x44},
+  { 1,  0, 0x44},
+  { 0,  0, 0x00},
+  { 1,  0, 0x00},
+  { 1,  0, 0x00},
+  {-1,  0, 0x00},
+  {-5,  0, 0x00},
+  { 2,  0, 0x00},
+  { 5,  0, 0x00},
+  {-1,  0, 0x44},
+  { 0,  0, 0x44},
+  { 0,  1, 0x44},
+  {-1,  0, 0x00},
+  { 0,  0, 0x00},
+  { 0, -1, 0x00},
+  { 0,  0, 0x00},
+  { 1,  0, 0x00},
+  { 2,  0, 0x00},
+  { 1,  0, 0x04},
+  { 2,  0, 0x04},
+  { 0,  0, 0x00},
+  { 1,  0, 0x00},
+  { 2,  0, 0x00},
+  { 1,  0, 0x04},
+  { 2,  0, 0x04},
+  { 0,  1, 0x44},
+  { 1,  1, 0x44},
+  { 2,  1, 0x44},
+  { 0, -1, 0x00},
+  { 1, -1, 0x00},
+  { 2, -1, 0x00},
+  { 1,  0, 0x04},
+  { 0,  0, 0x44},
+  { 0,  0, 0x00},
+  { 0,  1, 0x44},
+  { 0,  0, 0x00},
+  { 0,  0, 0x04},
+  { 0,  0, 0x44},
+  { 0,  1, 0x40},
+  { 0,  2, 0x40},
+  { 0, -1, 0x00},
+  { 0, -2, 0x00},
+  { 0,  0, 0x00},
+  { 1,  0, 0x00},
+  { 0,  0, 0x00},
+  { 0,  1, 0x44},
+  { 0, -1, 0x00},
+  { 1,  1, 0x00},
+  { 2,  1, 0x00},
+  { 2,  4, 0x00},
+  { 2,  1, 0x00},
+  { 0,  0, 0x00},
+  { 1,  0, 0x00},
+  { 1,  0, 0x00},
+  { 0,  0, 0x00},
+  { 1,  0, 0x00},
+  { 1, -1, 0x44},
+  { 2, -1, 0x44},
+  { 2, -4, 0x44},
+  { 2, -1, 0x44},
+  { 1,  0, 0x44},
+  { 0,  0, 0x00},
+  { 0,  0, 0x40},
+  { 0,  0, 0x04},
+  { 0,  0, 0x04},
+  { 0,  0, 0x00},
+  { 0,  0, 0x00},
+  { 0,  0, 0x00},
+  { 1,  0, 0x00},
+  { 2,  0, 0x04},
+  { 1,  0, 0x00},
+  { 2,  0, 0x04},
+  { 5,  1, 0x40},
+  { 6,  1, 0x44},
+  { 5, -1, 0x04},
+  { 6, -1, 0x00},
+  { 0,  0, 0x00},
+  { 0,  0, 0x04},
+  { 0,  0, 0x00},
+  { 0,  0, 0x00},
+  { 0,  0, 0x44},
+  { 0,  0, 0x00},
+  {13,  3, 0x44},
+  {12,  5, 0x44},
+  {12,  5, 0x44},
+  {13, -3, 0x00},
+  {12, -5, 0x00},
+  {12, -5, 0x00},
+  { 1,  0, 0x00},
+  { 0,  0, 0x00},
+  { 0,  0, 0x00},
+  { 1,  0, 0x00},
+  { 2,  0, 0x00},
+  { 0,  0, 0x44},
+  { 0,  0, 0x00},
+  { 0,  0, 0x00},
+  { 0,  0, 0x00},
+  { 0,  0, 0x44},
+  { 0,  0, 0x44},
+  {-1,  0, 0x04},
+  { 0,  0, 0x00},
+  {-1,  0, 0x00},
+  {-2,  0, 0x00},
+  { 0,  0, 0x00},
+  { 0,  0, 0x00},
+  {-1,  0, 0x00},
+  {-2,  0, 0x00},
+  { 0,  0, 0x00},
+  { 0,  0, 0x04},
+  {-1,  0, 0x00},
+  {-2,  0, 0x00},
+  { 0,  0, 0x00},
+  {-1,  0, 0x04},
+  {-2,  0, 0x04},
+  { 0,  0, 0x04},
+  {-1,  1, 0x44},
+  {-1,  0, 0x44},
+  { 0,  1, 0x44},
+  { 0,  1, 0x44},
+  {-1,  1, 0x44},
+  {-1,  0, 0x44},
+  { 0,  0, 0x44},
+  {-1, -1, 0x00},
+  {-1,  0, 0x00},
+  { 0, -1, 0x00},
+  { 0, -1, 0x00},
+  {-1, -1, 0x00},
+  {-1,  0, 0x00},
+  { 0,  0, 0x00},
+  { 0,  0, 0x04},
+  { 1,  0, 0x00},
+  { 2,  0, 0x00},
+  { 1,  0, 0x00},
+  { 2,  0, 0x00},
+  { 1,  0, 0x00},
+  { 2,  0, 0x00},
+  { 1,  0, 0x04},
+  { 2,  0, 0x04},
+  { 1,  1, 0x44},
+  { 2,  1, 0x44},
+  { 1, -1, 0x00},
+  { 2, -1, 0x00},
+  { 2,  0, 0x00},
+  { 2,  0, 0x00},
+  { 3,  0, 0x00},
+  { 3,  0, 0x00},
+  { 2, -2, 0x44},
+  { 2,  1, 0x44},
+  { 2,  2, 0x00},
+  { 2, -1, 0x00},
+  { 0,  0, 0x00},
+  { 1,  0, 0x00},
+  { 2,  0, 0x00},
+  { 1,  0, 0x04},
+  { 2,  0, 0x04},
+  { 2,  0, 0x00},
+  { 3,  0, 0x00},
+  { 4,  0, 0x00},
+  { 3,  0, 0x04},
+  { 4,  0, 0x04},
+  { 0,  0, 0x44},
+  { 1,  0, 0x44},
+  { 2,  0, 0x44},
+  { 0,  0, 0x00},
+  { 1,  0, 0x00},
+  { 2,  0, 0x00},
+  { 3,  0, 0x00},
+  { 2,  0, 0x00},
+  {-1,  0, 0x00},
+  { 0,  0, 0x00},
+  { 1,  0, 0x00},
+  {-1,  0, 0x00},
+  { 0,  0, 0x00},
+  { 1,  0, 0x00},
+  {-1,  0, 0x44},
+  { 0,  0, 0x44},
+  { 1,  0, 0x44},
+  {-1,  0, 0x44},
+  { 0,  0, 0x44},
+  { 1,  0, 0x44},
+  { 0,  0, 0x00},
+  { 1,  0, 0x00},
+  { 2,  0, 0x00},
+  { 1,  0, 0x00},
+  { 2,  0, 0x00},
+  { 0,  0, 0x00},
+  { 3,  0, 0x00},
+  { 4,  0, 0x00},
+  { 2,  0, 0x00},
+  { 0, -1, 0x44},
+  { 1,  1, 0x44},
+  { 0,  1, 0x44},
+  { 0,  1, 0x00},
+  { 1,  1, 0x00},
+  { 0, -1, 0x00},
+  { 3,  0, 0x00},
+  { 2,  0, 0x04},
+  { 3,  0, 0x04},
+  { 0,  2, 0x00},
+  { 8,  8, 0x00},
+  { 0,  0, 0x00},
+  { 0,  0, 0x00},
+  {-1,  0, 0x0f},
+  { 1,  0, 0x00},
+  { 0,  0, 0x04},
+  { 0,  0, 0x00},
+  { 2,  0, 0x00},
+  { 1,  4, 0x44},
+  { 1, -4, 0x00},
+  { 0,  0, 0x00},
+  { 1,  0, 0x00},
+  { 1,  0, 0x04},
+  { 0,  0, 0x00},
+  { 1,  0, 0x00},
+  { 1,  0, 0x04},
+  { 0,  1, 0x44},
+  { 1,  1, 0x44},
+  { 0, -1, 0x00},
+  { 1, -1, 0x00},
+  { 0,  0, 0x44},
+  {-2,  0, 0x00},
+  { 0, -2, 0x04},
+  { 0,  0, 0x00},
+  { 0,  1, 0x00},
+  { 0,  0, 0x04},
+  {12,  0, 0x08},
+  {14,  0, 0x80},
+  {12,  0, 0x00},
+  {11,  0, 0x00},
+};
+static const uint8 kSwordStuff_oam_index_ptrs_1[12] = {0, 0, 24, 32, 24, 0, 0, 24, 24, 24, 32, 0};
+static const uint8 kSwordStuff_oam_index_ptrs_0[12] = {8, 16, 16, 24, 16, 0, 0, 16, 24, 16, 24, 16};
+static const int8 kPlayerOam_DrawOam_Throwing_State[16] = {-1, -1, -1, -1, 0, -1, -1, -1, 0, 0, -1, -1, 0, 0, 0, -1};
+static const int8 kPlayerOam_DrawOam_Throwing_X[16] = {-1, -1, -1, -1, 8, -1, -1, -1, 8, 5, -1, -1, 8, 5, 2, -1};
+static const int8 kPlayerOam_DrawOam_Throwing_Y[16] = {-1, -1, -1, -1, 14, -1, -1, -1, 14, 22, -1, -1, 14, 22, 30, -1};
+static const uint8 kShieldTypeToOffs[4] = {4, 4, 8, 8};
+static const int8 kOffsToShadowGivenDir_X[12] = {0, 0, -1, 1, 0, 0, 0, 0, 0, 0, 0, 0};
+static const int8 kOffsToShadowGivenDir_Y[12] = {16, 16, 17, 17, 16, 16, 16, 16, 18, 18, 18, 18};
+static const uint8 kShadow_oam_indexes_1[12] = {12, 12, 0, 0, 0, 12, 12, 0, 0, 0, 0, 12};
+static const uint8 kShadow_oam_indexes_0[12] = {40, 40, 40, 40, 40, 40, 40, 40, 0, 40, 40, 40};
+static const uint16 kLinkShadows_Chardata[22] = {0x286c, 0x686c, 0x2828, 0x6828, 0x2838, 0xffff, 0x286e, 0x686e, 0x287e, 0x687e, 0x24d8, 0x64d8, 0x24d9, 0x64d9, 0x24da, 0x64da, 0x22c8, 0x62c8, 0x22c9, 0x62c9, 0x22ca, 0x62ca};
+static const uint8 kPlayerOam_DrawOam_2X[3] = {0, 0, 4};
+bool PlayerOam_WantInvokeSword() {
+  if (link_player_handler_state != kPlayerState_Ether &&
+      link_player_handler_state != kPlayerState_Bombos &&
+      link_player_handler_state != kPlayerState_Quake &&
+      link_player_handler_state != kPlayerState_SpinAttacking &&
+      link_player_handler_state != kPlayerState_SpinAttackMotion &&
+      !link_state_bits && !link_force_hold_sword_up && !link_electrocute_on_touch) {
+    if (link_item_in_hand & 0x40)
+      return false;
+    if (link_position_mode & 0x3d || link_item_in_hand & 0x93)
+      return true;
+    if (!(button_mask_b_y & 0x80))
+      return false;
+  }
+  return ((link_sword_type + 1) & 0xfe) != 0;
+}
+
+void CalculateSwordHitBox() {  // 879e63
+  if (link_sword_type == 0 || link_sword_type == 0xff)
+    return;
+  if (link_sword_type >= 2 && button_b_frames < 9) {
+    int i = button_b_frames + ((link_direction_facing>>1) * 9);
+    if ((uint8)kSwordTipSomething[i] != 0xff) {
+      player_oam_y_offset = kSwordOamYOffs_Good[i];
+      player_oam_x_offset = kSwordOamXOffs_Good[i];
+      return;
+    }
+  }
+  uint8 offs = button_b_frames;
+  if (offs == 9)
+    return;
+  uint8 y = 39;
+  if (offs >= 10) {
+    offs -= 10;
+    y = 3;
+  }
+  int i = kPlayerOamOtherOffs[(link_direction_facing >> 1) * 40 + y] + offs;
+  player_oam_y_offset = kSwordOamYOffs[i];
+  player_oam_x_offset = kSwordOamXOffs[i];
+}
+
+void LinkOam_Main() {  // 8da18e
+  uint16 y_coord_backup = link_y_coord;
+
+  if (submodule_index == 18 || submodule_index == 19) {
+    int t = submodule_index == 18 ? 0 : 12;
+    t += which_staircase_index & 4 ? 6 : 0;
+    t += (link_animation_steps < 6) ? link_animation_steps : 0;
+    link_y_coord += kPlayerOam_StairsOffsY[t];
+  }
+
+  uint8 xcoord = link_x_coord - BG2HOFS_copy2;
+  uint8 ycoord = link_y_coord - BG2VOFS_copy2;
+  player_oam_x_offset = player_oam_y_offset = 0x80;
+  uint8 scratch_0_var = (draw_water_ripples_or_grass != 0);
+  oam_priority_value = kPlayerOam_FloorOamPrio[link_is_on_lower_level];
+  sort_sprites_offset_into_oam_buffer = kPlayerOam_SortSpritesOffs[(uint8)sort_sprites_setting];
+
+  uint8 yt, rt;
+
+  if (link_player_handler_state == kPlayerState_AsleepInBed && link_pose_during_opening != 2) {
+    yt = 0x1f, rt = link_pose_during_opening;
+    goto continue_after_set;
+  }
+  if (link_force_hold_sword_up) {
+    yt = 0x24, rt = 0;
+    link_direction_facing_mirror = link_direction_facing;
+    goto continue_after_set;
+  }
+  if (link_is_bunny_mirror) {
+    yt = 0x21, rt = link_animation_steps & 3;
+    link_direction_facing_mirror = link_direction_facing;
+    goto continue_after_set;
+  }
+  yt = draw_water_ripples_or_grass ? 10 : 0;
+
+  if (submodule_index == 14 && main_module_index != 18 && ((yt = 10), link_actual_vel_x)) {
+    if (link_direction_facing != 4 && link_direction_facing != 6) {
+      rt = kPlayerOam_Tab1[link_animation_steps];
+      yt = which_staircase_index & 4 ? 0x1a : 0x19;
+    } else {
+      rt = link_animation_steps;
+    }
+  } else {
+    if (link_grabbing_wall & 3) {
+      yt = 0x18, rt = some_animation_timer_steps;
+    } else {
+      if (bitmask_of_dragstate & 0xd) {
+        yt = 0x16;
+        if (link_animation_steps >= 5)
+          link_animation_steps = 0;
+      }
+      rt = link_animation_steps;
+    }
+  }
+  link_direction_facing_mirror = link_direction_facing;
+  if (link_is_in_deep_water)
+    oam_priority_value = 0x2000;
+
+  if (link_player_handler_state == kPlayerState_Swimming) {
+    yt = 0x11, rt &= 1;
+    if (submodule_index == 0 && (joypad1H_last & 0xf) != 0 || (swimcoll_var7[0] | swimcoll_var7[1]))
+      yt = 0x13, rt = byte_7E02CC;
+    if (link_maybe_swim_faster)
+      yt = 0x12, rt = link_maybe_swim_faster - 1;
+    goto continue_after_set;
+  }
+  if (link_pose_for_item) {
+    rt = 0, yt = (link_pose_for_item != 2) ? 0x1d : 0x1e;
+    goto continue_after_set;
+  }
+  if (player_unk1 & 1) {
+    yt = 0x1b, rt = some_animation_timer_steps;
+    goto continue_after_set;
+  }
+
+  if (link_auxiliary_state != 0) {
+    if (link_auxiliary_state == 4) {
+      yt = 0x13, rt = kSwimmingTab1[(frame_counter & 0x18) >> 3];
+      goto continue_after_set;
+    } else if (link_auxiliary_state == 1) {
+      if (link_player_handler_state == kPlayerState_TurtleRock) {
+        if (!byte_7E034E)
+          oam_priority_value = 0x3000;
+        goto link_state_is_empty;
+      } else if (link_player_handler_state != kPlayerState_Hookshot && !link_cape_mode) {
+        if (link_electrocute_on_touch)
+          yt = 0x14, rt = player_handler_timer & 3;
+        else
+          yt = 5, rt = 0;
+        goto continue_after_set;
+      }
+    }
+  }
+
+  if (player_near_pit_state != 0 && player_near_pit_state != 1) {
+    if (player_near_pit_state == 3)
+      sort_sprites_offset_into_oam_buffer = 0;
+    yt = 4, rt = link_this_controls_sprite_oam;
+    if (rt >= 6)
+      oam_priority_value |= 0x3000;
+    goto continue_after_set;
+  }
+
+  if (link_state_bits != 0) {
+    uint8 bit = FindMostSignificantBit(link_state_bits);
+    if (bit < 6)
+      link_direction_facing_mirror = 2;
+    yt = kPlayerOam_Tab4[bit];
+    if (yt >= 0xd) {
+      if (link_picking_throw_state & 2)
+        yt += 1;
+
+      if (link_picking_throw_state & 1)
+        yt = 0x10;
+      else if (link_state_bits & 0x80)
+        goto continue_after_set;
+    }
+    rt = some_animation_timer_steps;
+    goto continue_after_set;
+  }
+link_state_is_empty:
+  if (link_unk_master_sword != 0) {
+    yt = 0x17, rt = link_unk_master_sword - 1;
+    goto continue_after_set;
+  }
+
+  if (link_item_in_hand != 0) {
+    yt = kPlayerOam_Tab2[FindMostSignificantBit(link_item_in_hand)];
+    rt = player_handler_timer;
+    goto continue_after_set;
+  } else if (link_position_mode != 0) {
+    yt = kPlayerOam_Tab3[FindMostSignificantBit(link_position_mode)];
+    rt = player_handler_timer;
+    goto continue_after_set;
+  }
+
+  if (link_player_handler_state == kPlayerState_Quake || link_player_handler_state == kPlayerState_Ether || link_player_handler_state == kPlayerState_Bombos) {
+    yt = 0x15, rt = state_for_spin_attack;
+    goto continue_after_set;
+  } else if (link_player_handler_state == kPlayerState_SpinAttackMotion || link_player_handler_state == kPlayerState_SpinAttacking) {
+    yt = 0xf, rt = state_for_spin_attack;
+    goto continue_after_set;
+  }
+
+  if (button_mask_b_y & 0x80) {
+    if (button_b_frames == 9) {
+      yt = 2;
+    } else {
+      yt = 0x27, rt = button_b_frames;
+      if (rt >= 9) {
+        yt = 3;
+        rt -= 10;
+      }
+    }
+  }
+continue_after_set:
+  value_computed_for_player_oam = yt;
+  if (yt != 5)
+    oam_priority_value_2 = oam_priority_value;
+
+  BYTE(index_of_interacting_tile) = rt;
+
+  int dir = link_direction_facing >> 1;
+
+  int r2 = kPlayerOamOtherOffs[dir * 40 + yt] + rt;
+  int r4loc = kPlayerOamSpriteLocs[r2];
+
+  link_palette_bits_of_oam = palette_swap_flag ? 0 : 0xe00;
+  link_dma_var1 = link_dma_var2 = 0;
+
+  int xt = FindInByteArray(kPlayerOam_Tab5, yt, 7);
+  if (xt >= 0) {
+    int j = kPlayerOam_Tab6[xt + dir * 7] + rt;
+    scratch_1 = j;
+    {
+      uint8 bank1 = kPlayerOam_Spr1Bank[j];
+      if (bank1 != 0xff) {
+        link_dma_var1 = bank1 * 2;
+        int oam_pos = ((scratch_0_var ? kPlayerOam_Tab19B : kPlayerOam_Tab19A)[r4loc] + sort_sprites_offset_into_oam_buffer) >> 2;
+        uint8 zt = ((int16)link_z_coord >= 0 || BYTE(link_z_coord) < 0xf0) ? BYTE(link_z_coord) : 0;
+        oam_buf[oam_pos].y = kPlayerOam_Spr1Y[j] + ycoord - zt;
+        oam_buf[oam_pos].x = kPlayerOam_Spr1X[j] + xcoord;
+        uint16 q = WORD(kPlayerOam_Prio[bank1 >> 1]);
+        q = (bank1 & 1) ? q << 4 : q;
+        WORD(oam_buf[oam_pos].charnum) = (q & 0xc000) | oam_priority_value | link_palette_bits_of_oam | 4;
+        bytewise_extended_oam[oam_pos] = 0;
+      }
+    }
+
+    uint8 bank2 = kPlayerOam_Spr2Bank[j];
+    if (bank2 != 0xff) {
+      link_dma_var2 = bank2 * 2;
+      int oam_pos = ((scratch_0_var ? kPlayerOam_Tab20B : kPlayerOam_Tab20A)[r4loc] + sort_sprites_offset_into_oam_buffer) >> 2;
+      uint8 zt = ((int16)link_z_coord >= 0 || BYTE(link_z_coord) < 0xf0) ? BYTE(link_z_coord) : 0;
+      oam_buf[oam_pos].y = kPlayerOam_Spr2Y[j] + ycoord - zt;
+      oam_buf[oam_pos].x = kPlayerOam_Spr2X[j] + xcoord;
+      uint16 q = WORD(kPlayerOam_Prio[bank2 >> 1]);
+      q = (bank2 & 1) ? q << 4 : q;
+      WORD(oam_buf[oam_pos].charnum) = (q & 0xc000) | oam_priority_value | link_palette_bits_of_oam | 0x14;
+      bytewise_extended_oam[oam_pos] = 0;
+    }
+  }
+  SwordResult sr;
+
+  if (link_picking_throw_state & 4) {
+    LinkOam_UnusedWeaponSettings(r4loc, xcoord, ycoord);
+  } else if (PlayerOam_WantInvokeSword() && !LinkOam_SetWeaponVRAMOffsets(r2, &sr)) {
+    uint8 zcoord = ((int16)link_z_coord >= 0 || BYTE(link_z_coord) < 0xf0) ? BYTE(link_z_coord) : 0;
+    uint8 oam_y = kDrawSword_y[r2] + ycoord - zcoord;
+    uint8 oam_x = kDrawSword_x[r2] + xcoord;
+
+    if ((link_item_in_hand & 2) ? (player_handler_timer == 2 && link_delay_timer_spin_attack == 15) : ((link_item_in_hand & 5) == 0)) {
+      player_oam_y_offset = kSwordOamYOffs[r2];
+      player_oam_x_offset = kSwordOamXOffs[r2];
+    }
+    uint16 oam_pal = 0;
+    if (link_item_in_hand & 5) {
+      assert(link_state_bits == 0);
+      oam_pal = kPlayerOam_Rod[eq_selected_rod - 1] << 8;
+    }
+    if ((link_position_mode & 8) && current_item_y == 13)
+      oam_pal = 0x400;  // cane of byrna
+
+    int oam_pos = ((scratch_0_var ? kSwordStuff_oam_index_ptrs_1 : kSwordStuff_oam_index_ptrs_0)[r4loc] + sort_sprites_offset_into_oam_buffer)>>2;
+    oam_pos = LinkOam_CalculateSwordSparklePosition(oam_pos, xcoord, ycoord);
+
+    int j = sr.r6 * 3;
+    for (int i = 0; i != 3; i++, j++) {
+      uint16 td = kSwordTiledata[j];
+      if (td != 0xffff) {
+        td = (td & ~0x3000) | oam_priority_value;
+        if ((td & 0xe00) != 0x200 && !link_palette_bits_of_oam)
+          td = (td & ~0xe00) | 0x600;
+        if (oam_pal)
+          td = (td & ~0xe00) | oam_pal;
+        WORD(oam_buf[oam_pos].charnum) = td;
+        oam_buf[oam_pos].x = oam_x;
+        oam_buf[oam_pos].y = oam_y;
+        uint16 xt = (uint8)xcoord - oam_x;
+        if ((int16)xt < 0) xt = -xt;
+        bytewise_extended_oam[oam_pos] = sr.r12 | (xt >= 0x80);
+        oam_pos++;
+      }
+      oam_x += 8;
+      if (i == 1)
+        oam_x -= 16, oam_y += 8;
+    }
+  }
+
+  //SwordStuff_fail
+  if (link_shield_type && sram_progress_indicator && !LinkOam_SetEquipmentVRAMOffsets(r2, &sr)) {
+    uint8 zcoord = ((int16)link_z_coord >= 0 || BYTE(link_z_coord) < 0xf0) ? BYTE(link_z_coord) : 0;
+    uint8 oam_y = kShieldStuff_y[r2] + ycoord - 1 - zcoord;
+    uint8 oam_x = kShieldStuff_x[r2] + xcoord;
+
+    LinkOam_CalculateXOffsetRelativeLink(kShieldStuff_x[r2]);
+
+    uint16 oam_pal = (link_palette_bits_of_oam >> 8) ? 0xa00 : 0x600;
+
+    int oam_pos = ((scratch_0_var ? kShieldStuff_oam_index_ptrs_1 : kShieldStuff_oam_index_ptrs_0)[r4loc] + sort_sprites_offset_into_oam_buffer)>>2;
+
+    int j = sr.r6 * 3;
+    for (int i = 0; i != 3; i++, j++) {
+      uint16 td = kShieldStuff_OamData[j];
+      if (td == 0xffff)
+        continue;
+      td = (td & 0xc1ff) | oam_pal | oam_priority_value;
+      WORD(oam_buf[oam_pos].charnum) = td;
+      WORD(oam_buf[oam_pos].x) = oam_x | oam_y << 8;
+      bytewise_extended_oam[oam_pos] = sr.r12 | bit9_of_xcoord;
+      oam_x += 8;
+      if (i == 1)
+        oam_x -= 16, oam_y += 8;
+    }
+  }
+
+  if (link_visibility_status != 12 && link_player_handler_state != kPlayerState_AsleepInBed) {
+    if (value_computed_for_player_oam != 5 && draw_water_ripples_or_grass) {
+      LinkOam_DrawFootObject(r4loc, xcoord, ycoord);
+    } else if (link_auxiliary_state != 4 && link_player_handler_state != kPlayerState_Swimming) {
+      if (player_near_pit_state != 0 && player_near_pit_state != 1) {
+        if (link_this_controls_sprite_oam >= 6) {
+          LinkOam_DrawDungeonFallShadow(r4loc, xcoord);
+          r4loc = 2; // wtf
+        }
+      } else {
+        // draw shadow
+        int shadow_idx = (link_auxiliary_state != 0) && (link_auxiliary_state != 1 || !link_cape_mode);
+        uint16 oam_y = link_y_coord - BG2VOFS_copy2 + kOffsToShadowGivenDir_Y[link_direction_facing_mirror >> 1];
+        if (oam_y < 256) {
+          uint8 oam_x = xcoord + kOffsToShadowGivenDir_X[link_direction_facing_mirror >> 1];
+          int oam_pos = ((scratch_0_var ? kShadow_oam_indexes_1 : kShadow_oam_indexes_0)[r4loc] + sort_sprites_offset_into_oam_buffer)>>2;
+
+          uint16 td = kLinkShadows_Chardata[shadow_idx*2] & ~0x3000 | oam_priority_value_2;
+          if (!link_palette_bits_of_oam)
+            td = td & ~0xe00 | 0x600;
+          WORD(oam_buf[oam_pos+0].charnum) = td;
+          WORD(oam_buf[oam_pos+1].charnum) = td & ~0xC000 | 0x4000;
+          WORD(oam_buf[oam_pos+0].x) = (uint8)oam_x | oam_y << 8;
+          WORD(oam_buf[oam_pos+1].x) = (uint8)(oam_x + 8) | oam_y << 8;
+          bytewise_extended_oam[oam_pos+0] = 0;
+          bytewise_extended_oam[oam_pos+1] = 0;
+        }
+      }
+    }
+  }
+
+  {
+    int oam_pos = ((scratch_0_var ? kLinkBody_oam_index_1 : kLinkBody_oam_index_0)[r4loc] + sort_sprites_offset_into_oam_buffer)>>2;
+
+    int j = kLinkDmaGraphicsIndices[r2];
+    link_dma_graphics_index = j * 2;
+
+    if (link_visibility_status != 12) {
+      uint8 zcoord = ((int16)link_z_coord >= 0 || BYTE(link_z_coord) < 0xf0) ? BYTE(link_z_coord) : 0;
+
+      const LinkSpriteBody *sp = &kLinkSpriteBodys[j];
+
+      uint8 oam_y = ycoord + sp->y - zcoord;
+      uint8 oam_x = xcoord + sp->x;
+      uint16 td = sp->tile << 8;
+
+      if ((td & 0xf000) != 0xf000) {
+        WORD(oam_buf[oam_pos].charnum) = td & 0xf000 | oam_priority_value | link_palette_bits_of_oam;
+        WORD(oam_buf[oam_pos].x) = oam_x | oam_y << 8;
+        bytewise_extended_oam[oam_pos] = 2 + (oam_x >= 0xf8);
+      }
+
+      if ((td << 4 & 0xf000) != 0xf000) {
+        WORD(oam_buf[oam_pos+1].charnum) = td << 4 & 0xf000 | oam_priority_value | link_palette_bits_of_oam | 2;
+        WORD(oam_buf[oam_pos+1].x) = (uint8)(xcoord) | (ycoord - zcoord + 8) << 8;
+        bytewise_extended_oam[oam_pos+1] = 2;
+      }
+    }
+  }
+
+  uint16 t;
+  bool hide_shadow = true;
+  if (is_standing_in_doorway && ((t = link_x_coord - BG2HOFS_copy2) < 4 || t >= 252 || (t = link_y_coord - BG2VOFS_copy2) < 4 || t >= 224) ||
+      (hide_shadow = false,
+      submodule_index == 0 && countdown_for_blink && --countdown_for_blink >= 4 && (countdown_for_blink & 1) == 0 ||
+      link_visibility_status == 12 ||
+      link_cape_mode != 0)) {
+    int shadow_oam_pos = (!hide_shadow && link_visibility_status != 12) ?
+        (scratch_0_var ? kShadow_oam_indexes_1 : kShadow_oam_indexes_0)[r4loc] >> 2 : -10;
+
+    // This appears to hide link by setting the extended bits of the oam to hide them from the screen.
+    // It doesn't really play well with the widescreen modes, so change how it's done.
+    if (enhanced_features0 & kFeatures0_WidescreenVisualFixes) {
+      OamEnt *oam = &oam_buf[sort_sprites_offset_into_oam_buffer >> 2];
+      for (int i = 0; i < 12; i++) {
+        if (i < shadow_oam_pos || i > shadow_oam_pos + 1)
+          oam[i].y = 0xf0;
+      }
+    } else {
+      uint8 *p = &bytewise_extended_oam[sort_sprites_offset_into_oam_buffer >> 2];
+      WORD(p[0]) = 0x101;
+      WORD(p[2]) = 0x101;
+      WORD(p[4]) = 0x101;
+      WORD(p[6]) = 0x101;
+      WORD(p[8]) = 0x101;
+      WORD(p[10]) = 0x101;
+      // Clear the bit again for the shadow oam so it's not hidden?
+      if (shadow_oam_pos >= 0)
+        WORD(p[shadow_oam_pos]) = 0;
+    }
+  }
+
+  if (submodule_index == 18 || submodule_index == 19)
+    link_y_coord = y_coord_backup;
+}
+
+uint8 FindMostSignificantBit(uint8 v) {  // 8daac3
+  int i = 7;
+  while (!(v & 0x80) && --i >= 0)
+    v <<= 1;
+  return (uint8)i;
+}
+
+bool LinkOam_SetWeaponVRAMOffsets(int r2, SwordResult *sr) {  // 8dab6e
+  uint8 j = kPlayerOam_Main_SwordStuff_array1[r2];
+  if ((sr->r6 = j) == 0xff)
+    return true;
+  sr->r12 = kPlayerOam_Main_SwordStuff_array2[j];
+  uint8 y = kPlayerOam_Main_SwordStuff_array3[j];
+  if (j < 29) {
+    link_dma_var3 = y;
+  } else {
+    if (link_item_in_hand & 5)
+      y = kPlayerOam_Main_SwordStuff_array4[j - 29];
+    link_dma_var5 = y;
+  }
+  return false;
+}
+
+bool LinkOam_SetEquipmentVRAMOffsets(int r2, SwordResult *sr) {  // 8dabe6
+  uint8 j = kPlayerOam_ShieldStuff_array1[r2];
+  if ((sr->r6 = j) == 0xff)
+    return true;
+
+  uint8 y = kPlayerOam_ShieldStuff_array2[j];
+  if (j >= 8) {
+    if (link_item_in_hand & 5)
+      y = kPlayerOam_ShieldStuff_array3[j - 8];
+    link_dma_var5 = y;
+    sr->r12 = (y & 7) ? 0 : 2;
+  } else {
+    link_dma_var4 = y;
+    sr->r12 = 2;
+  }
+  return false;
+}
+
+int LinkOam_CalculateSwordSparklePosition(int oam_pos, uint8 oam_x, uint8 oam_y) {  // 8dacd5
+  if (link_player_handler_state | link_speed_setting)
+    return oam_pos;
+  if (link_sword_type == 0 || link_sword_type == 1 || link_sword_type == 0xff || !(button_mask_b_y & 0x80) || button_b_frames >= 9)
+    return oam_pos;
+
+  int i = (link_direction_facing >> 1) * 9 + button_b_frames;
+  uint16 td = kSwordTipSomething[i];
+  if (td == 0xffff)
+    return oam_pos;
+  td = td & ~0x3000 | oam_priority_value;
+  if (!link_palette_bits_of_oam)
+    td = td & ~0xe00 | 0x600;
+  WORD(oam_buf[oam_pos].charnum) = td;
+  player_oam_x_offset = kSwordOamXOffs_Good[i];
+  player_oam_y_offset = kSwordOamYOffs_Good[i];
+  oam_x += player_oam_x_offset;
+  oam_y += player_oam_y_offset;
+  oam_buf[oam_pos].x = oam_x;
+  oam_buf[oam_pos].y = oam_y;
+  LinkOam_CalculateXOffsetRelativeLink(player_oam_x_offset);
+  bytewise_extended_oam[oam_pos] = bit9_of_xcoord;
+  return oam_pos + 1;
+}
+
+void LinkOam_UnusedWeaponSettings(int r4loc, uint8 oam_x, uint8 oam_y) {  // 8dadb6
+  int j = link_var30e * 4;
+  int oam_pos = ((draw_water_ripples_or_grass != 0 ? kSwordStuff_oam_index_ptrs_1 : kSwordStuff_oam_index_ptrs_0)[r4loc] + sort_sprites_offset_into_oam_buffer)>>2;
+  OamEnt *oam = &oam_buf[oam_pos];
+  for (int i = 0; i != 4; i++, j++) {
+    uint8 st = kPlayerOam_DrawOam_Throwing_State[j];
+    if (st != 0xff) {
+      WORD(oam->charnum) = 0x2609 & ~0x3000 | oam_priority_value;
+      oam->x = oam_x + kPlayerOam_DrawOam_Throwing_X[j];
+      oam->y = oam_y + kPlayerOam_DrawOam_Throwing_Y[j];
+      bytewise_extended_oam[oam_pos] = 0;
+      oam++, oam_pos++;
+    }
+  }
+}
+
+void LinkOam_DrawDungeonFallShadow(int r4loc, uint8 xcoord) {  // 8dae3b
+  uint8 yd = tiledetect_which_y_pos[0] - 12 - link_y_coord;
+  int yv = yd >= 240 ? 0 :
+           yd >= 96 ? 2 :
+           yd >= 48 ? 1 : 0;
+
+  xcoord += kPlayerOam_DrawOam_2X[yv];
+  uint8 ycoord = tiledetect_which_y_pos[0] - 12 - BG2VOFS_copy2 + 29;
+  int oam_pos = ((draw_water_ripples_or_grass ? kShadow_oam_indexes_1 : kShadow_oam_indexes_0)[r4loc] + sort_sprites_offset_into_oam_buffer)>>2;
+
+  yv *= 2;
+  for (int i = 0; i != 2; i++, oam_pos++, yv++) {
+    uint16 td = kLinkShadows_Chardata[yv];
+    if (td != 0xffff) {
+      WORD(oam_buf[oam_pos].charnum) = td & ~0x3000 | oam_priority_value_2;
+      WORD(oam_buf[oam_pos].x) = xcoord | ycoord << 8;
+    }
+    bytewise_extended_oam[oam_pos] = 0;
+    xcoord += 8;
+  }
+}
+
+void LinkOam_DrawFootObject(int r4loc, uint8 oam_x, uint8 oam_y) {  // 8daed1
+  primary_water_grass_timer = (primary_water_grass_timer + 1) & 0xf;
+  if (primary_water_grass_timer >= 9) {
+    primary_water_grass_timer = 0;
+    secondary_water_grass_timer = (secondary_water_grass_timer + 1) & 3;
+    if (secondary_water_grass_timer == 3)
+      secondary_water_grass_timer = 0;
+  }
+
+  int i = (link_direction_facing_mirror >> 1) + kShieldTypeToOffs[link_shield_type];
+
+  oam_x += kOffsToShadowGivenDir_X[i];
+  oam_y += kOffsToShadowGivenDir_Y[i];
+
+  int oam_pos = (kShadow_oam_indexes_1[r4loc] + sort_sprites_offset_into_oam_buffer)>>2;
+
+  uint8 yv;
+  if (draw_water_ripples_or_grass == 2) {
+    yv = (link_animation_steps >= 3 ? link_animation_steps - 3 : link_animation_steps);
+    ((uint8 *)&overlay_index)[1] = yv * 4;
+    yv = (8 + yv);
+  } else {
+    ((uint8 *)&overlay_index)[1] = secondary_water_grass_timer * 4;
+    yv = (5 + secondary_water_grass_timer);
+  }
+
+  OamEnt *oam = &oam_buf[oam_pos];
+
+  if (yv >= 11) {
+    // OOB read
+    WORD(oam[0].charnum) = 0x00 & ~0x3000 | oam_priority_value_2;
+    WORD(oam[1].charnum) = 0xAE | oam_priority_value_2;
+  } else {
+    WORD(oam[0].charnum) = kLinkShadows_Chardata[yv * 2 + 0] & ~0x3000 | oam_priority_value_2;
+    WORD(oam[1].charnum) = kLinkShadows_Chardata[yv * 2 + 1] | oam_priority_value_2;
+
+  }
+
+
+  oam[0].x = oam_x;
+  oam[1].x = oam_x + 8;
+
+  oam[0].y = oam_y;
+  oam[1].y = oam_y;
+
+  WORD(bytewise_extended_oam[oam_pos]) = 0;
+}
+
+void LinkOam_CalculateXOffsetRelativeLink(uint8 x) {  // 8dafc0
+  bit9_of_xcoord = (link_x_coord + (int8)x - BG2HOFS_copy2) >> 8 & 1;
+}
+
--- /dev/null
+++ b/src/player_oam.h
@@ -1,0 +1,19 @@
+#pragma once
+#include "types.h"
+
+typedef struct SwordResult {
+  uint8 r6;
+  uint8 r12;
+} SwordResult;
+
+bool PlayerOam_WantInvokeSword();
+void CalculateSwordHitBox();
+void LinkOam_Main();
+uint8 FindMostSignificantBit(uint8 v);
+bool LinkOam_SetWeaponVRAMOffsets(int r2, SwordResult *sr);
+bool LinkOam_SetEquipmentVRAMOffsets(int r2, SwordResult *sr);
+int LinkOam_CalculateSwordSparklePosition(int oam_pos, uint8 oam_x, uint8 oam_y);
+void LinkOam_UnusedWeaponSettings(int r4loc, uint8 oam_x, uint8 oam_y);
+void LinkOam_DrawDungeonFallShadow(int r4loc, uint8 xcoord);
+void LinkOam_DrawFootObject(int r4loc, uint8 oam_x, uint8 oam_y);
+void LinkOam_CalculateXOffsetRelativeLink(uint8 x);
--- /dev/null
+++ b/src/poly.c
@@ -1,0 +1,323 @@
+#include "poly.h"
+#include "zelda_rtl.h"
+#include "variables.h"
+
+static const int8 kPolySinCos[320] = {
+  0,   2,   3,   5,   6,   8,   9,  11,  12,  14,  16,  17,  19,  20,  22,  23,
+  24,  26,  27,  29,  30,  32,  33,  34,  36,  37,  38,  39,  41,  42,  43,  44,
+  45,  46,  47,  48,  49,  50,  51,  52,  53,  54,  55,  56,  56,  57,  58,  59,
+  59,  60,  60,  61,  61,  62,  62,  62,  63,  63,  63,  64,  64,  64,  64,  64,
+  64,  64,  64,  64,  64,  64,  63,  63,  63,  62,  62,  62,  61,  61,  60,  60,
+  59,  59,  58,  57,  56,  56,  55,  54,  53,  52,  51,  50,  49,  48,  47,  46,
+  45,  44,  43,  42,  41,  39,  38,  37,  36,  34,  33,  32,  30,  29,  27,  26,
+  24,  23,  22,  20,  19,  17,  16,  14,  12,  11,   9,   8,   6,   5,   3,   2,
+  0,  -2,  -3,  -5,  -6,  -8,  -9, -11, -12, -14, -16, -17, -19, -20, -22, -23,
+  -24, -26, -27, -29, -30, -32, -33, -34, -36, -37, -38, -39, -41, -42, -43, -44,
+  -45, -46, -47, -48, -49, -50, -51, -52, -53, -54, -55, -56, -56, -57, -58, -59,
+  -59, -60, -60, -61, -61, -62, -62, -62, -63, -63, -63, -64, -64, -64, -64, -64,
+  -64, -64, -64, -64, -64, -64, -63, -63, -63, -62, -62, -62, -61, -61, -60, -60,
+  -59, -59, -58, -57, -56, -56, -55, -54, -53, -52, -51, -50, -49, -48, -47, -46,
+  -45, -44, -43, -42, -41, -39, -38, -37, -36, -34, -33, -32, -30, -29, -27, -26,
+  -24, -23, -22, -20, -19, -17, -16, -14, -12, -11,  -9,  -8,  -6,  -5,  -3,  -2,
+  0,   2,   3,   5,   6,   8,   9,  11,  12,  14,  16,  17,  19,  20,  22,  23,
+  24,  26,  27,  29,  30,  32,  33,  34,  36,  37,  38,  39,  41,  42,  43,  44,
+  45,  46,  47,  48,  49,  50,  51,  52,  53,  54,  55,  56,  56,  57,  58,  59,
+  59,  60,  60,  61,  61,  62,  62,  62,  63,  63,  63,  64,  64,  64,  64,  64,
+};
+typedef struct Vertex3 {
+  int8 x, y, z;
+} Vertex3;
+static const Vertex3 kPoly0_Vtx[6] = {
+  {  0,  65,   0},
+  {  0, -65,   0},
+  {  0,   0, -40},
+  {-40,   0,   0},
+  {  0,   0,  40},
+  { 40,   0,   0},
+};
+static const uint8 kPoly0_Polys[40] = {
+  3, 0, 5, 2, 4,
+  3, 0, 2, 3, 1,
+  3, 0, 3, 4, 2,
+  3, 0, 4, 5, 3,
+  3, 1, 2, 5, 4,
+  3, 1, 3, 2, 1,
+  3, 1, 4, 3, 2,
+  3, 1, 5, 4, 3,
+};
+static const Vertex3 kPoly1_Vtx[6] = {
+  {  0,  40,  10},
+  { 40, -40,  10},
+  {-40, -40,  10},
+  {  0,  40, -10},
+  {-40, -40, -10},
+  { 40, -40, -10},
+};
+static const uint8 kPoly1_Polys[28] = {
+  3, 0, 1, 2, 7,
+  3, 3, 4, 5, 6,
+  4, 0, 3, 5, 1, 5,
+  4, 1, 5, 4, 2, 4,
+  4, 3, 0, 2, 4, 3,
+};
+typedef struct PolyConfig {
+  uint8 num_vtx, num_poly;
+  uint16 vtx_val, polys_val;
+  const Vertex3 *vertex;
+  const uint8 *poly;
+} PolyConfig;
+static const PolyConfig kPolyConfigs[2] = {
+  {6, 8, 0xff98, 0xffaa, kPoly0_Vtx, kPoly0_Polys},
+  {6, 5, 0xffd2, 0xffe4, kPoly1_Vtx, kPoly1_Polys},
+};
+static const uint32 kPoly_RasterColors[16] = {
+  0x00, 0xff, 0xff00, 0xffff,
+  0xff0000, 0xff00ff, 0xffff00, 0xffffff,
+  0xff000000, 0xff0000ff, 0xff00ff00, 0xff00ffff,
+  0xffff0000, 0xffff00ff, 0xffffff00, 0xffffffff,
+};
+static const uint16 kPoly_LeftSideMask[8] = {0xffff, 0x7f7f, 0x3f3f, 0x1f1f, 0xf0f, 0x707, 0x303, 0x101};
+static const uint16 kPoly_RightSideMask[8] = {0x8080, 0xc0c0, 0xe0e0, 0xf0f0, 0xf8f8, 0xfcfc, 0xfefe, 0xffff};
+uint16 Poly_Divide(uint16 a, uint16 b) {
+  poly_tmp1 = sign16(a) ? -a : a;
+  poly_tmp0 = b;
+  while (poly_tmp0 >= 256)
+    poly_tmp0 >>= 1, poly_tmp1 >>= 1;
+  int q = poly_tmp1 / poly_tmp0;
+  return sign16(a) ? -q : q;
+}
+
+void Poly_RunFrame() {
+  Polyhedral_EmptyBitMapBuffer();
+  Polyhedral_SetShapePointer();
+  Polyhedral_SetRotationMatrix();
+  Polyhedral_OperateRotation();
+  Polyhedral_DrawPolyhedron();
+}
+
+void Polyhedral_SetShapePointer() {  // 89f83d
+  poly_var1 = poly_config1 * 2 + 0x80;
+  poly_tmp0 = poly_which_model * 2;
+
+  const PolyConfig *poly_config = &kPolyConfigs[poly_which_model];
+  poly_config_num_vertex = poly_config->num_vtx;
+  poly_config_num_polys = poly_config->num_poly;
+  poly_fromlut_ptr2 = poly_config->vtx_val;
+  poly_fromlut_ptr4 = poly_config->polys_val;
+}
+
+void Polyhedral_SetRotationMatrix() {  // 89f864
+  poly_sin_a = kPolySinCos[poly_a];
+  poly_cos_a = kPolySinCos[poly_a + 64];
+  poly_sin_b = kPolySinCos[poly_b];
+  poly_cos_b = kPolySinCos[poly_b + 64];
+  poly_e0 = (int16)poly_sin_b * (int8)poly_sin_a >> 8 << 2;
+  poly_e1 = (int16)poly_cos_b * (int8)poly_cos_a >> 8 << 2;
+  poly_e2 = (int16)poly_cos_b * (int8)poly_sin_a >> 8 << 2;
+  poly_e3 = (int16)poly_sin_b * (int8)poly_cos_a >> 8 << 2;
+}
+
+void Polyhedral_OperateRotation() {  // 89f8fb
+  const PolyConfig *poly_config = &kPolyConfigs[poly_which_model];
+  const int8 *src = &poly_config->vertex[0].x;
+  int i = poly_config_num_vertex;
+  src += i * 3;
+  do {
+    src -= 3, i -= 1;
+    poly_fromlut_x = src[2];
+    poly_fromlut_y = src[1];
+    poly_fromlut_z = src[0];
+    Polyhedral_RotatePoint();
+    Polyhedral_ProjectPoint();
+    poly_arr_x[i] = poly_base_x + poly_f0;
+    poly_arr_y[i] = poly_base_y - poly_f1;
+  } while (i);
+}
+
+void Polyhedral_RotatePoint() {  // 89f931
+  int x = (int8)poly_fromlut_x;
+  int y = (int8)poly_fromlut_y;
+  int z = (int8)poly_fromlut_z;
+
+  poly_f0 =   (int16)poly_cos_b * z                         - (int16)poly_sin_b * x;
+  poly_f1 =   (int16)poly_e0    * z + (int16)poly_cos_a * y + (int16)poly_e2    * x;
+  poly_f2 = ((int16)poly_e3 * z >> 8) - ((int16)poly_sin_a * y >> 8) + ((int16)poly_e1 * x >> 8) + poly_var1;
+}
+
+void Polyhedral_ProjectPoint() {  // 89f9d6
+  poly_f0 = Poly_Divide(poly_f0, poly_f2);
+  poly_f1 = Poly_Divide(poly_f1, poly_f2);
+}
+
+void Polyhedral_DrawPolyhedron() {  // 89fa4f
+  const PolyConfig *poly_config = &kPolyConfigs[poly_which_model];
+  const uint8 *src = poly_config->poly;
+  do {
+    poly_num_vertex_in_poly = *src++;
+    BYTE(poly_tmp0) = poly_num_vertex_in_poly;
+    poly_xy_coords[0] = poly_num_vertex_in_poly * 2;
+
+    int i = 1;
+    do {
+      int j = *src++;
+      poly_xy_coords[i + 0] = poly_arr_x[j];
+      poly_xy_coords[i + 1] = poly_arr_y[j];
+      i += 2;
+    } while (--BYTE(poly_tmp0));
+
+    poly_raster_color_config = *src++;
+    int order = Polyhedral_CalculateCrossProduct();
+    if (order > 0) {
+      Polyhedral_SetForegroundColor();
+      Polyhedral_DrawFace();
+    }
+  } while (--poly_config_num_polys);
+}
+
+void Polyhedral_SetForegroundColor() {  // 89faca
+  uint8 t = poly_which_model ? (poly_config1 >> 5) : 0;
+  uint8 a = (poly_tmp0 << (t + 1)) >> 8;
+  Polyhedral_SetColorMask(a <= 1 ? 1 : a >= 7 ? 7 : a);
+}
+
+int16 Polyhedral_CalculateCrossProduct() {  // 89fb24
+  int16 a = poly_xy_coords[3] - poly_xy_coords[1];
+  poly_tmp0 = a * (int8)(poly_xy_coords[6] - poly_xy_coords[4]);
+  a = poly_xy_coords[5] - poly_xy_coords[3];
+  poly_tmp0 -= a * (int8)(poly_xy_coords[4] - poly_xy_coords[2]);
+  return poly_tmp0;
+}
+
+void Polyhedral_SetColorMask(int c) {  // 89fcae
+  uint32 v = kPoly_RasterColors[c];
+  poly_raster_color0 = v;
+  poly_raster_color1 = v >> 16;
+}
+
+void Polyhedral_EmptyBitMapBuffer() {  // 89fd04
+  memset(polyhedral_buffer, 0, 0x800);
+}
+
+void Polyhedral_DrawFace() {  // 89fd1e
+  int n = poly_xy_coords[0];
+  uint8 min_y = poly_xy_coords[n];
+  int min_idx = n;
+  while (n -= 2) {
+    if (poly_xy_coords[n] < min_y)
+      min_y = poly_xy_coords[n], min_idx = n;
+  }
+  poly_raster_dst_ptr = 0xe800 + (((min_y & 0x38) ^ (min_y & 0x20 ? 0x24 : 0)) << 6) + (min_y & 7) * 2;
+  poly_cur_vertex_idx0 = poly_cur_vertex_idx1 = min_idx;
+  poly_total_num_steps = poly_xy_coords[0] >> 1;
+  poly_y0_cur = poly_y1_cur = poly_xy_coords[min_idx];
+  poly_x0_cur = poly_x1_cur = poly_xy_coords[min_idx - 1];
+  if (Polyhedral_SetLeft() || Polyhedral_SetRight())
+    return;
+  for (;;) {
+    Polyhedral_FillLine();
+    if (BYTE(poly_raster_dst_ptr) != 0xe) {
+      poly_raster_dst_ptr += 2;
+    } else {
+      uint8 a = HIBYTE(poly_raster_dst_ptr) + 2;
+      poly_raster_dst_ptr = (a ^ ((a & 8) ? 0 : 0x19)) << 8;
+    }
+    if (poly_y0_cur == poly_y0_trig) {
+      poly_x0_cur = poly_x0_target;
+      if (Polyhedral_SetLeft())
+        return;
+    }
+    poly_y0_cur++;
+    if (poly_y1_cur == poly_y1_trig) {
+      poly_x1_cur = poly_x1_target;
+      if (Polyhedral_SetRight())
+        return;
+    }
+    poly_y1_cur++;
+    poly_x0_frac += poly_x0_step;
+    poly_x1_frac += poly_x1_step;
+  }
+}
+
+void Polyhedral_FillLine() {  // 89fdcf
+  uint16 left = kPoly_LeftSideMask[(poly_x0_frac >> 8) & 7];
+  uint16 right = kPoly_RightSideMask[(poly_x1_frac >> 8) & 7];
+  poly_tmp2 = (poly_x0_frac >> 8) & 0x38;
+  int d0 = ((poly_x1_frac >> 8) & 0x38);
+  uint16 *ptr = (uint16*)&g_ram[poly_raster_dst_ptr + d0 * 4];
+  if ((d0 -= poly_tmp2) == 0) {
+    poly_tmp1 = left & right;
+    ptr[0] ^= (ptr[0] ^ poly_raster_color0) & poly_tmp1;
+    ptr[8] ^= (ptr[8] ^ poly_raster_color1) & poly_tmp1;
+    return;
+  }
+  if (d0 < 0)
+    return;
+  int n = d0 >> 3;
+  ptr[0] ^= (ptr[0] ^ poly_raster_color0) & right;
+  ptr[8] ^= (ptr[8] ^ poly_raster_color1) & right;
+  ptr -= 0x10;
+  while (--n) {
+    ptr[0] = poly_raster_color0;
+    ptr[8] = poly_raster_color1;
+    ptr -= 0x10;
+  }
+  ptr[0] ^= (ptr[0] ^ poly_raster_color0) & left;
+  ptr[8] ^= (ptr[8] ^ poly_raster_color1) & left;
+  poly_tmp1 = left, poly_raster_numfull = 0;
+}
+
+bool Polyhedral_SetLeft() {  // 89feb4
+  int i;
+  for (;;) {
+    if (sign8(--poly_total_num_steps))
+      return true;
+    i = poly_cur_vertex_idx0 - 2;
+    if (i == 0)
+      i = poly_xy_coords[0];
+    if (poly_xy_coords[i] < poly_y0_cur)
+      return true;
+    if (poly_xy_coords[i] != poly_y0_cur)
+      break;
+    poly_x0_cur = poly_xy_coords[i - 1];
+    poly_cur_vertex_idx0 = i;
+  }
+  poly_y0_trig = poly_xy_coords[i];
+  poly_x0_target = poly_xy_coords[i - 1];
+  poly_cur_vertex_idx0 = i;
+  int t = poly_x0_target - poly_x0_cur, u = t;
+  if (t < 0)
+    t = -t;
+  t = ((t & 0xff) << 8) / (uint8)(poly_y0_trig - poly_y0_cur);
+  poly_x0_frac = (poly_x0_cur << 8) | 0x80;
+  poly_x0_step = (u < 0) ? -t : t;
+  return false;
+}
+
+bool Polyhedral_SetRight() {  // 89ff1e
+  int i;
+  for (;;) {
+    if (sign8(--poly_total_num_steps))
+      return true;
+    i = poly_cur_vertex_idx1;
+    if (i == poly_xy_coords[0])
+      i = 0;
+    i += 2;
+    if (poly_xy_coords[i] < poly_y1_cur)
+      return true;
+    if (poly_xy_coords[i] != poly_y1_cur)
+      break;
+    poly_x1_cur = poly_xy_coords[i - 1];
+    poly_cur_vertex_idx1 = i;
+  }
+  poly_y1_trig = poly_xy_coords[i];
+  poly_x1_target = poly_xy_coords[i - 1];
+  poly_cur_vertex_idx1 = i;
+  int t = poly_x1_target - poly_x1_cur, u = t;
+  if (t < 0)
+    t = -t;
+  t = ((t & 0xff) << 8) / (uint8)(poly_y1_trig - poly_y1_cur);
+  poly_x1_frac = (poly_x1_cur << 8) | 0x80;
+  poly_x1_step = (u < 0) ? -t : t;
+  return false;
+}
+
--- /dev/null
+++ b/src/poly.h
@@ -1,0 +1,19 @@
+#pragma once
+#include "types.h"
+
+uint16 Poly_Divide(uint16 a, uint16 b);
+void Poly_RunFrame();
+void Polyhedral_SetShapePointer();
+void Polyhedral_SetRotationMatrix();
+void Polyhedral_OperateRotation();
+void Polyhedral_RotatePoint();
+void Polyhedral_ProjectPoint();
+void Polyhedral_DrawPolyhedron();
+void Polyhedral_SetForegroundColor();
+int16 Polyhedral_CalculateCrossProduct();
+void Polyhedral_SetColorMask(int c);
+void Polyhedral_EmptyBitMapBuffer();
+void Polyhedral_DrawFace();
+void Polyhedral_FillLine();
+bool Polyhedral_SetLeft();
+bool Polyhedral_SetRight();
--- /dev/null
+++ b/src/select_file.c
@@ -1,0 +1,929 @@
+#include "zelda_rtl.h"
+#include "variables.h"
+#include "load_gfx.h"
+#include "select_file.h"
+#include "snes/snes_regs.h"
+#include "overworld.h"
+#include "messaging.h"
+#include "sprite.h"
+
+#define selectfile_R16 g_ram[0xc8]
+#define selectfile_R17 g_ram[0xc9]
+#define selectfile_R18 WORD(g_ram[0xca])
+#define selectfile_R20 WORD(g_ram[0xcc])
+static const uint8 kSelectFile_Draw_Y[3] = {0x43, 0x63, 0x83};
+bool Intro_CheckCksum(const uint8 *s) {
+  const uint16 *src = (const uint16 *)s;
+  uint16 sum = 0;
+  for (int i = 0; i < 0x280; i++)
+    sum += src[i];
+  return sum == 0x5a5a;
+
+}
+
+uint16 *SelectFile_Func1() {
+  static const uint16 kSelectFile_Func1_Tab[4] = {0x3581, 0x3582, 0x3591, 0x3592};
+  uint16 *dst = (uint16 *)&g_ram[0x1002];
+  *dst++ = 0x10;
+  *dst++ = 0xff07;
+  for (int i = 0; i < 1024; i++)
+    *dst++ = kSelectFile_Func1_Tab[((i & 0x20) >> 4) + (i & 1)];
+  return dst;
+}
+
+void SelectFile_Func5_DrawOams(int k) {
+  static const uint8 kSelectFile_Draw_OamIdx[3] = {0x28, 0x3c, 0x50};
+  static const uint8 kSelectFile_Draw_SwordChar[4] = {0x85, 0xa1, 0xa1, 0xa1};
+  static const uint8 kSelectFile_Draw_ShieldChar[3] = {0xc4, 0xca, 0xe0};
+  static const uint8 kSelectFile_Draw_Flags[3] = {0x72, 0x76, 0x7a};
+  static const uint8 kSelectFile_Draw_Flags2[3] = {0x32, 0x36, 0x3a};
+  static const uint8 kSelectFile_Draw_Flags3[3] = {0x30, 0x34, 0x38};
+
+  link_dma_graphics_index = 0x116 * 2;
+  uint8 *sram = g_zenv.sram + 0x500 * k;
+
+  OamEnt *oam = oam_buf + kSelectFile_Draw_OamIdx[k] / 4;
+  uint8 x = 0x34;
+  uint8 y = kSelectFile_Draw_Y[k];
+
+  uint8 sword = sram[kSrmOffs_Sword] - 1;
+  uint8 swordchar = kSelectFile_Draw_SwordChar[sign8(sword) ? 0 : sword];
+  SetOamPlain(oam + 0, x + 0xc, y - 5, swordchar, kSelectFile_Draw_Flags[k], 0);
+  SetOamPlain(oam + 1, x + 0xc, y + 3, swordchar + 16, kSelectFile_Draw_Flags[k], 0);
+  if (sign8(sword))
+    oam[1].y = oam[0].y = 0xf0;
+  uint8 shield = sram[kSrmOffs_Shield] - 1;
+  SetOamPlain(oam + 2, x - 5, y + 10, kSelectFile_Draw_ShieldChar[sign8(shield) ? 0 : shield], kSelectFile_Draw_Flags2[k], 2);
+  if (sign8(shield))
+    oam[2].y = 0xf0;
+  SetOamPlain(oam + 3, x, y + 0, 0, kSelectFile_Draw_Flags3[k], 2);
+  SetOamPlain(oam + 4, x, y + 8, 2, kSelectFile_Draw_Flags3[k] | 0x40, 2);
+}
+
+void SelectFile_Func6_DrawOams2(int k) {
+  static const uint8 kSelectFile_DrawDigit_Char[10] = {0xd0, 0xac, 0xad, 0xbc, 0xbd, 0xae, 0xaf, 0xbe, 0xbf, 0xc0};
+  static const int8 kSelectFile_DrawDigit_OamIdx[3] = {4, 16, 28};
+  static const int8 kSelectFile_DrawDigit_X[3] = {12, 4, -4};
+
+  uint8 *sram = g_zenv.sram + 0x500 * k;
+  uint8 x = 0x34;
+  uint8 y = kSelectFile_Draw_Y[k];
+
+  int died_ctr = WORD(sram[kSrmOffs_DiedCounter]);
+  if (died_ctr == 0xffff)
+    return;
+
+  if (died_ctr > 999)
+    died_ctr = 999;
+
+  uint8 digits[3];
+  digits[2] = died_ctr / 100;
+  died_ctr %= 100;
+  digits[1] = died_ctr / 10;
+  digits[0] = died_ctr % 10;
+
+  int i = (digits[2] != 0) ? 2 : (digits[1] != 0) ? 1 : 0;
+  OamEnt *oam = oam_buf + kSelectFile_DrawDigit_OamIdx[k] / 4;
+  do {
+    SetOamPlain(oam, x + kSelectFile_DrawDigit_X[i], y + 0x10, kSelectFile_DrawDigit_Char[digits[i]], 0x3c, 0);
+  } while (oam++, --i >= 0);
+}
+
+void SelectFile_Func17(int k) {
+  static const uint16 kSelectFile_DrawName_VramOffs[3] = {8, 0x5c, 0xb0};
+  static const uint16 kSelectFile_DrawName_HealthVramOffs[3] = {0x16, 0x6a, 0xbe};
+  uint8 *sram = g_zenv.sram + 0x500 * k;
+  uint16 *name = (uint16 *)(sram + kSrmOffs_Name);
+  uint16 *dst = vram_upload_data + kSelectFile_DrawName_VramOffs[k] / 2;
+  for (int i = 5; i >= 0; i--) {
+    uint16 t = *name++ + 0x1800;
+    dst[0] = t;
+    dst[21] = t + 0x10;
+    dst++;
+  }
+  int health = sram[kSrmOffs_Health] >> 3;
+  dst = vram_upload_data + kSelectFile_DrawName_HealthVramOffs[k] / 2;
+  uint16 *dst_org = dst;
+  int row = 10;
+  do {
+    *dst++ = 0x520;
+    if (--row == 0)
+      dst = dst_org + 21;
+  } while (--health);
+}
+
+void SelectFile_Func16() {
+  static const uint8 kSelectFile_Func16_FaerieY[2] = {175, 191};
+  FileSelect_DrawFairy(0x1c, kSelectFile_Func16_FaerieY[selectfile_R16]);
+
+  int k = selectfile_R16;
+  if (filtered_joypad_H & 0x2c) {
+    k += (filtered_joypad_H & 0x24) ? 1 : -1;
+    selectfile_R16 = k & 1;
+    sound_effect_2 = 0x20;
+  }
+
+  uint8 a = (filtered_joypad_L & 0xc0 | filtered_joypad_H) & 0xd0;
+  if (a != 0) {
+    sound_effect_1 = 0x2c;
+    if (selectfile_R16 == 0) {
+      sound_effect_2 = 0x22;
+      sound_effect_1 = 0x0;
+      int k = subsubmodule_index;
+      selectfile_arr1[k] = 0;
+      memset(g_zenv.sram + k * 0x500, 0, 0x500);
+      memset(g_zenv.sram + k * 0x500 + 0xf00, 0, 0x500);
+      ZeldaWriteSram();
+    }
+    ReturnToFileSelect();
+    subsubmodule_index = 0;
+  }
+}
+
+void Module_NamePlayer_1() {
+  uint16 *dst = SelectFile_Func1();
+  dst[0] = 0xffff;
+  nmi_load_bg_from_vram = 1;
+  submodule_index++;
+}
+
+void Module_NamePlayer_2() {
+  nmi_load_bg_from_vram = 5;
+  submodule_index++;
+  INIDISP_copy = 15;
+  nmi_disable_core_updates = 0;
+}
+
+void Intro_FixCksum(uint8 *s) {
+  uint16 *src = (uint16 *)s;
+  uint16 sum = 0;
+  for (int i = 0; i < 0x27f; i++)
+    sum += src[i];
+  src[0x27f] = 0x5a5a - sum;
+}
+
+void LoadFileSelectGraphics() {  // 80e4e9
+  Decomp_spr(&g_ram[0x14000], 0x5e);
+  Do3To4High(&g_zenv.vram[0x5000], &g_ram[0x14000]);
+
+  Decomp_spr(&g_ram[0x14000], 0x5f);
+  Do3To4High(&g_zenv.vram[0x5400], &g_ram[0x14000]);
+
+  TransferFontToVRAM();
+
+  Decomp_spr(&g_ram[0x14000], 0x6b);
+  memcpy(&g_zenv.vram[0x7800], &g_ram[0x14000], 0x300 * sizeof(uint16));
+}
+
+void Intro_ValidateSram() {  // 828054
+  uint8 *cart = g_zenv.sram;
+  for (int i = 0; i < 3; i++) {
+    uint8 *c = cart + i * 0x500;
+    if (!Intro_CheckCksum(c)) {
+      if (Intro_CheckCksum(c + 0xf00)) {
+        memcpy(c, c + 0xf00, 0x500);
+      } else {
+        memset(c, 0, 0x500);
+        memset(c + 0xf00, 0, 0x500);
+      }
+    }
+  }
+  memset(&g_ram[0xd00], 0, 256 * 3);
+}
+
+void Module01_FileSelect() {  // 8ccd7d
+  BG3HOFS_copy2 = 0;
+  BG3VOFS_copy2 = 0;
+  switch (submodule_index) {
+  case 0: Module_SelectFile_0(); break;
+  case 1: FileSelect_ReInitSaveFlagsAndEraseTriforce(); break;
+  case 2: Module_EraseFile_1(); break;
+  case 3: FileSelect_TriggerStripesAndAdvance(); break;
+  case 4: FileSelect_TriggerNameStripesAndAdvance(); break;
+  case 5: FileSelect_Main(); break;
+  }
+}
+
+void Module_SelectFile_0() {  // 8ccd9d
+  EnableForceBlank();
+  is_nmi_thread_active = 0;
+  nmi_flag_update_polyhedral = 0;
+  music_control = 11;
+  submodule_index++;
+  overworld_palette_aux_or_main = 0x200;
+  palette_main_indoors = 6;
+  nmi_disable_core_updates = 6;
+  Palette_Load_DungeonSet();
+  Palette_Load_OWBG3();
+  hud_palette = 0;
+  Palette_Load_HUD();
+  hud_cur_item = 0;
+  misc_sprites_graphics_index = 1;
+  main_tile_theme_index = 35;
+  aux_tile_theme_index = 81;
+  LoadDefaultGraphics();
+  InitializeTilesets();
+  LoadFileSelectGraphics();
+  Intro_ValidateSram();
+  DecompressEnemyDamageSubclasses();
+}
+
+void FileSelect_ReInitSaveFlagsAndEraseTriforce() {  // 8ccdf2
+  memset(selectfile_arr1, 0, 6);
+  FileSelect_EraseTriforce();
+}
+
+void FileSelect_EraseTriforce() {  // 8ccdf9
+  nmi_disable_core_updates = 128;
+  EnableForceBlank();
+  EraseTileMaps_triforce();
+  Palette_LoadForFileSelect();
+  flag_update_cgram_in_nmi++;
+  submodule_index++;
+}
+
+void Module_EraseFile_1() {  // 8cce53
+  static const uint8 kSelectFile_Gfx0[224] = {
+    0x10, 0x42,    0, 0x27, 0x89, 0x35, 0x8a, 0x35, 0x8b, 0x35, 0x8c, 0x35, 0x8b, 0x35, 0x8c, 0x35,
+    0x8b, 0x35, 0x8c, 0x35, 0x8b, 0x35, 0x8c, 0x35, 0x8b, 0x35, 0x8c, 0x35, 0x8b, 0x35, 0x8c, 0x35,
+    0x8b, 0x35, 0x8c, 0x35, 0x8b, 0x35, 0x8c, 0x35, 0x8a, 0x75, 0x89, 0x75, 0x10, 0x62,    0,    3,
+    0x99, 0x35, 0x9a, 0x35, 0x10, 0x64, 0x40, 0x1e, 0x7f, 0x34, 0x10, 0x74,    0,    3, 0x9a, 0x75,
+    0x99, 0x75, 0x10, 0x82,    0,    3, 0xa9, 0x35, 0xaa, 0x35, 0x10, 0x84, 0x40, 0x1e, 0x7f, 0x34,
+    0x10, 0x94,    0,    3, 0xaa, 0x75, 0xa9, 0x75, 0x10, 0xa2,    0, 0x27, 0x9d, 0x35, 0xad, 0x35,
+    0x9b, 0x35, 0x9c, 0x35, 0x9b, 0x35, 0x9c, 0x35, 0x9b, 0x35, 0x9c, 0x35, 0x9b, 0x35, 0x9c, 0x35,
+    0x9b, 0x35, 0x9c, 0x35, 0x9b, 0x35, 0x9c, 0x35, 0x9b, 0x35, 0x9c, 0x35, 0x9b, 0x35, 0x9c, 0x35,
+    0xad, 0x75, 0x9d, 0x75, 0x10, 0xc2,    0, 0x27, 0xab, 0x35, 0xac, 0x35, 0xab, 0x35, 0xac, 0x35,
+    0xab, 0x35, 0xac, 0x35, 0xab, 0x35, 0xac, 0x35, 0xab, 0x35, 0xac, 0x35, 0xab, 0x35, 0xac, 0x35,
+    0xab, 0x35, 0xac, 0x35, 0xab, 0x35, 0xac, 0x35, 0xab, 0x35, 0xac, 0x35, 0xab, 0x75, 0xac, 0x75,
+    0x10, 0xe2,    0,    1, 0x83, 0x35, 0x10, 0xe3, 0x40, 0x32, 0x85, 0x35, 0x10, 0xfd,    0,    1,
+    0x84, 0x35, 0x11,    2, 0xc0, 0x22, 0x86, 0x35, 0x11, 0x1d, 0xc0, 0x22, 0x96, 0x35, 0x13, 0x42,
+       0,    1, 0x93, 0x35, 0x13, 0x43, 0x40, 0x32, 0x95, 0x35, 0x13, 0x5d,    0,    1, 0x94, 0x35,
+  };
+  uint16 *dst = SelectFile_Func1();
+  memcpy(dst, kSelectFile_Gfx0, 224);
+  dst += 224 / 2;
+  uint16 t = 0x1103;
+  for (int i = 17; i >= 0; i--) {
+    *dst++ = swap16(t);
+    t += 0x20;
+    *dst++ = 0x3240;
+    *dst++ = 0x347f;
+  }
+  *(uint8 *)dst = 0xff;
+  submodule_index++;
+  nmi_load_bg_from_vram = 1;
+}
+
+void FileSelect_TriggerStripesAndAdvance() {  // 8ccea5
+  selectfile_R16 = selectfile_var2;
+  submodule_index++;
+  nmi_load_bg_from_vram = 6;
+}
+
+void FileSelect_TriggerNameStripesAndAdvance() {  // 8cceb1
+  static const uint8 kSelectFile_Func3_Data[253] = {
+    0x61, 0x29,    0, 0x25, 0xe7, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18,
+    0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18,
+    0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0x61, 0x49,    0, 0x25, 0xf7, 0x18,
+    0x91, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18,
+    0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18,
+    0xa9, 0x18, 0xa9, 0x18, 0x61, 0xa9,    0, 0x25, 0xe8, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18,
+    0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18,
+    0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0x61, 0xc9,
+       0, 0x25, 0xf8, 0x18, 0x91, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18,
+    0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18,
+    0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0x62, 0x29,    0, 0x25, 0xe9, 0x18, 0xa9, 0x18,
+    0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18,
+    0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18,
+    0xa9, 0x18, 0x62, 0x49,    0, 0x25, 0xf9, 0x18, 0x91, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18,
+    0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18,
+    0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xff,
+  };
+  memcpy(vram_upload_data, kSelectFile_Func3_Data, 253);
+  INIDISP_copy = 0xf;
+  nmi_disable_core_updates = 0;
+  submodule_index++;
+  nmi_load_bg_from_vram = 6;
+}
+
+void FileSelect_Main() {  // 8ccebd
+  static const uint8 kSelectFile_Faerie_Y[5] = {0x4a, 0x6a, 0x8a, 0xaf, 0xbf};
+
+  const uint8 *cart = g_zenv.sram;
+
+  if (selectfile_R16 < 3)
+    selectfile_var2 = selectfile_R16;
+
+  for (int k = 0; k < 3; k++) {
+    if (*(uint16 *)(cart + k * 0x500 + 0x3E5) == 0x55AA) {
+      selectfile_arr1[k] = 1;
+      SelectFile_Func5_DrawOams(k);
+      SelectFile_Func6_DrawOams2(k);
+      SelectFile_Func17(k);
+    }
+  }
+
+  FileSelect_DrawFairy(0x1c, kSelectFile_Faerie_Y[selectfile_R16]);
+  nmi_load_bg_from_vram = 1;
+
+  uint8 a = (filtered_joypad_L & 0xc0 | filtered_joypad_H) & 0xfc;
+  if (a & 0x2c) {
+    if (a & 8) {
+      sound_effect_2 = 0x20;
+      if (sign8(--selectfile_R16))
+        selectfile_R16 = 4;
+    } else {
+      sound_effect_2 = 0x20;
+      if (++selectfile_R16 == 5)
+        selectfile_R16 = 0;
+    }
+  } else if (a != 0) {
+    sound_effect_1 = 0x2c;
+    if (selectfile_R16 < 3) {
+      selectfile_R17 = 0;
+      if (!selectfile_arr1[selectfile_R16]) {
+        main_module_index = 4;
+        submodule_index = 0;
+        subsubmodule_index = 0;
+      } else {
+        music_control = 0xf1;
+        srm_var1 = selectfile_R16 * 2 + 2;
+        WORD(g_ram[0]) = selectfile_R16 * 0x500;
+        CopySaveToWRAM();
+      }
+    } else if (selectfile_arr1[0] | selectfile_arr1[1] | selectfile_arr1[2]) {
+      main_module_index = (selectfile_R16 == 3) ? 2 : 3;
+      selectfile_R16 = 0;
+      submodule_index = 0;
+      subsubmodule_index = 0;
+    } else {
+      sound_effect_1 = 0x3c;
+    }
+  }
+}
+
+void Module02_CopyFile() {  // 8cd053
+  selectfile_var2 = 0;
+  switch (submodule_index) {
+  case 0: FileSelect_EraseTriforce(); break;
+  case 1: Module_EraseFile_1(); break;
+  case 2: Module_CopyFile_2(); break;
+  case 3: CopyFile_ChooseSelection(); break;
+  case 4: CopyFile_ChooseTarget(); break;
+  case 5: CopyFile_ConfirmSelection(); break;
+  }
+}
+
+void Module_CopyFile_2() {  // 8cd06e
+  nmi_load_bg_from_vram = 7;
+  submodule_index++;
+  INIDISP_copy = 0xf;
+  nmi_disable_core_updates = 0;
+  int i = 0;
+  for (; selectfile_arr1[i] == 0; i++) {}
+  selectfile_R16 = i;
+}
+
+void CopyFile_ChooseSelection() {  // 8cd087
+  CopyFile_SelectionAndBlinker();
+  if (submodule_index == 3 && !(frame_counter & 0x30))
+    FilePicker_DeleteHeaderStripe();
+  nmi_load_bg_from_vram = 1;
+}
+
+void CopyFile_ChooseTarget() {  // 8cd0a2
+  CopyFile_TargetSelectionAndBlink();
+  if (submodule_index == 4 && !(frame_counter & 0x30))
+    FilePicker_DeleteHeaderStripe();
+  nmi_load_bg_from_vram = 1;
+}
+
+void CopyFile_ConfirmSelection() {  // 8cd0b9
+  CopyFile_HandleConfirmation();
+  nmi_load_bg_from_vram = 1;
+}
+
+void FilePicker_DeleteHeaderStripe() {  // 8cd0c6
+  static const uint16 kFilePicker_DeleteHeaderStripe_Dst[2] = {4, 0x1e};
+  for (int j = 1; j >= 0; j--) {
+    uint16 *dst = vram_upload_data + kFilePicker_DeleteHeaderStripe_Dst[j] / 2;
+    for (int i = 0; i != 11; i++)
+      dst[i] = 0xa9;
+  }
+}
+
+void CopyFile_SelectionAndBlinker() {  // 8cd13f
+  static const uint8 kCopyFile_SelectionAndBlinker_Tab[173] = {
+    0x61,    4,    0, 0x15, 0x85, 0x18, 0x26, 0x18,    7, 0x18, 0xaf, 0x18,    2, 0x18,    7, 0x18,
+    0x6f, 0x18, 0x86, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0x61, 0x24,    0, 0x15, 0x95, 0x18,
+    0x36, 0x18, 0x17, 0x18, 0xbf, 0x18, 0x12, 0x18, 0x17, 0x18, 0x7f, 0x18, 0x96, 0x18, 0xa9, 0x18,
+    0xa9, 0x18, 0xa9, 0x18, 0x61, 0x67,    0,  0xf, 0xe7, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18,
+    0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0x61, 0x87,    0,  0xf, 0xf7, 0x18, 0x91, 0x18,
+    0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0x61, 0xc7,    0,  0xf,
+    0xe8, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18,
+    0x61, 0xe7,    0,  0xf, 0xf8, 0x18, 0x91, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18,
+    0xa9, 0x18, 0xa9, 0x18, 0x62, 0x27,    0,  0xf, 0xe9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18,
+    0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0x62, 0x47,    0,  0xf, 0xf9, 0x18, 0x91, 0x18,
+    0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xff,
+  };
+  static const uint8 kCopyFile_SelectionAndBlinker_Tab1[73] = {
+    0x61, 0x67, 0x40,  0xe, 0xa9,    0, 0x61, 0x87, 0x40,  0xe, 0xa9,    0, 0x61, 0xc7, 0x40,  0xe,
+    0xa9,    0, 0x61, 0xe7, 0x40,  0xe, 0xa9,    0, 0x11, 0x30,    0,    1, 0x83, 0x35, 0x11, 0x31,
+    0x40, 0x14, 0x85, 0x35, 0x11, 0x3c,    0,    1, 0x84, 0x35, 0x11, 0x50, 0xc0,  0xe, 0x86, 0x35,
+    0x11, 0x5c, 0xc0,  0xe, 0x96, 0x35, 0x12, 0x50,    0,    1, 0x93, 0x35, 0x12, 0x51, 0x40, 0x14,
+    0x95, 0x35, 0x12, 0x5c,    0,    1, 0x94, 0x35, 0xff,
+  };
+  static const uint16 kCopyFile_SelectionAndBlinker_Dst[3] = {0x3c, 0x64, 0x8c};
+  static const uint8 kCopyFile_SelectionAndBlinker_FaerieX[4] = {36, 36, 36, 28};
+  static const uint8 kCopyFile_SelectionAndBlinker_FaerieY[4] = {87, 111, 135, 191};
+
+  vram_upload_offset = 0xac;
+  memcpy(vram_upload_data, kCopyFile_SelectionAndBlinker_Tab, 173);
+
+  for (int k = 0; k != 3; k++) {
+    if (selectfile_arr1[k] & 1) {
+      const uint16 *name = (uint16 *)(g_zenv.sram + 0x500 * k + kSrmOffs_Name);
+      uint16 *dst = vram_upload_data + kCopyFile_SelectionAndBlinker_Dst[k] / 2;
+      for (int i = 0; i != 6; i++) {
+        uint16 t = *name++ + 0x1800;
+        dst[0] = t;
+        dst[10] = t + 0x10;
+        dst++;
+      }
+    }
+  }
+  FileSelect_DrawFairy(kCopyFile_SelectionAndBlinker_FaerieX[selectfile_R16], kCopyFile_SelectionAndBlinker_FaerieY[selectfile_R16]);
+
+  uint8 a = (filtered_joypad_L & 0xc0 | filtered_joypad_H) & 0xfc;
+  if (a & 0x2c) {
+    uint8 k = selectfile_R16;
+    if (a & 8) {
+      do {
+        if (--k < 0) {
+          k = 3;
+          break;
+        }
+      } while (!selectfile_arr1[k]);
+    } else {
+      do {
+        k++;
+        if (k >= 4)
+          k = 0;
+      } while (k != 3 && !selectfile_arr1[k]);
+    }
+    selectfile_R16 = k;
+    sound_effect_2 = 0x20;
+  } else if (a != 0) {
+    sound_effect_1 = 0x2c;
+    if (selectfile_R16 == 3) {
+      ReturnToFileSelect();
+      return;
+    }
+    selectfile_R20 = selectfile_R16 * 2;
+    memcpy(vram_upload_data + 26, kCopyFile_SelectionAndBlinker_Tab1, 73);
+    if (selectfile_R16 != 2) {
+      uint16 *dst = vram_upload_data + selectfile_R16 * 6;
+      dst[26] = 0x2762;
+      dst[29] = 0x4762;
+    }
+    submodule_index++;
+    selectfile_R16 = 0;
+  }
+}
+
+void ReturnToFileSelect() {  // 8cd22d
+  main_module_index = 1;
+  submodule_index = 1;
+  subsubmodule_index = 0;
+  selectfile_R16 = 0;
+}
+
+void CopyFile_TargetSelectionAndBlink() {  // 8cd27b
+  {
+    int k = 1, t = 4;
+    do {
+      if (t != selectfile_R20)
+        selectfile_arr2[k--] = t;
+    } while ((t -= 2) >= 0);
+  }
+
+  static const uint8 kCopyFile_TargetSelectionAndBlink_Tab0[133] = {
+    0x61, 0x51,    0, 0x15, 0x85, 0x18, 0x23, 0x18,  0xe, 0x18, 0xa9, 0x18, 0x26, 0x18,    7, 0x18,
+    0xaf, 0x18,    2, 0x18,    7, 0x18, 0x6f, 0x18, 0x86, 0x18, 0x61, 0x71,    0, 0x15, 0x95, 0x18,
+    0x33, 0x18, 0x1e, 0x18, 0xb9, 0x18, 0x36, 0x18, 0x17, 0x18, 0xbf, 0x18, 0x12, 0x18, 0x17, 0x18,
+    0x7f, 0x18, 0x96, 0x18, 0x61, 0xb4,    0,  0xf, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18,
+    0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0x61, 0xd4,    0,  0xf, 0xa9, 0x18, 0x91, 0x18,
+    0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0x62, 0x14,    0,  0xf,
+    0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18,
+    0x62, 0x34,    0,  0xf, 0xa9, 0x18, 0x91, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18,
+    0xa9, 0x18, 0xa9, 0x18, 0xff,
+  };
+  static const uint8 kCopyFile_TargetSelectionAndBlink_Tab2[49] = {
+    0x61, 0xb4, 0x40,  0xe, 0xa9,    0, 0x61, 0xd4, 0x40,  0xe, 0xa9,    0, 0x62, 0xc6,    0,  0xd,
+       2, 0x18,  0xe, 0x18,  0xf, 0x18, 0x28, 0x18, 0xa9, 0x18,  0xe, 0x18,  0xa, 0x18, 0x62, 0xe6,
+       0,  0xd, 0x12, 0x18, 0x1e, 0x18, 0x1f, 0x18, 0x38, 0x18, 0xa9, 0x18, 0x1e, 0x18, 0x1a, 0x18,
+    0xff,
+  };
+  static const uint8 kCopyFile_TargetSelectionAndBlink_FaerieX[3] = {0x8c, 0x8c, 0x1c};
+  static const uint8 kCopyFile_TargetSelectionAndBlink_FaerieY[3] = {0x67, 0x7f, 0xbf};
+  static const uint16 kCopyFile_TargetSelectionAndBlink_Dst[2] = {0x38, 0x60};
+  static const uint16 kCopyFile_TargetSelectionAndBlink_Tab1[3] = {0x18e7, 0x18e8, 0x18e9};
+  memcpy(vram_upload_data, kCopyFile_TargetSelectionAndBlink_Tab0, 133);
+
+  for (int k = 0, j = 0; k != 3; k++) {
+    if (k * 2 == selectfile_R20)
+      continue;
+
+    uint16 *dst = vram_upload_data + kCopyFile_TargetSelectionAndBlink_Dst[j++] / 2;
+    uint16 t = kCopyFile_TargetSelectionAndBlink_Tab1[k];
+    dst[0] = t;
+    dst[10] = t + 0x10;
+    dst += 2;
+    if (selectfile_arr1[k]) {
+      const uint16 *name = (uint16 *)(g_zenv.sram + 0x500 * k + kSrmOffs_Name);
+      for (int i = 0; i != 6; i++) {
+        uint16 t = *name++ + 0x1800;
+        dst[0] = t;
+        dst[10] = t + 0x10;
+        dst++;
+      }
+    }
+  }
+
+  vram_upload_offset = 132;
+
+  FileSelect_DrawFairy(kCopyFile_TargetSelectionAndBlink_FaerieX[selectfile_R16], kCopyFile_TargetSelectionAndBlink_FaerieY[selectfile_R16]);
+
+  uint8 a = (filtered_joypad_L & 0xc0 | filtered_joypad_H) & 0xfc;
+  if (a & 0x2c) {
+    uint8 k = selectfile_R16;
+    if (a & 8) {
+      if (sign8(--k))
+        k = 2;
+    } else {
+      if (++k >= 3)
+        k = 0;
+    }
+    selectfile_R16 = k;
+    sound_effect_2 = 0x20;
+  } else if (a) {
+    sound_effect_1 = 0x2c;
+    if (selectfile_R16 == 2) {
+      ReturnToFileSelect();
+      selectfile_R16 = 0;
+      return;
+    }
+    selectfile_R18 = selectfile_arr2[selectfile_R16];
+    memcpy(vram_upload_data + 26, kCopyFile_TargetSelectionAndBlink_Tab2, 49);
+    if (selectfile_R16 == 0) {
+      uint16 *dst = vram_upload_data;
+      dst[26] = 0x1462;
+      dst[29] = 0x3462;
+    }
+    submodule_index++;
+    selectfile_R16 = 0;
+  }
+}
+
+void CopyFile_HandleConfirmation() {  // 8cd371
+  static const uint8 kCopyFile_HandleConfirmation_FaerieY[2] = {0xaf, 0xbf};
+  FileSelect_DrawFairy(0x1c, kCopyFile_HandleConfirmation_FaerieY[selectfile_R16]);
+
+  uint8 a = (filtered_joypad_L & 0xc0 | filtered_joypad_H) & 0xfc;
+  if (a & 0x2c) {
+    sound_effect_2 = 0x20;
+    if (a & 0x24) {
+      if (++selectfile_R16 >= 2)
+        selectfile_R16 = 0;
+    } else {
+      if (sign8(--selectfile_R16))
+        selectfile_R16 = 1;
+    }
+  } else if (a != 0) {
+    sound_effect_1 = 0x2c;
+    if (selectfile_R16 == 0) {
+      memcpy(g_zenv.sram + (selectfile_R18 >> 1) * 0x500, g_zenv.sram + (selectfile_R20 >> 1) * 0x500, 0x500);
+      selectfile_arr1[(selectfile_R18 >> 1)] = 1;
+      ZeldaWriteSram();
+    }
+    ReturnToFileSelect();
+    selectfile_R16 = 0;
+  }
+}
+
+void Module03_KILLFile() {  // 8cd485
+  switch (submodule_index) {
+  case 0: FileSelect_EraseTriforce(); break;
+  case 1: Module_EraseFile_1(); break;
+  case 2: KILLFile_SetUp(); break;
+  case 3: KILLFile_HandleSelection(); break;
+  case 4: KILLFile_HandleConfirmation(); break;
+  }
+}
+
+void KILLFile_SetUp() {  // 8cd49a
+  nmi_load_bg_from_vram = 8;
+  submodule_index++;
+  INIDISP_copy = 0xf;
+  nmi_disable_core_updates = 0;
+  int i = 0;
+  for (; selectfile_arr1[i] == 0; i++) {}
+  selectfile_R16 = i;
+}
+
+void KILLFile_HandleSelection() {  // 8cd49f
+  if (selectfile_R16 < 3)
+    selectfile_var2 = selectfile_R16;
+  KILLFile_ChooseTarget();
+  nmi_load_bg_from_vram = 1;
+}
+
+void KILLFile_HandleConfirmation() {  // 8cd4b1
+  SelectFile_Func16();
+  nmi_load_bg_from_vram = 1;
+}
+
+void KILLFile_ChooseTarget() {  // 8cd4ba
+  static const uint8 kKILLFile_ChooseTarget_Tab[253] = {
+    0x61, 0xa7,    0, 0x25, 0xe7, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18,
+    0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18,
+    0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0x61, 0xc7,    0, 0x25, 0xf7, 0x18,
+    0x91, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18,
+    0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18,
+    0xa9, 0x18, 0xa9, 0x18, 0x62,    7,    0, 0x25, 0xe8, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18,
+    0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18,
+    0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0x62, 0x27,
+       0, 0x25, 0xf8, 0x18, 0x91, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18,
+    0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18,
+    0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0x62, 0x67,    0, 0x25, 0xe9, 0x18, 0xa9, 0x18,
+    0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18,
+    0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18,
+    0xa9, 0x18, 0x62, 0x87,    0, 0x25, 0xf9, 0x18, 0x91, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18,
+    0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18,
+    0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xa9, 0x18, 0xff,
+  };
+  static const uint8 kKILLFile_ChooseTarget_Tab2[101] = {
+    0x61, 0xa7, 0x40, 0x24, 0xa9,    0, 0x61, 0xc7, 0x40, 0x24, 0xa9,    0, 0x62,    7, 0x40, 0x24,
+    0xa9,    0, 0x62, 0x27, 0x40, 0x24, 0xa9,    0, 0x62, 0xc6,    0, 0x21,    4, 0x18, 0x21, 0x18,
+       0, 0x18, 0x22, 0x18,    4, 0x18, 0xa9, 0x18, 0x23, 0x18,    7, 0x18, 0xaf, 0x18, 0x22, 0x18,
+    0xa9, 0x18,  0xf, 0x18,  0xb, 0x18,    0, 0x18, 0x28, 0x18,    4, 0x18, 0x21, 0x18, 0x62, 0xe6,
+       0, 0x21, 0x14, 0x18, 0x31, 0x18, 0x10, 0x18, 0x32, 0x18, 0x14, 0x18, 0xa9, 0x18, 0x33, 0x18,
+    0x17, 0x18, 0xbf, 0x18, 0x32, 0x18, 0xa9, 0x18, 0x1f, 0x18, 0x1b, 0x18, 0x10, 0x18, 0x38, 0x18,
+    0x14, 0x18, 0x31, 0x18, 0xff,
+  };
+  static const uint8 kKILLFile_ChooseTarget_FaerieX[4] = {36, 36, 36, 28};
+  static const uint8 kKILLFile_ChooseTarget_FaerieY[4] = {103, 127, 151, 191};
+  memcpy(vram_upload_data, kKILLFile_ChooseTarget_Tab, 253);
+  for (int k = 0; k < 3; k++) {
+    if (selectfile_arr1[k])
+      SelectFile_Func17(k);
+  }
+
+  FileSelect_DrawFairy(kKILLFile_ChooseTarget_FaerieX[selectfile_R16], kKILLFile_ChooseTarget_FaerieY[selectfile_R16]);
+
+  int k = selectfile_R16;
+  if (filtered_joypad_H & 0x2c) {
+    if (!(filtered_joypad_H & 0x24)) {
+      do {
+        if (--k < 0) {
+          k = 3;
+          break;
+        }
+      } while (!selectfile_arr1[k]);
+    } else {
+      do {
+        k++;
+        if (k >= 4)
+          k = 0;
+      } while (k != 3 && !selectfile_arr1[k]);
+    }
+    sound_effect_2 = 0x20;
+  }
+  selectfile_R16 = k;
+
+  uint8 a = (filtered_joypad_L & 0xc0 | filtered_joypad_H) & 0xd0;
+  if (a) {
+    sound_effect_1 = 0x2c;
+    if (k == 3) {
+      ReturnToFileSelect();
+      return;
+    }
+
+    memcpy(vram_upload_data, kKILLFile_ChooseTarget_Tab2, 101);
+    submodule_index++;
+    if (selectfile_R16 != 2) {
+      uint16 *dst = vram_upload_data + selectfile_R16 * 6;
+      dst[0] = 0x6762;
+      dst[3] = 0x8762;
+    }
+    subsubmodule_index = selectfile_R16;
+    selectfile_R16 = 0;
+  }
+}
+
+void FileSelect_DrawFairy(uint8 x, uint8 y) {  // 8cd7a5
+  SetOamPlain(&oam_buf[0], x, y, frame_counter & 8 ? 0xaa : 0xa8, 0x7e, 2);
+}
+
+void Module04_NameFile() {  // 8cd88a
+  switch (submodule_index) {
+  case 0: NameFile_EraseSave(); break;
+  case 1: Module_NamePlayer_1(); break;
+  case 2: Module_NamePlayer_2(); break;
+  case 3: NameFile_DoTheNaming(); break;
+  }
+}
+
+void NameFile_EraseSave() {  // 8cd89c
+  FileSelect_EraseTriforce();
+  irq_flag = 1;
+  selectfile_var3 = 0;
+  selectfile_var4 = 0;
+  selectfile_var5 = 0;
+  selectfile_arr2[0] = 0;
+  selectfile_var6 = 0;
+  selectfile_var7 = 0x83;
+  selectfile_var8 = 0x1f0;
+  BG3HOFS_copy2 = 0;
+  int offs = selectfile_R16 * 0x500;
+  attract_legend_ctr = offs;
+  memset(g_zenv.sram + offs, 0, 0x500);
+  uint16 *name = (uint16 *)(g_zenv.sram + offs + kSrmOffs_Name);
+  name[0] = name[1] = name[2] = name[3] = name[4] = name[5] = 0xa9;
+}
+
+void NameFile_DoTheNaming() {  // 8cda4d
+  static const int16 kNamePlayer_Tab1[26] = {
+    -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1,
+    -2, 2, -2, 2, -2, 2, -2, 2, -4, 4,
+  };
+  static const uint8 kNamePlayer_Tab2[4] = {131, 147, 163, 179};
+  static const int8 kNamePlayer_X[6] = {31, 47, 63, 79, 95, 111};
+  static const int16 kNamePlayer_Tab0[32] = {
+    0x1f0,     0,  0x10,  0x20,  0x30,  0x40,  0x50,  0x60,  0x70,  0x80,  0x90,  0xa0,  0xb0,  0xc0,  0xd0,  0xe0,
+     0xf0, 0x100, 0x110, 0x120, 0x130, 0x140, 0x150, 0x160, 0x170, 0x180, 0x190, 0x1a0, 0x1b0, 0x1c0, 0x1d0, 0x1e0,
+  };
+  static const int8 kNamePlayer_Tab3[128] = {
+       6,    7, 0x5f,    9, 0x59, 0x59, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x60, 0x23,
+    0x59, 0x59, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x59, 0x59, 0x59,    0,    1,    2,    3,    4,    5,
+    0x10, 0x11, 0x12, 0x13, 0x59, 0x59, 0x24, 0x5f, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d,
+    0x59, 0x59, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x59, 0x59, 0x59,  0xa,  0xb,  0xc,  0xd,  0xe,  0xf,
+    0x40, 0x41, 0x42, 0x59, 0x59, 0x59, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x40, 0x41, 0x42, 0x59,
+    0x59, 0x59, 0x61, 0x3f, 0x45, 0x46, 0x59, 0x59, 0x59, 0x59, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19,
+    0x44, 0x59, 0x6f, 0x6f, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x5a, 0x44, 0x59, 0x6f, 0x6f,
+    0x59, 0x59, 0x5a, 0x44, 0x59, 0x6f, 0x6f, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x5a,
+  };
+  for (;;) {
+    int j = selectfile_var9;
+    if (j == 0) {
+      NameFile_CheckForScrollInputX();
+      break;
+    }
+    if (j != 0x31)
+      selectfile_var9 += 4;
+    j--;
+    if (kNamePlayer_Tab0[selectfile_var3] == selectfile_var8) {
+      selectfile_var9 = (joypad1H_last & 3) ? 0x30 : 0;
+      NameFile_CheckForScrollInputX();
+      continue;
+    }
+    if (!selectfile_var10)
+      j += 2;
+    selectfile_var8 = (selectfile_var8 + WORD(((uint8*)&kNamePlayer_Tab1)[j])) & 0x1ff;
+    break;
+  }
+
+  for (;;) {
+    if (selectfile_var11 == 0) {
+      NameFile_CheckForScrollInputY();
+      break;
+    }
+    uint8 diff = selectfile_var7 - kNamePlayer_Tab2[selectfile_var5];
+    if (diff != 0) {
+      selectfile_var7 += sign8(diff) ? 2 : -2;
+      break;
+    }
+    selectfile_var11 = 0;
+    NameFile_CheckForScrollInputY();
+  }
+
+  OamEnt *oam = oam_buf;
+  for (int i = 0; i != 26; i++) {
+    SetOamPlain(oam, 0x18 + i * 8, selectfile_var7, 0x2e, 0x3c, 0);
+    oam++;
+  }
+  SetOamPlain(oam, kNamePlayer_X[selectfile_var4], 0x58, 0x29, 0xc, 0);
+
+  if (selectfile_var9 | selectfile_var11)
+    return;
+
+  if (!(filtered_joypad_H & 0x10)) {
+    if (!(filtered_joypad_H & 0xc0 || filtered_joypad_L & 0xc0))
+      return;
+
+    sound_effect_1 = 0x2b;
+    uint8 t = kNamePlayer_Tab3[selectfile_var3 + selectfile_var5 * 0x20];
+    if (t == 0x5a) {
+      if (!selectfile_var4)
+        selectfile_var4 = 5;
+      else
+        selectfile_var4--;
+      return;
+    } else if (t == 0x44) {
+      if (++selectfile_var4 == 6)
+        selectfile_var4 = 0;
+      return;
+    } else if (t != 0x6f) {
+      int p = selectfile_var4 * 2 + attract_legend_ctr;
+      uint16 chr = (t & 0xfff0) * 2 + (t & 0xf);
+      WORD(g_zenv.sram[p + kSrmOffs_Name]) = chr;
+      NameFile_DrawSelectedCharacter(selectfile_var4, chr);
+      if (++selectfile_var4 == 6)
+        selectfile_var4 = 0;
+      return;
+    }
+  }
+  int i = 0;
+  for(;;) {
+    uint16 a = WORD(g_zenv.sram[i * 2 + attract_legend_ctr + kSrmOffs_Name]);
+    if (a != 0xa9)
+      break;
+    if (++i == 6) {
+      sound_effect_1 = 0x3c;
+      return;
+    }
+  }
+  srm_var1 = selectfile_R16 * 2 + 2;
+  uint8 *sram = &g_zenv.sram[selectfile_R16 * 0x500];
+  WORD(sram[0x3e5]) = 0x55aa;
+  WORD(sram[0x20c]) = 0xf000;
+  WORD(sram[0x20e]) = 0xf000;
+  WORD(sram[kSrmOffs_DiedCounter]) = 0xffff;
+  static const uint8 kSramInit_Normal[60] = {
+    0, 0, 0, 0, 0, 0, 0, 0, 0,    0, 0, 0,    0,    0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0,    0, 0, 0,    0,    0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0,    0, 0, 0, 0x18, 0x18, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0xf8, 0, 0,
+  };
+  memcpy(sram + 0x340, kSramInit_Normal, 60);
+  Intro_FixCksum(sram);
+  ZeldaWriteSram();
+  ReturnToFileSelect();
+  irq_flag = 0xff;
+  sound_effect_1 = 0x2c;
+}
+
+void NameFile_CheckForScrollInputX() {  // 8cdc8c
+  static const uint16 kNameFile_CheckForScrollInputX_Add[2] = {1, 0xff};
+  static const int16 kNameFile_CheckForScrollInputX_Cmp[2] = {0x20, 0xff};
+  static const int16 kNameFile_CheckForScrollInputX_Set[2] = {0, 0x1f};
+  if (joypad1H_last & 3) {
+    int k = (joypad1H_last & 3) - 1;
+    selectfile_var10 = k;
+    selectfile_var9++;
+    uint8 t = selectfile_var3 + kNameFile_CheckForScrollInputX_Add[k];
+    if (t == kNameFile_CheckForScrollInputX_Cmp[k])
+      t = kNameFile_CheckForScrollInputX_Set[k];
+    selectfile_var3 = t;
+  }
+}
+
+void NameFile_CheckForScrollInputY() {  // 8cdcbf
+  static const int8 kNameFile_CheckForScrollInputY_Add[2] = {1, -1};
+  static const int8 kNameFile_CheckForScrollInputY_Cmp[2] = {4, -1};
+  static const int8 kNameFile_CheckForScrollInputY_Set[2] = {0, 3};
+
+  uint8 a = joypad1H_last & 0xc;
+  if (a) {
+    if ((a * 2 | selectfile_var5) == 0x10 || (a * 4 | selectfile_var5) == 0x13) {
+      selectfile_arr2[1] = a;
+      return;
+    }
+     a >>= 2;
+    int t = selectfile_var5 + kNameFile_CheckForScrollInputY_Add[a-1];
+    if (t == kNameFile_CheckForScrollInputY_Cmp[a-1])
+      t = kNameFile_CheckForScrollInputY_Set[a-1];
+    selectfile_var5 = t;
+
+    selectfile_var11++;
+    selectfile_arr2[1] = a;
+
+  } else {
+    selectfile_arr2[0] = 0;
+  }
+}
+
+void NameFile_DrawSelectedCharacter(int k, uint16 chr) {  // 8cdd30
+  static const uint16 kNameFile_DrawSelectedCharacter_Tab[6] = {0x84, 0x86, 0x88, 0x8a, 0x8c, 0x8e};
+  uint16 *dst = vram_upload_data;
+  uint16 a = kNameFile_DrawSelectedCharacter_Tab[k] | 0x6100;
+  dst[0] = swap16(a);
+  dst[1] = 0x100;
+  dst[2] = 0x1800 | chr;
+  dst[3] = swap16(a + 0x20);
+  dst[4] = 0x100;
+  dst[5] = (0x1800 | chr) + 0x10;
+  BYTE(dst[6]) = 0xff;
+  nmi_load_bg_from_vram = 1;
+}
+
--- /dev/null
+++ b/src/select_file.h
@@ -1,0 +1,44 @@
+#pragma once
+
+
+bool Intro_CheckCksum(const uint8 *s);
+uint16 *SelectFile_Func1();
+void SelectFile_Func5_DrawOams(int k);
+void SelectFile_Func6_DrawOams2(int k);
+void SelectFile_Func17(int k);
+void SelectFile_Func16();
+void Module_NamePlayer_1();
+void Module_NamePlayer_2();
+void Intro_FixCksum(uint8 *s);
+void LoadFileSelectGraphics();
+void Intro_ValidateSram();
+void Module01_FileSelect();
+void Module_SelectFile_0();
+void FileSelect_ReInitSaveFlagsAndEraseTriforce();
+void FileSelect_EraseTriforce();
+void Module_EraseFile_1();
+void FileSelect_TriggerStripesAndAdvance();
+void FileSelect_TriggerNameStripesAndAdvance();
+void FileSelect_Main();
+void Module02_CopyFile();
+void Module_CopyFile_2();
+void CopyFile_ChooseSelection();
+void CopyFile_ChooseTarget();
+void CopyFile_ConfirmSelection();
+void FilePicker_DeleteHeaderStripe();
+void CopyFile_SelectionAndBlinker();
+void ReturnToFileSelect();
+void CopyFile_TargetSelectionAndBlink();
+void CopyFile_HandleConfirmation();
+void Module03_KILLFile();
+void KILLFile_SetUp();
+void KILLFile_HandleSelection();
+void KILLFile_HandleConfirmation();
+void KILLFile_ChooseTarget();
+void FileSelect_DrawFairy(uint8 x, uint8 y);
+void Module04_NameFile();
+void NameFile_EraseSave();
+void NameFile_DoTheNaming();
+void NameFile_CheckForScrollInputX();
+void NameFile_CheckForScrollInputY();
+void NameFile_DrawSelectedCharacter(int k, uint16 chr);
--- /dev/null
+++ b/src/spc_player.c
@@ -1,0 +1,1447 @@
+#include <stdint.h>
+#include <string.h>
+#include <stdlib.h>
+#include <assert.h>
+#include "types.h"
+
+#include "snes/spc.h"
+#include "snes/dsp_regs.h"
+
+#include "spc_player.h"
+
+typedef struct MemMap {
+  uint16 off, org_off;
+} MemMap;
+
+typedef struct MemMapSized {
+  uint16 off, org_off, size;
+} MemMapSized;
+
+static const MemMap kChannel_Maps[] = {
+  {offsetof(Channel, pattern_order_ptr_for_chan), 0x8030},
+  {offsetof(Channel, note_ticks_left), 0x70},
+  {offsetof(Channel, note_keyoff_ticks_left), 0x71},
+  {offsetof(Channel, subroutine_num_loops), 0x80},
+  {offsetof(Channel, volume_fade_ticks), 0x90},
+  {offsetof(Channel, pan_num_ticks), 0x91},
+  {offsetof(Channel, pitch_slide_length), 0xa0},
+  {offsetof(Channel, pitch_slide_delay_left), 0xa1},
+  {offsetof(Channel, vibrato_hold_count), 0xb0},
+  {offsetof(Channel, vib_depth), 0xb1},
+  {offsetof(Channel, tremolo_hold_count), 0xc0},
+  {offsetof(Channel, tremolo_depth), 0xc1},
+  {offsetof(Channel, vibrato_change_count), 0x100},
+  {offsetof(Channel, note_length), 0x200},
+  {offsetof(Channel, note_gate_off_fixedpt), 0x201},
+  {offsetof(Channel, channel_volume_master), 0x210},
+  {offsetof(Channel, instrument_id), 0x211},
+  {offsetof(Channel, instrument_pitch_base), 0x8220},
+  {offsetof(Channel, saved_pattern_ptr), 0x8230},
+  {offsetof(Channel, pattern_start_ptr), 0x8240},
+  {offsetof(Channel, pitch_envelope_num_ticks), 0x280},
+  {offsetof(Channel, pitch_envelope_delay), 0x281},
+  {offsetof(Channel, pitch_envelope_direction), 0x290},
+  {offsetof(Channel, pitch_envelope_slide_value), 0x291},
+  {offsetof(Channel, vibrato_count), 0x2a0},
+  {offsetof(Channel, vibrato_rate), 0x2a1},
+  {offsetof(Channel, vibrato_delay_ticks), 0x2b0},
+  {offsetof(Channel, vibrato_fade_num_ticks), 0x2b1},
+  {offsetof(Channel, vibrato_fade_add_per_tick), 0x2c0},
+  {offsetof(Channel, vibrato_depth_target), 0x2c1},
+  {offsetof(Channel, tremolo_count), 0x2d0},
+  {offsetof(Channel, tremolo_rate), 0x2d1},
+  {offsetof(Channel, tremolo_delay_ticks), 0x2e0},
+  {offsetof(Channel, channel_transposition), 0x2f0},
+  {offsetof(Channel, channel_volume), 0x8300},
+  {offsetof(Channel, volume_fade_addpertick), 0x8310},
+  {offsetof(Channel, volume_fade_target), 0x320},
+  {offsetof(Channel, final_volume), 0x321},
+  {offsetof(Channel, pan_value), 0x8330},
+  {offsetof(Channel, pan_add_per_tick), 0x8340},
+  {offsetof(Channel, pan_target_value), 0x350},
+  {offsetof(Channel, pan_flag_with_phase_invert), 0x351},
+  {offsetof(Channel, pitch), 0x8360},
+  {offsetof(Channel, pitch_add_per_tick), 0x8370},
+  {offsetof(Channel, pitch_target), 0x380},
+  {offsetof(Channel, fine_tune), 0x381},
+  {offsetof(Channel, sfx_sound_ptr), 0x8390},
+  {offsetof(Channel, sfx_which_sound), 0x3a0},
+  {offsetof(Channel, sfx_arr_countdown), 0x3a1},
+  {offsetof(Channel, sfx_note_length_left), 0x3b0},
+  {offsetof(Channel, sfx_note_length), 0x3b1},
+  {offsetof(Channel, sfx_pan), 0x3d0},
+};
+
+static const MemMapSized kSpcPlayer_Maps[] = {
+  {offsetof(SpcPlayer, new_value_from_snes), 0x0, 4},
+  {offsetof(SpcPlayer, port_to_snes), 0x4, 4},
+  {offsetof(SpcPlayer, last_value_from_snes), 0x8, 4},
+  {offsetof(SpcPlayer, counter_sf0c), 0xc, 1},
+  {offsetof(SpcPlayer, _always_zero), 0xe, 2},
+  {offsetof(SpcPlayer, temp_accum), 0x10, 2},
+  {offsetof(SpcPlayer, ttt), 0x12, 1},
+  {offsetof(SpcPlayer, did_affect_volumepitch_flag), 0x13, 1},
+  {offsetof(SpcPlayer, addr0), 0x14, 2},
+  {offsetof(SpcPlayer, addr1), 0x16, 2},
+  {offsetof(SpcPlayer, lfsr_value), 0x18, 2},
+  {offsetof(SpcPlayer, is_chan_on), 0x1a, 1},
+  {offsetof(SpcPlayer, fast_forward), 0x1b, 1},
+  {offsetof(SpcPlayer, sfx_start_arg_pan), 0x20, 1},
+  {offsetof(SpcPlayer, sfx_sound_ptr_cur), 0x2c, 2},
+  {offsetof(SpcPlayer, music_ptr_toplevel), 0x40, 2},
+  {offsetof(SpcPlayer, block_count), 0x42, 1},
+  {offsetof(SpcPlayer, sfx_timer_accum), 0x43, 1},
+  {offsetof(SpcPlayer, chn), 0x44, 1},
+  {offsetof(SpcPlayer, key_ON), 0x45, 1},
+  {offsetof(SpcPlayer, key_OFF), 0x46, 1},
+  {offsetof(SpcPlayer, cur_chan_bit), 0x47, 1},
+  {offsetof(SpcPlayer, reg_FLG), 0x48, 1},
+  {offsetof(SpcPlayer, reg_NON), 0x49, 1},
+  {offsetof(SpcPlayer, reg_EON), 0x4a, 1},
+  {offsetof(SpcPlayer, reg_PMON), 0x4b, 1},
+  {offsetof(SpcPlayer, echo_stored_time), 0x4c, 1},
+  {offsetof(SpcPlayer, echo_parameter_EDL), 0x4d, 1},
+  {offsetof(SpcPlayer, reg_EFB), 0x4e, 1},
+  {offsetof(SpcPlayer, global_transposition), 0x50, 1},
+  {offsetof(SpcPlayer, main_tempo_accum), 0x51, 1},
+  {offsetof(SpcPlayer, tempo), 0x52, 2},
+  {offsetof(SpcPlayer, tempo_fade_num_ticks), 0x54, 1},
+  {offsetof(SpcPlayer, tempo_fade_final), 0x55, 1},
+  {offsetof(SpcPlayer, tempo_fade_add), 0x56, 2},
+  {offsetof(SpcPlayer, master_volume), 0x58, 2},
+  {offsetof(SpcPlayer, master_volume_fade_ticks), 0x5a, 1},
+  {offsetof(SpcPlayer, master_volume_fade_target), 0x5b, 1},
+  {offsetof(SpcPlayer, master_volume_fade_add_per_tick), 0x5c, 2},
+  {offsetof(SpcPlayer, vol_dirty), 0x5e, 1},
+  {offsetof(SpcPlayer, percussion_base_id), 0x5f, 1},
+  {offsetof(SpcPlayer, echo_volume_left), 0x60, 2},
+  {offsetof(SpcPlayer, echo_volume_right), 0x62, 2},
+  {offsetof(SpcPlayer, echo_volume_fade_add_left), 0x64, 2},
+  {offsetof(SpcPlayer, echo_volume_fade_add_right), 0x66, 2},
+  {offsetof(SpcPlayer, echo_volume_fade_ticks), 0x68, 1},
+  {offsetof(SpcPlayer, echo_volume_fade_target_left), 0x69, 1},
+  {offsetof(SpcPlayer, echo_volume_fade_target_right), 0x6a, 1},
+  {offsetof(SpcPlayer, sfx_channel_index), 0x3c0, 1},
+  {offsetof(SpcPlayer, current_bit), 0x3c1, 1},
+  {offsetof(SpcPlayer, dsp_register_index), 0x3c2, 1},
+  {offsetof(SpcPlayer, echo_channels), 0x3c3, 1},
+  {offsetof(SpcPlayer, byte_3C4), 0x3c4, 1},
+  {offsetof(SpcPlayer, byte_3C5), 0x3c5, 1},
+  {offsetof(SpcPlayer, echo_fract_incr), 0x3c7, 1},
+  {offsetof(SpcPlayer, sfx_channel_index2), 0x3c8, 1},
+  {offsetof(SpcPlayer, sfx_channel_bit), 0x3c9, 1},
+  {offsetof(SpcPlayer, pause_music_ctr), 0x3ca, 1},
+  {offsetof(SpcPlayer, port2_active), 0x3cb, 1},
+  {offsetof(SpcPlayer, port2_current_bit), 0x3cc, 1},
+  {offsetof(SpcPlayer, port3_active), 0x3cd, 1},
+  {offsetof(SpcPlayer, port3_current_bit), 0x3ce, 1},
+  {offsetof(SpcPlayer, port1_active), 0x3cf, 1},
+  {offsetof(SpcPlayer, port1_current_bit), 0x3e0, 1},
+  {offsetof(SpcPlayer, byte_3E1), 0x3e1, 1},
+  {offsetof(SpcPlayer, sfx_play_echo_flag), 0x3e2, 1},
+  {offsetof(SpcPlayer, sfx_channels_echo_mask2), 0x3e3, 1},
+  {offsetof(SpcPlayer, port1_counter), 0x3e4, 1},
+  {offsetof(SpcPlayer, channel_67_volume), 0x3e5, 1},
+  {offsetof(SpcPlayer, cutk_always_zero), 0x3ff, 1},
+};
+
+static void PlayNote(SpcPlayer *p, Channel *c, uint8 note);
+
+static void Dsp_Write(SpcPlayer *p, uint8_t reg, uint8 value) {
+  DspRegWriteHistory *hist = p->reg_write_history;
+  if (hist) {
+    if (hist->count < 256) {
+      hist->addr[hist->count] = reg;
+      hist->val[hist->count] = value;
+      hist->count++;
+    }
+  }
+  if (p->dsp)
+    dsp_write(p->dsp, reg, value);
+}
+
+static void Not_Implemented() {
+  assert(0);
+  printf("Not Implemented\n");
+}
+
+static uint16 SpcDivHelper(int a, uint8 b) {
+  int org_a = a;
+  if (a & 0x100)
+    a = -a;
+  int q = b ? (a & 0xff) / b : 0xff;
+  int r = b ? (a & 0xff) % b : (a & 0xff);
+  int t = (q << 8) + (b ? ((r << 8) / b & 0xff) : 0xff);
+  return (org_a & 0x100) ? -t : t;
+}
+
+static inline void Chan_DoAnyFade(uint16 *p, uint16 add, uint8 target, uint8 cont) {
+  if (!cont)
+    *p = target << 8;
+  else
+    *p += add;
+}
+
+static void SetupEchoParameter_EDL(SpcPlayer *p, uint8 a) {
+  p->echo_parameter_EDL = a;
+  if (a != p->last_written_edl) {
+    a = (p->last_written_edl & 0xf) ^ 0xff;
+    if (p->echo_stored_time & 0x80)
+      a += p->echo_stored_time;
+    p->echo_stored_time = a;
+
+    Dsp_Write(p, EON, 0);
+    Dsp_Write(p, EFB, 0);
+    Dsp_Write(p, EVOLR, 0);
+    Dsp_Write(p, EVOLL, 0);
+    Dsp_Write(p, FLG, p->reg_FLG | 0x20);
+
+    p->last_written_edl = p->echo_parameter_EDL;
+    Dsp_Write(p, EDL, p->echo_parameter_EDL);
+  }
+  Dsp_Write(p, ESA, (p->echo_parameter_EDL * 8 ^ 0xff) + 0xd1);
+}
+
+static void WriteVolumeToDsp(SpcPlayer *p, Channel *c, uint16 volume) {
+  static const uint8 kVolumeTable[22] = {0, 1, 3, 7, 13, 21, 30, 41, 52, 66, 81, 94, 103, 110, 115, 119, 122, 124, 125, 126, 127, 127};
+  if (p->is_chan_on & p->cur_chan_bit)
+    return;
+  for (int i = 0; i < 2; i++) {
+    int j = volume >> 8;
+    uint8 t;
+    if (j >= 21) {
+      t = p->ram[j + 0x1178] + ((p->ram[j + 0x1179] - p->ram[j + 0x1178]) * (uint8)volume >> 8);
+    } else {
+      t = kVolumeTable[j] + ((kVolumeTable[j + 1] - kVolumeTable[j]) * (uint8)volume >> 8);
+    }
+    
+     
+    t = t * c->final_volume >> 8;
+    if ((c->pan_flag_with_phase_invert << i) & 0x80)
+      t = -t;
+    Dsp_Write(p, V0VOLL + i + c->index * 16, t);
+    volume = 0x1400 - volume;
+  }
+}
+
+static void WritePitch(SpcPlayer *p, Channel *c, uint16 pitch) {
+  static const uint16 kBaseNoteFreqs[13] = {2143, 2270, 2405, 2548, 2700, 2860, 3030, 3211, 3402, 3604, 3818, 4045, 4286};
+  if ((pitch >> 8) >= 0x34) {
+    pitch += (pitch >> 8) - 0x34;
+  } else if ((pitch >> 8) < 0x13) {
+    pitch += (uint8)(((pitch >> 8) - 0x13) * 2) - 256;
+  }
+
+  uint8 pp = (pitch >> 8) & 0x7f;
+  uint8 q = pp / 12, r = pp % 12;
+  uint16 t = kBaseNoteFreqs[r] + ((uint8)(kBaseNoteFreqs[r + 1] - kBaseNoteFreqs[r]) * (uint8)pitch >> 8);
+  t *= 2;
+  while (q != 6)
+    t >>= 1, q++;
+
+  t = c->instrument_pitch_base * t >> 8;
+  if (!(p->cur_chan_bit & p->is_chan_on)) {
+    uint8 reg = c->index * 16;
+    Dsp_Write(p, reg + V0PITCHL, t & 0xff);
+    Dsp_Write(p, reg + V0PITCHH, t >> 8);
+  }
+}
+
+static void Music_ResetChan(SpcPlayer *p) {
+  Channel *c = &p->channel[7];
+  p->cur_chan_bit = 0x80;
+  do {
+    HIBYTE(c->channel_volume) = 0xff;
+    c->pan_flag_with_phase_invert = 10;
+    c->pan_value = 10 << 8;
+    c->instrument_id = 0;
+    c->fine_tune = 0;
+    c->channel_transposition = 0;
+    c->pitch_envelope_num_ticks = 0;
+    c->vib_depth = 0;
+    c->tremolo_depth = 0;
+  } while (c--, p->cur_chan_bit >>= 1);
+  p->master_volume_fade_ticks = 0;
+  p->echo_volume_fade_ticks = 0;
+  p->tempo_fade_num_ticks = 0;
+  p->global_transposition = 0;
+  p->block_count = 0;
+  p->percussion_base_id = 0;
+  HIBYTE(p->master_volume) = 0xc0;
+  HIBYTE(p->tempo) = 0x20;
+}
+
+static void Channel_SetInstrument(SpcPlayer *p, Channel *c, uint8 instrument) {
+  c->instrument_id = instrument;
+  if (instrument & 0x80)
+    instrument = instrument + 54 + p->percussion_base_id;
+  const uint8 *ip = p->ram + instrument * 6 + 0x3d00;
+  if (p->is_chan_on & p->cur_chan_bit)
+    return;
+  uint8 reg = c->index * 16;
+  if (ip[0] & 0x80) {
+    // noise
+    p->reg_FLG = (p->reg_FLG & 0x20) | ip[0] & 0x1f;
+    p->reg_NON |= p->cur_chan_bit;
+    Dsp_Write(p, reg + V0SRCN, 0);
+  } else {
+    Dsp_Write(p, reg + V0SRCN, ip[0]);
+  }
+  Dsp_Write(p, reg + V0ADSR1, ip[1]);
+  Dsp_Write(p, reg + V0ADSR2, ip[2]);
+  Dsp_Write(p, reg + V0GAIN, ip[3]);
+  c->instrument_pitch_base = ip[4] << 8 | ip[5];
+}
+
+static void ComputePitchAdd(Channel *c, uint8 pitch) {
+  c->pitch_target = pitch & 0x7f;
+  c->pitch_add_per_tick = SpcDivHelper(c->pitch_target - (c->pitch >> 8), c->pitch_slide_length);
+}
+
+static void PitchSlideToNote_Check(SpcPlayer *p, Channel *c) {
+  if (c->pitch_slide_length || p->ram[c->pattern_order_ptr_for_chan] != 0xf9)
+    return;
+
+  if (p->cur_chan_bit & p->is_chan_on) {
+    c->pattern_order_ptr_for_chan += 4;
+    return;
+  }
+  c->pattern_order_ptr_for_chan++;
+  c->pitch_slide_delay_left = p->ram[c->pattern_order_ptr_for_chan++];
+  c->pitch_slide_length = p->ram[c->pattern_order_ptr_for_chan++];
+  ComputePitchAdd(c, p->ram[c->pattern_order_ptr_for_chan++] + p->global_transposition + c->channel_transposition);
+}
+
+static const uint8 kEffectByteLength[27] = {1, 1, 2, 3, 0, 1, 2, 1, 2, 1, 1, 3, 0, 1, 2, 3, 1, 3, 3, 0, 1, 3, 0, 3, 3, 3, 1};
+
+static void HandleEffect(SpcPlayer *p, Channel *c, uint8 effect) {
+  uint8 arg = kEffectByteLength[effect - 0xe0] ? p->ram[c->pattern_order_ptr_for_chan++] : 0;
+
+  switch (effect) {
+  case 0xe0:
+    Channel_SetInstrument(p, c, arg);
+    break;
+  case 0xe1:
+    c->pan_flag_with_phase_invert = arg;
+    c->pan_value = (arg & 0x1f) << 8;
+    break;
+  case 0xe2:
+    c->pan_num_ticks = arg;
+    c->pan_target_value = p->ram[c->pattern_order_ptr_for_chan++];
+    c->pan_add_per_tick = SpcDivHelper(c->pan_target_value - (c->pan_value >> 8), arg);
+    break;
+  case 0xe3: // vibrato on
+    c->vibrato_delay_ticks = arg;
+    c->vibrato_rate = p->ram[c->pattern_order_ptr_for_chan++];
+    c->vibrato_depth_target = c->vib_depth = p->ram[c->pattern_order_ptr_for_chan++];
+    c->vibrato_fade_num_ticks = 0;
+    break;
+  case 0xe4: // vibrato off
+    c->vibrato_depth_target = c->vib_depth = 0;
+    c->vibrato_fade_num_ticks = 0;
+    break;
+  case 0xe5:
+    if (!p->pause_music_ctr && !p->byte_3E1)
+      p->master_volume = arg << 8;
+    break;
+  case 0xe6:
+    p->master_volume_fade_ticks = arg;
+    p->master_volume_fade_target = p->ram[c->pattern_order_ptr_for_chan++];
+    p->master_volume_fade_add_per_tick = SpcDivHelper(p->master_volume_fade_target - (p->master_volume >> 8), arg);
+    break;
+  case 0xe7:
+    p->tempo = arg << 8;
+    break;
+  case 0xe8:
+    p->tempo_fade_num_ticks = arg;
+    p->tempo_fade_final = p->ram[c->pattern_order_ptr_for_chan++];
+    p->tempo_fade_add = SpcDivHelper(p->tempo_fade_final - (p->tempo >> 8), arg);
+    break;
+  case 0xe9:
+    p->global_transposition = arg;
+    break;
+  case 0xea:
+    c->channel_transposition = arg;
+    break;
+  case 0xeb:
+    c->tremolo_delay_ticks = arg;
+    c->tremolo_rate = p->ram[c->pattern_order_ptr_for_chan++];
+    c->tremolo_depth = p->ram[c->pattern_order_ptr_for_chan++];
+    break;
+  case 0xec:
+    c->tremolo_depth = 0;
+    break;
+  case 0xed:
+    c->channel_volume = arg << 8;
+    break;
+  case 0xee:
+    c->volume_fade_ticks = arg;
+    c->volume_fade_target = p->ram[c->pattern_order_ptr_for_chan++];
+    c->volume_fade_addpertick = SpcDivHelper(c->volume_fade_target - (c->channel_volume >> 8), arg);
+    break;
+  case 0xef:
+    c->pattern_start_ptr = p->ram[c->pattern_order_ptr_for_chan++] << 8 | arg;
+    c->subroutine_num_loops = p->ram[c->pattern_order_ptr_for_chan++];
+    c->saved_pattern_ptr = c->pattern_order_ptr_for_chan;
+    c->pattern_order_ptr_for_chan = c->pattern_start_ptr;
+    break;
+  case 0xf0:
+    c->vibrato_fade_num_ticks = arg;
+    c->vibrato_fade_add_per_tick = arg ? c->vib_depth / arg : 0xff;
+    break;
+  case 0xf4:
+    c->fine_tune = arg;
+    break;
+  case 0xf5:
+    p->reg_EON = p->echo_channels = arg;
+    p->echo_volume_left = p->ram[c->pattern_order_ptr_for_chan++] << 8;
+    p->echo_volume_right = p->ram[c->pattern_order_ptr_for_chan++] << 8;
+    p->reg_FLG &= ~0x20;
+    break;
+  case 0xf6:  // echo off
+    p->echo_volume_left = 0;
+    p->echo_volume_right = 0;
+    p->reg_FLG |= 0x20;
+    break;
+  case 0xf7: {
+    static const int8_t kEchoFirParameters[] = {
+      127, 0, 0, 0, 0, 0, 0, 0,
+      88, -65, -37, -16, -2, 7, 12, 12,
+      12, 33, 43, 43, 19, -2, -13, -7,
+      52, 51, 0, -39, -27, 1, -4, -21,
+    };
+    SetupEchoParameter_EDL(p, arg);
+    p->reg_EFB = p->ram[c->pattern_order_ptr_for_chan++];
+    const int8_t *ep = kEchoFirParameters + p->ram[c->pattern_order_ptr_for_chan++] * 8;
+    for (int i = 0; i < 8; i++)
+      Dsp_Write(p, FIR0 + i * 16, *ep++);
+    break;
+  }
+  case 0xf8:
+    p->echo_volume_fade_ticks = arg;
+    p->echo_volume_fade_target_left = p->ram[c->pattern_order_ptr_for_chan++];
+    p->echo_volume_fade_target_right = p->ram[c->pattern_order_ptr_for_chan++];
+    p->echo_volume_fade_add_left = SpcDivHelper(p->echo_volume_fade_target_left - (p->echo_volume_left >> 8), arg);
+    p->echo_volume_fade_add_right = SpcDivHelper(p->echo_volume_fade_target_right - (p->echo_volume_right >> 8), arg);
+    break;
+  case 0xf9:
+    c->pitch_slide_delay_left = arg;
+    c->pitch_slide_length = p->ram[c->pattern_order_ptr_for_chan++];
+    ComputePitchAdd(c, p->ram[c->pattern_order_ptr_for_chan++] + p->global_transposition + c->channel_transposition);
+    break;
+  case 0xfa:
+    p->percussion_base_id = arg;
+    break;
+  default:
+    Not_Implemented();
+  }
+}
+
+static bool WantWriteKof(SpcPlayer *p, Channel *c) {
+  int loops = c->subroutine_num_loops;
+  int ptr = c->pattern_order_ptr_for_chan;
+
+  for (;;) {
+    uint8 cmd = p->ram[ptr++];
+    if (cmd == 0) {
+      if (loops == 0)
+        return true;
+      ptr = (--loops == 0) ? c->saved_pattern_ptr : c->pattern_start_ptr;
+    } else {
+      while (!(cmd & 0x80))
+        cmd = p->ram[ptr++];
+      if (cmd == 0xc8)
+        return false;
+      if (cmd == 0xef) {
+        ptr = p->ram[ptr + 0] | p->ram[ptr + 1] << 8;
+      } else if (cmd >= 0xe0) {
+        ptr += kEffectByteLength[cmd - 0xe0];
+      } else {
+        return true;
+      }
+    }
+  }
+}
+
+static void HandleTremolo(SpcPlayer *p, Channel *c) {
+  Not_Implemented();
+}
+
+static void CalcVibratoAddPitch(SpcPlayer *p, Channel *c, uint16 pitch, uint8 value) {
+  int t = value << 2;
+  t ^= (t & 0x100) ? 0xff : 0;
+  int r = (c->vib_depth >= 0xf1) ?
+      (uint8)t * (c->vib_depth & 0xf) :
+      (uint8)t * c->vib_depth >> 8;
+  WritePitch(p, c, pitch + (value & 0x80 ? -r : r));
+}
+
+static void HandlePanAndSweep(SpcPlayer *p, Channel *c) {
+  p->did_affect_volumepitch_flag = 0;
+  if (c->tremolo_depth) {
+    c->tremolo_hold_count = c->tremolo_delay_ticks;
+    HandleTremolo(p, c);
+  }
+
+  uint16 volume = c->pan_value;
+
+  if (c->pan_num_ticks) {
+    p->did_affect_volumepitch_flag = 0x80;
+    volume += p->main_tempo_accum * (int16_t)c->pan_add_per_tick / 256;
+  }
+
+  if (p->did_affect_volumepitch_flag)
+    WriteVolumeToDsp(p, c, volume);
+
+  p->did_affect_volumepitch_flag = 0;
+  uint16 pitch = c->pitch;
+  if (c->pitch_slide_length && !c->pitch_slide_delay_left) {
+    p->did_affect_volumepitch_flag |= 0x80;
+    pitch += p->main_tempo_accum * (int16_t)c->pitch_add_per_tick / 256;
+  }
+
+  if (c->vib_depth && c->vibrato_delay_ticks == c->vibrato_hold_count) {
+    CalcVibratoAddPitch(p, c, pitch, (p->main_tempo_accum * c->vibrato_rate >> 8) + c->vibrato_count);
+    return;
+  }
+
+  if (p->did_affect_volumepitch_flag)
+    WritePitch(p, c, pitch);
+}
+
+static void HandleNoteTick(SpcPlayer *p, Channel *c) {
+  if (c->note_keyoff_ticks_left != 0 && (--c->note_keyoff_ticks_left == 0 || c->note_ticks_left == 2)) {
+    if (WantWriteKof(p, c) && !(p->cur_chan_bit & p->is_chan_on))
+      Dsp_Write(p, KOF, p->cur_chan_bit);
+  }
+
+  p->did_affect_volumepitch_flag = 0;
+  if (c->pitch_slide_length) {
+    if (c->pitch_slide_delay_left) {
+      c->pitch_slide_delay_left--;
+    } else if (!(p->is_chan_on & p->cur_chan_bit)) {
+      p->did_affect_volumepitch_flag = 0x80;
+      Chan_DoAnyFade(&c->pitch, c->pitch_add_per_tick, c->pitch_target, --c->pitch_slide_length);
+    }
+  }
+
+  uint16 pitch = c->pitch;
+
+  if (c->vib_depth) {
+    if (c->vibrato_delay_ticks == c->vibrato_hold_count) {
+      if (c->vibrato_change_count == c->vibrato_fade_num_ticks) {
+        c->vib_depth = c->vibrato_depth_target;
+      } else {
+        c->vib_depth = (c->vibrato_change_count++ == 0 ? 0 : c->vib_depth) + c->vibrato_fade_add_per_tick;
+      }
+      c->vibrato_count += c->vibrato_rate;
+      CalcVibratoAddPitch(p, c, pitch, c->vibrato_count);
+      return;
+    }
+    c->vibrato_hold_count++;
+  }
+  
+  if (p->did_affect_volumepitch_flag)
+    WritePitch(p, c, pitch);
+}
+
+void CalcFinalVolume(SpcPlayer *p, Channel *c, uint8 vol) {
+  int t = (p->master_volume >> 8) * vol >> 8;
+  t = t * c->channel_volume_master >> 8;
+  t = t * (c->channel_volume >> 8) >> 8;
+  c->final_volume = t * t >> 8;
+}
+
+void CalcTremolo(SpcPlayer *p, Channel *c) {
+  Not_Implemented();
+}
+
+static void Chan_HandleTick(SpcPlayer *p, Channel *c) {
+  if (c->volume_fade_ticks) {
+    c->volume_fade_ticks--;
+    p->vol_dirty |= p->cur_chan_bit;
+    Chan_DoAnyFade(&c->channel_volume, c->volume_fade_addpertick, c->volume_fade_target, true);
+  }
+  if (c->tremolo_depth) {
+    if (c->tremolo_delay_ticks == c->tremolo_hold_count) {
+      p->vol_dirty |= p->cur_chan_bit;
+      if (c->tremolo_count & 0x80 && c->tremolo_depth == 0xff) {
+        c->tremolo_count = 0x80;
+      } else {
+        c->tremolo_count += c->tremolo_rate;
+      }
+      CalcTremolo(p, c);
+    } else {
+      c->tremolo_hold_count++;
+      CalcFinalVolume(p, c, 0xff);
+    }
+  } else {
+    CalcFinalVolume(p, c, 0xff);
+  }
+
+  if (c->pan_num_ticks) {
+    c->pan_num_ticks--;
+    p->vol_dirty |= p->cur_chan_bit;
+    Chan_DoAnyFade(&c->pan_value, c->pan_add_per_tick, c->pan_target_value, true);
+  }
+
+  if (p->vol_dirty & p->cur_chan_bit)
+    WriteVolumeToDsp(p, c, c->pan_value);
+}
+
+static void Port0_HandleMusic(SpcPlayer *p) {
+  Channel *c;
+  uint8 a = p->new_value_from_snes[0];
+  int t;
+
+  if (a == 0) {
+handle_cmd_00:
+    if (p->port_to_snes[0] == 0)
+      return;
+    if (p->pause_music_ctr != 0 && --p->pause_music_ctr == 0)
+      goto HandleCmd_0xf0_PauseMusic;
+    if (p->counter_sf0c == 0)
+      goto label_a;
+    if (--p->counter_sf0c != 0) {
+      Music_ResetChan(p);
+      return;
+    }
+next_phrase:
+    for (;;) {
+      t = WORD(p->ram[p->music_ptr_toplevel]);
+      p->music_ptr_toplevel += 2;
+      if ((t >> 8) != 0)
+        break;
+      if (t == 0)
+        goto HandleCmd_0xf0_PauseMusic;
+      if (t == 0x80) {
+        p->fast_forward = 0x80;
+      } else if (t == 0x81) {
+        p->fast_forward = 0;
+      } else {
+        if (sign8(--p->block_count))
+          p->block_count = t;
+        t = WORD(p->ram[p->music_ptr_toplevel]);
+        p->music_ptr_toplevel += 2;
+        if (p->block_count != 0)
+          p->music_ptr_toplevel = t;
+      }
+    }
+    for (int i = 0; i < 8; i++)
+      p->channel[i].pattern_order_ptr_for_chan = WORD(p->ram[t]), t += 2;
+
+    c = p->channel, p->cur_chan_bit = 1;
+    do {
+      if (HIBYTE(c->pattern_order_ptr_for_chan) && c->instrument_id == 0)
+        Channel_SetInstrument(p, c, 0);
+      c->subroutine_num_loops = 0;
+      c->volume_fade_ticks = 0;
+      c->pan_num_ticks = 0;
+      c->note_ticks_left = 1;
+    } while (c++, p->cur_chan_bit <<= 1);
+label_a:
+    p->vol_dirty = 0;
+    c = p->channel, p->cur_chan_bit = 1;
+    do {
+      if (!HIBYTE(c->pattern_order_ptr_for_chan))
+        continue;
+      if (!--c->note_ticks_left) {
+        for (;;) {
+          uint8 cmd = p->ram[c->pattern_order_ptr_for_chan++];
+          if (cmd == 0) {
+            if (!c->subroutine_num_loops)
+              goto next_phrase;
+            c->pattern_order_ptr_for_chan = (--c->subroutine_num_loops == 0) ? c->saved_pattern_ptr : c->pattern_start_ptr;
+            continue;
+          }
+          if (!(cmd & 0x80)) {
+            static const uint8 kNoteVol[16] = { 25, 50, 76, 101, 114, 127, 140, 152, 165, 178, 191, 203, 216, 229, 242, 252 };
+            static const uint8 kNoteGateOffPct[8] = { 50, 101, 127, 152, 178, 203, 229, 252 };
+            c->note_length = cmd;
+            cmd = p->ram[c->pattern_order_ptr_for_chan++];
+            if (!(cmd & 0x80)) {
+              c->note_gate_off_fixedpt = kNoteGateOffPct[cmd >> 4 & 7];
+              c->channel_volume_master = kNoteVol[cmd & 0xf];
+              cmd = p->ram[c->pattern_order_ptr_for_chan++];
+            }
+          }
+          if (cmd >= 0xe0) {
+            HandleEffect(p, c, cmd); 
+            continue;
+          }
+          if (!p->fast_forward && !(p->is_chan_on & p->cur_chan_bit))
+            PlayNote(p, c, cmd);
+          c->note_ticks_left = c->note_length;
+          t = c->note_ticks_left * c->note_gate_off_fixedpt >> 8;
+          c->note_keyoff_ticks_left = (t != 0) ? t : 1;
+          PitchSlideToNote_Check(p, c);
+          break;
+        }
+      } else if (!p->fast_forward) {
+        HandleNoteTick(p, c);
+        PitchSlideToNote_Check(p, c);
+      }
+    } while (c++, p->cur_chan_bit <<= 1);
+    if (p->tempo_fade_num_ticks)
+      p->tempo = (--p->tempo_fade_num_ticks == 0) ? p->tempo_fade_final << 8 : p->tempo + p->tempo_fade_add;
+    if (p->echo_volume_fade_ticks) {
+      p->echo_volume_left += p->echo_volume_fade_add_left;
+      p->echo_volume_right += p->echo_volume_fade_add_right;
+      if (--p->echo_volume_fade_ticks == 0) {
+        p->echo_volume_left = p->echo_volume_fade_target_left << 8;
+        p->echo_volume_right = p->echo_volume_fade_target_right << 8;
+      }
+    }
+    if (p->master_volume_fade_ticks) {
+      p->master_volume = (--p->master_volume_fade_ticks == 0) ? p->master_volume_fade_target << 8 : p->master_volume + p->master_volume_fade_add_per_tick;
+      p->vol_dirty = 0xff;
+    }
+    c = p->channel, p->cur_chan_bit = 1;
+    do {
+      if (HIBYTE(c->pattern_order_ptr_for_chan))
+        Chan_HandleTick(p, c);
+    } while (c++, p->cur_chan_bit <<= 1);
+  } else if (a == 0xff) {
+    // Load new music
+    Not_Implemented();
+  } else if (a == 0xf1) { // continue music
+    p->master_volume_fade_ticks = 0x80;
+    p->pause_music_ctr = 0x80;
+    p->master_volume_fade_target = 0;
+    p->master_volume_fade_add_per_tick = SpcDivHelper(0 - (p->master_volume >> 8), 0x80);
+
+    goto handle_cmd_00;
+  } else if (a == 0xf2) {
+    if (p->byte_3E1 != 0)
+      return;
+    p->byte_3E1 = HIBYTE(p->master_volume);
+    HIBYTE(p->master_volume) = 0x70;
+    goto handle_cmd_00;
+  } else if (a == 0xf3) {
+    if (p->byte_3E1 == 0)
+      return;
+    HIBYTE(p->master_volume) = p->byte_3E1;
+    p->byte_3E1 = 0;
+    goto handle_cmd_00;
+  } else if (a == 0xf0) HandleCmd_0xf0_PauseMusic: {
+    p->key_OFF = p->is_chan_on ^ 0xff;
+    p->port_to_snes[0] = 0;
+    p->cur_chan_bit = 0;
+  } else {
+    p->pause_music_ctr = 0;
+    p->byte_3E1 = 0;
+    p->port_to_snes[0] = a;
+    p->music_ptr_toplevel = WORD(p->ram[0xD000 + (a - 1) * 2]);
+    p->counter_sf0c = 2;
+    p->key_OFF |= p->is_chan_on ^ 0xff;
+  }
+
+}
+
+static inline uint8 Asl(uint8 *p) {
+  uint8 old = *p;
+  *p <<= 1;
+  return old >> 7;
+}
+
+static void Sfx_TurnOffChannel(SpcPlayer *p, Channel *c) {
+  c->sfx_which_sound = 0;
+  p->is_chan_on &= ~p->current_bit;
+  p->port1_active &= ~p->current_bit;
+  p->port2_active &= ~p->current_bit;
+  p->port3_active &= ~p->current_bit;
+  Channel_SetInstrument(p, c, c->instrument_id);
+  if (p->echo_channels & p->current_bit && !(p->reg_EON & p->current_bit)) {
+    p->reg_EON |= p->current_bit;
+    Dsp_Write(p, EON, p->reg_EON);
+    p->sfx_channels_echo_mask2 &= ~p->current_bit;
+  }
+}
+
+static void Write_KeyOn(SpcPlayer *p, uint8 bit) {
+  Dsp_Write(p, KOF, 0);
+  Dsp_Write(p, KON, bit);
+}
+
+static void PlayNote(SpcPlayer *p, Channel *c, uint8 note) {
+  if (note >= 0xca) {
+    Channel_SetInstrument(p, c, note);
+    note = 0xa4;
+  }
+
+//  if (c->index == 0) {
+//    if (note == 0xc8) {
+//      printf("-+-\n");
+//    } else if (note == 0xc9) {
+//      printf("---\n");
+//    }
+//  }
+
+  if (note >= 0xc8 || p->is_chan_on & p->cur_chan_bit)
+    return;
+
+  //static const char *const kNoteNames[] = { "C-", "C#", "D-", "D#", "E-", "F-", "F#", "G-", "G#", "A-", "A#", "B-" };
+  //if (c->index==0)
+  //  printf("%s%d\n", kNoteNames[(note & 0x7f) % 12], (note & 0x7f) / 12 + 1);
+
+  c->pitch = ((note & 0x7f) + p->global_transposition + c->channel_transposition) << 8 | c->fine_tune;
+  c->vibrato_count = c->vibrato_fade_num_ticks << 7;
+  c->vibrato_hold_count = 0;
+  c->vibrato_change_count = 0;
+  c->tremolo_count = 0;
+  c->tremolo_hold_count = 0;
+  p->vol_dirty |= p->cur_chan_bit;
+  p->key_ON |= p->cur_chan_bit;
+  c->pitch_slide_length = c->pitch_envelope_num_ticks;
+  if (c->pitch_slide_length) {
+    c->pitch_slide_delay_left = c->pitch_envelope_delay;
+    if (!c->pitch_envelope_direction)
+      c->pitch -= c->pitch_envelope_slide_value << 8;
+    ComputePitchAdd(c, (c->pitch >> 8) + c->pitch_envelope_slide_value);
+  }
+  WritePitch(p, c, c->pitch);
+}
+
+static void Sfx_MaybeDisableEcho(SpcPlayer *p) {
+  if (!(p->port_to_snes[0] & 0x10) || p->current_bit & p->sfx_channels_echo_mask2) {
+    if (p->current_bit & p->reg_EON) {
+      p->reg_EON ^= p->current_bit;
+      Dsp_Write(p, EON, p->reg_EON);
+    }
+  }
+}
+
+static void Sfx_ChannelTick(SpcPlayer *p, Channel *c, bool is_continue) {
+  uint8 cmd;
+
+  if (is_continue) {
+    Sfx_MaybeDisableEcho(p);
+    p->sfx_channel_index = c->index * 2;
+    p->sfx_sound_ptr_cur = c->sfx_sound_ptr;
+    if (--c->sfx_note_length_left)
+      goto note_continue;
+    p->sfx_sound_ptr_cur++;
+  }
+
+  for (;;) {
+    p->dsp_register_index = p->sfx_channel_index * 8;
+
+    cmd = p->ram[p->sfx_sound_ptr_cur];
+    if (cmd == 0) {
+      Sfx_TurnOffChannel(p, c);
+      return;
+    }
+
+    if (!(cmd & 0x80)) {
+      c->sfx_note_length = cmd;
+      cmd = p->ram[++p->sfx_sound_ptr_cur];
+      if (!(cmd & 0x80)) {
+        if (p->port1_active & p->current_bit) {
+          if (cmd == 0 || !p->channel_67_volume) {
+            uint8 volume = cmd;
+            Dsp_Write(p, p->dsp_register_index + V0VOLL, cmd);
+            cmd = p->ram[++p->sfx_sound_ptr_cur];
+            if (cmd & 0x80) {
+              Dsp_Write(p, p->dsp_register_index + V0VOLR, volume);
+            } else {
+              Dsp_Write(p, p->dsp_register_index + V0VOLR, cmd);
+              cmd = p->ram[++p->sfx_sound_ptr_cur];
+            }
+          } else {
+            cmd = p->ram[++p->sfx_sound_ptr_cur];
+          }
+        } else {
+          c->final_volume = cmd * 2;
+          c->pan_flag_with_phase_invert = 10;
+          WriteVolumeToDsp(p, c, (p->sfx_start_arg_pan & 0x80 ? 16 : p->sfx_start_arg_pan & 0x40 ? 4 : 10) << 8);
+          cmd = p->ram[++p->sfx_sound_ptr_cur];
+        }
+      }
+    }
+    // cmd_parsed
+    if (cmd == 0xe0) {
+      const uint8 *ip = p->ram + 0x3E00 + (p->ram[++p->sfx_sound_ptr_cur] * 9);
+      uint8 reg = c->index * 16;
+      Dsp_Write(p, reg + V0VOLL, ip[0]);
+      Dsp_Write(p, reg + V0VOLR, ip[1]);
+      Dsp_Write(p, reg + V0PITCHL, ip[2]);
+      Dsp_Write(p, reg + V0PITCHH, ip[3]);
+      Dsp_Write(p, reg + V0SRCN, ip[4]);
+      Dsp_Write(p, reg + V0ADSR1, ip[5]);
+      Dsp_Write(p, reg + V0ADSR2, ip[6]);
+      Dsp_Write(p, reg + V0GAIN, ip[7]);
+      c->instrument_pitch_base = ip[8] << 8;
+      p->sfx_sound_ptr_cur++;
+    } else if (cmd == 0xf9 || cmd == 0xf1) {
+      if (cmd == 0xf9) {
+        PlayNote(p, c, p->ram[++p->sfx_sound_ptr_cur]);
+        Write_KeyOn(p, p->current_bit);
+      }
+      c->pitch_slide_delay_left = p->ram[++p->sfx_sound_ptr_cur];
+      c->pitch_slide_length = p->ram[++p->sfx_sound_ptr_cur];
+      ComputePitchAdd(c, p->ram[++p->sfx_sound_ptr_cur]);
+      c->sfx_note_length_left = c->sfx_note_length;
+      goto note_continue;
+    } else if (cmd == 0xff) {
+      p->sfx_sound_ptr_cur = c->sfx_sound_ptr = WORD(p->ram[0x17C0 + (c->sfx_which_sound - 1) * 2]);
+    } else {
+      PlayNote(p, c, cmd);
+      Write_KeyOn(p, p->current_bit);
+      c->sfx_note_length_left = c->sfx_note_length;
+note_continue:
+      p->did_affect_volumepitch_flag = 0;
+      if (c->pitch_slide_length) {
+        p->did_affect_volumepitch_flag = 0x80;
+        Chan_DoAnyFade(&c->pitch, c->pitch_add_per_tick, c->pitch_target, --c->pitch_slide_length);
+        p->cur_chan_bit = 0;  // force change through
+        WritePitch(p, c, c->pitch);
+      } else if (c->sfx_note_length_left == 2) {
+        Dsp_Write(p, KOF, p->current_bit);
+      }
+      break;
+    }
+  }
+  c->sfx_sound_ptr = p->sfx_sound_ptr_cur;
+}
+
+static void Port1_Play_Inner(SpcPlayer *p) {
+  p->port1_counter = 0;
+  Channel *c = &p->channel[7];
+  c->sfx_which_sound = p->new_value_from_snes[1];
+  c->sfx_arr_countdown = 3;
+  c->pitch_envelope_num_ticks = 0;
+  p->port1_active = 0x80;
+  p->is_chan_on |= 0x80;
+  Dsp_Write(p, KOF, 0x80);
+  p->new_value_from_snes[1] = p->ram[0x1800 + p->new_value_from_snes[1] - 1];
+  if (!p->new_value_from_snes[1])
+    return;
+  c--;
+  c->sfx_which_sound = p->new_value_from_snes[1];
+  c->sfx_arr_countdown = 3;
+  c->pitch_envelope_num_ticks = 0;
+  p->port1_active = 0x40;
+  p->is_chan_on |= 0x40;
+  Dsp_Write(p, KOF, 0x40);
+  p->port1_active = 0xc0;
+  p->sfx_channels_echo_mask2 |= 0xc0;
+  p->port2_active &= 0x3f;
+  p->port3_active &= 0x3f;
+}
+
+static void Port1_StartNewSound(SpcPlayer *p) {
+  if (p->port1_counter != 0) {
+    if (--p->port1_counter == 0) {
+      p->new_value_from_snes[1] = 5;
+      Port1_Play_Inner(p);
+      p->new_value_from_snes[1] = 0;
+      return;
+    }
+    p->channel_67_volume = p->port1_counter >> 1;
+    Dsp_Write(p, V7VOLL, p->channel_67_volume);
+    Dsp_Write(p, V7VOLR, p->channel_67_volume);
+    Dsp_Write(p, V6VOLL, p->channel_67_volume);
+    Dsp_Write(p, V6VOLR, p->channel_67_volume);
+  }
+  p->port1_current_bit = p->port1_active;
+  if (!p->port1_current_bit)
+    return;
+  Channel *c = &p->channel[7];
+  p->current_bit = 0x80;
+  do {
+    if (Asl(&p->port1_current_bit)) {
+      p->sfx_channel_index = c->index * 2;
+      p->dsp_register_index = c->index * 16;
+      p->sfx_start_arg_pan = c->sfx_pan;
+      if (!c->sfx_arr_countdown) {
+        if (c->sfx_which_sound)
+          Sfx_ChannelTick(p, c, true);
+      } else {
+        p->sfx_channel_index = c->index * 2;
+        if (!--c->sfx_arr_countdown) {
+          p->sfx_sound_ptr_cur = c->sfx_sound_ptr = WORD(p->ram[0x17C0 + (c->sfx_which_sound - 1) * 2]);
+          Sfx_ChannelTick(p, c, false);
+        }
+      }
+    }
+  } while (c--, (p->current_bit >>= 1) != 0x10);
+}
+
+static void Port1_HandleCmd(SpcPlayer *p) {
+  uint8 a = p->new_value_from_snes[1];
+  if (!(a & 0x80)) {
+    if (a != 0) {
+      p->port_to_snes[1] = a;
+      if (a != 5 || p->port1_active)
+        Port1_Play_Inner(p);
+    }
+  } else {  
+    p->port_to_snes[1] = a;
+    if (p->port1_active)
+      p->port1_counter = 0x78;
+  }
+}
+
+static void Port2_StartNewSound(SpcPlayer *p) {
+  p->port2_current_bit = p->port2_active;
+  if (!p->port2_current_bit)
+    return;
+  Channel *c = &p->channel[7];
+  p->current_bit = 0x80;
+  do {
+    if (Asl(&p->port2_current_bit)) {
+      p->sfx_channel_index = c->index * 2;
+      p->dsp_register_index = c->index * 16;
+      p->sfx_start_arg_pan = c->sfx_pan;
+      if (!c->sfx_arr_countdown) {
+        if (c->sfx_which_sound)
+          Sfx_ChannelTick(p, c, true);
+      } else {
+        p->sfx_channel_index = c->index * 2;
+        if (!--c->sfx_arr_countdown) {
+          p->sfx_sound_ptr_cur = c->sfx_sound_ptr = WORD(p->ram[0x1820 + (c->sfx_which_sound - 1) * 2]);
+          Sfx_ChannelTick(p, c, false);
+        }
+      }
+    }
+  } while (c--, p->current_bit >>= 1);
+}
+
+static Channel *Port2_AllocateChan(SpcPlayer *p) {
+  p->sfx_play_echo_flag = p->ram[0x18dd + (p->new_value_from_snes[2] & 0x3f) - 1];
+  Channel *c = &p->channel[7];
+  p->current_bit = 0x80;
+  do {
+    if (p->port2_active & p->current_bit && c->sfx_which_sound + c->sfx_pan == p->new_value_from_snes[2])
+      goto found_channel;
+  } while (c--, p->current_bit >>= 1);
+  c = &p->channel[7];
+  p->current_bit = 0x80;
+  do {
+    if (!(p->is_chan_on & p->current_bit))
+      goto found_channel;
+  } while (c--, p->current_bit >>= 1);
+  assert(0);  // unreachable
+found_channel:
+  p->sfx_channel_index2 = p->sfx_channel_index = c->index * 2;
+  p->sfx_channel_bit = p->current_bit;
+  p->is_chan_on |= p->current_bit;
+  if (p->sfx_play_echo_flag)
+    p->sfx_channels_echo_mask2 |= p->current_bit;
+  Sfx_MaybeDisableEcho(p);
+  return c;
+}
+
+static void Port2_HandleCmd(SpcPlayer *p) {
+  while (p->new_value_from_snes[2] != 0 && p->is_chan_on != 0xff) {
+    Channel *c = Port2_AllocateChan(p);
+    c->sfx_pan = p->new_value_from_snes[2] & 0xc0;
+    c->sfx_which_sound = p->new_value_from_snes[2] & 0x3f;
+    c->sfx_arr_countdown = 3;
+    c->pitch_envelope_num_ticks = 0;
+    p->port2_active |= p->current_bit;
+    Dsp_Write(p, KOF, p->current_bit);
+    p->new_value_from_snes[2] = p->ram[0x189e + c->sfx_which_sound - 1];
+  }
+}
+
+
+static void Port3_StartNewSound(SpcPlayer *p) {
+  p->port3_current_bit = p->port3_active;
+  if (!p->port3_current_bit)
+    return;
+  Channel *c = &p->channel[7];
+  p->current_bit = 0x80;
+  do {
+    if (Asl(&p->port3_current_bit)) {
+      p->sfx_channel_index = c->index * 2;
+      p->dsp_register_index = c->index * 16;
+      p->sfx_start_arg_pan = c->sfx_pan;
+      if (!c->sfx_arr_countdown) {
+        if (c->sfx_which_sound)
+          Sfx_ChannelTick(p, c, true);
+      } else {
+        p->sfx_channel_index = c->index * 2;
+        if (!--c->sfx_arr_countdown) {
+          p->sfx_sound_ptr_cur = c->sfx_sound_ptr = WORD(p->ram[0x191C + (c->sfx_which_sound - 1) * 2]);
+          Sfx_ChannelTick(p, c, false);
+        }
+      }
+    }
+  } while (c--, p->current_bit >>= 1);
+}
+
+static Channel *Port3_AllocateChan(SpcPlayer *p) {
+  p->sfx_play_echo_flag = p->ram[0x19d8 + (p->new_value_from_snes[3] & 0x3f)];
+  Channel *c = &p->channel[7];
+  p->current_bit = 0x80;
+  do {
+    if (p->port3_active & p->current_bit && c->sfx_which_sound + c->sfx_pan == p->new_value_from_snes[3])
+      goto found_channel;
+  } while (c--, p->current_bit >>= 1);
+  c = &p->channel[7];
+  p->current_bit = 0x80;
+  do {
+    if (!(p->is_chan_on & p->current_bit))
+      goto found_channel;
+  } while (c--, p->current_bit >>= 1);
+  assert(0);  // unreachable
+found_channel:
+  p->sfx_channel_index2 = p->sfx_channel_index = c->index * 2;
+  p->sfx_channel_bit = p->current_bit;
+  p->is_chan_on |= p->current_bit;
+  if (p->sfx_play_echo_flag)
+    p->sfx_channels_echo_mask2 |= p->current_bit;
+  Sfx_MaybeDisableEcho(p);
+  return c;
+}
+
+static void Port3_HandleCmd(SpcPlayer *p) {
+  while (p->new_value_from_snes[3] != 0 && p->is_chan_on != 0xff) {
+    Channel *c = Port3_AllocateChan(p);
+    c->sfx_pan = p->new_value_from_snes[3] & 0xc0;
+    c->sfx_which_sound = p->new_value_from_snes[3] & 0x3f;
+    c->sfx_arr_countdown = 3;
+    c->pitch_envelope_num_ticks = 0;
+    p->port3_active |= p->current_bit;
+    Dsp_Write(p, KOF, p->current_bit);
+    p->new_value_from_snes[3] = p->ram[0x199a + c->sfx_which_sound - 1];
+  }
+}
+
+static void ReadPortFromSnes(SpcPlayer *p, int port) {
+  uint8 old = p->last_value_from_snes[port];
+  p->last_value_from_snes[port] = p->input_ports[port];
+  if (p->input_ports[port] != old)
+    p->new_value_from_snes[port] = p->input_ports[port];
+  else
+    p->new_value_from_snes[port] = 0;
+}
+
+static void Spc_Loop_Part1(SpcPlayer *p) {
+  Dsp_Write(p, KOF, p->key_OFF);
+  Dsp_Write(p, PMON, p->reg_PMON);
+  Dsp_Write(p, NON, p->reg_NON);
+  Dsp_Write(p, KOF, 0);
+  Dsp_Write(p, KON, p->key_ON);
+  if (!(p->echo_stored_time & 0x80)) {
+    Dsp_Write(p, FLG, p->reg_FLG);
+    if (p->echo_stored_time == p->echo_parameter_EDL) {
+      Dsp_Write(p, EON, p->reg_EON);
+      Dsp_Write(p, EFB, p->reg_EFB);
+      Dsp_Write(p, EVOLR, p->echo_volume_right >> 8);
+      Dsp_Write(p, EVOLL, p->echo_volume_left >> 8);
+    }
+  }
+  p->key_OFF = p->key_ON = 0;
+}
+
+static void Spc_Loop_Part2(SpcPlayer *p, uint8 ticks) {
+  int t = p->sfx_timer_accum + (uint8)(ticks * 0x38);
+  p->sfx_timer_accum = t;
+  if (t >= 256) {
+    Port1_StartNewSound(p);
+    Port1_HandleCmd(p);
+    ReadPortFromSnes(p, 1);
+
+    Port2_StartNewSound(p);
+    Port2_HandleCmd(p);
+    ReadPortFromSnes(p, 2);
+
+    Port3_StartNewSound(p);
+    Port3_HandleCmd(p);
+    ReadPortFromSnes(p, 3);
+
+    if (p->echo_stored_time != p->echo_parameter_EDL && !(++p->echo_fract_incr & 1))
+      p->echo_stored_time++;
+  }
+
+  t = p->main_tempo_accum + (uint8)(ticks * HIBYTE(p->tempo));
+  p->main_tempo_accum = t;
+  if (t >= 256) {
+    Port0_HandleMusic(p);
+    ReadPortFromSnes(p, 0);
+  } else if (p->port_to_snes[0]) {
+    Channel *c = p->channel;
+    for (p->cur_chan_bit = 1; p->cur_chan_bit != 0; p->cur_chan_bit <<= 1, c++) {
+      if (HIBYTE(c->pattern_order_ptr_for_chan))
+        HandlePanAndSweep(p, c);
+    }
+  }
+}
+
+static void Interrupt_Reset(SpcPlayer *p) {
+  dsp_reset(p->dsp);
+
+  memset(&p->new_value_from_snes, 0, sizeof(SpcPlayer) - offsetof(SpcPlayer, new_value_from_snes));
+  for (int i = 0; i < 8; i++)
+    p->channel[i].index = i;
+  SetupEchoParameter_EDL(p, 1);
+  p->reg_FLG |= 0x20;
+  Dsp_Write(p, MVOLL, 0x60);
+  Dsp_Write(p, MVOLR, 0x60);
+  Dsp_Write(p, DIR, 0x3c);
+  HIBYTE(p->tempo) = 16;
+  p->timer_cycles = 0;
+}
+
+SpcPlayer *SpcPlayer_Create() {
+  SpcPlayer *p = (SpcPlayer *)malloc(sizeof(SpcPlayer));
+  p->dsp = dsp_init(p->ram);
+  p->reg_write_history = 0;
+  return p;
+}
+
+void SpcPlayer_Initialize(SpcPlayer *p) {
+  Interrupt_Reset(p);
+  Spc_Loop_Part1(p);
+}
+
+void SpcPlayer_CopyVariablesToRam(SpcPlayer *p) {
+  Channel *c = p->channel;
+  for (int i = 0; i < 8; i++, c++) {
+    for (const MemMap *m = &kChannel_Maps[0]; m != &kChannel_Maps[countof(kChannel_Maps)]; m++)
+      memcpy(&p->ram[(m->org_off & 0x7fff) + i * 2], (uint8 *)c + m->off, m->org_off & 0x8000 ? 2 : 1);
+  }
+  for (const MemMapSized *m = &kSpcPlayer_Maps[0]; m != &kSpcPlayer_Maps[countof(kSpcPlayer_Maps)]; m++)
+    memcpy(&p->ram[m->org_off], (uint8 *)p + m->off, m->size);
+}
+
+void SpcPlayer_CopyVariablesFromRam(SpcPlayer *p) {
+  Channel *c = p->channel;
+  for (int i = 0; i < 8; i++, c++) {
+    for (const MemMap *m = &kChannel_Maps[0]; m != &kChannel_Maps[countof(kChannel_Maps)]; m++)
+      memcpy((uint8 *)c + m->off, &p->ram[(m->org_off & 0x7fff) + i * 2], m->org_off & 0x8000 ? 2 : 1);
+  }
+  for (const MemMapSized *m = &kSpcPlayer_Maps[0]; m != &kSpcPlayer_Maps[countof(kSpcPlayer_Maps)]; m++)
+    memcpy((uint8 *)p + m->off, &p->ram[m->org_off], m->size);
+}
+
+
+void SpcPlayer_GenerateSamples(SpcPlayer *p) {
+  assert(p->timer_cycles <= 64);
+
+  assert(p->dsp->sampleOffset <= 534);
+
+  for (;;) {
+    if (p->timer_cycles >= 64) {
+      Spc_Loop_Part2(p, p->timer_cycles >> 6);
+      Spc_Loop_Part1(p);
+      p->timer_cycles &= 63;
+    }
+
+    // sample rate 32000
+    int n = 534 - p->dsp->sampleOffset;
+    if (n > (64 - p->timer_cycles))
+      n = (64 - p->timer_cycles);
+
+    p->timer_cycles += n;
+
+    for (int i = 0; i < n; i++)
+      dsp_cycle(p->dsp);
+
+    if (p->dsp->sampleOffset == 534)
+      break;
+  }
+}
+
+void SpcPlayer_Upload(SpcPlayer *p, const uint8_t *data) {
+  Dsp_Write(p, EVOLL, 0);
+  Dsp_Write(p, EVOLR, 0);
+  Dsp_Write(p, KOF, 0xff);
+
+  for (;;) {
+    int numbytes = *(uint16 *)(data);
+    if (numbytes == 0)
+      break;
+    int target = *(uint16 *)(data + 2);
+    data += 4;
+    do {
+      p->ram[target++ & 0xffff] = *data++;
+    } while (--numbytes);
+  }
+  p->pause_music_ctr = 0;
+  p->port_to_snes[0] = 0;
+  p->port1_active = 0;
+  p->port2_active = 0;
+  p->port3_active = 0;
+  p->is_chan_on = 0;
+  p->input_ports[0] = p->input_ports[1] = p->input_ports[2] = p->input_ports[3] = 0;
+}
+
+// =======================================
+#define WITH_SPC_PLAYER_DEBUGGING 0
+
+#if WITH_SPC_PLAYER_DEBUGGING
+
+#include <SDL.h>
+
+static DspRegWriteHistory my_write_hist;
+static SpcPlayer my_spc, my_spc_snapshot;
+static int loop_ctr;
+
+bool CompareSpcImpls(SpcPlayer *p, SpcPlayer *p_org, Apu *apu) {
+  SpcPlayer_CopyVariablesToRam(p);
+  memcpy(p->ram + 0x18, apu->ram + 0x18, 2); //lfsr_value
+  memcpy(p->ram + 0x110, apu->ram + 0x110, 256-16);  // stack
+  memcpy(p->ram + 0xf1, apu->ram + 0xf1, 15);  // dsp regs
+  memcpy(p->ram + 0x10, apu->ram + 0x10, 8);  // temp regs
+  p->ram[0x44] = apu->ram[0x44]; // chn
+  int errs = 0;
+  for (int i = 0; i != 0xc000; i++) {  // skip compare echo etc
+    if (p->ram[i] != apu->ram[i]) {
+      if (errs < 16) {
+        if (errs == 0)
+          printf("@%d\n", loop_ctr);
+        printf("%.4X: %.2X != %.2X (mine, theirs) orig %.2X\n", i, p->ram[i], apu->ram[i], p_org->ram[i]);
+        errs++;
+      }
+    }
+  }
+
+  int n = my_write_hist.count < apu->hist.count ? apu->hist.count : my_write_hist.count;
+  for (int i = 0; i != n; i++) {
+    if (i >= my_write_hist.count || i >= apu->hist.count || my_write_hist.addr[i] != apu->hist.addr[i] || my_write_hist.val[i] != apu->hist.val[i]) {
+      if (errs == 0)
+        printf("@%d\n", loop_ctr);
+      printf("%d: ", i);
+      if (i >= my_write_hist.count) printf("[??: ??]"); else printf("[%.2x: %.2x]", my_write_hist.addr[i], my_write_hist.val[i]);
+      printf(" != ");
+      if (i >= apu->hist.count) printf("[??: ??]"); else printf("[%.2x: %.2x]", apu->hist.addr[i], apu->hist.val[i]);
+      printf("\n");
+      errs++;
+    }
+  }
+
+  if (errs) {
+    printf("Total %d errors\n", errs);
+    return false;
+  }
+
+  apu->hist.count = 0;
+  my_write_hist.count = 0;
+  loop_ctr++;
+  return true;
+}
+
+void RunAudioPlayer() {
+  if(SDL_Init(SDL_INIT_AUDIO) != 0) {
+    printf("Failed to init SDL: %s\n", SDL_GetError());
+    return;
+  }
+  
+  SDL_AudioSpec want, have;
+  SDL_AudioDeviceID device;
+  SDL_memset(&want, 0, sizeof(want));
+  want.freq = 44100;
+  want.format = AUDIO_S16;
+  want.channels = 2;
+  want.samples = 2048;
+  want.callback = NULL; // use queue
+  device = SDL_OpenAudioDevice(NULL, 0, &want, &have, 0);
+  if(device == 0) {
+    printf("Failed to open audio device: %s\n", SDL_GetError());
+    return;
+  }
+  int16_t* audioBuffer = (int16_t*)malloc(735 * 4); // *2 for stereo, *2 for sizeof(int16)
+  SDL_PauseAudioDevice(device, 0);
+
+  memset(&my_spc, 0, sizeof(my_spc));
+  FILE *f = fopen("lightworld.spc", "rb");
+  fread(my_spc.ram, 1, 65536, f);
+  fclose(f);
+
+  my_spc.reg_write_history = &my_write_hist;
+
+  bool run_both = 0;// false;// false;
+
+  if (!run_both) {
+    SpcPlayer *p = &my_spc;
+    Dsp *dsp = dsp_init(p->ram);
+    dsp_reset(dsp);
+    p->dsp = dsp;
+    SpcPlayer_Initialize(p);
+
+    p->input_ports[0] = 4;
+
+    for (;;) {
+      SpcPlayer_GenerateSamples(p);
+
+      int16_t audioBuffer[736 * 2];
+      dsp_getSamples(p->dsp, audioBuffer, 736, have.channels);
+      SDL_QueueAudio(device, audioBuffer, 736 * 2 * have.channels);
+      while (SDL_GetQueuedAudioSize(device) >= 736 * 4 * 3/* 44100 * 4 * 300*/)
+        SDL_Delay(1);
+
+    }
+
+  } else {
+    SpcPlayer *p = &my_spc;
+    Dsp *dsp = dsp_init(p->ram);
+    dsp_reset(dsp);
+    p->dsp = dsp;
+
+    Apu *apu = apu_init();
+    apu_reset(apu);
+    apu->spc->pc = 0x800;
+
+    memcpy(apu->ram, my_spc.ram, 65536);
+
+    CompareSpcImpls(&my_spc, &my_spc_snapshot, apu);
+
+    uint64_t cycle_counter = 0;
+    int tgt = 0x878;
+    uint8 ticks_next = 0;
+    bool apu_debug = false;
+    bool is_initialize = true;
+    for (;;) {
+      if (apu_debug && apu->cpuCyclesLeft == 0) {
+        char line[80];
+        getProcessorStateSpc(apu, line);
+        puts(line);
+      }
+
+      apu_cycle(apu);
+
+      if (((apu->cycles - 1) & 0x1f) == 0)
+        dsp_cycle(p->dsp);
+
+
+      if (apu->spc->pc == tgt) {
+        tgt ^= 0x878 ^ 0x879;
+        if (tgt == 0x878) {
+          uint8 ticks = ticks_next;
+          ticks_next = apu->spc->y;
+          my_spc_snapshot = my_spc;
+          for (;;) {
+            my_write_hist.count = 0;
+            if (is_initialize)
+              SpcPlayer_Initialize(&my_spc);
+            else {
+              Spc_Loop_Part2(&my_spc, ticks);
+              Spc_Loop_Part1(&my_spc);
+            }
+            is_initialize = false;
+            if (CompareSpcImpls(&my_spc, &my_spc_snapshot,apu))
+              break;
+            my_spc = my_spc_snapshot;
+          }
+
+          if (cycle_counter == 0)
+            apu->inPorts[0] = my_spc.input_ports[0] = 2;// 2 + cycle_counter / 1000;
+          cycle_counter++;
+        }
+      }
+
+      if (p->dsp->sampleOffset == 534) {
+        int16_t audioBuffer[736 * 2];
+        dsp_getSamples(p->dsp, audioBuffer, 736, have.channels);
+        SDL_QueueAudio(device, audioBuffer, 736 * 2 * have.channels);
+        while (SDL_GetQueuedAudioSize(device) >= 736 * 4 * 3/* 44100 * 4 * 300*/) {
+          SDL_Delay(1);
+        }
+      }
+    }
+  }
+}
+#endif  // WITH_SPC_PLAYER_DEBUGGING
\ No newline at end of file
--- /dev/null
+++ b/src/spc_player.h
@@ -1,0 +1,145 @@
+#include <stddef.h>
+#include "snes/dsp.h"
+
+typedef struct Channel {
+  uint16 pattern_order_ptr_for_chan;
+  uint8 note_ticks_left;
+  uint8 note_keyoff_ticks_left;
+  uint8 subroutine_num_loops;
+  uint8 volume_fade_ticks;
+  uint8 pan_num_ticks;
+  uint8 pitch_slide_length;
+  uint8 pitch_slide_delay_left;
+  uint8 vibrato_hold_count;
+  uint8 vib_depth;
+  uint8 tremolo_hold_count;
+  uint8 tremolo_depth;
+  uint8 vibrato_change_count;
+  uint8 note_length;
+  uint8 note_gate_off_fixedpt;
+  uint8 channel_volume_master;
+  uint8 instrument_id;
+  uint16 instrument_pitch_base;
+  uint16 saved_pattern_ptr;
+  uint16 pattern_start_ptr;
+  uint8 pitch_envelope_num_ticks;
+  uint8 pitch_envelope_delay;
+  uint8 pitch_envelope_direction;
+  uint8 pitch_envelope_slide_value;
+  uint8 vibrato_count;
+  uint8 vibrato_rate;
+  uint8 vibrato_delay_ticks;
+  uint8 vibrato_fade_num_ticks;
+  uint8 vibrato_fade_add_per_tick;
+  uint8 vibrato_depth_target;
+  uint8 tremolo_count;
+  uint8 tremolo_rate;
+  uint8 tremolo_delay_ticks;
+  uint8 channel_transposition;
+  uint16 channel_volume;
+  uint16 volume_fade_addpertick;
+  uint8 volume_fade_target;
+  uint8 final_volume;
+  uint16 pan_value;
+  uint16 pan_add_per_tick;
+  uint8 pan_target_value;
+  uint8 pan_flag_with_phase_invert;
+  uint16 pitch;
+  uint16 pitch_add_per_tick;
+  uint8 pitch_target;
+  uint8 fine_tune;
+  uint16 sfx_sound_ptr;
+  uint8 sfx_which_sound;
+  uint8 sfx_arr_countdown;
+  uint8 sfx_note_length_left;
+  uint8 sfx_note_length;
+  uint8 sfx_pan;
+  uint8 index;
+} Channel;
+
+typedef struct SpcPlayer {
+  DspRegWriteHistory *reg_write_history;
+  uint8 timer_cycles;
+  Dsp *dsp;
+  uint8 new_value_from_snes[4];
+  uint8 port_to_snes[4];
+  uint8 last_value_from_snes[4];
+  uint8 counter_sf0c;
+  uint16 _always_zero;
+  uint16 temp_accum;
+  uint8 ttt;
+  uint8 did_affect_volumepitch_flag;
+  uint16 addr0;
+  uint16 addr1;
+  uint16 lfsr_value;
+  uint8 is_chan_on;
+  uint8 fast_forward;
+  uint8 sfx_start_arg_pan;
+  uint16 sfx_sound_ptr_cur;
+  uint16 music_ptr_toplevel;
+  uint8 block_count;
+  uint8 sfx_timer_accum;
+  uint8 chn;
+  uint8 key_ON;
+  uint8 key_OFF;
+  uint8 cur_chan_bit;
+  uint8 reg_FLG;
+  uint8 reg_NON;
+  uint8 reg_EON;
+  uint8 reg_PMON;
+  uint8 echo_stored_time;
+  uint8 echo_parameter_EDL;
+  uint8 reg_EFB;
+  uint8 global_transposition;
+  uint8 main_tempo_accum;
+  uint16 tempo;
+  uint8 tempo_fade_num_ticks;
+  uint8 tempo_fade_final;
+  uint16 tempo_fade_add;
+  uint16 master_volume;
+  uint8 master_volume_fade_ticks;
+  uint8 master_volume_fade_target;
+  uint16 master_volume_fade_add_per_tick;
+  uint8 vol_dirty;
+  uint8 percussion_base_id;
+  uint16 echo_volume_left;
+  uint16 echo_volume_right;
+  uint16 echo_volume_fade_add_left;
+  uint16 echo_volume_fade_add_right;
+  uint8 echo_volume_fade_ticks;
+  uint8 echo_volume_fade_target_left;
+  uint8 echo_volume_fade_target_right;
+  uint8 sfx_channel_index;
+  uint8 current_bit;
+  uint8 dsp_register_index;
+  uint8 echo_channels;
+  uint8 byte_3C4;
+  uint8 byte_3C5;
+  uint8 echo_fract_incr;
+  uint8 sfx_channel_index2; 
+  uint8 sfx_channel_bit;
+  uint8 pause_music_ctr;
+  uint8 port2_active;
+  uint8 port2_current_bit;
+  uint8 port3_active;
+  uint8 port3_current_bit;
+  uint8 port1_active;
+  uint8 port1_current_bit;
+  uint8 byte_3E1;
+  uint8 sfx_play_echo_flag;
+  uint8 sfx_channels_echo_mask2;
+  uint8 port1_counter;
+  uint8 channel_67_volume;
+  uint8 cutk_always_zero;
+  uint8 last_written_edl;
+  uint8 input_ports[4];
+  Channel channel[8];
+  uint8 ram[65536]; // rest of ram
+} SpcPlayer;
+
+SpcPlayer *SpcPlayer_Create();
+void SpcPlayer_GenerateSamples(SpcPlayer *p);
+void SpcPlayer_Initialize(SpcPlayer *p);
+void SpcPlayer_Upload(SpcPlayer *p, const uint8_t *data);
+void SpcPlayer_CopyVariablesFromRam(SpcPlayer *p);
+void SpcPlayer_CopyVariablesToRam(SpcPlayer *p);
--- /dev/null
+++ b/src/sprite.c
@@ -1,0 +1,4328 @@
+#include "sprite.h"
+#include "dungeon.h"
+#include "hud.h"
+#include "load_gfx.h"
+#include "overworld.h"
+#include "variables.h"
+#include "tagalong.h"
+#include "overlord.h"
+#include "ancilla.h"
+#include "player.h"
+#include "misc.h"
+#include "overlord.h"
+#include "tile_detect.h"
+#include "sprite_main.h"
+#include "assets.h"
+static const uint16 kOamGetBufferPos_Tab0[6] = {0x171, 0x201, 0x31, 0xc1, 0x141, 0x1d1};
+static const uint16 kOamGetBufferPos_Tab1[48] = {
+   0x30,  0x50,  0x80,  0xb0,  0xe0, 0x110, 0x140, 0x170, 0x1d0, 0x1d4, 0x1dc, 0x1e0, 0x1e4, 0x1ec, 0x1f0, 0x1f8,
+      0,     4,     8,   0xc,  0x10,  0x14,  0x18,  0x1c,  0x30,  0x38,  0x50,  0x68,  0x80,  0x98,  0xb0,  0xc8,
+  0x120, 0x124, 0x128, 0x12c, 0x130, 0x134, 0x138, 0x13c, 0x140, 0x150, 0x160, 0x170, 0x180, 0x190, 0x1a0, 0x1b8,
+};
+static const uint8 kSprite2_ReturnIfRecoiling_Masks[6] = {3, 1, 0, 0, 0xc, 3};
+static const int8 kSpriteHitbox_XLo[32] = {
+  2, 3, 0, -3, -6, 0, 2, -8, 0, -4, -8, 0, -8, -16, 2, 2,
+  2, 2, 2, -8, 2, 2, -16, -8, -12, 4, -4, -12, 5, -32, -2, 4,
+};
+static const int8 kSpriteHitbox_XHi[32] = {
+  0, 0, 0, -1, -1, 0, 0, -1, 0, -1, -1, 0, -1, -1, 0, 0,
+  0, 0, 0, -1, 0, 0, -1, -1, -1, 0, -1, -1, 0, -1, -1, 0,
+};
+static const uint8 kSpriteHitbox_XSize[32] = {
+  12, 1, 16, 20, 20, 8, 4, 32, 48, 24, 32, 32, 32, 48, 12, 12,
+  60, 124, 12, 32, 4, 12, 48, 32, 40, 8, 24, 24, 5, 80, 4, 8,
+};
+static const int8 kSpriteHitbox_YLo[32] = {
+  0, 3, 4, -4, -8, 2, 0, -16, 12, -4, -8, 0, -10, -16, 2, 2,
+  2, 2, -3, -12, 2, 10, 0, -12, 16, 4, -4, -12, 3, -16, -8, 10,
+};
+static const int8 kSpriteHitbox_YHi[32] = {
+  0, 0, 0, -1, -1, 0, 0, -1, 0, -1, -1, 0, -1, -1, 0, 0,
+  0, 0, -1, -1, 0, 0, 0, -1, 0, 0, -1, -1, 0, -1, -1, 0,
+};
+static const uint8 kSpriteHitbox_YSize[32] = {
+  14, 1, 16, 21, 24, 4, 8, 40, 20, 24, 40, 29, 36, 48, 60, 124,
+  12, 12, 17, 28, 4, 2, 28, 20, 10, 4, 24, 16, 5, 48, 8, 12,
+};
+static const uint8 kSpriteDamage_Tab2[4] = {6, 4, 0, 0};
+static const uint8 kSpriteDamage_Tab3[4] = {4, 6, 0, 2};
+static const uint8 kSprite_Func21_Sfx[9] = {0x1f, 0x1f, 0x1e, 0x1e, 0x1e, 0x1f, 0x1f, 0x1f, 0x1f};
+static const int8 kSparkleGarnish_XY[4] = {-4, 12, 3, 8};
+static const uint8 kSpriteStunned_Main_Func1_Masks[7] = {0x7f, 0xf, 3, 1, 0, 0, 0};
+static const uint8 kSprite_Func7_Tab[4] = {8, 4, 2, 1};
+static const int8 kSprite_Func5_X[54] = {
+  8, 8, 2, 14, 8, 8, -2, 10, 8, 8, 1, 14, 4, 4, 4, 4,
+  4, 4, -2, 10, 8, 8, -25, 40, 8, 8, 2, 14, 8, 8, -8, 23,
+  8, 8, -20, 36, 8, 8, -1, 16, 8, 8, -1, 16, 8, 8, -8, 24,
+  8, 8, -8, 24, 8, 3,
+};
+static const int8 kSprite_Func5_Y[54] = {
+  6, 20, 13, 13, 0, 8, 4, 4, 1, 14, 8, 8, 4, 4, 4, 4,
+  -2, 10, 4, 4, -25, 40, 8, 8, 3, 16, 10, 10, -8, 25, 8, 8,
+  -20, 36, 8, 8, -1, 16, 8, 8, 14, 3, 8, 8, -8, 24, 8, 8,
+  -8, 32, 8, 8, 12, 4,
+};
+static const uint8 kSprite_SimplifiedTileAttr[256] = {
+  0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0,
+  1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 3, 3, 3,
+  0, 0, 0, 0, 0, 0, 1, 1, 4, 4, 4, 4, 4, 4, 4, 4,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+};
+static const int8 kSprite_Func5_Tab3[256] = {
+  0, 1, 2, 3, 2, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1,
+  1, 1, 1, 0, 0, 0, 1, 2, -1, -1, -1, -1, -1, -1, -1, -1,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1,
+  0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, -1, -1, -1, -1,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  0, 0, 0, 0, 0, 1, 0, 2, 0, 0, 0, 0, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+};
+static const int8 kSlopedTile[32] = {
+  7, 6, 5, 4, 3, 2, 1, 0,
+  0, 1, 2, 3, 4, 5, 6, 7,
+  0, 1, 2, 3, 4, 5, 6, 7,
+  7, 6, 5, 4, 3, 2, 1, 0,
+};
+static const uint8 kSprite_Func1_Tab[8] = {15, 15, 24, 15, 15, 19, 15, 15};
+static const uint8 kSprite_Func1_Tab2[8] = {6, 6, 6, 12, 6, 6, 6, 15};
+static const uint8 kSprite_Func14_Damage[12] = {1, 2, 3, 4, 2, 3, 4, 5, 1, 1, 2, 3};
+static const uint8 kEnemyDamages[128] = {
+  0, 1, 32, 255, 252, 251, 0, 0, 0, 2, 64, 4, 0, 0, 0, 0,
+  0, 4, 64, 2, 3, 0, 0, 0, 0, 8, 64, 4, 0, 0, 0, 0,
+  0, 16, 64, 8, 0, 0, 0, 0, 0, 16, 64, 8, 0, 0, 0, 0,
+  0, 4, 64, 16, 0, 0, 0, 0, 0, 255, 64, 255, 252, 251, 0, 0,
+  0, 4, 64, 255, 252, 251, 32, 0, 0, 100, 24, 100, 0, 0, 0, 0,
+  0, 249, 250, 255, 100, 0, 0, 0, 0, 8, 64, 253, 4, 16, 0, 0,
+  0, 8, 64, 254, 4, 0, 0, 0, 0, 16, 64, 253, 0, 0, 0, 0,
+  0, 254, 64, 16, 0, 0, 0, 0, 0, 32, 64, 255, 0, 0, 0, 250,
+};
+static const uint8 kSpriteInit_Flags2[243] = {
+     1,    2,    1, 0x82, 0x81, 0x84, 0x84, 0x84,    2,  0xf,    2,    1, 0x20,    3,    4, 0x84,
+     1,    5,    4,    1, 0x80,    4, 0xa2, 0x83,    4,    2, 0x82, 0x62, 0x82, 0x80, 0x80, 0x85,
+     1, 0xa5,    3,    4,    4, 0x83,    2,    1, 0x82, 0xa2, 0xa2, 0xa3, 0xaa, 0xa3, 0xa4, 0x82,
+  0x82, 0x83, 0x82, 0x80, 0x82, 0x82, 0xa5, 0x80, 0xa4, 0x82, 0x81, 0x82, 0x82, 0x82, 0x81,    6,
+     8,    8,    8,    8,    6,    8,    8,    8,    6,    7,    7,    2,    2, 0x22,    1,    1,
+  0x20, 0x82,    7, 0x85,  0xf, 0x21,    5, 0x83,    2,    1,    1,    1,    1,    7,    7,    7,
+     7,    0, 0x85, 0x83,    3, 0xa4,    0,    0,    0,    0,    9,    4, 0xa0,    0,    1,    0,
+     0,    3, 0x8b, 0x86, 0xc2, 0x82, 0x81,    4, 0x82, 0x21,    6,    3,    1,    3,    3,    3,
+     0,    0,    4,    5,    5,    3,    1,    2,    0,    0,    0,    2,    7,    0,    1,    1,
+  0x87,    6,    0, 0x83,    2, 0x22, 0x22, 0x22, 0x22,    4,    3,    5,    1,    1,    4,    1,
+     2,    8,    8, 0x80, 0x21,    3,    3,    3,    2,    2,    8, 0x8f, 0xa1, 0x81, 0x80, 0x80,
+  0x80, 0x80, 0xa1, 0x80, 0x81, 0x81, 0x86, 0x81, 0x82, 0x82, 0x80, 0x80, 0x83,    6,    0,    0,
+     5,    4,    6,    5,    2,    0,    0,    5,    4,    4,    7,  0xb,  0xc,  0xc,    6,    6,
+     3, 0xa4,    4, 0x82, 0x81, 0x83, 0x10, 0x10, 0x81, 0x82, 0x82, 0x82, 0x83, 0x83, 0x83, 0x81,
+  0x82, 0x83, 0x83, 0x81, 0x82, 0x81, 0x82, 0xa0, 0xa1, 0xa3, 0xa1, 0xa1, 0xa1, 0x83, 0x85, 0x83,
+  0x83, 0x83, 0x83,
+};
+static const uint8 kSpriteInit_Health[243] = {
+   12,   6, 255,   3,  3,   3,   3,   3,   2,  12,  4, 255,   0,   3,  12,   2,
+    0,  20,   4,   4,  0, 255,   0,   2,   3,   8,  0,   0,   0,   0,   0,   0,
+    8,   3,   8,   2,  2,   0,   3, 255,   0,   3,  3,   3,   3,   3,   3,   3,
+    3,   0,   3,   0,  3,   3,   3,   0,   3,   0,  0,   0,   0,   3,   2, 255,
+    2,   6,   4,   8,  6,   8,   6,   4,   8,   8,  8,   4,   4,   2,   2,   2,
+  255,   8, 255,  48, 16,   8,   8, 255,   2,   0,  0, 255, 255, 255, 255, 255,
+  255, 255, 255, 255,  4,   4, 255, 255, 255, 255, 16,   3,   0,   2,   4,   1,
+  255,   4, 255,   0,  0,   0,   0, 255,   0,   0, 96, 255,  24, 255, 255, 255,
+    3,   4, 255,  16,  8,   8,   0, 255,  32,  32, 32,  32,  32,   8,   8,   4,
+    8,  64,  48, 255,  2, 255, 255, 255, 255,  16,  4,   2,   4,   4,   8,   8,
+    8,  16,  64,  64,  8,   4,   8,   4,   4,   8, 12,  16,   0,   0,   0,   0,
+    0,   0,   0,   0,  0,   0,   0,   0,   0,   0,  0,   0,   0, 128,  48, 255,
+  255, 255, 255,   8,  0,   0,   0,  32,   0,   8,  5,  40,  40,  40,  90,  16,
+   24,  64,   0,   4,  0,   0, 255, 255,   0,   0,  0,   0,   0,   0,   0,   0,
+    0,   0,   0,   0,  0,   0,   0,   0,   0,   0,  0,   0,   0,   0,   0,   0,
+    0,   0,   0,
+};
+const uint8 kSpriteInit_BumpDamage[243] = {
+  0x83, 0x83, 0x81,    2,    2,    2,    2,    2,    1, 0x13,    1,    1,    1,    1,    8,    1,
+     1,    8,    5,    3, 0x40,    4,    0,    2,    3, 0x85,    0,    1,    0, 0x40,    0,    0,
+     6,    0,    5,    3,    1,    0,    0,    3,    0,    0,    0,    0,    0,    0,    0,    0,
+     0,    0,    0,    0,    0,    0,    0, 0x40,    0,    0,    0,    0,    0,    0,    2,    2,
+     0,    1,    1,    3,    1,    3,    1,    1,    3,    3,    3,    1,    3,    1,    1,    1,
+     1,    1,    1, 0x11, 0x14,    1,    1,    2,    5,    0,    0,    4,    4,    8,    8,    8,
+     8,    4,    0,    4,    3,    2,    2,    2,    2,    2,    3,    1,    0,    0,    1, 0x80,
+     5,    1,    0,    0,    0, 0x40,    0,    4,    0,    0, 0x14,    4,    6,    4,    4,    4,
+     4,    3,    4,    4,    4,    1,    4,    4, 0x15,    5,    4,    5, 0x15, 0x15,    3,    5,
+     0,    5, 0x15,    5,    5,    6,    6,    6,    6,    5,    3,    6,    5,    5,    3,    3,
+     3,    6, 0x17, 0x15, 0x15,    5,    5,    1, 0x85, 0x83,    5,    4,    0,    0,    0,    0,
+     0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0, 0x17, 0x17,    5,
+     5,    5,    4,    3,    2, 0x10,    0,    6,    0,    5,    7, 0x17, 0x17, 0x17, 0x15,    7,
+     6, 0x10,    0,    3,    3,    0, 0x19, 0x19,    0,    0,    0,    0,    0,    0,    0,    0,
+     0,    0,    0, 0x10,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+     0,    0,    0,
+};
+static const uint8 kSpriteInit_Flags3[243] = {
+  0x19,  0xb, 0x1b, 0x4b, 0x41, 0x41, 0x41, 0x4d, 0x1d,    1, 0x1d, 0x19, 0x8d, 0x1b,    9, 0x9d,
+  0x3d,    1,    9, 0x11, 0x40,    1, 0x4d, 0x19,    7, 0x1d, 0x59, 0x80, 0x4d, 0x40,    1, 0x49,
+  0x1b, 0x41,    3, 0x13, 0x15, 0x41, 0x18, 0x1b, 0x41, 0x47,  0xf, 0x49, 0x4b, 0x4d, 0x41, 0x47,
+  0x49, 0x4d, 0x49, 0x40, 0x4d, 0x47, 0x49, 0x41, 0x74, 0x47, 0x5b, 0x58, 0x51, 0x49, 0x1d, 0x5d,
+     3, 0x19, 0x1b, 0x17, 0x19, 0x17, 0x19, 0x1b, 0x17, 0x17, 0x17, 0x1b,  0xd,    9, 0x19, 0x19,
+  0x49, 0x5d, 0x5b, 0x49,  0xd,    3, 0x13, 0x41, 0x1b, 0x5b, 0x5d, 0x43, 0x43, 0x4d, 0x4d, 0x4d,
+  0x4d, 0x4d, 0x49,    1,    0, 0x41, 0x4d, 0x4d, 0x4d, 0x4d, 0x1d,    9, 0xc4,  0xd,  0xd,    9,
+     3,    3, 0x4b, 0x47, 0x47, 0x49, 0x49, 0x41, 0x47, 0x36, 0x8b, 0x49, 0x1d, 0x49, 0x43, 0x43,
+  0x43,  0xb, 0x41,  0xd,    7,  0xb, 0x1d, 0x43,  0xd, 0x43,  0xd, 0x1d, 0x4d, 0x4d, 0x1b, 0x1b,
+   0xa,  0xb,    0,    5,  0xd,    1,    1,    1,    1,  0xb,    5,    1,    1,    1,    7, 0x17,
+  0x19,  0xd,  0xd, 0x80, 0x4d, 0x19, 0x17, 0x19,  0xb,    9,  0xd, 0x4a, 0x12, 0x49, 0xc3, 0xc3,
+  0xc3, 0xc3, 0x76, 0x40, 0x59, 0x41, 0x58, 0x4f, 0x73, 0x5b, 0x44, 0x41, 0x51,  0xa,  0xb,  0xb,
+  0x4b,    0, 0x40, 0x5b,  0xd,    0,    0,  0xd, 0x4b,  0xb, 0x59, 0x41,  0xb,  0xd,    1,  0xd,
+   0xd,    0, 0x50, 0x4c, 0x44, 0x51,    1,    1, 0xf2, 0xf8, 0xf4, 0xf2, 0xd4, 0xd4, 0xd4, 0xf8,
+  0xf8, 0xf4, 0xf4, 0xd8, 0xf8, 0xd8, 0xdf, 0xc8, 0x69, 0xc1, 0xd2, 0xd2, 0xdc, 0xc7, 0xc1, 0xc7,
+  0xc7, 0xc7, 0xc1,
+};
+static const uint8 kSpriteInit_Flags4[243] = {
+     0,    0,    0, 0x43, 0x43, 0x43, 0x43, 0x43,    0,    0,    0,    0, 0x1c,    0,    0,    2,
+     1,    3,    0,    0,    3, 0xc0,    7,    0,    0,    0,    7, 0x45, 0x43,    0, 0x40,  0xd,
+     0,    0,    0,    0,    0,    0,    0,    0,    7,    7,    7,    7,    7,    7,  0xd,    7,
+     7,    7,    7,    3,    7,    7,    7, 0x40,    3,    7,  0xd,    0,    7,    7,    0,    0,
+     9, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12,    0,    0,    0,    0,
+  0x80, 0x12,    9,    9,    0, 0x40,    0,  0xc,    0,    0,    0, 0x40, 0x40, 0x10, 0x10, 0x2e,
+  0x2e, 0x40, 0x1e, 0x53,    0,  0xa,    0,    0,    0,    0, 0x12, 0x12, 0x40,    0,    0, 0x40,
+  0x19,    0,    0,  0xa,  0xd,  0xa,  0xa, 0x80,  0xa, 0x41,    0, 0x40,    0, 0x49,    0,    0,
+  0xc0,    0, 0x40,    0,    0, 0x40,    0,    0,    9, 0x80, 0xc0,    0, 0x40,    0,    0, 0x80,
+     0,    0, 0x18, 0x5a,    0, 0xd4, 0xd4, 0xd4, 0xd4,    0, 0x40,    0, 0x80, 0x80, 0x40, 0x40,
+  0x40,    0,    9, 0x1d,    0,    0,    0,    0,    0,    0,    0,    0,    0,  0xa, 0x1b, 0x1b,
+  0x1b, 0x1b, 0x41,    0,    3,    7,    7,    3,  0xa,    0,    1,  0xa,  0xa,    9,    0,    0,
+     0,    0,    9,    0,    0, 0x40, 0x40,    0,    0,    0,    0, 0x89, 0x80, 0x80,    0, 0x1c,
+     0, 0x40,    0,    0, 0x1c,    7,    3,    3, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44,
+  0x44, 0x44, 0x44, 0x43, 0x44, 0x43, 0x40, 0xc0, 0xc0, 0xc7, 0xc3, 0xc3, 0xc0, 0x1b,    8, 0x1b,
+  0x1b, 0x1b,    3,
+};
+static const uint8 kSpriteInit_Flags[243] = {
+     0,    0,    0,    0,    0,    0,    0,    0,    0,  0xa,    0,    1, 0x30,    0, 0, 0x20,
+  0x10,    0,    0,    1,    0,    0,    0,    0,    0,    0,    0,    8, 0x20,    0, 4,    0,
+     0,    0,    0,    0,    0,    0,    1,    4,    0,    0,    0,    0,    0,    0, 0,    0,
+     0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0, 0, 0x68,
+  0x60, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61,    0,    0, 0,    0,
+     0,    0,    2,    2,    2,    0,    0, 0x70,    0,    0,    0, 0x90, 0x90,    0, 0,    0,
+     0,    0,    0,    0,    0,    0,    0,    0,    0,    0, 0x60, 0x60,    0,    0, 0,    0,
+     0,    0,    0,    0,    0,    0,    0, 0x80,    0,    0,    2,    0,    0, 0x70, 0,    0,
+     0,    0,    0,    0,    0,    0, 0xb0,    0, 0xc2,    0, 0x20,    0,    2,    0, 0,    0,
+     0,    0,    2,    0, 0xb0,    0,    0,    0,    0,    0,    0,    0, 0xa0, 0xa0, 0,    0,
+     0,    4,    2,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0, 0,    0,
+     0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0, 0xc2, 0,    0,
+     0,    0,    0,    0,    4,    0,    0,    0,    0,    0,    0,    2,    2,    2, 2,    0,
+     0,    0,    0,    0,    0,    0,  0xa,  0xa, 0x10, 0x10, 0x10, 0x10,    0,    0, 0, 0x10,
+  0x10, 0x10, 0x10,    0, 0x10,    0,    0,    0,    0,    0,    0,    0,    0,    0, 0,    0,
+     0,    0,    0,
+};
+static const uint8 kSpriteInit_Flags5[243] = {
+  0x83, 0x96, 0x84, 0x80, 0x80, 0x80, 0x80, 0x80,    2,    0,    2, 0x80, 0xa0, 0x83, 0x97, 0x80,
+  0x80, 0x94, 0x91,    7,    0, 0x80,    0, 0x80, 0x92, 0x96, 0x80, 0xa0,    0,    0,    0, 0x80,
+     4, 0x80, 0x82,    6,    6,    0,    0, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+  0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,    0,    0, 0x80, 0x80, 0x90,
+  0x80, 0x91, 0x91, 0x91, 0x97, 0x91, 0x95, 0x95, 0x93, 0x97, 0x14, 0x91, 0x92, 0x81, 0x82, 0x82,
+  0x80, 0x85, 0x80, 0x80, 0x80,    4,    4, 0x80, 0x91, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+  0x80,    0, 0x80, 0x80, 0x82, 0x8a, 0x80, 0x80, 0x80, 0x80, 0x92, 0x91, 0x80, 0x82, 0x81, 0x81,
+  0x80, 0x81, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x97, 0x80, 0x80, 0x80,
+  0x80, 0xc2, 0x80, 0x15, 0x15, 0x17,    6,    0, 0x80,    0, 0xc0, 0x13, 0x40,    0,    2,    6,
+  0x10, 0x14,    0,    0, 0x40,    0,    0,    0,    0, 0x13, 0x46, 0x11, 0x80, 0x80,    0,    0,
+     0, 0x10,    0,    0,    0, 0x16, 0x16, 0x16, 0x81, 0x87, 0x82,    0, 0x80, 0x80,    0,    0,
+     0,    0, 0x80, 0x80,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+     0,    0,    0, 0x80,    0,    0,    0, 0x17,    0, 0x12,    0,    0,    0,    0,    0, 0x10,
+  0x17,    0, 0x40,    1,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+     0,    0,    0, 0x40,    0,    0,    0,    0,    0,    0,    0,    0, 0x80,    0,    0,    0,
+     0,    0,    0,
+};
+static const uint8 kSpriteInit_DeflBits[243] = {
+     0,    0, 0x44, 0x20, 0x20, 0x20, 0x20, 0x20,    0, 0x81,    0,    0, 0x48,    0,    0,    0,
+     0,    0,    0,    0,    0,    0,    4,    0,    0,    0,    0, 0x48, 0x24, 0x80,    0,    0,
+     0, 0x20,    0,    0,    0, 0x80,    0,    0,    0,    0,    0,    0,    0,    0,    0, 0x80,
+  0x80,    0,    0,    0,    0,    0,    0, 0x80,    0, 0x80,    0,    2,    0,    0,    0,    4,
+  0x80,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+  0x84,    0, 0x81,    5,    1, 0x40,    8, 0xa0,    0,    0,    0,    0,    0, 0x84, 0x84, 0x84,
+  0x84,    8, 0x80, 0x80, 0x80,    0, 0x80, 0x80, 0x80, 0x80,    0,    8, 0x80,    0,    0,    0,
+  0x40,    0,    0,    0,    0,    0,    0,    0,    0,    2,    1,    0,    0,    4,    0,    0,
+     0,    0, 0x80,    4,    4,    0,    0, 0x48,    0,    0,    4,    0,    1,    1,    0,    0,
+  0x80,    0,    0,    0, 0x40,    8,    8,    8,    8,    0,    0,    0, 0x80, 0x80,    0,    0,
+     0,    4,    1,    5,    0,    0,    0,    0,    0,    0,    0,    4,    2,    0, 0x80, 0x80,
+  0x80, 0x80, 0x82, 0x80,    0,    0, 0x80,    0,    0, 0x80, 0x80,    0,    0,    1,    1, 0x40,
+     0,    0,    4,    0,    0,    0,    0,    0,    0,    0,    4,    5,    5,    5, 0x80, 0x80,
+     0,    0,    0,    0,    0,    0,    0,    0,    2,    2,    2,    2,    2,    2,    2,    2,
+     2,    2,    2,    2,    2,    2,    2,    2,    2,    0, 0x82, 0x82,    8, 0x80, 0x20, 0x80,
+  0x80, 0x80, 0x20,
+};
+static const int8 kPlayerDamages[30] = {
+  2, 1, 1, 4, 4, 4, 0, 0, 0, 8, 4, 2, 8, 8, 8, 16,
+  8, 4, 32, 16, 8, 32, 24, 16, 24, 16, 8, 64, 48, 24,
+};
+static const uint8 kPlayerActionBoxRun_YHi[4] = {0xff, 0, 0, 0};
+static const uint8 kPlayerActionBoxRun_YLo[4] = {(uint8)-8, 16, 8, 8};
+static const uint8 kPlayerActionBoxRun_XHi[4] = {0, 0, 0xff, 0};
+static const uint8 kPlayerActionBoxRun_XLo[4] = {0, 0, (uint8)-8, 8};
+static const int8 kPlayer_SetupActionHitBox_X[65] = {
+  0, 2, 0, 0, -8, 0, 2, 0, 2, 2, 1, 1, 0, 0, 0, 0,
+  0, 2, 4, 4, 0, 0, -4, -4, -6, 2, 1, 1, 0, 0, 0, 0,
+  0, 0, 0, 0, 2, 2, 4, 4, 2, 2, 2, 2, 0, 0, 0, 0,
+  0, 0, 0, 0, -4, -4, -10, 0, 2, 2, 0, 0, 0, 0, 0, 0,
+  0,
+};
+static const int8 kPlayer_SetupActionHitBox_W[65] = {
+  15, 4, 8, 8, 8, 8, 12, 8, 4, 4, 6, 6, 0, 0, 0, 0,
+  0, 4, 16, 12, 8, 8, 12, 11, 12, 4, 6, 6, 0, 0, 0, 0,
+  0, 8, 8, 8, 10, 14, 15, 4, 4, 4, 6, 6, 0, 0, 0, 0,
+  0, 8, 8, 8, 10, 14, 15, 4, 4, 4, 6, 6, 0, 0, 0, 0,
+  0,
+};
+static const int8 kPlayer_SetupActionHitBox_Y[65] = {
+  0, 2, 0, 2, 4, 4, 4, 7, 2, 2, 1, 1, 0, 0, 0, 0,
+  0, 2, 0, 2, -4, -3, -8, 0, 0, 2, 1, 1, 0, 0, 0, 0,
+  0, 0, 0, 0, -2, 0, -4, 1, 2, 2, 1, 1, 0, 0, 0, 0,
+  0, 0, 0, 0, -2, 0, -4, 1, 2, 2, 1, 1, 0, 0, 0, 0,
+  0,
+};
+static const int8 kPlayer_SetupActionHitBox_H[65] = {
+  15, 4, 8, 2, 12, 8, 12, 8, 4, 4, 6, 6, 0, 0, 0, 0,
+  0, 4, 8, 4, 12, 12, 12, 4, 8, 4, 6, 4, 0, 0, 0, 0,
+  0, 8, 8, 8, 8, 8, 12, 4, 4, 4, 6, 6, 0, 0, 0, 0,
+  0, 8, 8, 8, 8, 8, 12, 4, 4, 4, 6, 6, 0, 0, 0, 0,
+  0,
+};
+static const int8 kPlayer_SetupActionHitBox_Tab4[13] = {
+  1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1
+};
+static const uint8 kSprite_PrepAndDrawSingleLarge_Tab1[236] = {
+  200, 0, 107, 0, 0, 0, 0, 0, 0, 203, 0, 8, 10, 11, 0, 0,
+  13, 0, 0, 86, 0, 0, 15, 17, 0, 19, 0, 0, 0, 0, 20, 0,
+  21, 27, 0, 42, 42, 248, 0, 182, 0, 0, 0, 170, 0, 0, 28, 0,
+  0, 0, 0, 0, 0, 0, 0, 243, 243, 0, 187, 39, 0, 0, 66, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 63, 0, 0, 0, 64, 64,
+  68, 0, 0, 0, 0, 71, 70, 0, 0, 72, 74, 101, 101, 0, 0, 0,
+  0, 0, 143, 0, 0, 76, 78, 78, 78, 78, 0, 48, 36, 50, 56, 60,
+  129, 0, 82, 0, 0, 0, 0, 0, 0, 92, 0, 98, 94, 0, 0, 0,
+  101, 102, 0, 0, 0, 0, 110, 14, 0, 59, 66, 0, 0, 117, 120, 123,
+  0, 0, 207, 0, 132, 141, 141, 141, 141, 0, 148, 117, 160, 0, 0, 162,
+  166, 0, 0, 0, 177, 0, 181, 0, 189, 0, 0, 0, 105, 0, 0, 0,
+  0, 0, 92, 0, 214, 230, 0, 0, 0, 219, 218, 233, 0, 0, 190, 192,
+  106, 0, 249, 215, 0, 0, 0, 216, 0, 0, 222, 227, 0, 0, 0, 235,
+  0, 0, 0, 0, 0, 0, 244, 244, 29, 31, 31, 31, 32, 32, 32, 33,
+  34, 35, 35, 37, 40, 106, 246, 41, 0, 0, 205, 206,
+};
+static const uint8 kSprite_PrepAndDrawSingleLarge_Tab2[251] = {
+  0xa0, 0xa2, 0xa0, 0xa2, 0x80, 0x82, 0x80, 0x82, 0xea, 0xec, 0x84, 0x4e, 0x61, 0xbd, 0x8c, 0x20,
+  0x22, 0xc0, 0xc2, 0xe6, 0xe4, 0x82, 0xaa, 0x84, 0xac, 0x80, 0xa0, 0xca, 0xaf, 0x29, 0x39, 0xb,
+  0x6e, 0x60, 0x62, 0x63, 0x4c, 0xea, 0xec, 0x24, 0x6b, 0x24, 0x22, 0x24, 0x26, 0x20, 0x30, 0x21,
+  0x2a, 0x24, 0x86, 0x88, 0x8a, 0x8c, 0x8e, 0xa2, 0xa4, 0xa6, 0xa8, 0xaa, 0x84, 0x80, 0x82, 0x6e,
+  0x40, 0x42, 0xe6, 0xe8, 0x80, 0x82, 0xc8, 0x8d, 0xe3, 0xe5, 0xc5, 0xe1, 4, 0x24, 0xe, 0x2e,
+  0xc, 0xa, 0x9c, 0xc7, 0xb6, 0xb7, 0x60, 0x62, 0x64, 0x66, 0x68, 0x6a, 0xe4, 0xf4, 2, 2,
+  0, 4, 0xc6, 0xcc, 0xce, 0x28, 0x84, 0x82, 0x80, 0xe5, 0x24, 0, 2, 4, 0xa0, 0xaa,
+  0xa4, 0xa6, 0xac, 0xa2, 0xa8, 0xa6, 0x88, 0x86, 0x8e, 0xae, 0x8a, 0x42, 0x44, 0x42, 0x44, 0x64,
+  0x66, 0xcc, 0xcc, 0xca, 0x87, 0x97, 0x8e, 0xae, 0xac, 0x8c, 0x8e, 0xaa, 0xac, 0xd2, 0xf3, 0x84,
+  0xa2, 0x84, 0xa4, 0xe7, 0x8a, 0xa8, 0x8a, 0xa8, 0x88, 0xa0, 0xa4, 0xa2, 0xa6, 0xa6, 0xa6, 0xa6,
+  0x7e, 0x7f, 0x8a, 0x88, 0x8c, 0xa6, 0x86, 0x8e, 0xac, 0x86, 0xbb, 0xac, 0xa9, 0xb9, 0xaa, 0xba,
+  0xbc, 0x8a, 0x8e, 0x8a, 0x86, 0xa, 0xc2, 0xc4, 0xe2, 0xe4, 0xc6, 0xea, 0xec, 0xff, 0xe6, 0xc6,
+  0xcc, 0xec, 0xce, 0xee, 0x4c, 0x6c, 0x4e, 0x6e, 0xc8, 0xc4, 0xc6, 0x88, 0x8c, 0x24, 0xe0, 0xae,
+  0xc0, 0xc8, 0xc4, 0xc6, 0xe2, 0xe0, 0xee, 0xae, 0xa0, 0x80, 0xee, 0xc0, 0xc2, 0xbf, 0x8c, 0xaa,
+  0x86, 0xa8, 0xa6, 0x2c, 0x28, 6, 0xdf, 0xcf, 0xa9, 0x46, 0x46, 0xea, 0xc0, 0xc2, 0xe0, 0xe8,
+  0xe2, 0xe6, 0xe4, 0xb, 0x8e, 0xa0, 0xec, 0xea, 0xe9, 0x48, 0x58,
+};
+static const uint8 kOverworldAreaSprcollSizes[192] = {
+  4, 4, 2, 4, 4, 4, 4, 2, 4, 4, 4, 4, 4, 4, 4, 4,
+  2, 2, 2, 2, 2, 2, 2, 2, 4, 4, 2, 4, 4, 2, 4, 4,
+  4, 4, 2, 4, 4, 2, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2,
+  4, 4, 2, 2, 2, 4, 4, 2, 4, 4, 2, 2, 2, 4, 4, 2,
+  4, 4, 2, 4, 4, 4, 4, 2, 4, 4, 4, 4, 4, 4, 4, 4,
+  2, 2, 2, 2, 2, 2, 2, 2, 4, 4, 2, 4, 4, 2, 4, 4,
+  4, 4, 2, 4, 4, 2, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2,
+  4, 4, 2, 2, 2, 4, 4, 2, 4, 4, 2, 2, 2, 4, 4, 2,
+  4, 4, 2, 4, 4, 4, 4, 2, 4, 4, 4, 4, 4, 4, 4, 4,
+  2, 2, 2, 2, 2, 2, 2, 2, 4, 4, 2, 4, 4, 2, 4, 4,
+  4, 4, 2, 4, 4, 2, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2,
+  4, 4, 2, 2, 2, 4, 4, 2, 4, 4, 2, 2, 2, 4, 4, 2,
+};
+static const uint16 kOam_ResetRegionBases[6] = {0x30, 0x1d0, 0, 0x30, 0x120, 0x140};
+static const uint8 kGarnish_OamMemSize[23] = {
+  0, 4, 4, 4, 4, 4,  4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+  8, 4, 4, 4, 8, 16,
+};
+static HandlerFuncK *const kGarnish_Funcs[22] = {
+  &Garnish01_FireSnakeTail,
+  &Garnish02_MothulaBeamTrail,
+  &Garnish03_FallingTile,
+  &Garnish04_LaserTrail,
+  &Garnish_SimpleSparkle,
+  &Garnish06_ZoroTrail,
+  &Garnish07_BabasuFlash,
+  &Garnish08_KholdstareTrail,
+  &Garnish09_LightningTrail,
+  &Garnish0A_CannonSmoke,
+  &Garnish_WaterTrail,
+  &Garnish0C_TrinexxIceBreath,
+  NULL,
+  &Garnish0E_TrinexxFireBreath,
+  &Garnish0F_BlindLaserTrail,
+  &Garnish10_GanonBatFlame,
+  &Garnish11_WitheringGanonBatFlame,
+  &Garnish12_Sparkle,
+  &Garnish13_PyramidDebris,
+  &Garnish14_KakKidDashDust,
+  &Garnish15_ArrghusSplash,
+  &Garnish16_ThrownItemDebris,
+};
+static const uint8 kSpriteFall_Tab1[32] = {
+  13, 13, 13, 13, 13, 13, 13, 12, 12, 12, 12, 12, 3, 3, 3, 3,
+  3, 2, 2, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0,
+};
+static const uint8 kSpriteFall_Tab2[32] = {
+  5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 3, 3, 3, 3,
+  3, 2, 2, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0,
+};
+static const uint8 kSpriteFall_Tab3[16] = {0xff, 0x3f, 0x1f, 0xf, 0xf, 7, 3, 1, 0xff, 0x3f, 0x1f, 0xf, 7, 3, 1, 0};
+static const int8 kSpriteFall_Tab4[4] = {0, 4, 8, 0};
+static const DrawMultipleData kSpriteDrawFall0Data[12] = {
+  {0, 0, 0x0146, 2},
+  {0, 0, 0x0148, 2},
+  {0, 0, 0x014a, 2},
+  {4, 4, 0x014c, 0},
+  {4, 4, 0x00b7, 0},
+  {4, 4, 0x0080, 0},
+  {0, 0, 0x016c, 2},
+  {0, 0, 0x016e, 2},
+  {0, 0, 0x014e, 2},
+  {4, 4, 0x015c, 0},
+  {4, 4, 0x00b7, 0},
+  {4, 4, 0x0080, 0},
+};
+static const int8 kSpriteDrawFall1_X[56] = {
+  -4, 4, -4, 12, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0,
+  -4, 12, -4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0,
+  -4, 12, -4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0,
+  4, 0, 0, 0, 4, 0, 0, 0,
+};
+static const int8 kSpriteDrawFall1_Y[56] = {
+  -4, -4, 4, 12, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0,
+  -4, -4, 12, 4, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0,
+  -4, -4, 12, 4, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0,
+  4, 0, 0, 0, 4, 0, 0, 0,
+};
+static const uint8 kSpriteDrawFall1_Char[56] = {
+  0xae, 0xa8, 0xa6, 0xaf, 0xaa, 0, 0, 0, 0xac, 0, 0, 0, 0xbe, 0, 0, 0,
+  0xa8, 0xae, 0xaf, 0xa6, 0xaa, 0, 0, 0, 0xac, 0, 0, 0, 0xbe, 0, 0, 0,
+  0xa6, 0xaf, 0xae, 0xa8, 0xaa, 0, 0, 0, 0xac, 0, 0, 0, 0xbe, 0, 0, 0,
+  0xb6, 0, 0, 0, 0x80, 0, 0, 0,
+};
+static const uint8 kSpriteDrawFall1_Flags[56] = {
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0x40, 0x40, 0x40, 0x40, 0x40, 0, 0, 0, 0x40, 0, 0, 0, 0x40, 0, 0, 0,
+  0x80, 0x80, 0x80, 0x80, 0x80, 0, 0, 0, 0x80, 0, 0, 0, 0x80, 0, 0, 0,
+  1, 0, 0, 0, 1, 0, 0, 0,
+};
+static const uint8 kSpriteDrawFall1_Ext[56] = {
+  0, 2, 2, 0, 2, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0,
+  2, 0, 0, 2, 2, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0,
+  2, 0, 0, 2, 2, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const int8 kSpriteDistress_X[4] = {-3, 2, 7, 11};
+static const int8 kSpriteDistress_Y[4] = {-5, -7, -7, -5};
+static const uint8 kPikitDropItems[4] = {0xdc, 0xe1, 0xd9, 0xe6};
+static const uint8 kPrizeMasks[7] = { 1, 1, 1, 0, 1, 1, 1 };
+static const uint8 kPrizeItems[56] = {
+  0xd8, 0xd8, 0xd8, 0xd8, 0xd9, 0xd8, 0xd8, 0xd9, 0xda, 0xd9, 0xda, 0xdb, 0xda, 0xd9, 0xda, 0xda,
+  0xe0, 0xdf, 0xdf, 0xda, 0xe0, 0xdf, 0xd8, 0xdf, 0xdc, 0xdc, 0xdc, 0xdd, 0xdc, 0xdc, 0xde, 0xdc,
+  0xe1, 0xd8, 0xe1, 0xe2, 0xe1, 0xd8, 0xe1, 0xe2, 0xdf, 0xd9, 0xd8, 0xe1, 0xdf, 0xdc, 0xd9, 0xd8,
+  0xd8, 0xe3, 0xe0, 0xdb, 0xde, 0xd8, 0xdb, 0xe2,
+};
+static const uint8 kPrizeZ[15] = {0, 0x24, 0x24, 0x24, 0x20, 0x20, 0x20, 0x24, 0x24, 0x24, 0x24, 0, 0x24, 0x20, 0x20};
+static const int8 kPerishOverlay_X[32] = {
+  0, 0, 0, 8, 0, 8, 0, 8, 8, 8, 0, 8, 0, 8, 0, 8,
+  0, 8, 0, 8, 0, 8, 0, 8, -3, 11, -3, 11, -6, 14, -6, 14,
+};
+static const int8 kPerishOverlay_Y[32] = {
+  0, 0, 8, 8, 0, 0, 8, 8, 0, 0, 8, 8, 0, 0, 8, 8,
+  0, 0, 8, 8, 0, 0, 8, 8, -3, -3, 11, 11, -6, -6, 14, 14,
+};
+static const uint8 kPerishOverlay_Char[32] = {
+  0, 0xb9, 0, 0, 0xb4, 0xb5, 0xb5, 0xb4, 0xb9, 0, 0, 0, 0xb5, 0xb4, 0xb4, 0xb5,
+  0xa8, 0xa8, 0xb8, 0xb8, 0xa8, 0xa8, 0xb8, 0xb8, 0xa9, 0xa9, 0xa9, 0xa9, 0x9b, 0x9b, 0x9b, 0x9b,
+};
+static const uint8 kPerishOverlay_Flags[32] = {
+  4, 4, 4, 4, 4, 4, 0xc4, 0xc4, 0x44, 4, 4, 4, 0x44, 0x44, 0x84, 0x84,
+  4, 0x44, 4, 0x44, 4, 0x44, 4, 0x44, 0x44, 4, 0xc4, 0x84, 4, 0x44, 0x84, 0xc4,
+};
+static HandlerFuncK *const kSprite_ExecuteSingle[12] = {
+  &Sprite_inactiveSprite,
+  &SpriteModule_Fall1,
+  &SpriteModule_Poof,
+  &SpriteModule_Drown,
+  &SpriteModule_Explode,
+  &SpriteModule_Fall2,
+  &SpriteModule_Die,
+  &SpriteModule_Burn,
+  &SpriteModule_Initialize,
+  &SpriteActive_Main,
+  &SpriteModule_Carried,
+  &SpriteModule_Stunned,
+};
+// it's not my job to tell you what to think, my job is to think about what you tell me'
+#define R0 WORD(g_ram[0])
+#define R2 WORD(g_ram[2])
+static const uint8 kSpawnSecretItems[22] = {
+  0xd9, 0x3e, 0x79, 0xd9, 0xdc, 0xd8, 0xda, 0xe4, 0xe1, 0xdc, 0xd8, 0xdf, 0xe0, 0xb, 0x42, 0xd3,
+  0x41, 0xd4, 0xd9, 0xe3, 0xd8, 0,
+};
+static const uint8 kSpawnSecretItem_SpawnFlag[22] = {
+  0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 0, 0,
+  0, 0, 0, 0, 0, 0,
+};
+static const uint8 kSpawnSecretItem_XLo[22] = {
+  4, 0, 4, 4, 0, 4, 4, 4, 4, 0, 4, 4, 4, 0, 0, 0,
+  0, 0, 4, 0, 4, 4,
+};
+static const uint8 kSpawnSecretItem_IgnoreProj[22] = {
+  1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0,
+  0, 0, 1, 1, 1, 1,
+};
+static const uint8 kSpawnSecretItem_ZVel[22] = {
+  16, 0, 0, 16, 0, 0, 16, 16, 16, 16, 0, 16, 10, 16, 0, 0,
+  0, 0, 16, 0, 0, 0,
+};
+static const uint8 kSprite_ReturnIfLifted_Dirs[4] = {4, 6, 0, 2};
+static const uint8 kAbsorbable_Tab1[15] = {0, 1, 1, 1, 2, 2, 2, 0, 1, 1, 2, 2, 1, 2, 2};
+static const uint8 kAbsorbable_Tab2[19] = {0, 0, 0, 0, 1, 2, 3, 0, 0, 4, 5, 0, 0, 0, 0, 2, 4, 6, 2};
+static const int16 kNumberedAbsorbable_X[18] = { 0, 0, 8, 0, 0, 8, 0, 0, 8, 0, 0, 2, 0, 0, 2, 0, 0, 0, };
+static const int16 kNumberedAbsorbable_Y[18] = { 0, 0, 8, 0, 0, 8, 0, 0, 8, 0, 8, 8, 0, 8, 8, 0, 8, 8, };
+static const uint8 kNumberedAbsorbable_Char[18] = { 0x6e, 0x6e, 0x68, 0x6e, 0x6e, 0x78, 0x6e, 0x6e, 0x79, 0x63, 0x73, 0x69, 0x63, 0x73, 0x6a, 0x63, 0x73, 0x73, };
+static const uint8 kNumberedAbsorbable_Ext[18] = { 2, 2, 0, 2, 2, 0, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, };
+static const uint8 kRupeesAbsorption[3] = {1, 5, 20};
+const uint8 kAbsorptionSfx[15] = {0xb, 0xa, 0xa, 0xa, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0x2f, 0x2f, 0xb};
+static const uint8 kBombsAbsorption[3] = {1, 4, 8};
+const uint8 kAbsorbBigKey[2] = {0x40, 0x20};
+static int AllocOverlord();
+static int Overworld_AllocSprite(uint8 type);
+uint16 Sprite_GetX(int k) {
+  return sprite_x_lo[k] | sprite_x_hi[k] << 8;
+}
+
+uint16 Sprite_GetY(int k) {
+  return sprite_y_lo[k] | sprite_y_hi[k] << 8;
+}
+
+void Sprite_SetX(int k, uint16 x) {
+  sprite_x_lo[k] = x;
+  sprite_x_hi[k] = x >> 8;
+}
+
+void Sprite_SetY(int k, uint16 y) {
+  sprite_y_lo[k] = y;
+  sprite_y_hi[k] = y >> 8;
+}
+
+void Sprite_ApproachTargetSpeed(int k, uint8 x, uint8 y) {
+  if (sprite_x_vel[k] - x)
+    sprite_x_vel[k] += sign8(sprite_x_vel[k] - x) ? 1 : -1;
+  if (sprite_y_vel[k] - y)
+    sprite_y_vel[k] += sign8(sprite_y_vel[k] - y) ? 1 : -1;
+}
+
+void SpriteAddXY(int k, int xv, int yv) {
+  Sprite_SetX(k, Sprite_GetX(k) + xv);
+  Sprite_SetY(k, Sprite_GetY(k) + yv);
+}
+
+void Sprite_MoveXYZ(int k) {
+  Sprite_MoveZ(k);
+  Sprite_MoveX(k);
+  Sprite_MoveY(k);
+}
+
+void Sprite_Invert_XY_Speeds(int k) {
+  sprite_x_vel[k] = -sprite_x_vel[k];
+  sprite_y_vel[k] = -sprite_y_vel[k];
+}
+
+int Sprite_SpawnSimpleSparkleGarnishEx(int k, uint16 x, uint16 y, int limit) {
+  int j = GarnishAllocLimit(limit);
+  if (j >= 0) {
+    garnish_type[j] = 5;
+    garnish_active = 5;
+    Garnish_SetX(j, Sprite_GetX(k) + x);
+    Garnish_SetY(j, Sprite_GetY(k) + y - sprite_z[k] + 16);
+    garnish_countdown[j] = 31;
+    garnish_sprite[j] = k;
+    garnish_floor[j] = sprite_floor[k];
+  }
+  g_ram[15] = j;
+  return j;
+}
+
+static int AllocOverlord() {
+  int i = 7;
+  while (i >= 0 && overlord_type[i] != 0)
+    i--;
+  return i;
+}
+
+static int Overworld_AllocSprite(uint8 type) {
+  int i = (type == 0x58) ? 4 :
+          (type == 0xd0) ? 5 :
+          (type == 0xeb || type == 0x53 || type  == 0xf3) ? 14 : 13;
+  for (; i >= 0; i--) {
+    if (sprite_state[i] == 0 || sprite_type[i] == 0x41 && sprite_C[i] != 0)
+      break;
+  }
+  return i;
+}
+
+uint16 Garnish_GetX(int k) {
+  return garnish_x_lo[k] | garnish_x_hi[k] << 8;
+}
+
+uint16 Garnish_GetY(int k) {
+  return garnish_y_lo[k] | garnish_y_hi[k] << 8;
+}
+
+void Garnish_SparkleCommon(int k, uint8 shift) {
+  static const uint8 kGarnishSparkle_Char[4] = {0x83, 0xc7, 0x80, 0xb7};
+  uint8 t = garnish_countdown[k] >> shift;
+  Point16U pt;
+  if (Garnish_ReturnIfPrepFails(k, &pt))
+    return;
+  OamEnt *oam = GetOamCurPtr();
+  int j = garnish_sprite[k];
+  SetOamPlain(oam, pt.x, pt.y, kGarnishSparkle_Char[t],
+               (sprite_oam_flags[j] | sprite_obj_prio[j]) & 0xf0 | 4, 0);
+}
+
+void Garnish_DustCommon(int k, uint8 shift) {
+  static const uint8 kRunningManDust_Char[3] = {0xdf, 0xcf, 0xa9};
+  tmp_counter = garnish_countdown[k] >> shift;
+  Point16U pt;
+  if (Garnish_ReturnIfPrepFails(k, &pt))
+    return;
+  OamEnt *oam = GetOamCurPtr();
+  SetOamPlain(oam, pt.x, pt.y, kRunningManDust_Char[tmp_counter], 0x24, 0);
+}
+
+void SpriteModule_Explode(int k) {
+  static const DrawMultipleData kSpriteExplode_Dmd[32] = {
+    { 0,  0, 0x0060, 2},
+    { 0,  0, 0x0060, 2},
+    { 0,  0, 0x0060, 2},
+    { 0,  0, 0x0060, 2},
+    {-5, -5, 0x0062, 2},
+    { 5, -5, 0x4062, 2},
+    {-5,  5, 0x8062, 2},
+    { 5,  5, 0xc062, 2},
+    {-8, -8, 0x0062, 2},
+    { 8, -8, 0x4062, 2},
+    {-8,  8, 0x8062, 2},
+    { 8,  8, 0xc062, 2},
+    {-8, -8, 0x0064, 2},
+    { 8, -8, 0x4064, 2},
+    {-8,  8, 0x8064, 2},
+    { 8,  8, 0xc064, 2},
+    {-8, -8, 0x0066, 2},
+    { 8, -8, 0x4066, 2},
+    {-8,  8, 0x8066, 2},
+    { 8,  8, 0xc066, 2},
+    {-8, -8, 0x0068, 2},
+    { 8, -8, 0x0068, 2},
+    {-8,  8, 0x0068, 2},
+    { 8,  8, 0x0068, 2},
+    {-8, -8, 0x006a, 2},
+    { 8, -8, 0x406a, 2},
+    {-8,  8, 0x806a, 2},
+    { 8,  8, 0xc06a, 2},
+    {-8, -8, 0x004e, 2},
+    { 8, -8, 0x404e, 2},
+    {-8,  8, 0x804e, 2},
+    { 8,  8, 0xc04e, 2},
+  };
+
+  if (sprite_A[k]) {
+    if (!sprite_delay_main[k]) {
+      sprite_state[k] = 0;
+      for (int j = 15; j >= 0; j--) {
+        if (sprite_state[j] == 4)
+          return;
+      }
+      load_chr_halfslot_even_odd = 1;
+      if (!Sprite_CheckIfScreenIsClear())
+        flag_block_link_menu = 0;
+    } else {
+      Sprite_DrawMultiple(k, &kSpriteExplode_Dmd[((sprite_delay_main[k] >> 2) ^ 7) * 4], 4, NULL);
+    }
+    return;
+  }
+  sprite_floor[k] = 2;
+
+  if (sprite_delay_main[k] == 32) {
+    sprite_state[k] = 0;
+    flag_is_link_immobilized = 0;
+    if (player_near_pit_state != 2 && Sprite_CheckIfScreenIsClear()) {
+      if (sprite_type[k] >= 0xd6) {
+        music_control = 0x13;
+      } else if (sprite_type[k] == 0x7a) {
+        PrepareDungeonExitFromBossFight();
+      } else {
+        SpriteExplode_SpawnEA(k);
+        return;
+      }
+    }
+  }
+
+  if (sprite_delay_main[k] >= 64 && (sprite_delay_main[k] >= 0x70 || !(sprite_delay_main[k] & 1)))
+    SpriteActive_Main(k);
+
+  uint8 type = sprite_type[k];
+  if (sprite_delay_main[k] >= 0xc0)
+    return;
+  if ((sprite_delay_main[k] & 3) == 0)
+    SpriteSfx_QueueSfx2WithPan(k, 0xc);
+  if (sprite_delay_main[k] & ((type == 0x92) ? 3 : 7))
+    return;
+
+  SpriteSpawnInfo info;
+  int j = Sprite_SpawnDynamically(k, 0x1c, &info);
+  if (j >= 0) {
+    static const int8 kSpriteExplode_RandomXY[16] = {0, 4, 8, 12, -4, -8, -12, 0, 0, 8, 16, 24, -24, -16, -8, 0};
+    load_chr_halfslot_even_odd = 11;
+    sprite_state[j] = 4;
+    sprite_flags2[j] = 3;
+    sprite_oam_flags[j] = 0xc;
+    int xoff = kSpriteExplode_RandomXY[(GetRandomNumber() & 7) | ((type == 0x92) ? 8 : 0)];
+    int yoff = kSpriteExplode_RandomXY[(GetRandomNumber() & 7) | ((type == 0x92) ? 8 : 0)];
+    Sprite_SetX(j, info.r0_x + xoff);
+    Sprite_SetY(j, info.r2_y + yoff - info.r4_z);
+    sprite_delay_main[j] = 31;
+    sprite_A[j] = 31;
+  }
+  // endif_1
+}
+
+void SpriteDeath_MainEx(int k, bool second_entry) {
+  if (!second_entry) {
+    uint8 type = sprite_type[k];
+    if (type == 0xec) {
+      ThrowableScenery_ScatterIntoDebris(k);
+      return;
+    }
+    if (type == 0x53 || type == 0x54 || type == 0x92 || type == 0x4a && sprite_C[k] >= 2) {
+      SpriteActive_Main(k);
+      return;
+    }
+    if (sprite_delay_main[k] == 0) {
+      Sprite_DoTheDeath(k);
+      return;
+    }
+  }
+  if (sign8(sprite_flags3[k])) {
+    SpriteActive_Main(k);
+    return;
+  }
+  if (!((frame_counter & 3) | submodule_index | flag_unk1))
+    sprite_delay_main[k]++;
+  SpriteDeath_DrawPoof(k);
+
+  if (sprite_type[k] != 0x40 && sprite_delay_main[k] < 10)
+    return;
+  oam_cur_ptr += 16;
+  oam_ext_cur_ptr += 4;
+  uint8 bak = sprite_flags2[k];
+  sprite_flags2[k] -= 4;
+  SpriteActive_Main(k);
+  sprite_flags2[k] = bak;
+}
+
+void SpriteModule_Burn(int k) {
+  static const uint8 kFlame_Gfx[32] = {
+    5, 4, 3, 1, 2, 0, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0,
+    1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0,
+  };
+  sprite_hit_timer[k] = 0;
+  int j = sprite_delay_main[k] - 1;
+  if (j == 0) {
+    Sprite_DoTheDeath(k);
+    return;
+  }
+  uint8 bak = sprite_graphics[k];
+  uint8 bak1 = sprite_oam_flags[k];
+  sprite_graphics[k] = kFlame_Gfx[j >> 3];
+  sprite_oam_flags[k] = 3;
+  Flame_Draw(k);
+  sprite_oam_flags[k] = bak1;
+  sprite_graphics[k] = bak;
+
+  oam_cur_ptr += 8;
+  oam_ext_cur_ptr += 2;
+  if (sprite_delay_main[k] >= 0x10) {
+    uint8 bak = sprite_flags2[k];
+    sprite_flags2[k] -= 2;
+    SpriteActive_Main(k);
+    sprite_flags2[k] = bak;
+  }
+}
+
+void Sprite_HitTimer31(int k) {
+  if (sprite_type[k] != 0x7a || is_in_dark_world)
+    return;
+  if (sprite_health[k] <= sprite_give_damage[k]) {
+    dialogue_message_index = 0x140;
+    Sprite_ShowMessageMinimal();
+  }
+}
+
+void SpriteStunned_MainEx(int k, bool second_entry) {
+  if (second_entry)
+    goto ThrownSprite_TileAndSpriteInteraction;
+  Sprite_DrawRippleIfInWater(k);
+  SpriteStunned_Main_Func1(k);
+  if (Sprite_ReturnIfPaused(k))
+    return;
+  if (sprite_F[k]) {
+    if (sign8(sprite_F[k]))
+      sprite_F[k] = 0;
+    sprite_x_vel[k] = sprite_y_vel[k] = 0;
+  }
+  if (sprite_delay_main[k] < 0x20)
+    Sprite_CheckDamageFromLink(k);
+  if (Sprite_ReturnIfRecoiling(k))
+    return;
+  Sprite_MoveXY(k);
+  if (!sprite_E[k]) {
+    Sprite_CheckTileCollision(k);
+    if (!sprite_state[k])
+      return;
+  ThrownSprite_TileAndSpriteInteraction:
+    if (sprite_wallcoll[k] & 0xf) {
+      Sprite_ApplyRicochet(k);
+      if (sprite_state[k] == 11)
+        SpriteSfx_QueueSfx2WithPan(k, 5);
+    }
+  }
+  Sprite_CheckTileProperty(k, 0x68);
+
+  if (kSpriteInit_Flags3[sprite_type[k]] & 0x10) {
+    sprite_flags3[k] |= 0x10;
+    if (sprite_tiletype == 32)
+      sprite_flags3[k] &= ~0x10;
+  }
+  Sprite_MoveZ(k);
+  sprite_z_vel[k] -= 2;
+  uint8 z = sprite_z[k] - 1;
+  if (z >= 0xf0) {
+    sprite_z[k] = 0;
+    if (sprite_type[k] == 0xe8 && sign8(sprite_z_vel[k] - 0xe8)) {
+      sprite_state[k] = 6;
+      sprite_delay_main[k] = 8;
+      sprite_flags2[k] = 3;
+      return;
+    }
+    ThrowableScenery_TransmuteIfValid(k);
+    uint8 a = sprite_tiletype;
+    if (sprite_tiletype == 32 && !(a = sprite_flags[k] >> 1, sprite_flags[k] & 1)) {  // wtf
+      Sprite_Func8(k);
+      return;
+    }
+    if (a == 9) {
+      z = sprite_z_vel[k];
+      sprite_z_vel[k] = 0;
+      int j;
+      SpriteSpawnInfo info;
+
+      if (sign8(z - 0xf0) && (j = Sprite_SpawnDynamically(k, 0xec, &info)) >= 0) {
+        Sprite_SetSpawnedCoordinates(j, &info);
+        Sprite_Func22(j);
+      }
+    } else if (a == 8) {
+      if (sprite_type[k] == 0xd2 || (GetRandomNumber() & 1))
+        Sprite_SpawnLeapingFish(k);
+      Sprite_Func22(k);
+      return;
+    }
+    z = sprite_z_vel[k];
+    if (sign8(z)) {
+      z = (uint8)(-z) >> 1;
+      sprite_z_vel[k] = z < 9 ? 0 : z;
+    }
+    sprite_x_vel[k] = (int8)sprite_x_vel[k] >> 1;
+    if (sprite_x_vel[k] == 255)
+      sprite_x_vel[k] = 0;
+    sprite_y_vel[k] = (int8)sprite_y_vel[k] >> 1;
+    if (sprite_y_vel[k] == 255)
+      sprite_y_vel[k] = 0;
+  }
+  if (sprite_state[k] != 11 || sprite_unk5[k] != 0) {
+    if (Sprite_ReturnIfLifted(k))
+      return;
+    if (sprite_type[k] != 0x4a)
+      ThrownSprite_CheckDamageToSprites(k);
+  }
+}
+
+int Ancilla_SpawnFallingPrize(uint8 item) {  // 85a51d
+  return AncillaAdd_FallingPrize(0x29, item, 4);
+}
+
+bool Sprite_CheckDamageToAndFromLink(int k) {  // 85ab93
+  Sprite_CheckDamageFromLink(k);
+  return Sprite_CheckDamageToLink(k);
+}
+
+uint8 Sprite_CheckTileCollision(int k) {  // 85b88d
+  Sprite_CheckTileCollision2(k);
+  return sprite_wallcoll[k];
+}
+
+bool Sprite_TrackBodyToHead(int k) {  // 85dca2
+  if (sprite_head_dir[k] != sprite_D[k]) {
+    if (frame_counter & 0x1f)
+      return false;
+    if (!((sprite_head_dir[k] ^ sprite_D[k]) & 2)) {
+      sprite_D[k] = (((k ^ frame_counter) >> 5 | 2) & 3) ^ (sprite_head_dir[k] & 2);
+      return false;
+    }
+  }
+  sprite_D[k] = sprite_head_dir[k];
+  return true;
+}
+
+void Sprite_DrawMultiple(int k, const DrawMultipleData *src, int n, PrepOamCoordsRet *info) {  // 85df6c
+  PrepOamCoordsRet info_buf;
+  if (!info)
+    info = &info_buf;
+  if (Sprite_PrepOamCoordOrDoubleRet(k, info))
+    return;
+  word_7E0CFE = 0;
+  uint8 a = sprite_state[k];
+  if (a == 10)
+    a = sprite_unk4[k];
+  if (a == 11)
+    BYTE(word_7E0CFE) = sprite_unk5[k];
+  OamEnt *oam = GetOamCurPtr();
+  do {
+    uint16 d = src->char_flags ^ WORD(info->r4);
+    if (word_7E0CFE >= 1)
+      d = d & ~0xE00 | 0x400;
+    SetOamHelper0(oam, src->x + info->x, src->y + info->y, d, d >> 8, src->ext);
+
+  } while (src++, oam++, --n);
+}
+
+void Sprite_DrawMultiplePlayerDeferred(int k, const DrawMultipleData *src, int n, PrepOamCoordsRet *info) {  // 85df75
+  Oam_AllocateDeferToPlayer(k);
+  Sprite_DrawMultiple(k, src, n, info);
+}
+
+int Sprite_ShowSolicitedMessage(int k, uint16 msg) {  // 85e1a7
+  static const uint8 kShowMessageFacing_Tab0[4] = {4, 6, 0, 2};
+  dialogue_message_index = msg;
+  if (!Sprite_CheckDamageToLink_same_layer(k) ||
+      Sprite_CheckIfLinkIsBusy() ||
+      !(filtered_joypad_L & 0x80) ||
+      sprite_delay_aux4[k] || link_auxiliary_state == 2)
+    return sprite_D[k];
+  uint8 dir = Sprite_DirectionToFaceLink(k, NULL);
+  if (link_direction_facing != kShowMessageFacing_Tab0[dir])
+    return sprite_D[k];
+  Sprite_ShowMessageUnconditional(dialogue_message_index);
+  sprite_delay_aux4[k] = 64;
+  return dir ^ 0x103;
+}
+
+int Sprite_ShowMessageOnContact(int k, uint16 msg) {  // 85e1f0
+  dialogue_message_index = msg;
+  if (!Sprite_CheckDamageToLink_same_layer(k) || link_auxiliary_state == 2)
+    return sprite_D[k];
+  Sprite_ShowMessageUnconditional(dialogue_message_index);
+  return Sprite_DirectionToFaceLink(k, NULL) ^ 0x103;
+}
+
+void Sprite_ShowMessageUnconditional(uint16 msg) {  // 85e219
+  dialogue_message_index = msg;
+  byte_7E0223 = 0;
+  messaging_module = 0;
+  submodule_index = 2;
+  saved_module_for_menu = main_module_index;
+  main_module_index = 14;
+  Sprite_NullifyHookshotDrag();
+  link_speed_setting = 0;
+  Link_CancelDash();
+  link_auxiliary_state = 0;
+  link_incapacitated_timer = 0;
+  if (link_player_handler_state == kPlayerState_RecoilWall)
+    link_player_handler_state = kPlayerState_Ground;
+}
+
+bool Sprite_TutorialGuard_ShowMessageOnContact(int k, uint16 msg) {  // 85fa59
+  dialogue_message_index = msg;
+  uint8 bak2 = sprite_flags2[k];
+  uint8 bak4 = sprite_flags4[k];
+  sprite_flags2[k] = 0x80;
+  sprite_flags4[k] = 0x07;
+  bool rv = Sprite_CheckDamageToLink_same_layer(k);
+  sprite_flags2[k] = bak2;
+  sprite_flags4[k] = bak4;
+  if (!rv)
+    return rv;
+  Sprite_NullifyHookshotDrag();
+  link_is_running = 0;
+  link_speed_setting = 0;
+  if (!link_auxiliary_state)
+    Sprite_ShowMessageMinimal();
+  return rv;
+}
+
+void Sprite_ShowMessageMinimal() {  // 85fa8e
+  byte_7E0223 = 0;
+  messaging_module = 0;
+  submodule_index = 2;
+  saved_module_for_menu = main_module_index;
+  main_module_index = 14;
+}
+
+void Prepare_ApplyRumbleToSprites() {  // 8680fa
+  static const int8 kApplyRumble_X[4] = { -32, -32, -32, 16 };
+  static const int8 kApplyRumble_Y[4] = { -32, 32, -24, -24 };
+  static const uint8 kApplyRumble_WH[6] = { 0x50, 0x50, 0x20, 0x20, 0x50, 0x50 };
+  int j = link_direction_facing >> 1;
+  SpriteHitBox hb;
+  uint16 x = link_x_coord + kApplyRumble_X[j];
+  uint16 y = link_y_coord + kApplyRumble_Y[j];
+  hb.r0_xlo = x;
+  hb.r8_xhi = x >> 8;
+  hb.r1_ylo = y;
+  hb.r9_yhi = y >> 8;
+  hb.r2 = kApplyRumble_WH[j];
+  hb.r3 = kApplyRumble_WH[j + 2];
+  Entity_ApplyRumbleToSprites(&hb);
+}
+
+void Sprite_SpawnImmediatelySmashedTerrain(uint8 what, uint16 x, uint16 y) {  // 86812d
+  uint8 bak1 = flag_is_sprite_to_pick_up;
+  uint8 bak2 = byte_7E0FB2;
+  int k = Sprite_SpawnThrowableTerrain_silently(what, x, y);
+  if (k >= 0)
+    ThrowableScenery_TransmuteToDebris(k);
+  byte_7E0FB2 = bak2;
+  flag_is_sprite_to_pick_up = bak1;
+}
+
+void Sprite_SpawnThrowableTerrain(uint8 what, uint16 x, uint16 y) {  // 86814b
+  sound_effect_1 = Link_CalculateSfxPan() | 29;
+  Sprite_SpawnThrowableTerrain_silently(what, x, y);
+}
+
+int Sprite_SpawnThrowableTerrain_silently(uint8 what, uint16 x, uint16 y) {  // 868156
+  int k = 15;
+  for (; k >= 0 && sprite_state[k] != 0; k--);
+  if (k < 0)
+    return k;
+  sprite_state[k] = 10;
+  sprite_type[k] = 0xEC;
+  Sprite_SetX(k, x);
+  Sprite_SetY(k, y);
+  SpritePrep_LoadProperties(k);
+  sprite_floor[k] = link_is_on_lower_level;
+  sprite_C[k] = what;
+  if (what >= 6)
+    sprite_flags2[k] = 0xa6;
+  // oob read, this array has only 6 elements.
+  uint8 flags = kThrowableScenery_Flags[what];
+  if (what == 2) {
+    if (player_is_indoors)
+      sprite_oam_flags[k] = 0x80, flags = 0x50;  // wtf
+  }
+  sprite_oam_flags[k] = flags;
+  sprite_unk4[k] = 9;
+  flag_is_sprite_to_pick_up = 2;
+  byte_7E0FB2 = 2;
+  sprite_delay_main[k] = 16;
+  sprite_floor[k] = link_is_on_lower_level;
+  sprite_graphics[k] = 0;
+  if (BYTE(dung_secrets_unk1) != 255) {
+    if (!(BYTE(dung_secrets_unk1) | player_is_indoors) && (uint8)(sprite_C[k] - 2) < 2)
+      Overworld_SubstituteAlternateSecret();
+    if (dung_secrets_unk1 & 0x80) {
+      sprite_graphics[k] = dung_secrets_unk1 & 0x7f;
+      BYTE(dung_secrets_unk1) = 0;
+    }
+    Sprite_SpawnSecret(k);
+  }
+  return k;
+}
+
+void Sprite_SpawnSecret(int k) {  // 868264
+  if (!player_is_indoors && (GetRandomNumber() & 8))
+    return;
+  int b = BYTE(dung_secrets_unk1);
+  if (b == 0)
+    return;
+  if (b == 4)
+    b = 19 + (GetRandomNumber() & 3);
+  if (!kSpawnSecretItems[b - 1])
+    return;
+  SpriteSpawnInfo info;
+  int j = Sprite_SpawnDynamically(k, kSpawnSecretItems[b - 1], &info);
+  if (j < 0)
+    return;
+  sprite_ai_state[j] = kSpawnSecretItem_SpawnFlag[b - 1];
+  sprite_ignore_projectile[j] = kSpawnSecretItem_IgnoreProj[b - 1];
+  sprite_z_vel[j] = kSpawnSecretItem_ZVel[b - 1];
+  Sprite_SetX(j, info.r0_x + kSpawnSecretItem_XLo[b - 1]);
+  Sprite_SetY(j, info.r2_y);
+  sprite_z[j] = info.r4_z;
+  sprite_graphics[j] = 0;
+  sprite_delay_aux4[j] = 32;
+  sprite_delay_aux2[j] = 48;
+  uint8 type = sprite_type[j];
+  if (type == 0xe4) {
+    SpritePrep_SmallKey(j);
+    sprite_stunned[j] = 255;
+  } else if (type == 0xb) {
+    sound_effect_1 = 0x30;
+    if (BYTE(dungeon_room_index2) == 1)
+      sprite_subtype[j] = 1;
+    sprite_stunned[j] = 255;
+  } else if (type == 0x41 || type == 0x42) {
+    sound_effect_2 = 4;
+    sprite_give_damage[j] = 0;
+    sprite_hit_timer[j] = 160;
+  } else if (type == 0x3e) {
+    sprite_oam_flags[j] = 9;
+  } else {
+    sprite_stunned[j] = 255;
+    if (type == 0x79)
+      sprite_A[j] = 32;
+  }
+}
+
+void Sprite_Main() {  // 868328
+  if (!player_is_indoors) {
+    ancilla_floor[0] = 0;
+    ancilla_floor[1] = 0;
+    ancilla_floor[2] = 0;
+    ancilla_floor[3] = 0;
+    ancilla_floor[4] = 0;
+    Sprite_ProximityActivation();
+  }
+  is_in_dark_world = (savegame_is_darkworld != 0);
+  if (submodule_index == 0)
+    drag_player_x = drag_player_y = 0;
+  Oam_ResetRegionBases();
+  Garnish_ExecuteUpperSlots();
+  Follower_Main();
+  byte_7E0FB2 = flag_is_sprite_to_pick_up;
+  flag_is_sprite_to_pick_up = 0;
+  HIBYTE(dungmap_var8) = 0x80;
+
+  if (set_when_damaging_enemies & 0x7f)
+    set_when_damaging_enemies--;
+  else
+    set_when_damaging_enemies = 0;
+  byte_7E0379 = 0;
+  link_unk_master_sword = 0;
+  link_prevent_from_moving = 0;
+  if (sprite_alert_flag)
+    sprite_alert_flag--;
+  Ancilla_Main();
+  Overlord_Main();
+  archery_game_out_of_arrows = 0;
+  for (int i = 15; i >= 0; i--) {
+    cur_object_index = i;
+    Sprite_ExecuteSingle(i);
+  }
+  Garnish_ExecuteLowerSlots();
+  byte_7E069E[0] = byte_7E069E[1] = 0;
+  ExecuteCachedSprites();
+  if (load_chr_halfslot_even_odd)
+    byte_7E0FC6 = load_chr_halfslot_even_odd;
+}
+
+void Oam_ResetRegionBases() {  // 8683d3
+  memcpy(oam_region_base, kOam_ResetRegionBases, 12);
+}
+
+void Sprite_TimersAndOam(int k) {  // 8683f2
+  Sprite_Get16BitCoords(k);
+
+  uint8 num = ((sprite_flags2[k] & 0x1f) + 1) * 4;
+
+  if (sort_sprites_setting) {
+    if (sprite_floor[k])
+      Oam_AllocateFromRegionF(num);
+    else
+      Oam_AllocateFromRegionD(num);
+  } else {
+    Oam_AllocateFromRegionA(num);
+  }
+
+  if (!(submodule_index | flag_unk1)) {
+    if (sprite_delay_main[k])
+      sprite_delay_main[k]--;
+    if (sprite_delay_aux1[k])
+      sprite_delay_aux1[k]--;
+    if (sprite_delay_aux2[k])
+      sprite_delay_aux2[k]--;
+    if (sprite_delay_aux3[k])
+      sprite_delay_aux3[k]--;
+
+    uint8 timer = sprite_hit_timer[k] & 0x7f;
+    if (timer) {
+      if (sprite_state[k] >= 9) {
+        if (timer == 31) {
+          Sprite_HitTimer31(k);
+        } else if (timer == 24) {
+          Sprite_MiniMoldorm_Recoil(k);
+        }
+      }
+      if (sprite_give_damage[k] < 251)
+        sprite_obj_prio[k] = sprite_hit_timer[k] * 2 & 0xe;
+      sprite_hit_timer[k]--;
+    } else {
+      sprite_hit_timer[k] = 0;
+      sprite_obj_prio[k] = 0;
+    }
+    if (sprite_delay_aux4[k])
+      sprite_delay_aux4[k]--;
+  }
+
+  static const uint8 kSpritePrios[4] = {0x20, 0x10, 0x30, 0x30};
+  int floor = link_is_on_lower_level;
+  if (floor != 3)
+    floor = sprite_floor[k];
+  sprite_obj_prio[k] = sprite_obj_prio[k] & 0xcf | kSpritePrios[floor];
+}
+
+void Sprite_Get16BitCoords(int k) {  // 8684c1
+  cur_sprite_x = sprite_x_lo[k] | sprite_x_hi[k] << 8;
+  cur_sprite_y = sprite_y_lo[k] | sprite_y_hi[k] << 8;
+}
+
+void Sprite_ExecuteSingle(int k) {  // 8684e2
+  uint8 st = sprite_state[k];
+  if (st != 0)
+    Sprite_TimersAndOam(k);
+  kSprite_ExecuteSingle[st](k);
+}
+
+void Sprite_inactiveSprite(int k) {  // 868510
+  if (!player_is_indoors) {
+    sprite_N_word[k] = 0xffff;
+  } else {
+    sprite_N[k] = 0xff;
+  }
+}
+
+void SpriteModule_Fall1(int k) {  // 86852e
+  if (!sprite_delay_main[k]) {
+    sprite_state[k] = 0;
+    Sprite_ManuallySetDeathFlagUW(k);
+  } else {
+    PrepOamCoordsRet info;
+    if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
+      return;
+    SpriteFall_Draw(k, &info);
+  }
+}
+
+void SpriteModule_Drown(int k) {  // 86859c
+  static const DrawMultipleData kSpriteDrown_Dmd[8] = {
+    {-7, -7, 0x0480, 0},
+    {14, -6, 0x0483, 0},
+    {-6, -6, 0x04cf, 0},
+    {13, -5, 0x04df, 0},
+    {-4, -4, 0x04ae, 0},
+    {12, -4, 0x44af, 0},
+    { 0,  0, 0x04e7, 2},
+    { 0,  0, 0x04e7, 2},
+  };
+  static const uint8 kSpriteDrown_Oam_Flags[4] = {0, 0x40, 0xc0, 0x80};
+  static const uint8 kSpriteDrown_Oam_Char[11] = {0xc0, 0xc0, 0xc0, 0xc0, 0xcd, 0xcd, 0xcd, 0xcb, 0xcb, 0xcb, 0xcb};
+
+  if (sprite_ai_state[k]) {
+    if (sprite_A[k] == 6)
+      Oam_AllocateFromRegionC(8);
+    sprite_flags3[k] ^= 16;
+    SpriteDraw_SingleLarge(k);
+    OamEnt *oam = GetOamCurPtr();
+    int j = sprite_delay_main[k];
+    if (j == 1)
+      sprite_state[k] = 0;
+    if (j != 0) {
+      assert((j >> 1) < 11);
+      oam->charnum = kSpriteDrown_Oam_Char[j >> 1];
+      oam->flags = 0x24;
+      return;
+    }
+    oam->charnum = 0x8a;
+    oam->flags = kSpriteDrown_Oam_Flags[sprite_subtype2[k] >> 2 & 3] | 0x24;
+
+    if (Sprite_ReturnIfPaused(k))
+      return;
+    sprite_subtype2[k]++;
+    Sprite_MoveXY(k);
+    Sprite_MoveZ(k);
+    sprite_z_vel[k] -= 2;
+    if (sign8(sprite_z[k])) {
+      sprite_z[k] = 0;
+      sprite_delay_main[k] = 18;
+      sprite_flags3[k] &= ~0x10;
+    }
+  } else {
+    if (Sprite_ReturnIfPaused(k))
+      return;
+    if (!(frame_counter & 1))
+      sprite_delay_main[k]++;
+    sprite_oam_flags[k] = 0;
+    sprite_hit_timer[k] = 0;
+    if (!sprite_delay_main[k])
+      sprite_state[k] = 0;
+    Sprite_DrawMultiple(k, &kSpriteDrown_Dmd[(sprite_delay_main[k] << 1 & 0xf8) >> 2], 2, NULL);
+  }
+}
+
+void Sprite_DrawDistress_custom(uint16 xin, uint16 yin, uint8 time) {  // 86a733
+  Oam_AllocateFromRegionA(0x10);
+  if (!(time & 0x18))
+    return;
+  int i = 3;
+  OamEnt *oam = GetOamCurPtr();
+  do {
+    SetOamHelper0(oam, xin + kSpriteDistress_X[i], yin + kSpriteDistress_Y[i],
+                  0x83, 0x22, 0);
+  } while (oam++, --i >= 0);
+}
+
+void Sprite_CheckIfLifted_permissive(int k) {  // 86aa0c
+  Sprite_ReturnIfLiftedPermissive(k);
+}
+
+void Entity_ApplyRumbleToSprites(SpriteHitBox *hb) {  // 86ad03
+  for (int j = 15; j >= 0; j--) {
+    if (!(sprite_defl_bits[j] & 2) || sprite_E[j] == 0)
+      continue;
+    if (byte_7E0FC6 != 0xe) {
+      Sprite_SetupHitBox(j, hb);
+      if (!CheckIfHitBoxesOverlap(hb))
+        continue;
+    }
+    sprite_E[j] = 0;
+    sound_effect_2 = 0x30;
+    sprite_z_vel[j] = 0x30;
+    sprite_x_vel[j] = 0x10;
+    sprite_delay_aux3[j] = 0x30;
+    sprite_stunned[j] = 255;
+    if (sprite_type[j] == 0xd8)
+      Sprite_TransmuteToBomb(j);
+  }
+}
+
+void Sprite_ZeroVelocity_XY(int k) {  // 86cf5d
+  sprite_x_vel[k] = sprite_y_vel[k] = 0;
+}
+
+bool Sprite_HandleDraggingByAncilla(int k) {  // 86cf64
+  int j = sprite_B[k];
+  if (j-- == 0)
+    return false;
+  if (ancilla_type[j] == 0) {
+    Sprite_HandleAbsorptionByPlayer(k);
+  } else {
+    sprite_x_lo[k] = ancilla_x_lo[j];
+    sprite_x_hi[k] = ancilla_x_hi[j];
+    sprite_y_lo[k] = ancilla_y_lo[j];
+    sprite_y_hi[k] = ancilla_y_hi[j];
+    sprite_z[k] = 0;
+  }
+  return true;
+}
+
+bool Sprite_ReturnIfPhasingOut(int k) {  // 86d0ed
+  if (!sprite_stunned[k] || (submodule_index | flag_unk1))
+    return false;
+  if (!(frame_counter & 1))
+    sprite_stunned[k]--;
+  uint8 a = sprite_stunned[k];
+  if (a == 0)
+    sprite_state[k] = 0;
+  else if (a >= 0x28 || (a & 1) != 0)
+    return false;
+  PrepOamCoordsRet info;
+  Sprite_PrepOamCoordOrDoubleRet(k, &info);
+  return true;
+}
+
+void Sprite_CheckAbsorptionByPlayer(int k) {  // 86d116
+  if (!sprite_delay_aux4[k] && Sprite_CheckDamageToPlayer_1(k))
+    Sprite_HandleAbsorptionByPlayer(k);
+}
+
+void Sprite_HandleAbsorptionByPlayer(int k) {  // 86d13c
+  sprite_state[k] = 0;
+  int t = sprite_type[k] - 0xd8;
+  SpriteSfx_QueueSfx3WithPan(k, kAbsorptionSfx[t]);
+  switch(t) {
+  case 0:
+    link_hearts_filler += 8;
+    break;
+  case 1: case 2: case 3:
+    link_rupees_goal += kRupeesAbsorption[t - 1];
+    break;
+  case 4: case 5: case 6:
+    link_bomb_filler += kBombsAbsorption[t - 4];
+    break;
+  case 7:
+    link_magic_filler += 0x10;
+    break;
+  case 8:
+    link_magic_filler = 0x80;
+    break;
+  case 9:
+    link_arrow_filler += (sprite_head_dir[k] == 0) ? 5 : sprite_head_dir[k];
+    break;
+  case 10:
+    link_arrow_filler += 10;
+    break;
+  case 11:
+    SpriteSfx_QueueSfx2WithPan(k, 0x31);
+    link_hearts_filler += 56;
+    break;
+  case 12:
+    link_num_keys += 1;
+    goto after_getkey;
+  case 13:
+    item_receipt_method = 0;
+    Link_ReceiveItem(0x32, 0);
+  after_getkey:
+    sprite_N[k] = sprite_subtype[k];
+    dung_savegame_state_bits |= kAbsorbBigKey[sprite_die_action[k]] << 8;
+    Sprite_ManuallySetDeathFlagUW(k);
+    break;
+  case 14:
+    link_shield_type = sprite_subtype[k];
+    // Shield needs to have the right palette after pikit
+    if (enhanced_features0 & kFeatures0_MiscBugFixes)
+      Palette_Load_Shield();
+    break;
+  }
+}
+
+bool SpriteDraw_AbsorbableTransient(int k, bool transient) {  // 86d22f
+  if (transient && Sprite_ReturnIfPhasingOut(k))
+    return false;
+  if (sort_sprites_setting == 0 && player_is_indoors != 0)
+    sprite_obj_prio[k] = 0x30;
+  if (byte_7E0FC6 >= 3)
+    return false;
+  if (sprite_delay_aux2[k] != 0)
+    Oam_AllocateFromRegionC(12);
+  if (sprite_E[k] != 0) {
+    // This code runs when an absorbable is hidden under say a rock.
+    // sprite_B holds the sprite that grabbed us with a hookshot.
+    // Cancel the grab if we're hidden.
+    if (enhanced_features0 & kFeatures0_MiscBugFixes)
+      sprite_B[k] = 0;
+    return true;
+  }
+  uint8 j = sprite_type[k];
+  assert(j >= 0xd8 && j < 0xd8 + 19);
+  uint8 a = kAbsorbable_Tab2[j - 0xd8];
+  if (a != 0) {
+    Sprite_DrawNumberedAbsorbable(k, a);
+    return false;
+  }
+  uint8 t = kAbsorbable_Tab1[j - 0xd8];
+  if (t == 0) {
+    SpriteDraw_SingleSmall(k);
+    return false;
+  }
+  if (t == 2) {
+    if (sprite_type[k] == 0xe6) {
+      if (sprite_subtype[k] == 1)
+        goto draw_key;
+      sprite_graphics[k] = 1;
+    }
+    SpriteDraw_SingleLarge(k);
+    return false;
+  }
+draw_key:
+  Sprite_DrawThinAndTall(k);
+  return false;
+}
+
+void Sprite_DrawNumberedAbsorbable(int k, int a) {  // 86d2fa
+  a = (a - 1) * 3;
+  PrepOamCoordsRet info;
+  if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
+    return;
+  OamEnt *oam = GetOamCurPtr();
+  int n = (sprite_head_dir[k] < 1) ? 2 : 1;
+  do {
+    int j = n + a;
+    SetOamHelper0(oam,
+                  info.x + kNumberedAbsorbable_X[j], info.y + kNumberedAbsorbable_Y[j],
+                  kNumberedAbsorbable_Char[j], info.flags,
+                  kNumberedAbsorbable_Ext[j]);
+  } while (oam++, --n >= 0);
+  SpriteDraw_Shadow(k, &info);
+}
+
+void Sprite_BounceOffWall(int k) {  // 86d9c0
+  if (sprite_wallcoll[k] & 3)
+    sprite_x_vel[k] = -sprite_x_vel[k];
+  if (sprite_wallcoll[k] & 12)
+    sprite_y_vel[k] = -sprite_y_vel[k];
+}
+
+void Sprite_InvertSpeed_XY(int k) {  // 86d9d5
+  sprite_x_vel[k] = -sprite_x_vel[k];
+  sprite_y_vel[k] = -sprite_y_vel[k];
+}
+
+bool Sprite_ReturnIfInactive(int k) {  // 86d9ec
+  return (sprite_state[k] != 9 || flag_unk1 || submodule_index || !(sprite_defl_bits[k] & 0x80) && sprite_pause[k]);
+}
+
+bool Sprite_ReturnIfPaused(int k) {  // 86d9f3
+  return (flag_unk1 || submodule_index || !(sprite_defl_bits[k] & 0x80) && sprite_pause[k]);
+}
+
+void SpriteDraw_SingleLarge(int k) {  // 86dc10
+  PrepOamCoordsRet info;
+  if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
+    return;
+  Sprite_PrepAndDrawSingleLargeNoPrep(k, &info);
+}
+
+void Sprite_PrepAndDrawSingleLargeNoPrep(int k, PrepOamCoordsRet *info) {  // 86dc13
+  OamEnt *oam = GetOamCurPtr();
+  oam->x = info->x;
+  if ((uint16)(info->y + 0x10) < 0x100) {
+    oam->y = info->y;
+    oam->charnum = kSprite_PrepAndDrawSingleLarge_Tab2[kSprite_PrepAndDrawSingleLarge_Tab1[sprite_type[k]] + sprite_graphics[k]];
+    oam->flags = info->flags;
+  }
+  bytewise_extended_oam[oam - oam_buf] = 2 | ((info->x >= 256) ? 1: 0);
+  if (sprite_flags3[k] & 0x10)
+    SpriteDraw_Shadow(k, info);
+}
+
+void SpriteDraw_Shadow_custom(int k, PrepOamCoordsRet *info, uint8 a) {  // 86dc5c
+  uint16 y = Sprite_GetY(k) + a;
+  info->y = y;
+  if (sprite_pause[k] || sprite_state[k] == 10 && sprite_unk3[k] == 3)
+    return;
+  y -= BG2VOFS_copy2;
+  info->y = y;
+  if ((uint16)(y + 0x10) >= 0x100)
+    return;
+  OamEnt *oam = GetOamCurPtr() + (sprite_flags2[k] & 0x1f);
+  if (sprite_flags3[k] & 0x20) {
+    SetOamHelper1(oam, info->x, y + 1, 0x38, (info->flags & 0x30) | 8, 0);
+  } else {
+    SetOamHelper1(oam, info->x, y, 0x6c, (info->flags & 0x30) | 8, 2);
+  }
+}
+
+void SpriteDraw_Shadow(int k, PrepOamCoordsRet *oam) {  // 86dc64
+  SpriteDraw_Shadow_custom(k, oam, 10);
+}
+
+void SpriteDraw_SingleSmall(int k) {  // 86dcef
+  PrepOamCoordsRet info;
+  if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
+    return;
+  OamEnt *oam = GetOamCurPtr();
+  oam->x = info.x;
+  if ((uint16)(info.y + 0x10) < 0x100) {
+    oam->y = info.y;
+    oam->charnum = kSprite_PrepAndDrawSingleLarge_Tab2[kSprite_PrepAndDrawSingleLarge_Tab1[sprite_type[k]] + sprite_graphics[k]];
+    oam->flags = info.flags;
+  }
+  bytewise_extended_oam[oam - oam_buf] = 0 | (info.x >= 256);
+  if (sprite_flags3[k] & 0x10)
+    SpriteDraw_Shadow_custom(k, &info, 2);
+}
+
+void Sprite_DrawThinAndTall(int k) {  // 86dd40
+  PrepOamCoordsRet info;
+  if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
+    return;
+  OamEnt *oam = GetOamCurPtr();
+  uint8 a = kSprite_PrepAndDrawSingleLarge_Tab2[kSprite_PrepAndDrawSingleLarge_Tab1[sprite_type[k]] + sprite_graphics[k]];
+  SetOamHelper0(oam + 0, info.x, info.y + 0, a + 0x00, info.flags, 0);
+  SetOamHelper0(oam + 1, info.x, info.y + 8, a + 0x10, info.flags, 0);
+  if (sprite_flags3[k] & 0x10)
+    SpriteDraw_Shadow(k, &info);
+}
+
+void SpriteModule_Carried(int k) {  // 86de83
+
+
+  static const uint8 kSpriteHeld_ZForFrame[6] = {3, 2, 1, 3, 2, 1};
+  static const int8 kSpriteHeld_X[16] = {0, 0, 0, 0, 0, 0, 0, 0, -13, -10, -5, 0, 13, 10, 5, 0};
+  static const uint8 kSpriteHeld_Z[16] = {13, 14, 15, 16, 0, 10, 22, 16, 8, 11, 14, 16, 8, 11, 14, 16};
+  sprite_room[k] = overworld_area_index;
+  if (sprite_unk3[k] != 3) {
+    if (sprite_delay_main[k] == 0) {
+      sprite_delay_main[k] = (sprite_C[k] == 6) ? 8 : 4;
+      sprite_unk3[k]++;
+    }
+  } else {
+    sprite_flags3[k] &= ~0x10;
+  }
+
+  uint8 t = sprite_delay_aux4[k] - 1;
+  uint8 r0 = t < 63 && (t & 2);
+  int j = link_direction_facing * 2 + sprite_unk3[k];
+
+  int t0 = (uint8)link_x_coord + (uint8)kSpriteHeld_X[j];
+  int t1 = (uint8)t0 + (t0 >> 8 & 1) + r0;
+  int t2 = HIBYTE(link_x_coord) + (t1 >> 8 & 1) + (t0 >> 8 & 1) + (uint8)(kSpriteHeld_X[j]>>8);
+  sprite_x_lo[k] = t1;
+  sprite_x_hi[k] = t2;
+
+ // Sprite_SetX(k, link_x_coord + kSpriteHeld_X[j] + r0);
+  sprite_z[k] = kSpriteHeld_Z[j];
+  int an = link_animation_steps < 6 ? link_animation_steps : 0;
+  uint16 z = link_z_coord + 1 + kSpriteHeld_ZForFrame[an];
+  Sprite_SetY(k, link_y_coord + 8 - z);
+  sprite_floor[k] = link_is_on_lower_level & 1;
+  CarriedSprite_CheckForThrow(k);
+  Sprite_Get16BitCoords(k);
+  if (sprite_unk4[k] != 11) {
+    SpriteActive_Main(k);
+    if (sprite_delay_aux4[k] == 1) {
+      sprite_state[k] = 9;
+      sprite_B[k] = 0;
+      sprite_delay_aux4[k] = 96;
+      sprite_z_vel[k] = 32;
+      sprite_flags3[k] |= 0x10;
+      link_picking_throw_state = 2;
+    }
+  } else {
+    SpriteStunned_Main_Func1(k);
+  }
+}
+
+void CarriedSprite_CheckForThrow(int k) {  // 86df6d
+  static const int8 kSpriteHeld_Throw_Xvel[4] = {0, 0, -62, 63};
+  static const int8 kSpriteHeld_Throw_Yvel[4] = {-62, 63, 0, 0};
+  static const uint8 kSpriteHeld_Throw_Zvel[4] = {4, 4, 4, 4};
+
+  if (main_module_index == 14)
+    return;
+
+  if (player_near_pit_state != 2) {
+    uint8 t = (link_auxiliary_state & 1) | link_is_in_deep_water | link_is_bunny_mirror |
+              link_pose_for_item | (link_disable_sprite_damage ? 0 : link_incapacitated_timer);
+    if (!t) {
+      if (sprite_unk3[k] != 3 || !((filtered_joypad_H | filtered_joypad_L) & 0x80))
+        return;
+      filtered_joypad_L &= 0x7f;
+    }
+  }
+
+  SpriteSfx_QueueSfx3WithPan(k, 0x13);
+  link_picking_throw_state = 2;
+  sprite_state[k] = sprite_unk4[k];
+  sprite_z_vel[k] = 0;
+  sprite_unk3[k] = 0;
+  sprite_flags3[k] = sprite_flags3[k] & ~0x10 | kSpriteInit_Flags3[sprite_type[k]] & 0x10;
+  int j = link_direction_facing >> 1;
+  sprite_x_vel[k] = kSpriteHeld_Throw_Xvel[j];
+  sprite_y_vel[k] = kSpriteHeld_Throw_Yvel[j];
+  sprite_z_vel[k] = kSpriteHeld_Throw_Zvel[j];
+  sprite_delay_aux4[k] = 0;
+}
+
+void SpriteModule_Stunned(int k) {  // 86dffa
+  SpriteStunned_MainEx(k, false);
+}
+
+void ThrownSprite_TileAndSpriteInteraction(int k) {  // 86e02a
+  SpriteStunned_MainEx(k, true);
+}
+
+void Sprite_Func8(int k) {  // 86e0ab
+  sprite_state[k] = 1;
+  sprite_delay_main[k] = 0x1f;
+  sound_effect_1 = 0;
+  SpriteSfx_QueueSfx2WithPan(k, 0x20);
+}
+
+void Sprite_Func22(int k) {  // 86e0f6
+  sound_effect_1 = Sprite_CalculateSfxPan(k) | 0x28;
+  sprite_state[k] = 3;
+  sprite_delay_main[k] = 15;
+  sprite_ai_state[k] = 0;
+  GetRandomNumber(); // wtf
+  sprite_flags2[k] = 3;
+}
+
+void ThrowableScenery_InteractWithSpritesAndTiles(int k) {  // 86e164
+  Sprite_MoveXY(k);
+  if (!sprite_E[k])
+    Sprite_CheckTileCollision(k);
+  ThrownSprite_TileAndSpriteInteraction(k);
+}
+
+void ThrownSprite_CheckDamageToSprites(int k) {  // 86e172
+  if (sprite_delay_aux4[k] || !(sprite_x_vel[k] | sprite_y_vel[k]))
+    return;
+  for (int i = 15; i >= 0; i--) {
+    if (i != cur_object_index && sprite_type[k] != 0xd2 && sprite_state[i] >= 9 &&
+      ((i ^ frame_counter) & 3 | sprite_ignore_projectile[i] | sprite_hit_timer[i]) == 0 && sprite_floor[k] == sprite_floor[i])
+      ThrownSprite_CheckDamageToSingleSprite(k, i);
+  }
+}
+
+void ThrownSprite_CheckDamageToSingleSprite(int k, int j) {  // 86e1b2
+  SpriteHitBox hb;
+  hb.r0_xlo = sprite_x_lo[k];
+  hb.r8_xhi = sprite_x_hi[k];
+  hb.r2 = 15;
+  int t = sprite_y_lo[k] - sprite_z[k];
+  int u = (t & 0xff) + 8;
+  hb.r1_ylo = u;
+  hb.r9_yhi = sprite_y_hi[k] + (u >> 8) - (t < 0);
+  hb.r3 = 8;
+  Sprite_SetupHitBox(j, &hb);
+  if (!CheckIfHitBoxesOverlap(&hb))
+    return;
+  if (sprite_type[j] == 0x3f) {
+    Sprite_PlaceWeaponTink(k);
+  } else {
+    uint8 a = (sprite_type[k] == 0xec && sprite_C[k] == 2 && !player_is_indoors) ? 1 : 3;
+    Ancilla_CheckDamageToSprite_preset(j, a);
+
+    sprite_x_recoil[j] = sprite_x_vel[k] * 2;
+    sprite_y_recoil[j] = sprite_y_vel[k] * 2;
+    sprite_delay_aux4[k] = 16;
+  }
+  Sprite_ApplyRicochet(k);
+}
+
+void Sprite_ApplyRicochet(int k) {  // 86e229
+  Sprite_InvertSpeed_XY(k);
+  Sprite_HalveSpeed_XY(k);
+  ThrowableScenery_TransmuteIfValid(k);
+}
+
+void ThrowableScenery_TransmuteIfValid(int k) {  // 86e22f
+  if (sprite_type[k] != 0xec)
+    return;
+  repulsespark_timer = 0;
+  ThrowableScenery_TransmuteToDebris(k);
+}
+
+void ThrowableScenery_TransmuteToDebris(int k) {  // 86e239
+  uint8 a = sprite_graphics[k];
+  if (a != 0) {
+    BYTE(dung_secrets_unk1) = a;
+    Sprite_SpawnSecret(k);
+    BYTE(dung_secrets_unk1) = 0;
+  }
+  a = player_is_indoors ? 0 : sprite_C[k];
+  sound_effect_1 = 0;
+  SpriteSfx_QueueSfx2WithPan(k, kSprite_Func21_Sfx[a]);
+  Sprite_ScheduleForBreakage(k);
+}
+
+void Sprite_ScheduleForBreakage(int k) {  // 86e25a
+  sprite_delay_main[k] = 31;
+  sprite_state[k] = 6;
+  sprite_flags2[k] += 4;
+}
+
+void Sprite_HalveSpeed_XY(int k) {  // 86e26e
+  sprite_x_vel[k] = (int8)sprite_x_vel[k] >> 1;
+  sprite_y_vel[k] = (int8)sprite_y_vel[k] >> 1;
+}
+
+void Sprite_SpawnLeapingFish(int k) {  // 86e286
+  SpriteSpawnInfo info;
+  int j = Sprite_SpawnDynamically(k, 0xd2, &info);
+  if (j < 0)
+    return;
+  Sprite_SetSpawnedCoordinates(j, &info);
+  sprite_ai_state[j] = 2;
+  sprite_delay_main[j] = 48;
+  if (sprite_type[k] == 0xd2)
+    sprite_A[j] = 0xd2;
+}
+
+void SpriteStunned_Main_Func1(int k) {  // 86e2ba
+  SpriteActive_Main(k);
+  if (sprite_unk5[k]) {
+    if (sprite_delay_main[k] < 32)
+      sprite_oam_flags[k] = sprite_oam_flags[k] & 0xf1 | 4;
+    uint8 t = ((k << 4) ^ frame_counter) | submodule_index;
+    if (t & kSpriteStunned_Main_Func1_Masks[sprite_delay_main[k] >> 4])
+      return;
+    uint16 x = kSparkleGarnish_XY[GetRandomNumber() & 3];
+    uint16 y = kSparkleGarnish_XY[GetRandomNumber() & 3];
+    Sprite_GarnishSpawn_Sparkle(k, x, y);
+  } else {
+    if ((frame_counter & 1) | submodule_index | flag_unk1)
+      return;
+    uint8 t = sprite_stunned[k];
+    if (t) {
+      sprite_stunned[k]--;
+      if (t < 0x38) {
+        sprite_x_vel[k] = (t & 1) ? -8 : 8;
+        Sprite_MoveX(k);
+      }
+      return;
+    }
+    sprite_state[k] = 9;
+    sprite_x_recoil[k] = 0;
+    sprite_y_recoil[k] = 0;
+  }
+}
+
+void SpriteModule_Poof(int k) {  // 86e393
+  static const int8 kSpritePoof_X[16] = {-6, 10, 1, 13, -6, 10, 1, 13, -7, 4, -5, 6, -1, 1, -2, 0};
+  static const int8 kSpritePoof_Y[16] = {-6, -4, 10, 9, -6, -4, 10, 9, -8, -10, 4, 3, -1, -2, 0, 1};
+  static const uint8 kSpritePoof_Char[16] = {0x9b, 0x9b, 0x9b, 0x9b, 0xb3, 0xb3, 0xb3, 0xb3, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a};
+  static const uint8 kSpritePoof_Flags[16] = {0x24, 0xa4, 0x24, 0xa4, 0xe4, 0x64, 0xa4, 0x24, 0x24, 0xe4, 0xe4, 0xe4, 0x24, 0xe4, 0xe4, 0xe4};
+  static const uint8 kSpritePoof_Ext[16] = {0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2};
+  // Frozen sprite pulverized by hammer
+  if (sprite_delay_main[k] == 0) {
+    if (sprite_type[k] == 0xd && sprite_head_dir[k] != 0) {
+      // buzz blob?
+      int bakx = Sprite_GetX(k);
+      PrepareEnemyDrop(k, 0xd);
+      Sprite_SetX(k, bakx);
+      sprite_z_vel[k] = 0;
+      sprite_ignore_projectile[k] = 0;
+    } else {
+      if (sprite_die_action[k] == 0) {
+        ForcePrizeDrop(k, 2, 2);
+      } else {
+        Sprite_DoTheDeath(k);
+      }
+    }
+  } else {
+    PrepOamCoordsRet info;
+    if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
+      return;
+    OamEnt *oam = GetOamCurPtr();
+    int j = ((sprite_delay_main[k] >> 1) & ~3) + 3;
+    for (int i = 3; i >= 0; i--, j--, oam++) {
+      SetOamPlain(oam, kSpritePoof_X[j] + BYTE(dungmap_var7), kSpritePoof_Y[j] + HIBYTE(dungmap_var7),
+                   kSpritePoof_Char[j], kSpritePoof_Flags[j], kSpritePoof_Ext[j]);
+    }
+    Sprite_CorrectOamEntries(k, 3, 0xff);
+  }
+}
+
+void Sprite_PrepOamCoord(int k, PrepOamCoordsRet *ret) {  // 86e416
+  Sprite_PrepOamCoordOrDoubleRet(k, ret);
+}
+
+bool Sprite_PrepOamCoordOrDoubleRet(int k, PrepOamCoordsRet *ret) {  // 86e41e
+  sprite_pause[k] = 0;
+  uint16 x = cur_sprite_x - BG2HOFS_copy2;
+  uint16 y = cur_sprite_y - BG2VOFS_copy2;
+  bool out_of_bounds = false;
+  R0 = x;
+  R2 = y - sprite_z[k];
+  ret->flags = sprite_oam_flags[k] ^ sprite_obj_prio[k];
+  ret->r4 = 0;
+  int xt = (enhanced_features0 & kFeatures0_ExtendScreen64) ? 0x40 : 0;
+
+  if ((uint16)(x + 0x40 + xt) >= (0x170 + xt * 2) ||
+      (uint16)(y + 0x40) >= 0x170 && !(sprite_flags4[k] & 0x20)) {
+    sprite_pause[k]++;
+    if (!(sprite_defl_bits[k] & 0x80))
+      Sprite_KillSelf(k);
+    out_of_bounds = true;
+  }
+  ret->x = R0;
+  ret->y = R2;
+  BYTE(dungmap_var7) = ret->x;
+  HIBYTE(dungmap_var7) = ret->y;
+  return out_of_bounds;
+}
+
+void Sprite_CheckTileCollision2(int k) {  // 86e4ab
+  sprite_wallcoll[k] = 0;
+  if (sign8(sprite_flags4[k]) || !dung_hdr_collision) {
+    Sprite_CheckTileCollisionSingleLayer(k);
+    return;
+  }
+  byte_7E0FB6 = sprite_floor[k];
+  sprite_floor[k] = 1;
+  Sprite_CheckTileCollisionSingleLayer(k);
+  if (dung_hdr_collision == 4) {
+    sprite_floor[k] = byte_7E0FB6;
+    return;
+  }
+  sprite_floor[k] = 0;
+  Sprite_CheckTileCollisionSingleLayer(k);
+  byte_7FFABC[k] = sprite_tiletype;
+}
+
+void Sprite_CheckTileCollisionSingleLayer(int k) {  // 86e4db
+  if (sprite_flags2[k] & 0x20) {
+    if (Sprite_CheckTileProperty(k, 0x6a))
+      sprite_wallcoll[k]++;
+    return;
+  }
+
+  if (sign8(sprite_flags4[k]) || dung_hdr_collision == 0) {
+    if (sprite_y_vel[k])
+      Sprite_CheckForTileInDirection_vertical(k, sign8(sprite_y_vel[k]) ? 0 : 1);
+    if (sprite_x_vel[k])
+      Sprite_CheckForTileInDirection_horizontal(k, sign8(sprite_x_vel[k]) ? 2 : 3);
+  } else {
+    Sprite_CheckForTileInDirection_vertical(k, 1);
+    Sprite_CheckForTileInDirection_vertical(k, 0);
+    Sprite_CheckForTileInDirection_horizontal(k, 3);
+    Sprite_CheckForTileInDirection_horizontal(k, 2);
+  }
+
+  if (sign8(sprite_flags5[k]) || sprite_z[k])
+    return;
+
+  Sprite_CheckTileProperty(k, 0x68);
+  sprite_I[k] = sprite_tiletype;
+  if (sprite_tiletype == 0x1c) {
+    if (sort_sprites_setting && sprite_state[k] == 11)
+      sprite_floor[k] = 1;
+  } else if (sprite_tiletype == 0x20) {
+    if (sprite_flags[k] & 1) {
+      if (!player_is_indoors) {
+        Sprite_Func8(k);
+      } else {
+        sprite_state[k] = 5;
+        if (sprite_type[k] == 0x13 || sprite_type[k] == 0x26) {
+          sprite_oam_flags[k] &= ~1;
+          sprite_delay_main[k] = 63;
+        } else {
+          sprite_delay_main[k] = 95;
+        }
+      }
+    }
+  } else if (sprite_tiletype == 0xc) {
+    if (byte_7FFABC[k] == 0x1c) {
+      SpriteFall_AdjustPosition(k);
+      sprite_wallcoll[k] |= 0x20;
+    }
+  } else if (sprite_tiletype >= 0x68 && sprite_tiletype < 0x6c) {
+    Sprite_ApplyConveyor(k, sprite_tiletype);
+  } else if (sprite_tiletype == 8) {
+    if (dung_hdr_collision == 4)
+      Sprite_ApplyConveyor(k, 0x6a);
+  }
+}
+
+void Sprite_CheckForTileInDirection_horizontal(int k, int yy) {  // 86e5b8
+  if (!Sprite_CheckTileInDirection(k, yy))
+    return;
+  sprite_wallcoll[k] |= kSprite_Func7_Tab[yy];
+  if ((sprite_subtype[k] & 7) < 5) {
+    int8 n = sprite_F[k] ? 3 : 1;
+    SpriteAddXY(k, (yy & 1) ? -n : n, 0);
+  }
+}
+
+void Sprite_CheckForTileInDirection_vertical(int k, int yy) {  // 86e5ee
+  if (!Sprite_CheckTileInDirection(k, yy))
+    return;
+  sprite_wallcoll[k] |= kSprite_Func7_Tab[yy];
+  if ((sprite_subtype[k] & 7) < 5) {
+    int8 n = sprite_F[k] ? 3 : 1;
+    SpriteAddXY(k, 0, (yy & 1) ? -n : n);
+  }
+}
+
+void SpriteFall_AdjustPosition(int k) {  // 86e624
+  SpriteAddXY(k, dung_floor_x_vel, dung_floor_y_vel);
+}
+
+bool Sprite_CheckTileInDirection(int k, int yy) {  // 86e72f
+  uint8 t = (sprite_flags[k] & 0xf0);
+  yy = 2 * ((t >> 2) + yy);
+  return Sprite_CheckTileProperty(k, yy);
+}
+
+bool Sprite_CheckTileProperty(int k, int j) {  // 86e73c
+  uint16 x, y;
+  bool in_bounds;
+  j >>= 1;
+
+  if (player_is_indoors) {
+    x = (cur_sprite_x + 8 & 0x1ff) + kSprite_Func5_X[j] - 8;
+    y = (cur_sprite_y + 8 & 0x1ff) + kSprite_Func5_Y[j] - 8;
+    in_bounds = (x < 0x200) && (y < 0x200);
+  } else {
+    x = cur_sprite_x + kSprite_Func5_X[j];
+    y = cur_sprite_y + kSprite_Func5_Y[j];
+    in_bounds = (uint16)(x - sprcoll_x_base) < sprcoll_x_size &&
+                (uint16)(y - sprcoll_y_base) < sprcoll_y_size;
+  }
+  if (!in_bounds) {
+    if (sprite_flags2[k] & 0x40) {
+      sprite_state[k] = 0;
+      return false;
+    } else {
+      return true;
+    }
+  }
+
+  int b = Sprite_GetTileAttribute(k, &x, y);
+
+  if (sprite_defl_bits[k] & 8) {
+    uint8 a = kSprite_SimplifiedTileAttr[b];
+    if (a == 4) {
+      if (!player_is_indoors)
+        sprite_E[k] = 4;
+    } else if (a >= 1) {
+      return (sprite_tiletype >= 0x10 && sprite_tiletype < 0x14) ? Entity_CheckSlopedTileCollision(x, y) : true;
+    }
+    return false;
+  }
+
+  if (sprite_flags5[k] & 0x40) {
+    uint8 type = sprite_type[k];
+    if ((type == 0xd2 || type == 0x8a) && b == 9)
+      return false;
+    if (type == 0x94 && !sprite_E[k] || type == 0xe3 || type == 0x8c || type == 0x9a || type == 0x81)
+      return (b != 8) && (b != 9);
+  }
+
+  if (kSprite_Func5_Tab3[b] == 0)
+    return false;
+
+  if (sprite_tiletype >= 0x10 && sprite_tiletype < 0x14)
+    return Entity_CheckSlopedTileCollision(x, y);
+
+  if (sprite_tiletype == 0x44) {
+    if (sprite_F[k] && !sign8(sprite_give_damage[k])) {
+
+      // Some mothula bug fix because we changed damage class 4.
+      if (sprite_type[k] == 0x88 && (enhanced_features0 & kFeatures0_MiscBugFixes)) {
+        if (sprite_hit_timer[k] == 0)
+          Ancilla_CheckDamageToSprite_preset(k, 6);
+      } else {
+        Ancilla_CheckDamageToSprite_preset(k, 4);
+      }
+      if (sprite_hit_timer[k]) {
+        sprite_hit_timer[k] = 153;
+        sprite_F[k] = 0;
+      }
+    }
+  } else if (sprite_tiletype == 0x20) {
+    return !(sprite_flags[k] & 1) || !sprite_F[k];
+  }
+  return true;
+}
+
+uint8 GetTileAttribute(uint8 floor, uint16 *x, uint16 y) {  // 86e87b
+  uint8 tiletype;
+  if (player_is_indoors) {
+    int t = (floor >= 1) ? 0x1000 : 0;
+    t += (*x & 0x1f8) >> 3;
+    t += (y & 0x1f8) << 3;
+    tiletype = dung_bg2_attr_table[t];
+  } else {
+    tiletype = Overworld_GetTileAttributeAtLocation(*x >>= 3, y);
+  }
+  sprite_tiletype = tiletype;
+  return tiletype;
+}
+
+uint8 Sprite_GetTileAttribute(int k, uint16 *x, uint16 y) {  // 86e883
+  return GetTileAttribute(sprite_floor[k], x, y);
+}
+
+bool Entity_CheckSlopedTileCollision(uint16 x, uint16 y) {  // 86e8fe
+  uint8 a = y & 7;
+  uint8 r6 = sprite_tiletype - 0x10;
+  uint8 b = kSlopedTile[r6 * 8 + (x & 7)];
+  return (r6 < 2) ? (b >= a) : (a >= b);
+}
+
+void Sprite_MoveXY(int k) {  // 86e92c
+  Sprite_MoveX(k);
+  Sprite_MoveY(k);
+}
+
+void Sprite_MoveX(int k) {  // 86e932
+  if (sprite_x_vel[k] != 0) {
+    uint32 t = sprite_x_subpixel[k] + (sprite_x_lo[k] << 8) + (sprite_x_hi[k] << 16) + ((int8)sprite_x_vel[k] << 4);
+    sprite_x_subpixel[k] = t, sprite_x_lo[k] = t >> 8, sprite_x_hi[k] = t >> 16;
+  }
+}
+
+void Sprite_MoveY(int k) {  // 86e93e
+  if (sprite_y_vel[k] != 0) {
+    uint32 t = sprite_y_subpixel[k] + (sprite_y_lo[k] << 8) + (sprite_y_hi[k] << 16) + ((int8)sprite_y_vel[k] << 4);
+    sprite_y_subpixel[k] = t, sprite_y_lo[k] = t >> 8, sprite_y_hi[k] = t >> 16;
+  }
+}
+
+void Sprite_MoveZ(int k) {  // 86e96c
+  uint16 z = (sprite_z[k] << 8 | sprite_z_subpos[k]) + ((int8)sprite_z_vel[k] << 4);
+  sprite_z_subpos[k] = z;
+  sprite_z[k] = z >> 8;
+}
+
+ProjectSpeedRet Sprite_ProjectSpeedTowardsLink(int k, uint8 vel) {  // 86e991
+  if (vel == 0) {
+    ProjectSpeedRet rv = { 0, 0, 0, 0 };
+    return rv;
+  }
+  PairU8 below = Sprite_IsBelowLink(k);
+  uint8 r12 = sign8(below.b) ? -below.b : below.b;
+
+  PairU8 right = Sprite_IsRightOfLink(k);
+  uint8 r13 = sign8(right.b) ? -right.b : right.b;
+  uint8 t;
+  bool swapped = false;
+  if (r13 < r12) {
+    swapped = true;
+    t = r12, r12 = r13, r13 = t;
+  }
+  uint8 xvel = vel, yvel = 0;
+  t = 0;
+  do {
+    t += r12;
+    if (t >= r13)
+      t -= r13, yvel++;
+  } while (--vel);
+  if (swapped)
+    t = xvel, xvel = yvel, yvel = t;
+  ProjectSpeedRet rv = {
+    (uint8)(right.a ? -xvel : xvel),
+    (uint8)(below.a ? -yvel : yvel),
+    right.b,
+    below.b
+
+  };
+  return rv;
+}
+
+void Sprite_ApplySpeedTowardsLink(int k, uint8 vel) {  // 86ea04
+  ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLink(k, vel);
+  sprite_x_vel[k] = pt.x;
+  sprite_y_vel[k] = pt.y;
+}
+
+ProjectSpeedRet Sprite_ProjectSpeedTowardsLocation(int k, uint16 x, uint16 y, uint8 vel) {  // 86ea2d
+  if (vel == 0) {
+    ProjectSpeedRet rv = { 0, 0, 0, 0 };
+    return rv;
+  }
+  PairU8 below = Sprite_IsBelowLocation(k, y);
+  uint8 r12 = sign8(below.b) ? -below.b : below.b;
+
+  PairU8 right = Sprite_IsRightOfLocation(k, x);
+  uint8 r13 = sign8(right.b) ? -right.b : right.b;
+  uint8 t;
+  bool swapped = false;
+  if (r13 < r12) {
+    swapped = true;
+    t = r12, r12 = r13, r13 = t;
+  }
+  uint8 xvel = vel, yvel = 0;
+  t = 0;
+  do {
+    t += r12;
+    if (t >= r13)
+      t -= r13, yvel++;
+  } while (--vel);
+  if (swapped)
+    t = xvel, xvel = yvel, yvel = t;
+  ProjectSpeedRet rv = {
+    (uint8)(right.a ? -xvel : xvel),
+    (uint8)(below.a ? -yvel : yvel),
+    right.b,
+    below.b
+  };
+  return rv;
+}
+
+uint8 Sprite_DirectionToFaceLink(int k, PointU8 *coords_out) {  // 86eaa4
+  PairU8 below = Sprite_IsBelowLink(k);
+  PairU8 right = Sprite_IsRightOfLink(k);
+  uint8 ym = sign8(below.b) ? -below.b : below.b;
+  tmp_counter = ym;
+  uint8 xm = sign8(right.b) ? -right.b : right.b;
+  if (coords_out)
+    coords_out->x = right.b, coords_out->y = below.b;
+  return (xm >= ym) ? right.a : below.a + 2;
+}
+
+PairU8 Sprite_IsRightOfLink(int k) {  // 86ead1
+  uint16 x = link_x_coord - Sprite_GetX(k);
+  PairU8 rv = { (uint8)(sign16(x) ? 1 : 0), (uint8)x };
+  return rv;
+}
+
+PairU8 Sprite_IsBelowLink(int k) {  // 86eae8
+  int t = BYTE(link_y_coord) + 8;
+  int u = (t & 0xff) + sprite_z[k];
+  int v = (u & 0xff) - sprite_y_lo[k];
+  int w = HIBYTE(link_y_coord) - sprite_y_hi[k] - (v < 0);
+  uint8 y = (w & 0xff) + (t >> 8) + (u >> 8);
+  PairU8 rv = { (uint8)(sign8(y) ? 1 : 0), (uint8)v };
+  return rv;
+}
+
+PairU8 Sprite_IsRightOfLocation(int k, uint16 x) {  // 86eb0a
+  uint16 xv = x - Sprite_GetX(k);
+  PairU8 rv = { (uint8)(sign16(xv) ? 1 : 0), (uint8)xv };
+  return rv;
+}
+
+PairU8 Sprite_IsBelowLocation(int k, uint16 y) {  // 86eb1d
+  uint16 yv = y - Sprite_GetY(k);
+  PairU8 rv = { (uint8)(sign16(yv) ? 1 : 0), (uint8)yv };
+  return rv;
+}
+
+uint8 Sprite_DirectionToFaceLocation(int k, uint16 x, uint16 y) {  // 86eb30
+  PairU8 below = Sprite_IsBelowLocation(k, y);
+  PairU8 right = Sprite_IsRightOfLocation(k, x);
+  uint8 ym = sign8(below.b) ? -below.b : below.b;
+  tmp_counter = ym;
+  uint8 xm = sign8(right.b) ? -right.b : right.b;
+  return (xm >= ym) ? right.a : below.a + 2;
+}
+
+void Guard_ParrySwordAttacks(int k) {  // 86eb5e
+  if (link_is_on_lower_level != sprite_floor[k] || link_incapacitated_timer | link_auxiliary_state || sign8(sprite_hit_timer[k]))
+    return;
+  SpriteHitBox hb;
+  Sprite_DoHitBoxesFast(k, &hb);
+  if (link_position_mode & 0x10 || player_oam_y_offset == 0x80) {
+    Sprite_AttemptDamageToLinkWithCollisionCheck(k);
+    return;
+  }
+  Player_SetupActionHitBox(&hb);
+  if (sign8(button_b_frames) || !CheckIfHitBoxesOverlap(&hb)) {
+    Sprite_SetupHitBox(k, &hb);
+    if (!CheckIfHitBoxesOverlap(&hb))
+      Sprite_AttemptDamageToLinkWithCollisionCheck(k);
+    else
+      Sprite_AttemptZapDamage(k);
+    return;
+  }
+  if (sprite_type[k] != 0x6a)
+    sprite_F[k] = kSprite_Func1_Tab[GetRandomNumber() & 7];
+  link_incapacitated_timer = kSprite_Func1_Tab2[GetRandomNumber() & 7];
+  ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLink(k, sign8(button_b_frames - 9) ? 32 : 24);
+  sprite_x_recoil[k] = -pt.x;
+  sprite_y_recoil[k] = -pt.y;
+  Sprite_ApplyRecoilToLink(k, sign8(button_b_frames - 9) ? 8 : 16);
+  Link_PlaceWeaponTink();
+  set_when_damaging_enemies = 0x90;
+}
+
+void Sprite_AttemptZapDamage(int k) {  // 86ec02
+  uint8 a = sprite_type[k];
+  if ((a == 0x7a || a == 0xd && (a = link_sword_type) < 4 || (a == 0x24 || a == 0x23) && sprite_delay_main[k] != 0) && sprite_state[k] == 9) {
+    if (!countdown_for_blink) {
+      sprite_delay_aux1[k] = 64;
+      link_electrocute_on_touch = 64;
+      Sprite_AttemptDamageToLinkPlusRecoil(k);
+    }
+  } else {
+    ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLink(k, sign8(button_b_frames - 9) ? 0x50 : 0x40);
+    sprite_x_recoil[k] = -pt.x;
+    sprite_y_recoil[k] = -pt.y;
+    Sprite_CalculateSwordDamage(k);
+  }
+}
+
+void Ancilla_CheckDamageToSprite_preset(int k, int a) {  // 86ece0
+  if (a == 15 && sprite_z[k] != 0)
+    return;
+
+  if (a != 0 && a != 7) {
+    Sprite_Func15(k, a);
+    return;
+  }
+  Sprite_Func15(k, a);
+  if (sprite_give_damage[k] || repulsespark_timer)
+    return;
+  // Called when hitting enemy which is frozen
+  repulsespark_timer = 5;
+  int j = byte_7E0FB6;
+  repulsespark_x_lo = ancilla_x_lo[j] + 4;
+  repulsespark_y_lo = ancilla_y_lo[j];
+  repulsespark_floor_status = link_is_on_lower_level;
+  sound_effect_1 = 0;
+  SpriteSfx_QueueSfx2WithPan(k, 5);
+}
+
+void Sprite_Func15(int k, int a) {  // 86ed25
+  damage_type_determiner = a;
+  Sprite_ApplyCalculatedDamage(k, a == 8 ? 0x35 : 0x20);
+}
+
+void Sprite_CalculateSwordDamage(int k) {  // 86ed3f
+  if (sprite_flags3[k] & 0x40)
+    return;
+  sprite_unk1[k] = link_is_running;
+  uint8 a = link_sword_type - 1;
+  if (!link_is_running)
+    a |= sign8(button_b_frames) ? 4 : sign8(button_b_frames - 9) ? 0 : 8;
+  damage_type_determiner = kSprite_Func14_Damage[a];
+  if (link_item_in_hand & 10)
+    damage_type_determiner = 3;
+  link_sword_delay_timer = 4;
+  set_when_damaging_enemies = 16;
+  Sprite_ApplyCalculatedDamage(k, 0x9d);
+}
+
+void Sprite_ApplyCalculatedDamage(int k, int a) {  // 86ed89
+  if ((sprite_flags3[k] & 0x40) || sprite_type[k] >= 0xD8)
+    return;
+  uint8 dmg = kEnemyDamages[damage_type_determiner * 8 | enemy_damage_data[sprite_type[k] * 16 | damage_type_determiner]];
+  Sprite_GiveDamage(k, dmg, a);
+}
+
+void Sprite_GiveDamage(int k, uint8 dmg, uint8 r0_hit_timer) {  // 86edc5
+  if (dmg == 249) {
+    Sprite_Func18(k, 0xe3);
+    return;
+  }
+  if (dmg == 250) {
+    Sprite_Func18(k, 0x8f);
+    sprite_ai_state[k] = 2;
+    sprite_z_vel[k] = 32;
+    sprite_oam_flags[k] = 8;
+    sprite_F[k] = 0;
+    sprite_hit_timer[k] = 0;
+    sprite_health[k] = 0;
+    sprite_bump_damage[k] = 1;
+    sprite_flags5[k] = 1;
+    return;
+  }
+  if (dmg >= sprite_give_damage[k])
+    sprite_give_damage[k] = dmg;
+  if (dmg == 0) {
+    if (damage_type_determiner != 10) {
+      if (sprite_flags[k] & 4)
+        goto flag4;
+      link_sword_delay_timer = 0;
+    }
+    sprite_hit_timer[k] = 0;
+    sprite_give_damage[k] = 0;
+    return;
+  }
+  if (dmg >= 254 && sprite_state[k] == 11) {
+    sprite_hit_timer[k] = 0;
+    sprite_give_damage[k] = 0;
+    return;
+  }
+  if (sprite_type[k] == 0x9a && sprite_give_damage[k] < 0xf0) {
+    sprite_state[k] = 9;
+    sprite_ai_state[k] = 4;
+    sprite_delay_main[k] = 15;
+    SpriteSfx_QueueSfx2WithPan(k, 0x28);
+    return;
+  }
+  if (sprite_type[k] == 0x1b) {
+    SpriteSfx_QueueSfx2WithPan(k, 5);
+    Sprite_ScheduleForBreakage(k);
+    Sprite_PlaceWeaponTink(k);
+    return;
+  }
+  sprite_hit_timer[k] = r0_hit_timer;
+  if (sprite_type[k] != 0x92 || sprite_C[k] >= 3) {
+    uint8 sfx = sprite_flags[k] & 2 ? 0x21 :
+                sprite_flags5[k] & 0x10 ? 0x1c : 8;
+    sound_effect_2 = sfx | Sprite_CalculateSfxPan(k);
+  }
+  uint8 type;
+flag4:
+  type = sprite_type[k];
+  sprite_F[k] = (damage_type_determiner >= 13) ? 0 :
+                (type == 9) ? 20 :
+                (type == 0x53 || type == 0x18) ? 11 : 15;
+}
+
+void Sprite_Func18(int k, uint8 new_type) {  // 86edcb
+  sprite_type[k] = new_type;
+  SpritePrep_LoadProperties(k);
+  Sprite_SpawnPoofGarnish(k);
+  sound_effect_2 = 0;
+  SpriteSfx_QueueSfx3WithPan(k, 0x32);
+  sprite_hit_timer[k] = 0;
+  sprite_give_damage[k] = 0;
+}
+
+void Sprite_MiniMoldorm_Recoil(int k) {  // 86eec8
+  if (sprite_state[k] < 9)
+    return;
+  tmp_counter = sprite_state[k];
+
+  uint8 dmg = sprite_give_damage[k];
+  if (dmg == 253) {
+    sprite_give_damage[k] = 0;
+    SpriteSfx_QueueSfx3WithPan(k, 9);
+    sprite_state[k] = 7;
+    sprite_delay_main[k] = 0x70;
+    sprite_flags2[k] += 2;
+    sprite_give_damage[k] = 0;
+    return;
+  }
+
+  if (dmg >= 251) {
+    sprite_give_damage[k] = 0;
+    if (sprite_state[k] == 11)
+      return;
+    sprite_unk5[k] = (dmg == 254);
+    if (sprite_unk5[k]) {
+      sprite_defl_bits[k] |= 8;
+      sprite_flags5[k] &= ~0x80;
+      SpriteSfx_QueueSfx2WithPan(k, 15);
+      sprite_z_vel[k] = 24;
+      sprite_bump_damage[k] &= ~0x80;
+      Sprite_ZeroVelocity_XY(k);
+    }
+    sprite_state[k] = 11;
+    sprite_delay_main[k] = 64;
+    static const uint8 kHitTimer24StunValues[5] = {0x20, 0x80, 0, 0, 0xff};
+    sprite_stunned[k] = kHitTimer24StunValues[(uint8)(dmg + 5)];
+    if (sprite_type[k] == 0x23)
+      sprite_type[k] = 0x24;
+    return;
+  }
+
+  int t = sprite_health[k] - sprite_give_damage[k];
+  sprite_health[k] = t;
+  sprite_give_damage[k] = 0;
+  if (t > 0)
+    return;
+
+  if (sprite_die_action[k] == 0) {
+    if (sprite_state[k] == 11)
+      sprite_die_action[k] = 3;
+    if (sprite_unk1[k] != 0) {
+      sprite_unk1[k] = 0;
+      sprite_flags5[k] = 0;
+    }
+  }
+
+  uint8 type = sprite_type[k];
+  if (type != 0x1b)
+    SpriteSfx_QueueSfx3WithPan(k, 9);
+
+  if (type == 0x40)
+    save_ow_event_info[BYTE(overworld_screen_index)] |= 0x40;
+  else if (type == 0xec) {
+    if (sprite_C[k] == 2)
+      ThrowableScenery_TransmuteToDebris(k);
+    return;
+  }
+
+  if (sprite_state[k] == 10) {
+    link_state_bits = 0;
+    link_picking_throw_state = 0;
+  }
+  sprite_state[k] = 6;
+
+  if (type == 0xc) {
+    Sprite_Func3(k);
+  } else if (type == 0x92) {
+    Sprite_KillFriends();
+    sprite_delay_main[k] = 255;
+    goto out_common;
+  } else if (type == 0xcb) {
+    sprite_ai_state[k] = 128;
+    sprite_delay_main[k] = 128;
+    sprite_state[k] = 9;
+    goto out_common;
+  } else if (type == 0xcc || type == 0xcd) {
+    sprite_ai_state[k] = 128;
+    sprite_delay_main[k] = 96;
+    sprite_state[k] = 9;
+    goto out_common;
+  } else if (type == 0x53) {
+    sprite_delay_main[k] = 35;
+    sprite_hit_timer[k] = 0;
+    goto out_common2;
+  } else if (type == 0x54) {
+    sprite_ai_state[k] = 5;
+    sprite_delay_main[k] = 0xc0;
+    sprite_hit_timer[k] = 0xc0;
+    goto out_common;
+  } else if (type == 0x9) {
+    sprite_ai_state[k] = 3;
+    sprite_delay_aux4[k] = 160;
+    sprite_state[k] = 9;
+    goto out_common;
+  } else if (type == 0x7a) {
+    Sprite_KillFriends();
+    sprite_state[k] = 9;
+    sprite_ignore_projectile[k] = 9;
+    if (is_in_dark_world == 0) {
+      sprite_ai_state[k] = 10;
+      sprite_delay_main[k] = 255;
+      sprite_z_vel[k] = 32;
+    } else {
+      sprite_delay_main[k] = 255;
+      sprite_ai_state[k] = 8;
+      sprite_ai_state[1] = 9;
+      sprite_ai_state[2] = 9;
+      sprite_graphics[1] = 0;
+      sprite_graphics[2] = 0;
+    }
+    goto out_common;
+  } else if (type == 0x23 && sprite_C[k] == 0) {
+    sprite_ai_state[k] = 2;
+    sprite_delay_main[k] = 32;
+    sprite_state[k] = 9;
+    sprite_hit_timer[k] = 0;
+  } else if (type == 0xf) {
+    sprite_hit_timer[k] = 0;
+    sprite_delay_main[k] = 15;
+  } else if (!(sprite_flags[k] & 2)) {
+    sprite_delay_main[k] = sprite_hit_timer[k] & 0x80 ? 31 : 15;
+    sprite_flags2[k] += 4;
+    if (tmp_counter == 11)
+      sprite_flags5[k] = 1;
+  } else {
+    if (type != 0xa2)
+      Sprite_KillFriends();
+    sprite_state[k] = 4;
+    sprite_A[k] = 0;
+    sprite_delay_main[k] = 255;
+    sprite_hit_timer[k] = 255;
+  out_common:
+    flag_block_link_menu++;
+  out_common2:
+    sound_effect_2 = 0;
+    SpriteSfx_QueueSfx3WithPan(k, 0x22);
+  }
+}
+
+void Sprite_Func3(int k) {  // 86efda
+  sprite_state[k] = 6;
+  sprite_delay_main[k] = 31;
+  sprite_flags2[k] = 3;
+}
+
+bool Sprite_CheckDamageToLink(int k) {  // 86f145
+  if (link_disable_sprite_damage)
+    return false;
+  return Sprite_CheckDamageToPlayer_1(k);
+}
+
+bool Sprite_CheckDamageToPlayer_1(int k) {  // 86f14a
+  if ((k ^ frame_counter) & 3 | sprite_hit_timer[k])
+    return false;
+  return Sprite_CheckDamageToLink_same_layer(k);
+}
+
+bool Sprite_CheckDamageToLink_same_layer(int k) {  // 86f154
+  if (link_is_on_lower_level != sprite_floor[k])
+    return false;
+  return Sprite_CheckDamageToLink_ignore_layer(k);
+}
+
+bool Sprite_CheckDamageToLink_ignore_layer(int k) {  // 86f15c
+  uint8 carry, t;
+  if (sprite_flags4[k]) {
+    SpriteHitBox hitbox;
+    Link_SetupHitBox(&hitbox);
+
+    // Set hitbox to the sword hitbox if the item type is an absorbable
+    if (sprite_type[k] >= 0xd8 && sprite_type[k] <= 0xe6 && (enhanced_features0 & kFeatures0_CollectItemsWithSword))
+      Link_UpdateHitBoxWithSword(&hitbox);
+
+    Sprite_SetupHitBox(k, &hitbox);
+    carry = CheckIfHitBoxesOverlap(&hitbox);
+  } else {
+    carry = Sprite_SetupHitBox00(k);
+  }
+
+  if (sign8(sprite_flags2[k]))
+    return carry;
+
+  if (!carry || link_auxiliary_state)
+    return false;
+
+  if (link_is_bunny_mirror || sign8(link_state_bits) || !(sprite_flags5[k] & 0x20) || !link_shield_type)
+    goto if_3;
+  sprite_state[k] = 0;
+
+  t = button_b_frames ? kSpriteDamage_Tab2[link_direction_facing >> 1] : link_direction_facing;
+  if (t != kSpriteDamage_Tab3[sprite_D[k]]) {
+if_3:
+    Sprite_AttemptDamageToLinkPlusRecoil(k);
+    if (sprite_type[k] == 0xc)
+      Sprite_Func3(k);
+    return true;
+  }
+  SpriteSfx_QueueSfx2WithPan(k, 6);
+  Sprite_PlaceRupulseSpark_2(k);
+  if (sprite_type[k] == 0x95) {
+    SpriteSfx_QueueSfx3WithPan(k, 0x26);
+    return false;
+  } else if (sprite_type[k] == 0x9B) {
+    Sprite_Invert_XY_Speeds(k);
+    sprite_D[k] ^= 1;
+    sprite_ai_state[k]++;
+    sprite_state[k] = 9;
+    return false;
+  } else if (sprite_type[k] == 0x1B) { // arrow
+    Sprite_ScheduleForBreakage(k);
+    return false;  // unk ret val
+  } else if (sprite_type[k] == 0xc) {
+    Sprite_Func3(k);
+    return true;
+  } else {
+    return false;  // unk ret val
+  }
+}
+
+bool Sprite_SetupHitBox00(int k) {  // 86f1f6
+  return (uint16)(link_x_coord - cur_sprite_x + 11) < 23 &&
+         (uint16)(link_y_coord - cur_sprite_y + sprite_z[k] + 16) < 24;
+}
+
+bool Sprite_ReturnIfLifted(int k) {  // 86f228
+  if (submodule_index | button_b_frames | flag_unk1 || sprite_floor[k] != link_is_on_lower_level)
+    return false;
+  for (int j = 15; j >= 0; j--)
+    if (sprite_state[j] == 10)
+      return false;
+  if (sprite_type[k] != 0xb && sprite_type[k] != 0x4a && (sprite_x_vel[k] | sprite_y_vel[k]) != 0)
+    return false;
+  if (link_is_running)
+    return false;
+  return Sprite_ReturnIfLiftedPermissive(k);
+}
+
+bool Sprite_ReturnIfLiftedPermissive(int k) {  // 86f257
+  if (link_is_running)
+    return false;
+  if ((uint8)(flag_is_sprite_to_pick_up_cached - 1) != cur_object_index) {
+    SpriteHitBox hb;
+    Link_SetupHitBox_conditional(&hb);
+    Sprite_SetupHitBox(k, &hb);
+    if (CheckIfHitBoxesOverlap(&hb))
+      byte_7E0FB2 = flag_is_sprite_to_pick_up = k + 1;
+    return false;
+  } else {
+    BYTE(filtered_joypad_L) = 0;
+    sprite_E[k] = 0;
+    SpriteSfx_QueueSfx2WithPan(k, 0x1d);
+    sprite_unk4[k] = sprite_state[k];
+    sprite_state[k] = 10;
+    sprite_delay_main[k] = 16;
+    sprite_unk3[k] = 0;
+    sprite_I[k] = 0;
+    link_direction_facing = kSprite_ReturnIfLifted_Dirs[Sprite_DirectionToFaceLink(k, NULL)];
+    return true;
+  }
+}
+
+uint8 Sprite_CheckDamageFromLink(int k) {  // 86f2b4
+  if (sprite_hit_timer[k] & 0x80 || sprite_floor[k] != link_is_on_lower_level || player_oam_y_offset == 0x80)
+    return 0;
+
+  SpriteHitBox hb;
+  Player_SetupActionHitBox(&hb);
+  Sprite_SetupHitBox(k, &hb);
+  if (!CheckIfHitBoxesOverlap(&hb))
+    return 0;
+
+  set_when_damaging_enemies = 0;
+  if (link_position_mode & 0x10)
+    return kCheckDamageFromPlayer_Carry | kCheckDamageFromPlayer_Ne;
+
+  if (link_item_in_hand & 10) {
+    if (sprite_type[k] >= 0xd6)
+      return 0;
+    if (sprite_state[k] == 11 && sprite_unk5[k] != 0) {
+      sprite_state[k] = 2;
+      sprite_delay_main[k] = 32;
+      sprite_flags2[k] = (sprite_flags2[k] & 0xe0) | 3;
+      SpriteSfx_QueueSfx2WithPan(k, 0x1f);
+      return kCheckDamageFromPlayer_Carry | kCheckDamageFromPlayer_Ne;
+    }
+  }
+  uint8 type = sprite_type[k];
+  if (type == 0x7b) {
+    if (!sign8(button_b_frames - 9))
+      return 0;
+  } else if (type == 9) {
+    if (!sprite_A[k]) {
+      Sprite_ApplyRecoilToLink(k, 48);
+      set_when_damaging_enemies = 144;
+      link_incapacitated_timer = 16;
+      SpriteSfx_QueueSfx2WithPan(k, 0x21);
+      sprite_delay_aux1[k] = 48;
+      sound_effect_2 = Sprite_CalculateSfxPan(k) | (enhanced_features0 & kFeatures0_MiscBugFixes ? 0x32 : 0);
+      Link_PlaceWeaponTink();
+      return kCheckDamageFromPlayer_Carry;
+    }
+  } else if (type == 0x92) {
+    if (sprite_C[k] >= 3)
+      goto is_many;
+    goto getting_out;
+  } else if (type == 0x26 || type == 0x13 || type == 2) {
+    bool cond = (type == 0x13 && kSpriteDamage_Tab3[sprite_D[k]] == link_direction_facing) || (type == 2);
+    Sprite_AttemptZapDamage(k);
+    Sprite_ApplyRecoilToLink(k, 32);
+    set_when_damaging_enemies = 16;
+    link_incapacitated_timer = 16;
+    if (cond) {
+      sprite_hit_timer[k] = 0;
+      Link_PlaceWeaponTink();
+    }
+    return 0; // what return value?
+  } else if (type == 0xcb || type == 0xcd || type == 0xcc || type == 0xd6 || type == 0xd7 || type == 0xce || type == 0x54) {
+is_many:
+    Sprite_ApplyRecoilToLink(k, 32);
+    set_when_damaging_enemies = 144;
+    link_incapacitated_timer = 16;
+  }
+  if (!(sprite_defl_bits[k] & 4)) {
+    Sprite_AttemptZapDamage(k);
+    return kCheckDamageFromPlayer_Carry;
+  }
+getting_out:
+  if (!set_when_damaging_enemies) {
+    Sprite_ApplyRecoilToLink(k, 4);
+    link_incapacitated_timer = 16;
+    set_when_damaging_enemies = 16;
+  }
+  Link_PlaceWeaponTink();
+  return kCheckDamageFromPlayer_Carry;
+}
+
+void Sprite_AttemptDamageToLinkWithCollisionCheck(int k) {  // 86f3ca
+  if ((k ^ frame_counter) & 1)
+    return;
+  SpriteHitBox hb;
+  Sprite_DoHitBoxesFast(k, &hb);
+  Link_SetupHitBox_conditional(&hb);
+  if (CheckIfHitBoxesOverlap(&hb))
+    Sprite_AttemptDamageToLinkPlusRecoil(k);
+}
+
+void Sprite_AttemptDamageToLinkPlusRecoil(int k) {  // 86f3db
+  if (countdown_for_blink | link_disable_sprite_damage)
+    return;
+  link_incapacitated_timer = 19;
+  Sprite_ApplyRecoilToLink(k, 24);
+  link_auxiliary_state = 1;
+  link_give_damage = kPlayerDamages[3 * (sprite_bump_damage[k] & 0xf) + link_armor];
+  if (sprite_type[k] == 0x61 && sprite_C[k]) {
+    link_actual_vel_x = sprite_x_vel[k] * 2;
+    link_actual_vel_y = sprite_y_vel[k] * 2;
+  }
+}
+
+void Player_SetupActionHitBox(SpriteHitBox *hb) {  // 86f5e0
+  if (link_is_running) {
+    int j = link_direction_facing >> 1;
+    int x = link_x_coord + (kPlayerActionBoxRun_XLo[j] | kPlayerActionBoxRun_XHi[j] << 8);
+    int y = link_y_coord + (kPlayerActionBoxRun_YLo[j] | kPlayerActionBoxRun_YHi[j] << 8);
+    hb->r0_xlo = x;
+    hb->r8_xhi = x >> 8;
+    hb->r1_ylo = y;
+    hb->r9_yhi = y >> 8;
+    hb->r2 = hb->r3 = 16;
+  } else {
+    int t = 0;
+    if (!(link_item_in_hand & 10) && !(link_position_mode & 0x10)) {
+      if (sign8(button_b_frames)) {
+        int x = link_x_coord - 14;
+        int y = link_y_coord - 10;
+        hb->r0_xlo = x;
+        hb->r8_xhi = x >> 8;
+        hb->r1_ylo = y;
+        hb->r9_yhi = y >> 8;
+        hb->r2 = 44;
+        hb->r3 = 45;
+        return;
+      } else if (kPlayer_SetupActionHitBox_Tab4[button_b_frames]) {
+        hb->r8_xhi = 0x80;
+        return;
+      }
+      t = link_direction_facing * 8 + button_b_frames + 1;
+    }
+    int x = link_x_coord + (int8)(kPlayer_SetupActionHitBox_X[t] + player_oam_x_offset);
+    int y = link_y_coord + (int8)(kPlayer_SetupActionHitBox_Y[t] + player_oam_y_offset);
+    hb->r0_xlo = x;
+    hb->r8_xhi = x >> 8;
+    hb->r1_ylo = y;
+    hb->r9_yhi = y >> 8;
+    hb->r2 = kPlayer_SetupActionHitBox_W[t];
+    hb->r3 = kPlayer_SetupActionHitBox_H[t];
+  }
+}
+
+void Link_UpdateHitBoxWithSword(SpriteHitBox *hb) {  // new
+  if (link_spin_attack_step_counter != 0 || sign8(button_b_frames) ||
+      kPlayer_SetupActionHitBox_Tab4[button_b_frames])
+    return;
+  int t = link_direction_facing * 8 + button_b_frames + 1, r;
+  int x = link_x_coord + (int8)(kPlayer_SetupActionHitBox_X[t] + player_oam_x_offset);
+  int y = link_y_coord + (int8)(kPlayer_SetupActionHitBox_Y[t] + player_oam_y_offset);
+  // Reduce size of hitbox if 'too' big.
+  hb->r2 = kPlayer_SetupActionHitBox_W[t];
+  if (hb->r2 - 2 >= 0)
+    r = IntMin(6, hb->r2 - 2), hb->r2 -= r, x += r >> 1;
+  hb->r3 = kPlayer_SetupActionHitBox_H[t];
+  if (hb->r3 - 2 >= 0)
+    r = IntMin(6, hb->r3 - 2), hb->r3 -= r, y += r >> 1;
+  hb->r0_xlo = x;
+  hb->r8_xhi = x >> 8;
+  hb->r1_ylo = y;
+  hb->r9_yhi = y >> 8;
+}
+
+void Sprite_DoHitBoxesFast(int k, SpriteHitBox *hb) {  // 86f645
+  if (HIBYTE(dungmap_var8) == 0x80) {
+    hb->r10_spr_xhi = 0x80;
+    return;
+  }
+  int t;
+  t = Sprite_GetX(k) + (int8)HIBYTE(dungmap_var8);
+  hb->r4_spr_xlo = t;
+  hb->r10_spr_xhi = t >> 8;
+  t = Sprite_GetY(k) + (int8)BYTE(dungmap_var8);
+  hb->r5_spr_ylo = t;
+  hb->r11_spr_yhi = t >> 8;
+  hb->r6_spr_xsize = hb->r7_spr_ysize = (sprite_type[k] == 0x6a) ? 16 : 3;
+}
+
+void Sprite_ApplyRecoilToLink(int k, uint8 vel) {  // 86f688
+  ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLink(k, vel);
+  link_actual_vel_x = pt.x;
+  link_actual_vel_y = pt.y;
+  g_ram[0xc7] = link_actual_vel_z = vel >> 1;
+  link_z_coord = 0;
+}
+
+void Link_PlaceWeaponTink() {  // 86f69f
+  if (repulsespark_timer)
+    return;
+  repulsespark_timer = 5;
+  int t = (uint8)link_x_coord + player_oam_x_offset;
+  repulsespark_x_lo = t;
+  t = (uint8)link_y_coord + player_oam_y_offset + (t >> 8);  // carry wtf
+  repulsespark_y_lo = t;
+  repulsespark_floor_status = link_is_on_lower_level;
+  sound_effect_1 = Link_CalculateSfxPan() | 5;
+}
+
+void Sprite_PlaceWeaponTink(int k) {  // 86f6ca
+  if (repulsespark_timer)
+    return;
+  SpriteSfx_QueueSfx2WithPan(k, 5);
+  Sprite_PlaceRupulseSpark_2(k);
+}
+
+void Sprite_PlaceRupulseSpark_2(int k) {  // 86f6d5
+  uint16 x = Sprite_GetX(k) - BG2HOFS_copy2;
+  uint16 y = Sprite_GetY(k) - BG2VOFS_copy2;
+  if (x & ~0xff || y & ~0xff)
+    return;
+  repulsespark_x_lo = sprite_x_lo[k];
+  repulsespark_y_lo = sprite_y_lo[k];
+  repulsespark_timer = 5;
+  repulsespark_floor_status = sprite_floor[k];
+}
+
+void Link_SetupHitBox_conditional(SpriteHitBox *hb) {  // 86f705
+  if (link_disable_sprite_damage)
+    hb->r9_yhi = 0x80;
+  else
+    Link_SetupHitBox(hb);
+}
+
+void Link_SetupHitBox(SpriteHitBox *hb) {  // 86f70a
+  hb->r3 = hb->r2 = 8;
+  uint16 x = link_x_coord + 4;
+  hb->r0_xlo = x;
+  hb->r8_xhi = x >> 8;
+  uint16 y = link_y_coord + 8;
+  hb->r1_ylo = y;
+  hb->r9_yhi = y >> 8;
+}
+
+void Sprite_SetupHitBox(int k, SpriteHitBox *hb) {  // 86f7ef
+  if (sign8(sprite_z[k])) {
+    hb->r10_spr_xhi = 0x80;
+    return;
+  }
+  int i = sprite_flags4[k] & 0x1f;
+  int t, u;
+
+  t = sprite_x_lo[k] + (uint8)kSpriteHitbox_XLo[i];
+  hb->r4_spr_xlo = t;
+  t = sprite_x_hi[k] + (uint8)kSpriteHitbox_XHi[i] + (t >> 8);
+  hb->r10_spr_xhi = t;
+
+  t = sprite_y_lo[k] + (uint8)kSpriteHitbox_YLo[i];
+  u = t >> 8;
+  t = (t & 0xff) - sprite_z[k];
+  hb->r5_spr_ylo = t;
+  t = sprite_y_hi[k] - (t < 0);
+  hb->r11_spr_yhi = t + u + (uint8)kSpriteHitbox_YHi[i];
+
+  hb->r6_spr_xsize = kSpriteHitbox_XSize[i];
+  hb->r7_spr_ysize = kSpriteHitbox_YSize[i];
+}
+
+// Returns the carry flag
+bool CheckIfHitBoxesOverlap(SpriteHitBox *hb) {  // 86f836
+  int t;
+  uint8 r15, r12;
+
+  if (hb->r8_xhi == 0x80 || hb->r10_spr_xhi == 0x80)
+    return false;
+
+  t = hb->r5_spr_ylo - hb->r1_ylo;
+  r15 = t + hb->r7_spr_ysize;
+  r12 = hb->r11_spr_yhi - hb->r9_yhi - (t < 0);
+  t = r12 + (((t & 0xff) + 0x80) >> 8);
+  if (t & 0xff)
+    return (t >= 0x100);
+  if ((uint8)(hb->r3 + hb->r7_spr_ysize) < r15)
+    return false;
+
+  t = hb->r4_spr_xlo - hb->r0_xlo;
+  r15 = t + hb->r6_spr_xsize;
+  r12 = hb->r10_spr_xhi - hb->r8_xhi - (t < 0);
+  t = r12 + (((t & 0xff) + 0x80) >> 8);
+  if (t & 0xff)
+    return (t >= 0x100);
+  if ((uint8)(hb->r2 + hb->r6_spr_xsize) < r15)
+    return false;
+
+  return true;
+}
+
+void Oam_AllocateDeferToPlayer(int k) {  // 86f86c
+  if (sprite_floor[k] != link_is_on_lower_level)
+    return;
+  PairU8 right = Sprite_IsRightOfLink(k);
+  if ((uint8)(right.b + 0x10) >= 0x20)
+    return;
+  PairU8 below = Sprite_IsBelowLink(k);
+  if ((uint8)(below.b + 0x20) >= 0x48)
+    return;
+  uint8 nslots = ((sprite_flags2[k] & 0x1f) + 1) << 2;
+  if (below.a)
+    Oam_AllocateFromRegionC(nslots);
+  else
+    Oam_AllocateFromRegionB(nslots);
+}
+
+void SpriteModule_Die(int k) {  // 86f8a2
+  SpriteDeath_MainEx(k, false);
+}
+
+void Sprite_DoTheDeath(int k) {  // 86f923
+  uint8 type = sprite_type[k];
+  // This is how Vitreous knows whether to come out of his slime pool
+  if (type == 0xBE)
+    sprite_G[0]--;
+
+  if (type == 0xaa && sprite_E[k] != 0) {
+    uint8 bak = sprite_subtype[k];
+    PrepareEnemyDrop(k, kPikitDropItems[sprite_E[k] - 1]);
+    sprite_subtype[k] = bak;
+    if (bak == 1) {
+      sprite_oam_flags[k] = 9;
+      sprite_flags3[k] = 0xf0;
+    }
+    sprite_head_dir[k]++;
+    return;
+  }
+
+  // Resets the music in the village when the crazy green guards are killed.
+  if (type == 0x45 && sram_progress_indicator == 2 && BYTE(overworld_area_index) == 0x18)
+    music_control = 7;
+
+  uint8 drop_item = sprite_die_action[k];
+  if (drop_item != 0) {
+    sprite_subtype[k] = sprite_N[k];
+    sprite_N[k] = 255;
+    uint8 arg = (drop_item == 1) ? 0xe4 : // small key, big key or rupee
+                (drop_item == 3) ? 0xd9 : 0xe5;
+    PrepareEnemyDrop(k, arg);
+    return;
+  }
+
+  uint8 prize = sprite_flags5[k] & 0xf;
+  if (prize-- != 0) {
+    uint8 luck = item_drop_luck;
+    if (luck != 0) {
+      if (++luck_kill_counter >= 10)
+        item_drop_luck = 0;
+      if (luck == 1) {
+        ForcePrizeDrop(k, prize, 1);
+        return;
+      }
+    } else {
+      if (!(GetRandomNumber() & kPrizeMasks[prize])) {
+        ForcePrizeDrop(k, prize, prize);
+        return;
+      }
+    }
+  }
+  sprite_state[k] = 0;
+  SpriteDeath_Func4(k);
+}
+
+void ForcePrizeDrop(int k, uint8 prize, uint8 slot) {  // 86f9bc
+  prize = prize * 8 | prizes_arr1[slot];
+  prizes_arr1[slot] = (prizes_arr1[slot] + 1) & 7;
+  PrepareEnemyDrop(k, kPrizeItems[prize]);
+}
+
+void PrepareEnemyDrop(int k, uint8 item) {  // 86f9d1
+  sprite_type[k] = item;
+  if (item == 0xe5)
+    SpritePrep_BigKey_load_graphics(k);
+  else if (item == 0xe4)
+    SpritePrep_KeySetItemDrop(k);
+
+  sprite_state[k] = 9;
+  uint8 zbak = sprite_z[k];
+  SpritePrep_LoadProperties(k);
+  sprite_ignore_projectile[k]++;
+
+  uint8 pz = kPrizeZ[sprite_type[k] - 0xd8];
+  sprite_z_vel[k] = pz & 0xf0;
+  Sprite_SetX(k, Sprite_GetX(k) + (pz & 0xf));
+  sprite_z[k] = zbak;
+  sprite_delay_aux4[k] = 21;
+  sprite_stunned[k] = 255;
+  SpriteDeath_Func4(k);
+}
+
+void SpriteDeath_Func4(int k) {  // 86fa25
+  if (sprite_type[k] == 0xa2 && Sprite_CheckIfScreenIsClear())
+    Ancilla_SpawnFallingPrize(4);
+  Sprite_ManuallySetDeathFlagUW(k);
+  num_sprites_killed++;
+  if (sprite_type[k] == 0x40) {
+    // evil barrier
+    sprite_state[k] = 9;
+    sprite_graphics[k] = 4;
+    SpriteDeath_MainEx(k, true);
+  }
+}
+
+void SpriteDeath_DrawPoof(int k) {  // 86fb2a
+  if (dung_hdr_collision == 4)
+    sprite_obj_prio[k] = 0x30;
+  PrepOamCoordsRet info;
+  if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
+    return;
+  OamEnt *oam = GetOamCurPtr();
+  uint8 r12 = (sprite_flags3[k] & 0x20) >> 3;
+  int i = ((sprite_delay_main[k] & 0x1c) ^ 0x1c) + 3, n = 3;
+  do {
+    if (kPerishOverlay_Char[i]) {
+      oam->charnum = kPerishOverlay_Char[i];
+      oam->y = HIBYTE(dungmap_var7) - r12 + kPerishOverlay_Y[i];
+      oam->x = BYTE(dungmap_var7) - r12 + kPerishOverlay_X[i];
+      oam->flags = (info.flags & 0x30) | kPerishOverlay_Flags[i];
+    }
+  } while (oam++, i--, --n >= 0);
+  Sprite_CorrectOamEntries(k, 3, 0);
+}
+
+void SpriteModule_Fall2(int k) {  // 86fbea
+  uint8 delay = sprite_delay_main[k];
+  if (!delay) {
+    sprite_state[k] = 0;
+    Sprite_ManuallySetDeathFlagUW(k);
+    return;
+  }
+
+  if (delay >= 0x40) {
+    if (sprite_oam_flags[k] != 5) {
+      if (!(delay & 7 | submodule_index | flag_unk1))
+        SpriteSfx_QueueSfx3WithPan(k, 0x31);
+      SpriteActive_Main(k);
+      PrepOamCoordsRet info;
+      if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
+        return;
+      Sprite_DrawDistress_custom(info.x, info.y - 8, delay + 20);
+      return;
+    }
+    sprite_delay_main[k] = delay = 63;
+  }
+
+  if (delay == 61)
+    SpriteSfx_QueueSfx2WithPan(k, 0x20);
+
+  int j = delay >> 1;
+
+  if (sprite_type[k] == 0x26 || sprite_type[k] == 0x13) {
+    sprite_graphics[k] = kSpriteFall_Tab2[j];
+    SpriteDraw_FallingHelmaBeetle(k);
+  } else {
+    uint8 t = kSpriteFall_Tab1[j];
+    if (t < 12)
+      t += kSpriteFall_Tab4[sprite_D[k]];
+    sprite_graphics[k] = t;
+    SpriteDraw_FallingHumanoid(k);
+  }
+  if (frame_counter & kSpriteFall_Tab3[sprite_delay_main[k] >> 3] | submodule_index)
+    return;
+  Sprite_CheckTileProperty(k, 0x68);
+  if (sprite_tiletype != 0x20) {
+    sprite_y_recoil[k] = 0;
+    sprite_x_recoil[k] = 0;
+  }
+  sprite_y_vel[k] = (int8)sprite_y_recoil[k] >> 2;
+  sprite_x_vel[k] = (int8)sprite_x_recoil[k] >> 2;
+  Sprite_MoveXY(k);
+}
+
+void SpriteDraw_FallingHelmaBeetle(int k) {  // 86fd17
+  PrepOamCoordsRet info;
+  const DrawMultipleData *src = kSpriteDrawFall0Data + sprite_graphics[k];
+  if (sprite_type[k] == 0x13)
+    src += 6;
+  Sprite_DrawMultiple(k, src, 1, &info);
+}
+
+void SpriteDraw_FallingHumanoid(int k) {  // 86fe5b
+  PrepOamCoordsRet info;
+  if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
+    return;
+
+  int q = sprite_graphics[k];
+  OamEnt *oam = GetOamCurPtr();
+  int n = (q < 12 && (q & 3) == 0) ? 3 : 0, nn = n;
+  do {
+    int i = q * 4 + n;
+    SetOamPlain(oam, info.x + kSpriteDrawFall1_X[i], info.y + kSpriteDrawFall1_Y[i],
+                 kSpriteDrawFall1_Char[i], info.flags ^ kSpriteDrawFall1_Flags[i], kSpriteDrawFall1_Ext[i]);
+  } while (oam++, --n >= 0);
+  Sprite_CorrectOamEntries(k, nn, 0xff);
+}
+
+void Sprite_CorrectOamEntries(int k, int n, uint8 islarge) {  // 86febc
+  OamEnt *oam = GetOamCurPtr();
+  uint8 *extp = &g_ram[oam_ext_cur_ptr];
+  uint16 spr_x = Sprite_GetX(k);
+  uint16 spr_y = Sprite_GetY(k);
+  uint8 scrollx = spr_x - BG2HOFS_copy2;
+  uint8 scrolly = spr_y - BG2VOFS_copy2;
+  do {
+    uint16 x = spr_x + (int8)(oam->x - scrollx);
+    uint16 y = spr_y + (int8)(oam->y - scrolly);
+    uint8 ext = sign8(islarge) ? (*extp & 2) : islarge;
+    *extp = ext + ((uint16)(x - BG2HOFS_copy2) >= 0x100);
+    if ((uint16)(y + 0x10 - BG2VOFS_copy2) >= 0x100)
+      oam->y = 0xf0;
+  } while (oam++, extp++, --n >= 0);
+}
+
+bool Sprite_ReturnIfRecoiling(int k) {  // 86ff78
+  if (!sprite_F[k])
+    return false;
+  if (!(sprite_F[k] & 0x7f)) {
+    sprite_F[k] = 0;
+    return false;
+  }
+  uint8 yvbak = sprite_y_vel[k];
+  uint8 xvbak = sprite_x_vel[k];
+  if (!--sprite_F[k] && ((uint8)(sprite_x_recoil[k] + 0x20) >= 0x40 || (uint8)(sprite_y_recoil[k] + 0x20) >= 0x40))
+    sprite_F[k] = 144;
+
+  int i = sprite_F[k];
+  uint8 t;
+  if (!sign8(i) && !(frame_counter & kSprite2_ReturnIfRecoiling_Masks[i>>2])) {
+    sprite_y_vel[k] = sprite_y_recoil[k];
+    sprite_x_vel[k] = sprite_x_recoil[k];
+    if (!sign8(sprite_bump_damage[k]) && (t = (Sprite_CheckTileCollision(k) & 0xf))) {
+      if (t < 4)
+        sprite_x_recoil[k] = sprite_x_vel[k] = 0;
+      else
+        sprite_y_recoil[k] = sprite_y_vel[k] = 0;
+    } else {
+      Sprite_MoveXY(k);
+    }
+  }
+  sprite_y_vel[k] = yvbak;
+  sprite_x_vel[k] = xvbak;
+  return sprite_type[k] != 0x7a;
+}
+
+bool Sprite_CheckIfLinkIsBusy() {  // 87f4d0
+  if (link_auxiliary_state | link_pose_for_item | (link_state_bits & 0x80))
+    return true;
+  for (int i = 4; i >= 0; i--) {
+    if (ancilla_type[i] == 0x27)
+      return true;
+  }
+  return false;
+}
+
+void Sprite_SetSpawnedCoordinates(int k, SpriteSpawnInfo *info) {  // 89ae64
+  sprite_x_lo[k] = info->r0_x;
+  sprite_x_hi[k] = info->r0_x >> 8;
+  sprite_y_lo[k] = info->r2_y;
+  sprite_y_hi[k] = info->r2_y >> 8;
+  sprite_z[k] = info->r4_z;
+}
+
+bool Sprite_CheckIfScreenIsClear() {  // 89af32
+  for (int i = 15; i >= 0; i--) {
+    if (sprite_state[i] && !(sprite_flags4[i] & 0x40)) {
+      uint16 x = Sprite_GetX(i) - BG2HOFS_copy2;
+      uint16 y = Sprite_GetY(i) - BG2VOFS_copy2;
+      if (x < 256 && y < 256)
+        return false;
+    }
+  }
+  return Sprite_CheckIfOverlordsClear();
+}
+
+bool Sprite_CheckIfRoomIsClear() {  // 89af61
+  for (int i = 15; i >= 0; i--) {
+    if (sprite_state[i] && !(sprite_flags4[i] & 0x40))
+      return false;
+  }
+  return Sprite_CheckIfOverlordsClear();
+}
+
+bool Sprite_CheckIfOverlordsClear() {  // 89af76
+  for (int i = 7; i >= 0; i--) {
+    if (overlord_type[i] == 0x14 || overlord_type[i] == 0x18)
+      return false;
+  }
+  return true;
+}
+
+void Sprite_InitializeMirrorPortal() {  // 89af89
+  for (int k = 15; k >= 0; k--) {
+    if (sprite_state[k] && sprite_type[k] == 0x6c)
+      sprite_state[k] = 0;
+  }
+
+  SpriteSpawnInfo info;
+  int j = Sprite_SpawnDynamically(0xff, 0x6c, &info);
+  if (j < 0)
+    j = 0;
+
+  Sprite_SetX(j, bird_travel_x_hi[15] << 8 | bird_travel_x_lo[15]);
+  Sprite_SetY(j, (bird_travel_y_hi[15] << 8 | bird_travel_y_lo[15]) + 8);
+
+  sprite_floor[j] = 0;
+  sprite_ignore_projectile[j] = 1;
+}
+
+void Sprite_InitializeSlots() {  // 89afd6
+  for (int k = 15; k >= 0; k--) {
+    uint8 st = sprite_state[k], ty = sprite_type[k];
+    if (st != 0) {
+      if (st == 10) {
+        if (ty != 0xec && ty != 0xd2) {
+          link_picking_throw_state = 0;
+          link_state_bits = 0;
+          sprite_state[k] = 0;
+        }
+      } else {
+        if (ty != 0x6c && sprite_room[k] != BYTE(overworld_area_index))
+          sprite_state[k] = 0;
+      }
+    }
+  }
+  for (int k = 7; k >= 0; k--) {
+    if (overlord_type[k] && overlord_spawned_in_area[k] != BYTE(overworld_area_index))
+      overlord_type[k] = 0;
+  }
+}
+
+void Garnish_ExecuteUpperSlots() {  // 89b08c
+  HandleScreenFlash();
+
+  if (garnish_active) {
+    for (int i = 29; i >= 15; i--)
+      Garnish_ExecuteSingle(i);
+  }
+}
+
+void Garnish_ExecuteLowerSlots() {  // 89b097
+  if (garnish_active) {
+    for (int i = 14; i >= 0; i--)
+      Garnish_ExecuteSingle(i);
+  }
+}
+
+void Garnish_ExecuteSingle(int k) {  // 89b0b6
+  cur_object_index = k;
+  uint8 type = garnish_type[k];
+  if (type == 0)
+    return;
+  if ((type == 5 || (submodule_index | flag_unk1) == 0) && garnish_countdown[k] != 0 && --garnish_countdown[k] == 0) {
+    garnish_type[k] = 0;
+    return;
+  }
+  uint8 sprsize = kGarnish_OamMemSize[garnish_type[k]];
+  if (sort_sprites_setting) {
+    if (garnish_floor[k])
+      Oam_AllocateFromRegionF(sprsize);
+    else
+      Oam_AllocateFromRegionD(sprsize);
+  } else {
+    Oam_AllocateFromRegionA(sprsize);
+  }
+  kGarnish_Funcs[garnish_type[k] - 1](k);
+}
+
+void Garnish15_ArrghusSplash(int k) {  // 89b178
+  static const int8 kArrghusSplash_X[8] = {-12, 20, -10, 10, -8, 8, -4, 4};
+  static const int8 kArrghusSplash_Y[8] = {-4, -4, -2, -2, 0, 0, 0, 0};
+  static const uint8 kArrghusSplash_Char[8] = {0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xac, 0xac};
+  static const uint8 kArrghusSplash_Flags[8] = {0x34, 0x74, 0x34, 0x74, 0x34, 0x74, 0x34, 0x74};
+  static const uint8 kArrghusSplash_Ext[8] = {0, 0, 2, 2, 2, 2, 2, 2};
+
+  Point16U pt;
+  if (Garnish_ReturnIfPrepFails(k, &pt))
+    return;
+  OamEnt *oam = GetOamCurPtr();
+  int g = (garnish_countdown[k] >> 1) & 6;
+  for (int i = 1; i >= 0; i--, oam++) {
+    int j = i + g;
+    SetOamPlain(oam, pt.x + kArrghusSplash_X[j], pt.y + kArrghusSplash_Y[j], kArrghusSplash_Char[j], kArrghusSplash_Flags[j], kArrghusSplash_Ext[j]);
+  }
+}
+
+void Garnish13_PyramidDebris(int k) {  // 89b216
+  OamEnt *oam = GetOamCurPtr();
+
+  int y = (garnish_y_lo[k] << 8) + garnish_y_subpixel[k] + ((int8)garnish_y_vel[k] << 4);
+  garnish_y_subpixel[k] = y;
+  garnish_y_lo[k] = y >> 8;
+
+  int x = (garnish_x_lo[k] << 8) + garnish_x_subpixel[k] + ((int8)garnish_x_vel[k] << 4);
+  garnish_x_subpixel[k] = x;
+  garnish_x_lo[k] = x >> 8;
+
+  garnish_y_vel[k] = garnish_y_vel[k] + 3;
+  uint8 t;
+  if ((t = garnish_x_lo[k] - BG2HOFS_copy2) >= 248) {
+    garnish_type[k] = 0;
+    return;
+  }
+  oam->x = t;
+  if ((t = garnish_y_lo[k] - BG2VOFS_copy2) >= 240) {
+    garnish_type[k] = 0;
+    return;
+  }
+  oam->y = t;
+  oam->charnum = 0x5c;
+  oam->flags = (frame_counter << 3) & 0xc0 | 0x34;
+  bytewise_extended_oam[oam - oam_buf] = 0;
+}
+
+void Garnish11_WitheringGanonBatFlame(int k) {  // 89b2b2
+  if ((submodule_index | flag_unk1) == 0) {
+    Garnish_SetY(k, Garnish_GetY(k) - 1);
+  }
+  Point16U pt;
+  if (Garnish_ReturnIfPrepFails(k, &pt))
+    return;
+  OamEnt *oam = GetOamCurPtr();
+  SetOamPlain(oam + 0, pt.x + 0, pt.y, 0xa4, 0x22, 0);
+  SetOamPlain(oam + 1, pt.x + 8, pt.y, 0xa5, 0x22, 0);
+}
+
+void Garnish10_GanonBatFlame(int k) {  // 89b306
+  static const uint8 kGanonBatFlame_Idx[32] = {
+    7, 6, 5, 4, 5, 4, 5, 4, 5, 4, 5, 4, 5, 4, 5, 4,
+    5, 4, 5, 4, 5, 4, 5, 4, 5, 4, 5, 4, 5, 4, 5, 4,
+  };
+  static const uint8 kGanonBatFlame_Char[7] = {0xac, 0xac, 0x66, 0x66, 0x8e, 0xa0, 0xa2};
+  static const uint8 kGanonBatFlame_Flags[7] = {1, 0x41, 1, 0x41, 0, 0, 0};
+
+  if (garnish_countdown[k] == 8)
+    garnish_type[k] = 0x11;
+  Point16U pt;
+  if (Garnish_ReturnIfPrepFails(k, &pt))
+    return;
+  int j = kGanonBatFlame_Idx[garnish_countdown[k] >> 3];
+  SetOamPlain(GetOamCurPtr(), pt.x, pt.y, kGanonBatFlame_Char[j], kGanonBatFlame_Flags[j] | 0x22, 2);
+  Garnish_CheckPlayerCollision(k, pt.x, pt.y);
+}
+
+void Garnish0C_TrinexxIceBreath(int k) {  // 89b34f
+  static const uint8 kTrinexxIce_Char[12] = {0xe8, 0xe8, 0xe6, 0xe6, 0xe4, 0xe4, 0xe4, 0xe4, 0xe4, 0xe4, 0xe4, 0xe4};
+  static const uint8 kTrinexxIce_Flags[4] = {0, 0x40, 0xc0, 0x80};
+
+  if (garnish_countdown[k] == 0x50 && (submodule_index | flag_unk1) == 0) {
+    Dungeon_UpdateTileMapWithCommonTile(Garnish_GetX(k), Garnish_GetY(k) - 16, 18);
+  }
+  Point16U pt;
+  if (Garnish_ReturnIfPrepFails(k, &pt))
+    return;
+  SetOamPlain(GetOamCurPtr(), pt.x, pt.y, kTrinexxIce_Char[garnish_countdown[k] >> 4],
+               kTrinexxIce_Flags[(garnish_countdown[k] >> 2) & 3] | 0x35, 2);
+}
+
+void Garnish14_KakKidDashDust(int k) {  // 89b3bc
+  Garnish_DustCommon(k, 2);
+}
+
+void Garnish_WaterTrail(int k) {  // 89b3c2
+  Garnish_DustCommon(k, 3);
+}
+
+void Garnish0A_CannonSmoke(int k) {  // 89b3ee
+  static const uint8 kGarnish_CannonPoof_Char[2] = { 0x8a, 0x86 };
+  static const uint8 kGarnish_CannonPoof_Flags[4] = { 0x20, 0x10, 0x30, 0x30 };
+  Point16U pt;
+  if (Garnish_ReturnIfPrepFails(k, &pt))
+    return;
+  int j = garnish_sprite[k];
+  SetOamPlain(GetOamCurPtr(), pt.x, pt.y, kGarnish_CannonPoof_Char[garnish_countdown[k] >> 3], kGarnish_CannonPoof_Flags[j] | 4, 2);
+}
+
+void Garnish09_LightningTrail(int k) {  // 89b429
+  static const uint8 kLightningTrail_Char[8] = {0xcc, 0xec, 0xce, 0xee, 0xcc, 0xec, 0xce, 0xee};
+  static const uint8 kLightningTrail_Flags[8] = {0x31, 0x31, 0x31, 0x31, 0x71, 0x71, 0x71, 0x71};
+  Point16U pt;
+  if (Garnish_ReturnIfPrepFails(k, &pt))
+    return;
+  int j = garnish_sprite[k];
+  SetOamPlain(GetOamCurPtr(), pt.x, pt.y,
+               kLightningTrail_Char[j] - (BYTE(dungeon_room_index2) == 0x20 ? 0x80 : 0),
+               (frame_counter << 1) & 0xe | kLightningTrail_Flags[j], 2);
+  Garnish_CheckPlayerCollision(k, pt.x, pt.y);
+}
+
+void Garnish_CheckPlayerCollision(int k, int x, int y) {  // 89b459
+  if ((k ^ frame_counter) & 7 | countdown_for_blink | link_disable_sprite_damage)
+    return;
+
+  if ((uint8)(link_x_coord - BG2HOFS_copy2 - x + 12) < 24 &&
+      (uint8)(link_y_coord - BG2VOFS_copy2 - y + 22) < 28) {
+    link_auxiliary_state = 1;
+    link_incapacitated_timer = 16;
+    link_give_damage = 16;
+    link_actual_vel_x ^= 255;
+    link_actual_vel_y ^= 255;
+  }
+}
+
+void Garnish07_BabasuFlash(int k) {  // 89b49e
+  static const uint8 kBabusuFlash_Char[4] = {0xa8, 0x8a, 0x86, 0x86};
+  static const uint8 kBabusuFlash_Flags[4] = {0x2d, 0x2c, 0x2c, 0x2c};
+  Point16U pt;
+  if (Garnish_ReturnIfPrepFails(k, &pt))
+    return;
+  int j = garnish_countdown[k] >> 3;
+  SetOamPlain(GetOamCurPtr(), pt.x, pt.y, kBabusuFlash_Char[j], kBabusuFlash_Flags[j], 2);
+}
+
+void Garnish08_KholdstareTrail(int k) {  // 89b4c6
+  static const int8 kGarnish_Nebule_XY[3] = { -1, -1, 0 };
+  static const uint8 kGarnish_Nebule_Char[3] = { 0x9c, 0x9d, 0x8d };
+
+  Point16U pt;
+  if (Garnish_ReturnIfPrepFails(k, &pt))
+    return;
+  int i = garnish_countdown[k] >> 2;
+  int j = garnish_sprite[k];
+  SetOamPlain(GetOamCurPtr(), pt.x + kGarnish_Nebule_XY[i], pt.y + kGarnish_Nebule_XY[i], kGarnish_Nebule_Char[i],
+               (sprite_oam_flags[j] | sprite_obj_prio[j]) & ~1, 0);
+}
+
+void Garnish06_ZoroTrail(int k) {  // 89b4fb
+  Point16U pt;
+  if (Garnish_ReturnIfPrepFails(k, &pt))
+    return;
+  int j = garnish_sprite[k];
+  SetOamPlain(GetOamCurPtr(), pt.x, pt.y, 0x75, sprite_oam_flags[j] | sprite_obj_prio[j], 0);
+}
+
+void Garnish12_Sparkle(int k) {  // 89b520
+  Garnish_SparkleCommon(k, 2);
+}
+
+void Garnish_SimpleSparkle(int k) {  // 89b526
+  Garnish_SparkleCommon(k, 3);
+}
+
+void Garnish0E_TrinexxFireBreath(int k) {  // 89b55d
+  static const uint8 kTrinexxLavaBubble_Char[4] = {0x83, 0xc7, 0x80, 0x9d};
+  Point16U pt;
+  if (Garnish_ReturnIfPrepFails(k, &pt))
+    return;
+  int j = garnish_sprite[k];
+  SetOamPlain(GetOamCurPtr(), pt.x, pt.y, kTrinexxLavaBubble_Char[garnish_countdown[k] >> 3],
+               (sprite_oam_flags[j] | sprite_obj_prio[j]) & 0xf0 | 0xe, 0);
+}
+
+void Garnish0F_BlindLaserTrail(int k) {  // 89b591
+  static const uint8 kBlindLaserTrail_Char[4] = {0x61, 0x71, 0x70, 0x60};
+  Point16U pt;
+  if (Garnish_ReturnIfPrepFails(k, &pt))
+    return;
+  int j = garnish_sprite[k];
+  SetOamPlain(GetOamCurPtr(), pt.x, pt.y, kBlindLaserTrail_Char[garnish_oam_flags[k] - 7], sprite_oam_flags[j] | sprite_obj_prio[j], 0);
+}
+
+void Garnish04_LaserTrail(int k) {  // 89b5bb
+  static const uint8 kLaserBeamTrail_Char[2] = {0xd2, 0xf3};
+  Point16U pt;
+  if (Garnish_ReturnIfPrepFails(k, &pt))
+    return;
+  SetOamPlain(GetOamCurPtr(), pt.x, pt.y, kLaserBeamTrail_Char[garnish_oam_flags[k]], 0x25, 0);
+}
+
+bool Garnish_ReturnIfPrepFails(int k, Point16U *pt) {  // 89b5de
+  uint16 x = Garnish_GetX(k) - BG2HOFS_copy2;
+  uint16 y = Garnish_GetY(k) - BG2VOFS_copy2;
+
+  if (x >= 256 || y >= 256) {
+    garnish_type[k] = 0;
+    return true;
+  }
+  pt->x = x;
+  pt->y = y - 16;
+  return false;
+}
+
+void Garnish03_FallingTile(int k) {  // 89b627
+  static const uint8 kCrumbleTile_XY[5] = {4, 0, 0, 0, 0};
+  static const uint8 kCrumbleTile_Char[5] = {0x80, 0xcc, 0xcc, 0xea, 0xca};
+  static const uint8 kCrumbleTile_Flags[5] = {0x30, 0x31, 0x31, 0x31, 0x31};
+  static const uint8 kCrumbleTile_Ext[5] = {0, 2, 2, 2, 2};
+
+  int j;
+  if ((j = garnish_countdown[k]) == 0x1e && (j = (submodule_index | flag_unk1)) == 0)
+    Dungeon_UpdateTileMapWithCommonTile(Garnish_GetX(k), Garnish_GetY(k) - 16, 4);
+  j >>= 3;
+  uint16 x = Garnish_GetX(k) + kCrumbleTile_XY[j] - BG2HOFS_copy2;
+  uint16 y = Garnish_GetY(k) + kCrumbleTile_XY[j] - BG2VOFS_copy2;
+  if (x < 256 && y < 256)
+    SetOamPlain(GetOamCurPtr(), x, y - 16, kCrumbleTile_Char[j], kCrumbleTile_Flags[j], kCrumbleTile_Ext[j]);
+}
+
+void Garnish01_FireSnakeTail(int k) {  // 89b6c0
+  Point16U pt;
+  if (Garnish_ReturnIfPrepFails(k, &pt))
+    return;
+  int j = garnish_sprite[k];
+  SetOamPlain(GetOamCurPtr(), pt.x, pt.y, 0x28, sprite_oam_flags[j] | sprite_obj_prio[j], 2);
+}
+
+void Garnish02_MothulaBeamTrail(int k) {  // 89b6e1
+  int j = garnish_sprite[k];
+  SetOamPlain(GetOamCurPtr(), garnish_x_lo[k] - BG2HOFS_copy2, garnish_y_lo[k] - BG2VOFS_copy2, 0xaa,
+               sprite_oam_flags[j] | sprite_obj_prio[j], 2);
+}
+
+void Dungeon_ResetSprites() {  // 89c114
+  Dungeon_CacheTransSprites();
+  link_picking_throw_state = 0;
+  link_state_bits = 0;
+  Sprite_DisableAll();
+  sprcoll_x_size = sprcoll_y_size = 0xffff;
+  int j = FindInWordArray(dungeon_room_history, dungeon_room_index2, 4);
+  if (j < 0) {
+    uint16 blk = dungeon_room_history[3];
+    dungeon_room_history[3] = dungeon_room_history[2];
+    dungeon_room_history[2] = dungeon_room_history[1];
+    dungeon_room_history[1] = dungeon_room_history[0];
+    dungeon_room_history[0] = dungeon_room_index2;
+    if (blk != 0xffff)
+      sprite_where_in_room[blk] = 0;
+  }
+  Dungeon_LoadSprites();
+}
+
+void Dungeon_CacheTransSprites() {  // 89c176
+  if (!player_is_indoors)
+    return;
+  alt_sprites_flag = player_is_indoors;
+  for (int k = 15; k >= 0; k--) {
+    alt_sprite_state[k] = 0;
+    alt_sprite_type[k] = sprite_type[k];
+    alt_sprite_x_lo[k] = sprite_x_lo[k];
+    alt_sprite_graphics[k] = sprite_graphics[k];
+    alt_sprite_x_hi[k] = sprite_x_hi[k];
+    alt_sprite_y_lo[k] = sprite_y_lo[k];
+    alt_sprite_y_hi[k] = sprite_y_hi[k];
+    if (sprite_pause[k] != 0 || sprite_state[k] == 4 || sprite_state[k] == 10)
+      continue;
+    alt_sprite_state[k] = sprite_state[k];
+    alt_sprite_A[k] = sprite_A[k];
+    alt_sprite_head_dir[k] = sprite_head_dir[k];
+    alt_sprite_oam_flags[k] = sprite_oam_flags[k];
+    alt_sprite_obj_prio[k] = sprite_obj_prio[k];
+    alt_sprite_D[k] = sprite_D[k];
+    alt_sprite_flags2[k] = sprite_flags2[k];
+    alt_sprite_floor[k] = sprite_floor[k];
+    alt_sprite_spawned_flag[k] = sprite_ai_state[k];
+    alt_sprite_flags3[k] = sprite_flags3[k];
+    alt_sprite_B[k] = sprite_B[k];
+    alt_sprite_C[k] = sprite_C[k];
+    alt_sprite_E[k] = sprite_E[k];
+    alt_sprite_subtype2[k] = sprite_subtype2[k];
+    alt_sprite_height_above_shadow[k] = sprite_z[k];
+    alt_sprite_delay_main[k] = sprite_delay_main[k];
+    alt_sprite_I[k] = sprite_I[k];
+    alt_sprite_maybe_ignore_projectile[k] = sprite_ignore_projectile[k];
+  }
+}
+
+void Sprite_DisableAll() {  // 89c22f
+  for (int k = 15; k >= 0; k--) {
+    if (sprite_state[k] && (player_is_indoors || sprite_type[k] != 0x6c))
+      sprite_state[k] = 0;
+  }
+  for (int k = 9; k >= 0; k--)
+    ancilla_type[k] = 0;
+  flag_is_ancilla_to_pick_up = 0;
+  sprite_limit_instance = 0;
+  byte_7E0B9B = 0;
+  byte_7E0B88 = 0;
+  archery_game_arrows_left = 0;
+  garnish_active = 0;
+  byte_7E0B9E = 0;
+  activate_bomb_trap_overlord = 0;
+  intro_times_pal_flash = 0;
+  byte_7E0FF8 = 0;
+  byte_7E0FFB = 0;
+  flag_block_link_menu = 0;
+  byte_7E0FFD = 0;
+  byte_7E0FC6 = 0;
+  is_archer_or_shovel_game = 0;
+  for (int k = 7; k >= 0; k--)
+    overlord_type[k] = 0;
+  for (int k = 29; k >= 0; k--)
+    garnish_type[k] = 0;
+}
+
+void Dungeon_LoadSprites() {  // 89c290
+  const uint8 *src = kDungeonSprites + kDungeonSpriteOffs[dungeon_room_index2];
+  byte_7E0FB1 = dungeon_room_index2 >> 3 & 0xfe;
+  byte_7E0FB0 = (dungeon_room_index2 & 0xf) << 1;
+  sort_sprites_setting = *src++;
+  for (int k = 0; *src != 0xff; src += 3)
+    k = Dungeon_LoadSingleSprite(k, src) + 1;
+}
+
+void Sprite_ManuallySetDeathFlagUW(int k) {  // 89c2f5
+  if (!player_is_indoors || sprite_defl_bits[k] & 1 || sign8(sprite_N[k]))
+    return;
+  sprite_where_in_room[dungeon_room_index2] |= 1 << sprite_N[k];
+}
+
+int Dungeon_LoadSingleSprite(int k, const uint8 *src) {  // 89c327
+  uint8 y = src[0], x = src[1], type = src[2];
+  if (type == 0xe4) {
+    if (y == 0xfe || y == 0xfd) {
+      sprite_die_action[k - 1] = (y == 0xfe) ? 1 : 2;
+      return k - 1;
+    }
+  } else if (x >= 0xe0) {
+    Dungeon_LoadSingleOverlord(src);
+    return k - 1;
+  }
+  if (!(kSpriteInit_DeflBits[type] & 1) && (sprite_where_in_room[dungeon_room_index2] & (1 << k)))
+    return k;
+  sprite_state[k] = 8;
+  tmp_counter = y;
+  sprite_floor[k] = (y >> 7);
+  Sprite_SetY(k, ((y << 4) & 0x1ff) + (byte_7E0FB1 << 8));
+  byte_7E0FB6 = x;
+  Sprite_SetX(k, ((x << 4) & 0x1ff) + (byte_7E0FB0 << 8));
+  sprite_type[k] = type;
+  tmp_counter = (tmp_counter & 0x60) >> 2;
+  sprite_subtype[k] = tmp_counter | byte_7E0FB6 >> 5;
+  sprite_N[k] = k;
+  sprite_die_action[k] = 0;
+  return k;
+}
+
+void Dungeon_LoadSingleOverlord(const uint8 *src) {  // 89c3e8
+  int k = AllocOverlord();
+  if (k < 0)
+    return;
+  uint8 y = src[0], x = src[1], type = src[2];
+  overlord_type[k] = type;
+  overlord_floor[k] = (y >> 7);
+  int t = ((y << 4) & 0x1ff) + (byte_7E0FB1 << 8);
+  overlord_y_lo[k] = t;
+  overlord_y_hi[k] = t >> 8;
+  t = ((x << 4) & 0x1ff) + (byte_7E0FB0 << 8);
+  overlord_x_lo[k] = t;
+  overlord_x_hi[k] = t >> 8;
+  overlord_spawned_in_area[k] = overworld_area_index;
+  overlord_gen2[k] = 0;
+  overlord_gen1[k] = 0;
+  overlord_gen3[k] = 0;
+  if (overlord_type[k] == 10 || overlord_type[k] == 11) {
+    overlord_gen2[k] = 160;
+  } else if (overlord_type[k] == 3) {
+    overlord_gen2[k] = 255;
+    overlord_x_lo[k] -= 8;
+  }
+}
+
+void Sprite_ResetAll() {  // 89c44e
+  Sprite_DisableAll();
+  Sprite_ResetAll_noDisable();
+}
+
+void Sprite_ResetAll_noDisable() {  // 89c452
+  byte_7E0FDD = 0;
+  sprite_alert_flag = 0;
+  byte_7E0FFD = 0;
+  byte_7E02F0 = 0;
+  byte_7E0FC6 = 0;
+  sprite_limit_instance = 0;
+  sort_sprites_setting = 0;
+  if (follower_indicator != 13)
+    super_bomb_indicator_unk2 = 0xfe;
+  memset(sprite_where_in_room, 0, 0x1000);
+  memset(overworld_sprite_was_loaded, 0, 0x200);
+  memset(dungeon_room_history, 0xff, 8);
+}
+
+void Sprite_ReloadAll_Overworld() {  // 89c499
+  Sprite_DisableAll();
+  Sprite_OverworldReloadAll_justLoad();
+}
+
+void Sprite_OverworldReloadAll_justLoad() {  // 89c49d
+  Sprite_ResetAll_noDisable();
+  Overworld_LoadSprites();
+  Sprite_ActivateAllProxima();
+}
+
+void Overworld_LoadSprites() {  // 89c4ac
+  sprcoll_x_base = (overworld_area_index & 7) << 9;
+  sprcoll_y_base = ((overworld_area_index & 0x3f) >> 2 & 0xe) << 8;
+  sprcoll_x_size = sprcoll_y_size = kOverworldAreaSprcollSizes[BYTE(overworld_area_index)] << 8;
+  const uint8 *src = GetOverworldSpritePtr(overworld_area_index);
+  uint8 b;
+
+  for (; (b = src[0]) != 0xff; src += 3) {
+    if (src[2] == 0xf4) {
+      byte_7E0FFD++;
+      continue;
+    }
+    uint8 r2 = (src[0] >> 4) << 2;
+    uint8 r6 = (src[1] >> 4) + r2;
+    uint8 r5 = src[1] & 0xf | src[0] << 4;
+    sprite_where_in_overworld[r5 | r6 << 8] = src[2] + 1;
+  }
+}
+
+void Sprite_ActivateAllProxima() {  // 89c55e
+  uint16 bak0 = BG2HOFS_copy2;
+  uint8 bak1 = byte_7E069E[1];
+  byte_7E069E[1] = 0xff;
+
+  int xt = (enhanced_features0 & kFeatures0_ExtendScreen64) ? 0x40 : 0;
+  BG2HOFS_copy2 -= xt;
+  for (int i = 21 + (xt >> 3); i >= 0; i--) {
+    Sprite_ActivateWhenProximal();
+    BG2HOFS_copy2 += 16;
+  }
+  byte_7E069E[1] = bak1;
+  BG2HOFS_copy2 = bak0;
+}
+
+void Sprite_ProximityActivation() {  // 89c58f
+  if (submodule_index != 0) {
+    Sprite_ActivateWhenProximal();
+    Sprite_ActivateWhenProximalBig();
+  } else {
+    if (!(spr_ranged_based_toggler & 1))
+      Sprite_ActivateWhenProximal();
+    if (spr_ranged_based_toggler & 1)
+      Sprite_ActivateWhenProximalBig();
+    spr_ranged_based_toggler++;
+  }
+}
+
+void Sprite_ActivateWhenProximal() {  // 89c5bb
+  if (byte_7E069E[1]) {
+    int xt = (enhanced_features0 & kFeatures0_ExtendScreen64) ? 0x40 : 0;
+    uint16 x = BG2HOFS_copy2 + (sign8(byte_7E069E[1]) ? -0x10 - xt : 0x110 + xt);
+    uint16 y = BG2VOFS_copy2 - 0x30;
+    for (int i = 21; i >= 0; i--, y += 16)
+      Sprite_Overworld_ProximityMotivatedLoad(x, y);
+  }
+}
+
+void Sprite_ActivateWhenProximalBig() {  // 89c5fa
+  if (byte_7E069E[0]) {
+    int xt = (enhanced_features0 & kFeatures0_ExtendScreen64) ? 0x40 : 0;
+    uint16 x = BG2HOFS_copy2 - 0x30 - xt;
+    uint16 y = BG2VOFS_copy2 + (sign8(byte_7E069E[0]) ? -0x10 : 0x110);
+    for (int i = 21 + (xt >> 3); i >= 0; i--, x += 16)
+      Sprite_Overworld_ProximityMotivatedLoad(x, y);
+  }
+}
+
+void Sprite_Overworld_ProximityMotivatedLoad(uint16 x, uint16 y) {  // 89c6f5
+  uint16 xt = (uint16)(x - sprcoll_x_base);
+  uint16 yt = (uint16)(y - sprcoll_y_base);
+  if (xt >= sprcoll_x_size || yt >= sprcoll_y_size)
+    return;
+
+  uint8 r1 = (yt >> 8) * 4 | (xt >> 8);
+  uint8 r0 = y & 0xf0 | x >> 4 & 0xf;
+  Overworld_LoadProximaSpriteIfAlive(r1 << 8 | r0);
+}
+
+void Overworld_LoadProximaSpriteIfAlive(uint16 blk) {  // 89c739
+  uint8 *p5 = sprite_where_in_overworld + blk;
+  uint8 sprite_to_spawn = *p5;
+  if (!sprite_to_spawn)
+    return;
+
+  uint8 loadedmask = (0x80 >> (blk & 7));
+  uint8 *loadedp = &overworld_sprite_was_loaded[blk >> 3];
+
+  if (*loadedp & loadedmask)
+    return;
+
+  if (sprite_to_spawn >= 0xf4) {
+    // load overlord
+    int k = AllocOverlord();
+    if (k < 0)
+      return;
+    *loadedp |= loadedmask;
+    overlord_offset_sprite_pos[k] = blk;
+    overlord_type[k] = sprite_to_spawn - 0xf3;
+    overlord_x_lo[k] = (blk << 4 & 0xf0) + (overlord_type[k] == 1 ? 8 : 0);
+    overlord_y_lo[k] = blk & 0xf0;
+    overlord_x_hi[k] = (blk >> 8 & 3) + HIBYTE(sprcoll_x_base);
+    overlord_y_hi[k] = (blk >> 10) + HIBYTE(sprcoll_y_base);
+    overlord_floor[k] = 0;
+    overlord_spawned_in_area[k] = overworld_area_index;
+    overlord_gen2[k] = 0;
+    overlord_gen1[k] = 0;
+    overlord_gen3[k] = 0;
+  } else {
+    // load regular sprite
+    int k = Overworld_AllocSprite(sprite_to_spawn);
+    if (k < 0)
+      return;
+    *loadedp |= loadedmask;
+
+    sprite_N_word[k] = blk;
+    sprite_type[k] = sprite_to_spawn - 1;
+    sprite_state[k] = 8;
+    sprite_x_lo[k] = blk << 4 & 0xf0;
+    sprite_y_lo[k] = blk & 0xf0;
+    sprite_x_hi[k] = (blk >> 8 & 3) + HIBYTE(sprcoll_x_base);
+    sprite_y_hi[k] = (blk >> 10) + HIBYTE(sprcoll_y_base);
+    sprite_floor[k] = 0;
+    sprite_subtype[k] = 0;
+    sprite_die_action[k] = 0;
+  }
+}
+
+void SpriteExplode_SpawnEA(int k) {  // 89ee4c
+  tmp_counter = sprite_type[k];
+  SpriteSpawnInfo info;
+  int j = Sprite_SpawnDynamicallyEx(k, 0xea, &info, 14);
+  Sprite_SetSpawnedCoordinates(j, &info);
+  sprite_z_vel[j] = 32;
+  sprite_floor[j] = link_is_on_lower_level;
+  sprite_A[j] = (j == 9) ? 2 : 6;
+  Sprite_SetY(j, info.r2_y + 3);
+  if (tmp_counter == 0xce) {
+    Sprite_SetY(j, info.r2_y + 16);
+    return;
+  }
+  if (tmp_counter == 0xcb) {
+    sprite_y_lo[j] = sprite_x_lo[j] = 0x78;
+    sprite_x_hi[j] = HIBYTE(link_x_coord);
+    sprite_y_hi[j] = HIBYTE(link_y_coord);
+  }
+}
+
+void Sprite_KillFriends() {  // 89ef56
+  for(int j = 15; j >= 0; j--) {
+    if (j != cur_object_index && sprite_state[j] && !(sprite_defl_bits[j] & 2) && sprite_type[j] != 0x7a) {
+      sprite_state[j] = 6;
+      sprite_delay_main[j] = 15;
+      sprite_flags3[j] = 0;
+      sprite_flags5[j] = 0;
+      sprite_flags2[j] = 3;
+    }
+  }
+}
+
+void Garnish16_ThrownItemDebris(int k) {  // 89f0cb
+  static const int16 kScatterDebris_Draw_X[64] = {
+     0,  8,  0,  8, -2,  9, -1,  9, -4,  9, -1, 10, -6,  9, -1, 12,
+    -7,  9, -2, 13, -9,  9, -3, 14, -4, -4,  9, 15, -3, -3, -3,  9,
+    -4,  4,  6, 10, -1,  4,  6,  7,  0,  2,  4,  7,  1,  1,  5,  7,
+     0, -2,  8,  9, -1, -6,  9, 10, -2, -7, 12, 11, -3, -9,  4,  6,
+  };
+  static const int8 kScatterDebris_Draw_Y[64] = {
+      0,  0,  8,  8,   0, -1, 10, 10,   0, -3, 11,  7,   1, -4, 12,  8,
+      1, -4, 13,  9,   2, -4, 16, 10,  14, 14, -4, 11,  16, 16, 16, -1,
+      2, -5,  5,  1,   3, -7,  8,  2,   4, -8,  4, 10,  -9,  4,  4, 12,
+    -10,  4,  8, 14, -12,  4,  8, 15, -15,  3,  8, 17, -17,  1, 18, 15,
+  };
+  static const int8 kScatterDebris_Draw_Char[64] = {
+    0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58,
+    0x48, 0x58, 0x58, 0x58, 0x48, 0x58, 0x58, 0x48, 0x48, 0x48, 0x58, 0x48, 0x48, 0x48, 0x48, 0x48,
+    0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59,
+    0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59,
+  };
+  static const uint8 kScatterDebris_Draw_Flags[64] = {
+    0x80,    0, 0x80, 0x40, 0x80, 0x40, 0x80,    0,    0, 0xc0,    0, 0x80, 0x80, 0x40, 0x80,    0,
+    0x80, 0xc0,    0, 0x80,    0,    0, 0x80,    0, 0x80, 0x80, 0x80, 0x80,    0,    0,    0,    0,
+    0x40, 0x40, 0x40,    0, 0x40, 0x40, 0x40,    0, 0x40, 0x40,    0,    0, 0x80,    0, 0x40, 0x40,
+    0x40,    0, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,    0,    0, 0x40,    0,    0,    0,
+  };
+  Point16U pt;
+  if (Garnish_ReturnIfPrepFails(k, &pt))
+    return;
+  uint8 r5 = garnish_oam_flags[k];
+  if (byte_7E0FC6 >= 3)
+    return;
+  if (garnish_sprite[k] == 3) {
+    ScatterDebris_Draw(k, pt);
+    return;
+  }
+  OamEnt *oam = GetOamCurPtr();
+  tmp_counter = garnish_sprite[k];
+  uint8 base = ((garnish_countdown[k] >> 2) ^ 7) << 2;
+  if (tmp_counter == 4 || tmp_counter == 2 && !player_is_indoors)
+    base += 0x20;
+  for (int i = 3; i >= 0; i--, oam++) {
+    int j = i + base;
+    SetOamHelper1(oam, pt.x + kScatterDebris_Draw_X[j], pt.y + kScatterDebris_Draw_Y[j],
+                  (tmp_counter == 0) ? 0x4E : (tmp_counter >= 0x80) ? 0xF2 : kScatterDebris_Draw_Char[j],
+                  kScatterDebris_Draw_Flags[j] | r5, 0);
+  }
+}
+
+void ScatterDebris_Draw(int k, Point16U pt) {  // 89f198
+  static const int8 kScatterDebris_Draw_X2[12] = {-8, 8, 16, -5, 8, 15, -1, 7, 11, 1, 3, 8};
+  static const int8 kScatterDebris_Draw_Y2[12] = {7, 2, 12, 9, 2, 10, 11, 2, 11, 7, 3, 8};
+  static const uint8 kScatterDebris_Draw_Char2[12] = {0xe2, 0xe2, 0xe2, 0xe2, 0xf2, 0xf2, 0xf2, 0xe2, 0xe2, 0xf2, 0xe2, 0xe2};
+  static const uint8 kScatterDebris_Draw_Flags2[12] = {0, 0, 0, 0, 0x80, 0x40, 0, 0x80, 0x40, 0, 0, 0};
+
+  if (garnish_countdown[k] == 16)
+    garnish_type[k] = 0;
+
+  OamEnt *oam = GetOamCurPtr();
+  int base = ((garnish_countdown[k] & 0xf) >> 2) * 3;
+
+  for (int i = 2; i >= 0; i--, oam++) {
+    int j = i + base;
+    SetOamHelper1(oam, pt.x + kScatterDebris_Draw_X2[j], pt.y + kScatterDebris_Draw_Y2[j],
+                  kScatterDebris_Draw_Char2[j], kScatterDebris_Draw_Flags2[j] | 0x22, 0);
+  }
+}
+
+void Sprite_KillSelf(int k) {  // 89f1f8
+  if (!(sprite_defl_bits[k] & 0x40) && player_is_indoors)
+    return;
+  sprite_state[k] = 0;
+  uint16 blk = sprite_N_word[k];
+  g_ram[0] = blk;  // Sprite_PrepOamCoordOrDoubleRet reads this!
+  WORD(g_ram[1]) = (blk >> 3) + 0xef80; // Sprite_PrepOamCoordOrDoubleRet reads this!
+  uint8 loadedmask = (0x80 >> (blk & 7));
+  uint16 addr = 0xEF80 + (blk >> 3);  // warning: blk may be bad, seen with cannon balls in 2nd dungeon
+
+  uint8 *loadedp = &g_ram[addr + 0x10000];
+
+  if (blk < 0xffff)
+    *loadedp &= ~loadedmask;
+  if (!player_is_indoors)
+    sprite_N_word[k] = 0xffff;
+  else
+    sprite_N[k] = 0xff;
+}
+
+void SpritePrep_LoadProperties(int k) {  // 8db818
+  SpritePrep_ResetProperties(k);
+  int j = sprite_type[k];
+  sprite_flags2[k] = kSpriteInit_Flags2[j];
+  sprite_health[k] = kSpriteInit_Health[j];
+  sprite_flags4[k] = kSpriteInit_Flags4[j];
+  sprite_flags5[k] = kSpriteInit_Flags5[j];
+  sprite_defl_bits[k] = kSpriteInit_DeflBits[j];
+  sprite_bump_damage[k] = kSpriteInit_BumpDamage[j];
+  sprite_flags[k] = kSpriteInit_Flags[j];
+  sprite_room[k] = player_is_indoors ? dungeon_room_index2 : overworld_area_index;
+  sprite_flags3[k] = kSpriteInit_Flags3[j];
+  sprite_oam_flags[k] = kSpriteInit_Flags3[j] & 0xf;
+}
+
+void SpritePrep_LoadPalette(int k) {  // 8db85c
+  int f = kSpriteInit_Flags3[sprite_type[k]];
+  sprite_flags3[k] = f;
+  sprite_oam_flags[k] = f & 15;
+}
+
+void SpritePrep_ResetProperties(int k) {  // 8db871
+  sprite_pause[k] = 0;
+  sprite_E[k] = 0;
+  sprite_x_vel[k] = 0;
+  sprite_y_vel[k] = 0;
+  sprite_z_vel[k] = 0;
+  sprite_x_subpixel[k] = 0;
+  sprite_y_subpixel[k] = 0;
+  sprite_z_subpos[k] = 0;
+  sprite_ai_state[k] = 0;
+  sprite_graphics[k] = 0;
+  sprite_D[k] = 0;
+  sprite_delay_main[k] = 0;
+  sprite_delay_aux1[k] = 0;
+  sprite_delay_aux2[k] = 0;
+  sprite_delay_aux4[k] = 0;
+  sprite_head_dir[k] = 0;
+  sprite_anim_clock[k] = 0;
+  sprite_G[k] = 0;
+  sprite_hit_timer[k] = 0;
+  sprite_wallcoll[k] = 0;
+  sprite_z[k] = 0;
+  sprite_health[k] = 0;
+  sprite_F[k] = 0;
+  sprite_x_recoil[k] = 0;
+  sprite_y_recoil[k] = 0;
+  sprite_A[k] = 0;
+  sprite_B[k] = 0;
+  sprite_C[k] = 0;
+  sprite_unk2[k] = 0;
+  sprite_subtype2[k] = 0;
+  sprite_ignore_projectile[k] = 0;
+  sprite_obj_prio[k] = 0;
+  sprite_oam_flags[k] = 0;
+  sprite_stunned[k] = 0;
+  sprite_give_damage[k] = 0;
+  sprite_unk3[k] = 0;
+  sprite_unk4[k] = 0;
+  sprite_unk5[k] = 0;
+  sprite_unk1[k] = 0;
+  sprite_I[k] = 0;
+}
+
+uint8 Oam_AllocateFromRegionA(uint8 num) {  // 8dba80
+  return Oam_GetBufferPosition(num, 0);
+}
+
+uint8 Oam_AllocateFromRegionB(uint8 num) {  // 8dba84
+  return Oam_GetBufferPosition(num, 2);
+}
+
+uint8 Oam_AllocateFromRegionC(uint8 num) {  // 8dba88
+  return Oam_GetBufferPosition(num, 4);
+}
+
+uint8 Oam_AllocateFromRegionD(uint8 num) {  // 8dba8c
+  return Oam_GetBufferPosition(num, 6);
+}
+
+uint8 Oam_AllocateFromRegionE(uint8 num) {  // 8dba90
+  return Oam_GetBufferPosition(num, 8);
+}
+
+uint8 Oam_AllocateFromRegionF(uint8 num) {  // 8dba94
+  return Oam_GetBufferPosition(num, 10);
+}
+
+uint8 Oam_GetBufferPosition(uint8 num, uint8 y) {  // 8dbb0a
+  y >>= 1;
+  uint16 p = oam_region_base[y], pstart = p;
+  p += num;
+  if (p >= kOamGetBufferPos_Tab0[y]) {
+    int j = oam_alloc_arr1[y]++ & 7;
+    pstart = kOamGetBufferPos_Tab1[y * 8 + j];
+  } else {
+    oam_region_base[y] = p;
+  }
+  oam_ext_cur_ptr = 0xa20 + (pstart >> 2);
+  oam_cur_ptr = 0x800 + pstart;
+  return oam_cur_ptr;
+}
+
+void Sprite_NullifyHookshotDrag() {  // 8ff540
+  for (int i = 4; i >= 0; i--) {
+    if (!(ancilla_type[i] & 0x1f) && related_to_hookshot) {
+      related_to_hookshot = 0;
+      break;
+    }
+  }
+  link_x_coord_safe_return_hi = link_x_coord >> 8;
+  link_y_coord_safe_return_hi = link_y_coord >> 8;
+  link_x_coord = link_x_coord_prev;
+  link_y_coord = link_y_coord_prev;
+  HandleIndoorCameraAndDoors();
+}
+
+void Overworld_SubstituteAlternateSecret() {  // 9afbdb
+  static const uint8 kSecretSubst_Tab0[64] = {
+    0,  0, 0, 0, 0, 0, 0, 4,  0,  0, 0, 0, 0, 0, 0, 0,
+    4,  4, 6, 4, 4, 6, 0, 0, 15, 15, 4, 5, 5, 4, 6, 6,
+    15, 15, 4, 5, 5, 7, 6, 6, 31, 31, 4, 7, 7, 4, 6, 6,
+    6,  7, 2, 0, 0, 0, 0, 0,  6,  6, 2, 0, 0, 0, 0, 0,
+  };
+  static const uint8 kSecretSubst_Tab2[16] = { 1, 1, 1, 1, 15, 1, 1, 18, 16, 1, 1, 1, 17, 1, 1, 3 };
+  static const uint8 kSecretSubst_Tab1[16] = { 0, 0, 0, 0, 2, 0, 0, 8, 16, 0, 0, 0, 1, 0, 0, 0 };
+  if (GetRandomNumber() & 1)
+    return;
+  int n = 0;
+  for (int j = 15; j >= 0; j--) {
+    if (sprite_state[j] && sprite_type[j] != 0x6c)
+      n++;
+  }
+  if (n >= 4 || sram_progress_indicator < 2)
+    return;
+  int j = (overworld_secret_subst_ctr++ & 7) + (is_in_dark_world ? 8 : 0);
+  if (!(kSecretSubst_Tab0[BYTE(overworld_area_index) & 0x3f] & kSecretSubst_Tab1[j]))
+    BYTE(dung_secrets_unk1) = kSecretSubst_Tab2[j];
+}
+
+void Sprite_ApplyConveyor(int k, int j) {  // 9d8010
+  if (!(frame_counter & 1))
+    return;
+  static const int8 kConveyorAdjustment_X[] = {0, 0, -1, 1};
+  static const int8 kConveyorAdjustment_Y[] = {-1, 1, 0, 0};
+  Sprite_SetX(k, Sprite_GetX(k) + kConveyorAdjustment_X[j - 0x68]);
+  Sprite_SetY(k, Sprite_GetY(k) + kConveyorAdjustment_Y[j - 0x68]);
+}
+
+uint8 Sprite_BounceFromTileCollision(int k) {  // 9dc751
+  int j = Sprite_CheckTileCollision(k);
+  if (j & 3) {
+    sprite_x_vel[k] = -sprite_x_vel[k];
+    sprite_G[k]++;
+  }
+  if (j & 12) {
+    sprite_y_vel[k] = -sprite_y_vel[k];
+    sprite_G[k]++;
+    return sprite_G[k]; // wtf
+  }
+  return 0;
+}
+
+void ExecuteCachedSprites() {  // 9de9da
+  if (!player_is_indoors || submodule_index == 0 || submodule_index == 14 || alt_sprites_flag == 0) {
+    alt_sprites_flag = 0;
+    return;
+  }
+  for (int i = 15; i >= 0; i--) {
+    cur_object_index = i;
+    if (alt_sprite_state[i])
+      UncacheAndExecuteSprite(i);
+  }
+}
+
+void UncacheAndExecuteSprite(int k) {  // 9dea00
+  uint8 bak0 = sprite_state[k];
+  uint8 bak1 = sprite_type[k];
+  uint8 bak2 = sprite_x_lo[k];
+  uint8 bak3 = sprite_x_hi[k];
+  uint8 bak4 = sprite_y_lo[k];
+  uint8 bak5 = sprite_y_hi[k];
+  uint8 bak6 = sprite_graphics[k];
+  uint8 bak7 = sprite_A[k];
+  uint8 bak8 = sprite_head_dir[k];
+  uint8 bak9 = sprite_oam_flags[k];
+  uint8 bak10 = sprite_obj_prio[k];
+  uint8 bak11 = sprite_D[k];
+  uint8 bak12 = sprite_flags2[k];
+  uint8 bak13 = sprite_floor[k];
+  uint8 bak14 = sprite_ai_state[k];
+  uint8 bak15 = sprite_flags3[k];
+  uint8 bak16 = sprite_B[k];
+  uint8 bak17 = sprite_C[k];
+  uint8 bak18 = sprite_E[k];
+  uint8 bak19 = sprite_subtype2[k];
+  uint8 bak20 = sprite_z[k];
+  uint8 bak21 = sprite_delay_main[k];
+  uint8 bak22 = sprite_I[k];
+  uint8 bak23 = sprite_ignore_projectile[k];
+  sprite_state[k] = alt_sprite_state[k];
+  sprite_type[k] = alt_sprite_type[k];
+  sprite_x_lo[k] = alt_sprite_x_lo[k];
+  sprite_x_hi[k] = alt_sprite_x_hi[k];
+  sprite_y_lo[k] = alt_sprite_y_lo[k];
+  sprite_y_hi[k] = alt_sprite_y_hi[k];
+  sprite_graphics[k] = alt_sprite_graphics[k];
+  sprite_A[k] = alt_sprite_A[k];
+  sprite_head_dir[k] = alt_sprite_head_dir[k];
+  sprite_oam_flags[k] = alt_sprite_oam_flags[k];
+  sprite_obj_prio[k] = alt_sprite_obj_prio[k];
+  sprite_D[k] = alt_sprite_D[k];
+  sprite_flags2[k] = alt_sprite_flags2[k];
+  sprite_floor[k] = alt_sprite_floor[k];
+  sprite_ai_state[k] = alt_sprite_spawned_flag[k];
+  sprite_flags3[k] = alt_sprite_flags3[k];
+  sprite_B[k] = alt_sprite_B[k];
+  sprite_C[k] = alt_sprite_C[k];
+  sprite_E[k] = alt_sprite_E[k];
+  sprite_subtype2[k] = alt_sprite_subtype2[k];
+  sprite_z[k] = alt_sprite_height_above_shadow[k];
+  sprite_delay_main[k] = alt_sprite_delay_main[k];
+  sprite_I[k] = alt_sprite_I[k];
+  sprite_ignore_projectile[k] = alt_sprite_maybe_ignore_projectile[k];
+  Sprite_ExecuteSingle(k);
+  if (sprite_pause[k] != 0)
+    alt_sprite_state[k] = 0;
+  sprite_ignore_projectile[k] = bak23;
+  sprite_I[k] = bak22;
+  sprite_delay_main[k] = bak21;
+  sprite_z[k] = bak20;
+  sprite_subtype2[k] = bak19;
+  sprite_E[k] = bak18;
+  sprite_C[k] = bak17;
+  sprite_B[k] = bak16;
+  sprite_flags3[k] = bak15;
+  sprite_ai_state[k] = bak14;
+  sprite_floor[k] = bak13;
+  sprite_flags2[k] = bak12;
+  sprite_D[k] = bak11;
+  sprite_obj_prio[k] = bak10;
+  sprite_oam_flags[k] = bak9;
+  sprite_head_dir[k] = bak8;
+  sprite_A[k] = bak7;
+  sprite_graphics[k] = bak6;
+  sprite_y_hi[k] = bak5;
+  sprite_y_lo[k] = bak4;
+  sprite_x_hi[k] = bak3;
+  sprite_x_lo[k] = bak2;
+  sprite_type[k] = bak1;
+  sprite_state[k] = bak0;
+
+}
+
+uint8 Sprite_ConvertVelocityToAngle(uint8 x, uint8 y) {  // 9df614
+  static const uint8 kConvertVelocityToAngle_Tab0[32] = {
+    0, 0, 1, 1, 1, 2, 2, 2, 0, 0, 15, 15, 15, 14, 14, 14,
+    8, 8, 7, 7, 7, 6, 6, 6, 8, 8,  9,  9,  9, 10, 10, 10,
+  };
+  static const uint8 kConvertVelocityToAngle_Tab1[32] = {
+    4, 4, 3, 3, 3, 2, 2, 2, 12, 12, 13, 13, 13, 14, 14, 14,
+    4, 4, 5, 5, 5, 6, 6, 6, 12, 12, 11, 11, 11, 10, 10, 10,
+  };
+  int s = ((y >> 7) + (x >> 7) * 2) * 8;
+  if (sign8(x)) x = -x;
+  if (sign8(y)) y = -y;
+  if (x >= y) {
+    return kConvertVelocityToAngle_Tab0[(y >> 2) + s];
+  } else {
+    return kConvertVelocityToAngle_Tab1[(x >> 2) + s];
+  }
+}
+
+int Sprite_SpawnDynamically(int k, uint8 what, SpriteSpawnInfo *info) {  // 9df65d
+  return Sprite_SpawnDynamicallyEx(k, what, info, 15);
+}
+
+int Sprite_SpawnDynamicallyEx(int k, uint8 what, SpriteSpawnInfo *info, int j) {  // 9df65f
+  do {
+    if (sprite_state[j] == 0) {
+      sprite_type[j] = what;
+      sprite_state[j] = 9;
+      info->r0_x = Sprite_GetX(k);
+      info->r2_y = Sprite_GetY(k);
+      info->r4_z = sprite_z[k];
+      info->r5_overlord_x = overlord_x_lo[k] | overlord_x_hi[k] << 8;
+      info->r7_overlord_y = overlord_y_lo[k] | overlord_y_hi[k] << 8;
+      SpritePrep_LoadProperties(j);
+      if (!player_is_indoors) {
+        sprite_N_word[j] = 0xffff;
+      } else {
+        sprite_N[j] = 0xff;
+      }
+      sprite_floor[j] = sprite_floor[k];
+      sprite_D[j] = sprite_D[k];
+      sprite_die_action[j] = 0;
+      sprite_subtype[j] = 0;
+      break;
+    }
+  } while (--j >= 0);
+  return j;
+}
+
+void SpriteFall_Draw(int k, PrepOamCoordsRet *info) {  // 9dffc5
+  static const uint8 kSpriteFall_Char[8] = {0x83, 0x83, 0x83, 0x80, 0x80, 0x80, 0xb7, 0xb7};
+  OamEnt *oam = GetOamCurPtr();
+  oam->x = info->x + 4;
+  oam->y = info->y + 4;
+  oam->charnum = kSpriteFall_Char[sprite_delay_main[k] >> 2];
+  oam->flags = info->flags & 0x30 | 0x04;
+  Sprite_CorrectOamEntries(k, 0, 0);
+}
+
+void Sprite_GarnishSpawn_Sparkle_limited(int k, uint16 x, uint16 y) {  // 9ea001
+  Sprite_SpawnSimpleSparkleGarnishEx(k, x, y, 14);
+}
+
+int Sprite_GarnishSpawn_Sparkle(int k, uint16 x, uint16 y) {  // 9ea007
+  return Sprite_SpawnSimpleSparkleGarnishEx(k, x, y, 29);
+}
+
+void Sprite_BehaveAsBarrier(int k) {  // 9ef4f3
+  uint8 bak = sprite_flags4[k];
+  sprite_flags4[k] = 0;
+  if (Sprite_CheckDamageToLink_same_layer(k))
+    Sprite_HaltAllMovement();
+  sprite_flags4[k] = bak;
+}
+
+void Sprite_HaltAllMovement() {  // 9ef508
+  Sprite_NullifyHookshotDrag();
+  link_speed_setting = 0;
+  Link_CancelDash();
+}
+
+int ReleaseFairy() {  // 9efe33
+  SpriteSpawnInfo info;
+  int j = Sprite_SpawnDynamically(0, 0xe3, &info);
+  if (j >= 0) {
+    sprite_floor[j] = link_is_on_lower_level;
+    Sprite_SetX(j, link_x_coord + 8);
+    Sprite_SetY(j, link_y_coord + 16);
+    sprite_D[j] = 0;
+    sprite_delay_aux4[j] = 96;
+  }
+  return j;
+}
+
+void Sprite_DrawRippleIfInWater(int k) {  // 9eff8d
+  if (sprite_I[k] != 8 && sprite_I[k] != 9)
+    return;
+
+  if (sprite_flags3[k] & 0x20) {
+    cur_sprite_x -= 4;
+    if (sprite_type[k] == 0xdf)
+      cur_sprite_y -= 7;
+  }
+  SpriteDraw_WaterRipple(k);
+  Sprite_Get16BitCoords(k);
+  Oam_AllocateFromRegionA(((sprite_flags2[k] & 0x1f) + 1) * 4);
+}
+
--- /dev/null
+++ b/src/sprite.h
@@ -1,0 +1,309 @@
+#pragma once
+#include "types.h"
+#include "variables.h"
+
+
+typedef struct PrepOamCoordsRet {
+  uint16 x, y;
+  uint8 r4;
+  uint8 flags;
+} PrepOamCoordsRet;
+
+typedef struct SpriteHitBox {
+  uint8 r0_xlo;
+  uint8 r8_xhi;
+  uint8 r1_ylo;
+  uint8 r9_yhi;
+  uint8 r2, r3;
+
+  uint8 r4_spr_xlo;
+  uint8 r10_spr_xhi;
+
+  uint8 r5_spr_ylo;
+  uint8 r11_spr_yhi;
+  uint8 r6_spr_xsize;
+  uint8 r7_spr_ysize;
+} SpriteHitBox;
+
+typedef struct SpriteSpawnInfo {
+  uint16 r0_x;
+  uint16 r2_y;
+  uint8 r4_z;
+  uint16 r5_overlord_x;
+  uint16 r7_overlord_y;
+} SpriteSpawnInfo;
+
+extern const uint8 kAbsorbBigKey[2];
+
+typedef struct DrawMultipleData {
+  int8 x, y;
+  uint16 char_flags;
+  uint8 ext;
+} DrawMultipleData;
+
+
+enum {
+  kCheckDamageFromPlayer_Carry = 1,
+  kCheckDamageFromPlayer_Ne = 2,
+};
+
+static inline void SetOamHelper0(OamEnt *oam, uint16 x, uint16 y, uint8 charnum, uint8 flags, uint8 big) {
+  oam->x = x;
+  oam->y = (uint16)(y + 0x10) < 0x100 ? y : 0xf0;
+  oam->charnum = charnum;
+  oam->flags = flags;
+  bytewise_extended_oam[oam - oam_buf] = big | (x >> 8 & 1);
+}
+
+static inline void SetOamHelper1(OamEnt *oam, uint16 x, uint8 y, uint8 charnum, uint8 flags, uint8 big) {
+  oam->x = x;
+  oam->y = y;
+  oam->charnum = charnum;
+  oam->flags = flags;
+  bytewise_extended_oam[oam - oam_buf] = big | (x >> 8 & 1);
+}
+
+static inline void SetOamPlain(OamEnt *oam, uint8 x, uint8 y, uint8 charnum, uint8 flags, uint8 big) {
+  oam->x = x;
+  oam->y = y;
+  oam->charnum = charnum;
+  oam->flags = flags;
+  bytewise_extended_oam[oam - oam_buf] = big;
+}
+
+
+
+extern const uint8 kAbsorptionSfx[15];
+extern const uint8 kSpriteInit_BumpDamage[243];
+extern const uint16 kSinusLookupTable[256];
+extern const uint8 kThrowableScenery_Flags[9];
+extern const uint8 kWishPond2_OamFlags[76];
+
+uint16 Sprite_GetX(int k);
+uint16 Sprite_GetY(int k);
+void Sprite_SetX(int k, uint16 x);
+void Sprite_SetY(int k, uint16 y);
+void Sprite_ApproachTargetSpeed(int k, uint8 x, uint8 y);
+void SpriteAddXY(int k, int xv, int yv);
+void Sprite_MoveXYZ(int k);
+void Sprite_Invert_XY_Speeds(int k);
+int Sprite_SpawnSimpleSparkleGarnishEx(int k, uint16 x, uint16 y, int limit);
+uint16 Garnish_GetX(int k);
+uint16 Garnish_GetY(int k);
+void Garnish_SparkleCommon(int k, uint8 shift);
+void Garnish_DustCommon(int k, uint8 shift);
+void SpriteModule_Explode(int k);
+void SpriteDeath_MainEx(int k, bool second_entry);
+void SpriteModule_Burn(int k);
+void Sprite_HitTimer31(int k);
+void SpriteStunned_MainEx(int k, bool second_entry);
+int Ancilla_SpawnFallingPrize(uint8 item);
+bool Sprite_CheckDamageToAndFromLink(int k);
+uint8 Sprite_CheckTileCollision(int k);
+bool Sprite_TrackBodyToHead(int k);
+void Sprite_DrawMultiple(int k, const DrawMultipleData *src, int n, PrepOamCoordsRet *info);
+void Sprite_DrawMultiplePlayerDeferred(int k, const DrawMultipleData *src, int n, PrepOamCoordsRet *info);
+int Sprite_ShowSolicitedMessage(int k, uint16 msg);
+int Sprite_ShowMessageOnContact(int k, uint16 msg);
+void Sprite_ShowMessageUnconditional(uint16 msg);
+bool Sprite_TutorialGuard_ShowMessageOnContact(int k, uint16 msg);
+void Sprite_ShowMessageMinimal();
+void Prepare_ApplyRumbleToSprites();
+void Sprite_SpawnImmediatelySmashedTerrain(uint8 what, uint16 x, uint16 y);
+void Sprite_SpawnThrowableTerrain(uint8 what, uint16 x, uint16 y);
+int Sprite_SpawnThrowableTerrain_silently(uint8 what, uint16 x, uint16 y);
+void Sprite_SpawnSecret(int k);
+void Sprite_Main();
+void Oam_ResetRegionBases();
+void Sprite_TimersAndOam(int k);
+void Sprite_Get16BitCoords(int k);
+void Sprite_ExecuteSingle(int k);
+void Sprite_inactiveSprite(int k);
+void SpriteModule_Fall1(int k);
+void SpriteModule_Drown(int k);
+void Sprite_DrawDistress_custom(uint16 xin, uint16 yin, uint8 time);
+void Sprite_CheckIfLifted_permissive(int k);
+void Entity_ApplyRumbleToSprites(SpriteHitBox *hb);
+void Sprite_ZeroVelocity_XY(int k);
+bool Sprite_HandleDraggingByAncilla(int k);
+bool Sprite_ReturnIfPhasingOut(int k);
+void Sprite_CheckAbsorptionByPlayer(int k);
+void Sprite_HandleAbsorptionByPlayer(int k);
+bool SpriteDraw_AbsorbableTransient(int k, bool transient);
+void Sprite_DrawNumberedAbsorbable(int k, int a);
+void Sprite_BounceOffWall(int k);
+void Sprite_InvertSpeed_XY(int k);
+bool Sprite_ReturnIfInactive(int k);
+bool Sprite_ReturnIfPaused(int k);
+void SpriteDraw_SingleLarge(int k);
+void Sprite_PrepAndDrawSingleLargeNoPrep(int k, PrepOamCoordsRet *info);
+void SpriteDraw_Shadow_custom(int k, PrepOamCoordsRet *info, uint8 a);
+void SpriteDraw_Shadow(int k, PrepOamCoordsRet *oam);
+void SpriteDraw_SingleSmall(int k);
+void Sprite_DrawThinAndTall(int k);
+void SpriteModule_Carried(int k);
+void CarriedSprite_CheckForThrow(int k);
+void SpriteModule_Stunned(int k);
+void ThrownSprite_TileAndSpriteInteraction(int k);
+void Sprite_Func8(int k);
+void Sprite_Func22(int k);
+void ThrowableScenery_InteractWithSpritesAndTiles(int k);
+void ThrownSprite_CheckDamageToSprites(int k);
+void ThrownSprite_CheckDamageToSingleSprite(int k, int j);
+void Sprite_ApplyRicochet(int k);
+void ThrowableScenery_TransmuteIfValid(int k);
+void ThrowableScenery_TransmuteToDebris(int k);
+void Sprite_ScheduleForBreakage(int k);
+void Sprite_HalveSpeed_XY(int k);
+void Sprite_SpawnLeapingFish(int k);
+void SpriteStunned_Main_Func1(int k);
+void SpriteModule_Poof(int k);
+void Sprite_PrepOamCoord(int k, PrepOamCoordsRet *ret);
+bool Sprite_PrepOamCoordOrDoubleRet(int k, PrepOamCoordsRet *ret);
+void Sprite_CheckTileCollision2(int k);
+void Sprite_CheckTileCollisionSingleLayer(int k);
+void Sprite_CheckForTileInDirection_horizontal(int k, int yy);
+void Sprite_CheckForTileInDirection_vertical(int k, int yy);
+void SpriteFall_AdjustPosition(int k);
+bool Sprite_CheckTileInDirection(int k, int yy);
+bool Sprite_CheckTileProperty(int k, int j);
+uint8 GetTileAttribute(uint8 floor, uint16 *x, uint16 y);
+uint8 Sprite_GetTileAttribute(int k, uint16 *x, uint16 y);
+bool Entity_CheckSlopedTileCollision(uint16 x, uint16 y);
+void Sprite_MoveXY(int k);
+void Sprite_MoveX(int k);
+void Sprite_MoveY(int k);
+void Sprite_MoveZ(int k);
+ProjectSpeedRet Sprite_ProjectSpeedTowardsLink(int k, uint8 vel);
+void Sprite_ApplySpeedTowardsLink(int k, uint8 vel);
+ProjectSpeedRet Sprite_ProjectSpeedTowardsLocation(int k, uint16 x, uint16 y, uint8 vel);
+uint8 Sprite_DirectionToFaceLink(int k, PointU8 *coords_out);
+PairU8 Sprite_IsRightOfLink(int k);
+PairU8 Sprite_IsBelowLink(int k);
+PairU8 Sprite_IsRightOfLocation(int k, uint16 x);
+PairU8 Sprite_IsBelowLocation(int k, uint16 y);
+uint8 Sprite_DirectionToFaceLocation(int k, uint16 x, uint16 y);
+void Guard_ParrySwordAttacks(int k);
+void Sprite_AttemptZapDamage(int k);
+void Ancilla_CheckDamageToSprite_preset(int k, int a);
+void Sprite_Func15(int k, int a);
+void Sprite_CalculateSwordDamage(int k);
+void Sprite_ApplyCalculatedDamage(int k, int a);
+void Sprite_GiveDamage(int k, uint8 dmg, uint8 r0_hit_timer);
+void Sprite_Func18(int k, uint8 new_type);
+void Sprite_MiniMoldorm_Recoil(int k);
+void Sprite_Func3(int k);
+bool Sprite_CheckDamageToLink(int k);
+bool Sprite_CheckDamageToPlayer_1(int k);
+bool Sprite_CheckDamageToLink_same_layer(int k);
+bool Sprite_CheckDamageToLink_ignore_layer(int k);
+bool Sprite_SetupHitBox00(int k);
+bool Sprite_ReturnIfLifted(int k);
+bool Sprite_ReturnIfLiftedPermissive(int k);
+uint8 Sprite_CheckDamageFromLink(int k);
+void Sprite_AttemptDamageToLinkWithCollisionCheck(int k);
+void Sprite_AttemptDamageToLinkPlusRecoil(int k);
+void Player_SetupActionHitBox(SpriteHitBox *hb);
+void Link_UpdateHitBoxWithSword(SpriteHitBox *hb);
+void Sprite_DoHitBoxesFast(int k, SpriteHitBox *hb);
+void Sprite_ApplyRecoilToLink(int k, uint8 vel);
+void Link_PlaceWeaponTink();
+void Sprite_PlaceWeaponTink(int k);
+void Sprite_PlaceRupulseSpark_2(int k);
+void Link_SetupHitBox_conditional(SpriteHitBox *hb);
+void Link_SetupHitBox(SpriteHitBox *hb);
+void Sprite_SetupHitBox(int k, SpriteHitBox *hb);
+bool CheckIfHitBoxesOverlap(SpriteHitBox *hb);
+void Oam_AllocateDeferToPlayer(int k);
+void SpriteModule_Die(int k);
+void Sprite_DoTheDeath(int k);
+void ForcePrizeDrop(int k, uint8 prize, uint8 slot);
+void PrepareEnemyDrop(int k, uint8 item);
+void SpriteDeath_Func4(int k);
+void SpriteDeath_DrawPoof(int k);
+void SpriteModule_Fall2(int k);
+void SpriteDraw_FallingHelmaBeetle(int k);
+void SpriteDraw_FallingHumanoid(int k);
+void Sprite_CorrectOamEntries(int k, int n, uint8 islarge);
+bool Sprite_ReturnIfRecoiling(int k);
+bool Sprite_CheckIfLinkIsBusy();
+void Sprite_SetSpawnedCoordinates(int k, SpriteSpawnInfo *info);
+bool Sprite_CheckIfScreenIsClear();
+bool Sprite_CheckIfRoomIsClear();
+bool Sprite_CheckIfOverlordsClear();
+void Sprite_InitializeMirrorPortal();
+void Sprite_InitializeSlots();
+void Garnish_ExecuteUpperSlots();
+void Garnish_ExecuteLowerSlots();
+void Garnish_ExecuteSingle(int k);
+void Garnish15_ArrghusSplash(int k);
+void Garnish13_PyramidDebris(int k);
+void Garnish11_WitheringGanonBatFlame(int k);
+void Garnish10_GanonBatFlame(int k);
+void Garnish0C_TrinexxIceBreath(int k);
+void Garnish14_KakKidDashDust(int k);
+void Garnish_WaterTrail(int k);
+void Garnish0A_CannonSmoke(int k);
+void Garnish09_LightningTrail(int k);
+void Garnish_CheckPlayerCollision(int k, int x, int y);
+void Garnish07_BabasuFlash(int k);
+void Garnish08_KholdstareTrail(int k);
+void Garnish06_ZoroTrail(int k);
+void Garnish12_Sparkle(int k);
+void Garnish_SimpleSparkle(int k);
+void Garnish0E_TrinexxFireBreath(int k);
+void Garnish0F_BlindLaserTrail(int k);
+void Garnish04_LaserTrail(int k);
+bool Garnish_ReturnIfPrepFails(int k, Point16U *pt);
+void Garnish03_FallingTile(int k);
+void Garnish01_FireSnakeTail(int k);
+void Garnish02_MothulaBeamTrail(int k);
+void Dungeon_ResetSprites();
+void Dungeon_CacheTransSprites();
+void Sprite_DisableAll();
+void Dungeon_LoadSprites();
+void Sprite_ManuallySetDeathFlagUW(int k);
+int Dungeon_LoadSingleSprite(int k, const uint8 *src);
+void Dungeon_LoadSingleOverlord(const uint8 *src);
+void Sprite_ResetAll();
+void Sprite_ResetAll_noDisable();
+void Sprite_ReloadAll_Overworld();
+void Sprite_OverworldReloadAll_justLoad();
+void Overworld_LoadSprites();
+void Sprite_ActivateAllProxima();
+void Sprite_ProximityActivation();
+void Sprite_ActivateWhenProximal();
+void Sprite_ActivateWhenProximalBig();
+void Sprite_Overworld_ProximityMotivatedLoad(uint16 x, uint16 y);
+void Overworld_LoadProximaSpriteIfAlive(uint16 blk);
+void SpriteExplode_SpawnEA(int k);
+void Sprite_KillFriends();
+void Garnish16_ThrownItemDebris(int k);
+void ScatterDebris_Draw(int k, Point16U pt);
+void Sprite_KillSelf(int k);
+void SpritePrep_LoadProperties(int k);
+void SpritePrep_LoadPalette(int k);
+void SpritePrep_ResetProperties(int k);
+uint8 Oam_AllocateFromRegionA(uint8 num);
+uint8 Oam_AllocateFromRegionB(uint8 num);
+uint8 Oam_AllocateFromRegionC(uint8 num);
+uint8 Oam_AllocateFromRegionD(uint8 num);
+uint8 Oam_AllocateFromRegionE(uint8 num);
+uint8 Oam_AllocateFromRegionF(uint8 num);
+uint8 Oam_GetBufferPosition(uint8 num, uint8 y);
+void Sprite_NullifyHookshotDrag();
+void Overworld_SubstituteAlternateSecret();
+void Sprite_ApplyConveyor(int k, int j);
+uint8 Sprite_BounceFromTileCollision(int k);
+void ExecuteCachedSprites();
+void UncacheAndExecuteSprite(int k);
+uint8 Sprite_ConvertVelocityToAngle(uint8 x, uint8 y);
+int Sprite_SpawnDynamically(int k, uint8 what, SpriteSpawnInfo *info);
+int Sprite_SpawnDynamicallyEx(int k, uint8 what, SpriteSpawnInfo *info, int j);
+void SpriteFall_Draw(int k, PrepOamCoordsRet *info);
+void Sprite_GarnishSpawn_Sparkle_limited(int k, uint16 x, uint16 y);
+int Sprite_GarnishSpawn_Sparkle(int k, uint16 x, uint16 y);
+void Sprite_BehaveAsBarrier(int k);
+void Sprite_HaltAllMovement();
+int ReleaseFairy();
+void Sprite_DrawRippleIfInWater(int k);
--- /dev/null
+++ b/src/sprite_main.c
@@ -1,0 +1,25878 @@
+#include "sprite_main.h"
+#include "sprite.h"
+#include "tagalong.h"
+#include "ancilla.h"
+#include "overworld.h"
+#include "load_gfx.h"
+#include "hud.h"
+#include "dungeon.h"
+#include "player.h"
+#include "misc.h"
+
+#define byte_7FFE01 (*(uint8*)(g_ram+0x1FE01))
+static const int8 kSpriteKeese_Tab2[16] = {0, 8, 11, 14, 16, 14, 11, 8, 0, -8, -11, -14, -16, -14, -11, -8};
+static const int8 kSpriteKeese_Tab3[16] = {-16, -14, -11, -8, 0, 8, 11, 14, 16, 14, 11, 8, 0, -9, -11, -14};
+static const int8 kZazak_Yvel[4] = {0, 0, 16, -16};
+static const int8 kFluteBoyAnimal_Xvel[4] = {16, -16, 0, 0};
+static const int8 kDesertBarrier_Xv[4] = {16, -16, 0, 0};
+static const int8 kDesertBarrier_Yv[4] = {0, 0, 16, -16};
+static const uint8 kCrystalSwitchPal[2] = {2, 4};
+static const uint8 kZazak_Dir2[8] = {2, 3, 2, 3, 0, 1, 0, 1};
+#define moldorm_x_lo ((uint8*)(g_ram+0x1FC00))
+#define moldorm_x_hi ((uint8*)(g_ram+0x1FC80))
+#define moldorm_y_lo ((uint8*)(g_ram+0x1FD00))
+#define moldorm_y_hi ((uint8*)(g_ram+0x1FD80))
+static const int8 kBadPullDownSwitch_X[5] = {-4, 12, 0, -4, 4};
+static const int8 kBadPullDownSwitch_Y[5] = {-3, -3, 0, 5, 5};
+static const uint8 kBadPullDownSwitch_Char[5] = {0xd2, 0xd2, 0xc4, 0xe4, 0xe4};
+static const uint8 kBadPullDownSwitch_Flags[5] = {0x40, 0, 0, 0x40, 0};
+static const uint8 kBadPullDownSwitch_Big[5] = {0, 0, 2, 2, 2};
+static const uint8 kBadPullSwitch_Tab5[6] = {0, 1, 2, 3, 4, 5};
+static const uint8 kBadPullSwitch_Tab4[12] = {0, 0, 1, 1, 2, 2, 3, 3, 4, 5, 5, 5};
+static const uint8 kThief_Gfx[12] = {11, 8, 2, 5, 9, 6, 0, 3, 10, 7, 1, 4};
+#define word_7FFE00 (*(uint16*)(g_ram+0x1FE00))
+#define word_7FFE02 (*(uint16*)(g_ram+0x1FE02))
+#define word_7FFE04 (*(uint16*)(g_ram+0x1FE04))
+#define word_7FFE06 (*(uint16*)(g_ram+0x1FE06))
+static const int16 kTutorialSoldier_X[20] = {
+  4, 0, -6, -6, 2, 0, 0, -7, -7, -7, 0, 0, 0xf, 0xf, 0xf, 6,
+  0xe, -4, 4, 0,
+};
+static const int16 kTutorialSoldier_Y[20] = {
+  0, -10, -4, 12, 12, 0, -9, -11, -3, 5, 0, -9, -11, -3, 5, -11,
+  5, 0, 0, -9,
+};
+static const uint8 kTutorialSoldier_Char[20] = {
+  0x46, 0x40, 0, 0x28, 0x29, 0x4e, 0x42, 0x39, 0x2a, 0x3a, 0x4e, 0x42, 0x39, 0x2a, 0x3a, 0x26,
+  0x38, 0x64, 0x64, 0x44,
+};
+static const uint8 kTutorialSoldier_Flags[20] = {
+  0x40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x40, 0x40, 0x40, 0x40, 0x40, 0,
+  0x40, 0, 0x40, 0,
+};
+static const uint8 kTutorialSoldier_Big[20] = {
+  2, 2, 2, 0, 0, 2, 2, 0, 0, 0, 2, 2, 0, 0, 0, 2,
+  0, 2, 2, 2,
+};
+static const uint8 kSprite_TutorialEntities_Tab[4] = {2, 1, 0, 3};
+static const uint8 kSoldier_DirectionLockSettings[4] = {3, 2, 0, 1};
+static const uint8 kWishPond_X[8] = {0, 4, 8, 12, 16, 20, 24, 0};
+static const uint8 kWishPond_Y[8] = {0, 8, 16, 24, 32, 40, 4, 36};
+const uint8 kWishPond2_OamFlags[76] = {
+  5, 0xff, 5, 5, 5, 5, 5, 1, 2, 1, 1, 1, 2, 2, 2, 4,
+  4,    4, 1, 1, 2, 1, 1, 1, 2, 1, 2, 1, 4, 4, 2, 1,
+  6,    1, 2, 1, 2, 2, 1, 2, 2, 4, 1, 1, 4, 2, 1, 4,
+  2,    2, 4, 4, 4, 2, 1, 4, 1, 2, 2, 1, 2, 2, 1, 1,
+  4,    4, 1, 2, 2, 4, 4, 4, 2, 5, 2, 1,
+};
+static const uint8 kWishPondItemOffs[32] = {
+  0, 4, 6, 7, 8, 10, 11, 12, 13, 14, 15, 16, 17, 20, 21, 22, 22, 23, 24, 25, 28, 30, 31, 32, 33, 33, 37, 40, 42, 42, 42, 42
+};
+static const uint8 kWishPondItemData[50] = {
+  0x3a, 0x3a, 0x3b, 0x3b, 0x0c, 0x2a, 0x0a, 0x27, 0x29, 0x0d, 0x07, 0x08, 0x0f, 0x10, 0x11, 0x12,
+  0x09, 0x13, 0x14, 0x4a, 0x21, 0x1d, 0x15, 0x18, 0x19, 0x31, 0x1a, 0x1a, 0x1b, 0x1c, 0x4b, 0x1e,
+  0x1f, 0x49, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x22, 0x23, 0x29, 0x16, 0x2b, 0x2c, 0x2d, 0x3d, 0x3c, 0x48
+};
+static const uint8 kUncle_LeaveHouse_Delay[2] = {64, 224};
+static const uint8 kUncle_LeaveHouse_Dir[2] = {2, 1};
+static const int8 kUncle_LeaveHouse_Xvel[4] = {0, 0, -12, 12};
+static const int8 kUncle_LeaveHouse_Yvel[4] = {-12, 12, 0, 0};
+static const DrawMultipleData kPriest_Dmd[20] = {
+  { 0, -8, 0x0e20, 2},
+  { 0,  0, 0x0e26, 2},
+  { 0, -8, 0x0e20, 2},
+  { 0,  0, 0x4e26, 2},
+  { 0, -8, 0x0e0e, 2},
+  { 0,  0, 0x0e24, 2},
+  { 0, -8, 0x0e0e, 2},
+  { 0,  0, 0x0e24, 2},
+  { 0, -8, 0x0e22, 2},
+  { 0,  0, 0x0e28, 2},
+  { 0, -8, 0x0e22, 2},
+  { 0,  0, 0x0e2a, 2},
+  { 0, -8, 0x4e22, 2},
+  { 0,  0, 0x4e28, 2},
+  { 0, -8, 0x4e22, 2},
+  { 0,  0, 0x4e2a, 2},
+  {-7,  1, 0x0e0a, 2},
+  { 3,  3, 0x0e0c, 2},
+  {-7,  1, 0x0e0a, 2},
+  { 3,  3, 0x0e0c, 2},
+};
+static const DrawMultipleData kSageMantle_Dmd[4] = {
+  {0, 0, 0x162c, 2},
+  {16, 0, 0x562c, 2},
+  {0, 16, 0x062e, 2},
+  {16, 16, 0x462e, 2},
+};
+static const uint8 kCrystalMaiden_Dma[16] = {0x20, 0xc0, 0x20, 0xc0, 0, 0xa0, 0, 0xa0, 0x40, 0x80, 0x40, 0x60, 0x40, 0x80, 0x40, 0x60};
+static const DrawMultipleData kCrystalMaiden_SpriteData[16] = {
+  {1, -7, 0x0120, 2},
+  {1,  3, 0x0122, 2},
+  {1, -7, 0x0120, 2},
+  {1,  3, 0x4122, 2},
+  {1, -7, 0x0120, 2},
+  {1,  3, 0x0122, 2},
+  {1, -7, 0x0120, 2},
+  {1,  3, 0x4122, 2},
+  {1, -7, 0x0120, 2},
+  {1,  3, 0x0122, 2},
+  {1, -7, 0x0120, 2},
+  {1,  3, 0x0122, 2},
+  {1, -7, 0x4120, 2},
+  {1,  3, 0x4122, 2},
+  {1, -7, 0x4120, 2},
+  {1,  3, 0x4122, 2},
+};
+static const int8 kZelda_Xvel[4] = {0, 0, -9, 9};
+static const int8 kZelda_Yvel[4] = {-9, 9, 0, 0};
+static const int8 kHeartRefill_AccelX[2] = {1, -1};
+static const int8 kHeartRefill_VelTarget[2] = {10, -10};
+static const DrawMultipleData kFakeSword_Dmd[2] = {
+  {4, 0, 0x00f4, 0},
+  {4, 8, 0x00f5, 0},
+};
+static const uint8 kThrowableScenery_Char[12] = {0x42, 0x44, 0x46, 0, 0x46, 0x44, 0x42, 0x44, 0x44, 0, 0x46, 0x44};
+const uint8 kThrowableScenery_Flags[9] = { 0xc, 0xc, 0xc, 0, 0, 0, 0xb0, 0x08, 0xb4 };
+static const int16 kThrowableScenery_DrawLarge_X[4] = {-8, 8, -8, 8};
+static const int16 kThrowableScenery_DrawLarge_Y[4] = {-14, -14, 2, 2};
+static const uint8 kThrowableScenery_DrawLarge_Flags[4] = {0, 0x40, 0x80, 0xc0};
+static const int16 kThrowableScenery_DrawLarge_X2[3] = {-6, 0, 6};
+static const uint8 kThrowableScenery_DrawLarge_OamFlags[2] = {0xc, 0};
+static const int8 kScatterDebris_X[4] = {-8, 8, -8, 8};
+static const int8 kScatterDebris_Y[4] = {-8, -8, 8, 8};
+static const uint8 kMovableMantle_X[6] = {0, 0x10, 0x20, 0, 0x10, 0x20};
+static const uint8 kMovableMantle_Y[6] = {0, 0, 0, 0x10, 0x10, 0x10};
+static const uint8 kMovableMantle_Char[6] = {0xc, 0xe, 0xc, 0x2c, 0x2e, 0x2c};
+static const uint8 kMovableMantle_Flags[6] = {0x31, 0x31, 0x71, 0x31, 0x31, 0x71};
+static const uint8 kSprite_SimplifiedTileAttr[256] = {
+  0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0,
+  1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 3, 3, 3,
+  0, 0, 0, 0, 0, 0, 1, 1, 4, 4, 4, 4, 4, 4, 4, 4,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+};
+static const uint8 kSoldier_Gfx[4] = {8, 0, 12, 5};
+static const uint8 kSoldier_Delay[4] = {0x60, 0xc0, 0xff, 0x40};
+static const uint8 kSoldier_Draw1_Char[4] = {0x42, 0x42, 0x40, 0x44};
+static const uint8 kSoldier_Draw1_Flags[4] = {0x40, 0, 0, 0};
+static const int8 kSoldier_Draw1_Yd[26] = {
+  7, 8, 7, 8, 8, 7, 8, 7, 8, 7, 8, 8, 7, 8, 8, 8,
+  8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+};
+static const int8 kSoldier_Draw2_Xd[104] = {
+  -4, 4, 10, 10, -4, 4, 10, 10, -4, 4, 10, 10, -4, 4, 10, 10,
+  -4, -4, 0, 0, -4, -4, 0, 0, -3, -3, 0, 0, -3, -3, -4, 4,
+  -3, -3, -4, 4, -3, -3, -4, 4, -3, -3, -4, 4, 12, 12, 0, 0,
+  12, 12, 0, 0, 11, 11, 0, 0, -4, 4, 0, 0, -4, 4, 0, 0,
+  -4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  -4, 4, 0, 0, -4, 4, 0, 0, -4, 4, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const int8 kSoldier_Draw2_Yd[104] = {
+  0, 0, 2, 10, 0, 0, 2, 10, 0, 0, 1, 9, 0, 0, 2, 10,
+  -2, 6, 1, 1, -2, 6, 2, 2, -2, 6, 1, 1, -5, 3, 0, 0,
+  -4, 4, 0, 0, -4, 4, 0, 0, -5, 3, 0, 0, -2, 6, 1, 1,
+  -2, 6, 2, 2, -2, 6, 1, 1, 0, 0, 8, 8, 0, 0, 8, 8,
+  0, 0, 8, 8, 0, 0, 8, 8, 0, 0, 8, 8, 0, 0, 8, 8,
+  0, 0, 8, 8, 0, 0, 8, 8, 0, 0, 8, 8, 0, 0, 8, 8,
+  0, 0, 8, 8, 0, 0, 8, 8,
+};
+static const uint8 kSoldier_Draw2_Char[104] = {
+  0x48, 0x49, 0x6d, 0x7d, 0x49, 0x48, 0x6d, 0x7d, 0x46, 0x46, 0x6d, 0x7d, 0x4b, 0x46, 0x6d, 0x7d,
+  0x4d, 0x5d, 0x4e, 0x4e, 0x4d, 0x5d, 0x60, 0x60, 0x4d, 0x5d, 0x62, 0x62, 0x6d, 0x7d, 0x64, 0x64,
+  0x6d, 0x7d, 0x66, 0x67, 0x6d, 0x7d, 0x67, 0x66, 0x6d, 0x7d, 0x64, 0x69, 0x4d, 0x5d, 0x4e, 0x4e,
+  0x4d, 0x5d, 0x60, 0x60, 0x4d, 0x5d, 0x62, 0x62, 2, 3, 0x20, 0x20, 2, 0xc, 0x20, 0x20,
+  2, 0xc, 0x20, 0x20, 8, 8, 0x20, 0x20, 0xe, 0xe, 0x20, 0x20, 0xe, 0xe, 0x20, 0x20,
+  5, 6, 0x20, 0x20, 0x22, 6, 0x20, 0x20, 0x22, 6, 0x20, 0x20, 8, 8, 0x20, 0x20,
+  0xe, 0xe, 0x20, 0x20, 0xe, 0xe, 0x20, 0x20,
+};
+static const uint8 kSoldier_Draw2_Flags[104] = {
+  0, 0, 0, 0, 0x40, 0x40, 0, 0, 0, 0x40, 0, 0, 0, 0x40, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x40,
+  0, 0, 0, 0, 0, 0, 0x40, 0x40, 0, 0, 0, 0x40, 0x40, 0x40, 0x40, 0x40,
+  0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x40, 0x40, 0x40, 0x40,
+  0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
+};
+static const uint8 kSoldier_Draw2_Big[104] = {
+  2, 2, 0, 0, 2, 2, 0, 0, 2, 2, 0, 0, 2, 2, 0, 0,
+  0, 0, 2, 2, 0, 0, 2, 2, 0, 0, 2, 2, 0, 0, 2, 2,
+  0, 0, 2, 2, 0, 0, 2, 2, 0, 0, 2, 2, 0, 0, 2, 2,
+  0, 0, 2, 2, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+  2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+  2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+  2, 2, 2, 2, 2, 2, 2, 2,
+};
+static const uint8 kSoldier_Draw2_OamIdx[4] = {12, 12, 12, 4};
+static const int8 kSoldier_Draw3_Xd[28] = {
+  -3, -3, -4, -4, -4, -4, -4, -4, -11, -3, -11, -3, -16, -8, 12, 12,
+  12, 12, 12, 12, 12, 12, 21, 13, 21, 13, 24, 16,
+};
+static const int8 kSoldier_Draw3_Yd[28] = {
+  11, 19, 11, 19, 10, 18, 14, 22, 8, 8, 8, 8, 6, 6, -10, -2,
+  -9, -1, -9, -1, -16, -8, 8, 8, 8, 8, 6, 6,
+};
+static const uint8 kSoldier_Draw3_Char[28] = {
+  0x7b, 0x6b, 0x7b, 0x6b, 0x7b, 0x6b, 0x7b, 0x6b, 0x6c, 0x7c, 0x6c, 0x7c, 0x6c, 0x7c, 0x6b, 0x7b,
+  0x6b, 0x7b, 0x6b, 0x7b, 0x6b, 0x7b, 0x6c, 0x7c, 0x6c, 0x7c, 0x6c, 0x7c,
+};
+static const uint8 kSoldier_Draw3_Flags[28] = {
+  0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
+};
+static const uint8 kSoldier_Draw3_OamIdx[4] = {4, 4, 4, 20};
+static const int8 kSoldier_Xvel[4] = {8, -8, 0, 0};
+static const int8 kSoldier_Yvel[4] = {0, 0, 8, -8};
+static const uint8 kSoldier_Gfx2[32] = {
+  11, 12, 13, 12, 4, 5, 6, 5, 0, 1, 2, 3, 7, 8, 9, 10,
+  17, 18, 17, 18, 7, 8, 7, 8, 3, 4, 3, 4, 13, 14, 13, 14,
+};
+static const int8 kSoldierB_Xvel[8] = {1, 1, -1, -1, -1, -1, 1, 1};
+static const int8 kSoldierB_Yvel[8] = {-1, 1, 1, -1, -1, 1, 1, -1};
+static const int8 kSoldierB_Xvel2[8] = {8, 0, -8, 0, -8, 0, 8, 0};
+static const int8 kSoldierB_Yvel2[8] = {0, 8, 0, -8, 0, 8, 0, -8};
+static const uint8 kSoldierB_Dir[8] = {0, 2, 1, 3, 1, 2, 0, 3};
+static const uint8 kSoldierB_Mask2[8] = {1, 4, 2, 8, 2, 4, 1, 8};
+static const uint8 kSoldierB_Mask[8] = {8, 1, 4, 2, 8, 2, 4, 1};
+static const uint8 kSoldierB_NextB2[8] = {1, 2, 3, 0, 5, 6, 7, 4};
+static const uint8 kSoldierB_NextB[8] = {3, 0, 1, 2, 7, 4, 5, 6};
+static const uint8 kSoldier_HeadDirs[32] = {
+  0, 2, 2, 2, 0, 3, 3, 3, 1, 3, 3, 3, 1, 2, 2, 2,
+  2, 0, 0, 0, 2, 1, 1, 1, 3, 1, 1, 1, 3, 0, 0, 0,
+};
+static const uint8 kSoldier_Tab1[4] = {13, 13, 12, 12};
+static const uint8 kSoldier_DrawShadow[4] = {0xc, 0xc, 0xa, 0xa};
+static const int8 kSoldier_SetTowardsVel[6] = {14, -14, 0, 0, 14, -14};
+static const uint8 kSprite_SpawnProbeStaggered_Tab[4] = {0x10, 0x30, 0, 0x20};
+static const int8 kSpawnProbe_Xvel[64] = {
+  -16, -16, -16, -16, -16, -16, -16, -16, -16, -14, -12, -10, -8, -6, -4, -2,
+  0, 2, 4, 6, 8, 10, 12, 14, 16, 16, 16, 16, 16, 16, 16, 16,
+  16, 16, 16, 16, 16, 16, 16, 16, 14, 12, 10, 8, 6, 4, 2, 0,
+  -2, -4, -6, -8, -10, -12, -14, -16, -16, -16, -16, -16, -16, -16, -16, -16,
+};
+static const int8 kSpawnProbe_Yvel[64] = {
+  0, 2, 4, 6, 8, 10, 12, 14, 16, 16, 16, 16, 16, 16, 16, 16,
+  16, 16, 16, 16, 16, 16, 16, 16, 14, 12, 10, 8, 6, 4, 2, 0,
+  -2, -4, -6, -8, -10, -12, -14, -16, -16, -16, -16, -16, -16, -16, -16, -16,
+  -16, -16, -16, -16, -16, -16, -16, -16, -14, -12, -10, -8, -6, -4, -2, 0,
+};
+int ctr;
+bool foo = false;
+static const uint8 kChainBallTrooper_Tab1[4] = {0x0d, 0x60, 0x22, 0x10};  // wtf
+static const uint8 kFlailTrooperGfx[32] = {
+  0x10, 0x11, 0x12, 0x13, 0x10, 0x11, 0x12, 0x13, 6, 7, 8, 9, 6, 7, 8, 9,
+  0, 1, 2, 3, 0, 1, 4, 5, 0xa, 0xb, 0xc, 0xd, 0xa, 0xb, 0xe, 0xf,
+};
+static const uint8 kJavelinTrooper_Tab2[64] = {
+  25, 25, 24, 24, 23, 23, 23, 23, 19, 19, 18, 18, 17, 17, 17, 17,
+  16, 16, 15, 15, 14, 14, 14, 14, 22, 22, 21, 21, 20, 20, 20, 20,
+  20, 20, 18, 18, 18, 16, 16, 16, 21, 21,  8,  8,  8,  6,  6,  6,
+  22, 22,  4,  4,  4,  3,  3,  3, 23, 23, 15, 15, 15, 11, 11, 11,
+};
+static const int8 kSprite_Recruit_Xvel[8] = {12, -12, 0, 0, 18, -18, 0, 0};
+static const int8 kSprite_Recruit_Yvel[8] = {0, 0, 0xc, -0xc, 0, 0, 0x12, -0x12};
+static const int8 kSprite_Recruit_Gfx[8] = {0, 2, 4, 6, 1, 3, 5, 7};
+static const uint8 kRecruit_Moving_HeadDir[8] = {2, 3, 2, 3, 0, 1, 0, 1};
+static const int16 kRecruit_Draw_X[8] = {2, 2, -2, -2, 0, 0, 0, 0};
+static const uint8 kRecruit_Draw_Char[8] = {0x8a, 0x8c, 0x8a, 0x8c, 0x86, 0x88, 0x8e, 0xa0};
+static const uint8 kRecruit_Draw_Flags[8] = {0x40, 0x40, 0, 0, 0, 0, 0, 0};
+static const uint8 kSprite_Zora_SurfacingGfx[16] = {4, 3, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 0, 0};
+static const uint8 kChainBallTrooperHead_Char[4] = {2, 2, 0, 4};
+static const uint8 kChainBallTrooperHead_Flags[4] = {0x40, 0, 0, 0};
+static const int8 kFlailTrooperBody_X[72] = {
+  -4, 4, 12, -4, 4, 13, -4, 4, 13, -4, 4, 13, -4, 4, 13, -4,
+  4, 13, 0, 0, 4, 0, 0, 5, 0, 0, 6, 0, 0, 4, -4, 4,
+  -6, -4, 4, -5, -4, 4, -5, -4, 4, -6, -4, 4, -5, -4, 4, -6,
+  0, 0, 4, 0, 0, 3, 0, 0, 2, 0, 0, 4, 0, 0, 0, 0,
+  0, 0, -4, 4, 4, -4, 4, 4,
+};
+static const int8 kFlailTrooperBody_Y[72] = {
+  0, 0, -4, 0, 0, -4, 0, 0, -3, 0, 0, -2, 0, 0, -3, 0,
+  0, -2, 0, 0, 1, 0, 0, 1, 0, 0, 2, 0, 0, 2, 0, 0,
+  -2, 0, 0, -2, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1,
+  0, 0, 1, 0, 0, 1, 0, 0, 2, 0, 0, 2, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const uint8 kFlailTrooperBody_Char[72] = {
+  0x46, 6, 0x2f, 0x46, 6, 0x2f, 0x48, 0xd, 0x2f, 0x48, 0xd, 0x2f, 0x49, 0xc, 0x2f, 0x49,
+  0xc, 0x2f, 8, 8, 0x2f, 8, 8, 0x2f, 0x22, 0x22, 0x2f, 0x22, 0x22, 0x2f, 0xa, 0x64,
+  0x2f, 0xa, 0x64, 0x2f, 0x2c, 0x67, 0x2f, 0x2c, 0x67, 0x2f, 0x2d, 0x66, 0x2f, 0x2d, 0x66, 0x2f,
+  8, 8, 0x2f, 8, 8, 0x2f, 0x22, 0x22, 0x2f, 0x22, 0x22, 0x2f, 0x62, 0x62, 0x62, 0x62,
+  0x62, 0x62, 0x46, 0x4b, 0x4b, 0x69, 0x64, 0x64,
+};
+static const uint8 kFlailTrooperBody_Flags[72] = {
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x40, 0x40, 0, 0x40,
+  0x40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x40,
+  0x40, 0, 0x40, 0x40, 0, 0, 0x40, 0, 0, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
+  0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0,
+  0, 0, 0, 0x40, 0x40, 0, 0x40, 0x40,
+};
+static const uint8 kFlailTrooperBody_Big[72] = {
+  2, 2, 0, 2, 2, 0, 2, 2, 0, 2, 2, 0, 2, 2, 0, 2,
+  2, 0, 2, 2, 0, 2, 2, 0, 2, 2, 0, 2, 2, 0, 2, 2,
+  0, 2, 2, 0, 2, 2, 0, 2, 2, 0, 2, 2, 0, 2, 2, 0,
+  2, 2, 0, 2, 2, 0, 2, 2, 0, 2, 2, 0, 2, 2, 2, 2,
+  2, 2, 2, 2, 2, 2, 2, 2,
+};
+static const uint8 kFlailTrooperBody_Num[24] = {
+  2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+  2, 2, 2, 2, 1, 1, 1, 1,
+};
+static const uint8 kFlailTrooperBody_SprOffs[24] = {
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 8, 8, 8, 8,
+};
+const uint16 kSinusLookupTable[256] = {
+  0, 3, 6, 9, 12, 15, 18, 21, 25, 28, 31, 34, 37, 40, 40, 46,
+  49, 53, 56, 59, 62, 65, 68, 71, 74, 77, 80, 83, 86, 89, 92, 95,
+  97, 100, 103, 106, 109, 112, 115, 117, 120, 123, 126, 128, 131, 134, 136, 139,
+  142, 144, 147, 149, 152, 155, 157, 159, 162, 164, 167, 169, 171, 174, 176, 178,
+  181, 183, 185, 187, 189, 191, 193, 195, 197, 199, 201, 203, 205, 207, 209, 211,
+  212, 214, 216, 217, 219, 221, 222, 224, 225, 227, 228, 230, 231, 232, 234, 235,
+  236, 237, 238, 239, 241, 242, 243, 244, 244, 245, 246, 247, 248, 249, 249, 250,
+  251, 251, 252, 252, 253, 253, 254, 254, 254, 255, 255, 255, 255, 255, 255, 255,
+  256, 255, 255, 255, 255, 255, 255, 255, 254, 254, 254, 253, 253, 252, 252, 251,
+  251, 250, 249, 249, 248, 247, 246, 245, 244, 244, 243, 242, 241, 239, 238, 237,
+  236, 235, 234, 232, 231, 230, 228, 227, 225, 224, 222, 221, 219, 217, 216, 214,
+  212, 211, 209, 207, 205, 203, 201, 199, 197, 195, 193, 191, 189, 187, 185, 183,
+  181, 178, 176, 174, 171, 169, 167, 164, 162, 159, 157, 155, 152, 149, 147, 144,
+  142, 139, 136, 134, 131, 128, 126, 123, 120, 117, 115, 112, 109, 106, 103, 100,
+  97, 95, 92, 89, 86, 83, 80, 77, 74, 71, 68, 65, 62, 59, 56, 53,
+  49, 46, 43, 40, 37, 34, 31, 28, 25, 21, 18, 15, 12, 9, 6, 3,
+};
+static const uint8 kFlailTrooperWeapon_Tab4[4] = {0x33, 0x66, 0x99, 0xcc};
+static const uint8 kFlailTrooperWeapon_Tab0[32] = {
+  0x10, 0x12, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e, 0x20, 0x22, 0x24, 0x26, 0x28, 0x2a, 0x2c, 0x2e,
+  0x30, 0x2e, 0x2c, 0x2a, 0x28, 0x26, 0x24, 0x22, 0x20, 0x1e, 0x1c, 0x1a, 0x18, 0x16, 0x14, 0x12,
+};
+static const int8 kFlailTrooperWeapon_Tab1[4] = {4, 4, 12, -5};
+static const int8 kFlailTrooperWeapon_Tab2[4] = {-2, -2, -6, -4};
+static const uint8 kFlailTrooperAttackDir[4] = {3, 1, 2, 0};
+static const uint8 kSprite_WarpVortex_Flags[4] = {0, 0x40, 0xc0, 0x80};
+static const int8 kSpriteRope_Gfx[8] = {0, 0, 2, 3, 2, 3, 1, 1};
+static const int8 kSpriteRope_Flags[8] = {0, 0x40, 0, 0, 0x40, 0x40, 0, 0x40};
+static const int8 kSpriteRope_Tab1[8] = {4, 5, 2, 3, 0, 1, 6, 7};
+static const int8 kSpriteRope_Xvel[8] = {8, -8, 0, 0, 16, -16, 0, 0};
+static const int8 kSpriteRope_Yvel[8] = {0, 0, 8, -8, 0, 0, 0x10, -0x10};
+static const int8 kSpriteRope_Tab0[4] = {2, 3, 1, 0};
+static const uint8 kSpawnBee_InitDelay[4] = {64, 64, 255, 255};
+static const int8 kSpawnBee_InitVel[8] = {15, 5, -5, -15, 20, 10, -10, -20};
+static const DrawMultipleData kLargeShadow_Dmd[15] = {
+  {-6, 19, 0x086c, 2},
+  { 0, 19, 0x086c, 2},
+  { 6, 19, 0x086c, 2},
+  {-5, 19, 0x086c, 2},
+  { 0, 19, 0x086c, 2},
+  { 5, 19, 0x086c, 2},
+  {-4, 19, 0x086c, 2},
+  { 0, 19, 0x086c, 2},
+  { 4, 19, 0x086c, 2},
+  {-3, 19, 0x086c, 2},
+  { 0, 19, 0x086c, 2},
+  { 3, 19, 0x086c, 2},
+  {-2, 19, 0x086c, 2},
+  { 0, 19, 0x086c, 2},
+  { 2, 19, 0x086c, 2},
+};
+static const uint8 kHelmasaur_Tab0[32] = {
+  0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 8, 8, 8, 8, 8, 8,
+  8, 8, 8, 8, 8, 8, 8, 8, 8, 7, 6, 5, 4, 3, 2, 1,
+};
+static const uint8 kFluteBoyAnimal_OamFlags[2] = {0x40, 0};
+static const uint8 kFluteBoyAnimal_Gfx[3] = {0, 1, 2};
+static const uint8 kGibo_OamFlags[4] = {0, 0x40, 0xc0, 0x80};
+static const uint8 kGibo_OamFlags2[2] = {11, 7};
+#define chainchomp_x_hist ((uint16*)(g_ram+0x1FC00))
+#define chainchomp_y_hist ((uint16*)(g_ram+0x1FD00))
+static const uint8 kBlindHead_Draw_Char[16] = {0x86, 0x86, 0x84, 0x82, 0x80, 0x82, 0x84, 0x86, 0x86, 0x86, 0x88, 0x8a, 0x8c, 0x8a, 0x88, 0x86};
+static const uint8 kBlindHead_Draw_Flags[16] = {0, 0, 0, 0, 0, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0, 0, 0, 0};
+static const uint8 kGanon_G_Func2[16] = { 8, 7, 6, 5, 4, 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, 1 };
+static const int8 kGanon_Draw_X[204] = {
+   18,  -8,   8, -8,   8, -18, -18, 18,  -8,   8,  -8,   8,  18,  -8,   8, -8,
+    8, -18, -18, 18,  -8,   8,  -8,  8,  16,  -8,   8,  -8,   8, -18, -18, 16,
+   -8,   8, -11, 11,  16,  -8,   8, -8,   8, -18, -18,  16,  -8,   8, -11, 11,
+   16,  -8,   8, -8,   8, -18, -18, 16,  -8,   8, -11,  11,  18,  -8,   8, -8,
+    8, -18, -18, 18,  -8,   8,  -8,  8,  18,  -8,   8,  -8,   8, -18, -18, 18,
+   -8,   8,  -8,  8,  18,  -8,   8, -8,   8, -18, -18,  18,  -8,   8, -11, 11,
+   -8,   8,  -8,  8,  -8,   8,  -8,  8, -18, -18,  18,  18,  -8,   8,  -8,  8,
+   -8,   8,  -8,  8, -18, -18,  18, 18,  -8,   8,  -8,   8,  -8,   8, -10, 10,
+  -18, -18,  18, 18,  -8,   8,  -8,  8,  -8,   8, -10,  10, -18, -18,  18, 18,
+   -8,   8,  -8,  8,  -8,   8, -10, 10, -18, -18,  18,  18,  -8,   8,  -8,  8,
+   -8,   8,  -8,  8, -18, -18,  18, 18,  -8,   8,  -8,   8,  -8,   8,  -8,  8,
+  -18, -18,  18, 18,  -7,  -8,   8, -8,   8,  -9,   8, -14, -14,  -8,   8,  8,
+   -8,   8,  -8,  8, -18, -18,  18, 18,  -8,   8, -11,  11,
+};
+static const int8 kGanon_Draw_Y[204] = {
+   -8, -16, -16, -13, -13,  -9,  -1, -16,   3,   3,   8,   8,  -8, -16, -16, -13,
+  -13,  -9,  -1, -16,   3,   3,   8,   8,   5, -10, -10, -13, -13,  -7,   1,  -3,
+    3,   3,   8,   8,   5, -10, -10, -13, -13,  -7,   1,  -3,   3,   3,   8,   8,
+    5, -10, -10, -13, -13,  -7,   1,  -3,   3,   3,   8,   8,  -1, -16, -16, -13,
+  -13,  -9,  -1,  -9,   3,   3,   8,   8, -10, -16, -16, -13, -13, -18, -10, -18,
+    3,   3,   8,   8,   1, -10, -10, -13, -13,  -7,   1,  -7,   3,   3,   8,   8,
+  -12, -12,   4,   4, -18, -18,  10,  10, -16,  -8,  -4,   4, -12, -12,   4,   4,
+  -18, -18,  10,  10, -16,  -8,  -4,   4, -12, -12,   4,   4, -12, -12,  10,  10,
+   -4,   4,  -4,   4, -12, -12,   4,   4, -12, -12,  10,  10,  -4,   4,  -4,   4,
+  -12, -12,   4,   4, -12, -12,  10,  10,  -4,   4,  -4,   4, -12, -12,   4,   4,
+  -18, -18,  10,  10,  -4,   4,  -4,   4, -12, -12,   4,   4, -18, -18,  10,  10,
+  -16,  -8, -16,  -8,  -7, -12, -12,   4,   4,   7,  13, -11,  -4, -16, -16, -16,
+  -10, -10, -13, -13,  -7,  -7,  -7,  -7,   3,   3,   8,   8,
+};
+static const uint8 kGanon_Draw_Char[204] = {
+  0x16,    0,    0,    2,    2,    8, 0x18,    6, 0x22, 0x22, 0x20, 0x20, 0x46,    0,    0,    2,
+     2,    8, 0x18, 0x36, 0x22, 0x22, 0x20, 0x20, 0x1a,    0,    0,    4,    4, 0x38, 0x48,  0xa,
+  0x24, 0x24, 0x20, 0x20, 0x1a, 0x40, 0x42,    4,    4, 0x38, 0x48,  0xa, 0x24, 0x24, 0x20, 0x20,
+  0x1a, 0x42, 0x40,    4,    4, 0x38, 0x48,  0xa, 0x24, 0x24, 0x20, 0x20, 0x18,    0,    0,    2,
+     2,    8, 0x18,    8, 0x22, 0x22, 0x20, 0x20, 0x16, 0x6a, 0x6a,  0xe,  0xe,    6, 0x16,    6,
+  0x22, 0x22, 0x20, 0x20, 0x48,    0,    0,    4,    4, 0x38, 0x48, 0x38, 0x24, 0x24, 0x20, 0x20,
+  0x4e, 0x4e, 0x6e, 0x6e, 0x6c, 0x6c, 0xa2, 0xa2,  0xc, 0x1c, 0x3c, 0x4c, 0x4e, 0x4e, 0x6e, 0x6e,
+  0x6c, 0x6c, 0xa2, 0xa2, 0x3a, 0x4a, 0x3c, 0x4c, 0x84, 0x84, 0xa4, 0xa4, 0xa0, 0xa0, 0xa2, 0xa2,
+  0x3c, 0x4c, 0x3c, 0x4c, 0x84, 0x84, 0xa4, 0xa4, 0x80, 0x82, 0xa2, 0xa2, 0x3c, 0x4c, 0x3c, 0x4c,
+  0x84, 0x84, 0xa4, 0xa4, 0x82, 0x80, 0xa2, 0xa2, 0x3c, 0x4c, 0x3c, 0x4c, 0x4e, 0x4e, 0x6e, 0x6e,
+  0x6c, 0x6c, 0xa2, 0xa2, 0x3c, 0x4c, 0x3c, 0x4c, 0x4e, 0x4e, 0x6e, 0x6e, 0x6c, 0x6c, 0xa2, 0xa2,
+   0xc, 0x1c,  0xc, 0x1c, 0xe0, 0xc6, 0xc8, 0xe6, 0xe8, 0x20, 0x20,    8, 0x18, 0xc0, 0xc2, 0xc2,
+     0,    0, 0xce, 0xce, 0xec, 0xec, 0xec, 0xec, 0xee, 0xee, 0xc4, 0xc4,
+};
+static const uint8 kGanon_Draw_Flags[204] = {
+  0x4c,  0xc, 0x4c,  0xa, 0x4a,  0xc,  0xc, 0x4c,  0xa, 0x4a,  0xc, 0x4c, 0x4c,  0xc, 0x4c,  0xa,
+  0x4a,  0xc,  0xc, 0x4c,  0xa, 0x4a,  0xc, 0x4c, 0x4c,  0xc, 0x4c,  0xa, 0x4a,  0xc,  0xc, 0x4c,
+   0xa, 0x4a,  0xc, 0x4c, 0x4c,  0xc,  0xc,  0xa, 0x4a,  0xc,  0xc, 0x4c,  0xa, 0x4a,  0xc, 0x4c,
+  0x4c, 0x4c, 0x4c,  0xa, 0x4a,  0xc,  0xc, 0x4c,  0xa, 0x4a,  0xc, 0x4c, 0x4c,  0xc, 0x4c,  0xa,
+  0x4a,  0xc,  0xc, 0x4c,  0xa, 0x4a,  0xc, 0x4c, 0x4c,  0xc, 0x4c,  0xa, 0x4a,  0xc,  0xc, 0x4c,
+   0xa, 0x4a,  0xc, 0x4c, 0x4c,  0xc, 0x4c,  0xa, 0x4a,  0xc,  0xc, 0x4c,  0xa, 0x4a,  0xc, 0x4c,
+   0xa, 0x4a,  0xa, 0x4a,  0xc, 0x4c,  0xc, 0x4c,  0xc,  0xc, 0x4c, 0x4c,  0xa, 0x4a,  0xa, 0x4a,
+   0xc, 0x4c,  0xc, 0x4c,  0xc,  0xc, 0x4c, 0x4c,  0xa, 0x4a,  0xa, 0x4a,  0xc, 0x4c,  0xc, 0x4c,
+   0xc,  0xc, 0x4c, 0x4c,  0xa, 0x4a,  0xa, 0x4a,  0xc,  0xc,  0xc, 0x4c,  0xc,  0xc, 0x4c, 0x4c,
+   0xa, 0x4a,  0xa, 0x4a, 0x4c, 0x4c,  0xc, 0x4c,  0xc,  0xc, 0x4c, 0x4c,  0xa, 0x4a,  0xa, 0x4a,
+   0xc, 0x4c,  0xc, 0x4c,  0xc,  0xc, 0x4c, 0x4c,  0xa, 0x4a,  0xa, 0x4a,  0xc, 0x4c,  0xc, 0x4c,
+   0xc,  0xc, 0x4c, 0x4c,  0xc,  0xa,  0xa,  0xa,  0xa,  0xc, 0x4c,  0xc,  0xc,  0xc,  0xc,  0xc,
+   0xc, 0x4c,  0xa, 0x4a,  0xc,  0xc, 0x4c, 0x4c,  0xa, 0x4a,  0xc, 0x4c,
+};
+static const uint8 kGanon_Draw_Char2[12] = { 0x40, 0x42, 0, 0, 0x42, 0x40, 0x82, 0x80, 0xa0, 0xa0, 0x80, 0x82 };
+static const uint8 kGanon_Draw_Flags2[12] = { 0, 0, 0, 0x40, 0x40, 0x40, 0x40, 0x40, 0, 0x40, 0, 0 };
+static HandlerFuncK *const kSpriteActiveRoutines[243] = {
+  &Sprite_Raven,
+  &Sprite_01_Vulture_bounce,
+  &Sprite_02_StalfosHead,
+  NULL,
+  &Sprite_PullSwitch_bounce,
+  &Sprite_PullSwitch_bounce,
+  &Sprite_PullSwitch_bounce,
+  &Sprite_PullSwitch_bounce,
+  &Sprite_08_Octorok,
+  &Sprite_09_GiantMoldorm,
+  &Sprite_08_Octorok,
+  &Sprite_0B_Cucco,
+  &Sprite_0C_OctorokStone,
+  &Sprite_0D_Buzzblob,
+  &Sprite_0E_Snapdragon,
+  &Sprite_0F_Octoballoon,
+  &Sprite_10_OctoballoonBaby,
+  &Sprite_11_Hinox,
+  &Sprite_12_Moblin,
+  &Sprite_13_MiniHelmasaur,
+  &Sprite_14_ThievesTownGrate,
+  &Sprite_15_Antifairy,
+  &Sprite_16_Elder_bounce,
+  &Sprite_17_Hoarder,
+  &Sprite_18_MiniMoldorm,
+  &Sprite_19_Poe,
+  &Sprite_1A_Smithy,
+  &Sprite_1B_Arrow,
+  &Sprite_1C_Statue,
+  &Sprite_1D_FluteQuest,
+  &Sprite_1E_CrystalSwitch,
+  &Sprite_1F_SickKid,
+  &Sprite_20_Sluggula,
+  &Sprite_21_WaterSwitch,
+  &Sprite_22_Ropa,
+  &Sprite_23_RedBari,
+  &Sprite_23_RedBari,
+  &Sprite_25_TalkingTree,
+  &Sprite_26_HardhatBeetle,
+  &Sprite_27_Deadrock,
+  &Sprite_28_DarkWorldHintNPC,
+  &Sprite_HumanMulti_1,
+  &Sprite_SweepingLady,
+  &Sprite_2B_Hobo,
+  &Sprite_Lumberjacks,
+  &Sprite_2D_TelepathicTile,
+  &Sprite_2E_FluteKid,
+  &Sprite_MazeGameLady,
+  &Sprite_MazeGameGuy,
+  &Sprite_FortuneTeller,
+  &Sprite_QuarrelBros,
+  &Sprite_33_RupeePull,
+  &Sprite_YoungSnitchLady,
+  &Sprite_InnKeeper,
+  &Sprite_Witch,
+  &Sprite_37_Waterfall,
+  &Sprite_38_EyeStatue,
+  &Sprite_39_Locksmith,
+  &Sprite_3A_MagicBat,
+  &Sprite_DashItem,
+  &Sprite_TroughBoy,
+  &Sprite_OldSnitchLady,
+  &Sprite_17_Hoarder,
+  &Sprite_TutorialGuardOrBarrier,
+  &Sprite_TutorialGuardOrBarrier,
+  // Trampoline 48 entries
+  &Sprite_41_BlueGuard,
+  &Sprite_41_BlueGuard,
+  &Sprite_41_BlueGuard,
+  &Sprite_44_BluesainBolt,
+  &Sprite_45_HogSpearMan,
+  &Sprite_46_BlueArcher,
+  &Sprite_47_GreenBushGuard,
+  &Sprite_48_RedJavelinGuard,
+  &Sprite_49_RedBushGuard,
+  &Sprite_4A_BombGuard,
+  &Sprite_4B_GreenKnifeGuard,
+  &Sprite_4C_Geldman,
+  &Sprite_4D_Toppo,
+  &Sprite_4E_Popo,
+  &Sprite_4E_Popo,
+  &Sprite_50_Cannonball,
+  &Sprite_51_ArmosStatue,
+  &Sprite_52_KingZora,
+  &Sprite_53_ArmosKnight,
+  &Sprite_54_Lanmolas,
+  &Sprite_55_Zora,
+  &Sprite_56_WalkingZora,
+  &Sprite_57_DesertStatue,
+  &Sprite_58_Crab,
+  &Sprite_59_LostWoodsBird,
+  &Sprite_5A_LostWoodsSquirrel,
+  &Sprite_5B_Spark_Clockwise,
+  &Sprite_5B_Spark_Clockwise,
+  &Sprite_5D_Roller_VerticalDownFirst,
+  &Sprite_5D_Roller_VerticalDownFirst,
+  &Sprite_5D_Roller_VerticalDownFirst,
+  &Sprite_5D_Roller_VerticalDownFirst,
+  &Sprite_61_Beamos,
+  &Sprite_62_MasterSword,
+  &Sprite_63_DebirandoPit,
+  &Sprite_64_Debirando,
+  &Sprite_65_ArcheryGame,
+  &Sprite_66_WallCannonVerticalLeft,
+  &Sprite_66_WallCannonVerticalLeft,
+  &Sprite_66_WallCannonVerticalLeft,
+  &Sprite_66_WallCannonVerticalLeft,
+  &Sprite_6A_BallNChain,
+  &Sprite_6B_CannonTrooper,
+  &Sprite_6C_MirrorPortal,
+  &Sprite_6D_Rat,
+  &Sprite_6E_Rope,
+  &Sprite_6F_Keese,
+  &Sprite_70_KingHelmasaurFireball,
+  &Sprite_71_Leever,
+  &Sprite_72_FairyPond,
+  &Sprite_73_UncleAndPriest,
+  &Sprite_RunningMan,
+  &Sprite_BottleVendor,
+  &Sprite_76_Zelda,
+  &Sprite_15_Antifairy,
+  &Sprite_78_MrsSahasrahla,
+  // Trampoline 68 entries
+  &Sprite_79_Bee,
+  &Sprite_7A_Agahnim,
+  &Sprite_7B_AgahnimBalls,
+  &Sprite_7C_GreenStalfos,
+  &Sprite_7D_BigSpike,
+  &Sprite_7E_Firebar_Clockwise,
+  &Sprite_7E_Firebar_Clockwise,
+  &Sprite_80_Firesnake,
+  &Sprite_81_Hover,
+  &Sprite_82_AntifairyCircle,
+  &Sprite_83_GreenEyegore,
+  &Sprite_83_GreenEyegore,
+  &Sprite_85_YellowStalfos,
+  &Sprite_86_Kodongo,
+  &Sprite_87_KodongoFire,
+  &Sprite_88_Mothula,
+  &Sprite_89_MothulaBeam,
+  &Sprite_8A_SpikeBlock,
+  &Sprite_8B_Gibdo,
+  &Sprite_8C_Arrghus,
+  &Sprite_8D_Arrghi,
+  &Sprite_8E_Terrorpin,
+  &Sprite_8F_Blob,
+  &Sprite_90_Wallmaster,
+  &Sprite_91_StalfosKnight,
+  &Sprite_92_HelmasaurKing,
+  &Sprite_93_Bumper,
+  &Sprite_94_Pirogusu,
+  &Sprite_95_LaserEyeLeft,
+  &Sprite_95_LaserEyeLeft,
+  &Sprite_95_LaserEyeLeft,
+  &Sprite_95_LaserEyeLeft,
+  &Sprite_99_Pengator,
+  &Sprite_9A_Kyameron,
+  &Sprite_9B_Wizzrobe,
+  &Sprite_9C_Zoro,
+  &Sprite_9C_Zoro,
+  &Sprite_9E_HauntedGroveOstritch,
+  &Sprite_9F_HauntedGroveRabbit,
+  &Sprite_A0_HauntedGroveBird,
+  &Sprite_A1_Freezor,
+  &Sprite_A2_Kholdstare,
+  &Sprite_A3_KholdstareShell,
+  &Sprite_A4_FallingIce,
+  &Sprite_Zazak_Main,
+  &Sprite_Zazak_Main,
+  &Sprite_A7_Stalfos,
+  &Sprite_A8_GreenZirro,
+  &Sprite_A8_GreenZirro,
+  &Sprite_AA_Pikit,
+  &Sprite_AB_CrystalMaiden,
+  &Sprite_AC_Apple,
+  &Sprite_AD_OldMan,
+  &Sprite_AE_Pipe_Down,
+  &Sprite_AE_Pipe_Down,
+  &Sprite_AE_Pipe_Down,
+  &Sprite_AE_Pipe_Down,
+  &Sprite_B2_PlayerBee,
+  &Sprite_B3_PedestalPlaque,
+  &Sprite_B4_PurpleChest,
+  &Sprite_B5_BombShop,
+  &Sprite_B6_Kiki,
+  &Sprite_B7_BlindMaiden,
+  &Sprite_B8_DialogueTester,
+  &Sprite_B9_BullyAndPinkBall,
+  &Sprite_BA_Whirlpool,
+  &Sprite_BB_Shopkeeper,
+  &Sprite_BC_Drunkard,
+  // Trampoline 4, starts at 187, 27 entries
+  &Sprite_BD_Vitreous,
+  &Sprite_BE_VitreousEye,
+  &Sprite_BF_Lightning,
+  &Sprite_C0_Catfish,
+  &Sprite_C1_CutsceneAgahnim,
+  &Sprite_C2_Boulder,
+  &Sprite_C3_Gibo,
+  &Sprite_C4_Thief,
+  &Sprite_C5_Medusa,
+  &Sprite_C6_4WayShooter,
+  &Sprite_C7_Pokey,
+  &Sprite_C8_BigFairy,
+  &Sprite_C9_Tektite,
+  &Sprite_CA_ChainChomp,
+  &Sprite_CB_TrinexxRockHead,
+  &Sprite_CC,
+  &Sprite_CD,
+  &Sprite_CE_Blind,
+  &Sprite_CF_Swamola,
+  &Sprite_D0_Lynel,
+  &Sprite_D1_BunnyBeam,
+  &Sprite_D2_FloppingFish,
+  &Sprite_D3_Stal,
+  &Sprite_D4_Landmine,
+  &Sprite_D5_DigGameGuy,
+  &Sprite_D6_Ganon,
+  &Sprite_D6_Ganon,
+  &Sprite_D8_Heart,
+  &Sprite_D9_GreenRupee,
+  &Sprite_D9_GreenRupee,
+  &Sprite_D9_GreenRupee,
+  &Sprite_D9_GreenRupee,
+  &Sprite_D9_GreenRupee,
+  &Sprite_D9_GreenRupee,
+  &Sprite_D9_GreenRupee,
+  &Sprite_D9_GreenRupee,
+  &Sprite_D9_GreenRupee,
+  &Sprite_D9_GreenRupee,
+  &Sprite_E3_Fairy,
+  &Sprite_E4_SmallKey,
+  &Sprite_E4_SmallKey,
+  &Sprite_D9_GreenRupee,
+  &Sprite_E7_Mushroom,
+  &Sprite_E8_FakeSword,
+  &Sprite_E9_PotionShop,
+  &Sprite_HeartContainer,
+  &Sprite_HeartPiece,
+  &Sprite_EC_ThrownItem,
+  &Sprite_ED_SomariaPlatform,
+  &Sprite_EE_MovableMantle,
+  &Sprite_ED_SomariaPlatform,
+  &Sprite_ED_SomariaPlatform,
+  &Sprite_ED_SomariaPlatform,
+  &Sprite_F2_MedallionTablet,
+};
+static HandlerFuncK *const kSpritePrep_Main[243] = {
+  &SpritePrep_Raven,
+  &SpritePrep_Vulture,
+  &SpritePrep_DoNothingA,
+  NULL,
+  &SpritePrep_Switch,
+  &SpritePrep_DoNothingA,
+  &SpritePrep_Switch,
+  &SpritePrep_SwitchFacingUp,
+  &SpritePrep_Octorok,
+  &SpritePrep_Moldorm,
+  &SpritePrep_Octorok,
+  &SpritePrep_DoNothingA,
+  &SpritePrep_DoNothingA,
+  &SpritePrep_DoNothingA,
+  &SpritePrep_DoNothingA,
+  &SpritePrep_Octoballoon,
+  &SpritePrep_DoNothingA,
+  &SpritePrep_DoNothingA,
+  &SpritePrep_DoNothingA,
+  &SpritePrep_MiniHelmasaur,
+  &SpritePrep_ThievesTownGrate,
+  &SpritePrep_Antifairy,
+  &SpritePrep_Sage,
+  &SpritePrep_DoNothingA,
+  &SpritePrep_MiniMoldorm_bounce,
+  &SpritePrep_Poe,
+  &SpritePrep_Smithy,
+  &SpritePrep_DoNothingA,
+  &SpritePrep_Statue,
+  &SpritePrep_IgnoreProjectiles,
+  &SpritePrep_CrystalSwitch,
+  &SpritePrep_SickKid,
+  &SpritePrep_DoNothingA,
+  &SpritePrep_WaterLever,
+  &SpritePrep_DoNothingA,
+  &SpritePrep_Bari,
+  &SpritePrep_Bari,
+  &SpritePrep_TalkingTree,
+  &SpritePrep_HardhatBeetle,
+  &SpritePrep_DoNothingA,
+  &SpritePrep_Storyteller,
+  &SpritePrep_Adults,
+  &SpritePrep_IgnoreProjectiles,
+  &SpritePrep_Hobo,
+  &SpritePrep_MagicBat,
+  &SpritePrep_IgnoreProjectiles,
+  &SpritePrep_FluteKid,
+  &SpritePrep_IgnoreProjectiles,
+  &SpritePrep_IgnoreProjectiles,
+  &SpritePrep_FortuneTeller,
+  &SpritePrep_IgnoreProjectiles,
+  &SpritePrep_RupeePull,
+  &SpritePrep_Snitch_bounce_2,
+  &SpritePrep_Snitch_bounce_3,
+  &SpritePrep_IgnoreProjectiles,
+  &SpritePrep_IgnoreProjectiles,
+  &SpritePrep_DoNothingA,
+  &SpritePrep_Locksmith,
+  &SpritePrep_MagicBat,
+  &SpritePrep_BonkItem,
+  &SpritePrep_IgnoreProjectiles,
+  &SpritePrep_Snitch_bounce_1,
+  &SpritePrep_DoNothingA,
+  &SpritePrep_DoNothingA,
+  &SpritePrep_AgahnimsBarrier,
+  &SpritePrep_StandardGuard,
+  &SpritePrep_StandardGuard,
+  &SpritePrep_StandardGuard,
+  &SpritePrep_TrooperAndArcherSoldier,
+  &SpritePrep_TrooperAndArcherSoldier,
+  &SpritePrep_TrooperAndArcherSoldier,
+  &SpritePrep_TrooperAndArcherSoldier,
+  &SpritePrep_TrooperAndArcherSoldier,
+  &SpritePrep_TrooperAndArcherSoldier,
+  &SpritePrep_TrooperAndArcherSoldier,
+  &SpritePrep_WeakGuard,
+  &SpritePrep_Geldman,
+  &SpritePrep_Kyameron,
+  &SpritePrep_Popo,
+  &SpritePrep_Popo2,
+  &SpritePrep_DoNothingA,
+  &SpritePrep_DoNothingD,
+  &SpritePrep_KingZora,
+  &SpritePrep_ArmosKnight,
+  &SpritePrep_Lanmolas,
+  &SpritePrep_SwimmingZora,
+  &SpritePrep_WalkingZora,
+  &SpritePrep_DesertStatue,
+  &SpritePrep_DoNothingA,
+  &SpritePrep_LostWoodsBird,
+  &SpritePrep_LostWoodsSquirrel,
+  &SpritePrep_Spark,
+  &SpritePrep_Spark,
+  &SpritePrep_Roller_VerticalDownFirst,
+  &SpritePrep_RollerUpDown,
+  &SpritePrep_Roller_HorizontalRightFirst,
+  &SpritePrep_RollerLeftRight,
+  &SpritePrep_DoNothingA,
+  &SpritePrep_MasterSword,
+  &SpritePrep_DebirandoPit,
+  &SpritePrep_FireDebirando,
+  &SpritePrep_ArrowGame_bounce,
+  &SpritePrep_WallCannon,
+  &SpritePrep_WallCannon,
+  &SpritePrep_WallCannon,
+  &SpritePrep_WallCannon,
+  &SpritePrep_DoNothingA,
+  &SpritePrep_DoNothingA,
+  &SpritePrep_DoNothingA,
+  &SpritePrep_Rat,
+  &SpritePrep_Rope,
+  &SpritePrep_Keese,
+  &SpritePrep_DoNothingG,
+  &SpritePrep_FairyPond,
+  &SpritePrep_IgnoreProjectiles,
+  &SpritePrep_UncleAndPriest_bounce,
+  &SpritePrep_RunningMan,
+  &SpritePrep_IgnoreProjectiles,
+  &SpritePrep_Zelda_bounce,
+  &SpritePrep_Antifairy,
+  &SpritePrep_MrsSahasrahla,
+  &SpritePrep_OverworldBonkItem,
+  &SpritePrep_Agahnim,
+  &SpritePrep_DoNothingG,
+  &SpritePrep_GreenStalfos,
+  &SpritePrep_BigSpike,
+  &SpritePrep_FireBar,
+  &SpritePrep_FireBar,
+  &SpritePrep_DoNothingG,
+  &SpritePrep_DoNothingG,
+  &SpritePrep_AntifairyCircle,
+  &SpritePrep_Eyegore,
+  &SpritePrep_Eyegore,
+  &SpritePrep_DoNothingG,
+  &SpritePrep_Kodongo,
+  &SpritePrep_DoNothingG,
+  &SpritePrep_Mothula,
+  &SpritePrep_DoNothingG,
+  &SpritePrep_Spike,
+  &SpritePrep_DoNothingG,
+  &SpritePrep_Arrghus,
+  &SpritePrep_Arrghi,
+  &SpritePrep_DoNothingG,
+  &SpritePrep_Blob,
+  &SpritePrep_DoNothingG,
+  &SpritePrep_DoNothingG,
+  &SpritePrep_HelmasaurKing,
+  &SpritePrep_Bumper,
+  &SpritePrep_DoNothingA,
+  &SpritePrep_LaserEye_bounce,
+  &SpritePrep_LaserEye_bounce,
+  &SpritePrep_LaserEye_bounce,
+  &SpritePrep_LaserEye_bounce,
+  &SpritePrep_DoNothingA,
+  &SpritePrep_Kyameron,
+  &SpritePrep_DoNothingA,
+  &SpritePrep_Zoro,
+  &SpritePrep_Babasu,
+  &SpritePrep_HauntedGroveOstritch,
+  &SpritePrep_HauntedGroveAnimal,
+  &SpritePrep_HauntedGroveAnimal,
+  &SpritePrep_MoveDown_8px,
+  &SpritePrep_Kholdstare,
+  &SpritePrep_KholdstareShell,
+  &SpritePrep_FallingIce,
+  &SpritePrep_Zazakku,
+  &SpritePrep_Zazakku,
+  &SpritePrep_Stalfos,
+  &SpritePrep_Bomber,
+  &SpritePrep_Bomber,
+  &SpritePrep_DoNothingC,
+  &SpritePrep_DoNothingH,
+  &SpritePrep_OverworldBonkItem,
+  &SpritePrep_OldMan_bounce,
+  &SpritePrep_DoNothingA,
+  &SpritePrep_DoNothingA,
+  &SpritePrep_DoNothingA,
+  &SpritePrep_DoNothingA,
+  &SpritePrep_NiceBee,
+  &SpritePrep_PedestalPlaque,
+  &SpritePrep_PurpleChest,
+  &SpritePrep_BombShoppe,
+  &SpritePrep_Kiki,
+  &SpritePrep_BlindMaiden,
+  &SpritePrep_DoNothingA,
+  &SpritePrep_BullyAndVictim,
+  &SpritePrep_Whirlpool,
+  &SpritePrep_Shopkeeper,
+  &SpritePrep_IgnoreProjectiles,
+  &SpritePrep_Vitreous,
+  &SpritePrep_MiniVitreous,
+  &SpritePrep_DoNothingA,
+  &SpritePrep_Catfish,
+  &SpritePrep_CutsceneAgahnim,
+  &SpritePrep_DoNothingA,
+  &SpritePrep_Gibo,
+  &SpritePrep_DoNothingA,
+  &SpritePrep_IgnoreProjectiles,
+  &SpritePrep_IgnoreProjectiles,
+  &SpritePrep_Pokey,
+  &SpritePrep_BigFairy,
+  &SpritePrep_Tektite,
+  &SpritePrep_Chainchomp_bounce,
+  &SpritePrep_Trinexx,
+  &SpritePrep_Trinexx,
+  &SpritePrep_Trinexx,
+  &SpritePrep_Blind,
+  &SpritePrep_Swamola,
+  &SpritePrep_DoNothingA,
+  &SpritePrep_DoNothingA,
+  &SpritePrep_IgnoreProjectiles,
+  &SpritePrep_RockStal,
+  &SpritePrep_IgnoreProjectiles,
+  &SpritePrep_DiggingGameGuy_bounce,
+  &SpritePrep_Ganon,
+  &SpritePrep_Ganon,
+  &SpritePrep_Absorbable,
+  &SpritePrep_Absorbable,
+  &SpritePrep_Absorbable,
+  &SpritePrep_Absorbable,
+  &SpritePrep_Absorbable,
+  &SpritePrep_Absorbable,
+  &SpritePrep_Absorbable,
+  &SpritePrep_Absorbable,
+  &SpritePrep_Absorbable,
+  &SpritePrep_Absorbable,
+  &SpritePrep_Absorbable,
+  &SpritePrep_Fairy,
+  &SpritePrep_SmallKey,
+  &SpritePrep_BigKey,
+  &SpritePrep_ShieldPickup,
+  &SpritePrep_Mushroom,
+  &SpritePrep_FakeSword,
+  &SpritePrep_PotionShop,
+  &SpritePrep_HeartContainer,
+  &SpritePrep_HeartPiece,
+  &SpritePrep_ThrowableScenery,
+  &SpritePrep_DoNothingA,
+  &SpritePrep_Mantle,
+  &SpritePrep_DoNothingA,
+  &SpritePrep_DoNothingA,
+  &SpritePrep_DoNothingA,
+  &SpritePrep_MedallionTable,
+};
+
+void Sprite_PullSwitch_bounce(int k) {
+  if (sprite_type[k] == 5 || sprite_type[k] == 7)
+    PullSwitch_FacingUp(k);
+  else
+    PullSwitch_FacingDown(k);
+}
+
+void GiantMoldorm_DrawSegment_AB(int k, int lookback) {
+  static const DrawMultipleData kGiantMoldorm_SegA_Dmd[8] = {
+    {-8, -8, 0x0084, 2},
+    { 8, -8, 0x0086, 2},
+    {-8,  8, 0x00a4, 2},
+    { 8,  8, 0x00a6, 2},
+    {-8, -8, 0x4086, 2},
+    { 8, -8, 0x4084, 2},
+    {-8,  8, 0x40a6, 2},
+    { 8,  8, 0x40a4, 2},
+  };
+  int j = sprite_subtype2[k] - lookback & 0x7f;
+  cur_sprite_x = moldorm_x_lo[j] | moldorm_x_hi[j] << 8;
+  cur_sprite_y = moldorm_y_lo[j] | moldorm_y_hi[j] << 8;
+  oam_cur_ptr += 0x10;
+  oam_ext_cur_ptr += 4;
+  Sprite_DrawMultiple(k, &kGiantMoldorm_SegA_Dmd[(sprite_subtype2[k] >> 1 & 1) * 4], 4, NULL);
+}
+
+void GiantMoldorm_DrawSegment_C_OrTail(int k, int lookback) {
+  static const uint8 kGiantMoldorm_OamFlags[4] = {0, 0x40, 0xc0, 0x80};
+  int j = sprite_subtype2[k] - lookback & 0x7f;
+  cur_sprite_x = moldorm_x_lo[j] | moldorm_x_hi[j] << 8;
+  cur_sprite_y = moldorm_y_lo[j] | moldorm_y_hi[j] << 8;
+  uint8 bak = sprite_oam_flags[k];
+  sprite_oam_flags[k] = (bak & 0x3f) | kGiantMoldorm_OamFlags[sprite_subtype2[k] >> 1 & 3];
+  SpriteDraw_SingleLarge(k);
+  sprite_oam_flags[k] = bak;
+}
+
+void Chicken_IncrSubtype2(int k, int j) {
+  sprite_subtype2[k] += j;
+  sprite_graphics[k] = (sprite_subtype2[k] >> 4) & 1;
+  Sprite_ReturnIfLifted(k);
+}
+
+bool Octoballoon_Find() {
+  for (int i = 15; i >= 0; i--) {
+    if (sprite_state[i] && sprite_type[i] == 0x10)
+      return true;
+  }
+  return false;
+}
+
+bool FluteBoy_CheckIfPlayerClose(int k) {
+  int xx = Sprite_GetX(k);
+  int yy = Sprite_GetY(k) - 16;
+  int x = link_x_coord - xx - (yy < 0); // zelda bug: carry
+  int y = link_y_coord - yy - (x < 0);
+  if (sign16(x)) x = ~x;
+  if (sign16(y)) y = ~y;
+  return (uint16)x < 48 && (uint16)y < 48;
+}
+
+void FortuneTeller_LightOrDarkWorld(int k, bool dark_world) {
+  int j;
+  static const uint8 kFortuneTeller_Prices[4] = {10, 15, 20, 30};
+
+  switch (sprite_ai_state[k]) {
+  case 0:  // WaitForInquiry
+    sprite_graphics[k] = 0;
+    sprite_A[k] = (j = (GetRandomNumber() & 3)) << 1;
+    if (link_rupees_goal < kFortuneTeller_Prices[j])
+      sprite_ai_state[k] = 1;
+    else
+      sprite_ai_state[k] = 2;
+    break;
+  case 1: // NotEnoughRupees
+    Sprite_ShowSolicitedMessage(k, 0xf2);
+    break;
+  case 2:  // AskIfPlayerWantsReading
+    if (Sprite_ShowSolicitedMessage(k, 0xf3) & 0x100) {
+      sprite_delay_main[k] = 255;
+      flag_is_link_immobilized = 1;
+      sprite_ai_state[k]=3;
+    }
+    break;
+  case 3: // ReactToPlayerResponse
+    if (!choice_in_multiselect_box) {
+      if (!sprite_delay_main[k])
+        sprite_ai_state[k]++;
+      sprite_graphics[k] = frame_counter >> 4 & 1;
+    } else {
+      Sprite_ShowMessageUnconditional(0xf5);
+      sprite_ai_state[k] = 2;
+      flag_is_link_immobilized = 0;
+    }
+    break;
+  case 4: // FortuneTeller_PerformPseudoScience
+    FortuneTeller_PerformPseudoScience(k);
+    break;
+  case 5:  // ShowCostMessage
+    if (!dark_world)
+      sprite_graphics[k] = 0;
+    j = kFortuneTeller_Prices[sprite_A[k]>>1];
+    dialogue_number[0] = (j / 10) | (j % 10)<< 4 ;
+    dialogue_number[1] = 0;
+    Sprite_ShowMessageUnconditional(0xf4);
+    sprite_ai_state[k]++;
+    break;
+  case 6:  // DeductPayment
+    link_rupees_goal -= kFortuneTeller_Prices[sprite_A[k]>>1];
+    sprite_ai_state[k]++;
+    link_hearts_filler = 160;
+    flag_is_link_immobilized = 0;
+    break;
+  case 7:
+    break;
+  }
+}
+
+int GarnishAllocForce() {
+  int k = 29;
+  while (garnish_type[k--] && k >= 0) {}
+  return k + 1;
+}
+
+int GarnishAlloc() {
+  int k = 29;
+  while (garnish_type[k] && k >= 0) k--;
+  return k;
+}
+
+int GarnishAllocLow() {
+  int k = 14;
+  while (garnish_type[k] && k >= 0) k--;
+  return k;
+}
+
+int GarnishAllocLimit(int k) {
+  while (garnish_type[k] && k >= 0) k--;
+  return k;
+}
+
+int GarnishAllocOverwriteOldLow() {
+  int k = 14;
+  while (garnish_type[k] && k >= 0) k--;
+  if (k < 0) {
+    if (sign8(--byte_7E0FF8))
+      byte_7E0FF8 = 14;
+    k = byte_7E0FF8;
+  }
+  return k;
+}
+
+int GarnishAllocOverwriteOld() {
+  int k = 29;
+  while (garnish_type[k] && k >= 0) k--;
+  if (k < 0) {
+    if (sign8(--byte_7E0FF8))
+      byte_7E0FF8 = 29;
+    k = byte_7E0FF8;
+  }
+  return k;
+}
+
+void Garnish_SetX(int k, uint16 x) {
+  garnish_x_lo[k] = x;
+  garnish_x_hi[k] = x >> 8;
+}
+
+void Garnish_SetY(int k, uint16 y) {
+  garnish_y_lo[k] = y;
+  garnish_y_hi[k] = y >> 8;
+}
+
+void Sprite_WishPond3(int k) {
+  int j;
+
+  switch (sprite_ai_state[k]) {
+  case 0:
+    flag_is_link_immobilized = 0;
+    if (sprite_delay_main[k] || Sprite_CheckIfLinkIsBusy())
+      return;
+    if (Sprite_ShowMessageOnContact(k, 0x14a) & 0x100) {
+      sprite_ai_state[k] = 1;
+      Link_ResetProperties_A();
+      link_direction_facing = 0;
+      sprite_head_dir[k] = 0;
+    }
+    break;
+  case 1:
+    if (!choice_in_multiselect_box) {
+      Sprite_ShowMessageUnconditional(0x8a);
+      sprite_ai_state[k] = 2;
+      flag_is_link_immobilized = 1;
+    } else {
+      Sprite_ShowMessageUnconditional(0x14b);
+      sprite_ai_state[k] = 0;
+      sprite_delay_main[k] = 255;
+    }
+    break;
+  case 2: {
+    sprite_ai_state[k] = 3;
+    j = choice_in_multiselect_box;
+    sprite_C[k] = j;
+    uint8 item = (&link_item_bow)[j];
+    (&link_item_bow)[j] = 0;
+    uint8 t = kWishPondItemData[kWishPondItemOffs[j] + ((j == 3 || j == 32) ? 1 : item) - 1];
+    AncillaAdd_TossedPondItem(0x28, t, 4);
+    Hud_RefreshIcon();
+    sprite_graphics[k] = t;
+    sprite_D[k] = item;
+    sprite_delay_main[k] = 255;
+    break;
+  }
+  case 3:
+    if (sprite_delay_main[k] == 0) {
+      SpriteSpawnInfo info;
+      int j = Sprite_SpawnDynamically(k, 0x72, &info);
+      assert(j >= 0);
+      Sprite_SetX(j, info.r0_x);
+      Sprite_SetY(j, info.r2_y - 80);
+      music_control = 0x1b;
+      last_music_control = 0;
+      sprite_B[j] = 1;
+      Palette_AssertTranslucencySwap();
+      PaletteFilter_WishPonds();
+      sprite_E[k] = j;
+      sprite_ai_state[k] = 4;
+      sprite_delay_main[k] = 255;
+    }
+    break;
+  case 4:
+    if (!(frame_counter & 7)) {
+      PaletteFilter_SP5F();
+      if (!BYTE(palette_filter_countdown)) {
+        Sprite_ShowMessageUnconditional(0x8b);
+        Palette_RevertTranslucencySwap();
+        TS_copy = 0;
+        CGADSUB_copy = 0x20;
+        flag_update_cgram_in_nmi++;
+        sprite_ai_state[k] = 5;
+      }
+    }
+    break;
+  case 5:
+    if (!choice_in_multiselect_box) {
+      sprite_ai_state[k] = 6;
+    } else {
+      sprite_ai_state[k] = 11;
+    }
+    break;
+  case 6:
+    sprite_ai_state[k] = 7;
+    if (!savegame_is_darkworld) {
+      if (sprite_graphics[k] == 12) {
+        sprite_graphics[k] = 42;
+        sprite_head_dir[k] = 1;
+      } else if (sprite_graphics[k] == 4) {
+        sprite_graphics[k] = 5;
+        sprite_head_dir[k] = 2;
+      } else if (sprite_graphics[k] == 22) {
+        sprite_graphics[k] = 44;
+        sprite_head_dir[k] = 3;
+      } else {
+        Sprite_ShowMessageUnconditional(0x14d);
+        return;
+      }
+    } else {
+      if (sprite_graphics[k] == 58) {
+        sprite_graphics[k] = 59;
+        sprite_head_dir[k] = 4;
+        Sprite_ShowMessageUnconditional(0x14f);
+        return;
+      } else if (sprite_graphics[k] == 2) {
+        sprite_graphics[k] = 3;
+        sprite_head_dir[k] = 5;
+      } else if (sprite_graphics[k] == 22) {
+        sprite_graphics[k] = 44;
+        sprite_head_dir[k] = 3;
+      } else {
+        Sprite_ShowMessageUnconditional(0x14d);
+        return;
+      }
+    }
+    Sprite_ShowMessageUnconditional(0x8c);
+    break;
+  case 7:
+    if (sprite_C[k] == 3)
+      (&link_item_bow)[sprite_C[k]] = sprite_D[k];
+    Palette_AssertTranslucencySwap();
+    TS_copy = 2;
+    CGADSUB_copy = 0x30;
+    flag_update_cgram_in_nmi++;
+    sprite_ai_state[k] = 8;
+    break;
+  case 8:
+    if (!(frame_counter & 7)) {
+      PaletteFilter_SP5F();
+      if (BYTE(palette_filter_countdown) == 30) {
+        sprite_state[sprite_E[k]] = 0;
+      } else if (BYTE(palette_filter_countdown) == 0) {
+        sprite_ai_state[k] = 9;
+      }
+    }
+    break;
+  case 9:
+    PaletteFilter_RestoreSP5F();
+    Palette_RevertTranslucencySwap();
+    item_receipt_method = 2;
+    Link_ReceiveItem(sprite_graphics[k], 0);
+    sprite_ai_state[k] = 10;
+    break;
+  case 10: {
+    static const uint8 kWishPondMsgs[5] = { 0x8f, 0x90, 0x92, 0x91, 0x93 };
+    if (sprite_head_dir[k])
+      Sprite_ShowMessageUnconditional(kWishPondMsgs[sprite_head_dir[k] - 1]);
+    sprite_ai_state[k] = 0;
+    sprite_delay_main[k] = 255;
+    break;
+  }
+  case 11:
+    Sprite_ShowMessageUnconditional(0x8d);
+    sprite_ai_state[k] = 12;
+    break;
+  case 12:
+    if (!choice_in_multiselect_box)
+      sprite_ai_state[k] = 13;
+    else
+      sprite_ai_state[k] = 6;
+    break;
+  case 13:
+    Sprite_ShowMessageUnconditional(0x8e);
+    sprite_ai_state[k] = 7;
+    break;
+  }
+}
+
+int Sprite_SpawnSmallSplash(int k) {
+  SpriteSpawnInfo info;
+  int j = Sprite_SpawnDynamicallyEx(k, 0xec, &info, 14);
+  if (j >= 0) {
+    Sprite_SetSpawnedCoordinates(j, &info);
+    sound_effect_1 = 0;
+    SpriteSfx_QueueSfx2WithPan(k, 0x28);
+    sprite_state[j] = 3;
+    sprite_delay_main[j] = 15;
+    sprite_ai_state[j] = 0;
+    sprite_flags2[j] = 3;
+  }
+  return j;
+}
+
+void HeartUpgrade_CheckIfAlreadyObtained(int k) {
+  if (!player_is_indoors) {
+    if (BYTE(overworld_screen_index) == 0x3b && !(save_ow_event_info[0x3b] & 0x20) ||
+      save_ow_event_info[BYTE(overworld_screen_index)] & 0x40)
+      sprite_state[k] = 0;
+  } else {
+    int j = sprite_x_hi[k] & 1;
+    if (dung_savegame_state_bits & (j ? 0x2000 : 0x4000))
+      sprite_state[k] = 0;
+  }
+}
+
+void Sprite_EE_MovableMantle(int k) {
+  MovableMantle_Draw(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  if (!Sprite_CheckDamageToLink_same_layer(k))
+    return;
+  Sprite_NullifyHookshotDrag();
+  Sprite_RepelDash();
+
+  if (follower_indicator != 1 || !link_item_torch || link_is_running || sprite_G[k] == 0x90 || sign8(link_actual_vel_x - 24))
+    return;
+
+  which_starting_point = 4;
+  sprite_subtype2[k]++;
+
+  if (!(sprite_subtype2[k] & 1))
+    sprite_G[k]++;
+
+  if (sprite_G[k] < 8)
+    return;
+  if (sound_effect_1 == 0)
+    sound_effect_1 = 34;
+  sprite_x_vel[k] = 2;
+  Sprite_MoveXY(k);
+}
+
+void Sprite_GoodOrBadArcheryTarget(int k) {
+  static const uint8 kArcheryGame_CashPrize[10] = {4, 8, 16, 32, 64, 99, 99, 99, 99, 99};
+  if (sprite_A[k] == 1) {
+    // good target
+    if (sprite_G[k] >= 5)
+      sprite_B[k] = 6;
+    sprite_flags2[k] &= ~0x1f;
+    int j = sprite_delay_aux2[k] ? sprite_delay_aux2[k] : (sprite_subtype2[k] >> 3);
+    sprite_oam_flags[k] = sprite_oam_flags[k] & ~0x40 | (j & 4) << 4;
+    BYTE(cur_sprite_y) -= 3;
+    SpriteDraw_SingleLarge(k);
+    if (sprite_delay_aux2[k]) {
+      if (sprite_delay_aux2[k] == 96 && !submodule_index) {
+        sprite_delay_main[0] = 112;
+        link_rupees_goal += kArcheryGame_CashPrize[sprite_B[k] - 1];
+      }
+      sprite_flags2[k] |= 5;
+      ArcheryGame_DrawPrize(k);
+    }
+  } else {
+    // bad target
+    sprite_flags2[k] &= ~0x1f;
+    BYTE(cur_sprite_y) += 3;
+    SpriteDraw_SingleLarge(k);
+  }
+  if (Sprite_ReturnIfInactive(k))
+    return;
+
+  if (sprite_delay_aux3[k] == 1)
+    sound_effect_1 = 0x3c;
+  sprite_subtype2[k]++;
+  Sprite_MoveX(k);
+  if (!sprite_delay_aux1[k]) {
+    sprite_ignore_projectile[k] = sprite_delay_main[k];
+    if (sprite_delay_main[k] == 0) {
+      if (Sprite_CheckTileCollision(k)) {
+        sprite_delay_main[k] = 16;
+        sprite_delay_aux2[k] = 0;
+      }
+    } else if (sprite_delay_main[k] == 1) {
+      static const int8 kArcheryTarget_X[2] = {-24, 8};
+      sprite_x_lo[k] = kArcheryTarget_X[sprite_graphics[k]];
+      sprite_x_hi[k] = link_x_coord >> 8;
+      sprite_delay_aux1[k] = 32;
+      sprite_G[k] = 0;
+    }
+  }
+}
+
+static inline uint8 ChainBallMult(uint16 a, uint8 b) {
+  if (a >= 256)
+    return b;
+  int p = a * b;
+  return (p >> 8) + (p >> 7 & 1);
+}
+
+void ChainBallTrooper_Draw(int k) {
+  PrepOamCoordsRet info;
+  if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
+    return;
+  SpriteDraw_GuardHead(k, &info, 0x18 / 4);
+  SpriteDraw_BNCBody(k, &info, 0x14 / 4);
+  SpriteDraw_BNCFlail(k, &info);
+
+  if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
+    return;
+  if (sprite_flags3[k] & 0x10)
+    SpriteDraw_Shadow_custom(k, &info, kSoldier_DrawShadow[sprite_D[k]]);
+}
+
+void Sprite_6B_CannonTrooper(int k) {
+  if (sprite_C[k] != 0) {
+    Sprite_Cannonball(k);
+    return;
+  }
+  assert(0);
+}
+
+void Bee_PutInBottle(int k) {
+  Bee_HandleInteractions(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  if (!choice_in_multiselect_box) {
+    int j = Sprite_Find_EmptyBottle();
+    if (j >= 0) {
+      link_bottle_info[j] = 7 + sprite_head_dir[k];
+      Hud_RefreshIcon();
+      sprite_state[k] = 0;
+      return;
+    }
+    Sprite_ShowMessageUnconditional(0xca);
+  }
+  sprite_delay_aux4[k] = 64;
+  sprite_ai_state[k] = 1;
+}
+
+static inline uint8 GuruguruBarMult(uint16 a, uint8 b) {
+  if (a >= 256)
+    return b;
+  int p = a * b;
+  return (p >> 8) + (p >> 7 & 1);
+}
+
+static inline int8 GuruguruBarSin(uint16 a, uint8 b) {
+  uint8 t = GuruguruBarMult(kSinusLookupTable[a & 0xff], b);
+  return (a & 0x100) ? -t : t;
+}
+
+static inline uint8 ArrgiMult(uint16 a, uint8 b) {
+  if (a >= 256)
+    return b;
+  int p = a * b;
+  return (p >> 8) + (p >> 7 & 1);
+}
+
+static inline int8 ArrgiSin(uint16 a, uint8 b) {
+  uint8 t = ArrgiMult(kSinusLookupTable[a & 0xff], b);
+  return (a & 0x100) ? -t : t;
+}
+
+static inline uint8 HelmasaurMult(uint16 a, uint8 b) {
+  if (a >= 256)
+    return b;
+  int p = a * b;
+  return (p >> 8) + (p >> 7 & 1);
+}
+
+static inline int8 HelmasaurSin(uint16 a, uint8 b) {
+  uint8 t = HelmasaurMult(kSinusLookupTable[a & 0xff], b);
+  return (a & 0x100) ? -t : t;
+}
+
+void Sprite_Wizzbeam(int k) {
+  Wizzbeam_Draw(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  sprite_oam_flags[k] ^= 6;
+  sprite_subtype2[k]++;
+  if (!sprite_ai_state[k])
+    Sprite_CheckDamageToLink(k);
+  Sprite_MoveXY(k);
+  if (Sprite_CheckTileCollision(k))
+    sprite_state[k] = 0;
+}
+
+void Kiki_LyingInwait(int k) {
+  PrepOamCoordsRet info;
+  Sprite_PrepOamCoord(k, &info);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  if (link_is_bunny_mirror | link_disable_sprite_damage | countdown_for_blink || follower_indicator == 10)
+    return;
+  if (save_ow_event_info[BYTE(overworld_screen_index)] & 0x20)
+    return;
+  if (Sprite_CheckDamageToLink_same_layer(k)) {
+    // Kiki Big Bomb Fix
+    if (enhanced_features0 & kFeatures0_MiscBugFixes)
+      follower_dropped = 0;  // defuse bomb
+
+    follower_indicator = 10;
+    tagalong_var5 = 0;
+    LoadFollowerGraphics();
+    Follower_Initialize();
+  }
+}
+
+int ChainChomp_OneMult(uint8 a, uint8 b) {
+  uint8 at = sign8(a) ? -a : a;
+  uint8 prod = at * b >> 8;
+  return sign8(a) ? ~prod : prod;
+}
+
+static inline uint8 TrinexxMult(uint8 a, uint8 b) {
+  uint8 at = sign8(a) ? -a : a;
+  int p = at * b;
+  uint8 res = (p >> 8) + (p >> 7 & 1);
+  return sign8(a) ? -res : res;
+}
+
+static inline uint8 TrinexxHeadMult(uint16 a, uint8 b) {
+  if (a >= 256)
+    return b;
+  int p = a * b;
+  return (p >> 8) + (p >> 7 & 1);
+}
+
+static inline int8 TrinexxHeadSin(uint16 a, uint8 b) {
+  uint8 t = TrinexxHeadMult(kSinusLookupTable[a & 0xff], b);
+  return (a & 0x100) ? -t : t;
+}
+
+void Sprite_CC(int k) {
+  if (!sprite_E[k]) {
+    Sprite_Sidenexx(k);
+    return;
+  }
+  PrepOamCoordsRet info;
+  Sprite_PrepOamCoord(k, &info);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  Sprite_MoveXY(k);
+  Sprite_TrinexxFire_AddFireGarnish(k);
+  Sprite_CC_CD_Common(k);
+}
+
+void Sprite_CD(int k) {
+  if (!sprite_E[k]) {
+    Sprite_Sidenexx(k);
+    return;
+  }
+  PrepOamCoordsRet info;
+  Sprite_PrepOamCoord(k, &info);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  uint8 old_xvel = sprite_x_vel[k];
+  sprite_x_vel[k] += sprite_C[k];
+  Sprite_MoveXY(k);
+  sprite_x_vel[k] = old_xvel;
+  Sprite_CD_SpawnGarnish(k);
+  Sprite_CC_CD_Common(k);
+}
+
+static inline uint8 GanonMult(uint16 a, uint8 b) {
+  if (a >= 256)
+    return b;
+  int p = a * b;
+  return (p >> 8) + (p >> 7 & 1);
+}
+
+static inline int8 GanonSin(uint16 a, uint8 b) {
+  uint8 t = GanonMult(kSinusLookupTable[a & 0xff], b);
+  return (a & 0x100) ? -t : t;
+}
+
+void SpritePrep_IncrXYLow8(int k) {
+  sprite_x_lo[k] += 8;
+  sprite_y_lo[k] += 8;
+}
+
+void SpritePrep_FakeSword(int k) {
+}
+
+void SpritePrep_MedallionTable(int k) {
+  sprite_ignore_projectile[k]++;
+  if (BYTE(overworld_screen_index) != 3) {
+    sprite_x_lo[k] += 8;
+    if (link_item_bombos_medallion) {
+      sprite_graphics[k] = 4;
+      sprite_ai_state[k] = 3;
+    }
+  } else {
+    if (link_item_ether_medallion) {
+      sprite_graphics[k] = 4;
+      sprite_ai_state[k] = 3;
+    }
+  }
+}
+
+void Hobo_Draw(int k) {  // 84ea60
+  static const DrawMultipleData kHobo_Dmd[12] = {
+    {-5,   3, 0x00a6, 2},
+    { 3,   3, 0x00a7, 2},
+    {-5,   3, 0x00a6, 2},
+    { 3,   3, 0x00a7, 2},
+    {-5,   3, 0x00ab, 0},
+    { 3,   3, 0x00a7, 2},
+    {-5,   3, 0x00a6, 2},
+    { 3,   3, 0x00a7, 2},
+    { 5, -11, 0x008a, 2},
+    {-5,   3, 0x00ab, 0},
+    { 3,   3, 0x0088, 2},
+    {-5,   3, 0x00a6, 2},
+  };
+  Sprite_DrawMultiplePlayerDeferred(k, &kHobo_Dmd[sprite_graphics[k] * 4], 4, NULL);
+}
+
+bool Landmine_CheckDetonationFromHammer(int k) {  // 84ea81
+  if (!(link_item_in_hand & 10) || player_oam_y_offset == 0x80)
+    return false;
+  SpriteHitBox hb;
+  Player_SetupActionHitBox(&hb);
+  Sprite_SetupHitBox(k, &hb);
+  return CheckIfHitBoxesOverlap(&hb);
+}
+
+void Sprite_DrawLargeWaterTurbulence(int k) {  // 84ebe5
+  static const DrawMultipleData kWaterTurbulence_Dmd[6] = {
+    {-10, 14, 0x00c0, 2},
+    { -5, 16, 0x40c0, 2},
+    { -2, 18, 0x00c0, 2},
+    {  2, 18, 0x40c0, 2},
+    {  5, 16, 0x00c0, 2},
+    { 10, 14, 0x40c0, 2},
+  };
+  uint8 bak = sprite_oam_flags[k];
+  sprite_oam_flags[k] = (sprite_subtype2[k] >> 1 & 1) ? 0x44 : 4;
+  sprite_obj_prio[k] &= ~0xf;
+  Oam_AllocateFromRegionC(sprite_obj_prio[k]);  // wtf?????
+  Sprite_DrawMultiple(k, kWaterTurbulence_Dmd, 6, NULL);
+  sprite_oam_flags[k] = bak;
+}
+
+void Sprite_SpawnSparkleGarnish(int k) {  // 858008
+  static const int8 kSparkleGarnish_Coord[4] = {-4, 0, 4, 8};
+  if (frame_counter & 3)
+    return;
+  int j = GarnishAllocForce();
+  garnish_type[j] = 0x12;
+  garnish_active = 0x12;
+  int x = Sprite_GetX(k) + kSparkleGarnish_Coord[GetRandomNumber() & 3];
+  int y = Sprite_GetY(k) + kSparkleGarnish_Coord[GetRandomNumber() & 3];
+  garnish_x_lo[j] = x;
+  garnish_x_hi[j] = x >> 8;
+  garnish_y_lo[j] = y;
+  garnish_y_hi[j] = y >> 8;
+  garnish_sprite[j] = k;
+  garnish_countdown[j] = 15;
+}
+
+void Sprite_70_KingHelmasaurFireball(int k) {  // 85807f
+  static const uint8 kHelmasaurFireball_Char[3] = {0xcc, 0xcc, 0xca};
+  static const uint8 kHelmasaurFireball_Flags[2] = {0x33, 0x73};
+  static const uint8 kHelmasaurFireball_Gfx[4] = {2, 2, 1, 0};
+  OamEnt *oam = GetOamCurPtr();
+  uint8 flags = kHelmasaurFireball_Flags[++sprite_subtype2[k] >> 2 & 1];
+
+  if ((uint8)((oam->x = sprite_x_lo[k] - BG2HOFS_copy2) + 32) < 64 ||
+      (uint8)((oam->y = sprite_y_lo[k] - BG2VOFS_copy2) + 16) < 32) {
+    sprite_state[k] = 0;
+    return;
+  }
+  oam->charnum = kHelmasaurFireball_Char[sprite_graphics[k]];
+  oam->flags = flags;
+  bytewise_extended_oam[oam - oam_buf] = 2;
+
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  if (!((k ^ frame_counter) & 3) &&
+      (uint16)(link_x_coord - cur_sprite_x + 8) < 16 &&
+      (uint16)(link_y_coord - cur_sprite_y + 16) < 16) {
+    Sprite_AttemptDamageToLinkPlusRecoil(k);
+  }
+  switch (sprite_ai_state[k]) {
+  case 0:  // pre migrate down
+    if (!sprite_delay_main[k]) {
+      sprite_delay_main[k] = 18;
+      sprite_ai_state[k] = 1;
+      sprite_y_vel[k] = 36;
+    }
+    break;
+  case 1:  // migrate down
+    if (!sprite_delay_main[k]) {
+      sprite_ai_state[k] = 2;
+      sprite_delay_main[k] = 31;
+    }
+    sprite_y_vel[k] -= 2;
+    Sprite_MoveY(k);
+    break;
+  case 2:  // delay tri split
+    if (!sprite_delay_main[k])
+      HelmasaurFireball_TriSplit(k);
+    else
+      sprite_graphics[k] = kHelmasaurFireball_Gfx[sprite_delay_main[k] >> 3];
+    break;
+  case 3:  // delay quad split
+    if (!sprite_delay_main[k]) {
+      HelmasaurFireball_QuadSplit(k);
+    } else if (sprite_head_dir[k] < 20) {
+      sprite_head_dir[k]++;
+      Sprite_MoveXY(k);
+    }
+    break;
+  case 4:  // move
+    Sprite_MoveXY(k);
+    break;
+  }
+}
+
+void Sprite_66_WallCannonVerticalLeft(int k) {  // 858090
+  static const int8 kWallCannon_Xvel[4] = {0, 0, -16, 16};
+  static const int8 kWallCannon_Yvel[4] = {-16, 16, 0, 0};
+  static const uint8 kWallCannon_Gfx[4] = {0, 0, 2, 2};
+  static const uint8 kWallCannon_OamFlags[4] = {0x40, 0, 0, 0x80};
+  static const int8 kWallCannon_Spawn_X[4] = {8, -8, 0, 0};
+  static const int8 kWallCannon_Spawn_Y[4] = {0, 0, 8, -8};
+  static const int8 kWallCannon_Spawn_Xvel[4] = {24, -24, 0, 0};
+  static const int8 kWallCannon_Spawn_Yvel[4] = {0, 0, 24, -24};
+
+  int j = sprite_D[k];
+  sprite_graphics[k] = kWallCannon_Gfx[j] + (sprite_delay_aux2[k] != 0);
+  sprite_oam_flags[k] = sprite_oam_flags[k] & ~0x40 | kWallCannon_OamFlags[j];
+  SpriteDraw_SingleLarge(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  if (!sprite_delay_main[k]) {
+    sprite_delay_main[k] = 128;
+    sprite_A[k] ^= 1;
+  }
+  j = sprite_A[k];
+  sprite_x_vel[k] = kWallCannon_Xvel[j];
+  sprite_y_vel[k] = kWallCannon_Yvel[j];
+  Sprite_MoveXY(k);
+
+  if (!((k << 2) + frame_counter & 31))
+    sprite_delay_aux2[k] = 16;
+  if (sprite_delay_aux2[k] != 1 || sprite_pause[k])
+    return;
+  SpriteSpawnInfo info;
+  j = Sprite_SpawnDynamicallyEx(k, 0x6B, &info, 13);
+  if (j >= 0) {
+    SpriteSfx_QueueSfx3WithPan(k, 0x7);
+    sprite_C[j] = 1;
+    sprite_graphics[j] = 1;
+    int i = sprite_D[k];
+    Sprite_SetX(j, info.r0_x + kWallCannon_Spawn_X[i]);
+    Sprite_SetY(j, info.r2_y + kWallCannon_Spawn_Y[i]);
+    sprite_x_vel[j] = kWallCannon_Spawn_Xvel[i];
+    sprite_y_vel[j] = kWallCannon_Spawn_Yvel[i];
+    sprite_flags2[j] = sprite_flags2[j] & 0xf0 | 1;
+    sprite_flags3[j] |= 0x47;
+    sprite_defl_bits[j] |= 0x44;
+    sprite_delay_main[j] = 32;
+  }
+}
+
+void Sprite_65_ArcheryGame(int k) {  // 8581ff
+  link_num_arrows = sprite_subtype[k];
+  if (sprite_A[k] == 0)
+    ArcheryGame_Host(k);
+  else
+    Sprite_GoodOrBadArcheryTarget(k);
+}
+
+void ArcheryGame_Host(int k) {  // 858217
+  if (!archery_game_arrows_left)
+    archery_game_out_of_arrows++;
+  ArcheryGameGuy_Draw(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  sprite_flags4[k] = 0;
+  if (Sprite_CheckDamageToLink_same_layer(k)) {
+    Sprite_NullifyHookshotDrag();
+    link_speed_setting = 0;
+    Link_CancelDash();
+  }
+  if (sprite_delay_main[k]) {
+    if (!(sprite_delay_main[k] & 7))
+      SpriteSfx_QueueSfx2WithPan(k, 0x11);
+    sprite_graphics[k] = (sprite_delay_main[k] & 4) >> 2;
+  } else {
+    static const uint8 kArcheryGameGuy_Gfx[4] = {3, 4, 3, 2};
+    sprite_graphics[k] = kArcheryGameGuy_Gfx[sprite_ai_state[k] ? (frame_counter >> 5 & 3) : 0];
+  }
+
+  switch (sprite_ai_state[k]) {
+  case 0:
+    sprite_flags4[k] = 10;
+    if (Sprite_CheckDamageToLink_same_layer(k) && filtered_joypad_L & 0x80) {
+      sprite_ai_state[k] = 1;
+      ArcheryGameGuy_ShowMsg(k, 0x85);
+    }
+    break;
+  case 1:
+  case 3:
+    if (!choice_in_multiselect_box && link_rupees_goal >= 20) {
+      sprite_head_dir[k] = 0;
+      byte_7E0B88 = 0;
+      sprite_ai_state[k] = 2;
+      ArcheryGameGuy_ShowMsg(k, 0x86);
+    } else {
+      sprite_ai_state[k] = 0;
+      ArcheryGameGuy_ShowMsg(k, 0x87);
+    }
+    break;
+  case 2:
+    ArcheryGame_Host_ProctorGame(k);
+    break;
+  }
+}
+
+void ArcheryGameGuy_ShowMsg(int k, int msg) {  // 8582bf
+  dialogue_message_index = msg;
+  Sprite_ShowMessageMinimal();
+  sprite_delay_main[k] = 0;
+}
+
+void ArcheryGame_Host_ProctorGame(int k) {  // 8582d4
+  static const uint8 kArcheryGame_NumSpr[6] = {5, 4, 3, 2, 1, 0};
+  static const int8 kArcheryGame_X[18] = { 0, 0, 0, 0, 48, 48, 48, 48, 8, 8, 16, 16, 24, 24, 32, 32, 40, 40, };
+  static const int8 kArcheryGame_Y[18] = {-8, 0, 8, 16, -8, 0, 8, 16, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8 };
+  static const uint8 kArcheryGame_Char[18] = { 0x2b, 0x3b, 0x3b, 0x2b, 0x2b, 0x3b, 0x3b, 0x2b, 0x63, 0x73, 0x63, 0x73, 0x63, 0x73, 0x63, 0x73, 0x63, 0x73 };
+  static const uint8 kArcheryGame_Flags[18] = { 0x33, 0x33, 0xb3, 0xb3, 0x73, 0x73, 0xf3, 0xf3, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32 };
+
+  if (!sprite_head_dir[k]) {
+    archery_game_arrows_left = 5;
+    Sprite_InitializeSecondaryItemMinigame(2);
+    sprite_delay_aux1[k] = 39;
+    link_rupees_goal -= 20;
+    sprite_head_dir[k]++;
+  }
+  Oam_AllocateFromRegionA(0x34);
+  PrepOamCoordsRet info;
+  if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
+    return;
+  OamEnt *oam = GetOamCurPtr();
+  int i = sprite_delay_aux1[k] ? kArcheryGame_NumSpr[sprite_delay_aux1[k] >> 3] : archery_game_arrows_left;
+  i = i * 2 + 7;
+  do {
+    SetOamPlain(oam, info.x - 20 + kArcheryGame_X[i] + 1, info.y - 48 + kArcheryGame_Y[i] + 1,
+                 kArcheryGame_Char[i], kArcheryGame_Flags[i], 0);
+  } while (oam++, --i >= 0);
+
+  if (archery_game_arrows_left | sprite_delay_aux4[k] |
+      ancilla_type[0] | ancilla_type[1] | ancilla_type[2] | ancilla_type[3] | ancilla_type[4])
+    return;
+  sprite_flags4[k] = 0xA;
+  if (Sprite_CheckDamageToLink_same_layer(k) && filtered_joypad_L & 0x80) {
+    ArcheryGameGuy_ShowMsg(k, 0x88);
+    sprite_ai_state[k] = 3;
+  }
+}
+
+void ArcheryGame_DrawPrize(int k) {  // 8584cf
+  static const int8 kGoodArcheryTarget_X[5] = {-8, -8, 0, 8, 16};
+  static const int8 kGoodArcheryTarget_Y[5] = {-24, -16, -20, -20, -20};
+  static const uint8 kGoodArcheryTarget_Draw_Char[3] = {0xb, 0x1b, 0xb6};
+  static const int8 kGoodArcheryTarget_Draw_Flags[5] = {0x38, 0x38, 0x34, 0x35, 0x35};
+  static const uint8 kGoodArcheryTarget_Draw_Char3[6] = {0x12, 0x32, 0x31, 3, 0x22, 0x33};
+  static const uint8 kGoodArcheryTarget_Draw_Char4[6] = {0x7c, 0x7c, 0x22, 2, 0x12, 0x33};
+  PrepOamCoordsRet info;
+  if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
+    return;
+  OamEnt *oam = GetOamCurPtr() + 1;
+  int b = sprite_B[k];
+  for (int i = 4; i >= 0; i--, oam++) {
+    uint8 charnum = (i == 4) ? kGoodArcheryTarget_Draw_Char4[b - 1] :
+                    (i == 3) ? kGoodArcheryTarget_Draw_Char3[b - 1] : kGoodArcheryTarget_Draw_Char[i];
+    SetOamPlain(oam, info.x + kGoodArcheryTarget_X[i], info.y + kGoodArcheryTarget_Y[i], charnum,
+                 kGoodArcheryTarget_Draw_Flags[i] & (charnum < 0x7c ? 0xff : 0xfe), 0);
+  }
+  Sprite_DrawDistress_custom(info.x, info.y, frame_counter);
+}
+
+void Sprite_63_DebirandoPit(int k) {  // 858531
+  static const uint8 kDebirandoPit_OpeningGfx[4] = {5, 4, 3, 3};
+  static const uint8 kDebirandoPit_ClosingGfx[4] = {3, 3, 4, 5};
+
+  PointU8 pt;
+  Sprite_DirectionToFaceLink(k, &pt);
+  if ((uint8)(pt.y + 0x20) < 0x40 && (uint8)(pt.x + 0x20) < 0x40)
+    Oam_AllocateFromRegionB(16);
+
+  DebirandoPit_Draw(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  int j = sprite_head_dir[k];
+  if (sprite_state[j] == 6) {
+    sprite_state[k] = sprite_state[j];
+    sprite_delay_main[k] = sprite_delay_main[j];
+    sprite_flags2[k] += 4;
+    return;
+  }
+  if (sprite_graphics[k] < 3 && Sprite_CheckDamageToLink_same_layer(k)) {
+    Link_CancelDash();
+    if (!(filtered_joypad_L & 16))
+      link_prevent_from_moving = 1;
+    Sprite_ApplySpeedTowardsLink(k, 16);
+    uint8 v = sprite_y_vel[k];
+    int t;
+    sprite_A[k] = (t = (sign8(v) ? (uint8)-v : v) + sprite_A[k]);
+    if (t >= 256)
+      drag_player_y = sign8(v) ? 1 : -1;
+
+    v = sprite_x_vel[k];
+    sprite_B[k] = (t = (sign8(v) ? (uint8)-v : v) + sprite_B[k]);
+    if (t >= 256)
+      drag_player_x = sign8(v) ? 1 : -1;
+  }
+  switch (sprite_ai_state[k]) {
+  case 0:  // closed
+    sprite_graphics[k] = 6;
+    if (!sprite_delay_main[k]) {
+      sprite_ai_state[k] = 1;
+      sprite_delay_main[k] = 63;
+    }
+    break;
+  case 1:  // opening
+    if (!sprite_delay_main[k]) {
+      sprite_ai_state[k] = 2;
+      sprite_delay_main[k] = 255;
+    } else {
+      sprite_graphics[k] = kDebirandoPit_OpeningGfx[sprite_delay_main[k] >> 4];
+    }
+    break;
+  case 2:  // open
+    if (!(frame_counter & 15) && ++sprite_graphics[k] >= 3)
+      sprite_graphics[k] = 0;
+    if (!sprite_delay_main[k]) {
+      sprite_delay_main[k] = 63;
+      sprite_ai_state[k] = 3;
+    }
+    break;
+  case 3:  // closing
+    if (!sprite_delay_main[k]) {
+      sprite_ai_state[k] = 0;
+      sprite_delay_main[k] = 32;
+    } else {
+      sprite_graphics[k] = kDebirandoPit_ClosingGfx[sprite_delay_main[k] >> 4];
+    }
+    break;
+  }
+}
+
+void DebirandoPit_Draw(int k) {  // 8586e4
+  static const int16 kDebirandoPit_Draw_X[24] = {
+    -8, 8, -8, 8, -8, 8, -8, 8, -8, 8, -8, 8, 0, 8, 0, 8,
+    0, 8,  0, 8, -8, 8, -8, 8,
+  };
+  static const int16 kDebirandoPit_Draw_Y[24] = {
+    -8, -8, 8, 8, -8, -8, 8, 8, -8, -8, 8, 8, 0, 0, 8, 8,
+    0,  0, 8, 8, -8, -8, 8, 8,
+  };
+  static const uint8 kDebirandoPit_Draw_Char[24] = {
+    4,    4,    4,    4, 0x22, 0x22, 0x22, 0x22, 2, 2, 2, 2, 0x29, 0x29, 0x29, 0x29,
+    0x39, 0x39, 0x39, 0x39, 0x2a, 0x2a, 0x2a, 0x2a,
+  };
+  static const uint8 kDebirandoPit_Draw_Flags[24] = {
+    0, 0x40, 0x80, 0xc0, 0, 0x40, 0x80, 0xc0, 0, 0x40, 0x80, 0xc0, 0, 0x40, 0x80, 0xc0,
+    0, 0x40, 0x80, 0xc0, 0, 0x40, 0x80, 0xc0,
+  };
+  static const uint8 kDebirandoPit_Draw_Big[6] = {2, 2, 2, 0, 0, 2};
+  PrepOamCoordsRet info;
+  if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
+    return;
+  int g = sprite_graphics[k];
+  if (g == 6)
+    return;
+  OamEnt *oam = GetOamCurPtr();
+  uint8 big = kDebirandoPit_Draw_Big[g];
+  for (int i = 3; i >= 0; i--, oam++) {
+    int j = g * 4 + i;
+    SetOamHelper0(oam, info.x + kDebirandoPit_Draw_X[j],
+                       info.y + kDebirandoPit_Draw_Y[j],
+                       kDebirandoPit_Draw_Char[j],
+                       kDebirandoPit_Draw_Flags[j] | info.flags, big);
+  }
+}
+
+void Sprite_64_Debirando(int k) {  // 85874d
+  static const uint8 kDebirando_Emerge_Gfx[2] = {1, 0};
+  static const uint8 kDebirando_Submerge_Gfx[2] = {0, 1};
+  Debirando_Draw(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  switch (sprite_ai_state[k]) {
+  case 0:  // under sand
+    sprite_ignore_projectile[k] = sprite_delay_main[k];
+    if (!sprite_delay_main[k]) {
+      sprite_ai_state[k]++;
+      sprite_delay_main[k] = 31;
+    }
+    break;
+  case 1:  // emerge
+    Sprite_CheckDamageToAndFromLink(k);
+    if (!sprite_delay_main[k]) {
+      sprite_ai_state[k]++;
+      sprite_delay_main[k] = 128;
+    } else {
+      sprite_graphics[k] = kDebirando_Emerge_Gfx[sprite_delay_main[k] >> 4];
+    }
+    break;
+  case 2:  // fireball
+    Sprite_CheckDamageToAndFromLink(k);
+    if (!sprite_delay_main[k]) {
+      sprite_delay_main[k] = 31;
+      sprite_ai_state[k]++;
+    } else {
+      if (!(sprite_delay_main[k] & 31 | sprite_G[k] | submodule_index | sprite_pause[k] | flag_unk1))
+        Sprite_SpawnFireball(k);
+      sprite_graphics[k] = (++sprite_subtype2[k] >> 3 & 1) + 2;
+    }
+    break;
+  case 3:  // submerge
+    Sprite_CheckDamageToAndFromLink(k);
+    if (!sprite_delay_main[k]) {
+      sprite_ai_state[k] = 0;
+      sprite_delay_main[k] = 223;
+    } else {
+      sprite_graphics[k] = kDebirando_Submerge_Gfx[sprite_delay_main[k] >> 4];
+    }
+    break;
+  }
+}
+
+void Debirando_Draw(int k) {  // 858857
+  if (!sprite_ai_state[k])
+    return;
+  static const int8 kDebirando_Draw_X[16] = {0, 8, 0, 8, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0};
+  static const int8 kDebirando_Draw_Y[16] = {2, 2, 6, 6, -2, -2, 6, 6, -4, -4, -4, -4, -4, -4, -4, -4};
+  static const uint8 kDebirando_Draw_Char[16] = {0, 0, 0xd8, 0xd8, 0, 0, 0xd9, 0xd9, 0, 0, 0, 0, 0x20, 0x20, 0x20, 0x20};
+  static const uint8 kDebirando_Draw_Flags[16] = {1, 0x41, 0, 0x40, 1, 1, 0, 0x40, 1, 1, 1, 1, 1, 1, 1, 1};
+  static const uint8 kDebirando_Draw_Big[16] = {0, 0, 0, 0, 2, 2, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2};
+  PrepOamCoordsRet info;
+  if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
+    return;
+  OamEnt *oam = GetOamCurPtr();
+  int d = sprite_graphics[k] * 4;
+  for (int i = 3; i >= 0; i--, oam++) {
+    int j = d + i;
+    uint8 f = kDebirando_Draw_Flags[j];
+    SetOamHelper0(oam,
+                  info.x + kDebirando_Draw_X[j],
+                  info.y + kDebirando_Draw_Y[j],
+                  kDebirando_Draw_Char[j],
+                  (f ^ info.flags) & ((f & 0xf) == 0 ? 0xf0 : 0xff),
+                  kDebirando_Draw_Big[j]);
+  }
+}
+
+void Sprite_62_MasterSword(int k) {  // 8588c5
+  switch (sprite_subtype2[k]) {
+  case 0: MasterSword_Main(k); break;
+  case 1: Sprite_MasterSword_LightFountain(k); break;
+  case 2: Sprite_MasterSword_LightBeam(k); break;
+  case 3: Sprite_MasterSword_Prop(k); break;
+  case 4: Sprite_MasterSword_LightWell(k); break;
+  }
+}
+
+void MasterSword_Main(int k) {  // 8588d6
+  if (main_module_index != 26 && save_ow_event_info[BYTE(overworld_screen_index)] & 0x40) {
+    sprite_state[k] = 0;
+    return;
+  }
+  if (sprite_ai_state[k] != 5)
+    MasterSword_Draw(k);
+  switch (sprite_ai_state[k]) {
+  case 0:  // waiting
+    if (Sprite_CheckIfLinkIsBusy() || !Sprite_CheckDamageToLink_same_layer(k) || link_direction_facing != 2 ||
+      !(filtered_joypad_L & 0x80) || (link_which_pendants & 7) != 7)
+      return;
+
+    music_control = 10;
+    link_disable_sprite_damage = 1;
+    MasterSword_SpawnPendantProp(k, 9);
+    MasterSword_SpawnPendantProp(k, 11);
+    MasterSword_SpawnPendantProp(k, 15);
+    MasterSword_SpawnLightWell(k);
+    sprite_ai_state[k] = 1;
+    sprite_delay_main[k] = 240;
+    break;
+  case 1:  // pendants transfer
+    if (!sprite_delay_main[k]) {
+      MasterSword_SpawnLightFountain(k);
+      sprite_ai_state[k] = 2;
+      sprite_delay_main[k] = 192;
+    }
+    link_unk_master_sword = 10;
+    flag_is_link_immobilized = 1;
+    break;
+  case 2:  // light show
+    if (!sprite_delay_main[k]) {
+      MasterSword_SpawnLightBeam(k, 0, 0xff);
+      sprite_ai_state[k] = 3;
+      sprite_delay_main[k] = 8;
+    }
+    link_unk_master_sword = 10;
+    flag_is_link_immobilized = 1;
+    break;
+  case 3:  //
+    if (!sprite_delay_main[k]) {
+      MasterSword_SpawnLightBeam(k, 1, 0xff);
+      sprite_ai_state[k] = 4;
+      sprite_delay_main[k] = 16;
+    }
+    link_unk_master_sword = 11;
+    flag_is_link_immobilized = 1;
+    break;
+  case 4:  // give to player
+    if (!sprite_delay_main[k]) {
+      save_ow_event_info[BYTE(overworld_screen_index)] |= 0x40;
+      item_receipt_method = 0;
+      Link_ReceiveItem(1, 0);
+      savegame_map_icons_indicator = 5;
+      link_unk_master_sword = 0;
+      sprite_ai_state[k] = 5;
+    }
+    break;
+  case 5:  // stop
+    sprite_state[k] = 0;
+    break;
+  }
+}
+
+void Sprite_MasterSword_LightFountain(int k) {  // 8589dc
+  static const uint8 kMasterSword_Gfx1[9] = {0, 1, 1, 2, 2, 2, 1, 1, 0};
+  static const uint8 kMasterSword_NumLightBeams[9] = {0, 0, 1, 1, 2, 2, 0, 0, 0};
+  SpriteDraw_LightFountain(k);
+  sprite_A[k]++;
+  if (!sprite_A[k]) {
+    sprite_C[k]++;
+    sprite_state[k] = 0;
+  }
+  sprite_D[k] = sprite_A[k] >> 2 & 3;
+  int j = sprite_A[k] >> 5 & 7;
+  sprite_graphics[k] = kMasterSword_Gfx1[j];
+  if (kMasterSword_NumLightBeams[j])
+    MasterSword_SpawnLightBeam(k, sprite_A[k] >> 2 & 1, kMasterSword_NumLightBeams[j]);
+}
+
+void Sprite_MasterSword_LightWell(int k) {  // 858a16
+  SpriteDraw_LightFountain(k);
+  sprite_A[k]++;
+  if (!sprite_A[k]) {
+    sprite_C[k]++;
+    sprite_state[k] = 0;
+  }
+  sprite_D[k] = sprite_A[k] >> 2 & 3;
+  sprite_graphics[k] = 0;
+}
+
+void SpriteDraw_LightFountain(int k) {  // 858a94
+  static const DrawMultipleData kMasterSword_LightBall_Dmd[12] = {
+    {-6, 4, 0x0082, 2},
+    {-6, 4, 0x4082, 2},
+    {-6, 4, 0xc082, 2},
+    {-6, 4, 0x8082, 2},
+    {-6, 4, 0x00a0, 2},
+    {-6, 4, 0x40a0, 2},
+    {-6, 4, 0xc0a0, 2},
+    {-6, 4, 0x80a0, 2},
+    {-6, 4, 0x0080, 2},
+    {-6, 4, 0x4080, 2},
+    {-6, 4, 0xc080, 2},
+    {-6, 4, 0x8080, 2},
+  };
+  Oam_AllocateFromRegionC(4);
+  Sprite_DrawMultiple(k, &kMasterSword_LightBall_Dmd[sprite_graphics[k] * 4 + sprite_D[k]], 1, NULL);
+}
+
+void MasterSword_SpawnLightWell(int k) {  // 858ab6
+  SpriteSpawnInfo info;
+  int j = Sprite_SpawnDynamically(k, 0x62, &info);
+  Sprite_SetSpawnedCoordinates(j, &info);
+  sprite_subtype2[j] = 4;
+  sprite_oam_flags[j] = 5;
+  sprite_flags2[j] = 0;
+}
+
+void MasterSword_SpawnLightFountain(int k) {  // 858ad0
+  SpriteSpawnInfo info;
+  int j = Sprite_SpawnDynamically(k, 0x62, &info);
+  Sprite_SetSpawnedCoordinates(j, &info);
+  sprite_subtype2[j] = 1;
+  sprite_oam_flags[j] = 5;
+  sprite_flags2[j] = 0;
+}
+
+void Sprite_MasterSword_LightBeam(int k) {  // 858aea
+  SpriteDraw_SingleLarge(k);
+  if (sprite_A[k]) {
+    Sprite_MoveXY(k);
+    if (frame_counter & 3)
+      return;
+    MasterSword_SpawnReplacementLightBeam(k);
+  }
+  if (!--sprite_B[k])
+    sprite_state[k] = 0;
+}
+
+void MasterSword_SpawnReplacementLightBeam(int k) {  // 858b20
+  SpriteSpawnInfo info;
+  int j;
+  if ((j = Sprite_SpawnDynamically(k, 0x62, &info)) < 0)
+    return;
+  Sprite_SetX(j, info.r0_x);
+  Sprite_SetY(j, info.r2_y);
+  sprite_subtype2[j] = 2;
+  sprite_B[j] = 3;
+  sprite_graphics[j] = sprite_graphics[k];
+  sprite_oam_flags[j] = sprite_oam_flags[k];
+  sprite_flags2[j] = 0;
+}
+
+void MasterSword_SpawnLightBeam(int k, uint8 ain, uint8 yin) {  // 858b62
+  static const int8 kMasterSword_LightBeam_Xv0[2] = {0, -48};
+  static const int8 kMasterSword_LightBeam_Xv1[2] = {0, 48};
+  static const int8 kMasterSword_LightBeam_Xv2[2] = {-96, -48};
+  static const int8 kMasterSword_LightBeam_Xv3[2] = {96, 48};
+  static const int8 kMasterSword_LightBeam_Yv0[2] = {-96, -48};
+  static const int8 kMasterSword_LightBeam_Yv1[2] = {96, 48};
+  static const int8 kMasterSword_LightBeam_Yv2[2] = {0, 48};
+  static const int8 kMasterSword_LightBeam_Yv3[2] = {0, -48};
+  static const uint8 kMasterSword_LightBeam_Gfx0[2] = {1, 0};
+  static const uint8 kMasterSword_LightBeam_Gfx2[2] = {3, 2};
+  static const uint8 kMasterSword_LightBeam_Flags0[2] = {5, 0x45};
+  static const uint8 kMasterSword_LightBeam_Flags2[2] = {5, 5};
+
+  SpriteSpawnInfo info;
+  int j;
+  if ((j = Sprite_SpawnDynamically(k, 0x62, &info)) < 0)
+    return;
+  Sprite_SetX(j, info.r0_x - 4);
+  Sprite_SetY(j, info.r2_y + 4);
+  sprite_subtype2[j] = 2;
+  sprite_A[j] = 2;
+  sprite_flags2[j] = 0;
+  sprite_x_vel[j] = kMasterSword_LightBeam_Xv0[ain];
+  sprite_y_vel[j] = kMasterSword_LightBeam_Yv0[ain];
+  sprite_graphics[j] = kMasterSword_LightBeam_Gfx0[ain];
+  sprite_oam_flags[j] = kMasterSword_LightBeam_Flags0[ain];
+  sprite_B[j] = yin;
+
+  if ((j = Sprite_SpawnDynamically(k, 0x62, &info)) < 0)
+    return;
+  Sprite_SetX(j, info.r0_x - 4);
+  Sprite_SetY(j, info.r2_y + 4);
+  sprite_subtype2[j] = 2;
+  sprite_A[j] = 2;
+  sprite_flags2[j] = 0;
+  sprite_x_vel[j] = kMasterSword_LightBeam_Xv1[ain];
+  sprite_y_vel[j] = kMasterSword_LightBeam_Yv1[ain];
+  sprite_graphics[j] = kMasterSword_LightBeam_Gfx0[ain];
+  sprite_oam_flags[j] = kMasterSword_LightBeam_Flags0[ain];
+  sprite_B[j] = yin;
+
+  if ((j = Sprite_SpawnDynamically(k, 0x62, &info)) < 0)
+    return;
+  Sprite_SetX(j, info.r0_x - 4);
+  Sprite_SetY(j, info.r2_y + 4);
+  sprite_subtype2[j] = 2;
+  sprite_A[j] = 2;
+  sprite_flags2[j] = 0;
+  sprite_x_vel[j] = kMasterSword_LightBeam_Xv2[ain];
+  sprite_y_vel[j] = kMasterSword_LightBeam_Yv2[ain];
+  sprite_graphics[j] = kMasterSword_LightBeam_Gfx2[ain];
+  sprite_oam_flags[j] = kMasterSword_LightBeam_Flags2[ain];
+  sprite_B[j] = yin;
+
+  if ((j = Sprite_SpawnDynamically(k, 0x62, &info)) < 0)
+    return;
+  Sprite_SetX(j, info.r0_x - 4);
+  Sprite_SetY(j, info.r2_y + 4);
+  sprite_subtype2[j] = 2;
+  sprite_A[j] = 2;
+  sprite_flags2[j] = 0;
+  sprite_x_vel[j] = kMasterSword_LightBeam_Xv3[ain];
+  sprite_y_vel[j] = kMasterSword_LightBeam_Yv3[ain];
+  sprite_graphics[j] = kMasterSword_LightBeam_Gfx2[ain];
+  sprite_oam_flags[j] = kMasterSword_LightBeam_Flags2[ain];
+  sprite_B[j] = yin;
+}
+
+void MasterSword_SpawnPendantProp(int k, uint8 ain) {  // 858cd3
+  static const int8 kMasterSword_Pendant_Xv[4] = {-4, 4, 0, 0};
+  static const int8 kMasterSword_Pendant_Yv[4] = {-2, -2, -4, -4};
+  SpriteSpawnInfo info;
+  int j;
+  if ((j = Sprite_SpawnDynamically(k, 0x62, &info)) < 0)
+    return;
+  sprite_oam_flags[j] = ain;
+  Sprite_SetX(j, link_x_coord);
+  Sprite_SetY(j, link_y_coord + 8);
+  sprite_graphics[j] = 4;
+  sprite_subtype2[j] = 3;
+  sprite_flags2[j] = 64;
+  sprite_delay_main[j] = 228;
+  int i = ain >> 1 & 3;
+  sprite_x_vel[j] = kMasterSword_Pendant_Xv[i];
+  sprite_y_vel[j] = kMasterSword_Pendant_Yv[i];
+}
+
+void Sprite_MasterSword_Prop(int k) {  // 858d29
+  Oam_AllocateFromRegionB(4);
+  SpriteDraw_SingleLarge(k);
+  switch (sprite_ai_state[k]) {
+  case 0:  // drifting away
+    Sprite_MoveXY(k);
+    if (!sprite_delay_main[k]) {
+      sprite_ai_state[k] = 1;
+      sprite_delay_main[k] = 208;
+      sprite_A[k] = sprite_oam_flags[k];
+    }
+    break;
+  case 1:  // flashing
+    sprite_oam_flags[k] = (sprite_oam_flags[k] & ~0xe) | ((k << 1 ^ frame_counter) & 0xe);
+    if (!sprite_delay_main[k]) {
+      sprite_ai_state[k] = 2;
+      sprite_oam_flags[k] = sprite_A[k];
+    }
+    break;
+  case 2:  // fly
+    Sprite_MoveXY(k);
+    if (!sprite_delay_main[k]) {
+      sprite_x_vel[k] <<= 1;
+      sprite_y_vel[k] <<= 1;
+      sprite_delay_main[k] = 6;
+    }
+    sprite_E[k]++;
+    if (sprite_E[k] == 0)
+      sprite_state[k] = 0;
+    break;
+  }
+}
+
+void MasterSword_Draw(int k) {  // 858da8
+  static const int8 kMasterSword_Draw_X[6] = {-8, 0, -8, 0, -8, 0};
+  static const int8 kMasterSword_Draw_Y[6] = {-8, -8, 0, 0, 8, 8};
+  static const uint8 kMasterSword_Draw_Char[6] = {0xc3, 0xc4, 0xd3, 0xd4, 0xe0, 0xf0};
+  PrepOamCoordsRet info;
+  if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
+    return;
+  OamEnt *oam = GetOamCurPtr();
+  for (int i = 5; i >= 0; i--, oam++) {
+    oam->x = kMasterSword_Draw_X[i] + info.x;
+    oam->y = kMasterSword_Draw_Y[i] + info.y;
+    oam->charnum = kMasterSword_Draw_Char[i];
+    oam->flags = info.flags;
+  }
+  Sprite_CorrectOamEntries(k, 5, 0);
+}
+
+void Sprite_5D_Roller_VerticalDownFirst(int k) {  // 858dde
+  static const int8 kSpikeRoller_XYvel[6] = {-16, 16, 0, 0, -16, 16};
+  sprite_graphics[k] = sprite_subtype2[k] >> 1 & 1 | sprite_D[k] & 2;
+  SpikeRoller_Draw(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  Sprite_CheckDamageToAndFromLink(k);
+  if (!sprite_delay_main[k]) {
+    sprite_delay_main[k] = 112;
+    sprite_D[k] ^= 1;
+  }
+  int j = sprite_D[k];
+  sprite_x_vel[k] = kSpikeRoller_XYvel[j];
+  sprite_y_vel[k] = kSpikeRoller_XYvel[j + 2];
+  Sprite_MoveXY(k);
+  sprite_subtype2[k]++;
+}
+
+void SpikeRoller_Draw(int k) {  // 858ee3
+  static const uint8 kSpikeRoller_Draw_X[32] = {
+    0,    0,    0,    0,    0,    0,    0,    0, 0,    0,    0,    0,    0,    0,    0,    0,
+    0, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70,
+  };
+  static const uint8 kSpikeRoller_Draw_Y[32] = {
+    0, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70,
+    0,    0,    0,    0,    0,    0,    0,    0, 0,    0,    0,    0,    0,    0,    0,    0,
+  };
+  static const uint8 kSpikeRoller_Draw_Char[32] = {
+    0x8e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x8e, 0x8e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x8e,
+    0x88, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x88, 0x88, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x88,
+  };
+  static const uint8 kSpikeRoller_Draw_Flags[32] = {
+    0, 0, 0, 0x80, 0, 0, 0, 0x80, 0x40, 0x40, 0x40, 0xc0, 0x40, 0x40, 0x40, 0xc0,
+    0, 0, 0, 0x40, 0, 0, 0, 0x40, 0x80, 0x80, 0x80, 0xc0, 0x80, 0x80, 0x80, 0xc0,
+  };
+  PrepOamCoordsRet info;
+  if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
+    return;
+  OamEnt *oam = GetOamCurPtr();
+  int g = sprite_graphics[k];
+  uint8 chr = kSpikeRoller_Draw_Char[g * 8];
+
+  for (int i = sprite_ai_state[k] ? 7 : 3; i >= 0; i--, oam++) {
+    int j = g * 8 + i;
+    SetOamHelper0(oam,
+                  info.x + kSpikeRoller_Draw_X[j],
+                  info.y + kSpikeRoller_Draw_Y[j],
+                  chr ? chr : kSpikeRoller_Draw_Char[j],
+                  kSpikeRoller_Draw_Flags[j] | info.flags, 2);
+    chr = 0;
+  }
+}
+
+void Sprite_61_Beamos(int k) {  // 858f54
+  if (sprite_C[k] == 1) {
+    Sprite_Beamos_Laser(k);
+    return;
+  } else if (sprite_C[k] != 0) {
+    Sprite_Beamos_LaserHit(k);
+    return;
+  }
+
+  Beamos_Draw(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  Sprite_CheckTileCollision(k);
+  Sprite_CheckDamageToLink(k);
+  switch (sprite_ai_state[k]) {
+  case 0:
+    if (!((k ^ frame_counter) & 3)) {
+      Sprite_SpawnProbeAlways(k, sprite_D[k]);
+      sprite_D[k]++;
+    }
+    sprite_D[k] &= 63;
+    break;
+  case 3:
+    if (!sprite_delay_main[k]) {
+      sprite_ai_state[k] = 4;
+      sprite_delay_main[k] = 80;
+      SpritePrep_LoadPalette(k);
+    } else {
+      if (sprite_delay_main[k] == 15)
+        Beamos_FireLaser(k);
+      sprite_oam_flags[k] ^= (sprite_delay_main[k] >> 1 & 0xe);
+    }
+    break;
+  default:
+    if (!sprite_delay_main[k])
+      sprite_ai_state[k] = 0;
+    break;
+  }
+}
+
+void Beamos_FireLaser(int k) {  // 858fc2
+  if (sprite_limit_instance >= 4)
+    return;
+  SpriteSpawnInfo info;
+  int j, t;
+  if ((j = Sprite_SpawnDynamically(k, 0x61, &info)) < 0)
+    return;
+  SpriteSfx_QueueSfx3WithPan(k, 0x19);
+  Sprite_SetX(j, info.r0_x + (int8)BYTE(dungmap_var7));
+  Sprite_SetY(j, info.r2_y + (int8)HIBYTE(dungmap_var7));
+  Sprite_ApplySpeedTowardsLink(j, 0x20);
+  sprite_flags2[j] = 0x3f;
+  sprite_flags4[j] = 0x54;
+  sprite_C[j] = 1;
+  sprite_defl_bits[j] = 0x48;
+  sprite_oam_flags[j] = 3;
+  sprite_bump_damage[j] = 4;
+  sprite_delay_aux1[j] = 12;
+  sprite_graphics[j] = t = sprite_limit_instance++;
+  for (int i = 0; i < 32; i++) {
+    beamos_x_lo[t * 32 + i] = sprite_x_lo[j];
+    beamos_x_hi[t * 32 + i] = sprite_x_hi[j];
+    beamos_y_lo[t * 32 + i] = sprite_y_lo[j];
+    beamos_y_hi[t * 32 + i] = sprite_y_hi[j];
+  }
+}
+
+void Beamos_Draw(int k) {  // 859068
+  static const int8 kBeamos_Draw_Y[2] = {-16, 0};
+  static const int8 kBeamos_Draw_Char[2] = {0x48, 0x68};
+  PrepOamCoordsRet info;
+  if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
+    return;
+  int spr_offs = 0;
+  if (sprite_D[k] < 0x20) {
+    Oam_AllocateFromRegionB(12);
+    spr_offs = 1;
+  } else {
+    Oam_AllocateFromRegionC(12);
+  }
+  OamEnt *oam = GetOamCurPtr() + spr_offs;
+  for (int i = 1; i >= 0; i--, oam++)
+    SetOamHelper0(oam, info.x, info.y + kBeamos_Draw_Y[i], kBeamos_Draw_Char[i], info.flags, 2);
+  SpriteDraw_Beamos_Eyeball(k, &info);
+}
+
+void SpriteDraw_Beamos_Eyeball(int k, PrepOamCoordsRet *info) {  // 859151
+  static const int8 kBeamosEyeball_Draw_X[32] = {
+    -1,  0,  1,  2,  3,  4,  5, 7, 8, 10, 11, 12, 13, 14, 15, 16,
+    17, 15, 14, 13, 12, 11, 10, 8, 7,  5,  4,  3,  2,  1,  0, -2,
+  };
+  static const int8 kBeamosEyeball_Draw_Y[32] = {
+    11, 12, 13, 14, 14, 15, 15, 15, 15, 15, 15, 14, 14, 13, 12, 11,
+    10,  9,  8,  7,  7,  6,  6,  6,  6,  6,  6,  7,  7,  8,  9, 10,
+  };
+  static const uint8 kBeamosEyeball_Draw_Char[32] = {
+    0x5b, 0x5b, 0x5a, 0x5a, 0x4b, 0x4b, 0x4a, 0x4a, 0x4a, 0x4a, 0x4b, 0x4b, 0x5a, 0x5a, 0x5b, 0x5b,
+    0x5b, 0x5b, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x5b, 0x5b, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c,
+  };
+  static const uint8 kBeamosEyeball_Draw_Flags[32] = {
+    0,    0,    0,    0,    0,    0,    0,    0, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
+    0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,    0,    0,    0,    0,    0,    0,    0,    0,
+  };
+  int n = (sprite_D[k] < 0x20) ? 0 : 2;
+  OamEnt *oam = GetOamCurPtr() + n;
+  int i = sprite_D[k] >> 1;
+  BYTE(dungmap_var7) = kBeamosEyeball_Draw_X[i] - 3;
+  oam->x = BYTE(dungmap_var7) + info->x;
+  HIBYTE(dungmap_var7) = kBeamosEyeball_Draw_Y[i] - 18;
+  oam->y = HIBYTE(dungmap_var7) + info->y;
+  oam->charnum = kBeamosEyeball_Draw_Char[i];
+  oam->flags = info->flags&0x31|0xA|kBeamosEyeball_Draw_Flags[i];
+  oam_cur_ptr += n * 4;
+  oam_ext_cur_ptr += n;
+  Sprite_CorrectOamEntries(k, 0, 0);
+}
+
+void Sprite_Beamos_Laser(int k) {  // 8591b5
+  if (sprite_delay_aux1[k])
+    return;
+  BeamosLaser_Draw(k);
+  if (!sprite_state[k]) {
+    sprite_limit_instance--;
+    return;
+  }
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  for (int i = 3; i >= 0; i--) {
+    int t = (sprite_subtype2[k]++ & 31) + sprite_graphics[k] * 32;
+    beamos_y_hi[t] = sprite_y_hi[k];
+    beamos_y_lo[t] = sprite_y_lo[k];
+    beamos_x_hi[t] = sprite_x_hi[k];
+    beamos_x_lo[t] = sprite_x_lo[k];
+    Sprite_MoveXY(k);
+  }
+
+  if (sprite_delay_main[k]) {
+    if (sprite_delay_main[k] == 1) {
+      sprite_state[k] = 0;
+      sprite_limit_instance--;
+    }
+    return;
+  }
+  if (!Sprite_CheckDamageToLink_same_layer(k) && !Sprite_CheckTileCollision(k))
+    return;
+  SpriteSfx_QueueSfx3WithPan(k, 0x26);
+  sprite_delay_main[k] = 16;
+  Sprite_ZeroVelocity_XY(k);
+  SpriteSpawnInfo info;
+  int j = Sprite_SpawnDynamically(k, 0x61, &info);
+  if (j >= 0) {
+    Sprite_SetSpawnedCoordinates(j, &info);
+    sprite_delay_main[j] = 16;
+    sprite_flags2[j] = 3;
+    sprite_C[j] = 2;
+    sprite_flags3[j] = 0x40;
+  }
+  sprite_y_hi[k] = 128;
+}
+
+void BeamosLaser_Draw(int k) {  // 85925b
+  PrepOamCoordsRet info;
+  Sprite_PrepOamCoord(k, &info);
+  OamEnt *oam = GetOamCurPtr();
+  int g = sprite_graphics[k];
+  for (int i = 31; i >= 0; i--, oam++) {
+    int j = g * 32 + i;
+    uint16 x = (beamos_x_lo[j] | beamos_x_hi[j] << 8) - BG2HOFS_copy2;
+    uint16 y = (beamos_y_lo[j] | beamos_y_hi[j] << 8) - BG2VOFS_copy2;
+    SetOamHelper0(oam, x, y, 0x5c, info.flags, 0);
+  }
+}
+
+void Sprite_Beamos_LaserHit(int k) {  // 8592da
+  static const int8 kBeamosLaserHit_Draw_X[4] = {-4, 4, -4, 4};
+  static const int8 kBeamosLaserHit_Draw_Y[4] = {-4, -4, 4, 4};
+  static const uint8 kBeamosLaserHit_Draw_Flags[4] = {6, 0x46, 0x86, 0xc6};
+  if (!sprite_delay_main[k])
+    sprite_state[k] = 0;
+  PrepOamCoordsRet info;
+  if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
+    return;
+  OamEnt *oam = GetOamCurPtr();
+  for (int i = 3; i >= 0; i--, oam++) {
+    SetOamHelper0(oam, info.x + kBeamosLaserHit_Draw_X[i], info.y + kBeamosLaserHit_Draw_Y[i],
+                  0xd6, kBeamosLaserHit_Draw_Flags[i] | info.flags & 0x30, 0);
+  }
+}
+
+void Sprite_5B_Spark_Clockwise(int k) {  // 85933f
+  static const uint8 kSpark_OamFlags[4] = {0, 0x40, 0x80, 0xc0};
+  static const uint8 kSpark_directions[8] = {1, 3, 2, 0, 7, 5, 6, 4};
+  int j;
+
+  SpriteDraw_SingleLarge(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  if (!(frame_counter & 1))
+    sprite_oam_flags[k] ^= 6;
+  if (!sprite_ai_state[k]) {
+    sprite_ai_state[k] = 1;
+    sprite_x_vel[k] = sprite_y_vel[k] = 1;
+    uint8 coll = Sprite_CheckTileCollision(k);
+    sprite_x_vel[k] = sprite_y_vel[k] = -1;
+    coll |= Sprite_CheckTileCollision(k);
+    if (coll < 4)
+      j = (coll & 1) ? 0 : 1;
+    else
+      j = (coll & 4) ? 2 : 3;
+    sprite_D[k] = kSpark_directions[(sprite_type[k] != 0x5c) * 4 + j];
+  }
+
+  sprite_oam_flags[k] = sprite_oam_flags[k] & 0x3f | kSpark_OamFlags[frame_counter >> 2 & 3];
+  Sprite_MoveXY(k);
+  Sprite_CheckDamageToLink(k);
+  j = sprite_D[k];
+  sprite_x_vel[k] = kSoldierB_Xvel[j];
+  sprite_y_vel[k] = kSoldierB_Yvel[j];
+  Sprite_CheckTileCollision(k);
+
+  j = sprite_D[k];
+  if (sprite_delay_aux2[k]) {
+    if (sprite_delay_aux2[k] == 6)
+      j = kSoldierB_NextB[j];
+  } else {
+    if (!(sprite_wallcoll[k] & kSoldierB_Mask[j]))
+      sprite_delay_aux2[k] = 10;
+  }
+  if (sprite_wallcoll[k] & kSoldierB_Mask2[j])
+    j = kSoldierB_NextB2[j];
+  sprite_D[k] = j;
+  sprite_x_vel[k] = kSoldierB_Xvel2[j] * 2;
+  sprite_y_vel[k] = kSoldierB_Yvel2[j] * 2;
+}
+
+void Sprite_59_LostWoodsBird(int k) {  // 85940e
+  if (sprite_delay_aux1[k])
+    return;
+  sprite_oam_flags[k] = sprite_oam_flags[k] & ~0x40 | (sign8(sprite_x_vel[k]) ? 0 : 0x40);
+  SpriteDraw_SingleLarge(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  Sprite_MoveXY(k);
+  Sprite_MoveZ(k);
+  switch (sprite_ai_state[k]) {
+  case 0:
+    sprite_graphics[k] = 0;
+    if (sign8(--sprite_z_vel[k] - 0xf1))
+      sprite_ai_state[k] = 1;
+    break;
+  case 1:
+    sprite_z_vel[k] += 2;
+    if (!sign8(sprite_z_vel[k] - 0x10))
+      sprite_ai_state[k] = 0;
+    sprite_graphics[k] = ++sprite_subtype2[k] >> 1 & 1;
+    break;
+  }
+}
+
+void Sprite_5A_LostWoodsSquirrel(int k) {  // 859468
+  if (sprite_delay_aux1[k])
+    return;
+  sprite_oam_flags[k] = sprite_oam_flags[k] & ~0x40 | (sign8(sprite_x_vel[k]) ? 0 : 0x40);
+  SpriteDraw_SingleLarge(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  Sprite_MoveXY(k);
+  Sprite_MoveZ(k);
+  sprite_z_vel[k] -= 2;
+  if (sign8(sprite_z[k])) {
+    sprite_z[k] = 0;
+    sprite_z_vel[k] = 16;
+    sprite_delay_main[k] = 12;
+  }
+  sprite_graphics[k] = sprite_delay_main[k] ? 1 : 0;
+}
+
+void Sprite_58_Crab(int k) {  // 8594b5
+  static const int8 kCrab_Xvel[4] = {28, -28, 0, 0};
+  static const int8 kCrab_Yvel[4] = {0, 0, 12, -12};
+  Crab_Draw(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  if (Sprite_ReturnIfRecoiling(k))
+    return;
+  Sprite_CheckDamageToAndFromLink(k);
+  Sprite_MoveXY(k);
+  if (Sprite_CheckTileCollision(k) || !sprite_delay_main[k]) {
+    sprite_delay_main[k] = (GetRandomNumber() & 63) + 32;
+    sprite_D[k] = sprite_delay_main[k] & 3;
+  }
+  int j = sprite_D[k];
+  sprite_x_vel[k] = kCrab_Xvel[j & 3];
+  sprite_y_vel[k] = kCrab_Yvel[j & 3];
+  sprite_graphics[k] = (++sprite_subtype2[k] >> (j < 2 ? 1 : 3)) & 1;
+}
+
+void Crab_Draw(int k) {  // 859510
+  static const int16 kCrab_Draw_X[4] = {-8, 8, -8, 8};
+  static const uint8 kCrab_Draw_Char[4] = {0x8e, 0x8e, 0xae, 0xae};
+  static const int8 kCrab_Draw_Flags[4] = {0, 0x40, 0, 0x40};
+  PrepOamCoordsRet info;
+  if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
+    return;
+  OamEnt *oam = GetOamCurPtr();
+  int d = sprite_graphics[k] * 2;
+  for (int i = 1; i >= 0; i--, oam++) {
+    int j = d + i;
+    SetOamHelper0(oam, info.x + kCrab_Draw_X[j], info.y, kCrab_Draw_Char[j], kCrab_Draw_Flags[j] | info.flags, 2);
+  }
+  SpriteDraw_Shadow(k, &info);
+}
+
+void Sprite_57_DesertStatue(int k) {  // 85956d
+  static const uint8 kDesertBarrier_NextD[4] = {3, 2, 0, 1};
+  DesertBarrier_Draw(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  bool dmg = Sprite_CheckDamageToLink_same_layer(k);
+  if (dmg) {
+    Sprite_NullifyHookshotDrag();
+    Sprite_RepelDash();
+  }
+  if (sprite_delay_main[k] || sign8(sprite_ai_state[k]))
+    return;
+
+  if (sprite_ai_state[k] == 0) {
+    if (!byte_7E02F0)
+      return;
+    sprite_ai_state[k] = byte_7E02F0;
+    sprite_delay_main[k] = 128;
+    sound_effect_ambient = 7;
+  }
+
+  if (dmg && !link_incapacitated_timer) {
+    link_incapacitated_timer = 16;
+    Sprite_ApplySpeedTowardsLink(k, 32);
+  }
+
+  int j = sprite_D[k];
+  sprite_x_vel[k] = kDesertBarrier_Xv[j];
+  sprite_y_vel[k] = kDesertBarrier_Yv[j];
+  Sprite_MoveXY(k);
+  if (Sprite_CheckTileCollision(k))
+    sprite_D[k] = kDesertBarrier_NextD[sprite_D[k]];
+  flag_is_link_immobilized = 1;
+  if (!(++sprite_subtype2[k] & 1)) {
+    if (++sprite_G[k] == 130) {
+      sprite_ai_state[k] = 128;
+      flag_is_link_immobilized = 0;
+    }
+  }
+}
+
+void DesertBarrier_Draw(int k) {  // 859626
+  static const DrawMultipleData kDesertBarrier_Dmd[4] = {
+    {-8, -8, 0x008e, 2},
+    { 8, -8, 0x408e, 2},
+    {-8,  8, 0x00ae, 2},
+    { 8,  8, 0x40ae, 2},
+  };
+  if (sprite_delay_main[k] == 1) {
+    sound_effect_2 = 0x1b;
+    sound_effect_ambient = 5;
+  }
+  BYTE(cur_sprite_x) += (sprite_delay_main[k] >> 1) & 1;
+  PointU8 pt;
+  Sprite_DirectionToFaceLink(k, &pt);
+  if ((uint8)(pt.x + 0x20) < 0x40 && (uint8)(pt.y + 0x20) < 0x40)
+    Oam_AllocateFromRegionB(16);
+  Sprite_DrawMultiple(k, kDesertBarrier_Dmd, 4, NULL);
+}
+
+void Sprite_55_Zora(int k) {  // 85967b
+  if (sprite_E[k])
+    Sprite_Fireball(k);
+  else
+    Sprite_Zora_Main(k);
+}
+
+void Sprite_Fireball(int k) {  // 859683
+  static const uint8 kSprite_ZoraFireball_Offs[4] = {3, 2, 0, 0};
+  static const int8 kSprite_ZoraFireball_X[4] = {4, 4, -4, 16};
+  static const int8 kSprite_ZoraFireball_Y[4] = {0, 16, 8, 8};
+  static const uint8 kSprite_ZoraFireball_W[4] = {8, 8, 4, 4};
+  static const uint8 kSprite_ZoraFireball_H[4] = {4, 4, 8, 8};
+
+  sprite_ignore_projectile[k] = sprite_E[k];
+  if (sprite_delay_main[k])
+    Oam_AllocateFromRegionC(4);
+  SpriteDraw_SingleSmall(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  Fireball_SpawnTrailGarnish(k);
+  if (Sprite_CheckDamageToLink(k)) {
+    sprite_state[k] = 0;
+    return;
+  }
+  Sprite_MoveXY(k);
+  if (player_is_indoors && !sprite_delay_aux1[k] && !((k ^ frame_counter) & 3) && Sprite_CheckTileCollision(k)) {
+    sprite_state[k] = 0;
+    return;
+  }
+
+  if ((link_is_bunny_mirror | link_disable_sprite_damage) || sign8(link_state_bits) || link_shield_type < 2 ||
+      link_is_on_lower_level != sprite_floor[k])
+    return;
+  SpriteHitBox hb;
+  Sprite_SetupHitBox(k, &hb);
+  int j = link_direction_facing >> 1;
+  if (button_b_frames)
+    j = kSprite_ZoraFireball_Offs[j];
+  int x = link_x_coord + kSprite_ZoraFireball_X[j], y = link_y_coord + kSprite_ZoraFireball_Y[j];
+  hb.r0_xlo = x;
+  hb.r8_xhi = x >> 8;
+  hb.r2 = kSprite_ZoraFireball_W[j];
+  hb.r1_ylo = y;
+  hb.r9_yhi = y >> 8;
+  hb.r3 = kSprite_ZoraFireball_H[j];
+  if (CheckIfHitBoxesOverlap(&hb)) {
+    Sprite_PlaceRupulseSpark_2(k);
+    sprite_state[k] = 0;
+    SpriteSfx_QueueSfx2WithPan(k, 0x6);
+  }
+}
+
+void Sprite_Zora_Main(int k) {  // 859725
+  static const int8 kSprite_Zora_Surface_XY[8] = {-32, -24, -16, -8, 8, 16, 24, 32};
+  static const uint8 kSprite_Zora_AttackGfx[8] = {5, 5, 6, 10, 6, 5, 5, 5};
+  static const uint8 kSprite_Zora_SubmergeGfx[12] = {12, 11, 9, 8, 7, 0, 0, 0, 0, 0, 0, 0};
+  PrepOamCoordsRet info;
+  if (!sprite_ai_state[k])
+    Sprite_PrepOamCoord(k, &info);
+  else
+    Zora_Draw(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  switch (sprite_ai_state[k]) {
+  case 0:  // choose surfacing location
+    sprite_ignore_projectile[k] = sprite_delay_main[k];
+    if (!sprite_delay_main[k]) {
+      int org_x = (sprite_A[k] | sprite_B[k] << 8);
+      int org_y = (sprite_C[k] | sprite_head_dir[k] << 8);
+      Sprite_SetX(k, org_x + kSprite_Zora_Surface_XY[GetRandomNumber() & 7]);
+      Sprite_SetY(k, org_y + kSprite_Zora_Surface_XY[GetRandomNumber() & 7]);
+      Sprite_Get16BitCoords(k);
+      Sprite_CheckTileCollision(k);
+      if (sprite_tiletype == 8) spawn_anyway: {
+        sprite_delay_main[k] = 127;
+        sprite_ai_state[k]++;
+        sprite_flags3[k] |= 0x40;
+      } else {
+        // In Misery Mire some Zoras are placed in shallow water so they can't spawn
+        // This fixes so they will be able to spawn in shallow water after a delay.
+        if (enhanced_features0 & kFeatures0_GameChangingBugFixes) {
+          if (sprite_tiletype == 9 && sprite_delay_aux2[k] == 1)
+            goto spawn_anyway;
+          Sprite_SetX(k, org_x);
+          Sprite_SetY(k, org_y);
+          sprite_ignore_projectile[k] = 1;
+          if (sprite_delay_aux2[k] == 0)
+            sprite_delay_aux2[k] = 32;
+        }
+      }
+    }
+    break;
+  case 1:  // surfacing
+    sprite_ignore_projectile[k] = sprite_delay_main[k];
+    if (!sprite_delay_main[k]) {
+      sprite_ai_state[k]++;
+      sprite_delay_main[k] = 127;
+      sprite_flags3[k] &= ~0x40;
+    } else {
+      sprite_graphics[k] = kSprite_Zora_SurfacingGfx[sprite_delay_main[k] >> 3];
+    }
+    break;
+  case 2:  // attack
+    Sprite_CheckDamageToAndFromLink(k);
+    if (!sprite_delay_main[k]) {
+      sprite_ai_state[k]++;
+      sprite_delay_main[k] = 23;
+    } else {
+      if (sprite_delay_main[k] == 48)
+        Sprite_SpawnFireball(k);
+      sprite_graphics[k] = kSprite_Zora_AttackGfx[sprite_delay_main[k] >> 4];
+    }
+    break;
+  case 3:  // submerging
+    if (!sprite_delay_main[k]) {
+      sprite_delay_main[k] = 128;
+      sprite_graphics[k] = 0;
+      sprite_ai_state[k] = 0;
+    } else {
+      sprite_graphics[k] = kSprite_Zora_SubmergeGfx[sprite_delay_main[k] >> 2];
+    }
+    break;
+  }
+}
+
+void Zora_Draw(int k) {  // 8598f5
+  static const int8 kZora_Draw_X[26] = {
+    4, 4,  0,  0, 0, 0,  0,  0,  0,  0, 0, 0, 0, 0, 0, 0,
+    0, 0, -4, 11, 0, 4, -8, 18, -8, 18,
+  };
+  static const int8 kZora_Draw_Y[26] = {
+    4,  4,  0,  0,  0, 0,   0,  -3,   0,  -3, -3, -3, -3, -3, -3, -3,
+    -6, -6, -8, -9, -3, 5, -10, -11, -10, -11,
+  };
+  static const uint8 kZora_Draw_Char[26] = {
+    0xa8, 0xa8, 0x88, 0x88, 0x88, 0x88, 0x88, 0xa4, 0x88, 0xa4, 0xa4, 0xa4, 0xa6, 0xa6, 0xa4, 0xc0,
+    0x8a, 0x8a, 0xae, 0xaf, 0xa6, 0x8d, 0xcf, 0xcf, 0xdf, 0xdf,
+  };
+  static const uint8 kZora_Draw_Flags[26] = {
+    0x25, 0x25, 0x25, 0x25, 0xe5, 0xe5, 0x25, 0x20, 0xe5, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x24,
+    0x25, 0x25, 0x24, 0x64, 0x20, 0x26, 0x24, 0x64, 0x24, 0x64,
+  };
+  static const uint8 kZora_Draw_Big[26] = {
+    0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+    2, 2, 0, 0, 2, 0, 0, 0, 0, 0,
+  };
+  PrepOamCoordsRet info;
+  if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
+    return;
+  OamEnt *oam = GetOamCurPtr();
+  int d = sprite_graphics[k] * 2;
+  for (int i = 1; i >= 0; i--, oam++) {
+    int j = d + i;
+    uint8 f = kZora_Draw_Flags[j];
+    SetOamHelper0(oam, info.x + kZora_Draw_X[j], info.y + kZora_Draw_Y[j], kZora_Draw_Char[j], f | (f & 0xf ? 0 : info.flags), kZora_Draw_Big[j]);
+  }
+}
+
+void Sprite_52_KingZora(int k) {  // 85995b
+  ZoraKing_Draw(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  switch(sprite_ai_state[k]) {
+  case 0:  // WaitingForPlayer
+    if ((uint16)(link_x_coord - cur_sprite_x + 16) < 32 && (uint16)(link_y_coord - cur_sprite_y + 48) < 96) {
+      Link_CancelDash();
+      sprite_delay_main[k] = 127;
+      sound_effect_1 = 0x35;
+      sprite_ai_state[k] = 1;
+      for (int j = 15; j >= 0; j--) {
+        if (j != k && !(sprite_defl_bits[j] & 0x80)) {
+          if (sprite_state[j] == 10) {
+            link_state_bits = 0;
+            link_picking_throw_state = 0;
+          }
+          Sprite_KillSelf(j);
+        }
+      }
+    }
+    break;
+  case 1:  // RumblingGround
+    if (!sprite_delay_main[k]) {
+      sprite_ai_state[k] = 2;
+      sprite_delay_main[k] = 127;
+      bg1_x_offset = 0;
+      sprite_graphics[k] = 4;
+    } else {
+      bg1_x_offset = sprite_delay_main[k] & 1 ? -1 : 1;
+      flag_is_link_immobilized = 1;
+    }
+    break;
+  case 2: {  // Surfacing
+    static const uint8 kZoraKing_Surfacing_Gfx[16] = {0, 0, 0, 3, 9, 8, 7, 6, 9, 8, 7, 6, 5, 4, 5, 4};
+    if (!sprite_delay_main[k]) {
+      sprite_ai_state[k] = 3;
+      sprite_delay_main[k] = 127;
+    } else {
+      if (sprite_delay_main[k] == 28) {
+        sprite_delay_aux2[k] = 15;
+        Sprite_SpawnBigSplash(k);
+      }
+      sprite_graphics[k] = kZoraKing_Surfacing_Gfx[sprite_delay_main[k] >> 3];
+    }
+    break;
+  }
+  case 3: { // Dialogue
+    static const uint8 kZoraKing_Dialogue_Gfx[8] = {0, 0, 1, 2, 1, 2, 0, 0};
+    int j = sprite_delay_main[k];
+    if (!j) {
+      sprite_ai_state[k] = 4;
+      sprite_delay_main[k] = 36;
+      return;
+    }
+    sprite_graphics[k] = kZoraKing_Dialogue_Gfx[j >> 4];
+    if (j == 80) {
+      dialogue_message_index = 0x142;
+      Sprite_ShowMessageMinimal();
+    } else if (j == 79) {
+      if (choice_in_multiselect_box == 0) {
+        dialogue_message_index = 0x143;
+        Sprite_ShowMessageMinimal();
+      } else {
+        dialogue_message_index = 0x146;
+        Sprite_ShowMessageMinimal();
+        sprite_delay_main[k] = 0x30;
+      }
+    } else if (j == 78) {
+      if (choice_in_multiselect_box == 0 && link_rupees_goal >= 500) {
+        link_rupees_goal -= 500;
+        dialogue_message_index = 0x144;
+        Sprite_ShowMessageMinimal();
+        sprite_E[k] = 1;
+      } else {
+        dialogue_message_index = 0x145;
+        Sprite_ShowMessageMinimal();
+        sprite_delay_main[k] = 0x30;
+      }
+    } else if (j == 77) {
+      if (sprite_E[k])
+        Sprite_Zora_RegurgitateFlippers(k);
+    }
+    break;
+  }
+  case 4: {  // Submerge
+    static const uint8 kZoraKing_Submerge_Gfx[21] = {
+      12, 12, 12, 12, 12, 12, 11, 11, 11, 11, 11, 10, 10, 10, 10, 3,
+      3,  3,  3,  3,  3,
+    };
+    int j = sprite_delay_main[k];
+    if (!j) {
+      Sprite_KillSelf(k);
+      flag_is_link_immobilized = 0;
+    } else {
+      if (j == 29) {
+        sprite_delay_aux2[k] = 15;
+        Sprite_SpawnBigSplash(k);
+      }
+      sprite_graphics[k] = kZoraKing_Submerge_Gfx[sprite_delay_main[k] >> 1];
+    }
+    break;
+  }
+  }
+}
+
+void Sprite_SpawnBigSplash(int k) {  // 859b40
+  static const int8 kSpawnSplashRing_X[8] = {-8, -5, 4, 13, 16, 13, 4, -5};
+  static const int8 kSpawnSplashRing_Y[8] = {4, -5, -8, -5, 4, 13, 16, 13};
+  static const int8 kSpawnSplashRing_Xvel[8] = {-8, -6, 0, 6, 8, 6, 0, -6};
+  static const int8 kSpawnSplashRing_Yvel[8] = {0, -6, -8, -6, 0, 6, 8, 6};
+  SpriteSfx_QueueSfx2WithPan(k, 0x24);
+
+  for (int i = 7; i >= 0; i--) {
+    SpriteSpawnInfo info;
+    int j = Sprite_SpawnDynamically(k, 8, &info);
+    if (j >= 0) {
+      sprite_state[j] = 3;
+      Sprite_SetX(j, info.r0_x + kSpawnSplashRing_X[i] - 4);
+      Sprite_SetY(j, info.r2_y + kSpawnSplashRing_Y[i] - 4);
+      sprite_x_vel[j] = kSpawnSplashRing_Xvel[i];
+      sprite_y_vel[j] = kSpawnSplashRing_Yvel[i];
+      sprite_A[j] = i;
+      sprite_z_vel[j] = (GetRandomNumber() & 15) + 24;
+      sprite_ai_state[j] = 1;
+      sprite_z[j] = 0;
+      sprite_flags3[j] |= 0x40;
+      sprite_ignore_projectile[j] = sprite_flags3[j];
+    }
+  }
+}
+
+void ZoraKing_Draw(int k) {  // 859cab
+  PrepOamCoordsRet info;
+  if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
+    return;
+
+  if (sprite_ai_state[k] >= 2) {
+    static const int8 kZoraKing_Draw_X0[52] = {
+      -8,  8,  -8,  8, -8, 8, -8, 8, -8, 8, -8, 8,  -8,  8,  -8,  8,
+      0,  0,   0,  0,  0, 0,  0, 0, -8, 8, -8, 8,  -8,  8,  -8,  8,
+      -8,  8,  -8,  8, -8, 8, -8, 8, -9, 9, -9, 9, -10, 10, -10, 10,
+      -11, 11, -11, 11,
+    };
+    static const int8 kZoraKing_Draw_Y0[52] = {
+      -18, -18, -2, -2, -18, -18, -2, -2, -18, -18, -2, -2, -12, -12, 4, 4,
+      0,   0,  0,  0,   0,   0,  0,  0,  -8,  -8,  8,  8,  -8,  -8, 8, 8,
+      -8,  -8,  8,  8,  -8,  -8,  8,  8,  -5,  -5,  5,  5,  -5,  -5, 5, 5,
+      -5,  -5,  5,  5,
+    };
+    static const uint8 kZoraKing_Draw_Char0[52] = {
+      0xc0, 0xc0, 0xe0, 0xe0, 0xc2, 0xea, 0xe2, 0xe2, 0xea, 0xc2, 0xe2, 0xe2, 0xc0, 0xc0, 0xe4, 0xe6,
+      0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0xc4, 0xc6, 0xe4, 0xe6, 0xc6, 0xc4, 0xe6, 0xe4,
+      0xe6, 0xe4, 0xc6, 0xc4, 0xe4, 0xe6, 0xc4, 0xc6, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
+      0x88, 0x88, 0x88, 0x88,
+    };
+    static const uint8 kZoraKing_Draw_Flags0[52] = {
+      0, 0x40,    0, 0x40,    0, 0x40,    0, 0x40, 0, 0x40,    0, 0x40,    0, 0x40,    5,    5,
+      5,    5,    5,    5, 0xc5, 0xc5, 0xc5, 0xc5, 5,    5,    5,    5, 0x45, 0x45, 0x45, 0x45,
+      0xc5, 0xc5, 0xc5, 0xc5, 0x85, 0x85, 0x85, 0x85, 4, 0x44, 0x84, 0xc4,    4, 0x44, 0x84, 0xc4,
+      4, 0x44, 0x84, 0xc4,
+    };
+    OamEnt *oam = GetOamCurPtr();
+    int g = sprite_graphics[k];
+    for (int i = 3; i >= 0; i--, oam++) {
+      int j = g * 4 + i;
+      oam->x = kZoraKing_Draw_X0[j] + info.x;
+      oam->y = kZoraKing_Draw_Y0[j] + info.y;
+      oam->charnum = kZoraKing_Draw_Char0[j];
+      uint8 f = kZoraKing_Draw_Flags0[j];
+      oam->flags = (f & 0xf ? f : f | info.flags) | 0x20;
+    }
+    Sprite_CorrectOamEntries(k, 3, 2);
+    if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
+      return;
+  }
+
+  if (!sprite_delay_aux2[k])
+    return;
+
+  static const int8 kZoraKing_Draw_X1[8] = {-23, 23, 23, 23, -20, -15, 13, 18};
+  static const int8 kZoraKing_Draw_Y1[8] = {-8, -8, -8, -8, -7, 0, 0, -7};
+  static const uint8 kZoraKing_Draw_Char1[8] = {0xae, 0xae, 0xae, 0xae, 0xac, 0xac, 0xac, 0xac};
+  static const uint8 kZoraKing_Draw_Flags1[8] = {0, 0x40, 0x40, 0x40, 0, 0, 0x40, 0x40};
+  Oam_AllocateFromRegionC(0x10);
+  OamEnt *oam = GetOamCurPtr();
+  int g = (sprite_delay_aux2[k] >> 1) & 4;
+  for (int i = 3; i >= 0; i--, oam++) {
+    int j = g + i;
+    SetOamPlain(oam, kZoraKing_Draw_X1[j] + info.x, kZoraKing_Draw_Y1[j] + info.y,
+                 kZoraKing_Draw_Char1[j], kZoraKing_Draw_Flags1[j] | 0x24, 2);
+  }
+}
+
+void Sprite_56_WalkingZora(int k) {  // 859d4a
+  if (sprite_F[k]) {
+    sprite_F[k] = 0;
+    sprite_B[k] = 3;
+    sprite_G[k] = 192;
+    sprite_x_vel[k] = (int8)sprite_x_recoil[k] >> 1;
+    sprite_y_vel[k] = (int8)sprite_y_recoil[k] >> 1;
+  }
+  PrepOamCoordsRet info;
+  switch(sprite_B[k]) {
+  case 0:  // Waiting
+    Sprite_PrepOamCoord(k, &info);
+    if (Sprite_ReturnIfInactive(k))
+      return;
+    if (!sprite_delay_main[k]) {
+      sprite_delay_main[k] = 127;
+      sprite_B[k]++;
+      sprite_flags3[k] |= 64;
+    }
+    break;
+  case 1:  // Surfacing
+    Zora_Draw(k);
+    if (Sprite_ReturnIfInactive(k))
+      return;
+    sprite_ignore_projectile[k] = sprite_delay_main[k];
+    if (!sprite_delay_main[k]) {
+      sprite_flags3[k] &= ~0x40;
+      SpriteSfx_QueueSfx2WithPan(k, 0x28);
+      sprite_B[k]++;
+      sprite_z_vel[k] = 48;
+      sprite_head_dir[k] = sprite_D[k] = Sprite_DirectionToFaceLink(k, NULL);
+    } else {
+      sprite_graphics[k] = kSprite_Zora_SurfacingGfx[sprite_delay_main[k] >> 3];
+    }
+    break;
+  case 2:  // Ambulating
+    sprite_graphics[k] = kSprite_Recruit_Gfx[(sprite_subtype2[k] >> 1 & 4) + sprite_D[k]];
+    WalkingZora_Draw(k);
+    if (Sprite_ReturnIfInactive(k))
+      return;
+    Sprite_CheckDamageToAndFromLink(k);
+    Sprite_MoveZ(k);
+    sprite_z_vel[k] -= 2;
+    if (sign8(sprite_z[k] - 1)) {
+      if (sign8(sprite_z_vel[k] + 16))
+        Sprite_ZeroVelocity_XY(k);
+      sprite_z[k] = 0;
+      sprite_z_vel[k] = 0;
+      if (!((k ^ frame_counter) & 15)) {
+        int j = Sprite_DirectionToFaceLink(k, NULL);
+        sprite_head_dir[k] = j;
+        if (!((k ^ frame_counter) & 31)) {
+          sprite_D[k] = j;
+          Sprite_ApplySpeedTowardsLink(k, 8);
+        }
+      }
+    }
+    Sprite_MoveXY(k);
+    Sprite_CheckTileCollision(k);
+    if (sign8(sprite_z[k] - 1)) {
+      WalkingZora_AdjustShadow(k);
+      if (sprite_tiletype == 8) {
+        Sprite_KillSelf(k);
+        SpriteSfx_QueueSfx2WithPan(k, 0x28);
+        sprite_state[k] = 3;
+        sprite_delay_main[k] = 15;
+        sprite_ai_state[k] = 0;
+        sprite_flags2[k] = 3;
+      }
+    }
+    sprite_subtype2[k]++;
+    break;
+  case 3:  // Depressed
+    Sprite_CheckDamageFromLink(k);
+    if (!(frame_counter & 3) && !--sprite_G[k]) {
+      sprite_B[k] = 2;
+      if (sprite_state[k] == 10) {
+        link_state_bits = 0;
+        link_picking_throw_state = 0;
+      }
+      sprite_state[k] = 9;
+    }
+    if (sprite_G[k] < 48 && !(frame_counter & 1))
+      Sprite_SetX(k, Sprite_GetX(k) + (frame_counter & 2 ? -1 : 1));
+    sprite_graphics[k] = 0;
+    sprite_wallcoll[k] = 0;
+    WalkingZora_DrawWaterRipples(k);
+    sprite_flags2[k] -= 2;
+    SpriteDraw_SingleLarge(k);
+    sprite_flags2[k] += 2;
+    sprite_anim_clock[k] = 0;
+    if (Sprite_ReturnIfInactive(k))
+      return;
+    if (Sprite_ReturnIfRecoiling(k))
+      return;
+    Sprite_MoveXY(k);
+    ThrownSprite_TileAndSpriteInteraction(k);
+    WalkingZora_AdjustShadow(k);
+    break;
+  }
+}
+
+void WalkingZora_AdjustShadow(int k) {  // 859edb
+  sprite_anim_clock[k] = (sprite_z[k] == 0 && sprite_tiletype == 9);
+}
+
+void WalkingZora_Draw(int k) {  // 859f08
+  static const uint8 kWalkingZora_Draw_Char[4] = {0xce, 0xce, 0xa4, 0xee};
+  static const uint8 kWalkingZora_Draw_Flags[4] = {0x40, 0, 0, 0};
+  static const uint8 kWalkingZora_Draw_Char2[8] = {0xcc, 0xec, 0xcc, 0xec, 0xe8, 0xe8, 0xca, 0xca};
+  static const uint8 kWalkingZora_Draw_Flags2[8] = {0x40, 0x40, 0, 0, 0, 0x40, 0, 0x40};
+
+  PrepOamCoordsRet info;
+  WalkingZora_DrawWaterRipples(k);
+  if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
+    return;
+  OamEnt *oam = GetOamCurPtr();
+  int g = sprite_graphics[k];
+  if (g == 0 || g == 2)
+    info.y--;
+
+  int i = sprite_head_dir[k];
+  SetOamHelper0(oam + 0, info.x, info.y - 6, kWalkingZora_Draw_Char[i], info.flags | kWalkingZora_Draw_Flags[i], 2);
+  SetOamHelper0(oam + 1, info.x, info.y + 2, kWalkingZora_Draw_Char2[g], info.flags | kWalkingZora_Draw_Flags2[g], 2);
+
+  if (!sprite_anim_clock[k])
+    SpriteDraw_Shadow(k, &info);
+}
+
+void WalkingZora_DrawWaterRipples(int k) {  // 859fe0
+  if (sprite_anim_clock[k])
+    SpriteDraw_WaterRipple_WithOamAdjust(k);
+}
+
+void SpriteDraw_WaterRipple_WithOamAdjust(int k) {  // 859fe5
+  SpriteDraw_WaterRipple(k);
+  oam_cur_ptr += 8;
+  oam_ext_cur_ptr += 2;
+}
+
+void SpriteDraw_WaterRipple(int k) {  // 859ffa
+  static const DrawMultipleData kWaterRipple_Dmd[6] = {
+    {0, 10, 0x01d8, 0},
+    {8, 10, 0x41d8, 0},
+    {0, 10, 0x01d9, 0},
+    {8, 10, 0x41d9, 0},
+    {0, 10, 0x01da, 0},
+    {8, 10, 0x41da, 0},
+  };
+  static const uint8 kWaterRipple_Idx[4] = {0, 1, 2, 1};
+  Sprite_DrawMultiple(k, &kWaterRipple_Dmd[kWaterRipple_Idx[frame_counter >> 2 & 3] * 2], 2, NULL);
+  OamEnt *oam = GetOamCurPtr();
+  uint8 t = (oam[0].flags & 0x30) | 0x4;
+  oam[0].flags = t;
+  oam[1].flags = t | 0x40;
+}
+
+void Sprite_53_ArmosKnight(int k) {  // 85a036
+  static const uint8 kArmosKnight_Gfx1[5] = {5, 4, 3, 2, 1};
+  static const int8 kArmosKnight_Xv[2] = {16, -16};
+
+  sprite_obj_prio[k] |= 0x30;
+  ArmosKnight_Draw(k);
+  if (Sprite_ReturnIfPaused(k))
+    return;
+  if (sprite_state[k] != 9) {
+    if (sprite_delay_main[k]) {
+      sprite_graphics[k] = kArmosKnight_Gfx1[sprite_delay_main[k] >> 3];
+      return;
+    }
+    if (--byte_7E0FF8 == 1) {
+      for (int j = 5; j >= 0; j--) {
+        sprite_health[j] = 48;
+        sprite_x_vel[j] = sprite_y_vel[j] = sprite_z_vel[j] = 0;
+      }
+    }
+    sprite_state[k] = 0;
+    if (Sprite_CheckIfScreenIsClear()) {
+      SpriteSpawnInfo info;
+      int j = Sprite_SpawnDynamically(k, 0xea, &info);
+      assert(j >= 0);
+      Sprite_SetSpawnedCoordinates(j, &info);
+      sprite_z_vel[j] = 32;
+      sprite_A[j] = 1;
+    }
+    return;
+  }
+  Sprite_MoveXY(k);
+  Sprite_MoveZ(k);
+  sprite_z_vel[k] -= 4;
+  if (sign8(sprite_z[k])) {
+    sprite_z_vel[k] = 0;
+    sprite_z[k] = 0;
+    if (byte_7E0FF8 != 1 && sprite_A[k]) {
+      sprite_z_vel[k] = 48;
+      SpriteSfx_QueueSfx3WithPan(k, 0x16);
+    }
+  }
+  if (sprite_F[k]) {
+    Sprite_ZeroVelocity_XY(k);
+    sprite_ai_state[k] = 0;
+    sprite_G[k] = 0;
+  }
+  if (Sprite_ReturnIfRecoiling(k))
+    return;
+  if (!sprite_A[k]) {
+    if (!sprite_delay_main[k]) {
+      sprite_A[k]++;
+      sprite_flags2[k] = (sprite_flags2[k] & 0x7f) - 2;
+      sprite_defl_bits[k] &= ~4;
+      sprite_flags3[k] &= ~0x40;
+    } else {
+      if (sprite_delay_main[k] == 64) {
+        sound_effect_1 = 0x35;
+      } else if (sprite_delay_main[k] < 64) {
+        int j = ((sprite_delay_main[k] >> 1) ^ k) & 1;
+        sprite_x_vel[k] = kArmosKnight_Xv[j];
+        Sprite_MoveX(k);
+        sprite_x_vel[k] = 0;
+      }
+      Sprite_CheckDamageFromLink(k);
+      if (Sprite_CheckDamageToLink_same_layer(k)) {
+        Sprite_NullifyHookshotDrag();
+        Sprite_RepelDash();
+      }
+    }
+  } else if (byte_7E0FF8 == 1) {
+    Sprite_ArmosCrusher(k);
+  } else {
+    Sprite_CheckDamageToAndFromLink(k);
+    if (!sprite_ai_state[k]) {
+      uint16 x = overlord_y_hi[k] << 8 | overlord_x_hi[k];
+      uint16 y = overlord_floor[k] << 8 | overlord_gen2[k];
+      ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLocation(k, x, y, 16);
+      sprite_x_vel[k] = pt.x;
+      sprite_y_vel[k] = pt.y;
+      Sprite_Get16BitCoords(k);
+      if ((uint16)(x - cur_sprite_x + 2) < 4 && (uint16)(y - cur_sprite_y + 2) < 4)
+        sprite_ai_state[k] = 1;
+    } else {
+      sprite_x_lo[k] = overlord_x_hi[k];
+      sprite_x_hi[k] = overlord_y_hi[k];
+      sprite_y_lo[k] = overlord_gen2[k];
+      sprite_y_hi[k] = overlord_floor[k];
+    }
+  }
+}
+
+void ArmosKnight_Draw(int k) {  // 85a274
+  static const int8 kArmosKnight_Draw_X[24] = {
+    -8,  8,  -8,  8, -10, 10, -10, 10, -10, 10, -10, 10, -12, 12, -12, 12,
+    -14, 14, -14, 14, -16, 24, -16, 24,
+  };
+  static const int8 kArmosKnight_Draw_Y[24] = {
+    -8,  -8,  8,  8, -10, -10, 10, 10, -10, -10, 10, 10, -12, -12, 12, 12,
+    -14, -14, 14, 14, -16, -16, 24, 24,
+  };
+  static const uint8 kArmosKnight_Draw_Char[24] = {
+    0xc0, 0xc2, 0xe0, 0xe2, 0xc0, 0xc2, 0xe0, 0xe2, 0xc4, 0xc4, 0xc4, 0xc4, 0xc6, 0xc6, 0xc6, 0xc6,
+    0xc8, 0xc8, 0xc8, 0xc8, 0xd8, 0xd8, 0xd8, 0xd8,
+  };
+  static const uint8 kArmosKnight_Draw_Flags[24] = {
+    0, 0,    0,    0,    0, 0,    0,    0, 0x40, 0, 0xc0, 0x80, 0x40, 0, 0xc0, 0x80,
+    0x40, 0, 0xc0, 0x80, 0x40, 0, 0xc0, 0x80,
+  };
+  static const uint8 kArmosKnight_Draw_Big[24] = {
+    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+    2, 2, 2, 2, 0, 0, 0, 0,
+  };
+
+  PrepOamCoordsRet info;
+  if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
+    return;
+  if (!sprite_A[k] && submodule_index != 7)
+    Oam_AllocateDeferToPlayer(k);
+  OamEnt *oam = GetOamCurPtr();
+  int g = sprite_graphics[k];
+  for (int i = 3; i >= 0; i--, oam++) {
+    int j = g * 4 + i;
+    SetOamHelper0(oam, info.x + kArmosKnight_Draw_X[j], info.y + kArmosKnight_Draw_Y[j],
+                  kArmosKnight_Draw_Char[j], kArmosKnight_Draw_Flags[j] | info.flags,
+                  kArmosKnight_Draw_Big[j]);
+  }
+  if (g != 0)
+    return;
+  if (sprite_A[k]) {
+    int spr_idx = 76 + k * 2;
+    oam_cur_ptr = 0x800 + spr_idx * 4;
+    oam_ext_cur_ptr = 0xA20 + spr_idx;
+  }
+  oam = GetOamCurPtr();
+  int z = sprite_z[k];
+  z = ((z >= 32) ? 32 : z) >> 3;
+  uint16 y = Sprite_GetY(k) - BG2VOFS_copy2;
+  SetOamHelper0(oam + 4, info.x - 8 + z, y + 12, 0xe4, 0x25, 2);
+  SetOamHelper0(oam + 5, info.x + 8 - z, y + 12, 0xe4, 0x25 | 0x40, 2);
+}
+
+void Sprite_54_Lanmolas(int k) {  // 85a3a2
+  static const uint8 kLanmola_RandB[8] = {0x58, 0x50, 0x60, 0x70, 0x80, 0x90, 0xa0, 0x98};
+  static const uint8 kLanmola_RandC[8] = {0x68, 0x60, 0x70, 0x80, 0x90, 0xa0, 0xa8, 0x80};
+  static const int8 kLanmola_ZVel[2] = {2, -2};
+  PrepOamCoordsRet info;
+  Sprite_PrepOamCoord(k, &info);
+  Lanmola_Draw(k);
+  if (Sprite_ReturnIfPaused(k))
+    return;
+  switch(sprite_ai_state[k]) {
+  case 0:
+    if (!(sprite_delay_main[k] | sprite_pause[k])) {
+      sprite_delay_main[k] = 127;
+      sprite_ai_state[k] = 1;
+      SpriteSfx_QueueSfx2WithPan(k, 0x35);
+    }
+    break;
+  case 1:
+    if (!sprite_delay_main[k]) {
+      Lanmola_SpawnShrapnel(k);
+      sound_effect_ambient = 0x13;
+      sprite_B[k] = kLanmola_RandB[GetRandomNumber() & 7];
+      sprite_C[k] = kLanmola_RandC[GetRandomNumber() & 7];
+      sprite_ai_state[k] = 2;
+      sprite_z_vel[k] = 24;
+      sprite_anim_clock[k] = 0;
+      sprite_G[k] = 0;
+lbl_a:
+      sprite_D[k] = sprite_x_lo[k];
+      sprite_wallcoll[k] = sprite_y_lo[k];
+      sprite_delay_aux1[k] = 74;
+    }
+    break;
+  case 2: {
+    Sprite_CheckDamageToAndFromLink(k);
+    Sprite_MoveZ(k);
+    if (!sprite_anim_clock[k]) {
+      if (!--sprite_z_vel[k])
+        sprite_anim_clock[k]++;
+    } else if ((frame_counter & 1) == 0) {
+      int j = sprite_G[k] & 1;
+      if ((sprite_z_vel[k] += kLanmola_ZVel[j]) == (uint8)kDesertBarrier_Xv[j])
+        sprite_G[k]++;
+    }
+    uint16 x = Sprite_GetX(k), y = Sprite_GetY(k);
+    uint16 x2 = sprite_x_hi[k] << 8 | sprite_B[k];
+    uint16 y2 = sprite_y_hi[k] << 8 | sprite_C[k];
+    if ((uint16)(x - x2 + 2) < 4 && (uint16)(y - y2 + 2) < 4)
+      sprite_ai_state[k] = 3;
+    ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLocation(k, x2, y2, 10);
+    sprite_y_vel[k] = pt.y;
+    sprite_x_vel[k] = pt.x;
+    Sprite_MoveXY(k);
+    break;
+  }
+  case 3:
+    Sprite_CheckDamageToAndFromLink(k);
+    Sprite_MoveXY(k);
+    Sprite_MoveZ(k);
+    if (!sign8(sprite_z_vel[k] + 20))
+      sprite_z_vel[k] -= 1;
+    if (sign8(sprite_z[k])) {
+      sprite_ai_state[k] = 4;
+      sprite_delay_main[k] = 128;
+      goto lbl_a;
+    }
+    break;
+  case 4:
+    if (!sprite_delay_main[k]) {
+      sprite_ai_state[k] = 0;
+      sprite_x_lo[k] = kLanmola_RandB[GetRandomNumber() & 7];
+      sprite_y_lo[k] = kLanmola_RandC[GetRandomNumber() & 7];
+    }
+    break;
+  case 5:
+    if (!sprite_delay_main[k]) {
+      sprite_state[k] = 0;
+      if (Sprite_CheckIfScreenIsClear()) {
+        SpriteSpawnInfo info;
+        int j = Sprite_SpawnDynamically(k, 0xEA, &info);
+        assert(j >= 0);
+        Sprite_SetSpawnedCoordinates(j, &info);
+        sprite_z_vel[j] = 32;
+        sprite_A[j] = 3;
+      }
+    }
+    if (sprite_delay_main[k] >= 32 && sprite_delay_main[k] < 160 && !(sprite_delay_main[k] & 15)) {
+      int i = ((sprite_subtype2[k] - garnish_y_lo[k] * 8) & 0x3f) + k * 0x40;
+      uint8 xlo = moldorm_x_lo[i] - BG2HOFS_copy2;
+      uint8 ylo = moldorm_y_lo[i] - beamos_x_hi[i] - BG2VOFS_copy2;
+      SpriteSpawnInfo info;
+      int j = Sprite_SpawnDynamically(k, 0x00, &info);
+      if (j >= 0) {
+        load_chr_halfslot_even_odd = 11;
+        sprite_state[j] = 4;
+        sprite_delay_main[j] = 31;
+        sprite_A[j] = 31;
+        Sprite_SetX(j, BG2HOFS_copy2 + xlo);
+        Sprite_SetY(j, BG2VOFS_copy2 + ylo);
+        sprite_flags2[j] = 3;
+        sprite_oam_flags[j] = 0xc;
+        SpriteSfx_QueueSfx2WithPan(k, 0xc);
+        if (!sign8(garnish_y_lo[k]))
+          garnish_y_lo[k]--;
+      }
+    }
+    break;
+  }
+}
+
+void Lanmola_Draw(int k) {  // 85a64a
+  static const uint8 kLanmola_SprOffs[4] = {76, 60, 44, 28};
+  static const uint8 kLanmola_Draw_Char1[16] = {0xc4, 0xe2, 0xc2, 0xe0, 0xc0, 0xe0, 0xc2, 0xe2, 0xc4, 0xe2, 0xc2, 0xe0, 0xc0, 0xe0, 0xc2, 0xe2};
+  static const uint8 kLanmola_Draw_Char0[16] = {0xcc, 0xe4, 0xca, 0xe6, 0xc8, 0xe6, 0xca, 0xe4, 0xcc, 0xe4, 0xca, 0xe6, 0xc8, 0xe6, 0xca, 0xe4};
+  static const uint8 kLanmola_Draw_Flags[16] = {0xc0, 0xc0, 0xc0, 0xc0, 0x80, 0x80, 0x80, 0x80, 0, 0, 0, 0, 0x40, 0x40, 0x40, 0x40};
+
+  int spr_offs = kLanmola_SprOffs[k];
+  oam_cur_ptr = 0x800 + spr_offs * 4;
+  oam_ext_cur_ptr = 0xA20 + spr_offs;
+  sprite_graphics[k] = Sprite_ConvertVelocityToAngle(sprite_x_vel[k], sprite_y_vel[k] - sprite_z_vel[k]);
+  uint8 r2 = sprite_subtype2[k], r5 = r2;
+  int j = k * 64 + r2;
+  moldorm_x_lo[j] = sprite_x_lo[k];
+  moldorm_y_lo[j] = sprite_y_lo[k];
+  beamos_x_hi[j] = sprite_z[k];
+  beamos_y_hi[j] = sprite_graphics[k];
+  if (sprite_state[k] == 9 && !(submodule_index | flag_unk1))
+    sprite_subtype2[k] = sprite_subtype2[k] + 1 & 63;
+  uint8 r3 = sprite_oam_flags[k] | sprite_obj_prio[k];
+  uint8 n = garnish_y_lo[k];
+  if (sign8(n))
+    return;
+  j = sign8(sprite_y_vel[k]) ? 1 : 0;
+  int oam_step = (j ? -1 : 1);
+  OamEnt *oam = GetOamCurPtr() + (j ? 7 : 0);
+  uint8 i = n;
+  do {
+    int j = r2 + k * 64;
+    r2 = r2 - 8 & 63;
+    oam->x = moldorm_x_lo[j] - BG2HOFS_copy2;
+    if (!sign8(beamos_x_hi[j]))
+      oam->y = moldorm_y_lo[j] - beamos_x_hi[j] - BG2VOFS_copy2;
+    j = beamos_y_hi[j];
+    if (n != 7 || i != 0) {
+      oam->charnum = (n == i) ? kLanmola_Draw_Char1[j] : 0xc6;
+    } else {
+      oam->charnum = kLanmola_Draw_Char0[j];
+    }
+    oam->flags = kLanmola_Draw_Flags[j] | r3;
+    bytewise_extended_oam[oam - oam_buf] = 2;
+  } while (oam += oam_step, !sign8(--i));
+  oam = GetOamCurPtr() + 8;
+  i = n;
+  do {
+    int j = r5 + k * 64;
+    r5 = r5 - 8 & 63;
+    oam->x = moldorm_x_lo[j] - BG2HOFS_copy2;
+    if (!sign8(beamos_x_hi[j]))
+      oam->y = moldorm_y_lo[j] + 10 - BG2VOFS_copy2;
+    oam->charnum = 0x6c;
+    oam->flags = 0x34;
+    bytewise_extended_oam[oam - oam_buf] = 2;
+  } while (oam++, !sign8(--i));
+
+  if (sprite_ai_state[k] == 1) {
+    static const uint8 kLanmola_Draw_Idx2[16] = {4, 5, 4, 5, 4, 5, 4, 5, 4, 3, 2, 2, 1, 1, 0, 0};
+    static const uint8 kLanmola_Draw_Char2[6] = {0xee, 0xee, 0xec, 0xec, 0xce, 0xce};
+    static const uint8 kLanmola_Draw_Flags2[6] = {0, 0x40, 0, 0x40, 0, 0x40};
+    Oam_AllocateFromRegionB(4);
+    OamEnt *oam = GetOamCurPtr();
+    j = kLanmola_Draw_Idx2[sprite_delay_main[k] >> 3];
+    SetOamPlain(oam, sprite_x_lo[k] - BG2HOFS_copy2, sprite_y_lo[k] - BG2VOFS_copy2,
+                 kLanmola_Draw_Char2[j], kLanmola_Draw_Flags2[j] | 0x31, 2);
+  } else if (sprite_ai_state[k] != 5 && sprite_delay_aux1[k] != 0) {
+    static const int8 kLanmola_Draw_X4[8] = {-8, 8, -10, 10, -16, 16, -24, 32};
+    static const int8 kLanmola_Draw_Y4[8] = {0, 0, -1, -1, -1, -1, 3, 3};
+    static const uint8 kLanmola_Draw_Char4[8] = {0xe8, 0xe8, 0xe8, 0xe8, 0xea, 0xea, 0xea, 0xea};
+    static const uint8 kLanmola_Draw_Flags4[8] = {0, 0x40, 0, 0x40, 0, 0x40, 0, 0x40};
+    static const uint8 kLanmola_Draw_Big4[8] = {2, 2, 2, 2, 2, 2, 0, 0};
+
+    if (((sprite_y_vel[k] >> 6) ^ sprite_ai_state[k]) & 2)
+      Oam_AllocateFromRegionB(8);
+    else
+      Oam_AllocateFromRegionC(8);
+    OamEnt *oam = GetOamCurPtr();
+    uint8 r6 = (((sprite_delay_aux1[k] >> 2) & 3) ^ 3) * 2;
+    uint8 x = sprite_D[k] - BG2HOFS_copy2;
+    uint8 y = sprite_wallcoll[k] - BG2VOFS_copy2;
+    for (int i = 1; i >= 0; i--, oam++) {
+      int j = i + r6;
+      SetOamPlain(oam, x + kLanmola_Draw_X4[j], y + kLanmola_Draw_Y4[j], kLanmola_Draw_Char4[j], kLanmola_Draw_Flags4[j] | 0x31, kLanmola_Draw_Big4[j]);
+    }
+  }
+}
+
+void Sprite_6D_Rat(int k) {  // 85a8b0
+  static const uint8 kSpriteRat_Tab0[16] = {0, 0, 3, 3, 1, 2, 4, 5, 1, 2, 4, 5, 0, 0, 3, 3};
+  static const uint8 kSpriteRat_Tab1[16] = {0, 0x40, 0, 0x40, 0, 0, 0, 0, 0x40, 0x40, 0x40, 0x40, 0x80, 0xc0, 0x80, 0xc0};
+  static const uint8 kSpriteRat_Tab2[8] = {10, 11, 6, 7, 2, 3, 14, 15};
+  static const uint8 kSpriteRat_Tab4[8] = {8, 9, 4, 5, 0, 1, 12, 13};
+  static const int8 kSpriteRat_Xvel[4] = {24, -24, 0, 0};
+  static const int8 kSpriteRat_Yvel[4] = {0, 0, 24, -24};
+  static const uint8 kSpriteRat_Tab3[4] = {2, 3, 1, 0};
+
+  int j = sprite_A[k];
+  sprite_graphics[k] = kSpriteRat_Tab0[j];
+  sprite_oam_flags[k] = (sprite_oam_flags[k] & 0x3f) | kSpriteRat_Tab1[j];
+  SpriteDraw_SingleLarge(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  if (Sprite_ReturnIfRecoiling(k))
+    return;
+  Sprite_CheckDamageToAndFromLink(k);
+  Sprite_MoveXY(k);
+  Sprite_CheckTileCollision(k);
+  if (sprite_ai_state[k] != 0) {
+    if (sprite_delay_main[k] == 0) {
+      if (is_in_dark_world == 0)
+        SpriteSfx_QueueSfx3WithPan(k, 0x17);
+      sprite_ai_state[k] = 0;
+      sprite_delay_main[k] = 80;
+    }
+    j = sprite_D[k];
+    if (sprite_wallcoll[k] != 0)
+      sprite_D[k] = j = kSpriteRat_Tab3[j];
+    sprite_x_vel[k] = kSpriteRat_Xvel[j];
+    sprite_y_vel[k] = kSpriteRat_Yvel[j];
+    sprite_A[k] = kSpriteRat_Tab4[sprite_D[k] * 2 + (frame_counter >> 2 & 1)];
+  } else {
+    Sprite_ZeroVelocity_XY(k);
+    if (sprite_delay_main[k] == 0) {
+      uint8 a = GetRandomNumber();
+      sprite_D[k] = a & 3;
+      sprite_ai_state[k]++;
+      sprite_delay_main[k] = (a & 0x7f) + 0x40;
+    }
+    sprite_A[k] = kSpriteRat_Tab2[sprite_D[k] * 2 + (frame_counter >> 3 & 1)];
+  }
+}
+
+void Sprite_6E_Rope(int k) {  // 85a973
+  int j;
+  j = sprite_A[k];
+  sprite_graphics[k] = kSpriteRope_Gfx[j];
+  sprite_oam_flags[k] = (sprite_oam_flags[k] & 0x3f) | kSpriteRope_Flags[j];
+  SpriteDraw_SingleLarge(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  if (sprite_E[k]) {
+    OamEnt *oam = GetOamCurPtr();
+    oam[0].flags |= 0x30;
+
+    uint8 old_z = sprite_z[k];
+    Sprite_MoveZ(k);
+    if (!sign8(sprite_z_vel[k] - 0xc0))
+      sprite_z_vel[k] -= 2;
+    if (!sign8(old_z ^ sprite_z[k]) || !sign8(sprite_z[k]))
+      return;
+    sprite_z[k] = 0;
+    sprite_z_vel[k] = 0;
+    sprite_E[k] = 0;
+    sprite_flags3[k] &= ~0x10;
+  } else {
+    sprite_flags2[k] = 0;
+    if (Sprite_ReturnIfRecoiling(k))
+      return;
+    Sprite_CheckDamageToAndFromLink(k);
+    Sprite_MoveXY(k);
+    Sprite_CheckTileCollision(k);
+    if (sprite_ai_state[k] != 0) {
+      if (sprite_delay_main[k] == 0) {
+        sprite_ai_state[k] = 0;
+        sprite_delay_main[k] = 32;
+      }
+      j = sprite_D[k];
+      if (sprite_wallcoll[k] != 0)
+        sprite_D[k] = j = kSpriteRope_Tab0[j];
+
+      j += sprite_G[k];
+      sprite_x_vel[k] = kSpriteRope_Xvel[j];
+      sprite_y_vel[k] = kSpriteRope_Yvel[j];
+
+      int i = frame_counter;
+      if (j < 4)
+        i >>= 1;
+
+      sprite_A[k] = kSpriteRope_Tab1[sprite_D[k] * 2 + (i >> 1 & 1)];
+    } else {
+      Sprite_ZeroVelocity_XY(k);
+      if (sprite_delay_main[k] == 0) {
+        sprite_G[k] = 0;
+        uint8 a = GetRandomNumber();
+        sprite_D[k] = a & 3;
+        sprite_ai_state[k]++;
+        sprite_delay_main[k] = (a & 0x7f) + 0x40;
+
+        PointU8 pt;
+        uint8 dir = Sprite_DirectionToFaceLink(k, &pt);
+        if ((uint8)(pt.y + 0x10) < 0x20 || (uint8)(pt.x + 0x18) < 0x20) {
+          sprite_G[k] = 4;
+          sprite_D[k] = dir;
+        }
+      }
+      sprite_A[k] = kSpriteRope_Tab1[sprite_D[k] * 2 + (frame_counter >> 3 & 1)];
+    }
+  }
+}
+
+void Sprite_6F_Keese(int k) {  // 85aa8b
+  static const int8 kSpriteKeese_Tab1[2] = {1, -1};
+  static const int8 kSpriteKeese_Tab0[4] = {2, 10, 6, 14};
+
+  sprite_obj_prio[k] |= 0x30;
+  SpriteDraw_SingleLarge(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  if (Sprite_ReturnIfRecoiling(k))
+    return;
+  Sprite_CheckDamageToAndFromLink(k);
+  Sprite_MoveXY(k);
+  if (sprite_ai_state[k]) {
+    if (sprite_delay_main[k] == 0) {
+      sprite_ai_state[k] = 0;
+      sprite_delay_main[k] = 64;
+      sprite_graphics[k] = 0;
+      Sprite_ZeroVelocity_XY(k);
+    } else {
+      if ((sprite_delay_main[k] & 7) == 0) {
+        sprite_A[k] += kSpriteKeese_Tab1[sprite_B[k] & 1];
+        if (!(GetRandomNumber() & 3))
+          sprite_B[k]++;
+      }
+      int j = sprite_A[k] & 0xf;
+      sprite_x_vel[k] = kSpriteKeese_Tab2[j];
+      sprite_y_vel[k] = kSpriteKeese_Tab3[j];
+      sprite_graphics[k] = ((frame_counter >> 2) & 1) + 1;
+    }
+  } else {
+    if ((k ^ frame_counter) & 3 | sprite_delay_main[k])
+      return;
+
+    PointU8 pt;
+    uint8 dir = Sprite_DirectionToFaceLink(k, &pt);
+    if ((uint8)(pt.y + 0x28) >= 0x50 || (uint8)(pt.x + 0x28) >= 0x50)
+      return;
+    SpriteSfx_QueueSfx3WithPan(k, 0x1e);
+    sprite_ai_state[k]++;
+    sprite_delay_main[k] = 64;
+    sprite_B[k] = 64;
+    sprite_A[k] = kSpriteKeese_Tab0[dir];
+  }
+}
+
+void Sprite_Cannonball(int k) {  // 85ab54
+  SpriteDraw_SingleLarge(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  Sprite_MoveXY(k);
+  if (sprite_delay_main[k] == 30) {
+    Sprite_SpawnPoofGarnish(k);
+  } else if (sprite_delay_main[k] == 0 && Sprite_CheckTileCollision(k)) {
+    sprite_state[k] = 0;
+    sprite_x_lo[k] += 4;
+    sprite_y_lo[k] += 4;
+    Sprite_PlaceRupulseSpark_2(k);
+    SpriteSfx_QueueSfx2WithPan(k, 0x5);
+  }
+  Sprite_CheckDamageToAndFromLink(k);
+}
+
+void Sprite_SpawnPoofGarnish(int j) {  // 85ab9c
+  int k = GarnishAllocForce();
+  garnish_type[k] = 10;
+  garnish_active = 10;
+  garnish_x_lo[k] = sprite_x_lo[j];
+  garnish_x_hi[k] = sprite_x_hi[j];
+  int y = Sprite_GetY(j) + 16;
+  garnish_y_lo[k] = y;
+  garnish_y_hi[k] = y >> 8;
+  garnish_sprite[k] = sprite_floor[j];
+  garnish_countdown[k] = 15;
+}
+
+void Sprite_6C_MirrorPortal(int k) {  // 85af75
+  if (savegame_is_darkworld) {
+    sprite_state[k] = 0;
+  } else {
+    if (BYTE(overworld_screen_index) >= 0x80)
+      return;
+
+    if (submodule_index != 0x23 && byte_7E0FC6 < 3)
+      SpriteDraw_SingleLarge(k);
+    if (Sprite_ReturnIfInactive(k))
+      return;
+    int j = frame_counter >> 2 & 3;
+    sprite_oam_flags[k] = sprite_oam_flags[k] & 0x3f | kSprite_WarpVortex_Flags[j];
+    if (Sprite_CheckIfLinkIsBusy())
+      return;
+    if (Sprite_CheckDamageToLink_same_layer(k)) {
+      if (sprite_A[k] && (link_disable_sprite_damage | countdown_for_blink) == 0 && !flag_is_link_immobilized) {
+        submodule_index = 0x23;
+        link_triggered_by_whirlpool_sprite = 1;
+        subsubmodule_index = 0;
+        link_actual_vel_y = 0;
+        link_actual_vel_x = 0;
+        link_player_handler_state = kPlayerState_Mirror;
+        last_light_vs_dark_world = overworld_screen_index & 0x40;
+        sprite_state[k] = 0;
+      }
+    } else {
+      sprite_A[k] = 1;
+    }
+  }
+  if (++sprite_B[k] == 0)
+    sprite_A[k] = 1;
+  sprite_x_lo[k] = bird_travel_x_lo[15];
+  sprite_x_hi[k] = bird_travel_x_hi[15];
+  int t = (bird_travel_y_lo[15] | (bird_travel_y_hi[15] << 8)) + 8;
+  sprite_y_lo[k] = t;
+  sprite_y_hi[k] = t >> 8;
+}
+
+void Sprite_6A_BallNChain(int k) {  // 85b01b
+  ChainBallTrooper_Draw(k);
+  if (sprite_ai_state[k] < 2)
+    HIBYTE(dungmap_var8) = 0x80;
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  Guard_ParrySwordAttacks(k);
+
+  int t = sprite_B[k] << 8 | sprite_A[k];
+  t += kChainBallTrooper_Tab1[sprite_ai_state[k]];
+  sprite_A[k] = t;
+  sprite_B[k] = t >> 8 & 1;
+  if (Sprite_ReturnIfRecoiling(k))
+    return;
+  Sprite_CheckTileCollision(k);
+  Sprite_MoveXY(k);
+  Sprite_CheckDamageToLink(k);
+
+  PointU8 pt = { 0, 0 };
+
+  if (((k ^ frame_counter) & 0xf) == 0)
+    sprite_head_dir[k] = Sprite_DirectionToFaceLink(k, &pt);
+
+  switch (sprite_ai_state[k]) {
+  case 0:
+    if (((k ^ frame_counter) & 0xf) == 0) {
+      sprite_D[k] = sprite_head_dir[k];
+      if ((uint8)(pt.y + 0x40) < 0x68 && (uint8)(pt.x + 0x30) < 0x60) {
+        sprite_ai_state[k]++;
+        sprite_delay_main[k] = 24;
+        return;
+      }
+      Sprite_ApplySpeedTowardsLink(k, 8);
+    }
+    BallNChain_Animate(k);
+    break;
+  case 1:
+    Sprite_ZeroVelocity_XY(k);
+    if (!sprite_delay_main[k]) {
+      sprite_delay_main[k] = 48;
+      sprite_ai_state[k]++;
+    }
+    break;
+  case 2:
+    if (!sprite_delay_main[k] &&
+        sprite_head_dir[k] == kFlailTrooperAttackDir[(sprite_A[k] >> 7 & 1) + sprite_B[k] * 2]) {
+      sprite_ai_state[k]++;
+      sprite_delay_aux2[k] = 31;
+    }
+attack_common:
+    sprite_subtype2[k]++;
+    BallNChain_Animate(k);
+    if (((k ^ frame_counter) & 0xf) == 0)
+      SpriteSfx_QueueSfx3WithPan(k, 6);
+    break;
+  case 3:
+    Sprite_ZeroVelocity_XY(k);
+    t = sprite_delay_aux2[k];
+    if (t == 0)
+      sprite_ai_state[k] = 0;
+    else if (t >= 0x10)
+      goto attack_common;
+    sprite_subtype2[k]++;
+    BallNChain_Animate(k);
+    break;
+  }
+}
+
+void BallNChain_Animate(int k) {  // 85b0ab
+  sprite_graphics[k] = kFlailTrooperGfx[sprite_D[k] * 8 + (++sprite_subtype2[k] >> 2 & 7)];
+}
+
+void SpriteDraw_GuardHead(int k, PrepOamCoordsRet *info, int spr_offs) {  // 85b160
+  int j = sprite_head_dir[k];
+  OamEnt *oam = GetOamCurPtr() + spr_offs;
+  SetOamHelper0(oam, info->x, info->y - 9, kChainBallTrooperHead_Char[j], info->flags | kChainBallTrooperHead_Flags[j], 2);
+}
+
+void SpriteDraw_BNCBody(int k, PrepOamCoordsRet *info, int spr_offs) {  // 85b3cb
+  int g = sprite_graphics[k];
+  spr_offs += kFlailTrooperBody_SprOffs[g] >> 2;
+  OamEnt *oam = GetOamCurPtr() + spr_offs;
+  int n = kFlailTrooperBody_Num[g];
+  do {
+    int j = g * 3 + n;
+    SetOamHelper0(oam, info->x + kFlailTrooperBody_X[j], info->y + kFlailTrooperBody_Y[j],
+                  kFlailTrooperBody_Char[j], info->flags | kFlailTrooperBody_Flags[j],
+                  kFlailTrooperBody_Big[j]);
+    if (n == 2)
+      oam++;
+  } while (oam++, --n >= 0);
+}
+
+void SpriteDraw_BNCFlail(int k, PrepOamCoordsRet *info) {  // 85b468
+  OamEnt *oam = GetOamCurPtr();
+
+  BYTE(dungmap_var7) = info->x;
+  HIBYTE(dungmap_var7) = info->y;
+
+  uint8 t;
+  uint16 r0 = sprite_A[k] | sprite_B[k] << 8;
+  uint8 qq = sprite_ai_state[k] < 2 ? 0 : kFlailTrooperWeapon_Tab0[sprite_delay_aux2[k]];
+  uint8 r12 = kFlailTrooperWeapon_Tab1[sprite_D[k]];
+  uint8 r13 = kFlailTrooperWeapon_Tab2[sprite_D[k]];
+
+  uint16 r2 = (r0 + 0x80) & 0x1ff;
+
+  uint8 r14 = ChainBallMult(kSinusLookupTable[r0 & 0xff], qq);
+  uint8 r4 = (r0 & 0x100) ? -r14 : r14;
+
+  uint8 r15 = ChainBallMult(kSinusLookupTable[r2 & 0xff], qq);
+  uint8 r6 = (r2 & 0x100) ? -r15 : r15;
+
+  HIBYTE(dungmap_var8) = r4 - 4 + r12;
+  BYTE(dungmap_var8) = r6 - 4 + r13;
+
+  SetOamPlain(oam, HIBYTE(dungmap_var8) + BYTE(dungmap_var7), BYTE(dungmap_var8) + HIBYTE(dungmap_var7), 0x2a, 0x2d, 2);
+  oam++;
+
+  for (int i = 3; i >= 0; i--, oam++) {
+    t = (kFlailTrooperWeapon_Tab4[i] * r14) >> 8;
+    t = sign8(r4) ? -t : t;
+    uint8 x = t + BYTE(dungmap_var7) + r12;
+    uint8 ty = (kFlailTrooperWeapon_Tab4[i] * r15) >> 8;
+    ty = sign8(r6) ? -ty : ty;
+    uint8 y = ty + HIBYTE(dungmap_var7) + r13;
+    SetOamPlain(oam, x, y, 0x3f, 0x2d, 0);
+  }
+  Sprite_CorrectOamEntries(k, 4, 0xff);
+}
+
+void Sprite_50_Cannonball(int k) {  // 85b648
+  if (!sprite_ai_state[k])
+    SpriteDraw_SingleLarge(k);
+  else
+    SpriteDraw_BigCannonball(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  sprite_graphics[k] = ++sprite_subtype2[k] >> 2 & 1;
+  Sprite_MoveXY(k);
+  if (sprite_delay_main[k]) {
+    if (sprite_delay_main[k] == 1)
+      sprite_state[k] = 0;
+    return;
+  }
+  Sprite_CheckDamageToAndFromLink(k);
+  if (!sprite_delay_aux2[k] && Sprite_CheckTileCollision(k))
+    sprite_delay_main[k] = 16;
+}
+
+void SpriteDraw_BigCannonball(int k) {  // 85b6a4
+  static const int8 kMetalBallLarge_X[4] = {-8, 8, -8, 8};
+  static const int8 kMetalBallLarge_Y[4] = {-8, -8, 8, 8};
+  static const uint8 kMetalBallLarge_Char[8] = {0x84, 0x88, 0x88, 0x88, 0x86, 0x88, 0x88, 0x88};
+  static const uint8 kMetalBallLarge_Flags[4] = {0, 0, 0xc0, 0x80};
+
+  PrepOamCoordsRet info;
+  if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
+    return;
+  OamEnt *oam = GetOamCurPtr();
+  int g = sprite_graphics[k];
+  for (int i = 3; i >= 0; i--, oam++) {
+    SetOamHelper0(oam, info.x + kMetalBallLarge_X[i], info.y + kMetalBallLarge_Y[i],
+                  kMetalBallLarge_Char[g * 4 + i], kMetalBallLarge_Flags[i] | info.flags, 2);
+  }
+}
+
+void Sprite_51_ArmosStatue(int k) {  // 85b703
+  Armos_Draw(k);
+  if (sprite_F[k])
+    Sprite_ZeroVelocity_XY(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  Sprite_MoveZ(k);
+  sprite_z_vel[k] -= 2;
+  if (sign8(sprite_z[k])) {
+    sprite_z[k] = 0;
+    sprite_z_vel[k] = 0;
+    Sprite_ZeroVelocity_XY(k);
+  }
+  if (!sprite_ai_state[k]) {
+    sprite_flags3[k] |= 0x40;
+    if (sprite_delay_main[k] == 1) {
+      sprite_flags3[k] &= ~0x40;
+      sprite_ai_state[k]++;
+      sprite_flags2[k] &= ~0x80;
+      sprite_flags3[k] &= ~0x40;
+      sprite_oam_flags[k] = 0xb;
+    } else {
+      if (!((k ^ frame_counter) & 3) &&
+          (uint16)(link_x_coord - cur_sprite_x + 31) < 62 &&
+          (uint16)(link_y_coord + 8 - cur_sprite_y + 48) < 88 && !sprite_delay_main[k]) {
+        sprite_delay_main[k] = 48;
+        SpriteSfx_QueueSfx2WithPan(k, 0x22);
+      }
+      if (Sprite_CheckDamageToLink_same_layer(k)) {
+        Sprite_NullifyHookshotDrag();
+        Sprite_RepelDash();
+      }
+      if (sprite_delay_main[k])
+        sprite_oam_flags[k] ^= (sprite_delay_main[k] >> 1) & 0xe;
+    }
+  } else {
+    Sprite_CheckDamageToAndFromLink(k);
+    if (Sprite_ReturnIfRecoiling(k))
+      return;
+    Sprite_MoveXY(k);
+    Sprite_CheckTileCollision(k);
+    if ((sprite_delay_main[k] | sprite_z[k]) == 0) {
+      sprite_delay_main[k] = 8;
+      sprite_z_vel[k] = 16;
+      Sprite_ApplySpeedTowardsLink(k, 12);
+    }
+  }
+}
+
+void Armos_Draw(int k) {  // 85b7ef
+  static const DrawMultipleData kArmos_Dmd[2] = {
+    {0, -16, 0x00c0, 2},
+    {0,   0, 0x00e0, 2},
+  };
+  PrepOamCoordsRet info;
+  if (!sprite_ai_state[k]) {
+    if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
+      return;
+  }
+  Sprite_DrawMultiple(k, &kArmos_Dmd[0], 2, &info);
+  SpriteDraw_Shadow(k, &info);
+}
+
+void Sprite_4E_Popo(int k) {  // 85b80a
+  Bot_Draw(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  if (Sprite_ReturnIfRecoiling(k))
+    return;
+  sprite_subtype2[k]++;
+  sprite_A[k] = sprite_subtype2[k] >> 4 & 3;
+  Sprite_CheckDamageToAndFromLink(k);
+  switch (sprite_ai_state[k]) {
+  case 0:
+    if (!sprite_delay_main[k]) {
+      sprite_ai_state[k] = 1;
+      sprite_delay_main[k] = 105;
+    }
+    break;
+  case 1:
+    sprite_subtype2[k]++;
+    if (!sprite_delay_main[k]) {
+      sprite_delay_main[k] = (GetRandomNumber() & 63) + 128;
+      sprite_ai_state[k]++;
+      int j = GetRandomNumber() & 15;
+      sprite_x_vel[k] = kSpriteKeese_Tab2[j] << 2;
+      sprite_y_vel[k] = kSpriteKeese_Tab3[j] << 2;
+    }
+    break;
+  case 2:
+    sprite_subtype2[k]++;
+    if (sprite_delay_main[k]) {
+      if ((k ^ frame_counter) & sprite_B[k]) {
+        Sprite_CheckTileCollision(k);
+        return;
+      }
+      Sprite_MoveXY(k);
+      if (!sprite_wallcoll[k]) {
+        Sprite_CheckTileCollision(k);
+        return;
+      }
+    }
+    sprite_ai_state[k] = 0;
+    sprite_delay_main[k] = 80;
+    break;
+  }
+}
+
+void Bot_Draw(int k) {  // 85b89a
+  static const uint8 kBot_Gfx[4] = {0, 1, 0, 1};
+  static const uint8 kBot_OamFlags[4] = {0, 0, 0x40, 0x40};
+  int j = sprite_A[k];
+  sprite_graphics[k] = kBot_Gfx[j];
+  sprite_oam_flags[k] = sprite_oam_flags[k] & ~0x40 | kBot_OamFlags[j];
+  SpriteDraw_SingleLarge(k);
+}
+
+void Sprite_4C_Geldman(int k) {  // 85b8b3
+  static const uint8 kGerudoMan_EmergeGfx[8] = {3, 2, 0, 0, 0, 0, 0, 0};
+  static const uint8 kGerudoMan_PursueGfx[2] = {4, 5};
+  static const uint8 kGerudoMan_SubmergeGfx[5] = {0, 1, 2, 3, 3};
+  PrepOamCoordsRet info;
+  if (sprite_ai_state[k] < 2)
+    Sprite_PrepOamCoord(k, &info);
+  else
+    GerudoMan_Draw(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  if (Sprite_ReturnIfRecoiling(k))
+    return;
+  sprite_ignore_projectile[k] = 1;
+  switch (sprite_ai_state[k]) {
+  case 0:  // return
+    if (!sprite_delay_main[k]) {
+      sprite_x_lo[k] = sprite_A[k];
+      sprite_x_hi[k] = sprite_B[k];
+      sprite_y_lo[k] = sprite_C[k];
+      sprite_y_hi[k] = sprite_head_dir[k];
+      sprite_ai_state[k] = 1;
+    }
+    break;
+  case 1:  // wait
+    if (!((k ^ frame_counter) & 7) &&
+        (uint16)(link_x_coord - cur_sprite_x + 0x30) < 0x60 &&
+        (uint16)(link_y_coord - cur_sprite_y + 0x30) < 0x60) {
+      sprite_ai_state[k] = 2;
+      sprite_delay_main[k] = 31;
+    }
+    break;
+  case 2:  // emerge
+    if (!sprite_delay_main[k]) {
+      sprite_ai_state[k] = 3;
+      sprite_delay_main[k] = 96;
+      Sprite_ApplySpeedTowardsLink(k, 16);
+    } else {
+      sprite_graphics[k] = kGerudoMan_EmergeGfx[sprite_delay_main[k] >> 2];
+    }
+    break;
+  case 3:  // pursue
+    sprite_ignore_projectile[k] = 0;
+    if (!sprite_delay_main[k]) {
+      sprite_ai_state[k] = 4;
+      sprite_delay_main[k] = 8;
+    } else {
+      sprite_graphics[k] = kGerudoMan_PursueGfx[sprite_delay_main[k] >> 2 & 1];
+      Sprite_CheckDamageToAndFromLink(k);
+      Sprite_MoveXY(k);
+    }
+    break;
+  case 4:  // submerge
+    if (!sprite_delay_main[k]) {
+      sprite_ai_state[k] = 0;
+      sprite_delay_main[k] = 16;
+    } else {
+      sprite_graphics[k] = kGerudoMan_SubmergeGfx[sprite_delay_main[k] >> 1];
+    }
+    break;
+  }
+}
+
+void GerudoMan_Draw(int k) {  // 85ba24
+  static const int8 kGerudoMan_Draw_X[18] = { 4, 4, 4, 4, 4, 4, -8, 8, 8, -8, 8, 8, -16, 0, 16, -16, 0, 16 };
+  static const int8 kGerudoMan_Draw_Y[18] = { 8, 8, 8, 8, 8, 8, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+  static const uint8 kGerudoMan_Draw_Char[18] = {
+    0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa4, 0xa2, 0xa0, 0xa0, 0xa2, 0xa4,
+  };
+  static const uint8 kGerudoMan_Draw_Flags[18] = {
+    0, 0, 0, 0x40, 0x40, 0x40, 0, 0x40, 0x40, 0, 0x40, 0x40, 0x40, 0x40, 0x40, 0, 0, 0,
+  };
+  static const uint8 kGerudoMan_Draw_Big[18] = { 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 };
+  PrepOamCoordsRet info;
+  if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
+    return;
+  OamEnt *oam = GetOamCurPtr();
+  int g = sprite_graphics[k];
+  for (int i = 2; i >= 0; i--, oam++) {
+    int j = g * 3 + i;
+    SetOamHelper0(oam, info.x + kGerudoMan_Draw_X[j], info.y + kGerudoMan_Draw_Y[j],
+                  kGerudoMan_Draw_Char[j], kGerudoMan_Draw_Flags[j] | info.flags, kGerudoMan_Draw_Big[j]);
+  }
+}
+
+void Sprite_4D_Toppo(int k) {  // 85ba85
+  static const int8 kToppo_XOffs[4] = {-32, 32, 0, 0};
+  static const int8 kToppo_YOffs[4] = {0, 0, -32, 32};
+
+  if (sprite_ai_state[k]) {
+    sprite_obj_prio[k] |= 0x30;
+    Toppo_Draw(k);
+  }
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  switch (sprite_ai_state[k]) {
+  case 0:  // Toppo_Hiding
+    if (!sprite_delay_main[k]) {
+      sprite_ai_state[k] = 1;
+      sprite_delay_main[k] = 8;
+      int j = GetRandomNumber() & 3;
+      uint16 x = sprite_A[k] | sprite_B[k] << 8;
+      uint16 y = sprite_C[k] | sprite_head_dir[k] << 8;
+      Sprite_SetX(k, x + kToppo_XOffs[j]);
+      Sprite_SetY(k, y + kToppo_YOffs[j]);
+    }
+    break;
+  case 1:  // Toppo_RustleGrass
+    if (!sprite_delay_main[k]) {
+      sprite_ai_state[k] = 2;
+      sprite_delay_main[k] = 16;
+    } else {
+      sprite_graphics[k] = sprite_delay_main[k] >> 2 & 1;
+      Toppo_VerifyTile(k);
+    }
+    break;
+  case 2:  // Toppo_PokingOut
+    if (!sprite_delay_main[k]) {
+      sprite_ai_state[k] = 3;
+      sprite_z_vel[k] = 64;
+    }
+    sprite_graphics[k] = 2;
+    Toppo_VerifyTile(k);
+    break;
+  case 3:  // Toppo_Leaping
+    Sprite_CheckDamageToAndFromLink(k);
+    Sprite_MoveZ(k);
+    sprite_z_vel[k] -= 2;
+    if (sign8(sprite_z[k])) {
+      sprite_z[k] = 0;
+      sprite_ai_state[k] = 4;
+      sprite_delay_main[k] = 16;
+      Toppo_VerifyTile(k);
+    }
+    break;
+  case 4:  // Toppo_Retreat
+    if (!sprite_delay_main[k]) {
+      sprite_ai_state[k] = 0;
+      sprite_delay_main[k] = 32;
+    } else {
+      sprite_graphics[k] = sprite_delay_main[k] >> 2 & 1;
+    }
+    Toppo_VerifyTile(k);
+    break;
+  case 5:  // Toppo_Flustered
+    Toppo_Flustered(k);
+    break;
+  }
+}
+
+void Toppo_VerifyTile(int k) {  // 85bb72
+  uint16 x = Sprite_GetX(k);
+  if (GetTileAttribute(0, &x, Sprite_GetY(k)) != 0x40)
+    sprite_ai_state[k] = 5;
+}
+
+void Toppo_Draw(int k) {  // 85bbff
+  static const int8 kToppo_Draw_X[15] = {0, 8, 8, 0, 8, 8, 0, 0, 8, 0, 0, 0, 0, 0, 0};
+  static const int8 kToppo_Draw_Y[15] = {8, 8, 8, 8, 8, 8, 0, 8, 8, 0, 0, 0, 0, 0, 0};
+  static const uint8 kToppo_Draw_Char[15] = {0xc8, 0xc8, 0xc8, 0xca, 0xca, 0xca, 0xc0, 0xc8, 0xc8, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2};
+  static const uint8 kToppo_Draw_Flags[15] = {0, 0x40, 0x40, 0, 0x40, 0x40, 0, 0, 0x40, 0, 0, 0, 0x40, 0x40, 0x40};
+  static const uint8 kToppo_Draw_Big[15] = {0, 0, 0, 0, 0, 0, 2, 0, 0, 2, 2, 2, 2, 2, 2};
+
+  PrepOamCoordsRet info;
+  if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
+    return;
+  OamEnt *oam = GetOamCurPtr();
+  int g = sprite_graphics[k];
+  uint16 ybase = Sprite_GetY(k) - BG2VOFS_copy2;
+  for (int i = 2; i >= 0; i--, oam++) {
+    int j = i + g * 3;
+    uint8 big = kToppo_Draw_Big[j];
+    uint8 flags = kToppo_Draw_Flags[j] | info.flags;
+    if (big == 0)
+      flags = flags & ~0xf | 2;
+    SetOamHelper0(oam,
+                  info.x + kToppo_Draw_X[j],
+                  (big ? info.y : ybase) + kToppo_Draw_Y[j],
+                  kToppo_Draw_Char[j], flags, big);
+  }
+}
+
+void Sprite_4B_GreenKnifeGuard(int k) {  // 85bca2
+  sprite_graphics[k] = kSprite_Recruit_Gfx[sprite_D[k] + (sprite_subtype2[k] >> 1 & 4) ];
+  Recruit_Draw(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  if (Sprite_ReturnIfRecoiling(k))
+    return;
+  Sprite_CheckDamageToAndFromLink(k);
+  Sprite_MoveXY(k);
+  Sprite_CheckTileCollision(k);
+  if (sprite_ai_state[k] != 0) {
+    GreenKnifeGuard_Moving(k);
+    return;
+  }
+  if (sprite_delay_main[k] != 0)
+    return;
+
+  sprite_delay_main[k] = (GetRandomNumber() & 0x3f) + 0x30;
+  sprite_ai_state[k]++;
+  sprite_D[k] = sprite_head_dir[k];
+  PointU8 out;
+  int j = sprite_D[k];
+  if (j == Sprite_DirectionToFaceLink(k, &out) &&
+     (((uint8)(out.x + 0x10) < 0x20) || ((uint8)(out.y + 0x10) < 0x20))) {
+    j += 4;
+    sprite_delay_main[k] = 128;
+  }
+  sprite_x_vel[k] = kSprite_Recruit_Xvel[j];
+  sprite_y_vel[k] = kSprite_Recruit_Yvel[j];
+}
+
+void GreenKnifeGuard_Moving(int k) {  // 85bd1e
+  uint8 t = 0x10;
+
+  if (sprite_wallcoll[k] == 0) {
+    if (sprite_delay_main[k] != 0)
+      goto out;
+    t = 0x30;
+  }
+  sprite_delay_main[k] = t;
+  Sprite_ZeroVelocity_XY(k);
+  sprite_head_dir[k] = kRecruit_Moving_HeadDir[sprite_D[k] * 2 | (GetRandomNumber() & 1)];
+  sprite_ai_state[k] = 0;
+out:
+  sprite_subtype2[k] += (sprite_delay_aux1[k] != 0) ? 2 : 1;
+}
+
+void Recruit_Draw(int k) {  // 85bd7e
+  PrepOamCoordsRet info;
+  if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
+    return;
+  OamEnt *oam = GetOamCurPtr();
+  int hd = sprite_head_dir[k];
+  SetOamHelper0(oam + 0, info.x, info.y - 11, kSoldier_Draw1_Char[hd], kSoldier_Draw1_Flags[hd] | info.flags, 2);
+  int r6 = sprite_graphics[k];
+  SetOamHelper0(oam + 1, info.x + kRecruit_Draw_X[r6], info.y, kRecruit_Draw_Char[r6], kRecruit_Draw_Flags[r6] | info.flags, 2);
+  SpriteDraw_Shadow(k, &info);
+}
+
+void Sprite_4A_BombGuard(int k) {  // 85be0a
+  if (sprite_C[k] == 0) {
+    BombGuard(k);
+    return;
+  }
+  if (sprite_C[k] < 2) {
+    SpriteBomb_ExplosionIncoming(k);
+    return;
+  }
+
+  if (sprite_C[k] == 2) {
+    for (int j = 15; j >= 0; j--) {
+      if (j != cur_object_index && sprite_state[j] >= 9 && !((frame_counter ^ j) & 7 | sprite_hit_timer[j]))
+        SpriteBomb_CheckDamageToSprite(k, j);
+    }
+    Sprite_CheckDamageToLink(k);
+  }
+  SpriteDraw_SpriteBombExplosion(k);
+  if (!sprite_delay_aux1[k])
+    sprite_state[k] = 0;
+}
+
+void SpriteBomb_CheckDamageToSprite(int k, int j) {  // 85be49
+  int x = Sprite_GetX(k) - 16, y = Sprite_GetY(k) - 16;
+  SpriteHitBox hb;
+  hb.r0_xlo = x;
+  hb.r8_xhi = x >> 8;
+  hb.r3 = hb.r2 = 48;
+  hb.r1_ylo = y;
+  hb.r9_yhi = y >> 8;
+  Sprite_SetupHitBox(j, &hb);
+  if (!CheckIfHitBoxesOverlap(&hb) || sprite_type[j] == 0x11)
+    return;
+  Ancilla_CheckDamageToSprite_preset(j, 8);
+  x = Sprite_GetX(j);
+  y = Sprite_GetY(j) - sprite_z[j];
+  ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLocation(k, x, y, 32);
+  sprite_y_recoil[j] = pt.y;
+  sprite_x_recoil[j] = pt.x;
+}
+
+void SpriteBomb_ExplosionIncoming(int k) {  // 85bed3
+  if (sprite_E[k])
+    sprite_obj_prio[k] |= 48;
+  SpriteDraw_SingleLarge(k);
+  if (sprite_hit_timer[k] || sprite_delay_aux1[k] == 1) {
+    sprite_hit_timer[k] = 0;
+    if (sprite_state[k] == 10)
+      link_state_bits = 0, link_picking_throw_state = 0;
+    SpriteSfx_QueueSfx2WithPan(k, 0xc);
+    sprite_C[k]++;
+    sprite_flags4[k] = 9;
+    sprite_oam_flags[k] = 2;
+    sprite_delay_aux1[k] = 31;
+    sprite_state[k] = 6;
+    sprite_flags2[k] = 3;
+    return;
+  }
+  if (sprite_delay_aux1[k] < 64)
+    sprite_oam_flags[k] = sprite_oam_flags[k] & ~0xe | (sprite_delay_aux1[k] >> 1) & 0xe;
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  if (!sprite_delay_aux3[k])
+    Sprite_CheckDamageFromLink(k);
+  Sprite_MoveXY(k);
+  if (player_is_indoors)
+    Sprite_CheckTileCollision(k);
+  ThrownSprite_TileAndSpriteInteraction(k);
+}
+
+void BombGuard(int k) {  // 85bf51
+  BombTrooper_Draw(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  Sprite_CheckDamageToAndFromLink(k);
+  sprite_head_dir[k] = sprite_D[k] = Sprite_DirectionToFaceLink(k, NULL);
+  if (sprite_ai_state[k] == 0) {
+    if (!sprite_delay_main[k]) {
+      sprite_ai_state[k] = 1;
+      sprite_delay_main[k] = 112;
+    }
+  } else {
+    int j = sprite_delay_main[k];
+    if (!j) {
+      sprite_ai_state[k] = 0;
+      sprite_delay_main[k] = 32;
+      return;
+    }
+    sprite_subtype2[k] = (j >= 80);
+    if (j == 32)
+      BombGuard_CreateBomb(k);
+    sprite_graphics[k] = kJavelinTrooper_Tab2[(sprite_D[k] << 3 | j >> 4) + 32];
+  }
+}
+
+void BombGuard_CreateBomb(int k) {  // 85bfc1
+  static const int8 kBombTrooperBomb_X[4] = {0, 1, 9, -8};
+  static const int8 kBombTrooperBomb_Y[4] = {-12, -12, -15, -13};
+  static const int8 kBombTrooperBomb_Zvel[16] = {32, 40, 48, 56, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64};
+  SpriteSpawnInfo info;
+  int j = Sprite_SpawnDynamically(k, 0x4a, &info);
+  if (j >= 0) {
+    int i = sprite_D[k];
+    Sprite_SetX(j, info.r0_x + kBombTrooperBomb_X[i]);
+    Sprite_SetY(j, info.r2_y + kBombTrooperBomb_Y[i]);
+    Sprite_ApplySpeedTowardsLink(j, 16);
+    PointU8 pt;
+    sprite_C[j] = 1;
+    Sprite_DirectionToFaceLink(j, &pt);
+    if (sign8(pt.x))
+      pt.x = -pt.x;
+    if (sign8(pt.y))
+      pt.y = -pt.y;
+    sprite_z_vel[j] = kBombTrooperBomb_Zvel[(pt.y | pt.x) >> 4];
+    sprite_flags3[j] = sprite_flags3[k] & 0xee | 0x18;
+    sprite_oam_flags[j] = 8;
+    sprite_delay_aux1[j] = 255;
+    sprite_health[j] = 0;
+    SpriteSfx_QueueSfx3WithPan(j, 0x13);
+  }
+}
+
+void BombTrooper_Draw(int k) {  // 85c04b
+  PrepOamCoordsRet info;
+  if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
+    return;
+  SpriteDraw_GuardHead(k, &info, 2);
+  SpriteDraw_BNCBody(k, &info, 1);
+  if (sprite_graphics[k] < 20)
+    SpriteDraw_BombGuard_Arm(k, &info);
+  SpriteDraw_Shadow_custom(k, &info, 10);
+}
+
+void SpriteDraw_BombGuard_Arm(int k, PrepOamCoordsRet *info) {  // 85c089
+  static const int8 kBombTrooper_DrawArm_X[8] = {-1, 1, 2, 0, 9, 9, -8, -8};
+  static const int8 kBombTrooper_DrawArm_Y[8] = {-12, -12, -12, -12, -16, -14, -12, -14};
+  OamEnt *oam = GetOamCurPtr();
+  int j = sprite_D[k] * 2 | sprite_subtype2[k];
+  SetOamHelper0(oam,
+                info->x + kBombTrooper_DrawArm_X[j],
+                info->y + kBombTrooper_DrawArm_Y[j], 0x6e, info->flags & 0x30 | 0x8, 2);
+}
+
+void SpriteDraw_SpriteBombExplosion(int k) {  // 85c113
+  static const int8 kEnemyBombExplosion_X[16] = {-12, 12, -12, 12, -8, 8, -8, 8, -8, 8, -8, 8, 0, 0, 0, 0};
+  static const int8 kEnemyBombExplosion_Y[16] = {-12, -12, 12, 12, -8, -8, 8, 8, -8, -8, 8, 8, 0, 0, 0, 0};
+  static const uint8 kEnemyBombExplosion_Char[16] = {0x88, 0x88, 0x88, 0x88, 0x8a, 0x8a, 0x8a, 0x8a, 0x84, 0x84, 0x84, 0x84, 0x86, 0x86, 0x86, 0x86};
+  static const uint8 kEnemyBombExplosion_Flags[16] = {0, 0x40, 0x80, 0xc0, 0, 0x40, 0x80, 0xc0, 0, 0x40, 0x80, 0xc0, 0, 0, 0, 0};
+  PrepOamCoordsRet info;
+  if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
+    return;
+  OamEnt *oam = GetOamCurPtr();
+  int base = sprite_delay_aux1[k] >> 1 & 0xc;
+  for (int i = 3; i >= 0; i--, oam++) {
+    int j = base + i;
+    oam->x = kEnemyBombExplosion_X[j] + info.x;
+    oam->y = kEnemyBombExplosion_Y[j] + info.y;
+    oam->charnum = kEnemyBombExplosion_Char[j];
+    oam->flags = kEnemyBombExplosion_Flags[j] | info.flags;
+  }
+  Sprite_CorrectOamEntries(k, 3, 2);
+}
+
+void Sprite_41_BlueGuard(int k) {  // 85c155
+  if (sprite_C[k])
+    Probe(k);
+  else
+    Guard_Main(k);
+}
+
+void Probe(int k) {  // 85c15d
+  SpriteAddXY(k, (int8)sprite_x_vel[k], (int8)sprite_y_vel[k]);
+  bool is_close;
+  if (sprite_type[sprite_C[k] - 1] == 0xce) {
+    // parent is blind the thief?
+    uint16 x = cur_sprite_x - link_x_coord + 16;
+    uint16 y = link_y_coord - cur_sprite_y + 24;
+    is_close = (x < 32 && y < 32);
+  } else {
+    if (Probe_CheckTileSolidity(k) && sprite_tiletype != 9 || link_cape_mode != 0) {
+      sprite_state[k] = 0;
+      return;
+    }
+    uint16 x = cur_sprite_x - link_x_coord;
+    uint16 y = cur_sprite_y - link_y_coord;
+    is_close = (x < 16 && y < 16 && sprite_floor[k] == link_is_on_lower_level);
+  }
+  if (is_close) {
+    int p = sprite_C[k] - 1;
+    if (sprite_ai_state[p] != 3) {
+      sprite_ai_state[p] = 3;
+      if (sprite_type[p] != 0xce) {
+        sprite_delay_main[p] = 16;
+        sprite_subtype2[p] = 0;
+      }
+    }
+    sprite_state[k] = 0;
+  } else {
+    PrepOamCoordsRet oam;
+    if (Sprite_PrepOamCoordOrDoubleRet(k, &oam))
+      return;
+    if ((oam.x | oam.y) >= 256)
+      sprite_state[k] = 0;
+  }
+}
+
+void Guard_Main(int k) {  // 85c227
+  uint8 bak1 = sprite_graphics[k];
+  uint8 bak2 = sprite_D[k];
+
+  if (sprite_delay_aux1[k]) {
+    sprite_D[k] = kSoldier_DirectionLockSettings[bak2];
+    sprite_graphics[k] = kSoldier_Gfx[bak2];
+  }
+  Guard_HandleAllAnimation(k);
+  sprite_D[k] = bak2;
+  sprite_graphics[k] = bak1;
+
+  if (sprite_state[k] == 5) {
+    if (submodule_index == 0) {
+      sprite_subtype2[k]++;
+      Guard_TickAndUpdateBody(k);
+      sprite_subtype2[k]++;
+      Guard_TickAndUpdateBody(k);
+    }
+    return;
+  }
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  Guard_ParrySwordAttacks(k);
+  if ((Sprite_CheckDamageToLink(k) || sprite_alert_flag) && sprite_ai_state[k] < 3) {
+    sprite_ai_state[k] = 3;
+    Guard_SetTimerAndAssertTileHitBox(k, 0x20);
+  } else if (sprite_F[k] != 0 && sprite_F[k] >= 4) {
+    sprite_ai_state[k] = 4;
+    Guard_SetTimerAndAssertTileHitBox(k, 0x80);
+  }
+  if (Sprite_ReturnIfRecoiling(k))
+    return;
+  if ((sprite_subtype[k] & 7) < 5) {
+    if (!sprite_wallcoll[k])
+      Sprite_MoveXY(k);
+    Sprite_CheckTileCollision(k);
+  } else {
+    Sprite_MoveXY(k);
+  }
+  if (sprite_ai_state[k] != 4)
+    sprite_G[k] = 0;
+
+  switch (sprite_ai_state[k]) {
+  case 0:
+    Sprite_ZeroVelocity_XY(k);
+    if (sprite_delay_main[k])
+      break;
+    sprite_ai_state[k]++;
+    if (sprite_subtype[k] && (sprite_subtype[k] & 7) < 5) {
+      sprite_delay_main[k] = kSoldier_Delay[sprite_subtype[k] >> 3 & 3];
+      sprite_D[k] ^= 1;
+      sprite_subtype2[k] = 0;
+    } else {
+      sprite_delay_main[k] = (GetRandomNumber() & 0x3f) + 0x28; // note: adc
+      uint8 t = sprite_D[k], u = GetRandomNumber() & 3;
+      sprite_D[k] = u;
+      if (t == u || (t ^ u) & 2)
+        return;
+    }
+    sprite_delay_aux1[k] = 12;
+    break;
+  case 1: {
+    Sprite_Guard_SendOutProbe(k);
+    if ((sprite_subtype[k] & 7) >= 5) {
+      Guard_ShootProbeAndStuff(k);
+      return;
+    }
+    if (!sprite_delay_main[k]) {
+      Sprite_ZeroVelocity_XY(k);
+      sprite_ai_state[k] = 2;
+      sprite_delay_main[k] = 160;
+      return;
+    }
+    if (!(sprite_subtype2[k] & 1))
+      sprite_delay_main[k]++;
+    if (sprite_wallcoll[k] & 0xf) {
+      sprite_D[k] ^= 1;
+      Guard_SetGlanceTo12(k);
+    }
+    int dir = sprite_D[k];
+    sprite_x_vel[k] = kSoldier_Xvel[dir];
+    sprite_y_vel[k] = kSoldier_Yvel[dir];
+    sprite_head_dir[k] = dir;
+    Guard_TickAndUpdateBody(k);
+    break;
+  }
+  case 2: {
+    Sprite_ZeroVelocity_XY(k);
+    Sprite_Guard_SendOutProbe(k);
+    if (sprite_delay_main[k] == 0) {
+      sprite_delay_main[k] = 0x20;
+      sprite_ai_state[k] = 0;
+    } else if (sprite_delay_main[k] < 0x80) {
+      int t = sprite_D[k] * 8 | (sprite_delay_main[k] >> 3 & 7);
+      sprite_head_dir[k] = kSoldier_HeadDirs[t];
+    }
+    break;
+  }
+  case 3:
+    Sprite_ZeroVelocity_XY(k);
+    sprite_head_dir[k] = Sprite_DirectionToFaceLink(k, NULL);
+    if (sprite_delay_main[k] == 0) {
+      sprite_ai_state[k] = 4;
+      Guard_SetTimerAndAssertTileHitBox(k, 255);
+    }
+    break;
+  case 4:
+    if (sprite_delay_main[k]) {
+      Soldier_Func12(k);
+    } else {
+      sprite_anim_clock[k] = kSoldier_Tab1[sprite_D[k]];
+      Sprite_ZeroVelocity_XY(k);
+      sprite_ai_state[k] = 2;
+      sprite_delay_main[k] = 160;
+    }
+    break;
+  }
+}
+
+void Guard_SetGlanceTo12(int k) {  // 85c32b
+  sprite_delay_aux1[k] = 12;
+}
+
+void Guard_ShootProbeAndStuff(int k) {  // 85c3a1
+  int i = sprite_B[k];
+  sprite_x_vel[k] = kSoldierB_Xvel[i];
+  sprite_y_vel[k] = kSoldierB_Yvel[i];
+  Sprite_CheckTileCollision(k);
+  if (sprite_delay_aux2[k]) {
+    if (sprite_delay_aux2[k] == 44)
+      sprite_B[k] = i = kSoldierB_NextB[i];
+  } else if (!(sprite_wallcoll[k] & kSoldierB_Mask[i])) {
+    sprite_delay_aux2[k] = 88;
+  }
+  if (sprite_wallcoll[k] & kSoldierB_Mask2[i])
+    sprite_B[k] = i = kSoldierB_NextB2[i];
+  sprite_x_vel[k] = kSoldierB_Xvel2[i];
+  sprite_y_vel[k] = kSoldierB_Yvel2[i];
+  sprite_head_dir[k] = sprite_D[k] = kSoldierB_Dir[i];
+  Guard_TickAndUpdateBody(k);
+}
+
+void Guard_TickAndUpdateBody(int k) {  // 85c454
+  sprite_subtype2[k]++;
+  int t = sprite_D[k] * 4 + (sprite_subtype2[k] >> 3 & 3);
+  sprite_graphics[k] = kSoldier_Gfx2[t];
+}
+
+void Guard_SetTimerAndAssertTileHitBox(int k, uint8 a) {  // 85c4d7
+  sprite_delay_main[k] = a;
+  sprite_subtype[k] = 0;
+  sprite_flags[k] = sprite_flags[k] & 0xf | 0x60;
+}
+
+void Soldier_Func12(int k) {  // 85c500
+  if (((k ^ frame_counter) & 0x1f) == 0) {
+    if (!sprite_G[k]) {
+      sprite_G[k] = 1;
+      SpriteSfx_QueueSfx3WithPan(k, 4);
+    }
+    Sprite_ApplySpeedTowardsLink(k, 16);
+    sprite_D[k] = sprite_head_dir[k] = Sprite_DirectionToFaceLink(k, NULL);
+  }
+  Guard_ApplySpeedInDirection(k);
+  sprite_subtype2[k]++;
+  Guard_TickAndUpdateBody(k);
+}
+
+void Guard_ApplySpeedInDirection(int k) {  // 85c542
+  if (!sprite_wallcoll[k])
+    return;
+  int i;
+  if (sprite_wallcoll[k] & 3) {
+    i = 2 + Sprite_IsBelowLink(k).a;
+  } else {
+    i = Sprite_IsRightOfLink(k).a;
+  }
+  sprite_x_vel[k] = kSoldier_SetTowardsVel[i];
+  sprite_y_vel[k] = kSoldier_SetTowardsVel[i + 2];
+}
+
+void Sprite_Guard_SendOutProbe(int k) {  // 85c5f2
+  if ((k + frame_counter & 3) | sprite_pause[k])
+    return;
+  uint8 a = sprite_anim_clock[k]++;
+  uint8 r15 = ((a & 0x1f) + kSprite_SpawnProbeStaggered_Tab[sprite_D[k]]) & 0x3f;
+  Sprite_SpawnProbeAlways(k, r15);
+}
+
+void Sprite_SpawnProbeAlways(int k, uint8 r15) {  // 85c612
+  SpriteSpawnInfo info;
+  int j = Sprite_SpawnDynamicallyEx(k, 0x41, &info, 10);
+  if (j < 0)
+    return;
+  int t = info.r0_x + 8;
+  sprite_x_lo[j] = t;
+  sprite_x_hi[j] = t >> 8;
+  t = info.r2_y + 4;
+  sprite_y_lo[j] = t;
+  sprite_y_hi[j] = t >> 8;
+  sprite_D[j] = r15;
+  sprite_x_vel[j] = kSpawnProbe_Xvel[r15];
+  sprite_y_vel[j] = kSpawnProbe_Yvel[r15];
+  sprite_flags2[j] = sprite_flags2[j] & 0xf0 | 0xa0;
+  sprite_C[j] = k + 1;
+  sprite_ignore_projectile[j] = k + 1;
+  sprite_flags4[j] = 0x40;
+  sprite_flags3[j] = 0x40;
+  sprite_defl_bits[j] = 2;
+}
+
+void Guard_HandleAllAnimation(int k) {  // 85c680
+  PrepOamCoordsRet poc;
+  if (Sprite_PrepOamCoordOrDoubleRet(k, &poc))
+    return;
+  Guard_AnimateHead(k, 0, &poc);
+  Guard_AnimateBody(k, kSoldier_Draw2_OamIdx[sprite_D[k]] >> 2, &poc);
+  Guard_AnimateWeapon(k, &poc);
+  if (sprite_flags3[k] & 0x10)
+    SpriteDraw_Shadow_custom(k, &poc, kSoldier_DrawShadow[sprite_D[k]]);
+}
+
+void Guard_AnimateHead(int k, int oam_offs, const PrepOamCoordsRet *poc) {  // 85c6de
+  OamEnt *oam = GetOamCurPtr() + oam_offs;
+  int dir = sprite_head_dir[k];
+  SetOamHelper0(oam, poc->x, poc->y - kSoldier_Draw1_Yd[sprite_graphics[k]],
+                kSoldier_Draw1_Char[dir], kSoldier_Draw1_Flags[dir] | poc->flags, 2);
+}
+
+void Guard_AnimateBody(int k, int oam_idx, const PrepOamCoordsRet *poc) {  // 85ca09
+  int g = sprite_graphics[k] * 4;
+  uint8 type = sprite_type[k];
+  OamEnt *oam = GetOamCurPtr() + oam_idx;
+  for (int i = 3; i >= 0; i--) {
+    int j = i + g;
+    if (type >= 0x46 && (!kSoldier_Draw2_Big[j] || i == 3 && kSoldier_Draw2_Char[j] == 0x20))
+      continue;
+    uint8 flags = kSoldier_Draw2_Flags[j] | poc->flags;
+    if (kSoldier_Draw2_Char[j] == 0x20) {
+      flags = flags & 0xf1 | 2;
+    } else if (kSoldier_Draw2_Big[j] == 0) {
+      flags = flags & 0xf1 | 8;
+    }
+    SetOamHelper0(oam, poc->x + kSoldier_Draw2_Xd[j], poc->y + kSoldier_Draw2_Yd[j],
+                  kSoldier_Draw2_Char[j], flags, kSoldier_Draw2_Big[j]);
+    if (oam->charnum == 0x20 && type == 0x46)
+      oam->y = 0xf0;
+    oam++;
+  }
+}
+
+void Guard_AnimateWeapon(int k, const PrepOamCoordsRet *poc) {  // 85cb64
+  int oam_idx = kSoldier_Draw3_OamIdx[sprite_D[k]] >> 2;
+  int g = sprite_graphics[k] * 2;
+  uint8 type = sprite_type[k];
+  OamEnt *oam = GetOamCurPtr() + oam_idx;
+  for (int i = 1; i >= 0; i--, oam++) {
+    int j = i + g;
+    dungmap_var8 = kSoldier_Draw3_Xd[j] << 8 | (uint8)kSoldier_Draw3_Yd[j];
+    SetOamHelper0(oam, poc->x + kSoldier_Draw3_Xd[j], poc->y + kSoldier_Draw3_Yd[j],
+                  kSoldier_Draw3_Char[j] + (type < 0x43 ? 3 : 0),
+                  kSoldier_Draw3_Flags[j] | poc->flags, 0);
+  }
+}
+
+void Sprite_45_HogSpearMan(int k) {  // 85cbe0
+  Guard_HandleAllAnimation(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  BoltGuard_TriggerChaseTheme(k);
+  Guard_ParrySwordAttacks(k);
+  if (Sprite_ReturnIfRecoiling(k))
+    return;
+  if (!sprite_wallcoll[k])
+    Sprite_MoveXY(k);
+  Sprite_CheckTileCollision(k);
+  Sprite_CheckDamageToLink(k);
+  if (!((k ^ frame_counter) & 15)) {
+    sprite_head_dir[k] = sprite_D[k] = Sprite_DirectionToFaceLink(k, NULL);
+    Sprite_ApplySpeedTowardsLink(k, 18);
+    Guard_ApplySpeedInDirection(k);
+  }
+  sprite_subtype2[k]++;
+  Guard_TickAndUpdateBody(k);
+}
+
+void BoltGuard_TriggerChaseTheme(int k) {  // 85cc3c
+  if (sprite_G[k] != 16 && sprite_G[k]++ == 15) {
+    SpriteSfx_QueueSfx3WithPan(k, 0x4);
+    if (sram_progress_indicator == 2 && BYTE(overworld_area_index) == 24)
+      music_control = 12;
+  }
+}
+
+void Sprite_44_BluesainBolt(int k) {  // 85cc65
+  PsychoTrooper_Draw(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  BoltGuard_TriggerChaseTheme(k);
+  Guard_ParrySwordAttacks(k);
+  if (Sprite_ReturnIfRecoiling(k))
+    return;
+  if (!sprite_wallcoll[k])
+    Sprite_MoveXY(k);
+  Sprite_CheckTileCollision(k);
+  Sprite_CheckDamageToLink(k);
+  if (!((k ^ frame_counter) & 15)) {
+    sprite_D[k] = sprite_head_dir[k] = Sprite_DirectionToFaceLink(k, NULL);
+    Sprite_ApplySpeedTowardsLink(k, 18);
+    Guard_ApplySpeedInDirection(k);
+  }
+  sprite_graphics[k] = kFlailTrooperGfx[++sprite_subtype2[k] >> 1 & 7 | sprite_D[k] << 3];
+}
+
+void PsychoTrooper_Draw(int k) {  // 85ccd5
+  PrepOamCoordsRet info;
+  if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
+    return;
+  SpriteDraw_GuardHead(k, &info, 3);
+  SpriteDraw_BNCBody(k, &info, 2);
+  SpriteDraw_GuardSpear(k, &info, 0);
+  if (sprite_flags3[k] & 0x10)
+    SpriteDraw_Shadow_custom(k, &info, kSoldier_DrawShadow[sprite_D[k]]);
+}
+
+void SpriteDraw_GuardSpear(int k, PrepOamCoordsRet *info, int spr_offs) {  // 85cd54
+  static const int8 kSolderThrowing_Draw_X[16] = {15, 7, 17, 9, -8, 0, -10, -2, 13, 13, 13, 13, -4, -4, -4, -4};
+  static const int8 kSolderThrowing_Draw_Y[16] = {-2, -2, -2, -2, -2, -2, -2, -2, 8, 0, 10, 2, -14, -6, -16, -8};
+  static const uint8 kSolderThrowing_Draw_Char[16] = {0x6f, 0x7f, 0x6f, 0x7f, 0x6f, 0x7f, 0x6f, 0x7f, 0x6e, 0x7e, 0x6e, 0x7e, 0x6e, 0x7e, 0x6e, 0x7e};
+  static const uint8 kSolderThrowing_Draw_Flags[16] = {0x40, 0x40, 0x40, 0x40, 0, 0, 0, 0, 0x80, 0x80, 0x80, 0x80, 0, 0, 0, 0};
+
+  OamEnt *oam = GetOamCurPtr() + spr_offs;
+  uint8 r6 = sprite_D[k] * 4 + (((sprite_A[k] ^ 1) << 1) & 2);
+  for (int i = 1; i >= 0; i--, oam++) {
+    int j = r6 + i;
+    uint16 x = info->x + kSolderThrowing_Draw_X[j];
+    uint16 y = info->y + kSolderThrowing_Draw_Y[j];
+    HIBYTE(dungmap_var8) = kSolderThrowing_Draw_X[j];
+    BYTE(dungmap_var8) = kSolderThrowing_Draw_Y[j];
+    SetOamHelper0(oam, x, y,
+                  kSolderThrowing_Draw_Char[j] - (sprite_type[k] >= 0x48 ? 3 : 0),
+                  (kSolderThrowing_Draw_Flags[j] | info->flags) & 0xf1 | 8, 0);
+  }
+}
+
+void Sprite_48_RedJavelinGuard(int k) {  // 85cde1
+  static const uint8 kJavelinTrooper_Gfx[4] = {12, 0, 18, 8};
+  uint8 bak0 = sprite_graphics[k];
+  int j = sprite_D[k];
+  if (sprite_delay_aux1[k] != 0) {
+    sprite_D[k] = kSoldier_DirectionLockSettings[j];
+    sprite_graphics[k] = kJavelinTrooper_Gfx[j];
+  }
+  JavelinTrooper_Draw(k);
+  sprite_D[k] = j;
+  sprite_graphics[k] = bak0;
+  SoldierThrowing_Common(k);
+}
+
+void Sprite_46_BlueArcher(int k) {  // 85cdff
+  uint8 bak0 = sprite_graphics[k];
+  int j = sprite_D[k];
+  if (sprite_delay_aux1[k] != 0) {
+    sprite_D[k] = kSoldier_DirectionLockSettings[j];
+    sprite_graphics[k] = kSoldier_Gfx[j];
+  }
+  ArcherSoldier_Draw(k);
+  sprite_D[k] = j;
+  sprite_graphics[k] = bak0;
+  SoldierThrowing_Common(k);
+}
+
+void SoldierThrowing_Common(int k) {  // 85ce23
+  int j;
+
+  static const uint8 kSolderThrowing_DirFlags[4] = {3, 3, 12, 12};
+  static const int8 kSolderThrowing_Xd[8] = {-80, 80, 0, -8, -80, 80, -8, 8};
+  static const int8 kSolderThrowing_Yd[8] = {8, 8, -80, 80, 8, 8, -80, 80};
+
+  if (Sprite_ReturnIfInactive(k))
+    return;
+
+  if ((Sprite_CheckDamageToAndFromLink(k) || sprite_alert_flag) && sprite_ai_state[k] < 3) {
+    sprite_ai_state[k] = 3;
+    sprite_delay_main[k] = 32;
+  }
+  if (sprite_F[k] >= 4) {
+    sprite_ai_state[k] = 4;
+    sprite_delay_main[k] = 60;
+    sprite_subtype2[k] = 0;
+  }
+  if (Sprite_ReturnIfRecoiling(k))
+    return;
+  if (!sprite_wallcoll[k])
+    Sprite_MoveXY(k);
+  Sprite_CheckTileCollision(k);
+  switch (sprite_ai_state[k]) {
+  case 0:  // resting
+    Sprite_ZeroVelocity_XY(k);
+    if (sprite_delay_main[k] == 0) {
+      sprite_ai_state[k]++;
+      sprite_delay_main[k] = 0x50 + (GetRandomNumber() & 0x7f);
+      uint8 jbak = sprite_D[k];
+      sprite_D[k] = GetRandomNumber() & 3;
+      if (sprite_D[k] != jbak && !((sprite_D[k] ^ jbak) & 2))
+        sprite_delay_aux1[k] = 12;
+    }
+    break;
+  case 1:  // walking
+    if (sprite_delay_main[k] == 0) {
+      sprite_ai_state[k] = 2;
+      sprite_delay_main[k] = 160;
+      return;
+    }
+    Sprite_Guard_SendOutProbe(k);
+    if (sprite_wallcoll[k] & 0xf) {
+      sprite_D[k] ^= 1;
+      Guard_SetGlanceTo12(k);
+    }
+    j = sprite_D[k];
+    sprite_x_vel[k] = kSoldier_Xvel[j];
+    sprite_y_vel[k] = kSoldier_Yvel[j];
+    sprite_head_dir[k] = j;
+agitated_jump_to:
+    sprite_subtype2[k]++;
+    if (!(sprite_subtype2[k] & 0xf) && ++sprite_A[k] == 2)
+      sprite_A[k] = 0;
+    sprite_graphics[k] = kSoldier_Gfx2[sprite_D[k] * 4 + sprite_A[k] + (sprite_type[k] == 0x48 ? 16 : 0)];
+    break;
+  case 2:  // looking
+    Sprite_ZeroVelocity_XY(k);
+    Sprite_Guard_SendOutProbe(k);
+    if (sprite_delay_main[k] == 0) {
+      sprite_delay_main[k] = 32;
+      sprite_ai_state[k] = 0;
+    } else if (sprite_delay_main[k] < 0x80) {
+      int t = sprite_D[k] * 8 | (sprite_delay_main[k] >> 3 & 7);
+      sprite_head_dir[k] = kSoldier_HeadDirs[t];
+    }
+    break;
+  case 3:  // noticed player
+    Sprite_ZeroVelocity_XY(k);
+    sprite_head_dir[k] = Sprite_DirectionToFaceLink(k, NULL);
+    if (sprite_delay_main[k] == 0) {
+      sprite_ai_state[k] = 4;
+      sprite_delay_main[k] = 60;
+      sprite_subtype2[k] = 0;
+    }
+    break;
+  case 4:  // agitated
+    j = sprite_D[k];
+    if (sprite_wallcoll[k] & kSolderThrowing_DirFlags[j] || !sprite_delay_main[k]) {
+      sprite_ai_state[k]++;
+      sprite_delay_main[k] = 24;
+      return;
+    }
+    if (!((frame_counter ^ k) & 7)) {
+      sprite_D[k] = sprite_head_dir[k] = j = Sprite_DirectionToFaceLink(k, NULL);
+      if (sprite_type[k] == 0x48)
+        j += 4;
+      uint16 x = link_x_coord + kSolderThrowing_Xd[j];
+      uint16 y = link_y_coord + kSolderThrowing_Yd[j];
+      ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLocation(k, x, y, 24);
+      sprite_x_vel[k] = pt.x;
+      sprite_y_vel[k] = pt.y;
+      if ((uint8)(pt.xdiff + 6) < 12 && (uint8)(pt.ydiff + 6) < 12) {
+        sprite_ai_state[k]++;
+        sprite_delay_main[k] = 24;
+        return;
+      }
+    }
+    sprite_subtype2[k]++;
+    goto agitated_jump_to;
+  case 5:  // attack
+    sprite_anim_clock[k] = kSoldier_Tab1[sprite_D[k]];
+    Sprite_ZeroVelocity_XY(k);
+    if ((j = sprite_delay_main[k]) == 0) {
+      sprite_ai_state[k] = 2;
+      sprite_delay_main[k] = 160;
+      return;
+    }
+    sprite_subtype2[k] = (j >= 40) ? 255 : 0;
+    if (j == 12)
+      Guard_LaunchProjectile(k);
+    sprite_graphics[k] = kJavelinTrooper_Tab2[sprite_D[k] * 8 + (j >> 3) + (sprite_type[k] == 0x48 ? 32 : 0)];
+    break;
+  }
+}
+
+void Guard_LaunchProjectile(int k) {  // 85d0c5
+  static const int8 kJavelinProjectile_X[8] = {16, -8, 3, 11, 12, -4, 12, -4};
+  static const int8 kJavelinProjectile_Y[8] = {2, 2, 16, -8, -2, -2, 2, -8};
+  static const int8 kJavelinProjectile_Xvel[8] = {48, -48, 0, 0, 32, -32, 0, 0};
+  static const int8 kJavelinProjectile_Yvel[8] = {0, 0, 48, -48, 0, 0, 32, -32};
+  static const uint8 kJavelinProjectile_Flags4[4] = {5, 5, 6, 6};
+
+  SpriteSpawnInfo info;
+  int j = Sprite_SpawnDynamically(k, 0x1b, &info);
+  if (j < 0)
+    return;
+  SpriteSfx_QueueSfx3WithPan(k, 0x5);
+  int i = sprite_D[k] + (sprite_type[k] >= 0x48 ? 4 : 0);
+
+  Sprite_SetX(j, info.r0_x + kJavelinProjectile_X[i]);
+  Sprite_SetY(j, info.r2_y + kJavelinProjectile_Y[i]);
+  sprite_x_vel[j] = kJavelinProjectile_Xvel[i];
+  sprite_y_vel[j] = kJavelinProjectile_Yvel[i];
+  i &= 3;
+  sprite_D[j] = i;
+  sprite_flags4[j] = kJavelinProjectile_Flags4[i];
+  sprite_z[j] = 0;
+  sprite_A[j] = (sprite_type[k] >= 0x48);
+  if (sprite_A[j] && link_shield_type == 0)
+    sprite_flags5[j] &= ~0x20;
+}
+
+void BushJavelinSoldier_Draw(int k) {  // 85d141
+  uint8 bak0 = sprite_graphics[k];
+  sprite_graphics[k] = 0;
+  uint8 bak1 = sprite_oam_flags[k];
+  sprite_oam_flags[k] = sprite_oam_flags[k] & 0xf1 | 2;
+  uint16 bak2 = cur_sprite_y;
+  cur_sprite_y += 8;
+  SpriteDraw_SingleLarge(k);
+  cur_sprite_y = bak2;
+  sprite_oam_flags[k] = bak1;
+  sprite_graphics[k] = bak0;
+
+  PrepOamCoordsRet info;
+  if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
+    return;
+  Guard_AnimateHead(k, 0x10 / 4, &info);
+  SpriteDraw_BNCBody(k, &info, 0xC / 4);
+  if (sprite_graphics[k] < 20)
+    SpriteDraw_GuardSpear(k, &info, 4 / 4);
+  if (sprite_flags3[k] & 0x10)
+    SpriteDraw_Shadow_custom(k, &info, kSoldier_DrawShadow[sprite_D[k]]);
+
+}
+
+void JavelinTrooper_Draw(int k) {  // 85d192
+  PrepOamCoordsRet info;
+  if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
+    return;
+  SpriteDraw_GuardHead(k, &info, 3);
+  SpriteDraw_BNCBody(k, &info, 2);
+  if (sprite_graphics[k] < 20)
+    SpriteDraw_GuardSpear(k, &info, 0);
+  if (sprite_flags3[k] & 0x10)
+    SpriteDraw_Shadow_custom(k, &info, kSoldier_DrawShadow[sprite_D[k]]);
+}
+
+void Sprite_49_RedBushGuard(int k) {  // 85d1ac
+  if (sprite_ai_state[k]) {
+    if (sprite_ai_state[k] == 2)
+      BushJavelinSoldier_Draw(k);
+    else
+      BushSoldierCommon_Draw(k);
+  }
+  Sprite_BushGuard_Main(k);
+}
+
+void Sprite_47_GreenBushGuard(int k) {  // 85d1bf
+  if (sprite_ai_state[k]) {
+    if (sprite_graphics[k] >= 14)
+      ArcherSoldier_Draw(k);
+    else
+      BushSoldierCommon_Draw(k);
+  }
+  Sprite_BushGuard_Main(k);
+}
+
+void Sprite_BushGuard_Main(int k) {  // 85d1d3
+  int j;
+  static const uint8 kBushSoldier_Gfx[32] = {
+    4, 4, 4, 4, 4, 4, 4, 4, 0, 1, 0, 1, 0, 1, 0, 1,
+    0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
+  };
+  static const uint8 kBushSoldier_Gfx2[16] = {0, 1, 0, 1, 0, 1, 0, 1, 0, 2, 3, 4, 4, 4, 4, 4};
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  sprite_ignore_projectile[k] = 1;
+  switch (sprite_ai_state[k]) {
+  case 0:
+    if (!sprite_delay_main[k]) {
+      sprite_ai_state[k] = 1;
+      sprite_delay_main[k] = 64;
+    }
+    break;
+  case 1:
+    Sprite_CheckDamageFromLink(k);
+    if (sprite_delay_main[k] == 0) {
+      sprite_ai_state[k] = 2;
+      sprite_delay_main[k] = 48;
+      sprite_head_dir[k] = sprite_D[k] = Sprite_DirectionToFaceLink(k, NULL);;
+    } else {
+      if (sprite_delay_main[k] == 0x20)
+        BushGuard_SpawnFoliage(k);
+      sprite_graphics[k] = kBushSoldier_Gfx[sprite_delay_main[k] >> 2];
+    }
+    break;
+  case 2:
+    sprite_ignore_projectile[k] = 0;
+    Sprite_CheckDamageToAndFromLink(k);
+    j = sprite_delay_main[k];
+    if (!j) {
+      sprite_ai_state[k] = 3;
+      sprite_delay_main[k] = 48;
+      goto case_3;
+    }
+    sprite_A[k] = j < 40 ? 0xff : 0x00;
+    if (j == 16)
+      Guard_LaunchProjectile(k);
+    sprite_graphics[k] = kJavelinTrooper_Tab2[sprite_D[k] * 8 + (j >> 3) + (sprite_type[k] == 0x49 ? 32 : 0)];
+    break;
+  case 3:
+  case_3:
+    Sprite_CheckDamageToAndFromLink(k);
+    if (!sprite_delay_main[k]) {
+      sprite_ai_state[k] = 0;
+      sprite_delay_main[k] = 64;
+    } else {
+      sprite_graphics[k] = kBushSoldier_Gfx2[sprite_delay_main[k] >> 2];
+    }
+    break;
+  }
+}
+
+void BushGuard_SpawnFoliage(int k) {  // 85d252
+  SpriteSpawnInfo info;
+  int j = Sprite_SpawnDynamically(k, 0xec, &info);
+  if (j < 0)
+    return;
+  Sprite_SetSpawnedCoordinates(j, &info);
+  sprite_state[j] = 6;
+  sprite_delay_main[j] = 32;
+  sprite_flags2[j] += 3;
+  sprite_C[j] = 2;
+}
+
+void BushSoldierCommon_Draw(int k) {  // 85d321
+  static const int8 kBushSoldierCommon_Y[14] = {8, 8, 8, 8, 2, 8, 0, 8, -3, 8, -3, 8, -3, 8};
+  static const uint8 kBushSoldierCommon_Char[14] = {0x20, 0x20, 0x20, 0x20, 0x40, 0x20, 0x40, 0x20, 0x40, 0x20, 0x42, 0x20, 0x42, 0x20};
+  static const uint8 kBushSoldierCommon_Flags[14] = {9, 3, 0x49, 0x43, 9, 3, 0x49, 0x43, 9, 3, 0x49, 0x43, 9, 3};
+  PrepOamCoordsRet info;
+  if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
+    return;
+  OamEnt *oam = GetOamCurPtr();
+  int g = sprite_graphics[k] * 2;
+  for (int i = 1; i >= 0; i--, oam++) {
+    int j = g + i;
+    uint8 flags = kBushSoldierCommon_Flags[j] | 0x20;
+    if (i == 0)
+      flags = flags & ~0xe | info.flags;
+    SetOamHelper0(oam, info.x, info.y + kBushSoldierCommon_Y[j], kBushSoldierCommon_Char[j], flags, 2);
+  }
+}
+
+void ArcherSoldier_Draw(int k) {  // 85d38c
+  static const uint8 kArcherSoldier_WeaponOamOffs[4] = {0, 0, 0, 16};
+  static const uint8 kArcherSoldier_HeadOamOffs[4] = {16, 16, 16, 0};
+  static const uint8 kArcherSoldier_BodyOamOffs[4] = {20, 20, 20, 4};
+  PrepOamCoordsRet info;
+  if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
+    return;
+  Guard_AnimateHead(k, kArcherSoldier_HeadOamOffs[sprite_D[k]] >> 2, &info);
+  Guard_AnimateBody(k, kArcherSoldier_BodyOamOffs[sprite_D[k]] >> 2, &info);
+  SpriteDraw_Archer_Weapon(k, kArcherSoldier_WeaponOamOffs[sprite_D[k]] >> 2, &info);
+  if (sprite_flags3[k] & 0x10)
+    SpriteDraw_Shadow_custom(k, &info, kSoldier_DrawShadow[sprite_D[k]]);
+}
+
+void SpriteDraw_Archer_Weapon(int k, int spr_offs, PrepOamCoordsRet *info) {  // 85d4d4
+  static const uint8 kArcherSoldier_Tab1[4] = {9, 3, 0, 6};
+  static const int8 kArcherSoldier_Draw_X[48] = {
+    -1,  7,  3,  3, -1,  7,  3,  3, -1,  7,  7,  7, -5, -5, -10, -2,
+    -4, -4, -6,  2, -5, -5, -5, -5,  6, 14, 11, 11,  6, 14,  11, 11,
+    6, 14, 14, 14, 11, 11, 18, 10, 12, 12, 14,  6, 11, 11,  11, 11,
+  };
+  static const int8 kArcherSoldier_Draw_Y[48] = {
+    7,  7,  3, 11,  6, 6, 1, 9,  7,  7,   7,  7, -2,  6,  2,  2,
+    -2,  6,  2,  2, -2, 6, 6, 6, -6, -6, -12, -4, -6, -6, -9, -1,
+    -6, -6, -6, -6, -2, 6, 2, 2, -2,  6,   2,  2, -2,  6,  6,  6,
+  };
+  static const uint8 kArcherSoldier_Draw_Char[48] = {
+    0xa,  0xa, 0x2a, 0x2b, 0x1a, 0x1a, 0x2a, 0x2b,  0xa,  0xa,  0xa,  0xa, 0xb, 0xb, 0x3d, 0x3a,
+    0x1b, 0x1b, 0x3d, 0x3a,  0xb,  0xb,  0xb,  0xb,  0xa,  0xa, 0x2b, 0x2a, 0xa, 0xa, 0x2b, 0x2a,
+    0xa,  0xa,  0xa,  0xa,  0xb,  0xb, 0x3d, 0x3a, 0x1b, 0x1b, 0x3d, 0x3a, 0xb, 0xb,  0xb,  0xb,
+  };
+  static const uint8 kArcherSoldier_Draw_Flags[48] = {
+    0xd, 0x4d,    8,    8,  0xd, 0x4d,    8,    8,  0xd, 0x4d, 0x4d, 0x4d,  0xd, 0x8d, 0x48, 0x48,
+    0xd, 0x8d, 0x48, 0x48,  0xd, 0x8d, 0x8d, 0x8d, 0x8d, 0xcd, 0x88, 0x88, 0x8d, 0xcd, 0x88, 0x88,
+    0x8d, 0xcd, 0xcd, 0xcd, 0x4d, 0xcd,    8,    8, 0x4d, 0xcd,    8,    8, 0x4d, 0xcd, 0xcd, 0xcd,
+  };
+  OamEnt *oam = GetOamCurPtr() + spr_offs;
+  int base = sprite_graphics[k] - 14;
+  if (base < 0)
+    base = kArcherSoldier_Tab1[sprite_D[k]];
+  for (int i = 3; i >= 0; i--, oam++) {
+    int j = base * 4 + i;
+    SetOamHelper0(oam, info->x + kArcherSoldier_Draw_X[j], info->y + kArcherSoldier_Draw_Y[j], kArcherSoldier_Draw_Char[j], kArcherSoldier_Draw_Flags[j] | 0x20, 0);
+  }
+}
+
+void TutorialSoldier_Draw(int k) {  // 85d64b
+  PrepOamCoordsRet info;
+  if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
+    return;
+  OamEnt *oam = GetOamCurPtr();
+  int d = sprite_graphics[k] * 5;
+  for (int i = 4; i >= 0; i--, oam++) {
+    int j = d + i;
+    uint8 flags = kTutorialSoldier_Flags[j] | info.flags;
+    if (kTutorialSoldier_Char[j] < 0x40)
+      flags = (flags & 0xf1) | 8;
+    SetOamHelper0(oam, info.x + kTutorialSoldier_X[j], info.y + kTutorialSoldier_Y[j], kTutorialSoldier_Char[j], flags, kTutorialSoldier_Big[j]);
+  }
+  SpriteDraw_Shadow_custom(k, &info, 12);
+}
+
+void PullSwitch_FacingUp(int k) {  // 85d6d4
+  static const uint8 kBadPullSwitch_Tab1[10] = {8, 24, 4, 4, 4, 4, 4, 4, 2, 10};
+  static const uint8 kBadPullSwitch_Tab0[10] = {6, 7, 8, 8, 8, 8, 8, 9, 9, 9};
+  PullSwitch_HandleUpPulling(k);
+  int j = sprite_graphics[k];
+  if (j != 0 && j != 11) {
+    link_unk_master_sword = kBadPullSwitch_Tab0[j - 1];
+    link_y_coord = Sprite_GetY(k) - 19;
+    link_x_coord = Sprite_GetX(k);
+    if (sprite_delay_main[k] == 0) {
+      sprite_graphics[k] = ++j;
+      if (j == 11) {
+        sound_effect_2 = 0x1b;
+        dung_flag_statechange_waterpuzzle = 1;
+      }
+      sprite_delay_main[k] = kBadPullSwitch_Tab1[j - 2];
+    }
+  }
+  if (sprite_type[k] != 7)
+    BadPullDownSwitch_Draw(k);
+  else
+    BadPullUpSwitch_Draw(k);
+}
+
+void PullSwitch_HandleUpPulling(int k) {  // 85d743
+  if (!Sprite_CheckDamageToLink_same_layer(k))
+    return;
+  link_actual_vel_y = 0;
+  link_actual_vel_x = 0;
+  Sprite_RepelDash();
+  bitmask_of_dragstate = 0;
+  uint8 y = link_y_coord - sprite_y_lo[k];
+  if (!sign8(y - 2)) {
+    link_y_coord = Sprite_GetY(k) + 9;
+  } else if (sign8(y - 244)) {
+    byte_7E0379++;
+    if (joypad1L_last & 0x80 && !(joypad1H_last & 3) && sprite_graphics[k] == 0) {
+      sprite_graphics[k] = 1;
+      sprite_delay_main[k] = 8;
+      SpriteSfx_QueueSfx2WithPan(k, 0x22);
+    }
+    link_y_coord = Sprite_GetY(k) - 21;
+  } else {
+    if (sign8(link_x_coord - sprite_x_lo[k]))
+      link_x_coord = Sprite_GetX(k) - 16;
+    else
+      link_x_coord = Sprite_GetX(k) + 14;
+  }
+}
+
+void BadPullDownSwitch_Draw(int k) {  // 85d7f9
+  PrepOamCoordsRet info;
+  if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
+    return;
+  Oam_AllocateDeferToPlayer(k);
+  OamEnt *oam = GetOamCurPtr();
+  uint8 yoff = kBadPullSwitch_Tab5[kBadPullSwitch_Tab4[sprite_graphics[k]]];
+  for (int i = 4; i >= 0; i--, oam++) {
+    SetOamPlain(oam, info.x + kBadPullDownSwitch_X[i], info.y + kBadPullDownSwitch_Y[i] - (i == 2 ? yoff : 0),
+                 kBadPullDownSwitch_Char[i], kBadPullDownSwitch_Flags[i] | 0x21, kBadPullDownSwitch_Big[i]);
+  }
+  Sprite_CorrectOamEntries(k, 4, 0xff);
+}
+
+void BadPullUpSwitch_Draw(int k) {  // 85d858
+  static const uint8 kBadPullUpSwitch_Tab2[2] = {0xa2, 0xa4};
+  PrepOamCoordsRet info;
+  if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
+    return;
+  Oam_AllocateDeferToPlayer(k);
+  OamEnt *oam = GetOamCurPtr();
+  uint8 yoff = kBadPullSwitch_Tab5[kBadPullSwitch_Tab4[sprite_graphics[k]]];
+  for (int i = 1; i >= 0; i--, oam++) {
+    SetOamHelper0(oam, info.x, info.y - ((i == 0) ? yoff : 0), kBadPullUpSwitch_Tab2[i], info.flags, 2);
+  }
+}
+
+void PullSwitch_FacingDown(int k) {  // 85d8b5
+  static const uint8 kGoodPullSwitch_Tab1[12] = {5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5};
+  static const uint8 kGoodPullSwitch_Tab0[12] = {1, 1, 2, 2, 3, 3, 1, 1, 4, 4, 5, 5};
+  static const uint8 kGoodPullSwitch_YOffs[12] = {9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14};
+  PullSwitch_HandleDownPulling(k);
+  int j = sprite_graphics[k];
+  if (j != 0 && j != 13) {
+    link_unk_master_sword = kGoodPullSwitch_Tab0[j - 1];
+    link_y_coord = Sprite_GetY(k) + kGoodPullSwitch_YOffs[j - 1];
+    link_x_coord = Sprite_GetX(k);
+    if (sprite_delay_main[k] == 0) {
+      sprite_graphics[k] = ++j;
+      if (j == 13) {
+        if (sprite_type[k] == 6) {
+          activate_bomb_trap_overlord = 1;
+          sound_effect_1 = 0x3c;
+        } else {
+          dung_flag_statechange_waterpuzzle = 1;
+          sound_effect_2 = 0x1b;
+        }
+      }
+      sprite_delay_main[k] = kGoodPullSwitch_Tab1[j - 2];
+    }
+  }
+  GoodPullSwitch_Draw(k);
+  if (sprite_pause[k])
+    sprite_graphics[k] = 0;
+}
+
+void GoodPullSwitch_Draw(int k) {  // 85d953
+  static const uint8 kGoodPullSwitch_Tab2[14] = {1, 1, 2, 3, 2, 3, 4, 5, 6, 7, 6, 7, 7, 7};
+  PrepOamCoordsRet info;
+  if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
+    return;
+  Oam_AllocateDeferToPlayer(k);
+  OamEnt *oam = GetOamCurPtr();
+  uint8 t = kGoodPullSwitch_Tab2[sprite_graphics[k]];
+  oam[0].x = oam[1].x = info.x;
+  oam[0].y = info.y - 1;
+  oam[1].y = info.y - 1 + t;
+  oam[0].charnum = 0xee;
+  oam[1].charnum = 0xce;
+  oam[0].flags = oam[1].flags = info.flags;
+  Sprite_CorrectOamEntries(k, 1, 2);
+}
+
+void PullSwitch_HandleDownPulling(int k) {  // 85d999
+  if (!Sprite_CheckDamageToLink_same_layer(k))
+    return;
+  link_actual_vel_y = 0;
+  link_actual_vel_x = 0;
+  Sprite_RepelDash();
+  bitmask_of_dragstate = 0;
+  uint8 y = link_y_coord - sprite_y_lo[k];
+  if (!sign8(y - 2)) {
+    byte_7E0379++;
+    if (joypad1L_last & 0x80 && !(joypad1H_last & 3)) {
+      link_unk_master_sword++;
+      if ((joypad1H_last & 4) && sprite_graphics[k] == 0) {
+        sprite_graphics[k] = 1;
+        sprite_delay_main[k] = 12;
+        SpriteSfx_QueueSfx2WithPan(k, 0x22);
+      }
+    }
+    link_y_coord = Sprite_GetY(k) + 9;
+  } else if (sign8(y - 244)) {
+    link_y_coord = Sprite_GetY(k) - 21;
+  } else {
+    if (sign8(link_x_coord - sprite_x_lo[k]))
+      link_x_coord = Sprite_GetX(k) - 16;
+    else
+      link_x_coord = Sprite_GetX(k) + 14;
+  }
+}
+
+void Priest_SpawnMantle(int k) {  // 85db27
+  sprite_state[15]++;
+  SpriteSpawnInfo info;
+  int j = Sprite_SpawnDynamically(k, 0x73, &info);
+  sprite_state[15] = 0;
+  sprite_flags2[j] = sprite_flags2[j] & 0xf0 | 0x3;
+  sprite_x_lo[j] = 0xF0;
+  sprite_x_hi[j] = 4;
+  sprite_y_lo[j] = 0x37;
+  sprite_y_hi[j] = 2;
+  sprite_E[j] = 2;
+  sprite_flags4[j] = 11;
+  sprite_defl_bits[j] |= 0x20;
+  sprite_subtype2[j] = 1;
+  if (link_y_coord < Sprite_GetY(j))
+    sprite_C[j] = 1;
+}
+
+void Sprite_SanctuaryMantle(int k) {  // 85db9b
+  SageMantle_Draw(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+
+  if (sprite_C[k]) {
+    sprite_A[k] = 0x40;
+    goto lbl2;
+  }
+  if (Sprite_CheckDamageToLink_same_layer(k)) {
+    Sprite_NullifyHookshotDrag();
+    link_speed_setting = 0;
+    Sprite_RepelDash();
+    sprite_delay_aux1[k] = 7;
+lbl:
+    sprite_subtype2[k] = 0;
+    bitmask_of_dragstate = 0x81;
+    link_speed_setting = 8;
+lbl2:
+    switch (sprite_ai_state[k]) {
+    case 0: {
+      uint16 x = Sprite_GetX(k);
+      Sprite_SetX(k, x + 19);
+      uint8 dir = Sprite_DirectionToFaceLink(k, NULL);
+      Sprite_SetX(k, x);
+      if (dir == 1 || dir == 3) {
+        sprite_A[k]++;
+        if (sprite_A[k] >= 64) {
+          sprite_ai_state[k]++;
+          flag_is_link_immobilized = 1;
+        }
+      }
+      break;
+    }
+    case 1:
+      SpriteSfx_QueueSfx3WithPan(k, 24);
+      sprite_ai_state[k]++;
+      sprite_delay_main[k] = 168;
+      sprite_x_vel[k] = 3;
+      sprite_delay_aux1[k] = 2;
+      break;
+    case 2:
+      Sprite_MoveXY(k);
+      if (sprite_delay_main[k] == 0) {
+        flag_is_link_immobilized = 0;
+        sprite_x_vel[k] = 0;
+        sprite_C[k] = 0;
+      } else {
+        sprite_delay_aux1[k] = 2;
+      }
+      break;
+    }
+  } else {  // no collision
+    if (sprite_delay_aux1[k])
+      goto lbl;
+    switch (sprite_subtype2[k]) {
+    case 0:
+      sprite_A[k] = 0;
+      bitmask_of_dragstate = 0;
+      link_speed_setting = 0;
+      sprite_subtype2[k]++;
+      break;
+    case 1:
+      break;
+    }
+  }
+}
+
+void SageMantle_Draw(int k) {  // 85dc8a
+  if (sprite_C[k] == 0)
+    Oam_AllocateFromRegionB(0x10);
+  Sprite_DrawMultiple(k, kSageMantle_Dmd, 4, NULL);
+}
+
+void Sprite_Priest(int k) {  // 85dce6
+  if (sprite_A[k] == 0)
+    Priest_Draw(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  Sprite_BehaveAsBarrier(k);
+  if (Sprite_TrackBodyToHead(k))
+    Sprite_MoveXY(k);
+  switch (sprite_subtype2[k]) {
+  case 0: Priest_Dying(k); break;
+  case 1: Priest_RunRescueCutscene(k); break;
+  case 2: Priest_Chillin(k); break;
+  }
+}
+
+void Priest_Dying(int k) {  // 85dd0a
+  sprite_head_dir[k] = 4;
+  sprite_D[k] = 4;
+  switch (sprite_ai_state[k]) {
+  case 0:  // Priest_LyingOnGround
+    if (Sprite_ShowSolicitedMessage(k, 0x1b) & 0x100) {
+      sprite_ai_state[k]++;
+      sprite_graphics[k]++;
+      sram_progress_flags |= 0x2;
+      sprite_delay_aux2[k] = 128;
+    }
+    break;
+  case 1:  // Priest_FinalWords
+    sprite_graphics[k] = 0;
+    if (sprite_delay_aux2[k] == 0)
+      sprite_ai_state[k]++;
+    sprite_A[k] = frame_counter & 2;
+    if (!(sprite_delay_aux2[k] & 7))
+      SpriteSfx_QueueSfx2WithPan(k, 0x33);
+    break;
+  case 2:  // Priest_Die
+    sprite_state[k] = 0;
+    break;
+  }
+}
+
+void Priest_RunRescueCutscene(int k) {  // 85dd63
+  int j;
+  switch (sprite_ai_state[k]) {
+  case 0:
+    sprite_head_dir[k] = 0;
+    sprite_D[k] = 0;
+    if (sprite_delay_main[k] == 0) {
+      Sprite_ShowMessageUnconditional(0x17);
+      sprite_ai_state[k]++;
+      byte_7FFE01 = 1;
+      Priest_SpawnRescuedPrincess();
+      flag_is_link_immobilized = 1;
+      savegame_map_icons_indicator = 1;
+    }
+    break;
+  case 1:
+    if (byte_7FFE01 == 2) {
+      Sprite_ShowMessageUnconditional(0x18);
+      sprite_ai_state[k]++;
+    }
+    break;
+  case 2:
+    if (choice_in_multiselect_box == 0) {
+      sprite_ai_state[k]++;
+      flag_is_link_immobilized = 0;
+    } else {
+      sprite_ai_state[k] = 1;
+    }
+    break;
+  case 3:
+    sprite_head_dir[k] = Sprite_DirectionToFaceLink(k, NULL) ^ 3;
+    j = Sprite_ShowSolicitedMessage(k, 0x16);
+    if (j & 0x100)
+      sprite_D[k] = sprite_head_dir[k] = (uint8)j;
+    break;
+  }
+}
+
+void Priest_Chillin(int k) {  // 85dde5
+  sprite_head_dir[k] = Sprite_DirectionToFaceLink(k, NULL) ^ 3;
+  int m = (link_which_pendants & 7) == 7 ? 0x1a :
+          savegame_map_icons_indicator >= 3 ? 0x19 : 0x16;
+  int j = Sprite_ShowSolicitedMessage(k, m);
+  if (j & 0x100) {
+    sprite_D[k] = sprite_head_dir[k] = (uint8)j;
+    link_hearts_filler = 0xa0;
+  }
+}
+
+void Sprite_Uncle(int k) {  // 85de2c
+  Uncle_Draw(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  if (sprite_subtype2[k] == 0)
+    Uncle_AtHouse(k);
+  else
+    Uncle_InPassage(k);
+}
+
+void Uncle_AtHouse(int k) {  // 85de3e
+  Sprite_MoveXY(k);
+  switch (sprite_ai_state[k]) {
+  case 0:  // Uncle_TriggerTelepathy
+    link_x_coord_prev = 0x940;
+    link_y_coord_prev = 0x215a;
+    Sprite_ShowMessageUnconditional(0x1f);
+    sprite_ai_state[k]++;
+    break;
+  case 1:  // Uncle_AwakenLink
+    if (frame_counter & 3)
+      break;
+    if (COLDATA_copy0 != 32) {
+      COLDATA_copy0--;
+      COLDATA_copy1--;
+      break;
+    }
+    link_pose_during_opening++;
+    player_sleep_in_bed_state++;
+    link_y_coord = 0x2157;
+    flag_is_link_immobilized = 1;
+    sprite_ai_state[k]++;
+    break;
+  case 2:  // Uncle_DeclareCurfew
+    Sprite_ShowMessageUnconditional(0x0d);
+    music_control = 3;
+    sprite_graphics[k] = 1;
+    sprite_ai_state[k]++;
+    break;
+  case 3:  // Uncle_Embark
+    sprite_graphics[k] = frame_counter >> 3 & 1;
+    if (!sprite_delay_main[k]) {
+      int j = sprite_A[k];
+      if (j == 2) {
+        sprite_ai_state[k]++;
+      } else {
+        sprite_A[k]++;
+        if (!j)
+          sprite_y_lo[k] -= 2;
+        sprite_delay_main[k] = kUncle_LeaveHouse_Delay[j];
+        sprite_D[k] = j = kUncle_LeaveHouse_Dir[j];
+        sprite_x_vel[k] = kUncle_LeaveHouse_Xvel[j];
+        sprite_y_vel[k] = kUncle_LeaveHouse_Yvel[j];
+      }
+    }
+    break;
+  case 4:  // Uncle_ApplyTelepathyFollower
+    follower_indicator = 5;
+    word_7E02CD = 0xdf3;
+    sram_progress_flags |= 0x10;
+    sprite_state[k] = 0;
+    flag_is_link_immobilized = 0;
+    break;
+  }
+}
+
+void Uncle_InPassage(int k) {  // 85df19
+  switch (sprite_ai_state[k]) {
+  case 0:  // RemoveZeldaTelepathTagalong
+    if (Sprite_CheckDamageToLink_same_layer(k))
+      Link_CancelDash();
+    if (Sprite_ShowMessageOnContact(k, 0xe) & 0x100) {
+      follower_indicator = 0;
+      sprite_ai_state[k]++;
+    }
+    break;
+  case 1:  // GiveSwordAndShield
+    item_receipt_method = 0;
+    Link_ReceiveItem(0, 0);
+    sprite_ai_state[k]++;
+    sprite_graphics[k] = 1;
+    which_starting_point = 3;
+    sram_progress_flags |= 1;
+    sram_progress_indicator = 1;
+    break;
+  }
+}
+
+void Sprite_QuarrelBros(int k) {  // 85e013
+  QuarrelBros_Draw(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  Sprite_TrackBodyToHead(k);
+  sprite_head_dir[k] = Sprite_DirectionToFaceLink(k, NULL) ^ 3;
+  if (!(dungeon_room_index & 1)) {
+    Sprite_ShowSolicitedMessage(k, 0x131);
+  } else if (!(dung_door_opened & 0xff00)) {
+    Sprite_ShowSolicitedMessage(k, 0x12f);
+  } else {
+    Sprite_ShowSolicitedMessage(k, 0x130);
+  }
+  Sprite_BehaveAsBarrier(k);
+}
+
+void QuarrelBros_Draw(int k) {  // 85e17f
+  static const DrawMultipleData kQuarrelBros_Dmd[16] = {
+    {0, -12, 0x0004, 2},
+    {0,   0, 0x000a, 2},
+    {0, -11, 0x0004, 2},
+    {0,   1, 0x400a, 2},
+    {0, -12, 0x0004, 2},
+    {0,   0, 0x000a, 2},
+    {0, -11, 0x0004, 2},
+    {0,   1, 0x400a, 2},
+    {0, -12, 0x0008, 2},
+    {0,   0, 0x000a, 2},
+    {0, -11, 0x0008, 2},
+    {0,   1, 0x400a, 2},
+    {0, -12, 0x4008, 2},
+    {0,   0, 0x000a, 2},
+    {0, -11, 0x4008, 2},
+    {0,   1, 0x400a, 2},
+  };
+  PrepOamCoordsRet info;
+  Sprite_DrawMultiplePlayerDeferred(k, &kQuarrelBros_Dmd[sprite_graphics[k] * 2 + sprite_D[k] * 4], 2, &info);
+  SpriteDraw_Shadow(k, &info);
+
+}
+
+void Sprite_YoungSnitchLady(int k) {  // 85e2f2
+  Sprite_OldSnitchLady(k);
+}
+
+void YoungSnitchLady_Draw(int k) {  // 85e37f
+  static const DrawMultipleData kYoungSnitchLady_Dmd[16] = {
+    {0, -8, 0x0026, 2},
+    {0,  0, 0x00e8, 2},
+    {0, -7, 0x0026, 2},
+    {0,  1, 0x40e8, 2},
+    {0, -8, 0x0024, 2},
+    {0,  0, 0x00c2, 2},
+    {0, -7, 0x0024, 2},
+    {0,  1, 0x40c2, 2},
+    {0, -8, 0x0028, 2},
+    {0,  0, 0x00e4, 2},
+    {0, -7, 0x0028, 2},
+    {0,  1, 0x00e6, 2},
+    {0, -8, 0x4028, 2},
+    {0,  0, 0x40e4, 2},
+    {0, -7, 0x4028, 2},
+    {0,  1, 0x40e6, 2},
+  };
+  PrepOamCoordsRet info;
+  Sprite_DrawMultiplePlayerDeferred(k, &kYoungSnitchLady_Dmd[sprite_graphics[k] * 2 + sprite_D[k] * 4], 2, &info);
+  SpriteDraw_Shadow(k, &info);
+}
+
+void Sprite_InnKeeper(int k) {  // 85e3af
+  InnKeeper_Draw(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  Sprite_BehaveAsBarrier(k);
+  Sprite_ShowSolicitedMessage(k, link_item_flippers ? 0x183 : 0x182);
+}
+
+void InnKeeper_Draw(int k) {  // 85e3dc
+  static const DrawMultipleData kInnKeeper_Dmd[2] = {
+    {0, -8, 0x00c4, 2},
+    {0,  0, 0x00ca, 2},
+  };
+  PrepOamCoordsRet info;
+  Sprite_DrawMultiplePlayerDeferred(k, kInnKeeper_Dmd, 2, &info);
+  SpriteDraw_Shadow(k, &info);
+}
+
+void Sprite_Witch(int k) {  // 85e3fb
+  Witch_Draw(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  uint8 bak0 = sprite_flags4[k];
+  sprite_flags4[k] = 2;
+  if (Sprite_CheckDamageToLink_same_layer(k)) {
+    Sprite_NullifyHookshotDrag();
+    link_speed_setting = 0;
+    Link_CancelDash();
+  }
+  sprite_flags4[k] = bak0;
+  if (!frame_counter)
+    sprite_A[k] = (GetRandomNumber() & 1) + 2;
+  int shift = sprite_A[k] + 1;
+  sprite_graphics[k] = (frame_counter >> shift) & 7;
+  if (Sprite_CheckIfLinkIsBusy())
+    return;
+  switch (sprite_ai_state[k]) {
+  case 0:  // main
+    if (link_item_mushroom == 0) {
+      if (save_dung_info[0x109] & 0x80)
+        Sprite_ShowSolicitedMessage(k, 0x4b);
+      else
+        Sprite_ShowSolicitedMessage(k, 0x4a);
+    } else if (link_item_mushroom == 1) {
+      if (!(joypad1H_last & 0x40)) {
+        Sprite_ShowSolicitedMessage(k, 0x4c);
+      } else if (Sprite_CheckDamageToLink_same_layer(k) && hud_cur_item == kHudItem_Mushroom) {
+        Witch_AcceptShroom(k);
+      }
+    } else {
+      Sprite_ShowSolicitedMessage(k, 0x4a);
+    }
+    break;
+  case 1:  // grant cane of byrna
+    sprite_ai_state[k] = 0;
+    item_receipt_method = 0;
+    Link_ReceiveItem(0x18, 0);
+    break;
+  }
+}
+
+void Witch_AcceptShroom(int k) {  // 85e4cf
+  link_item_mushroom = 0;
+  save_dung_info[0x109] |= 0x80;
+  sound_effect_1 = 0;
+  Hud_RefreshIcon();
+  Sprite_ShowMessageUnconditional(0x4b);
+  SpriteSfx_QueueSfx1WithPan(k, 0xd);
+  flag_overworld_area_did_change = 0;
+}
+
+void Witch_Draw(int k) {  // 85e55d
+  static const OamEntSigned kWitch_DrawDataA[16] = {
+    {-3,  8, 0xae, 0x00},
+    {-3, 16, 0xbe, 0x00},
+    {-2,  8, 0xae, 0x00},
+    {-2, 16, 0xbe, 0x00},
+    {-1,  8, 0xaf, 0x00},
+    {-1, 16, 0xbf, 0x00},
+    { 0,  9, 0xaf, 0x00},
+    { 0, 17, 0xbf, 0x00},
+    { 1, 10, 0xaf, 0x00},
+    { 1, 18, 0xbf, 0x00},
+    { 0, 11, 0xaf, 0x00},
+    { 0, 18, 0xbf, 0x00},
+    {-1, 10, 0xae, 0x00},
+    {-1, 18, 0xbe, 0x00},
+    {-3,  9, 0xae, 0x00},
+    {-3, 17, 0xbe, 0x00},
+  };
+  static const OamEntSigned kWitch_DrawDataB[3] = {
+      {  0, -4, 0x80, 0x00},
+      {-11, 15, 0x86, 0x04},
+      { -3, 15, 0x86, 0x44},
+  };
+  static const OamEntSigned kWitch_DrawDataC[2] = {
+      {0, 4, 0x84, 0x00},
+      {0, 4, 0x82, 0x00},
+  };
+
+  PrepOamCoordsRet info;
+  if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
+    return;
+  Oam_AllocateDeferToPlayer(k);
+  OamEnt *oam = GetOamCurPtr();
+  int g = sprite_graphics[k] * 2;
+  uint8 x = BYTE(dungmap_var7);
+  uint8 y = HIBYTE(dungmap_var7);
+
+  SetOamPlain(oam + 0, x + kWitch_DrawDataA[g + 0].x, y + kWitch_DrawDataA[g + 0].y, info.r4 | kWitch_DrawDataA[g + 0].charnum, info.flags, 0);
+  SetOamPlain(oam + 1, x + kWitch_DrawDataA[g + 1].x, y + kWitch_DrawDataA[g + 1].y, info.r4 | kWitch_DrawDataA[g + 1].charnum, info.flags, 0);
+
+  for (int i = 0; i < 3; i++) {
+    SetOamPlain(&oam[i + 2], x + kWitch_DrawDataB[i].x, y + kWitch_DrawDataB[i].y,
+                info.r4 ^ kWitch_DrawDataB[i].charnum,
+                info.flags ^ kWitch_DrawDataB[i].flags, 2);
+  }
+  int i = (uint16)(g - 6) < 6;
+  SetOamPlain(&oam[5], x + kWitch_DrawDataC[i].x, y + kWitch_DrawDataC[i].y,
+              info.r4 | kWitch_DrawDataC[i].charnum,
+              info.flags, 2);
+  Sprite_CorrectOamEntries(k, 5, 0xff);
+}
+
+void SpritePrep_Snitches(int k) {  // 85e67d
+  sprite_D[k] = 2;
+  sprite_head_dir[k] = 2;
+  sprite_ignore_projectile[k]++;
+  sprite_A[k] = sprite_x_lo[k];
+  sprite_B[k] = sprite_x_hi[k];
+  sprite_x_vel[k] = -9;
+}
+
+void Sprite_OldSnitchLady(int k) {  // 85e6aa
+  static const int8 kOldSnitchLady_Xd[2] = {-32, 32};
+  static const int8 kOldSnitchLady_Xvel[4] = {0, 0, -9, 9};
+  static const int8 kOldSnitchLady_Yvel[4] = {-9, 9, 0, 0};
+
+  int j;
+
+  if (sprite_type[k] == 0x34) {
+    if (sprite_ai_state[k] < 2)
+      YoungSnitchLady_Draw(k);
+  } else {
+    if (sprite_subtype[k]) {
+      Sprite_ChickenLady(k);
+      return;
+    }
+    if (sprite_ai_state[k] < 3)
+      Lady_Draw(k);
+  }
+
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  if (sprite_ai_state[k] < 3) {
+    if (player_is_indoors) {
+      Sprite_TrackBodyToHead(k);
+      sprite_head_dir[k] = Sprite_DirectionToFaceLink(k, NULL) ^ 3;
+      Sprite_ShowSolicitedMessage(k, 0xad);
+      return;
+    }
+    if (!sprite_ai_state[k] && Sprite_CheckDamageToLink_same_layer(k)) {
+      sprite_D[k] = Sprite_DirectionToFaceLink(k, NULL) ^ 3;
+      sprite_delay_main[k] = 1;
+    } else {
+      if (Sprite_TrackBodyToHead(k))
+        Sprite_MoveXY(k);
+      else
+        sprite_delay_main[k] = 1;
+    }
+  }
+
+  switch (sprite_ai_state[k]) {
+  case 0: {
+    if (sprite_delay_main[k] == 0) {
+      uint16 t = (sprite_A[k] | sprite_B[k] << 8) + kOldSnitchLady_Xd[sprite_C[k]];
+      if (t == Sprite_GetX(k)) {
+        sprite_head_dir[k] = (j = sprite_D[k] ^ 1);
+        sprite_x_vel[k] = kOldSnitchLady_Xvel[j];
+        sprite_y_vel[k] = kOldSnitchLady_Yvel[j];
+        sprite_C[k] ^= 1;
+      }
+    }
+    sprite_graphics[k] = (k ^ frame_counter) >> 4 & 1;
+    uint8 bak0 = sprite_flags4[k];
+    sprite_flags4[k] = 3;
+    j = Sprite_ShowMessageOnContact(k, 0x2f);
+    sprite_flags4[k] = bak0;
+    if (j & 0x100) {
+      sprite_D[k] = j;
+      Snitch_SpawnGuard(k);
+      sprite_ai_state[k] = 1;
+    }
+    break;
+  }
+  case 1: {
+    uint16 ovx = overlord_x_lo[byte_7E0FDE] | overlord_x_hi[byte_7E0FDE] << 8;
+    uint16 ovy = overlord_y_lo[byte_7E0FDE] | overlord_y_hi[byte_7E0FDE] << 8;
+    if (ovy >= Sprite_GetY(k)) {
+      sprite_ai_state[k] = 2;
+      sprite_x_vel[k] = 0;
+      sprite_y_vel[k] = 0;
+      sprite_flags4[k] = 2;
+      uint16 pos = ((ovy - overworld_offset_base_y) & overworld_offset_mask_y) * 8;
+      pos += (((ovx >> 3) - overworld_offset_base_x) & overworld_offset_mask_x);
+      Overworld_DrawWoodenDoor(pos, false);
+      sprite_delay_main[k] = 16;
+    } else {
+      flag_is_link_immobilized = 1;
+      ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLocation(k, ovx, ovy, 64);
+      sprite_x_vel[k] = pt.x;
+      sprite_y_vel[k] = pt.y;
+      sprite_D[k] = 0;
+      sprite_head_dir[k] = 0;
+      sprite_graphics[k] = (k ^ frame_counter) >> 3 & 1;
+    }
+    break;
+  }
+  case 2:
+    if (sprite_delay_main[k] == 0) {
+      uint16 ovx = overlord_x_lo[byte_7E0FDE] | overlord_x_hi[byte_7E0FDE] << 8;
+      uint16 ovy = overlord_y_lo[byte_7E0FDE] | overlord_y_hi[byte_7E0FDE] << 8;
+      Sprite_SetX(k, ovx);
+      Sprite_SetY(k, ovy);
+      uint16 pos = ((ovy - overworld_offset_base_y) & overworld_offset_mask_y) * 8;
+      pos += (((ovx >> 3) - overworld_offset_base_x) & overworld_offset_mask_x);
+      Overworld_DrawWoodenDoor(pos, true);
+      sprite_ai_state[k] = 3;
+    }
+    Sprite_MoveXY(k);
+    break;
+  case 3:
+    sprite_state[k] = 0;
+    flag_is_link_immobilized = 0;
+    break;
+  }
+}
+
+void SpritePrep_RunningMan(int k) {  // 85e896
+  sprite_head_dir[k] = 2;
+  sprite_D[k] = 2;
+  sprite_ignore_projectile[k]++;
+}
+
+void Sprite_RunningMan(int k) {  // 85e8b2
+  static const int8 kRunningMan_Xvel2[2] = {-24, 24};
+  static const int8 kRunningMan_Xvel[4] = {0, 0, -54, 54};
+  static const int8 kRunningMan_Yvel[4] = {-54, 54, 0, 0};
+  static const int8 kRunningMan_Dir[4] = {3, 1, 3, -1};
+  static const uint8 kRunningMan_A[4] = {120, 24, 128, 3};
+  int j;
+  RunningMan_Draw(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  Sprite_TrackBodyToHead(k);
+  Sprite_BehaveAsBarrier(k);
+  sprite_subtype[k] = 255;
+  Sprite_CheckTileCollision(k);
+  uint8 bak0 = sprite_flags4[k];
+  sprite_flags4[k] = 7;
+  if (Sprite_CheckDamageToLink_same_layer(k)) {
+    sprite_C[k] = sprite_ai_state[k];
+    sprite_ai_state[k] = 3;
+  }
+  sprite_flags4[k] = bak0;
+  switch (sprite_ai_state[k]) {
+  case 0:  // chill
+    Sprite_TrackBodyToHead(k);
+    j = Sprite_DirectionToFaceLink(k, NULL);
+    sprite_head_dir[k] = j ^ 3;
+    if (Sprite_CheckDamageToLink_same_layer(k)) {
+      Link_CancelDash();
+      sprite_D[k] = j ^ 3;
+      sprite_head_dir[k] = j | 2;
+      sprite_ai_state[k] = (j & 1) + 1;
+      sprite_x_vel[k] = kRunningMan_Xvel2[j & 1];
+      sprite_delay_main[k] = 32;
+    } else {
+      sprite_x_vel[k] = 0;
+      sprite_y_vel[k] = 0;
+    }
+    break;
+  case 1:  // run left
+  case 2:  // run right
+    if (sprite_delay_main[k] != 0) {
+      sprite_graphics[k] = frame_counter >> 3 & 1;
+      Sprite_MoveXY(k);
+    } else {
+      RunningBoy_SpawnDustGarnish(k);
+      sprite_graphics[k] = frame_counter >> 2 & 1;
+      j = sprite_head_dir[k];
+      sprite_x_vel[k] = kRunningMan_Xvel[j];
+      sprite_y_vel[k] = kRunningMan_Yvel[j];
+      Sprite_MoveXY(k);
+      if (sprite_A[k]) {
+        sprite_A[k]--;
+        break;
+      }
+      if (sprite_ai_state[k] == 1) {  // left
+        sprite_A[k] = 255;
+        sprite_head_dir[k] = 2;
+      } else {
+        j = sprite_B[k]++;
+        sprite_A[k] = kRunningMan_A[j];
+        if (kRunningMan_Dir[j] < 0) {
+          sprite_ai_state[k] = 0;
+          sprite_subtype2[k] = 0;
+        } else {
+          sprite_head_dir[k] = kRunningMan_Dir[j];
+        }
+      }
+    }
+    break;
+  case 3:  // caught
+    Sprite_ShowMessageUnconditional(0xa6);
+    if (link_player_handler_state >= kPlayerState_RecoilWall)  // wtf
+      sprite_D[k] = link_player_handler_state;
+    sprite_ai_state[k] = sprite_C[k];
+    break;
+
+  }
+}
+
+void RunningMan_Draw(int k) {  // 85ea4d
+  static const DrawMultipleData kRunningMan_Dmd[16] = {
+    {0, -8, 0x002c, 2},
+    {0,  0, 0x08ee, 2},
+    {0, -7, 0x002c, 2},
+    {0,  1, 0x48ee, 2},
+    {0, -8, 0x002a, 2},
+    {0,  0, 0x08ca, 2},
+    {0, -7, 0x002a, 2},
+    {0,  1, 0x48ca, 2},
+    {0, -8, 0x002e, 2},
+    {0,  0, 0x08cc, 2},
+    {0, -7, 0x002e, 2},
+    {0,  1, 0x08ce, 2},
+    {0, -8, 0x402e, 2},
+    {0,  0, 0x48cc, 2},
+    {0, -7, 0x402e, 2},
+    {0,  1, 0x48ce, 2},
+  };
+  PrepOamCoordsRet info;
+  Sprite_DrawMultiplePlayerDeferred(k, &kRunningMan_Dmd[(sprite_D[k] * 4 + sprite_graphics[k] * 2) & 0xf], 2, &info);
+  SpriteDraw_Shadow(k, &info);
+}
+
+void Sprite_BottleVendor(int k) {  // 85ea79
+  int j;
+
+  sprite_A[k] = BottleVendor_Draw(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  BottleMerchant_DetectFish(k);
+  Sprite_BehaveAsBarrier(k);
+  if (Sprite_CheckIfLinkIsBusy())
+    return;
+  if (GetRandomNumber() == 0) {
+    sprite_delay_main[k] = 20;
+    sprite_graphics[k] = 1;
+  } else if (!sprite_delay_main[k]) {
+    sprite_graphics[k] = 0;
+  }
+  switch (sprite_ai_state[k]) {
+  case 0:  // base
+    if (!sprite_A[k] && sprite_E[k])
+      sprite_ai_state[k] = 3;
+    else if (sram_progress_indicator_3 & 2)
+      Sprite_ShowSolicitedMessage(k, 0xd4);
+    else if (Sprite_ShowSolicitedMessage(k, 0xd1) & 0x100)
+      sprite_ai_state[k] = 1;
+    break;
+  case 1:  // selling
+    if (choice_in_multiselect_box == 0 && link_rupees_goal >= 100) {
+      Sprite_ShowMessageUnconditional(0xd2);
+      sprite_ai_state[k] = 2;
+    } else {
+      Sprite_ShowMessageUnconditional(0xd3);
+      sprite_ai_state[k] = 0;
+    }
+    break;
+  case 2:  // giving
+    item_receipt_method = 0;
+    Link_ReceiveItem(0x16, 0);
+    sram_progress_indicator_3 |= 2;
+    link_rupees_goal -= 100;
+    sprite_ai_state[k] = 0;
+    break;
+  case 3:  // buying
+    if (!sign8(sprite_E[k]))
+      Sprite_ShowMessageUnconditional(0xd5);
+    else
+      Sprite_ShowMessageUnconditional(0xd6);
+    sprite_ai_state[k] = 4;
+    break;
+  case 4:  // reward
+    j = sprite_E[k];
+    if (!sign8(j)) {
+      sprite_state[j - 1] = 0;
+      BottleMerchant_BuyBee(k);
+    } else {
+      sprite_state[j & 0xf] = 0;
+      BottleMerchant_BuyFish(k);
+    }
+    sprite_E[k] = 0;
+    sprite_ai_state[k] = 0;
+    break;
+  }
+
+}
+
+uint8 BottleVendor_Draw(int k) {  // 85eba7
+  PrepOamCoordsRet info;
+  static const DrawMultipleData kBottleVendor_Dmd[4] = {
+    {0, -7, 0x00ac, 2},
+    {0,  0, 0x0088, 2},
+    {0, -6, 0x00ac, 2},
+    {0,  0, 0x00a2, 2},
+  };
+  Sprite_DrawMultiplePlayerDeferred(k, &kBottleVendor_Dmd[sprite_graphics[k] * 2], 2, &info);
+  SpriteDraw_Shadow(k, &info);
+  return (info.x | info.y) >> 8;
+}
+
+void Priest_SpawnRescuedPrincess() {  // 85ec4c
+  SpriteSpawnInfo info;
+  int k = Sprite_SpawnDynamically(0, 0x76, &info);
+  if (k < 0)
+    return;
+  sprite_D[k] = sprite_head_dir[k] = tagalong_layerbits[tagalong_var2] & 3;
+  Sprite_SetX(k, link_x_coord);
+  Sprite_SetY(k, link_y_coord);
+  sprite_subtype2[k] = 1;
+  follower_indicator = 0;
+  sprite_ignore_projectile[k]++;
+  sprite_flags4[k] = 3;
+}
+
+void Sprite_76_Zelda(int k) {  // 85ec9e
+  CrystalMaiden_Draw(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  Sprite_BehaveAsBarrier(k);
+  if (Sprite_TrackBodyToHead(k))
+    Sprite_MoveXY(k);
+  switch (sprite_subtype2[k]) {
+  case 0: Zelda_InCell(k); break;
+  case 1: Zelda_EnteringSanctuary(k); break;
+  case 2: Zelda_AtSanctuary(k); break;
+  }
+}
+
+void Zelda_InCell(int k) {  // 85ecbf
+  int j;
+  sprite_head_dir[k] = Sprite_DirectionToFaceLink(k, NULL) ^ 3;
+  switch (sprite_ai_state[k]) {
+  case 0:  // AwaitingRescue
+    if (!Sprite_CheckDamageToLink_same_layer(k))
+      return;
+    sprite_ai_state[k]++;
+    flag_is_link_immobilized++;
+    j = sprite_head_dir[k];
+    sprite_x_vel[k] = kZelda_Xvel[j];
+    sprite_y_vel[k] = kZelda_Yvel[j];
+    sprite_delay_main[k] = 16;
+    break;
+  case 1:  // ApproachingPlayer
+    if (!sprite_delay_main[k]) {
+      sprite_ai_state[k]++;
+      Sprite_ShowMessageUnconditional(0x1c);
+      sprite_x_vel[k] = 0;
+      sprite_y_vel[k] = 0;
+      music_control = 25;
+    }
+    sprite_graphics[k] = frame_counter >> 3 & 1;
+    break;
+  case 2:  // TheWizardIsBadMkay
+    sprite_ai_state[k]++;
+    Sprite_ShowMessageUnconditional(0x25);
+    break;
+  case 3:  // WaitUntilPlayerPaysAttention
+    if (choice_in_multiselect_box) {
+      sprite_ai_state[k] = 2;
+    } else {
+      sprite_ai_state[k]++;
+      Sprite_ShowMessageUnconditional(0x24);
+    }
+    break;
+  case 4:  // TransitionToTagalong
+    flag_is_link_immobilized = 0;
+    which_starting_point = 2;
+    SavePalaceDeaths();
+    follower_indicator = 1;
+    Dungeon_FlagRoomData_Quadrants();
+    Sprite_BecomeFollower(k);
+    sprite_state[k] = 0;
+    music_control = 16;
+    break;
+  }
+}
+
+void Zelda_EnteringSanctuary(int k) {  // 85ed69
+  static const uint8 kZelda_Delay0[4] = {38, 26, 44, 1};
+  static const uint8 kZelda_Dir0[4] = {1, 3, 1, 2};
+  int j;
+  switch (sprite_ai_state[k]) {
+  case 0:  // walk to priest
+    if (sprite_delay_main[k] == 0) {
+      j = sprite_A[k];
+      if (j >= 4) {
+        sprite_ai_state[k]++;
+        sprite_head_dir[k] = sprite_D[k] = 0;
+        sprite_x_vel[k] = 0;
+        sprite_y_vel[k] = 0;
+        return;
+      }
+      sprite_delay_main[k] = kZelda_Delay0[j];
+      sprite_D[k] = sprite_head_dir[k] = j = kZelda_Dir0[j];
+      sprite_A[k]++;
+      sprite_x_vel[k] = kZelda_Xvel[j];
+      sprite_y_vel[k] = kZelda_Yvel[j];
+    }
+    sprite_graphics[k] = (frame_counter >> 3) & 1;
+    break;
+  case 1:  // respond to priest
+    Sprite_ShowMessageUnconditional(0x1d);
+    sprite_ai_state[k]++;
+    byte_7FFE01 = 2;
+    which_starting_point = 1;
+    SavePalaceDeaths();
+    sram_progress_indicator = 2;
+    Sprite_LoadGraphicsProperties_light_world_only();
+    break;
+  case 2:  // be careful
+    sprite_head_dir[k] = Sprite_DirectionToFaceLink(k, NULL) ^ 3;
+    j = Sprite_ShowSolicitedMessage(k, 0x1e);
+    if (j & 0x100)
+      sprite_D[k] = sprite_head_dir[k] = (uint8)j;
+    break;
+  }
+}
+
+void Zelda_AtSanctuary(int k) {  // 85ee0c
+  sprite_head_dir[k] = Sprite_DirectionToFaceLink(k, NULL) ^ 3;
+  int m = (link_which_pendants & 7) == 7 ? 0x27 :
+          savegame_map_icons_indicator >= 3 ? 0x26 : 0x1e;
+  int j = Sprite_ShowSolicitedMessage(k, m);
+  if (j & 0x100) {
+    sprite_D[k] = sprite_head_dir[k] = (uint8)j;
+    link_hearts_filler = 0xa0;
+  }
+}
+
+void SpritePrep_Mushroom(int k) {  // 85ee53
+  if (link_item_mushroom >= 2) {
+    sprite_state[k] = 0;
+  } else {
+    sprite_graphics[k] = 0;
+    sprite_oam_flags[k] |= 8;
+    sprite_ignore_projectile[k]++;
+  }
+}
+
+void Sprite_E7_Mushroom(int k) {  // 85ee78
+  SpriteDraw_SingleLarge(k);
+  if (Sprite_CheckIfLinkIsBusy())
+    return;
+
+  // If we're in the middle of a mirror warp, don't get the mushroom yet
+  if (enhanced_features0 & kFeatures0_MiscBugFixes && submodule_index != 0)
+    return;
+
+  if (Sprite_CheckDamageToLink_same_layer(k)) {
+    sprite_state[k] = 0;
+    item_receipt_method = 0;
+    Link_ReceiveItem(0x29, 0);
+  } else if ((frame_counter & 0x1f) == 0) {
+    sprite_oam_flags[k] ^= 0x40;
+  }
+}
+
+void Sprite_E8_FakeSword(int k) {  // 85eeaf
+  FakeSword_Draw(k);
+  if (Sprite_ReturnIfPaused(k))
+    return;
+  if (sprite_unk3[k] == 3) {
+    if (!sprite_C[k]) {
+      sprite_C[k] = 1;
+      Sprite_ShowMessageUnconditional(0x6f);
+    }
+  } else {
+    Sprite_MoveXY(k);
+    ThrownSprite_TileAndSpriteInteraction(k);
+  }
+}
+
+void FakeSword_Draw(int k) {  // 85eee6
+  Sprite_DrawMultiplePlayerDeferred(k, kFakeSword_Dmd, 2, NULL);
+}
+
+void SpritePrep_HeartContainer(int k) {  // 85ef01
+  HeartUpgrade_CheckIfAlreadyObtained(k);
+}
+
+void Sprite_HeartContainer(int k) {  // 85ef47
+  if (BYTE(cur_palace_index_x2) == 26) {
+    sprite_state[k] = 0;
+    return;
+  }
+  sprite_ignore_projectile[k] = sprite_G[k];
+  if (!sprite_G[k]) {
+    DecodeAnimatedSpriteTile_variable(3);
+    Sprite_Get16BitCoords(k);
+    sprite_G[k] = 1;
+  }
+
+  if (BYTE(dungeon_room_index2) == 6 && !sprite_z[k])
+    SpriteDraw_WaterRipple_WithOamAdjust(k);
+  SpriteDraw_SingleLarge(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  sprite_z_vel[k] -= 2;
+  Sprite_MoveZ(k);
+  if (sign8(sprite_z[k])) {
+    sprite_z[k] = 0;
+    sprite_z_vel[k] = (uint8)-sprite_z_vel[k] >> 2;
+    if (BYTE(dungeon_room_index2) == 6 && !sprite_subtype[k]) {
+      sprite_flags2[k] += 2;
+      sprite_subtype[k] = 1;
+      Sprite_SpawnWaterSplash(k);
+    }
+  }
+  if (Sprite_CheckIfLinkIsBusy())
+    return;
+  if (!Sprite_CheckDamageToLink_same_layer(k))
+    return;
+  sprite_state[k] = 0;
+  if (sprite_A[k]) {
+    item_receipt_method = 2;
+    Link_ReceiveItem(0x3e, 0);
+    dung_savegame_state_bits |= 0x8000;
+    return;
+  }
+  Link_CancelDash();
+  item_receipt_method = 0;
+  Link_ReceiveItem(0x26, 0);
+  if (!player_is_indoors)
+    save_ow_event_info[BYTE(overworld_screen_index)] |= 0x40;
+  else
+    dung_savegame_state_bits |= (sprite_x_hi[k] & 1) ? 0x2000 : 0x4000;
+}
+
+void Sprite_HeartPiece(int k) {  // 85f020
+  static const uint16 kHeartPieceMsg[4] = {0x158, 0x155, 0x156, 0x157};
+  if (!sprite_ai_state[k]) {
+    sprite_ai_state[k]++;
+    HeartUpgrade_CheckIfAlreadyObtained(k);
+    if (!sprite_state[k])
+      return;
+  }
+  SpriteDraw_SingleLarge(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  if (Sprite_CheckIfLinkIsBusy())
+    return;
+
+  if (Sprite_CheckTileCollision(k) & 3)
+    sprite_x_vel[k] = -sprite_x_vel[k];
+
+  sprite_z_vel[k]--;
+  Sprite_MoveZ(k);
+  Sprite_MoveXY(k);
+  if (sign8(sprite_z[k])) {
+    sprite_z[k] = 0;
+    sprite_z_vel[k] = ((sprite_z_vel[k] ^ 255) & 248) >> 1;
+    sprite_x_vel[k] = (int8)sprite_x_vel[k] >> 1;
+  }
+
+  if (sprite_delay_aux4[k] || !Sprite_CheckDamageToLink_same_layer(k))
+    return;
+
+  link_heart_pieces = link_heart_pieces + 1 & 3;
+  if (link_heart_pieces == 0) {
+    Link_CancelDash();
+    item_receipt_method = 0;
+    Link_ReceiveItem(0x26, 0);
+  } else {
+    SpriteSfx_QueueSfx3WithPan(k, 0x2d);
+    Sprite_ShowMessageUnconditional(kHeartPieceMsg[link_heart_pieces]);
+  }
+  sprite_state[k] = 0;
+  HeartUpgrade_SetObtainedFlag(k);
+}
+
+void HeartUpgrade_SetObtainedFlag(int k) {  // 85f0c3
+  if (!player_is_indoors) {
+    save_ow_event_info[BYTE(overworld_screen_index)] |= 0x40;
+  } else {
+    int j = sprite_x_hi[k] & 1;
+    dung_savegame_state_bits |= (j ? 0x2000 : 0x4000);
+  }
+}
+
+void Sprite_Aginah(int k) {  // 85f0ea
+  if (!(sram_progress_flags & 0x20))
+    goto default_msg;
+  if (link_sword_type >= 2) {
+    Sprite_ShowSolicitedMessage(k, 0x128);
+  } else if ((link_which_pendants & 7) == 7) {
+    Sprite_ShowSolicitedMessage(k, 0x126);
+  } else if ((link_which_pendants & 2) != 0) {
+    Sprite_ShowSolicitedMessage(k, 0x129);
+  } else if (link_item_book_of_mudora) {
+    Sprite_ShowSolicitedMessage(k, 0x127);
+  } else {
+default_msg:
+    sram_progress_flags |= 0x20;
+    Sprite_ShowSolicitedMessage(k, 0x125);
+  }
+  sprite_graphics[k] = frame_counter >> 5 & 1;
+}
+
+void Sprite_Sahasrahla(int k) {  // 85f14d
+  switch (sprite_ai_state[k]) {
+  case 0:  // dialogue
+    Sasha_Idle(k);
+    break;
+  case 1:  // mark map
+    Sprite_ShowMessageUnconditional(0x33);
+    sprite_ai_state[k] = 0;
+    savegame_map_icons_indicator = 3;
+    break;
+  case 2:  // grant boots
+    item_receipt_method = 0;
+    Link_ReceiveItem(0x4b, 0);
+    sprite_ai_state[k] = 3;
+    savegame_map_icons_indicator = 3;
+    break;
+  case 3:  // shamelessly promote ice rod
+    Sprite_ShowMessageUnconditional(0x37);
+    sprite_ai_state[k] = 0;
+    break;
+  }
+}
+
+void Sasha_Idle(int k) {  // 85f160
+  if (!(link_which_pendants & 4)) {
+    if (Sprite_ShowSolicitedMessage(k, 0x32) & 0x100)
+      sprite_ai_state[k] = 1;
+  } else if (!link_item_boots) {
+    int m = (savegame_map_icons_indicator >= 3) ? 0x38 : 0x39;
+    if (Sprite_ShowSolicitedMessage(k, m) & 0x100)
+      sprite_ai_state[k] = 2;
+  } else if (!link_item_ice_rod) {
+    Sprite_ShowSolicitedMessage(k, 0x37);
+  } else if ((link_which_pendants & 7) != 7) {
+    Sprite_ShowSolicitedMessage(k, 0x34);
+  } else if (link_sword_type < 2) {
+    Sprite_ShowSolicitedMessage(k, 0x30);
+  } else {
+    Sprite_ShowSolicitedMessage(k, 0x31);
+  }
+  sprite_graphics[k] = frame_counter >> 5 & 1;
+}
+
+void Elder_Draw(int k) {  // 85f23a
+  static const DrawMultipleData kElder_Dmd[4] = {
+    {0, -9, 0x00a0, 2},
+    {0,  0, 0x00a2, 2},
+    {0, -8, 0x00a0, 2},
+    {0,  0, 0x40a4, 2},
+  };
+  PrepOamCoordsRet info;
+  Sprite_DrawMultiplePlayerDeferred(k, &kElder_Dmd[sprite_graphics[k] * 2], 2, &info);
+  SpriteDraw_Shadow(k, &info);
+}
+
+void Sprite_DustCloud(int k) {  // 85f2b2
+  static const uint8 kDustCloud_Gfx[9] = {0, 1, 2, 3, 4, 5, 1, 0, 0xff};
+  DustCloud_Draw(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  if (sprite_delay_main[k])
+    return;
+  sprite_delay_main[k] = 5;
+  if (!sign8(kDustCloud_Gfx[sprite_A[k]])) {
+    sprite_graphics[k] = kDustCloud_Gfx[sprite_A[k]];
+    sprite_A[k]++;
+  } else {
+    sprite_state[k] = 0;
+  }
+}
+
+int Sprite_SpawnDustCloud(int k) {  // 85f2d6
+  SpriteSpawnInfo info;
+  int j = Sprite_SpawnDynamically(k, 0xF2, &info);
+  if (j >= 0) {
+    info.r2_y += (GetRandomNumber() & 15);
+    info.r0_x += (GetRandomNumber() & 15) - 8;
+    Sprite_SetSpawnedCoordinates(j, &info);
+    sprite_subtype2[j] = 1;
+  }
+  return j;
+}
+
+void MedallionTablet_Main(int k) {  // 85f30c
+  MedallionTablet_Draw(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  link_position_mode &= ~0x20;
+  sprite_A[k] = 0;
+  if (Sprite_CheckDamageToLink_same_layer(k)) {
+    Sprite_NullifyHookshotDrag();
+    link_speed_setting = 0;
+    Sprite_RepelDash();
+    sprite_A[k]++;
+  }
+  if (Sprite_CheckIfLinkIsBusy())
+    return;
+  switch (sprite_ai_state[k]) {
+  case 0:  // wait for mudora
+    if (BYTE(overworld_screen_index) != 3)
+      BombosTablet(k);
+    else
+      EtherTablet(k);
+    break;
+  case 1:  // delay
+    if (!sprite_delay_main[k]) {
+      sprite_ai_state[k]++;
+      sprite_delay_main[k] = 128;
+    }
+    break;
+  case 2:  // crumbling
+    if (!sprite_delay_main[k]) {
+      sprite_ai_state[k]++;
+      sprite_delay_main[k] = 240;
+    } else {
+      if (sprite_delay_main[k] == 0x20 || sprite_delay_main[k] == 0x40 || sprite_delay_main[k] == 0x60)
+        sprite_graphics[k]++;
+      if (!(frame_counter & 7))
+        Sprite_SpawnDustCloud(k);
+    }
+    break;
+  case 3:  // final animstate
+    sprite_graphics[k] = 4;
+    break;
+  }
+}
+
+void BombosTablet(int k) {  // 85f355
+  static const uint16 kMedallionTabletMsg[2] = {0x10d, 0x10f};
+  if (link_direction_facing || Sprite_DirectionToFaceLink(k, NULL) != 2)
+    return;
+  if ((uint16)(cur_sprite_y + 16) < link_y_coord)
+    return;
+  if (filtered_joypad_H & 0x80 && link_sword_type == 2)
+    return;
+
+  int j = 1;
+  if (!(hud_cur_item == kHudItem_BookMudora && (filtered_joypad_H & 0x40)) && (j = 0, !(filtered_joypad_L & 0x80)))
+    return;
+  if (j) {
+    player_handler_timer = 0;
+    link_position_mode = 32;
+    sound_effect_1 = 0;
+    if (!sign8(link_sword_type) && link_sword_type >= 2) {
+      sprite_ai_state[k]++;
+      BombosTablet_StartCutscene();
+      sprite_delay_main[k] = 64;
+    }
+  }
+  Sprite_ShowMessageUnconditional(kMedallionTabletMsg[j]);
+}
+
+void EtherTablet(int k) {  // 85f3c4
+  static const uint16 kMedallionTabletEtherMsg[2] = {0x10d, 0x10e};
+  if (link_direction_facing || Sprite_DirectionToFaceLink(k, NULL) != 2)
+    return;
+  if ((uint8)(sprite_y_lo[k] + 16) < BYTE(link_y_coord))
+    return;
+  if (filtered_joypad_H & 0x80 && link_sword_type == 2)
+    return;
+
+  int j = 1;
+  if (!(hud_cur_item == kHudItem_BookMudora && (filtered_joypad_H & 0x40)) && (j = 0, !(filtered_joypad_L & 0x80)))
+    return;
+
+  if (j) {
+    player_handler_timer = 0;
+    link_position_mode = 32;
+    sound_effect_1 = 0;
+    if (!sign8(link_sword_type) && link_sword_type >= 2) {
+      sprite_ai_state[k]++;
+      EtherTablet_StartCutscene();
+      sprite_delay_main[k] = 64;
+    }
+  }
+  Sprite_ShowMessageUnconditional(kMedallionTabletEtherMsg[j]);
+}
+
+void ElderWife_Draw(int k) {  // 85f505
+  static const DrawMultipleData kElderWife_Dmd[4] = {
+    {0, -5, 0x008e, 2},
+    {0,  5, 0x0028, 2},
+    {0, -4, 0x008e, 2},
+    {0,  5, 0x4028, 2},
+  };
+  Sprite_DrawMultiplePlayerDeferred(k, &kElderWife_Dmd[sprite_graphics[k] * 2], 2, NULL);
+}
+
+void SpritePrep_PotionShop(int k) {  // 85f529
+  MagicShopAssistant_SpawnPowder(k);
+  MagicShopAssistant_SpawnGreenCauldron(k);
+  MagicShopAssistant_SpawnBlueCauldron(k);
+  MagicShopAssistant_SpawnRedCauldron(k);
+  sprite_ignore_projectile[k]++;
+}
+
+void MagicShopAssistant_SpawnPowder(int k) {  // 85f539
+  if (!flag_overworld_area_did_change || link_item_mushroom == 2)
+    return;
+  if (save_dung_info[0x109] & 0x80) {
+    SpriteSpawnInfo info;
+    int j = Sprite_SpawnDynamically(k, 0xe9, &info);
+    sprite_subtype2[j] = 1;
+    Sprite_SetX(j, info.r0_x - 16);
+    Sprite_SetY(j, info.r2_y);
+    sprite_flags4[j] = 3;
+    sprite_defl_bits[j] |= 0x20;
+  }
+}
+
+void MagicShopAssistant_SpawnGreenCauldron(int k) {  // 85f58e
+  SpriteSpawnInfo info;
+  int j = Sprite_SpawnDynamically(k, 0xe9, &info);
+  sprite_subtype2[j] = 2;
+  Sprite_SetX(j, info.r0_x - 40);
+  Sprite_SetY(j, info.r2_y - 72);
+  sprite_flags4[j] = 3;
+  sprite_defl_bits[j] |= 0x20;
+}
+
+void MagicShopAssistant_SpawnBlueCauldron(int k) {  // 85f5bf
+  SpriteSpawnInfo info;
+  int j = Sprite_SpawnDynamically(k, 0xe9, &info);
+  sprite_subtype2[j] = 3;
+  Sprite_SetX(j, info.r0_x + 8);
+  Sprite_SetY(j, info.r2_y - 72);
+  sprite_flags4[j] = 3;
+  sprite_defl_bits[j] |= 0x20;
+}
+
+void MagicShopAssistant_SpawnRedCauldron(int k) {  // 85f5f0
+  SpriteSpawnInfo info;
+  int j = Sprite_SpawnDynamically(k, 0xe9, &info);
+  sprite_subtype2[j] = 4;
+  Sprite_SetX(j, info.r0_x - 88);
+  Sprite_SetY(j, info.r2_y - 72);
+  sprite_flags4[j] = 3;
+  sprite_defl_bits[j] |= 0x20;
+}
+
+void Sprite_E9_PotionShop(int k) {  // 85f633
+  switch(sprite_subtype2[k]) {
+  case 0: Sprite_MagicShopAssistant_Main(k); return;
+  case 1: Sprite_BagOfPowder(k); return;
+  case 2: Sprite_GreenCauldron(k); return;
+  case 3: Sprite_BlueCauldron(k); return;
+  case 4: Sprite_RedCauldron(k); return;
+  }
+}
+
+void Sprite_BagOfPowder(int k) {  // 85f644
+  MagicPowderItem_Draw(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  Sprite_BehaveAsBarrier(k);
+  if (!Sprite_CheckDamageToLink_same_layer(k) || !(filtered_joypad_L & 0x80))
+    return;
+  Link_CancelDash();
+  item_receipt_method = 0;
+  Link_ReceiveItem(0xd, 0);
+  sprite_state[k] = 0;
+}
+
+void MagicPowderItem_Draw(int k) {  // 85f67b
+  static const DrawMultipleData kMagicPowder_Dmd[2] = {
+    {0, 0, 0x04e6, 2},
+    {0, 0, 0x04e6, 2},
+  };
+  Sprite_DrawMultiplePlayerDeferred(k, kMagicPowder_Dmd, 2, NULL);
+}
+
+void Sprite_GreenCauldron(int k) {  // 85f68e
+  GreenPotionItem_Draw(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  Sprite_BehaveAsBarrier(k);
+  if (sprite_delay_main[k])
+    return;
+  if (!PotionCauldron_CheckBottles()) {
+    if (Sprite_ShowMessageOnContact(k, 0x4f) & 0x100)
+      PotionCauldron_GoBeep(k);
+    return;
+  }
+  if (!Sprite_CheckDamageToLink_same_layer(k) || !(filtered_joypad_L & 0x80))
+    return;
+  if (link_rupees_goal < 60) {
+    Sprite_ShowMessageUnconditional(0x17c);
+    PotionCauldron_GoBeep(k);
+    return;
+  }
+  if (Sprite_Find_EmptyBottle() < 0) {
+    Sprite_ShowMessageUnconditional(0x50);
+    PotionCauldron_GoBeep(k);
+    return;
+  }
+  SpriteSfx_QueueSfx3WithPan(k, 0x1d);
+  sprite_delay_main[k] = 64;
+  link_rupees_goal -= 60;
+  item_receipt_method = 0;
+  Link_ReceiveItem(0x2f, 0);
+}
+
+void GreenPotionItem_Draw(int k) {  // 85f718
+  static const DrawMultipleData kGreenPotionItem_Dmd[3] = {
+    { 0,  0, 0x08c0, 2},
+    { 8, 18, 0x0a30, 0},
+    {-1, 18, 0x0a22, 0},
+  };
+  Sprite_DrawMultiplePlayerDeferred(k, kGreenPotionItem_Dmd, 3, NULL);
+}
+
+void Sprite_BlueCauldron(int k) {  // 85f72b
+  BluePotionItem_Draw(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  Sprite_BehaveAsBarrier(k);
+  if (sprite_delay_main[k])
+    return;
+  if (!PotionCauldron_CheckBottles()) {
+    if (Sprite_ShowMessageOnContact(k, 0x4f) & 0x100)
+      PotionCauldron_GoBeep(k);
+    return;
+  }
+  if (!Sprite_CheckDamageToLink_same_layer(k) || !(filtered_joypad_L & 0x80))
+    return;
+  if (link_rupees_goal < 160) {
+    Sprite_ShowMessageUnconditional(0x17c);
+    PotionCauldron_GoBeep(k);
+    return;
+  }
+  if (Sprite_Find_EmptyBottle() < 0) {
+    Sprite_ShowMessageUnconditional(0x50);
+    PotionCauldron_GoBeep(k);
+    return;
+  }
+  SpriteSfx_QueueSfx3WithPan(k, 0x1d);
+  sprite_delay_main[k] = 64;
+  link_rupees_goal -= 160;
+  item_receipt_method = 0;
+  Link_ReceiveItem(0x30, 0);
+}
+
+void BluePotionItem_Draw(int k) {  // 85f7bd
+  static const DrawMultipleData kBluePotionItem_Dmd[4] = {
+    { 0,  0, 0x04c0, 2},
+    {13, 18, 0x0a30, 0},
+    { 5, 18, 0x0a22, 0},
+    {-3, 18, 0x0a31, 0},
+  };
+  Sprite_DrawMultiplePlayerDeferred(k, kBluePotionItem_Dmd, 4, NULL);
+}
+
+void Sprite_RedCauldron(int k) {  // 85f7d0
+  RedPotionItem_Draw(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  Sprite_BehaveAsBarrier(k);
+  if (sprite_delay_main[k])
+    return;
+  if (!PotionCauldron_CheckBottles()) {
+    if (Sprite_ShowMessageOnContact(k, 0x4f) & 0x100)
+      PotionCauldron_GoBeep(k);
+    return;
+  }
+  if (!Sprite_CheckDamageToLink_same_layer(k) || !(filtered_joypad_L & 0x80))
+    return;
+  if (link_rupees_goal < 120) {
+    Sprite_ShowMessageUnconditional(0x17c);
+    PotionCauldron_GoBeep(k);
+    return;
+  }
+  if (Sprite_Find_EmptyBottle() < 0) {
+    Sprite_ShowMessageUnconditional(0x50);
+    PotionCauldron_GoBeep(k);
+    return;
+  }
+  SpriteSfx_QueueSfx3WithPan(k, 0x1d);
+  sprite_delay_main[k] = 64;
+  link_rupees_goal -= 120;
+  item_receipt_method = 0;
+  Link_ReceiveItem(0x2e, 0);
+}
+
+void PotionCauldron_GoBeep(int k) {  // 85f846
+  SpriteSfx_QueueSfx2WithPan(k, 0x3c);
+}
+
+void RedPotionItem_Draw(int k) {  // 85f86d
+  static const DrawMultipleData kRedPotionItem_Dmd[4] = {
+    { 0,  0, 0x02c0, 2},
+    {13, 18, 0x0a30, 0},
+    { 5, 18, 0x0a02, 0},
+    {-3, 18, 0x0a31, 0},
+  };
+  Sprite_DrawMultiplePlayerDeferred(k, kRedPotionItem_Dmd, 4, NULL);
+}
+
+bool PotionCauldron_CheckBottles() {  // 85f880
+  return (link_bottle_info[0] | link_bottle_info[1] | link_bottle_info[2] | link_bottle_info[3]) >= 2;
+}
+
+void Sprite_MagicShopAssistant_Main(int k) {  // 85f893
+  Shopkeeper_Draw(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  Sprite_BehaveAsBarrier(k);
+  if (Sprite_CheckIfLinkIsBusy())
+    return;
+  if (sprite_ai_state[k]) {
+    link_hearts_filler = 160;
+    sprite_ai_state[k] = 0;
+  }
+  sprite_graphics[k] = frame_counter >> 5 & 1;
+  int msg;
+  if (link_bottle_info[0] >= 2 || link_bottle_info[1] >= 2 || link_bottle_info[2] >= 2 || link_bottle_info[3] >= 2 || !flag_overworld_area_did_change)
+    msg = 0x4e;
+  else
+    msg = 0x4d;
+  if (Sprite_ShowSolicitedMessage(k, msg) & 0x100)
+    sprite_ai_state[k] = 1;
+}
+
+void Shopkeeper_Draw(int k) {  // 85f91b
+  static const DrawMultipleData kShopkeeper_Dmd[4] = {
+    {0, -8, 0x0c00, 2},
+    {0,  0, 0x0c10, 2},
+    {0, -8, 0x0c00, 2},
+    {0,  0, 0x4c10, 2},
+  };
+  PrepOamCoordsRet info;
+  Sprite_DrawMultiplePlayerDeferred(k, &kShopkeeper_Dmd[sprite_graphics[k] * 2], 2, &info);
+  SpriteDraw_Shadow(k, &info);
+}
+
+void Sprite_DashItem(int k) {  // 85fbf7
+  switch (sprite_graphics[k]) {
+  case 0: Sprite_BookOfMudora(k); break;
+  case 1: Sprite_BonkKey(k); break;
+  case 2: Sprite_LumberjackTree(k); break;
+  }
+}
+
+void Sprite_BonkKey(int k) {  // 85fc04
+  Sprite_DrawThinAndTall(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  if (Sprite_CheckDamageToLink_same_layer(k))
+    sprite_ai_state[k] = 3;
+  Sprite_MoveXY(k);
+  sprite_z_vel[k]--;
+  Sprite_MoveZ(k);
+  if (sign8(sprite_z[k])) {
+    sprite_y_vel[k] = 0;
+    sprite_z[k] = 0;
+    sprite_z_vel[k] = (uint8)-sprite_z_vel[k] >> 2;
+    if (sprite_z_vel[k] & 254)
+      SpriteSfx_QueueSfx3WithPan(k, 0x14);
+  }
+  switch (sprite_ai_state[k]) {
+  case 0:  // wait for dash
+    if ((uint16)(cur_sprite_x - link_x_coord + 16) < 33 &&
+        (uint16)(cur_sprite_y - link_y_coord + 24) < 41 && (bg1_x_offset | bg1_y_offset))
+      sprite_ai_state[k] = 1;
+    break;
+  case 1:  // being falling
+    sprite_z_vel[k] = 32;
+    sprite_y_vel[k] = -5;
+    sound_effect_2 = 27;
+    sprite_ai_state[k] = 2;
+    break;
+  case 2:  // falling
+    if (!sprite_z[k])
+      sprite_floor[k] = link_is_on_lower_level;
+    break;
+  case 3:  // give to player
+    link_num_keys++;
+    sprite_state[k] = 0;
+    dung_savegame_state_bits |= (sprite_die_action[k] ? 0x2000 : 0x4000);
+    SpriteSfx_QueueSfx3WithPan(k, 0x2f);
+    break;
+  }
+}
+
+void Sprite_BookOfMudora(int k) {  // 85fc9e
+  SpriteDraw_SingleLarge(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  if (Sprite_CheckDamageToLink_same_layer(k))
+    sprite_ai_state[k] = 3;
+  Sprite_MoveXY(k);
+  sprite_z_vel[k]--;
+  Sprite_MoveZ(k);
+  if (sign8(sprite_z[k])) {
+    sprite_y_vel[k] = 0;
+    sprite_z[k] = 0;
+    sprite_z_vel[k] = (uint8)-sprite_z_vel[k] >> 2;
+    if (sprite_z_vel[k] & 254)
+      SpriteSfx_QueueSfx2WithPan(k, 0x21);
+  }
+  switch (sprite_ai_state[k]) {
+  case 0:  // wait for dash
+    if (link_direction_facing == 0 &&
+        (uint16)(cur_sprite_x - link_x_coord + 39) < 47 &&
+        (uint16)(cur_sprite_y - link_y_coord + 40) < 46 && (bg1_x_offset | bg1_y_offset))
+      sprite_ai_state[k] = 1;
+    break;
+  case 1:  // being falling
+    sprite_z_vel[k] = 32;
+    sprite_y_vel[k] = -5;
+    sound_effect_2 = 27;
+    sprite_ai_state[k] = 2;
+    break;
+  case 2:  // falling
+    if (!sprite_z[k])
+      sprite_floor[k] = link_is_on_lower_level;
+    break;
+  case 3:  // give to player
+    Link_CancelDash();
+    item_receipt_method = 0;
+    Link_ReceiveItem(0x1d, 0);
+    sprite_state[k] = 0;
+    break;
+  }
+}
+
+void Sprite_LumberjackTree(int k) {  // 85fd4d
+  sprite_flags2[k] = 0x8f;
+  sprite_flags4[k] = 0x47;
+  DashTreeTop_Draw(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  if (Sprite_CheckDamageToLink_same_layer(k)) {
+    Sprite_NullifyHookshotDrag();
+    link_speed_setting = 0;
+    Sprite_RepelDash();
+  }
+  Sprite_MoveXY(k);
+  sprite_z_vel[k]--;
+  Sprite_MoveZ(k);
+  if (sign8(sprite_z[k])) {
+    sprite_z[k] = 0;
+    sprite_z_vel[k] = (uint8)-sprite_z_vel[k] >> 2;
+  }
+  switch (sprite_ai_state[k]) {
+  case 0:  // wait for dash
+    sprite_subtype2[k] = 0;
+    if ((uint16)(cur_sprite_x - link_x_coord + 24) < 65 &&
+        (uint16)(cur_sprite_y - link_y_coord + 32) < 81 && (bg1_x_offset | bg1_y_offset) & 0xff) {
+      sprite_z_vel[k] = 20;
+      sprite_ai_state[k] = 1;
+    }
+    break;
+  case 1:  // spawn leaves
+    if (!sprite_z[k]) {
+      sprite_ai_state[k]++;
+      sound_effect_2 = 0x1b;
+      sprite_x_vel[k] = -4;
+      sprite_y_vel[k] = -4;
+      int j = LumberjackTree_SpawnLeaves(k);
+      sprite_x_vel[j] = 5;
+      sprite_y_vel[j] = 5;
+      j = LumberjackTree_SpawnLeaves(k);
+      sprite_x_vel[j] = 5;
+      sprite_y_vel[j] = -4;
+      j = LumberjackTree_SpawnLeaves(k);
+      sprite_x_vel[j] = -4;
+      sprite_y_vel[j] = 4;
+    }
+    break;
+  case 2: // dancing leaves
+    if (!sprite_delay_main[k]) {
+      sprite_delay_main[k] = 8;
+      if (sprite_subtype2[k] == 6)
+        sprite_state[k] = 0;
+      sprite_subtype2[k]++;
+    }
+    break;
+  }
+}
+
+void DashTreeTop_Draw(int k) {  // 85fe6f
+  static const uint16 kDashTreeTop_CharFlags[16] = {0x3100, 0x3102, 0x7102, 0x7100, 0x3120, 0x3122, 0x7122, 0x7120, 0x3104, 0x3106, 0x7106, 0x7104, 0x3124, 0x3126, 0x7126, 0x7124};
+  static const int8 kDashTreeTop_X[16] = {10, 22, 30, 1, 34, 5, 13, 29, 0, 17, 27, 44, 15, 33, 18, 26};
+  static const int8 kDashTreeTop_Y[16] = {0, 4, 2, 7, 10, 16, 24, 23, 34, 35, 30, 31, 46, 42, 10, 11};
+  static const int8 kDashTreeTop_Char[6] = {8, 8, 0x28, 0x28, 0x2a, 0x2a};
+  static const int8 kDashTreeTop_Flags[6] = {0x31, 0x71, 0x31, 0x71, 0x31, 0x71};
+  PrepOamCoordsRet info;
+  if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
+    return;
+  OamEnt *oam = GetOamCurPtr();
+
+  BYTE(dungmap_var7) -= 0x20;
+  HIBYTE(dungmap_var7) -= 0x20;
+
+  if (!sprite_subtype2[k]) {
+    uint8 x = BYTE(dungmap_var7);
+    uint8 y = HIBYTE(dungmap_var7);
+    for (int i = 0; i < 16; i++) {
+      oam[i].x = x + (i & 3) * 0x10;
+      oam[i].y = y + (i >> 2) * 0x10;
+      WORD(oam[i].charnum) = kDashTreeTop_CharFlags[i];
+    }
+    Sprite_CorrectOamEntries(k, 15, 2);
+  } else {
+    int j = sprite_subtype2[k] - 1;
+    for (int i = 15; i >= 0; i--, oam++) {
+      oam->x = BYTE(dungmap_var7) + kDashTreeTop_X[i];
+      oam->y = HIBYTE(dungmap_var7) + kDashTreeTop_Y[i];
+      oam->charnum = kDashTreeTop_Char[j];
+      oam->flags = kDashTreeTop_Flags[j];
+    }
+    Sprite_CorrectOamEntries(k, 15, 2);
+  }
+}
+
+int LumberjackTree_SpawnLeaves(int k) {  // 85ff39
+  SpriteSpawnInfo info;
+  int j = Sprite_SpawnDynamically(k, 0x3B, &info);
+  assert(j >= 0);
+  sprite_graphics[j] = 2;
+  sprite_z_vel[j] = sprite_z_vel[k];
+  sprite_subtype2[j] = 1;
+  sprite_ai_state[j] = 2;
+  sprite_delay_main[j] = 8;
+  Sprite_SetSpawnedCoordinates(j, &info);
+  return j;
+}
+
+void Sprite_TroughBoy(int k) {  // 85ff66
+  TroughBoy_Draw(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  Sprite_BehaveAsBarrier(k);
+  Sprite_TrackBodyToHead(k);
+  sprite_head_dir[k] = Sprite_DirectionToFaceLink(k, NULL) ^ 3;
+
+  if (savegame_map_icons_indicator < 3) {
+    if (Sprite_ShowSolicitedMessage(k, 0x147) & 0x100)
+      savegame_map_icons_indicator = 2;
+  } else {
+    Sprite_ShowSolicitedMessage(k, 0x148);
+  }
+}
+
+void TroughBoy_Draw(int k) {  // 85ffdf
+  static const DrawMultipleData kTroughBoy_Dmd[8] = {
+    {0, -8, 0x0882, 2},
+    {0,  0, 0x0aaa, 2},
+    {0, -8, 0x0882, 2},
+    {0,  0, 0x0aaa, 2},
+    {0, -8, 0x4880, 2},
+    {0,  0, 0x0aaa, 2},
+    {0, -8, 0x0880, 2},
+    {0,  0, 0x0aaa, 2},
+  };
+  PrepOamCoordsRet info;
+  Sprite_DrawMultiplePlayerDeferred(k, &kTroughBoy_Dmd[sprite_D[k] * 2], 2, &info);
+  SpriteDraw_Shadow(k, &info);
+}
+
+void BottleMerchant_DetectFish(int k) {  // 868000
+  for (int i = 15; i >= 0; i--) {
+    if (sprite_state[i] && sprite_type[i] == 0xd2) {
+      SpriteHitBox hb;
+      hb.r0_xlo = sprite_x_lo[k];
+      hb.r8_xhi = sprite_x_hi[k];
+      hb.r2 = 16;
+      hb.r1_ylo = sprite_y_lo[k];
+      hb.r9_yhi = sprite_y_hi[k];
+      hb.r3 = 16;
+      Sprite_SetupHitBox(i, &hb);
+      if (CheckIfHitBoxesOverlap(&hb))
+        sprite_E[k] = 0x80 | i;
+      return;
+    }
+  }
+}
+
+void BottleMerchant_BuyFish(int k) {  // 868054
+  static const uint8 kBottleVendor_FishRewardType[5] = {0xdb, 0xe0, 0xde, 0xe2, 0xd9};
+  static const int8 kBottleVendor_FishRewardXv[5] = {-6, -3, 0, 4, 7};
+  static const int8 kBottleVendor_FishRewardYv[5] = {11, 14, 16, 14, 11};
+  SpriteSpawnInfo info;
+  SpriteSfx_QueueSfx3WithPan(k, 0x13);
+  tmp_counter = 4;
+  do {
+    int j = Sprite_SpawnDynamically(k, kBottleVendor_FishRewardType[tmp_counter], &info);
+    if (j < 0)
+      return;
+    Sprite_SetSpawnedCoordinates(j, &info);
+    sprite_x_lo[j] = info.r0_x + 4;
+    sprite_stunned[j] = 0xff;
+    sprite_x_vel[j] = kBottleVendor_FishRewardXv[tmp_counter];
+    sprite_y_vel[j] = kBottleVendor_FishRewardYv[tmp_counter];
+    sprite_z_vel[j] = 32;
+    sprite_delay_aux4[j] = 32;
+  } while (!sign8(--tmp_counter));
+}
+
+void SpritePrep_ThrowableScenery(int k) {  // 86850f
+}
+
+void SpriteModule_Initialize(int k) {  // 86864d
+  SpritePrep_LoadProperties(k);
+  sprite_state[k]++;
+  kSpritePrep_Main[sprite_type[k]](k);
+}
+
+void SpritePrep_Mantle(int k) {  // 868841
+  sprite_y_lo[k] += 3;
+  sprite_x_lo[k] += 8;
+}
+
+void SpritePrep_Switch(int k) {  // 868859
+  int j = BYTE(dungeon_room_index2);
+  if (j == 0xce || j == 4 || j == 0x3f)
+    sprite_oam_flags[k] = 0xD;
+}
+
+void SpritePrep_SwitchFacingUp(int k) {  // 86886d
+}
+
+void SpritePrep_Snitch_bounce_1(int k) {  // 86886e
+  SpritePrep_Snitches(k);
+}
+
+void SpritePrep_DoNothingA(int k) {  // 868873
+}
+
+void SpritePrep_Rat(int k) {  // 868878
+  static const uint8 kSpriteRat_BumpDamage[2] = {0, 5};
+  static const uint8 kSpriteRat_Health[2] = {2, 8};
+  int j = is_in_dark_world;
+  sprite_bump_damage[k] = kSpriteRat_BumpDamage[j];
+  sprite_health[k] = kSpriteRat_Health[j];
+}
+
+void SpritePrep_Keese(int k) {  // 86888e
+  static const uint8 kSpriteKeese_BumpDamage[2] = {0x80, 0x85};
+  static const uint8 kSpriteKeese_Health[2] = {1, 4};
+  static const uint8 kSpriteKeese_Flags5[2] = {0, 7};
+  int j = is_in_dark_world;
+  sprite_bump_damage[k] = kSpriteKeese_BumpDamage[j];
+  sprite_health[k] = kSpriteKeese_Health[j];
+  sprite_flags5[k] = kSpriteKeese_Flags5[j];
+}
+
+void SpritePrep_Rope(int k) {  // 8688aa
+  static const uint8 kSpriteRope_BumpDamage[2] = {1, 5};
+  static const uint8 kSpriteRope_Health[2] = {4, 8};
+  static const uint8 kSpriteRope_Flags5[2] = {1, 7};
+  int j = is_in_dark_world;
+  sprite_bump_damage[k] = kSpriteRope_BumpDamage[j];
+  sprite_health[k] = kSpriteRope_Health[j];
+  sprite_flags5[k] = kSpriteRope_Flags5[j];
+}
+
+void SpritePrep_Swamola(int k) {  // 8688c0
+  SpritePrep_Swamola_InitializeSegments(k);
+  SpritePrep_Kyameron(k);
+}
+
+void SpritePrep_Blind(int k) {  // 8688c7
+  if (Sprite_ReturnIfBossFinished(k))
+    return;
+  SpritePrep_Blind_PrepareBattle(k);
+}
+
+void SpritePrep_Ganon(int k) {  // 8688cf
+  if (Sprite_ReturnIfBossFinished(k))
+    return;
+  Ganon_HandleAnimation_Idle(k);
+  sprite_delay_main[k] = 128;
+  sprite_room[k] = 2;
+  music_control = 0x1e;
+}
+
+void SpritePrep_Pokey(int k) {  // 8688df
+  static const int8 kHokbok_InitXvel[4] = {16, -16, 16, -16};
+  static const int8 kHokbok_InitYvel[4] = {16, 16, -16, -16};
+  sprite_A[k] = 3;
+  sprite_B[k] = 8;
+  int j = GetRandomNumber() & 3;
+  sprite_x_vel[k] = kHokbok_InitXvel[j];
+  sprite_y_vel[k] = kHokbok_InitYvel[j];
+}
+
+void SpritePrep_MiniVitreous(int k) {  // 8688fd
+  Sprite_ReturnIfBossFinished(k);
+}
+
+void SpritePrep_Gibo(int k) {  // 868901
+  sprite_z[k] = 16;
+  sprite_G[k] = 8;
+}
+
+void SpritePrep_Octoballoon(int k) {  // 868910
+  static const uint8 kSprite_Octoballoon_Delay[4] = {192, 208, 224, 240};
+  sprite_delay_main[k] = kSprite_Octoballoon_Delay[k & 3];
+}
+
+void SpritePrep_AgahnimsBarrier(int k) {  // 86891b
+  if (save_ow_event_info[BYTE(overworld_screen_index)] & 0x40)
+    sprite_graphics[k] = 4;
+  SpritePrep_MoveDown_8px_Right8px(k);
+  sprite_y_lo[k] -= 12;
+  sprite_ignore_projectile[k]++;
+}
+
+void SpritePrep_Catfish(int k) {  // 86892c
+  SpritePrep_MoveDown_8px_Right8px(k);
+  sprite_y_lo[k] -= 12;
+  SpritePrep_IgnoreProjectiles(k);
+}
+
+void SpritePrep_CutsceneAgahnim(int k) {  // 86893b
+  if (dung_savegame_state_bits & 0x4000) {
+    sprite_state[k] = 0;
+  } else {
+    CutsceneAgahnim_SpawnZeldaOnAltar(k);
+    sprite_ignore_projectile[k]++;
+  }
+}
+
+void SpritePrep_Vitreous(int k) {  // 86894d
+  if (Sprite_ReturnIfBossFinished(k))
+    return;
+  SpritePrep_MoveDown_8px_Right8px(k);
+  sprite_y_lo[k] -= 16;
+  Vitreous_SpawnSmallerEyes(k);
+  sprite_ignore_projectile[k]++;
+}
+
+void SpritePrep_Raven(int k) {  // 868969
+  static const uint8 kSpriteRaven_BumpDamage[2] = {0x81, 0x88};
+  static const uint8 kSpriteRaven_Health[2] = {4, 8};
+  static const uint8 kSpriteRaven_Flags5[2] = {6, 2};
+  int j = is_in_dark_world;
+  sprite_bump_damage[k] = kSpriteRaven_BumpDamage[j];
+  sprite_health[k] = kSpriteRaven_Health[j];
+  sprite_flags5[k] = kSpriteRaven_Flags5[j];
+  sprite_z[k] = 0;
+  sprite_A[k] = (sprite_x_lo[k] & 16) >> 4;
+  sprite_subtype[k] = 254;
+}
+
+void SpritePrep_Vulture(int k) {  // 86897e
+  sprite_z[k] = 0;
+  sprite_A[k] = (sprite_x_lo[k] & 16) >> 4;
+  sprite_subtype[k] = 254;
+}
+
+void SpritePrep_Poe(int k) {  // 868991
+  sprite_z[k] = 12;
+  sprite_subtype[k] = 254;
+}
+
+void SpritePrep_DoNothingC(int k) {  // 86899b
+  // empty
+}
+
+void SpritePrep_BlindMaiden(int k) {  // 86899c
+  if (!(save_dung_info[0xac] & 0x800)) {
+    sprite_ignore_projectile[k]++;
+    if (follower_indicator != 6) {
+      follower_indicator = 6;
+      follower_dropped = 0;
+      tagalong_var5 = 0;
+      LoadFollowerGraphics();
+      Follower_Initialize();
+      follower_indicator = 0;
+      return;
+    }
+  }
+  sprite_state[k] = 0;
+}
+
+void SpritePrep_MiniMoldorm_bounce(int k) {  // 8689d3
+  int j = 32 * k;
+  for (int i = 0; i < 32; i++, j++) {
+    moldorm_x_lo[j] = sprite_x_lo[k];
+    moldorm_x_hi[j] = sprite_x_hi[k];
+    moldorm_y_lo[j] = sprite_y_lo[k];
+    moldorm_y_hi[j] = sprite_y_hi[k];
+  }
+}
+
+void SpritePrep_Bomber(int k) {  // 8689d8
+  sprite_z[k] = 16;
+  sprite_subtype[k] = 254;
+}
+
+void SpritePrep_BombShoppe(int k) {  // 8689df
+  sprite_ignore_projectile[k]++;
+  SpriteSpawnInfo info;
+  int j = Sprite_SpawnDynamically(k, 0xb5, &info);
+  if (j >= 0) {
+    Sprite_SetX(j, info.r0_x - 24);
+    Sprite_SetY(j, info.r2_y - 24);
+    sprite_subtype2[j] = 1;
+    sprite_ignore_projectile[j] = 1;
+  }
+  if ((link_has_crystals & 5) == 5 && sram_progress_indicator_3 & 32) {
+    int j = Sprite_SpawnDynamically(k, 0xb5, &info);
+    if (j >= 0) {
+      Sprite_SetX(j, info.r0_x - 56);
+      Sprite_SetY(j, info.r2_y - 24);
+      sprite_subtype2[j] = 2;
+      sprite_ignore_projectile[j] = 2;
+    }
+  }
+}
+
+void SpritePrep_BullyAndVictim(int k) {  // 868a51
+  SpawnBully(k);
+  sprite_ignore_projectile[k]++;
+}
+
+void SpritePrep_PurpleChest(int k) {  // 868a59
+  if (follower_indicator != 12 && !(sram_progress_indicator_3 & 16) && sram_progress_indicator_3 & 32)
+    sprite_ignore_projectile[k]++;
+  else
+    sprite_state[k] = 0;
+}
+
+void SpritePrep_Smithy(int k) {  // 868a79
+  sprite_ignore_projectile[k]++;
+  if (savegame_is_darkworld & 64) {
+    if (sram_progress_indicator_3 & 32 || follower_indicator != 0)
+      sprite_state[k] = 0;
+    else
+      sprite_subtype2[k] = 2;
+    return;
+  }
+  Smithy_SpawnDumbBarrierSprite(k);
+  if (!(sram_progress_indicator_3 & 32)) {
+    sprite_x_lo[k] += 2;
+    sprite_y_lo[k] -= 3;
+    return;
+  }
+  sprite_x_lo[k] += 2;
+  sprite_y_lo[k] -= 3;
+  int j = Smithy_SpawnDwarfPal(k);
+  Smithy_SpawnDumbBarrierSprite(j);
+  sprite_E[j] = k;
+  sprite_E[k] = j;
+
+  if (sram_progress_indicator_3 & 0x80) {
+    sprite_ai_state[k] = 5;
+    sprite_ai_state[j] = 5;
+  }
+}
+
+void SpritePrep_Babasu(int k) {  // 868af0
+  SpritePrep_MoveDown_8px(k);
+  SpritePrep_Zoro(k);
+}
+
+void SpritePrep_Zoro(int k) {  // 868af3
+  sprite_D[k] = (sprite_type[k] - 0x9c) << 1;
+  sprite_graphics[k]--;
+}
+
+void SpritePrep_LaserEye_bounce(int k) {  // 868b03
+  int t = sprite_type[k];
+  sprite_D[k] = t - 0x95;
+  if (t >= 0x97) {
+    sprite_x_lo[k] += 8;
+    sprite_head_dir[k] = sprite_x_lo[k] & 16 ^ 16;
+    if (!sprite_head_dir[k])
+      sprite_y_lo[k] += (t & 1) ? -8 : 8;
+  } else {
+    sprite_head_dir[k] = sprite_y_lo[k] & 16;
+    if (!sprite_head_dir[k])
+      sprite_x_lo[k] += (t & 1) ? -8 : 8;
+  }
+}
+
+void SpritePrep_Popo(int k) {  // 868b08
+  sprite_B[k] = 7;
+}
+
+void SpritePrep_Popo2(int k) {  // 868b0c
+  sprite_B[k] = 15;
+}
+
+void SpritePrep_Statue(int k) {  // 868b12
+  sprite_y_lo[k] += 7;
+}
+
+void SpritePrep_Bari(int k) {  // 868b1c
+  sprite_z[k] = 6;
+  if (BYTE(dungeon_room_index2) == 206)
+    sprite_C[k]--;
+  sprite_delay_aux1[k] = (GetRandomNumber() & 63) + 128;
+}
+
+void SpritePrep_GreenStalfos(int k) {  // 868b2e
+  sprite_z[k] = 9;
+}
+
+void SpritePrep_WaterLever(int k) {  // 868b34
+  sprite_y_lo[k] += 5;
+}
+
+void SpritePrep_FireDebirando(int k) {  // 868b3e
+  sprite_type[k] = 0x63;
+  SpritePrep_LoadProperties(k);
+  sprite_G[k]--;
+  SpritePrep_DebirandoPit(k);
+}
+
+void SpritePrep_DebirandoPit(int k) {  // 868b4a
+  static const uint8 kDebirando_OamFlags[2] = {6, 8};
+  sprite_G[k]++;
+  sprite_delay_main[k] = 0;
+  sprite_graphics[k] = 6;
+  SpritePrep_IgnoreProjectiles(k);
+  SpriteSpawnInfo info;
+  int j = Sprite_SpawnDynamically(k, 0x64, &info);
+  if (j >= 0) {
+    Sprite_SetSpawnedCoordinates(j, &info);
+    sprite_delay_main[j] = 96;
+    sprite_head_dir[k] = j;
+    sprite_G[j] = sprite_G[k];
+    sprite_oam_flags[j] = kDebirando_OamFlags[sprite_G[j]];
+  }
+}
+
+void SpritePrep_WeakGuard(int k) {  // 868b81
+  sprite_D[k] = sprite_head_dir[k] = GetRandomNumber() & 3;
+  sprite_delay_main[k] = 16;
+}
+
+void SpritePrep_WallCannon(int k) {  // 868b93
+  sprite_D[k] = sprite_type[k] - 0x66;
+  sprite_A[k] = sprite_D[k] & 2;
+}
+
+void SpritePrep_ArrowGame_bounce(int k) {  // 868ba2
+  static const uint8 kArcheryGameGuy_X[8] = {0, 0x40, 0x80, 0xc0, 0x30, 0x60, 0x90, 0xc0};
+  static const uint8 kArcheryGameGuy_Y[8] = {0, 0x4f, 0x4f, 0x4f, 0x5a, 0x5a, 0x5a, 0x5a};
+  static const uint8 kArcheryGameGuy_A[8] = {0, 1, 1, 1, 2, 2, 2, 2};
+  static const int8 kArcheryGameGuy_Xvel[2] = {-8, 12};
+  static const uint8 kArcheryGameGuy_Flags4[2] = {0x1c, 0x15};
+  byte_7E0B88 = 0;
+  sprite_y_lo[k] -= 9;
+  for (int i = 7; i != 0; i--) {
+    sprite_type[i] = 0x65;
+    sprite_state[i] = 9;
+    SpritePrep_LoadProperties(i);
+    sprite_x_hi[i] = (link_x_coord >> 8);
+    sprite_x_lo[i] = kArcheryGameGuy_X[i];
+    sprite_y_hi[i] = (link_y_coord >> 8);
+    sprite_y_lo[i] = kArcheryGameGuy_Y[i];
+    sprite_A[i] = kArcheryGameGuy_A[i];
+    int j = kArcheryGameGuy_A[i] - 1;
+    sprite_graphics[i] = j;
+    sprite_x_vel[i] = kArcheryGameGuy_Xvel[j];
+    sprite_flags4[i] = kArcheryGameGuy_Flags4[j];
+    sprite_oam_flags[i] = 13;
+    sprite_floor[i] = link_is_on_lower_level;
+    sprite_subtype2[i] = GetRandomNumber();
+  }
+  sprite_ignore_projectile[k]++;
+  sprite_subtype[k] = link_num_arrows;
+}
+
+void SpritePrep_IgnoreProjectiles(int k) {  // 868ba7
+  sprite_ignore_projectile[k]++;
+}
+
+void SpritePrep_HauntedGroveAnimal(int k) {  // 868bab
+  sprite_D[k] = Sprite_IsRightOfLink(k).a;
+  SpritePrep_HauntedGroveOstritch(k);
+}
+
+void SpritePrep_HauntedGroveOstritch(int k) {  // 868bb2
+  if (link_item_flute >= 2)
+    sprite_state[k] = 0;
+  sprite_ignore_projectile[k]++;
+}
+
+void SpritePrep_DiggingGameGuy_bounce(int k) {  // 868bbf
+  if (link_y_coord < Sprite_GetY(k)) {
+    sprite_ai_state[k] = 5;
+    sprite_x_lo[k] -= 9;
+    sprite_graphics[k] = 1;
+  }
+  sprite_ignore_projectile[k]++;
+}
+
+void SpritePrep_ThievesTownGrate(int k) {  // 868bc4
+  if (save_ow_event_info[0x58] & 0x20)
+    sprite_state[k] = 0;
+  sprite_ignore_projectile[k]++;
+  Sprite_SetX(k, Sprite_GetX(k) - 8);
+}
+
+void SpritePrep_RupeePull(int k) {  // 868bcf
+  sprite_ignore_projectile[k]++;
+  Sprite_SetX(k, Sprite_GetX(k) - 8);
+}
+
+void SpritePrep_Shopkeeper(int k) {  // 868bf1
+  sprite_ignore_projectile[k]++;
+  sprite_flags2[k] |= 2;
+  sprite_oam_flags[k] |= 12;
+  sprite_flags3[k] |= 16;
+  static const uint8 kShopKeeperWhere[13] = {0xf, 0x10, 0, 6, 0x18, 0x12, 0x1e, 0xff, 0x1f, 0x23, 0x24, 0x25, 0x27};
+  uint8 room = BYTE(dungeon_room_index);
+  int j = FindInByteArray(kShopKeeperWhere, room, 13);
+  switch (j) {
+  case 0:
+    ShopKeeper_SpawnShopItem(k, 0, 7);
+    ShopKeeper_SpawnShopItem(k, 1, 8);
+    ShopKeeper_SpawnShopItem(k, 2, 12);
+    break;
+  case 1:
+    ShopKeeper_SpawnShopItem(k, 0, 9);
+    ShopKeeper_SpawnShopItem(k, 1, 13);
+    ShopKeeper_SpawnShopItem(k, 2, 11);
+    break;
+  case 2:
+    sprite_subtype2[k] = 4;
+    minigame_credits = 0xff;
+    break;
+  case 3:
+    sprite_subtype2[k] = sprite_graphics[k] = 1;
+    minigame_credits = 0xff;
+    break;
+  case 4:
+    sprite_subtype2[k] = 3;
+    minigame_credits = 0xff;
+    break;
+  case 5: case 7: case 8:
+    ShopKeeper_SpawnShopItem(k, 0, 7);
+    ShopKeeper_SpawnShopItem(k, 1, 10);
+    ShopKeeper_SpawnShopItem(k, 2, 12);
+    break;
+  case 6: case 9: case 12:
+    sprite_subtype2[k] = 2;
+    break;
+  case 10:
+    sprite_subtype2[k] = 5;
+    break;
+  case 11:
+    sprite_subtype2[k] = 6;
+    break;
+  default:
+    assert(0);
+  }
+}
+
+void SpritePrep_Storyteller(int k) {  // 868c9e
+  static const uint8 kStoryTellerRooms[5] = {0xe, 0xe, 0x12, 0x1a, 0x14};
+  int r = FindInByteArray(kStoryTellerRooms, BYTE(dungeon_room_index), 5);
+  if (r == 0 && sprite_x_hi[k] & 1)
+    r = 1;
+  sprite_subtype2[k] = r;
+  sprite_ignore_projectile[k]++;
+}
+
+void SpritePrep_Adults(int k) {  // 868cc1
+  static const uint8 kHumanMultiTypes[3] = {3, 0xe1, 0x19};
+  sprite_ignore_projectile[k]++;
+  sprite_subtype2[k] = FindInByteArray(kHumanMultiTypes, BYTE(dungeon_room_index), 3);
+}
+
+void SpritePrep_Whirlpool(int k) {  // 868cd5
+  sprite_ignore_projectile[k]++;
+  sprite_A[k] = 1;
+}
+
+void SpritePrep_Sage(int k) {  // 868cde
+  sprite_ignore_projectile[k]++;
+  if (BYTE(dungeon_room_index) == 10) {
+    sprite_subtype2[k]++;
+    sprite_oam_flags[k] = 11;
+  }
+}
+
+void SpritePrep_BonkItem(int k) {  // 868cf2
+  static const uint16 kDashItemMask[2] = {0x4000, 0x2000};
+  if (!player_is_indoors) {
+    sprite_graphics[k] = 2;
+    return;
+  }
+  sprite_floor[k] = 2;
+  if (dungeon_room_index == 0x107) {
+    if (link_item_book_of_mudora)
+      sprite_state[k] = 0;
+    else
+      DecodeAnimatedSpriteTile_variable(0xe);
+  } else {
+    int j = byte_7E0B9B++;
+    sprite_die_action[k] = j;
+    if (dung_savegame_state_bits & kDashItemMask[j])
+      sprite_state[k] = 0;
+    sprite_graphics[k]++;
+    sprite_oam_flags[k] = 8;
+    sprite_flags3[k] |= 0x20;
+  }
+}
+
+void SpritePrep_Kiki(int k) {  // 868d46
+  sprite_ignore_projectile[k]++;
+  if (save_ow_event_info[BYTE(overworld_screen_index)] & 0x20)
+    sprite_state[k] = 0;
+}
+
+void SpritePrep_Locksmith(int k) {  // 868d59
+  sprite_ignore_projectile[k]++;
+  if (follower_indicator == 9) {
+    sprite_state[k] = 0;
+    return;
+  }
+  if (follower_indicator == 12) {
+    sprite_ai_state[k] = 2;
+  }
+  if (sram_progress_indicator_3 & 0x10)
+    sprite_ai_state[k] = 4;
+}
+
+void SpritePrep_SickKid(int k) {  // 868d7f
+  if (link_item_bug_net)
+    sprite_ai_state[k] = 3;
+  sprite_ignore_projectile[k]++;
+}
+
+void SpritePrep_Tektite(int k) {  // 868d94
+  static const uint8 kGanonHelpers_OamFlags[2] = {9, 7};
+  static const uint8 kGanonHelpers_Health[2] = {8, 12};
+  static const uint8 kGanonHelpers_BumpDamage[2] = {3, 5};
+  int j;
+  sprite_A[k] = j = sprite_x_lo[k] >> 4 & 1;
+  sprite_oam_flags[k] = kGanonHelpers_OamFlags[j];
+  sprite_health[k] = kGanonHelpers_Health[j];
+  sprite_bump_damage[k] = kGanonHelpers_BumpDamage[j];
+  Sprite_ApplySpeedTowardsLink(k, 16);
+  sprite_z_vel[k] = 32;
+  sprite_ai_state[k]++;
+}
+
+void SpritePrep_Chainchomp_bounce(int k) {  // 868dc1
+  int i = k * 8;
+  for (int j = 5; j >= 0; j--, i++) {
+    chainchomp_x_hist[i] = cur_sprite_x;
+    chainchomp_y_hist[i] = cur_sprite_y;
+  }
+  sprite_A[k] = sprite_x_lo[k];
+  sprite_B[k] = sprite_x_hi[k];
+  sprite_C[k] = sprite_y_lo[k];
+  sprite_G[k] = sprite_y_hi[k];
+}
+
+void SpritePrep_BigFairy(int k) {  // 868dc6
+  sprite_z[k] = 24;
+  SpritePrep_MoveDown_8px_Right8px(k);
+  sprite_ignore_projectile[k]++;
+}
+
+void SpritePrep_MrsSahasrahla(int k) {  // 868dd1
+  sprite_y_lo[k] += 8;
+  SpritePrep_MagicBat(k);
+}
+
+void SpritePrep_MagicBat(int k) {  // 868dda
+  sprite_x_lo[k] += 8;
+  sprite_ignore_projectile[k]++;
+}
+
+void SpritePrep_FortuneTeller(int k) {  // 868de0
+  SpritePrep_IncrXYLow8(k);
+  sprite_ignore_projectile[k]++;
+}
+
+void SpritePrep_FairyPond(int k) {  // 868de9
+  static const uint8 kLeever_OamFlags[2] = {10, 2};
+  int j = sprite_x_lo[k] >> 4 & 1;
+  sprite_A[k] = j;
+  sprite_oam_flags[k] = kLeever_OamFlags[j];
+}
+
+void SpritePrep_Hobo(int k) {  // 868dfd
+  for (int i = 15; i; i--)
+    SpritePrep_Hobo_SpawnSmoke(k);
+  for (int i = 15; i; i--) {
+    if (sprite_type[i] == 0x2b)
+      sprite_state[i] = 0;
+  }
+  SpritePrep_Hobo_SpawnFire(k);
+  if (sram_progress_indicator_3 & 1)
+    sprite_ai_state[0] = 3;
+  sprite_ignore_projectile[0] = 1;
+}
+
+void SpritePrep_MasterSword(int k) {  // 868e30
+  sprite_x_lo[k] += 6;
+  sprite_y_lo[k] += 6;
+}
+
+void SpritePrep_Roller_HorizontalRightFirst(int k) {  // 868e42
+  sprite_ai_state[k] = (~sprite_x_lo[k] & 16) >> 4;
+  if (sprite_ai_state[k])
+    sprite_flags4[k]++;
+  sprite_D[k] = 0;
+}
+
+void SpritePrep_RollerLeftRight(int k) {  // 868e46
+  sprite_ai_state[k] = (~sprite_x_lo[k] & 16) >> 4;
+  if (sprite_ai_state[k])
+    sprite_flags4[k]++;
+  sprite_D[k] = 1;
+}
+
+void SpritePrep_Roller_VerticalDownFirst(int k) {  // 868e4f
+  sprite_ai_state[k] = (sprite_y_lo[k] & 16) >> 4;
+  if (sprite_ai_state[k])
+    sprite_flags4[k]++;
+  sprite_D[k] = 2;
+}
+
+void SpritePrep_RollerUpDown(int k) {  // 868e53
+  sprite_ai_state[k] = (sprite_y_lo[k] & 16) >> 4;
+  if (sprite_ai_state[k])
+    sprite_flags4[k]++;
+  sprite_D[k] = 3;
+}
+
+void SpritePrep_Kodongo(int k) {  // 868e6b
+  sprite_x_lo[k] += 4;
+  Sprite_SetY(k, Sprite_GetY(k) - 5);
+  sprite_subtype[k]--;
+}
+
+void SpritePrep_Spark(int k) {  // 868e85
+  sprite_subtype[k]--;
+}
+
+void SpritePrep_LostWoodsBird(int k) {  // 868ec1
+  sprite_z_vel[k] = (GetRandomNumber() & 0x1f) - 0x10;
+  sprite_z[k] = 64;
+  SpritePrep_LostWoodsSquirrel(k);
+}
+
+void SpritePrep_LostWoodsSquirrel(int k) {  // 868ed2
+  sprite_x_vel[k] = Sprite_IsRightOfLink(k).a ? -16 : 16;
+  sprite_ignore_projectile[k] = sprite_y_vel[k] = sign8(byte_7E069E[0]) ? 4 : -4;
+}
+
+void SpritePrep_Antifairy(int k) {  // 868ef2
+  static const int8 kBubble_Xvel[2] = {16, -16};
+  sprite_x_vel[k] = kBubble_Xvel[sprite_x_lo[k] >> 4 & 1];
+  sprite_y_vel[k] = -16;
+}
+
+void SpritePrep_FallingIce(int k) {  // 868f08
+  if (Sprite_ReturnIfBossFinished(k))
+    return;
+  sprite_ignore_projectile[k]++;
+}
+
+void SpritePrep_KingZora(int k) {  // 868f0f
+  if (link_item_flippers)
+    sprite_state[k] = 0;
+  else
+    sprite_ignore_projectile[k]++;
+}
+
+bool Sprite_ReturnIfBossFinished(int k) {  // 868f1c
+  if (dung_savegame_state_bits & 0x8000) {
+    sprite_state[k] = 0;
+    return true;
+  }
+  for (int j = 15; j >= 0; j--) {
+    if (!(kSpriteInit_BumpDamage[sprite_type[j]] & 0x10))
+      sprite_state[j] = 0;
+  }
+  return false;
+}
+
+void SpritePrep_ArmosKnight(int k) {  // 868f3f
+  if (Sprite_ReturnIfBossFinished(k))
+    return;
+  sprite_delay_main[k] = 255;
+  byte_7E0FF8++;
+  SpritePrep_MoveDown_8px_Right8px(k);
+}
+
+void SpritePrep_DesertStatue(int k) {  // 868f4d
+  sprite_A[k] = sprite_limit_instance;
+  sprite_limit_instance++;
+  SpritePrep_MoveDown_8px_Right8px(k);
+  sprite_D[k] = (sprite_x_lo[k] < 0x30) ? 1 : (sprite_x_lo[k] < 0xe0) ? 3 : 2;
+}
+
+void SpritePrep_DoNothingD(int k) {  // 868f6c
+  // empty
+}
+
+void SpritePrep_Octorok(int k) {  // 868f71
+  static const uint8 kOctorock_BumpDamage[2] = {3, 5};
+  static const uint8 kOctorock_Health[2] = {2, 4};
+  int j = is_in_dark_world;
+  sprite_health[k] = kOctorock_Health[j];
+  sprite_bump_damage[k] = kOctorock_BumpDamage[j];
+  sprite_delay_main[k] = GetRandomNumber() & 127;
+}
+
+void SpritePrep_Moldorm(int k) {  // 868f8a
+  if (Sprite_ReturnIfBossFinished(k))
+    return;
+  sprite_ignore_projectile[k]++;
+  Sprite_InitializedSegmented(k);
+}
+
+void SpritePrep_Lanmolas(int k) {  // 868f95
+  static const uint8 kLanmola_InitDelay[3] = {128, 192, 255};
+
+  if (Sprite_ReturnIfBossFinished(k))
+    return;
+  sprite_delay_main[k] = kLanmola_InitDelay[k];
+  sprite_z[k] = -1;
+  for (int i = 0; i < 64; i++)
+    beamos_x_hi[k * 0x40 + i] = 0xff;
+  garnish_y_lo[k] = 7;
+}
+
+void SpritePrep_BigSpike(int k) {  // 868f9d
+  SpritePrep_MoveDown_8px_Right8px(k);
+  SpritePrep_Kyameron(k);
+}
+
+void SpritePrep_SwimmingZora(int k) {  // 868fa2
+  sprite_delay_main[k] = 64;
+  SpritePrep_Geldman(k);
+}
+
+void SpritePrep_Geldman(int k) {  // 868fa7
+  sprite_x_lo[k] += 8;
+  SpritePrep_Kyameron(k);
+}
+
+void SpritePrep_Kyameron(int k) {  // 868fb0
+  sprite_A[k] = sprite_x_lo[k];
+  sprite_B[k] = sprite_x_hi[k];
+  sprite_C[k] = sprite_y_lo[k];
+  sprite_head_dir[k] = sprite_y_hi[k];
+}
+
+void SpritePrep_WalkingZora(int k) {  // 868fc9
+  sprite_delay_main[k] = 96;
+}
+
+void SpritePrep_StandardGuard(int k) {  // 868fd6
+  static const uint8 kSpriteSoldier_Tab0[8] = {0, 2, 1, 3, 6, 4, 5, 7};
+
+  uint8 subtype = sprite_subtype[k];
+  if (subtype != 0) {
+    if ((subtype & 7) >= 5) {
+      int j = ((subtype & 7) != 5) * 4 + (subtype >> 3 & 3);
+      sprite_B[k] = kSpriteSoldier_Tab0[j];
+      sprite_flags[k] = sprite_flags[k] & 0xf | 0x50;
+      SpritePrep_TrooperAndArcherSoldier(k);
+      return;
+    }
+    sprite_D[k] = ((subtype & 7) - 1) ^ 1;
+  }
+  if (player_is_indoors) {
+    sprite_flags5[k] &= ~0x80;
+    return;
+  }
+  sprite_ai_state[k] = 1;
+  sprite_delay_main[k] = 112;
+  sprite_D[k] = sprite_head_dir[k] = Sprite_DirectionToFaceLink(k, NULL);
+  SpritePrep_TrooperAndArcherSoldier(k);
+}
+
+void SpritePrep_TrooperAndArcherSoldier(int k) {  // 869001
+  uint8 bak0 = submodule_index;
+  submodule_index = 0;
+  sprite_defl_bits[k] = (sprite_defl_bits[k] >> 1) | 0x80;
+  SpriteActive_Main(k);
+  SpriteActive_Main(k);
+  sprite_defl_bits[k] <<= 1;
+  submodule_index = bak0;
+}
+
+void SpritePrep_TalkingTree(int k) {  // 869043
+  sprite_ignore_projectile[k]++;
+  Sprite_SetX(k, Sprite_GetX(k) - 8);
+  SpritePrep_TalkingTree_SpawnEyeball(k, 0);
+  SpritePrep_TalkingTree_SpawnEyeball(k, 1);
+}
+
+void SpritePrep_CrystalSwitch(int k) {  // 869064
+  sprite_oam_flags[k] |= kCrystalSwitchPal[orange_blue_barrier_state & 1];
+}
+
+void SpritePrep_FluteKid(int k) {  // 869075
+  sprite_ignore_projectile[k]++;
+  sprite_subtype2[k] = savegame_is_darkworld >> 6 & 1;
+  if (sprite_subtype2[k]) {
+    if (sram_progress_indicator_3 & 8 || link_item_flute > 2) {
+      sprite_graphics[k] = 3;
+      sprite_ai_state[k] = 5;
+    } else if (link_item_flute == 2) {
+      sprite_graphics[k] = 1;
+    }
+    sprite_x_lo[k] += 8;
+    sprite_y_lo[k] -= 8;
+  } else {
+    if (link_item_flute >= 2)
+      sprite_state[k] = 0;
+    else
+      sprite_x_lo[k] += 7;
+  }
+}
+
+void SpritePrep_MoveDown_8px(int k) {  // 8690cc
+  sprite_y_lo[k] += 8;
+}
+
+void SpritePrep_Zazakku(int k) {  // 8690d5
+  // empty
+}
+
+void SpritePrep_PedestalPlaque(int k) {  // 8690d6
+  sprite_ignore_projectile[k]++;
+  if (BYTE(overworld_screen_index) == 48)
+    sprite_x_lo[k] += 7;
+}
+
+void SpritePrep_Stalfos(int k) {  // 8690e0
+  sprite_subtype[k] = sprite_x_lo[k] & 16;
+  if (sprite_subtype[k])
+    sprite_oam_flags[k] = 7;
+}
+
+void SpritePrep_KholdstareShell(int k) {  // 8690f0
+  if (Sprite_ReturnIfBossFinished(k))
+    return;
+  sprite_delay_aux1[k] = 192;
+  SpritePrep_MoveDown_8px_Right8px(k);
+}
+
+void SpritePrep_Kholdstare(int k) {  // 8690fa
+  if (Sprite_ReturnIfBossFinished(k))
+    return;
+  sprite_ai_state[k] = 3;
+  SpritePrep_IgnoreProjectiles(k);
+  SpritePrep_MoveDown_8px_Right8px(k);
+}
+
+void SpritePrep_Bumper(int k) {  // 869107
+  sprite_ignore_projectile[k]++;
+  SpritePrep_MoveDown_8px_Right8px(k);
+}
+
+void SpritePrep_MoveDown_8px_Right8px(int k) {  // 86910a
+  sprite_x_lo[k] += 8;
+  sprite_y_lo[k] += 8;
+}
+
+void SpritePrep_HardhatBeetle(int k) {  // 869122
+  static const uint8 kHardHatBeetle_OamFlags[2] = {6, 8};
+  static const uint8 kHardHatBeetle_Health[2] = {32, 6};
+  static const uint8 kHardHatBeetle_A[2] = {16, 12};
+  static const uint8 kHardHatBeetle_State[2] = {1, 3};
+  static const uint8 kHardHatBeetle_Flags5[2] = {2, 6};
+  static const uint8 kHardHatBeetle_BumpDamage[2] = {5, 3};
+  int j = (sprite_x_lo[k] & 0x10) != 0;
+  sprite_oam_flags[k] = kHardHatBeetle_OamFlags[j];
+  sprite_health[k] = kHardHatBeetle_Health[j];
+  sprite_A[k] = kHardHatBeetle_A[j];
+  sprite_ai_state[k] = kHardHatBeetle_State[j];
+  sprite_flags5[k] = kHardHatBeetle_Flags5[j];
+  sprite_bump_damage[k] = kHardHatBeetle_BumpDamage[j];
+}
+
+void SpritePrep_MiniHelmasaur(int k) {  // 869151
+  sprite_A[k] = 16;
+  sprite_ai_state[k] = 1;
+}
+
+void SpritePrep_Fairy(int k) {  // 86915c
+  sprite_A[k] = GetRandomNumber() & 1;
+  sprite_D[k] = sprite_A[k] ^ 1;
+  SpritePrep_Absorbable(k);
+}
+
+void SpritePrep_Absorbable(int k) {  // 86916a
+  if (!player_is_indoors) {
+    sprite_E[k]++;
+    sprite_ignore_projectile[k]++;
+  }
+}
+
+void SpritePrep_OverworldBonkItem(int k) {  // 86916e
+  sprite_E[k]++;
+  sprite_ignore_projectile[k]++;
+}
+
+void SpritePrep_ShieldPickup(int k) {  // 869174
+}
+
+void SpritePrep_NiceBee(int k) {  // 869175
+  uint8 or_bottle = link_bottle_info[0] | link_bottle_info[1] | link_bottle_info[2] | link_bottle_info[3];
+  if (or_bottle & 8)
+    sprite_state[k] = 0;
+  sprite_E[k]++;
+  sprite_ignore_projectile[k]++;
+}
+
+void SpritePrep_Agahnim(int k) {  // 869195
+  static const uint8 kAgahnim_OamFlags[2] = {11, 7};
+  if (Sprite_ReturnIfBossFinished(k))
+    return;
+  sprite_graphics[k] = 0;
+  sprite_D[k] = 3;
+  SpritePrep_MoveDown_8px_Right8px(k);
+  sprite_oam_flags[k] = kAgahnim_OamFlags[is_in_dark_world];
+}
+
+void SpritePrep_DoNothingG(int k) {  // 8691ae
+  // empty
+}
+
+void SpritePrep_FireBar(int k) {  // 8691b4
+  sprite_B[k]++;
+  sprite_ignore_projectile[k]++;
+}
+
+void SpritePrep_Trinexx(int k) {  // 8691ba
+  if (Sprite_ReturnIfBossFinished(k))
+    return;
+  TrinexxComponents_Initialize(k);
+  for (int i = 15; i >= 0; i--)
+    alt_sprite_state[i] = 0;
+}
+
+void SpritePrep_HelmasaurKing(int k) {  // 8691c5
+  if (Sprite_ReturnIfBossFinished(k))
+    return;
+  HelmasaurKing_Initialize(k);
+  memset(alt_sprite_state, 0, 16);
+}
+
+void SpritePrep_Spike(int k) {  // 8691d7
+  sprite_x_vel[k] = 32;
+  sprite_y_vel[k] = -16;
+  Sprite_MoveY(k);
+  sprite_y_vel[k] = 0;
+}
+
+void SpritePrep_RockStal(int k) {  // 8691dc
+  sprite_y_vel[k] = -16;
+  Sprite_MoveY(k);
+  sprite_y_vel[k] = 0;
+}
+
+void SpritePrep_Blob(int k) {  // 8691e8
+  sprite_graphics[k] = 4;
+  SpritePrep_IgnoreProjectiles(k);
+}
+
+void SpritePrep_Arrghus(int k) {  // 8691f1
+  if (Sprite_ReturnIfBossFinished(k))
+    return;
+  sprite_z[k] = 24;
+}
+
+void SpritePrep_Arrghi(int k) {  // 8691fa
+  if (Sprite_ReturnIfBossFinished(k))
+    return;
+  sprite_subtype2[k] = GetRandomNumber();
+  if (k == 13) {
+    overlord_x_lo[2] = 0;
+    overlord_x_lo[3] = 0;
+    Arrghus_HandlePuffs(0);
+  }
+  sprite_x_lo[k] = overlord_x_lo[k + 7];
+  sprite_x_hi[k] = overlord_y_lo[k + 7];
+  sprite_y_lo[k] = overlord_gen1[k + 7];
+  sprite_y_hi[k] = overlord_gen3[k + 7];
+}
+
+void SpritePrep_Mothula(int k) {  // 86922f
+  if (Sprite_ReturnIfBossFinished(k))
+    return;
+  sprite_delay_main[k] = 80;
+  sprite_ignore_projectile[k]++;
+  sprite_graphics[k] = 2;
+  BYTE(dung_floor_move_flags)++;
+  sprite_C[k] = 112;
+}
+
+void SpritePrep_DoNothingH(int k) {  // 86924d
+  // empty
+}
+
+void SpritePrep_BigKey(int k) {  // 86924e
+  sprite_x_lo[k] += 8;
+  sprite_subtype[k] = 0xff;
+  SpritePrep_BigKey_load_graphics(k);
+}
+
+void SpritePrep_BigKey_load_graphics(int k) {  // 869256
+  DecodeAnimatedSpriteTile_variable(0x22);
+  SpritePrep_KeySetItemDrop(k);
+}
+
+void SpritePrep_SmallKey(int k) {  // 869262
+  sprite_subtype[k] = 255;
+  sprite_die_action[k] = byte_7E0B9B++;
+}
+
+void SpritePrep_KeySetItemDrop(int k) {  // 869267
+  sprite_die_action[k] = byte_7E0B9B;
+  byte_7E0B9B++;
+}
+
+void SpriteActive_Main(int k) {  // 869271
+  uint8 type = sprite_type[k];
+  kSpriteActiveRoutines[type](k);
+}
+
+void Sprite_09_GiantMoldorm(int k) {  // 869469
+  static const int8 kGiantMoldorm_Xvel[32] = {
+    24, 22, 17,  9, 0,  -9, -17, -22, -24, -22, -17,  -9, 0,  9, 17, 22,
+    36, 33, 25, 13, 0, -13, -25, -33, -36, -33, -25, -13, 0, 13, 25, 33,
+  };
+  static const int8 kGiantMoldorm_Yvel[32] = {
+    0,  9, 17, 22, 24, 22, 17,  9, 0,  -9, -17, -22, -24, -22, -17,  -9,
+    0, 13, 25, 33, 36, 33, 25, 13, 0, -13, -25, -33, -36, -33, -25, -13,
+  };
+  static const uint8 kGiantMoldorm_NextDir[16] = {8, 9, 10, 11, 12, 13, 14, 15, 0, 1, 2, 3, 4, 5, 6, 7};
+  GiantMoldorm_Draw(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  if (sprite_ai_state[k] == 3) {
+    // await death
+    if (!sprite_delay_aux4[k]) {
+      sprite_state[k] = 4;
+      sprite_A[k] = 0;
+      sprite_delay_main[k] = 224;
+    } else {
+      sprite_hit_timer[k] = sprite_delay_aux4[k] | 224;
+    }
+    return;
+  }
+
+  Sprite_CheckDamageFromLink(k);
+  bool low_health = (sprite_health[k] < 3);
+  sprite_subtype2[k] += low_health ? 2 : 1;
+  if (!(frame_counter & (low_health ? 3 : 7)))
+    SpriteSfx_QueueSfx3WithPan(k, 0x31);
+
+  if (sprite_F[k]) {
+    sprite_delay_aux2[k] = 64;
+    if (!(frame_counter & 3))
+      sprite_F[k]--;
+    return;
+  }
+
+  if (!link_incapacitated_timer && Sprite_CheckDamageToLink(k)) {
+    Link_CancelDash();
+    ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLink(k, 0x28);
+    link_actual_vel_y = pt.y;
+    link_actual_vel_x = pt.x;
+    link_incapacitated_timer = 24;
+    sprite_delay_aux1[k] = 48;
+    // For some reason they forgot to or in the sfx.
+    sound_effect_2 = Sprite_CalculateSfxPan(k) | (enhanced_features0 & kFeatures0_MiscBugFixes ? 0x32 : 0);
+  }
+
+  int j = sprite_D[k] + low_health * 16;
+  sprite_x_vel[k] = kGiantMoldorm_Xvel[j];
+  sprite_y_vel[k] = kGiantMoldorm_Yvel[j];
+  Sprite_MoveXY(k);
+  if (Sprite_CheckTileCollision(k)) {
+    sprite_D[k] = kGiantMoldorm_NextDir[sprite_D[k]];
+    SpriteSfx_QueueSfx2WithPan(k, 0x21);
+  }
+  switch(sprite_ai_state[k]) {
+  case 0:  // straight path
+    if (!sprite_delay_main[k]) {
+      j = 1;
+      if (++sprite_G[k] == 3)
+        sprite_G[k] = 0, j = 2;
+      sprite_ai_state[k] = j;
+      sprite_head_dir[k] = (GetRandomNumber() & 2) - 1;
+      sprite_delay_main[k] = (GetRandomNumber() & 31) + 32;
+    }
+    break;
+  case 1:  // spinning meander
+    if (!sprite_delay_main[k]) {
+      sprite_delay_main[k] = (GetRandomNumber() & 15) + 8;
+      sprite_ai_state[k] = 0;
+    } else if (!(sprite_delay_main[k] & 3)) {
+      sprite_D[k] = (sprite_D[k] + sprite_head_dir[k]) & 0xf;
+    }
+    break;
+  case 2:  // lunge at player
+    if (!((k ^ frame_counter) & 3)) {
+      Sprite_ApplySpeedTowardsLink(k, 0x1f);
+      uint8 dir = Sprite_ConvertVelocityToAngle(sprite_x_vel[k], sprite_y_vel[k]) - sprite_D[k];
+      if (dir == 0) {
+        sprite_ai_state[k] = 0;
+        sprite_delay_main[k] = 48;
+      } else {
+        sprite_D[k] += sign8(dir) ? -1 : 1;
+      }
+    }
+    break;
+  }
+}
+
+void Sprite_01_Vulture_bounce(int k) {  // 869473
+  static const uint8 kVulture_Gfx[4] = {1, 2, 3, 2};
+  sprite_obj_prio[k] |= 0x30;
+  Vulture_Draw(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  if (Sprite_ReturnIfRecoiling(k))
+    return;
+  Sprite_CheckDamageToAndFromLink(k);
+  Sprite_MoveXY(k);
+  switch (sprite_ai_state[k]) {
+  case 0:  // dormant
+    if (++sprite_subtype2[k] == 160) {
+      sprite_ai_state[k] = 1;
+      SpriteSfx_QueueSfx3WithPan(k, 0x1e);
+      sprite_delay_main[k] = 16;
+    }
+    break;
+  case 1: { // circling
+    sprite_graphics[k] = kVulture_Gfx[frame_counter >> 1 & 3];
+    if (sprite_delay_main[k]) {
+      sprite_z[k]++;
+      return;
+    }
+    if ((k ^ frame_counter) & 1)
+      return;
+    ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLink(k, (k & 0xf) + 24);
+    sprite_x_vel[k] = -pt.y;
+    sprite_y_vel[k] = pt.x;
+    if ((uint8)(pt.xdiff + 0x28) < 0x50 && (uint8)(pt.ydiff + 0x28) < 0x50)
+      return;
+    sprite_y_vel[k] += (int8)pt.y >> 2;
+    sprite_x_vel[k] += (int8)pt.x >> 2;
+    break;
+  }
+  }
+}
+
+void Sprite_27_Deadrock(int k) {  // 86948a
+  static const uint8 kDeadRock_Gfx[9] = {0, 1, 0, 1, 2, 2, 3, 3, 4};
+  static const uint8 kDeadRock_OamFlags[9] = {0x40, 0x40, 0, 0, 0, 0x40, 0, 0x40, 0};
+  static const int8 kDeadRock_Xvel[4] = {32, -32, 0, 0};
+  static const int8 kDeadRock_Yvel[4] = {0, 0, 32, -32};
+  int j = (sprite_delay_aux2[k] ? (sprite_delay_aux2[k] & 4) : (sprite_ai_state[k] != 2)) ? sprite_A[k] : 8;
+  sprite_graphics[k] = kDeadRock_Gfx[j];
+  sprite_oam_flags[k] = sprite_oam_flags[k] & ~0x40 | kDeadRock_OamFlags[j];
+  SpriteDraw_SingleLarge(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  if (!sprite_F[k] && (Sprite_CheckDamageFromLink(k) & kCheckDamageFromPlayer_Carry) && !sound_effect_1)
+    SpriteSfx_QueueSfx2WithPan(k, 0xb);
+  if (Sprite_CheckDamageToLink_same_layer(k)) {
+    Sprite_NullifyHookshotDrag();
+    Sprite_RepelDash();
+  }
+  if (sprite_F[k] == 14) {
+    sprite_ai_state[k] = 2;
+    sprite_delay_aux1[k] = 255;
+    sprite_delay_aux2[k] = 64;
+  }
+  if (Sprite_ReturnIfRecoiling(k))
+    return;
+  switch(sprite_ai_state[k]) {
+  case 0:  // pick dir
+    if (!sprite_delay_main[k]) {
+      sprite_flags2[k] &= ~0x80;
+      sprite_defl_bits[k] &= ~4;
+      sprite_flags3[k] &= ~0x40;
+      sprite_ai_state[k]++;
+      sprite_delay_main[k] = (GetRandomNumber() & 31) + 32;
+      if (++sprite_B[k] == 4) {
+        sprite_B[k] = 0;
+        j = Sprite_DirectionToFaceLink(k, NULL);
+      } else {
+        j = GetRandomNumber() & 3;
+      }
+set_dir:
+      sprite_D[k] = j;
+      sprite_x_vel[k] = kDeadRock_Xvel[j];
+      sprite_y_vel[k] = kDeadRock_Yvel[j];
+    }
+    break;
+  case 1:  // walk
+    if (!sprite_delay_main[k]) {
+      sprite_ai_state[k] = 0;
+      sprite_delay_main[k] = 32;
+    } else {
+      Sprite_MoveXY(k);
+      if (Sprite_CheckTileCollision(k)) {
+        j = sprite_D[k] ^ 1;
+        goto set_dir;
+      }
+      sprite_A[k] = sprite_D[k] << 1 | ++sprite_subtype2[k] >> 2 & 1;
+    }
+    break;
+  case 2:  // petrified
+    sprite_flags2[k] |= 0x80;
+    sprite_defl_bits[k] |= 4;
+    sprite_flags3[k] |= 0x40;
+    if (!(frame_counter & 1)) {
+      if (sprite_delay_aux1[k] == 0) {
+        sprite_ai_state[k] = 0;
+        sprite_delay_main[k] = 16;
+      } else if (sprite_delay_aux1[k] == 0x20) {
+        sprite_delay_aux2[k] = 0x40;
+      }
+    } else {
+      sprite_delay_aux1[k]++;
+    }
+    break;
+  }
+}
+
+void Sprite_20_Sluggula(int k) {  // 8695d9
+  static const uint8 kSluggula_Gfx[8] = {0, 1, 0, 1, 2, 3, 4, 5};
+  static const uint8 kSluggula_OamFlags[8] = {0x40, 0x40, 0, 0, 0, 0, 0, 0};
+  static const int8 kSluggula_XYvel[6] = {16, -16, 0, 0, 16, -16};
+  int j = sprite_D[k] << 1 | (sprite_subtype2[k] & 8) >> 3;
+  sprite_graphics[k] = kSluggula_Gfx[j];
+  sprite_oam_flags[k] = sprite_oam_flags[k] & 191 | kSluggula_OamFlags[j];
+  SpriteDraw_SingleLarge(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  if (Sprite_ReturnIfRecoiling(k))
+    return;
+  Sprite_CheckDamageToAndFromLink(k);
+  sprite_subtype2[k]++;
+  switch(sprite_ai_state[k]) {
+  case 0:  // normal
+    if (!sprite_delay_main[k]) {
+      sprite_ai_state[k] = 1;
+      sprite_delay_main[k] = (GetRandomNumber() & 31) + 32;
+      sprite_D[k] = j = sprite_delay_main[k] & 3;
+set_vel:
+      sprite_x_vel[k] = kSluggula_XYvel[j];
+      sprite_y_vel[k] = kSluggula_XYvel[j + 2];
+    } else if (sprite_delay_main[k] == 16 && !(GetRandomNumber() & 1)) {
+      Sluggula_DropBomb(k);
+    }
+    break;
+  case 1:  // break from bombing
+    if (!sprite_delay_main[k]) {
+      sprite_ai_state[k] = 0;
+      sprite_delay_main[k] = 32;
+    }
+    Sprite_MoveXY(k);
+    if (!Sprite_CheckTileCollision(k))
+      return;
+    j = (sprite_D[k] ^= 1);
+    goto set_vel;
+  }
+}
+
+void Sluggula_DropBomb(int k) {  // 869673
+  SpriteSpawnInfo info;
+  int j = Sprite_SpawnDynamicallyEx(k, 0x4a, &info, 11);
+  if (j >= 0) {
+    Sprite_SetSpawnedCoordinates(j, &info);
+    Sprite_TransmuteToBomb(j);
+  }
+}
+
+void Sprite_19_Poe(int k) {  // 869688
+  static const int8 kPoe_Accel[4] = {1, -1, 2, -2};
+  static const int8 kPoe_ZvelTarget[2] = {8, -8};
+  static const int8 kPoe_XvelTarget[4] = {16, -16, 28, -28};
+  static const uint8 kPoe_OamFlags[2] = {0x40, 0};
+  static const int8 kPoe_Yvel[2] = {8, -8};
+  int j;
+  sprite_D[k] = j = sprite_x_vel[k] >> 7;
+  sprite_oam_flags[k] = sprite_oam_flags[k] & ~0x40 | kPoe_OamFlags[j];
+  if (!sprite_E[k])
+    sprite_obj_prio[k] |= 0x30;
+  Poe_Draw(k);
+  oam_cur_ptr += 4;
+  oam_ext_cur_ptr++;
+  sprite_flags2[k]--;
+  SpriteDraw_SingleLarge(k);
+  sprite_flags2[k]++;
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  if (Sprite_ReturnIfRecoiling(k))
+    return;
+  if (sprite_E[k]) {
+    if (++sprite_z[k] == 12)
+      sprite_E[k] = 0;
+    return;
+  }
+  Sprite_CheckDamageToAndFromLink(k);
+  sprite_subtype2[k]++;
+  Sprite_MoveXY(k);
+  if (!(frame_counter & 1)) {
+    j = sprite_G[k] & 1;
+    sprite_z_vel[k] += kPoe_Accel[j];
+    if (sprite_z_vel[k] == (uint8)kPoe_ZvelTarget[j])
+      sprite_G[k]++;
+  }
+  Sprite_MoveZ(k);
+  sprite_y_vel[k] = 0;
+  switch(sprite_ai_state[k]) {
+  case 0:  // select vertical dir
+    if (!sprite_delay_main[k]) {
+      sprite_ai_state[k] = 1;
+      if (!(GetRandomNumber() & 12))
+        sprite_head_dir[k] = Sprite_IsBelowLink(k).a;
+      else
+        sprite_head_dir[k] = GetRandomNumber() & 1;
+    }
+    break;
+  case 1:  // roaming
+    if (!(frame_counter & 1)) {
+      int j = (sprite_anim_clock[k] & 1) + is_in_dark_world * 2;
+      sprite_x_vel[k] += kPoe_Accel[j];
+      if (sprite_x_vel[k] == (uint8)kPoe_XvelTarget[j]) {
+        sprite_anim_clock[k]++;
+        sprite_ai_state[k] = 0;
+        sprite_delay_main[k] = (GetRandomNumber() & 31) + 16;
+      }
+    }
+    sprite_y_vel[k] = kPoe_Yvel[sprite_head_dir[k]];
+    break;
+  }
+}
+
+void Poe_Draw(int k) {  // 869786
+  static const int8 kPoe_Draw_X[2] = {9, -1};
+  static const uint8 kPoe_Draw_Char[4] = {0x7c, 0x80, 0xb7, 0x80};
+  PrepOamCoordsRet info;
+  if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
+    return;
+  OamEnt *oam = GetOamCurPtr();
+  SetOamHelper0(oam, info.x + kPoe_Draw_X[sprite_D[k]], info.y + 9,
+                kPoe_Draw_Char[sprite_subtype2[k] >> 3 & 3], info.flags & 0xf0 | 2, 0);
+}
+
+void Sprite_18_MiniMoldorm(int k) {  // 869808
+  static const int8 kMoldorm_Xvel[16] = {24, 22, 17, 9, 0, -9, -17, -22, -24, -22, -17, -9, 0, 9, 17, 22};
+  static const int8 kMoldorm_Yvel[16] = {0, 9, 17, 22, 24, 22, 17, 9, 0, -9, -17, -22, -24, -22, -17, -9};
+  static const uint8 kMoldorm_NextDir[16] = {8, 9, 10, 11, 12, 13, 14, 15, 0, 1, 2, 3, 4, 5, 6, 7};
+
+  Moldorm_Draw(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  if (sprite_F[k])
+    SpritePrep_MiniMoldorm_bounce(k);
+  if (Sprite_ReturnIfRecoiling(k))
+    return;
+  Sprite_CheckDamageToAndFromLink(k);
+  sprite_subtype2[k]++;
+  int j = sprite_D[k];
+  sprite_x_vel[k] = kMoldorm_Xvel[j];
+  sprite_y_vel[k] = kMoldorm_Yvel[j];
+  Sprite_MoveXY(k);
+  if (Sprite_CheckTileCollision(k)) {
+    if (GetRandomNumber() & 1)
+      sprite_head_dir[k] = -sprite_head_dir[k];
+    sprite_D[k] = kMoldorm_NextDir[sprite_D[k]];
+  }
+  switch (sprite_ai_state[k]) {
+  case 0:  // configure
+    if (!sprite_delay_main[k]) {
+      if (++sprite_G[k] == 6)
+        sprite_G[k] = 0, sprite_ai_state[k] = 2;
+      else
+        sprite_ai_state[k] = 1;
+      sprite_head_dir[k] = (GetRandomNumber() & 2) - 1;
+      sprite_delay_main[k] = (GetRandomNumber() & 0x1f) + 0x20;
+    }
+    break;
+  case 1:  // meander
+    if (!sprite_delay_main[k]) {
+      sprite_delay_main[k] = (GetRandomNumber() & 15) + 8;
+      sprite_ai_state[k] = 0;
+    } else if ((sprite_delay_main[k] & 3) == 0) {
+      sprite_D[k] = (sprite_D[k] + sprite_head_dir[k]) & 0xf;
+    }
+    break;
+  case 2:  // seek player
+    if (!((k ^ frame_counter) & 3)) {
+      Sprite_ApplySpeedTowardsLink(k, 31);
+      uint8 d = Sprite_ConvertVelocityToAngle(sprite_x_vel[k], sprite_y_vel[k]) - sprite_D[k];
+      if (d == 0) {
+        sprite_ai_state[k] = 0;
+        sprite_delay_main[k] = 48;
+      } else {
+        sprite_D[k] = (sprite_D[k] + (sign8(d) ? -1 : 1)) & 0xf;
+      }
+    }
+    break;
+  }
+}
+
+void Sprite_12_Moblin(int k) {  // 8698e4
+  static const int8 kMoblin_Xvel[4] = {16, -16, 0, 0};
+  static const int8 kMoblin_Yvel[4] = {0, 0, 16, -16};
+  static const uint8 kMoblin_Delay[4] = {0x10, 0x20, 0x30, 0x40};
+  static const uint8 kMoblin_Gfx2[8] = {11, 10, 8, 9, 7, 5, 0, 2};
+  static const uint8 kMoblin_Dirs[8] = {2, 3, 2, 3, 0, 1, 0, 1};
+  static const uint8 kMoblin_Gfx[4] = {6, 4, 0, 2};
+  int j;
+  Moblin_Draw(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  if (Sprite_ReturnIfRecoiling(k))
+    return;
+  Sprite_CheckDamageToAndFromLink(k);
+  Sprite_MoveXY(k);
+  Sprite_CheckTileCollision2(k);
+  switch(sprite_ai_state[k]) {
+  case 0:  // select dir
+    if (!sprite_delay_main[k]) {
+      sprite_delay_main[k] = kMoblin_Delay[GetRandomNumber() & 3];
+      sprite_ai_state[k]++;
+      sprite_D[k] = sprite_head_dir[k];
+      j = sprite_head_dir[k];
+      sprite_x_vel[k] = kMoblin_Xvel[j];
+      sprite_y_vel[k] = kMoblin_Yvel[j];
+    }
+    break;
+  case 1:  // walk
+    sprite_graphics[k] = (sprite_subtype2[k] & 1) + kMoblin_Gfx[sprite_D[k]];
+    if (!sprite_wallcoll[k]) {
+      if (sprite_delay_main[k]) {
+        if (sign8(--sprite_E[k])) {
+          sprite_E[k] = 11;
+          sprite_subtype2[k]++;
+        }
+        return;
+      }
+      if (sprite_D[k] == Sprite_DirectionToFaceLink(k, NULL)) {
+        sprite_ai_state[k]++;
+        sprite_delay_main[k] = 32;
+        Sprite_ZeroVelocity_XY(k);
+        sprite_z_vel[k] = 0;
+        return;
+      }
+      sprite_delay_main[k] = 0x10;
+    } else {
+      sprite_delay_main[k] = 0xc;
+    }
+    sprite_head_dir[k] = kMoblin_Dirs[sprite_D[k] << 1 | GetRandomNumber() & 1];
+    sprite_ai_state[k] = 0;
+    if (++sprite_C[k] == 4) {
+      sprite_C[k] = 0;
+      sprite_head_dir[k] = Sprite_DirectionToFaceLink(k, NULL);
+    }
+    Sprite_ZeroVelocity_XY(k);
+    sprite_z_vel[k] = 0;
+    break;
+  case 2:  // throw spear
+    j = sprite_D[k];
+    if (!sprite_delay_main[k])
+      sprite_ai_state[k] = 0;
+    if (sprite_delay_main[k] < 16) {
+      if (sprite_delay_main[k] == 15) {
+        Moblin_MaterializeSpear(k);
+        sprite_delay_aux1[k] = 32;
+      }
+      j += 4;
+    }
+    sprite_graphics[k] = kMoblin_Gfx2[j];
+    break;
+  }
+}
+
+void Moblin_MaterializeSpear(int k) {  // 8699eb
+  static const int8 kMoblinSpear_X[4] = {11, -2, -3, 11};
+  static const int8 kMoblinSpear_Y[4] = {-3, -3, 3, -11};
+  static const int8 kMoblinSpear_Xvel[4] = {32, -32, 0, 0};
+  static const int8 kMoblinSpear_Yvel[4] = {0, 0, 32, -32};
+  SpriteSpawnInfo info;
+  int j = Sprite_SpawnDynamically(k, 0x1b, &info), i;
+  if (j >= 0) {
+    sprite_A[j] = 3;
+    sprite_D[j] = i = sprite_D[k];
+    Sprite_SetX(j, info.r0_x + kMoblinSpear_X[i]);
+    Sprite_SetY(j, info.r2_y + kMoblinSpear_Y[i]);
+    sprite_x_vel[j] = kMoblinSpear_Xvel[i];
+    sprite_y_vel[j] = kMoblinSpear_Yvel[i];
+  }
+}
+
+void Moblin_Draw(int k) {  // 869bc4
+  static const DrawMultipleData kMoblin_Dmd[48] = {
+    {-2,   3, 0x8091, 0},
+    {-2,  11, 0x8090, 0},
+    { 0, -10, 0x0086, 2},
+    { 0,   0, 0x008a, 2},
+    {-2,   7, 0x8091, 0},
+    {-2,  15, 0x8090, 0},
+    { 0, -10, 0x0086, 2},
+    { 0,   0, 0x408a, 2},
+    { 0,  -9, 0x0084, 2},
+    { 0,   0, 0x00a0, 2},
+    {11,  -5, 0x0090, 0},
+    {11,   3, 0x0091, 0},
+    { 0,  -9, 0x0084, 2},
+    { 0,   0, 0x40a0, 2},
+    {11,  -8, 0x0090, 0},
+    {11,   0, 0x0091, 0},
+    {-4,   8, 0x0080, 0},
+    { 4,   8, 0x0081, 0},
+    { 0,  -9, 0x0088, 2},
+    { 0,   0, 0x00a6, 2},
+    {-9,   6, 0x0080, 0},
+    {-1,   6, 0x0081, 0},
+    { 0,  -8, 0x0088, 2},
+    { 0,   0, 0x00a4, 2},
+    {12,   8, 0x4080, 0},
+    { 4,   8, 0x4081, 0},
+    { 0,  -9, 0x4088, 2},
+    { 0,   0, 0x40a6, 2},
+    {17,   6, 0x4080, 0},
+    { 9,   6, 0x4081, 0},
+    { 0,  -8, 0x4088, 2},
+    { 0,   0, 0x40a4, 2},
+    {-3,  -5, 0x8091, 0},
+    {-3,   3, 0x8090, 0},
+    { 0, -10, 0x0086, 2},
+    { 0,   0, 0x00a8, 2},
+    {11, -11, 0x0090, 0},
+    {11,  -3, 0x0091, 0},
+    { 0,  -9, 0x0084, 2},
+    { 0,   0, 0x4082, 2},
+    {-2,  -3, 0x0080, 0},
+    { 6,  -3, 0x0081, 0},
+    { 0,  -9, 0x0088, 2},
+    { 0,   0, 0x00a2, 2},
+    {10,  -3, 0x4080, 0},
+    { 2,  -3, 0x4081, 0},
+    { 0,  -9, 0x4088, 2},
+    { 0,   0, 0x40a2, 2},
+  };
+  static const uint8 kMoblin_ObjOffs[12] = {2, 2, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2};
+  static const uint8 kMoblin_HeadChar[4] = {0x88, 0x88, 0x86, 0x84};
+  static const uint8 kMoblin_HeadFlags[4] = {0x40, 0, 0, 0};
+  PrepOamCoordsRet info;
+  Sprite_DrawMultiple(k, &kMoblin_Dmd[sprite_graphics[k] * 4], 4, &info);
+  if (sprite_pause[k])
+    return;
+  OamEnt *oam = GetOamCurPtr();
+  if (sprite_delay_aux1[k]) {
+    for (int i = 0; i < 4; i++, oam++) {
+      if (!(bytewise_extended_oam[oam - oam_buf] & 2))
+        oam->y = 0xf0;
+    }
+  }
+  oam = GetOamCurPtr() + kMoblin_ObjOffs[sprite_graphics[k]];
+  int j = sprite_head_dir[k];
+  oam->charnum = kMoblin_HeadChar[j];
+  oam->flags = oam->flags &~0x40 | kMoblin_HeadFlags[j];
+  SpriteDraw_Shadow(k, &info);
+}
+
+void Sprite_0E_Snapdragon(int k) {  // 869c24
+  static const uint8 kSnapDragon_Delay[4] = {0x20, 0x30, 0x40, 0x50};
+  static const uint8 kSnapDragon_Gfx[4] = {4, 0, 6, 2};
+  static const int8 kSnapDragon_Xvel[8] = {8, -8, 8, -8, 16, -16, 16, -16};
+  static const int8 kSnapDragon_Yvel[8] = {8, 8, -8, -8, 16, 16, -16, -16};
+  int j;
+  sprite_graphics[k] = sprite_B[k] + kSnapDragon_Gfx[sprite_D[k]];
+  SnapDragon_Draw(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  if (Sprite_ReturnIfRecoiling(k))
+    return;
+  Sprite_CheckDamageToAndFromLink(k);
+  sprite_B[k] = 0;
+  switch(sprite_ai_state[k]) {
+  case 0:  // resting
+    if (!sprite_delay_main[k]) {
+      sprite_ai_state[k]++;
+      sprite_delay_main[k] = kSnapDragon_Delay[(GetRandomNumber() & 12) >> 2];
+      if (sign8(--sprite_A[k])) {
+        sprite_A[k] = 3;
+        sprite_delay_main[k] = 96;
+        sprite_C[k]++;
+        sprite_D[k] = Sprite_IsBelowLink(k).a * 2 + Sprite_IsRightOfLink(k).a;
+      } else {
+        sprite_D[k] = GetRandomNumber() & 3;
+      }
+    } else if (sprite_delay_main[k] & 0x18) {
+      sprite_B[k]++;
+    }
+    break;
+  case 1:  // attack
+    sprite_B[k]++;
+    Sprite_MoveXY(k);
+    if (Sprite_CheckTileCollision(k))
+      sprite_D[k] ^= 3;
+    j = sprite_D[k] + (sprite_C[k] ? 4 : 0);
+    sprite_x_vel[k] = kSnapDragon_Xvel[j];
+    sprite_y_vel[k] = kSnapDragon_Yvel[j];
+    Sprite_MoveZ(k);
+    sprite_z_vel[k] -= 4;
+    if (sign8(sprite_z[k])) {
+      sprite_z[k] = 0;
+      if (!sprite_delay_main[k]) {
+        sprite_ai_state[k] = 0;
+        sprite_C[k] = 0;
+        sprite_delay_main[k] = 63;
+      } else {
+        sprite_z_vel[k] = 20;
+      }
+    }
+    break;
+  }
+}
+
+void SnapDragon_Draw(int k) {  // 869e02
+  static const DrawMultipleData kSnapDragon_Dmd[32] = {
+    { 4, -8, 0x008f, 0},
+    {12, -8, 0x009f, 0},
+    {-4,  0, 0x008c, 2},
+    { 4,  0, 0x008d, 2},
+    { 4, -8, 0x002b, 0},
+    {12, -8, 0x003b, 0},
+    {-4,  0, 0x0028, 2},
+    { 4,  0, 0x0029, 2},
+    {-4, -8, 0x003c, 0},
+    { 4, -8, 0x003d, 0},
+    {-4,  0, 0x00aa, 2},
+    { 4,  0, 0x00ab, 2},
+    {-4, -8, 0x003e, 0},
+    { 4, -8, 0x003f, 0},
+    {-4,  0, 0x00ad, 2},
+    { 4,  0, 0x00ae, 2},
+    {-4, -8, 0x409f, 0},
+    { 4, -8, 0x408f, 0},
+    {-4,  0, 0x408d, 2},
+    { 4,  0, 0x408c, 2},
+    {-4, -8, 0x403b, 0},
+    { 4, -8, 0x402b, 0},
+    {-4,  0, 0x4029, 2},
+    { 4,  0, 0x4028, 2},
+    { 4, -8, 0x403d, 0},
+    {12, -8, 0x403c, 0},
+    {-4,  0, 0x40ab, 2},
+    { 4,  0, 0x40aa, 2},
+    { 4, -8, 0x403f, 0},
+    {12, -8, 0x403e, 0},
+    {-4,  0, 0x40ae, 2},
+    { 4,  0, 0x40ad, 2},
+  };
+  PrepOamCoordsRet info;
+  Sprite_DrawMultiple(k, &kSnapDragon_Dmd[sprite_graphics[k] * 4], 4, &info);
+  SpriteDraw_Shadow(k, &info);
+}
+
+void Sprite_22_Ropa(int k) {  // 869e1f
+  Ropa_Draw(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  if (Sprite_ReturnIfRecoiling(k))
+    return;
+  Sprite_CheckDamageToAndFromLink(k);
+  sprite_subtype2[k]++;
+  sprite_graphics[k] = sprite_subtype2[k] >> 3 & 3;
+  switch(sprite_ai_state[k]) {
+  case 0:  // stationary
+    if (!sprite_delay_main[k]) {
+      Sprite_ApplySpeedTowardsLink(k, 16);
+      sprite_z_vel[k] = (GetRandomNumber() & 15) + 20;
+      sprite_ai_state[k]++;
+    }
+    break;
+  case 1:  // pounce
+    Sprite_MoveXY(k);
+    if (Sprite_CheckTileCollision(k))
+      Sprite_ZeroVelocity_XY(k);
+    Sprite_MoveZ(k);
+    sprite_z_vel[k] -= 2;
+    if (sign8(sprite_z[k])) {
+      sprite_z[k] = 0;
+      sprite_delay_main[k] = 48;
+      sprite_ai_state[k] = 0;
+    }
+    break;
+  }
+}
+
+void Ropa_Draw(int k) {  // 869ee5
+  static const DrawMultipleData kRopa_Dmd[12] = {
+    {0, -8, 0x0026, 0},
+    {8, -8, 0x0027, 0},
+    {0,  0, 0x0008, 2},
+    {0, -8, 0x0036, 0},
+    {8, -8, 0x0037, 0},
+    {0,  0, 0x000a, 2},
+    {0, -8, 0x4027, 0},
+    {8, -8, 0x4026, 0},
+    {0,  0, 0x4008, 2},
+    {0, -8, 0x4037, 0},
+    {8, -8, 0x4036, 0},
+    {0,  0, 0x4008, 2},
+  };
+  PrepOamCoordsRet info;
+  Sprite_DrawMultiple(k, &kRopa_Dmd[sprite_graphics[k] * 3], 3, &info);
+  SpriteDraw_Shadow(k, &info);
+
+}
+
+void Sprite_11_Hinox(int k) {  // 869f05
+  Hinox_Draw(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  if (sprite_F[k]) {
+    Hinox_FaceLink(k);
+    sprite_ai_state[k] = 2;
+    sprite_delay_main[k] = 48;
+  }
+  if (Sprite_ReturnIfRecoiling(k))
+    return;
+  Sprite_CheckDamageToAndFromLink(k);
+  switch(sprite_ai_state[k]) {
+  case 0:  // select dir
+    if (!sprite_delay_main[k]) {
+      if (!(GetRandomNumber() & 3)) {
+        sprite_ai_state[k] = 2;
+        sprite_delay_main[k] = 64;
+      } else {
+        if (++sprite_C[k] == 4) {
+          sprite_C[k] = 0;
+          Hinox_FaceLink(k);
+        } else {
+          static const uint8 kHinox_RandomDirs[8] = {2, 3, 3, 2, 0, 1, 1, 0};
+          Hinox_SetDirection(k, kHinox_RandomDirs[sprite_D[k] * 2 + (GetRandomNumber() & 1)]);
+        }
+      }
+    }
+    break;
+  case 1:  // walk
+    if (sprite_delay_main[k]) {
+      if (sign8(--sprite_A[k])) {
+        sprite_A[k] = 11;
+        sprite_subtype2[k]++;
+      }
+      Sprite_MoveXY(k);
+      if (!Sprite_CheckTileCollision(k)) {
+        static const uint8 kHinox_WalkGfx[4] = {6, 4, 0, 2};
+        sprite_graphics[k] = kHinox_WalkGfx[sprite_D[k]] + (sprite_subtype2[k] & 1);
+        return;
+      }
+    }
+    sprite_delay_main[k] = 16;
+    sprite_ai_state[k] = 0;
+    break;
+  case 2:  // throw bomb
+    if (!sprite_delay_main[k]) {
+      sprite_ai_state[k] = 0;
+      sprite_delay_main[k] = 2;
+      return;
+    }
+    if (sprite_delay_main[k] == 32) {
+      static const int8 kHinox_BombX[4] = {8, -8, -13, 13};
+      static const int8 kHinox_BombY[4] = {-11, -11, -16, -16};
+      static const int8 kHinox_BombXvel[4] = {24, -24, 0, 0};
+      static const int8 kHinox_BombYvel[4] = {0, 0, 24, -24};
+      SpriteSpawnInfo info;
+      int j = Sprite_SpawnDynamically(k, 0x4a, &info);
+      if (j >= 0) {
+        Sprite_TransmuteToBomb(j);
+        sprite_delay_aux1[j] = 64;
+        int i = sprite_D[k];
+        Sprite_SetX(j, info.r0_x + kHinox_BombX[i]);
+        Sprite_SetY(j, info.r2_y + kHinox_BombY[i]);
+        sprite_x_vel[j] = kHinox_BombXvel[i];
+        sprite_y_vel[j] = kHinox_BombYvel[i];
+        sprite_z_vel[j] = 40;
+      }
+    } else {
+      static const uint8 kHinox_Gfx[8] = {11, 10, 8, 9, 7, 5, 1, 3};
+      sprite_graphics[k] = kHinox_Gfx[sprite_D[k] + (sprite_delay_main[k] < 32 ? 4 : 0)];
+    }
+    break;
+  }
+
+}
+
+void Hinox_ThrowBomb(int k) {  // 869f4a
+
+}
+
+void Hinox_FaceLink(int k) {  // 869fe1
+  Hinox_SetDirection(k, Sprite_DirectionToFaceLink(k, NULL));
+  sprite_x_vel[k] <<= 1;
+  sprite_y_vel[k] <<= 1;
+}
+
+void Hinox_SetDirection(int k, uint8 dir) {  // 86a004
+  static const int8 kHinox_Xvel[4] = {8, -8, 0, 0};
+  static const int8 kHinox_Yvel[4] = {0, 0, 8, -8};
+  sprite_D[k] = dir;
+  sprite_delay_main[k] = (GetRandomNumber() & 63) + 96;
+  sprite_ai_state[k]++;
+  sprite_x_vel[k] = kHinox_Xvel[dir];
+  sprite_y_vel[k] = kHinox_Yvel[dir];
+}
+
+void Hinox_Draw(int k) {  // 86a1f9
+  static const DrawMultipleData kHinox_Dmd[46] = {
+    {  0, -13, 0x0600, 2},
+    { -8,  -5, 0x0624, 2},
+    {  8,  -5, 0x4624, 2},
+    {  0,   1, 0x0606, 2},
+    {  0, -13, 0x0600, 2},
+    { -8,  -5, 0x0624, 2},
+    {  8,  -5, 0x4624, 2},
+    {  0,   1, 0x4606, 2},
+    { -8,  -6, 0x0624, 2},
+    {  8,  -6, 0x4624, 2},
+    {  0,   0, 0x0606, 2},
+    {  0, -13, 0x0604, 2},
+    { -8,  -6, 0x0624, 2},
+    {  8,  -6, 0x4624, 2},
+    {  0,   0, 0x4606, 2},
+    {  0, -13, 0x0604, 2},
+    { -3, -13, 0x0602, 2},
+    {  0,  -8, 0x060c, 2},
+    {  0,   0, 0x061c, 2},
+    { -3, -12, 0x0602, 2},
+    {  0,  -8, 0x060e, 2},
+    {  0,   0, 0x061e, 2},
+    {  3, -13, 0x4602, 2},
+    {  0,  -8, 0x460c, 2},
+    {  0,   0, 0x461c, 2},
+    {  3, -12, 0x4602, 2},
+    {  0,  -8, 0x460e, 2},
+    {  0,   0, 0x461e, 2},
+    {-13, -16, 0x056e, 2},
+    {  0, -13, 0x0600, 2},
+    { -8,  -5, 0x0620, 2},
+    {  8,  -5, 0x4624, 2},
+    {  0,   1, 0x0606, 2},
+    { -8,  -5, 0x0624, 2},
+    {  8,  -5, 0x4620, 2},
+    {  0,   1, 0x0606, 2},
+    {  0, -13, 0x0604, 2},
+    { 13, -16, 0x056e, 2},
+    { -8, -11, 0x056e, 2},
+    { -3, -13, 0x0602, 2},
+    {  0,   0, 0x0622, 2},
+    {  0,  -8, 0x060c, 2},
+    {  8, -11, 0x056e, 2},
+    {  3, -13, 0x4602, 2},
+    {  0,   0, 0x4622, 2},
+    {  0,  -8, 0x460c, 2},
+  };
+  PrepOamCoordsRet info;
+  static const uint8 kHinoxNum[12] = { 4, 4, 4, 4, 3, 3, 3, 3, 5, 5, 4, 4 };
+  static const uint8 kHinoxOffs[12] = { 0, 4, 8, 12, 16, 19, 22, 25, 28, 33, 38, 42 };
+  int j = sprite_graphics[k];
+  Sprite_DrawMultiple(k, &kHinox_Dmd[kHinoxOffs[j]], kHinoxNum[j], &info);
+  SpriteDraw_Shadow(k, &info);
+}
+
+void Sprite_23_RedBari(int k) {  // 86a23d
+  static const int8 kBari_Xvel2[16] = {0, 8, 11, 14, 16, 14, 11, 8, 0, -8, -11, -14, -16, -14, -11, -8};
+  static const int8 kBari_Yvel2[16] = {-16, -14, -11, -8, 0, 8, 11, 14, 16, 14, 11, 8, 0, -9, -11, -14};
+  static const uint8 kBari_Gfx[2] = {0, 3};
+  int j;
+
+  if (sign8(sprite_C[k])) {
+    if (sprite_head_dir[k] != 16) {
+      sprite_head_dir[k]++;
+    } else {
+      sprite_x_vel[k] = 255;
+      sprite_subtype[k] = 255;
+      Sprite_CheckTileCollision2(k);
+      sprite_subtype[k] = 0;
+      if (!sprite_tiletype) {
+        sprite_C[k] = 0;
+        sprite_ignore_projectile[k] = 0;
+        goto set_electrocute_delay;
+      }
+      sprite_ignore_projectile[k] = sprite_tiletype;
+    }
+    return;
+  }
+  if (sprite_C[k] != 0) {
+    SpriteDraw_SingleSmall(k);
+  } else if (sprite_graphics[k] >= 2) {
+    SpriteDraw_SingleLarge(k);
+  } else {
+    RedBari_Draw(k);
+  }
+
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  if (Sprite_ReturnIfRecoiling(k))
+    return;
+  if (sprite_delay_aux2[k])
+    goto recoil_from_split;
+
+  if (sprite_ai_state[k] == 2) {
+    static const int8 kBari_Xvel[2] = {8, -8};
+    sprite_ignore_projectile[k] = sprite_ai_state[k];
+    sprite_x_vel[k] = kBari_Xvel[frame_counter >> 1 & 1];
+    Sprite_MoveX(k);
+    if (!sprite_delay_main[k]) {
+      RedBari_Split(k);
+      sprite_state[k] = 0;
+    }
+    return;
+  }
+
+  Sprite_CheckDamageToAndFromLink(k);
+  if (!((k ^ frame_counter) & 15)) {
+    sprite_A[k] += (sprite_B[k] & 1) ? -1 : 1;
+    if (!(GetRandomNumber() & 3))
+      sprite_B[k]++;
+  }
+  j = sprite_A[k] & 15;
+  sprite_x_vel[k] = kBari_Xvel2[j];
+  sprite_y_vel[k] = kBari_Yvel2[j];
+
+  if (!((k ^ frame_counter) & 3 | sprite_delay_main[k])) {
+recoil_from_split:
+    if (!sprite_wallcoll[k])
+      Sprite_MoveXY(k);
+    Sprite_CheckTileCollision2(k);
+  }
+  j = sprite_C[k];
+  sprite_graphics[k] = (frame_counter >> 3 & 1) + kBari_Gfx[j];
+  if (sprite_ai_state[k]) {
+    if (sprite_delay_main[k]) {
+      sprite_graphics[k] = (frame_counter >> 1 & 2) + kBari_Gfx[j];
+      return;
+    }
+    sprite_ai_state[k] = 0;
+  } else if (sprite_delay_aux1[k]) {
+    return;
+  } else if (!(GetRandomNumber() & 1)) {
+    sprite_delay_main[k] = 128;
+    sprite_ai_state[k]++;
+    return;
+  }
+set_electrocute_delay:
+  sprite_delay_aux1[k] = (GetRandomNumber() & 63) + 128;
+}
+
+void RedBari_Split(int k) {  // 86a34e
+  static const int8 kRedBari_SplitX[2] = {0, 8};
+  static const int8 kRedBari_SplitXvel[2] = {-32, 32};
+
+  tmp_counter = 1;
+  do {
+    SpriteSpawnInfo info;
+    int j = Sprite_SpawnDynamically(k, 0x23, &info);
+    if (j >= 0) {
+      Sprite_SetSpawnedCoordinates(j, &info);
+      sprite_flags3[j] = 0x33;
+      sprite_oam_flags[j] = 3;
+      sprite_flags4[j] = 1;
+      sprite_C[j] = 1;
+      Sprite_SetX(j, info.r0_x + kRedBari_SplitX[tmp_counter]);
+      sprite_x_vel[j] = kRedBari_SplitXvel[tmp_counter];
+      sprite_delay_aux2[j] = 8;
+      sprite_delay_aux1[j] = 64;
+    }
+  } while (!sign8(--tmp_counter));
+
+}
+
+void RedBari_Draw(int k) {  // 86a3dc
+  static const DrawMultipleData kRedBari_Dmd[8] = {
+    {0, 0, 0x0022, 0},
+    {8, 0, 0x4022, 0},
+    {0, 8, 0x0032, 0},
+    {8, 8, 0x4032, 0},
+    {0, 0, 0x0023, 0},
+    {8, 0, 0x4023, 0},
+    {0, 8, 0x0033, 0},
+    {8, 8, 0x4033, 0},
+  };
+  PrepOamCoordsRet info;
+  Sprite_DrawMultiple(k, &kRedBari_Dmd[sprite_graphics[k] * 4], 4, &info);
+  SpriteDraw_Shadow(k, &info);
+}
+
+void Sprite_13_MiniHelmasaur(int k) {  // 86a409
+  static const uint8 kHelmasaur_Gfx[8] = {3, 4, 3, 4, 2, 2, 5, 5};
+  static const uint8 kHelmasaur_OamFlags[8] = {0x40, 0x40, 0, 0, 0, 0x40, 0x40, 0};
+  int j = sprite_subtype2[k] >> 2 & 1 | sprite_D[k] << 1;
+  sprite_graphics[k] = kHelmasaur_Gfx[j];
+  sprite_oam_flags[k] = sprite_oam_flags[k] & ~0x40 | kHelmasaur_OamFlags[j];
+  if (!((k ^ frame_counter) & 15)) {
+    uint8 x = sprite_x_vel[k];
+    if (sign8(x)) x = -x;
+    uint8 y = sprite_y_vel[k];
+    if (sign8(y)) y = -y;
+    sprite_D[k] = (x >= y) ? (sprite_x_vel[k] >> 7) : (sprite_y_vel[k] >> 7) + 2;
+  }
+  SpriteDraw_SingleLarge(k);
+  HelmasaurHardHatBeetleCommon(k);
+}
+
+void Sprite_26_HardhatBeetle(int k) {  // 86a460
+  sprite_graphics[k] = sprite_subtype2[k] >> 2 & 1;
+  HardHatBeetle_Draw(k);
+  HelmasaurHardHatBeetleCommon(k);
+}
+
+void HelmasaurHardHatBeetleCommon(int k) {  // 86a46d
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  sprite_subtype2[k]++;
+  if (Sprite_ReturnIfRecoiling(k))
+    return;
+  Sprite_CheckDamageToAndFromLink(k);
+  if (sprite_wallcoll[k] & 15) {
+    if (sprite_wallcoll[k] & 3)
+      sprite_x_vel[k] = 0;
+    sprite_y_vel[k] = 0;
+  } else {
+    Sprite_MoveXY(k);
+  }
+  Sprite_CheckTileCollision(k);
+  if (!((k ^ frame_counter) & 31)) {
+    ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLink(k, sprite_A[k]);
+    sprite_B[k] = pt.y;
+    sprite_C[k] = pt.x;
+  }
+  if ((k ^ frame_counter) & sprite_ai_state[k])
+    return;
+  sprite_y_vel[k] += sign8(sprite_y_vel[k] - sprite_B[k]) ? 1 : -1;
+  sprite_x_vel[k] += sign8(sprite_x_vel[k] - sprite_C[k]) ? 1 : -1;
+}
+
+void HardHatBeetle_Draw(int k) {  // 86a4f2
+  static const DrawMultipleData kHardHatBeetle_Dmd[4] = {
+    {0, -4, 0x0140, 2},
+    {0,  2, 0x0142, 2},
+    {0, -5, 0x0140, 2},
+    {0,  2, 0x0144, 2},
+  };
+  PrepOamCoordsRet info;
+  Sprite_DrawMultiple(k, &kHardHatBeetle_Dmd[sprite_graphics[k] * 2], 2, &info);
+  if (sprite_flags3[k] & 0x10)
+    SpriteDraw_Shadow(k, &info);
+}
+
+void Sprite_15_Antifairy(int k) {  // 86a50c
+  SpriteDraw_Antfairy(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  if (Sprite_CheckDamageToLink(k) && sprite_delay_main[k] == 0) {
+    sprite_delay_main[k] = 16;
+    int t = link_magic_power - 8;
+    if (t < 0)
+      t = 0;
+    else
+      sound_effect_2 = 0x1d;
+    link_magic_power = t;
+  }
+  Sprite_MoveXY(k);
+  Sprite_BounceFromTileCollision(k);
+}
+
+void Sprite_0B_Cucco(int k) {  // 86a5c2
+  if (sprite_x_vel[k] != 0)
+    sprite_oam_flags[k] = sprite_oam_flags[k] & ~0x40 | (sign8(sprite_x_vel[k]) ? 0 : 0x40);
+
+  SpriteDraw_SingleLarge(k);
+  if (sprite_head_dir[k] != 0) {
+    sprite_type[k] = 0x3d;
+    SpritePrep_LoadProperties(k);
+    sprite_subtype[k]++;
+    sprite_delay_main[k] = 48;
+    sound_effect_1 = 21;
+    sprite_ignore_projectile[k] = 21;
+    return;
+  }
+  if (sprite_state[k] == 10) {
+    sprite_ai_state[k] = 3;
+    if (submodule_index == 0) {
+      Chicken_IncrSubtype2(k, 3);
+      Cucco_DrawPANIC(k);
+      if (!(frame_counter & 0xf))
+        BawkBawk(k);
+    }
+  }
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  if (sprite_C[k] != 0) {
+    sprite_oam_flags[k] |= 0x10;
+    Sprite_MoveXY(k);
+    sprite_z[k] = 12;
+    sprite_ignore_projectile[k] = 12;
+    if (((k ^ frame_counter) & 7) == 0)
+      Sprite_CheckDamageToLink(k);
+    Chicken_IncrSubtype2(k, 4);
+  } else {
+    sprite_health[k] = 255;
+    if (sprite_B[k] >= 35)
+      Cucco_SummonAvenger(k);
+    if (sprite_F[k] != 0) {
+      sprite_F[k] = 0;
+      if (sprite_B[k] < 35) {
+        sprite_B[k]++;
+        BawkBawk(k);
+      }
+      sprite_ai_state[k] = 2;
+    }
+    Sprite_CheckDamageFromLink(k);
+    switch (sprite_ai_state[k]) {
+    case 0: Cucco_Calm(k); break;
+    case 1: Chicken_Hopping(k); break;
+    case 2: Cucco_Flee(k); break;
+    case 3: Cucco_Carried(k); break;
+    }
+  }
+}
+
+void Cucco_Calm(int k) {  // 86a67f
+  if (sprite_delay_main[k] == 0) {
+    int j = GetRandomNumber() & 0xf;
+    sprite_x_vel[k] = kSpriteKeese_Tab2[j];
+    sprite_y_vel[k] = kSpriteKeese_Tab3[j];
+    sprite_delay_main[k] = (GetRandomNumber() & 0x1f) + 0x10;
+    sprite_ai_state[k]++;
+  }
+  sprite_graphics[k] = 0;
+  Sprite_ReturnIfLifted(k);
+}
+
+void Chicken_Hopping(int k) {  // 86a6b1
+  if ((k ^ frame_counter) & 1 && Cucco_DoMovement_XY(k))
+    sprite_ai_state[k] = 0;
+  Sprite_MoveZ(k);
+  sprite_z_vel[k] -= 2;
+  if (sign8(sprite_z[k])) {
+    sprite_z[k] = 0;
+    if (sprite_delay_main[k] == 0) {
+      sprite_delay_main[k] = 32;
+      sprite_ai_state[k] = 0;
+    }
+    sprite_z_vel[k] = 10;
+  }
+  Chicken_IncrSubtype2(k, 4);
+}
+
+void Cucco_Flee(int k) {  // 86a6fc
+  Sprite_ReturnIfLifted(k);
+  Cucco_DoMovement_XY(k);
+  sprite_z[k] = 0;
+  if (!((k ^ frame_counter) & 0x1f)) {
+    ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLink(k, 16);
+    sprite_x_vel[k] = -pt.x;
+    sprite_y_vel[k] = -pt.y;
+  }
+  Chicken_IncrSubtype2(k, 5);
+  Cucco_DrawPANIC(k);
+}
+
+void Cucco_DrawPANIC(int k) {  // 86a727
+  PrepOamCoordsRet info;
+  if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
+    return;
+  Sprite_DrawDistress_custom(info.x, info.y, frame_counter);
+}
+
+void Cucco_Carried(int k) {  // 86a78e
+  Sprite_MoveZ(k);
+  if (Cucco_DoMovement_XY(k)) {
+    sprite_x_vel[k] = -sprite_x_vel[k];
+    sprite_y_vel[k] = -sprite_y_vel[k];
+    Sprite_MoveXY(k);
+    Sprite_HalveSpeed_XY(k);
+    Sprite_HalveSpeed_XY(k);
+    BawkBawk(k);
+  }
+  sprite_z_vel[k]--;
+  if (sign8(sprite_z[k])) {
+    sprite_z[k] = 0;
+    sprite_ai_state[k] = 2;
+    ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLink(k, 16);
+    sprite_x_vel[k] = -pt.x;
+    sprite_y_vel[k] = -pt.y;
+    Chicken_IncrSubtype2(k, 5);
+    Cucco_DrawPANIC(k);
+  } else {
+    Chicken_IncrSubtype2(k, 4);
+  }
+}
+
+uint8 Cucco_DoMovement_XY(int k) {  // 86a7bb
+  Sprite_MoveXY(k);
+  return Sprite_CheckTileCollision(k);
+}
+
+void Cucco_SummonAvenger(int k) {  // 86a7d3
+  static const uint8 kChicken_Avenger[2] = {0, 0xff};
+  if ((k ^ frame_counter) & 0xf | player_is_indoors)
+    return;
+  SpriteSpawnInfo info;
+  int j = Sprite_SpawnDynamicallyEx(k, 0xB, &info, 10);
+  if (j < 0)
+    return;
+  SpriteSfx_QueueSfx3WithPan(j, 0x1e);
+  sprite_C[j] = 1;
+  uint8 t = GetRandomNumber();
+  uint16 x = BG2HOFS_copy2, y = BG2VOFS_copy2;
+  if (t & 2)
+    x += t, y += kChicken_Avenger[t & 1];
+  else
+    y += t, x += kChicken_Avenger[t & 1];
+  Sprite_SetX(j, x);
+  Sprite_SetY(j, y);
+  Sprite_ApplySpeedTowardsLink(j, 32);
+  BawkBawk(k);
+}
+
+void BawkBawk(int k) {  // 86a84c
+  SpriteSfx_QueueSfx2WithPan(k, 0x30);
+}
+
+void Sprite_17_Hoarder(int k) {  // 86a86c
+  if (sprite_ai_state[k])
+    Sprite_Hoarder_Frantic(k);
+  else
+    Sprite_Hoarder_Covered(k);
+}
+
+void Sprite_Hoarder_Covered(int k) {  // 86a874
+  static const uint8 kRupeeCoveredGrab_Gfx[4] = {3, 4, 5, 4};
+  static const int8 kRupeeCoveredGrab_Xvel[4] = {-12, 12, 0, 0};
+  static const int8 kRupeeCoveredGrab_Yvel[4] = {0, 0, -12, 12};
+  CoveredRupeeCrab_Draw(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  sprite_graphics[k] = 0;
+  PointU8 pt;
+  uint8 dir = Sprite_DirectionToFaceLink(k, &pt);
+  if (sprite_delay_main[k])
+    goto lbl;
+  if ((uint8)(pt.y + 0x30) < 0x60 && (uint8)(pt.x + 0x20) < 0x40) {
+    sprite_delay_main[k] = 32;
+lbl:sprite_x_vel[k] = kRupeeCoveredGrab_Xvel[dir];
+    sprite_y_vel[k] = kRupeeCoveredGrab_Yvel[dir];
+    if (!sprite_wallcoll[k])
+      Sprite_MoveXY(k);
+    Sprite_CheckTileCollision2(k);
+    Sprite_CheckDamageFromLink(k);
+    sprite_graphics[k] = kRupeeCoveredGrab_Gfx[++sprite_subtype2[k] >> 1 & 3];
+  }
+  if (sprite_type[k] != 0x3e || link_item_gloves >= 1)
+    Sprite_ReturnIfLiftedPermissive(k);  // note, dont ret
+  if (sprite_state[k] != 9) {
+    sprite_C[k] = (sprite_type[k] == 0x17) ? 2 : 1;
+    sprite_type[k] = 0xec;
+    sprite_oam_flags[k] &= ~1;
+    sprite_graphics[k] = 0;
+    SpriteSpawnInfo info;
+    int j = Sprite_SpawnDynamically(k, 0x3e, &info);
+    if (j >= 0) {
+      Sprite_SetSpawnedCoordinates(j, &info);
+      sprite_flags2[j] &= ~0x80;
+      sprite_delay_aux2[j] = 128;
+      sprite_oam_flags[j] = 9;
+      sprite_ai_state[j] = 9;
+    }
+  }
+}
+
+void Sprite_Hoarder_Frantic(int k) {  // 86a91d
+  static const uint8 kRupeeCrab_Gfx[4] = {0, 1, 0, 1};
+  static const uint8 kRupeeCrab_OamFlags[4] = {0, 0, 0x40, 0};
+  static const int8 kRupeeCrab_Xvel[4] = {-16, 16, -16, 16};
+  static const int8 kRupeeCrab_Yvel[4] = {-16, -16, 16, 16};
+
+  SpriteDraw_SingleLarge(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  if (Sprite_ReturnIfRecoiling(k))
+    return;
+  Sprite_CheckDamageFromLink(k);
+  if (!sprite_delay_aux2[k])
+    Sprite_CheckDamageToLink(k);
+  int j = ++sprite_subtype2[k] >> 1 & 3;
+  sprite_graphics[k] = kRupeeCrab_Gfx[j];
+  sprite_oam_flags[k] = sprite_oam_flags[k] & ~0x40 | kRupeeCrab_OamFlags[j];
+  if (sprite_wallcoll[k]) {
+    sprite_delay_aux4[k] = 16;
+    j = GetRandomNumber() & 3;
+    sprite_x_vel[k] = kRupeeCrab_Xvel[j];
+    sprite_y_vel[k] = kRupeeCrab_Yvel[j];
+  } else {
+    Sprite_MoveXY(k);
+  }
+  Sprite_CheckTileCollision2(k);
+  if (!sprite_delay_aux4[k] && !((k ^ frame_counter) & 31)) {
+    ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLink(k, 16);
+    sprite_y_vel[k] = -pt.y;
+    sprite_x_vel[k] = -pt.x;
+  }
+  if (frame_counter & 1)
+    return;
+
+  int end;
+  uint8 type;
+  if (++sprite_G[k] == 192) {
+    sprite_delay_main[k] = 15;
+    sprite_state[k] = 6;
+    sprite_flags2[k] += 4;
+    end = 1;
+    type = 0xd9;
+  } else {
+    if (sprite_G[k] & 15)
+      return;
+    end = 0;
+    type = sprite_head_dir[k] == 6 ? 0xdb : 0xd9;
+  }
+  SpriteSpawnInfo info;
+  j = Sprite_SpawnDynamicallyEx(k, type, &info, end);
+  if (j >= 0) {
+    sprite_head_dir[k]++;
+    Sprite_SetSpawnedCoordinates(j, &info);
+    Sprite_SetX(j, info.r0_x + 8);
+    sprite_z_vel[j] = 32;
+    sprite_delay_aux4[j] = 16;
+    ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLink(j, 16);
+    sprite_y_vel[j] = ~pt.y;
+    sprite_x_vel[j] = ~pt.x;
+    SpriteSfx_QueueSfx3WithPan(k, 0x30);
+  }
+}
+
+void CoveredRupeeCrab_Draw(int k) {  // 86aa48
+  static const int8 kCoveredRupeeCrab_DrawY[12] = {0, 0, 0, -3, 0, -5, 0, -6, 0, -6, 0, -6};
+  static const uint8 kCoveredRupeeCrab_DrawChar[12] = {0x44, 0x44, 0xe8, 0x44, 0xe8, 0x44, 0xe6, 0x44, 0xe8, 0x44, 0xe6, 0x44};
+  static const uint8 kCoveredRupeeCrab_DrawFlags[12] = {0, 0xc, 3, 0xc, 3, 0xc, 3, 0xc, 3, 0xc, 0x43, 0xc};
+  PrepOamCoordsRet info;
+  if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
+    return;
+  if (byte_7E0FC6 >= 3)
+    return;
+  OamEnt *oam = GetOamCurPtr();
+  uint8 r7 = (sprite_type[k] == 0x17) ? 2 : 0;
+  uint8 r6 = sprite_graphics[k] * 2;
+  for (int i = 1; i >= 0; i--, oam++) {
+    int j = i + r6;
+    uint8 ch = kCoveredRupeeCrab_DrawChar[j];
+    SetOamHelper0(oam, info.x, info.y + kCoveredRupeeCrab_DrawY[j],
+                  ch + (ch == 0x44 ? r7 : 0),
+                  (info.flags & ~1) | kCoveredRupeeCrab_DrawFlags[j], 2);
+  }
+}
+
+void Sprite_EC_ThrownItem(int k) {  // 86aae0
+  if (byte_7E0FC6 < 3) {
+    if (sort_sprites_setting && sprite_floor[k]) {
+      int spr_slot = 0x2c + (k & 3);
+      oam_cur_ptr = 0x0800 + spr_slot * 4;
+      oam_ext_cur_ptr = 0x0A20 + spr_slot;
+    }
+    sprite_ignore_projectile[k] = sprite_state[k];
+    if (sprite_C[k] >= 6) {
+      SpriteDraw_ThrownItem_Gigantic(k);
+    } else {
+      SpriteDraw_SingleLarge(k);
+      OamEnt *oam = GetOamCurPtr();
+      uint8 t = player_is_indoors + is_in_dark_world;
+      int j = sprite_C[k];
+      oam->charnum = kThrowableScenery_Char[j + ((t >= 2) ? 6 : 0)];
+      oam->flags = (oam->flags & 0xf0) | kThrowableScenery_Flags[j];
+      sprite_oam_flags[k] = (sprite_oam_flags[k] & 0xc0) | (oam->flags & 0xf);
+    }
+  }
+  if (sprite_state[k] == 9) {
+    if (Sprite_ReturnIfInactive(k))
+      return;
+    ThrowableScenery_InteractWithSpritesAndTiles(k);
+  }
+}
+
+void SpriteDraw_ThrownItem_Gigantic(int k) {  // 86ab76
+  PrepOamCoordsRet info;
+  sprite_oam_flags[k] = kThrowableScenery_DrawLarge_OamFlags[sprite_C[k] - 6];
+
+  if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
+    return;
+
+  OamEnt *oam = GetOamCurPtr();
+  for (int i = 3; i >= 0; i--, oam++) {
+    SetOamHelper0(oam, info.x + kThrowableScenery_DrawLarge_X[i], info.y + kThrowableScenery_DrawLarge_Y[i],
+                  0x4a, kThrowableScenery_DrawLarge_Flags[i] | info.flags, 2);
+  }
+  Oam_AllocateFromRegionB(12);
+  oam = GetOamCurPtr();
+  info.y = Sprite_GetY(k) - BG2VOFS_copy2;
+  for (int i = 2; i >= 0; i--, oam++) {
+    SetOamHelper0(oam, info.x + kThrowableScenery_DrawLarge_X2[i], info.y + 12, 0x6c, 0x24, 2);
+  }
+}
+
+void ThrowableScenery_ScatterIntoDebris(int k) {  // 86ac41
+  if (!sign8(sprite_C[k]) && sprite_C[k] >= 6) {
+    for (int i = 3; i >= 0; i--) {
+      SpriteSpawnInfo info;
+      int j = Sprite_SpawnDynamically(k, 0xec, &info);
+      if (j >= 0) {
+        sprite_z[j] = sprite_z[k];
+        Sprite_SetX(j, info.r0_x + kScatterDebris_X[i]);
+        Sprite_SetY(j, info.r2_y + kScatterDebris_Y[i]);
+        sprite_C[j] = 1;
+        Sprite_ScheduleForBreakage(j);
+        sprite_oam_flags[j] = (sprite_C[k] < 7) ? 12 : 0;
+      }
+    }
+    sprite_state[k] = 0;
+  } else {
+    sprite_state[k] = 0;
+    PrepOamCoordsRet info;
+    if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
+      return;
+    int j = 29;
+    while (garnish_type[j--] && j >= 0) {}
+    j++;
+    garnish_type[j] = 22;
+    garnish_active = 22;
+    garnish_x_lo[j] = sprite_x_lo[k];
+    garnish_x_hi[j] = sprite_x_hi[k];
+    uint16 y = Sprite_GetY(k) - sprite_z[k] + 0x10;
+    garnish_y_lo[j] = (uint8)y;
+    garnish_y_hi[j] = (uint8)(y >> 8);
+    garnish_oam_flags[j] = info.flags;
+    garnish_floor[j] = sprite_floor[k];
+    garnish_countdown[j] = 31;
+    garnish_sprite[j] = sprite_C[k];
+  }
+}
+
+void Sprite_TransmuteToBomb(int k) {  // 86ad50
+  sprite_type[k] = 0x4a;
+  sprite_C[k] = 1;
+  sprite_delay_aux1[k] = 255;
+  sprite_flags3[k] = 0x18;
+  sprite_oam_flags[k] = 8;
+  sprite_health[k] = 0;
+}
+
+void Sprite_28_DarkWorldHintNPC(int k) {  // 86ad6f
+  StoryTeller_1_Draw(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  Sprite_BehaveAsBarrier(k);
+  if (!sprite_delay_main[k])
+    sprite_graphics[k] = frame_counter >> 4 & 1;
+
+  switch(sprite_subtype2[k]) {
+  case 0:
+    switch (sprite_ai_state[k]) {
+    case 0: DarkWorldHintNPC_Idle(k); break;
+    case 1:
+      if (choice_in_multiselect_box == 0 && DarkWorldHintNPC_HandlePayment()) {
+        Sprite_ShowMessageUnconditional(0xff);
+        sprite_ai_state[k] = 2;
+      } else {
+        Sprite_ShowMessageUnconditional(0x100);
+        sprite_ai_state[k] = 0;
+      }
+      break;
+    case 2: DarkWorldHintNPC_RestoreHealth(k); break;
+    }
+    break;
+  case 1:
+    switch (sprite_ai_state[k]) {
+    case 0: DarkWorldHintNPC_Idle(k); break;
+    case 1:
+      if (choice_in_multiselect_box == 0 && DarkWorldHintNPC_HandlePayment()) {
+        Sprite_ShowMessageUnconditional(0x101);
+        sprite_ai_state[k] = 2;
+      } else {
+        Sprite_ShowMessageUnconditional(0x100);
+        sprite_ai_state[k] = 0;
+      }
+      break;
+    case 2: DarkWorldHintNPC_RestoreHealth(k); break;
+    }
+    break;
+  case 2:
+    switch (sprite_ai_state[k]) {
+    case 0: DarkWorldHintNPC_Idle(k); break;
+    case 1:
+      if (choice_in_multiselect_box == 0 && DarkWorldHintNPC_HandlePayment()) {
+        Sprite_ShowMessageUnconditional(0x102);
+        sprite_ai_state[k] = 2;
+      } else {
+        Sprite_ShowMessageUnconditional(0x100);
+        sprite_ai_state[k] = 0;
+      }
+      break;
+    case 2: DarkWorldHintNPC_RestoreHealth(k); break;
+    }
+    break;
+  case 3:
+    if (sprite_delay_main[k] == 0) {
+      if ((frame_counter & 0x3f) == 0)
+        sprite_oam_flags[k] ^= 0x40;
+      if (GetRandomNumber() == 0)
+        sprite_delay_main[k] = 32;
+    }
+    Sprite_ShowSolicitedMessage(k, 0x149);
+    break;
+  case 4:
+    sprite_graphics[k] = frame_counter >> 1 & 1;
+    Sprite_MoveZ(k);
+    if (sign8(sprite_z[k]))
+      sprite_z[k] = 0;
+    sprite_z_vel[k] += (sprite_z[k] >= 4) ? -1 : 1;
+    switch (sprite_ai_state[k]) {
+    case 0: DarkWorldHintNPC_Idle(k); break;
+    case 1:
+      if (choice_in_multiselect_box == 0 && DarkWorldHintNPC_HandlePayment()) {
+        Sprite_ShowMessageUnconditional(0x103);
+        sprite_ai_state[k] = 2;
+      } else {
+        Sprite_ShowMessageUnconditional(0x100);
+        sprite_ai_state[k] = 0;
+      }
+      break;
+    case 2: DarkWorldHintNPC_RestoreHealth(k); break;
+    }
+    break;
+  }
+}
+
+void DarkWorldHintNPC_Idle(int k) {  // 86ada7
+  if (Sprite_ShowSolicitedMessage(k, 0xfe) & 0x100)
+    sprite_ai_state[k] = 1;
+}
+
+void DarkWorldHintNPC_RestoreHealth(int k) {  // 86adb5
+  link_hearts_filler = 0xa0;
+  sprite_ai_state[k] = 0;
+}
+
+bool DarkWorldHintNPC_HandlePayment() {  // 86aeab
+  if (link_rupees_goal < 20)
+    return false;
+  link_rupees_goal -= 20;
+  return true;
+}
+
+void StoryTeller_1_Draw(int k) {  // 86af1a
+  static const DrawMultipleData kStoryTeller_Dmd[10] = {
+    {0, 0, 0x0a4a, 2},
+    {0, 0, 0x4a6e, 2},
+    {0, 0, 0x0a24, 2},
+    {0, 0, 0x4a24, 2},
+    {0, 0, 0x0804, 2},
+    {0, 0, 0x4804, 2},
+    {0, 0, 0x0a6a, 2},
+    {0, 0, 0x0a6c, 2},
+    {0, 0, 0x0a0e, 2},
+    {0, 0, 0x0a2e, 2},
+  };
+  PrepOamCoordsRet info;
+  Sprite_DrawMultiplePlayerDeferred(k, &kStoryTeller_Dmd[sprite_subtype2[k] * 2 + sprite_graphics[k]], 1, &info);
+  SpriteDraw_Shadow(k, &info);
+}
+
+void Sprite_2E_FluteKid(int k) {  // 86af3b
+  switch (sprite_head_dir[k]) {
+  case 0:
+    switch (sprite_subtype2[k]) {
+    case 0: FluteKid_Human(k); break;
+    case 1: Sprite_FluteKid_Stumpy(k); break;
+    }
+    break;
+  case 1: Sprite_FluteKid_Quaver(k); break;
+  }
+}
+
+void FluteKid_Human(int k) {  // 86af51
+  if (sprite_ai_state[k] != 3)
+    sprite_C[k] = FluteBoy_Draw(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  if (!sprite_C[k] && !sprite_B[k]) {
+    sound_effect_ambient = 11;
+    sprite_B[k] = 11;
+  }
+  sprite_graphics[k] = frame_counter >> 5 & 1;
+  switch (sprite_ai_state[k]) {
+  case 0:  // wait
+    if (link_item_flute >= 2 || FluteBoy_CheckIfPlayerClose(k)) {
+      sprite_ai_state[k] = 1;
+      sprite_D[k]++;
+      byte_7E0FDD++;
+      sprite_delay_main[k] = 176;
+      flag_is_link_immobilized = 1;
+    }
+    if (!sprite_delay_main[k]) {
+      sprite_delay_main[k] = 25;
+      FluteKid_SpawnQuaver(k);
+    }
+    break;
+  case 1:  // prep phase out
+    flag_is_link_immobilized = 1;
+    if (!sprite_delay_main[k]) {
+      TS_copy = 2;
+      CGADSUB_copy = 48;
+      BYTE(palette_filter_countdown) = 0;
+      BYTE(darkening_or_lightening_screen) = 0;
+      Palette_AssertTranslucencySwap();
+      sprite_ai_state[k] = 2;
+      sound_effect_ambient = 128;
+      SpriteSfx_QueueSfx2WithPan(k, 0x33);
+    }
+    break;
+  case 2:  // phase out
+    if (!(frame_counter & 15)) {
+      PaletteFilter_SP5F();
+      if (!BYTE(palette_filter_countdown))
+        sprite_ai_state[k] = 3;
+    }
+    break;
+  case 3:  // phased out
+    PaletteFilter_RestoreSP5F();
+    Palette_RevertTranslucencySwap();
+    sprite_state[k] = 0;
+    flag_is_link_immobilized = 0;
+    break;
+  }
+}
+
+void Sprite_FluteKid_Stumpy(int k) {  // 86b040
+  static const int8 kFluteAardvark_Gfx[20] = {
+    1, 1, 1, 1, 2, 1, 2, 1, 2, 1, 2, 3, 2, 3, 2, 3, 2, 3, 2, -1,
+  };
+  static const int8 kFluteAardvark_Delay[19] = {
+    -1, -1, -1, 16, 2, 12, 6, 8, 10, 4, 14, 2, 10, 6, 6, 10, 2, 14,  2,
+  };
+  FluteAardvark_Draw(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  switch (sprite_ai_state[k]) {
+  case 0:  //
+    switch (link_item_flute & 3) {
+    case 0:  // supplicate
+      if (Sprite_ShowSolicitedMessage(k, 0xe5) & 0x100)
+        sprite_ai_state[k] = 1;
+      break;
+    case 1:  // give me flute
+      Sprite_ShowSolicitedMessage(k, 0xe8);
+      break;
+    case 2:  // thanks
+      sprite_graphics[k] = 1;
+      if (Sprite_ShowSolicitedMessage(k, 0xe9) & 0x100)
+        sprite_ai_state[k] = 3;
+      break;
+    case 3:  // already did
+      sprite_graphics[k] = 3;
+      break;
+    }
+    break;
+  case 1:  //
+    if (!choice_in_multiselect_box) {
+      Sprite_ShowMessageUnconditional(0xe6);
+      sprite_ai_state[k] = 2;
+    } else {
+      Sprite_ShowMessageUnconditional(0xe7);
+      sprite_ai_state[k] = 0;
+    }
+    break;
+  case 2:  // grant shovel
+    item_receipt_method = 0;
+    Link_ReceiveItem(0x13, 0);
+    sprite_ai_state[k] = 0;
+    break;
+  case 3:  // wait for music
+    if (hud_cur_item == kHudItem_Flute && joypad1H_last & 0x40) {
+      sprite_ai_state[k] = 4;
+      music_control = 0xf2;
+      sound_effect_1 = 0;
+      sound_effect_ambient = 23;
+      flag_is_link_immobilized++;
+    }
+    break;
+  case 4:  //
+    if (!sprite_delay_main[k]) {
+      if (sprite_A[k] >= 3)
+        SpriteSfx_QueueSfx2WithPan(k, 0x33);
+      int j = sprite_A[k]++;
+      if (kFluteAardvark_Gfx[j] >= 0) {
+        sprite_graphics[k] = kFluteAardvark_Gfx[j];
+        sprite_delay_main[k] = kFluteAardvark_Delay[j];
+      } else {
+        music_control = 0xf3;
+        sprite_ai_state[k] = 5;
+        flag_is_link_immobilized = 0;
+      }
+    }
+    break;
+  case 5:  // done
+    sprite_graphics[k] = 3;
+    sram_progress_indicator_3 |= 8;
+    break;
+  }
+}
+
+void Sprite_FluteKid_Quaver(int k) {  // 86b173
+  SpriteDraw_SingleSmall(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  Sprite_MoveXY(k);
+  Sprite_MoveZ(k);
+  if (!sprite_delay_main[k])
+    sprite_state[k] = 0;
+  if (!(frame_counter & 1))
+    sprite_x_vel[k] += (frame_counter >> 5 ^ cur_object_index) & 1 ? -1 : 1;
+}
+
+void FluteKid_SpawnQuaver(int k) {  // 86b1a5
+  SpriteSpawnInfo info;
+  int j = Sprite_SpawnDynamically(k, 0x2e, &info);
+  if (j >= 0) {
+    Sprite_SetX(j, info.r0_x + 4);
+    Sprite_SetY(j, info.r2_y - 4);
+    sprite_head_dir[j] = 1;
+    sprite_z_vel[j] = 8;
+    sprite_delay_main[j] = 96;
+    sprite_ignore_projectile[j] = 96;
+  }
+}
+
+void Sprite_1A_Smithy(int k) {  // 86b1ee
+  switch (sprite_subtype2[k]) {
+  case 0: Smithy_Main(k); break;
+  case 1: Smithy_Spark(k); break;
+  case 2: Smithy_Frog(k); break;
+  case 3: Smithy_Homecoming(k); break;
+  }
+}
+
+void Smithy_Homecoming(int k) {  // 86b1fd
+  ReturningSmithy_Draw(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  switch(sprite_ai_state[k]) {
+  case 0: { // ApproachTheBench
+    static const int8 kReturningSmithy_Delay[3] = {104, 12, 0};
+    static const int8 kReturningSmithy_Dir[3] = {0, 2, -1};
+    static const int8 kReturningSmithy_Xvel[4] = {0, 0, -13, 13};
+    static const int8 kReturningSmithy_Yvel[4] = {-13, 13, 0, 0};
+    Sprite_MoveXY(k);
+    sprite_graphics[k] = frame_counter >> 3 & 1;
+    if (sprite_delay_main[k])
+      return;
+    int j = sprite_A[k]++;
+    sprite_delay_main[k] = kReturningSmithy_Delay[j];
+    if ((j = kReturningSmithy_Dir[j]) >= 0) {
+      sprite_D[k] = j;
+      sprite_x_vel[k] = kReturningSmithy_Xvel[j];
+      sprite_y_vel[k] = kReturningSmithy_Yvel[j];
+    } else {
+      sprite_ai_state[k] = 1;
+    }
+    break;
+  }
+  case 1: // Thankful
+    Sprite_BehaveAsBarrier(k);
+    Sprite_ShowSolicitedMessage(k, 0xe3);
+    flag_is_link_immobilized = 0;
+    sprite_D[k] = 1;
+    sram_progress_indicator_3 |= 32;
+    break;
+  }
+}
+
+void Smithy_Frog(int k) {  // 86b274
+  SmithyFrog_Draw(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  Sprite_BehaveAsBarrier(k);
+  sprite_z_vel[k] -= 2;
+  Sprite_MoveZ(k);
+  if (sign8(sprite_z[k])) {
+    sprite_z[k] = 0;
+    sprite_z_vel[k] = 16;
+  }
+  if (!sprite_ai_state[k]) {
+    sprite_D[k] = 1;
+    if (Sprite_ShowSolicitedMessage(k, 0xe1) & 0x100)
+      sprite_ai_state[k] = 1;
+  } else {
+    follower_indicator = 7;
+    LoadFollowerGraphics();
+    Sprite_BecomeFollower(k);  // zelda bug: doesn't save X
+    sprite_state[k] = 0;
+  }
+}
+
+void ReturningSmithy_Draw(int k) {  // 86b308
+  static const DrawMultipleData kReturningSmithy_Dmd[8] = {
+    {0, 0, 0x4122, 2},
+    {0, 0, 0x0122, 2},
+    {0, 0, 0x4122, 2},
+    {0, 0, 0x0122, 2},
+    {0, 0, 0x0122, 2},
+    {0, 0, 0x0122, 2},
+    {0, 0, 0x4122, 2},
+    {0, 0, 0x4122, 2},
+  };
+  static const uint8 kReturningSmithy_Dma[8] = {0xc0, 0xc0, 0xa0, 0xa0, 0x80, 0x60, 0x80, 0x60};
+  int j = sprite_D[k] * 2 + sprite_graphics[k];
+  PrepOamCoordsRet info;
+  BYTE(dma_var7) = kReturningSmithy_Dma[j];
+  Sprite_DrawMultiplePlayerDeferred(k, &kReturningSmithy_Dmd[j], 1, &info);
+  SpriteDraw_Shadow(k, &info);
+}
+
+void SmithyFrog_Draw(int k) {  // 86b339
+  static const DrawMultipleData kSmithyFrog_Dmd[1] = {
+    {0, 0, 0x00c8, 2},
+  };
+  PrepOamCoordsRet info;
+  Sprite_DrawMultiplePlayerDeferred(k, kSmithyFrog_Dmd, 1, &info);
+  SpriteDraw_Shadow(k, &info);
+}
+
+void Smithy_Main(int k) {  // 86b34e
+  Smithy_Draw(k);
+  sprite_z_vel[k] -= 2;
+  Sprite_MoveZ(k);
+  if (sign8(sprite_z[k])) {
+    sprite_z[k] = 0;
+    sprite_z_vel[k] = 0;
+  }
+  if (Sprite_ReturnIfInactive(k))
+    return;
+
+  int j = sprite_ai_state[sprite_E[k]];
+  int i = sprite_ai_state[k];
+  if ((j == 5 || j == 7 || j == 9 || i == 5 || i == 7 || i == 9 || (i | j) == 0) && sprite_B[k]-- == 0) {
+    static const uint8 kSmithy_Gfx[8] = {0, 1, 2, 3, 3, 2, 1, 0};
+    static const uint8 kSmithy_B[8] = {24, 4, 1, 16, 16, 5, 10, 16};
+    j = sprite_A[k];
+    sprite_A[k] = j + 1 & 7;
+    sprite_graphics[k] = kSmithy_Gfx[j];
+    sprite_B[k] = kSmithy_B[j];
+    if (j == 1)
+      sprite_z_vel[k] = 16;
+    if (j == 3) {
+      Smithy_SpawnSpark(k);
+      SpriteSfx_QueueSfx2WithPan(k, 0x5);
+    }
+  }
+  switch(sprite_ai_state[k]) {
+  case 0:  // ConversationStart
+    sprite_C[k] = 0;
+    if (follower_indicator != 8) {
+      if (Smithy_ListenForHammer(k)) {
+        Sprite_ShowMessageUnconditional(0xe4);
+        sprite_delay_aux1[k] = 96;
+        sprite_C[k]++;
+      } else if (sram_progress_indicator_3 & 0x20) {
+        if (Sprite_ShowSolicitedMessage(k, 0xd8) & 0x100) {
+          sprite_ai_state[k]++;
+          sprite_C[k]++;
+        }
+      } else {
+        Sprite_ShowSolicitedMessage(k, 0xdf);
+      }
+    } else {
+      if (BYTE(link_y_coord) < 0xc2) {
+        Sprite_ShowMessageUnconditional(0xe0);
+        sprite_ai_state[k] = 10;
+        flag_is_link_immobilized++;
+      }
+    }
+    break;
+  case 1:  // ProvideTemperingChoice
+    if (!choice_in_multiselect_box) {
+      Sprite_ShowMessageUnconditional(0xd9);
+      sprite_ai_state[k] = 2;
+    } else {
+      Sprite_ShowMessageUnconditional(0xdc);
+      sprite_ai_state[k] = 0;
+    }
+    break;
+  case 2:  // HandleTemperingChoice
+    if (choice_in_multiselect_box == 0) {
+      if (link_sword_type < 3) {
+        Sprite_ShowMessageUnconditional(0xda);
+        sprite_ai_state[k] = 3;
+      } else {
+        Sprite_ShowMessageUnconditional(0xdb);
+        sprite_ai_state[k] = 0;
+      }
+    } else {
+      Sprite_ShowMessageUnconditional(0xdc);
+      sprite_ai_state[k] = 0;
+    }
+    break;
+  case 3:  // HandleTemperingCost
+    if (choice_in_multiselect_box || link_rupees_goal < 10) {
+      Sprite_ShowMessageUnconditional(0xdc);
+      sprite_ai_state[k] = 0;
+    } else {
+      link_rupees_goal -= 10;
+      Sprite_ShowMessageUnconditional(0xdd);
+      sprite_ai_state[sprite_E[k]] = 5;
+      sprite_ai_state[k] = 5;
+      flag_overworld_area_did_change = 0;
+      link_sword_type = 255;
+      sram_progress_indicator_3 |= 128;
+    }
+    break;
+  case 4:  // TemperingSword
+  case 5:  //
+    sprite_C[k] = 0;
+    if (Smithy_ListenForHammer(k)) {
+      Sprite_ShowMessageUnconditional(0xe4);
+      sprite_delay_aux1[k] = 96;
+      sprite_C[k]++;
+    } else if (flag_overworld_area_did_change) {
+      if (Sprite_ShowSolicitedMessage(k, 0xde) & 0x100) {
+        sprite_ai_state[k]++;
+        sprite_graphics[k] = 4;
+      }
+    } else {
+      Sprite_ShowSolicitedMessage(k, 0xe2);
+    }
+    break;
+  case 6:  // Smithy_GiveTemperedSword
+    sprite_ai_state[k] = 0;
+    sprite_ai_state[sprite_E[k]] = 0;
+    item_receipt_method = 0;
+    Link_ReceiveItem(2, 0);
+    sram_progress_indicator_3 &= ~0x80;
+    break;
+  case 7:  //
+  case 8:  //
+  case 9:  //
+    break;
+  case 10: { // Smithy_SpawnFriend
+    SpriteSpawnInfo info;
+    int j = Sprite_SpawnDynamically(k, 0x1a, &info);
+    if (j >= 0) {
+      Sprite_SetX(j, link_x_coord);
+      Sprite_SetY(j, link_y_coord);
+      sprite_subtype2[j] = 3;
+      sprite_ignore_projectile[j] = 3;
+    }
+    sprite_ai_state[k] = 11;
+    follower_indicator = 0;
+    sprite_graphics[k] = 4;
+    break;
+  }
+  case 11:  // Smithy_CopiouslyThankful
+    Sprite_ShowSolicitedMessage(k, 0xe3);
+    break;
+
+  }
+}
+
+bool Smithy_ListenForHammer(int k) {  // 86b43d
+  return sprite_delay_aux1[k] == 0 && hud_cur_item == kHudItem_Hammer && (link_item_in_hand & 2) && player_handler_timer == 2 && Sprite_CheckDamageToLink_same_layer(k);
+}
+
+int Smithy_SpawnDwarfPal(int k) {  // 86b5a6
+  SpriteSpawnInfo info;
+  int j = Sprite_SpawnDynamically(k, 0x1a, &info);
+  if (j < 0)
+    return j;
+  Sprite_SetX(j, info.r0_x);
+  Sprite_SetY(j, info.r2_y);
+  sprite_x_lo[j] += 0x2C;
+  sprite_D[j] = 1;
+  sprite_A[j] = 4;
+  sprite_ignore_projectile[j] = 4;
+  return j;
+}
+
+void Smithy_Draw(int k) {  // 86b673
+  static const DrawMultipleData kSmithy_Dmd[20] = {
+    {  1,   0, 0x4040, 2},
+    {-11, -10, 0x4060, 2},
+    { -1,   0, 0x0040, 2},
+    { 11, -10, 0x0060, 2},
+    {  1,   0, 0x4040, 2},
+    { -3, -14, 0x4044, 2},
+    { -1,   0, 0x0040, 2},
+    {  3, -14, 0x0044, 2},
+    {  1,   0, 0x4042, 2},
+    { 11, -10, 0x0060, 2},
+    { -1,   0, 0x0042, 2},
+    {-11, -10, 0x4060, 2},
+    {  1,   0, 0x4042, 2},
+    { 13,   2, 0x4062, 2},
+    { -1,   0, 0x0042, 2},
+    {-13,   2, 0x0062, 2},
+    {  0,   0, 0x4064, 2},
+    {  0,   0, 0x4062, 2},
+    {  0,   0, 0x0064, 2},
+    {  0,   0, 0x0064, 2},
+  };
+  PrepOamCoordsRet info;
+  Sprite_DrawMultiplePlayerDeferred(k, &kSmithy_Dmd[sprite_graphics[k] * 4 + sprite_D[k] * 2], 2, &info);
+  SpriteDraw_Shadow(k, &info);
+}
+
+void Smithy_Spark(int k) {  // 86b6a3
+  static const int8 kSmithySpark_Gfx[7] = {0, 1, 2, 1, 2, 1, -1};
+  static const int8 kSmithySpark_Delay[6] = {4, 1, 3, 2, 1, 1};
+  SmithySpark_Draw(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  if (!sprite_delay_main[k]) {
+    int j = sprite_A[k];
+    sprite_A[k] = j + 1 & 7;
+    if (sign8(kSmithySpark_Gfx[j])) {
+      sprite_state[k] = 0;
+      return;
+    }
+    sprite_graphics[k] = kSmithySpark_Gfx[j];
+    sprite_delay_main[k] = kSmithySpark_Delay[j];
+  }
+}
+
+void Smithy_SpawnSpark(int k) {  // 86b6cd
+  SpriteSpawnInfo info;
+  int j = Sprite_SpawnDynamically(k, 0x1a, &info);
+  if (j >= 0) {
+    Sprite_SetX(j, info.r0_x);
+    Sprite_SetY(j, info.r2_y);
+    sprite_x_lo[j] += sprite_D[k] ? -15 : 15;
+    sprite_y_lo[j] += 2;
+    sprite_subtype2[j] = 1;
+  }
+}
+
+void SmithySpark_Draw(int k) {  // 86b72c
+  Oam_AllocateFromRegionB(8);
+  static const DrawMultipleData kSmithySpark_Dmd[6] = {
+    { 0,  3, 0x41aa, 2},
+    { 0, -1, 0x41aa, 2},
+    {-4,  0, 0x0190, 0},
+    {12,  0, 0x4190, 0},
+    {-5, -2, 0x0191, 0},
+    {13, -2, 0x0191, 0},
+  };
+  Sprite_DrawMultiple(k, &kSmithySpark_Dmd[sprite_graphics[k] * 2], 2, NULL);
+}
+
+void Sprite_1B_Arrow(int k) {  // 86b754
+  int j;
+  static const int8 kEnemyArrow_Xvel[8] = {0, 0, 16, 16, 0, 0, -16, -16};
+  static const int8 kEnemyArrow_Yvel[8] = {16, 16, 0, 0, -16, -16, 0, 0};
+  static const uint8 kEnemyArrow_Dirs[4] = {0, 2, 1, 3};
+
+  EnemyArrow_Draw(k);
+  if (Sprite_ReturnIfPaused(k))
+    return;
+  if (sprite_state[k] == 9) {
+    j = sprite_delay_main[k];
+    if (j != 0) {
+      if (--j == 0) {
+        sprite_state[k] = 0;
+      } else if (j >= 32 && !(j & 1)) {
+        j = (frame_counter << 1 & 4) | sprite_D[k];
+        sprite_x_vel[k] = kEnemyArrow_Xvel[j];
+        sprite_y_vel[k] = kEnemyArrow_Yvel[j];
+        Sprite_MoveXY(k);
+      }
+      return;
+    }
+    Sprite_CheckDamageToLink_same_layer(k);
+    if (sprite_E[k] == 0 && Sprite_CheckTileCollision(k)) {
+      if (sprite_A[k]) {
+        SpriteSfx_QueueSfx2WithPan(k, 0x5);
+        Sprite_ScheduleForBreakage(k);
+        Sprite_PlaceWeaponTink(k);
+      } else {
+        sprite_delay_main[k] = 48;
+        sprite_A[k] = 2;
+        SpriteSfx_QueueSfx2WithPan(k, 0x8);
+      }
+    } else {
+      Sprite_MoveXY(k);
+    }
+  } else {
+    if (sprite_ai_state[k] == 0) {
+      Sprite_ApplyRicochet(k);
+      sprite_z_vel[k] = 24;
+      sprite_delay_main[k] = 255;
+      sprite_ai_state[k]++;
+      sprite_hit_timer[k] = 0;
+    }
+    sprite_D[k] = kEnemyArrow_Dirs[sprite_delay_main[k] >> 3 & 3];
+    Sprite_MoveZ(k);
+    Sprite_MoveXY(k);
+    sprite_z_vel[k] -= 2;
+    if (sign8(sprite_z[k]))
+      sprite_state[k] = 0;
+  }
+}
+
+void EnemyArrow_Draw(int k) {  // 86b867
+  static const int16 kEnemyArrow_Draw_X[8] = {-8, 0, 0, 8, 0, 0, 0, 0};
+  static const int16 kEnemyArrow_Draw_Y[8] = {0, 0, 0, 0, -8, 0, 0, 8};
+  static const uint8 kEnemyArrow_Draw_Char[32] = {
+    0x3a, 0x3d, 0x3d, 0x3a, 0x2a, 0x2b, 0x2b, 0x2a, 0x7c, 0x6c, 0x6c, 0x7c, 0x7b, 0x6b, 0x6b, 0x7b,
+    0x3a, 0x3b, 0x3b, 0x3a, 0x2a, 0x3c, 0x3c, 0x2a, 0x81, 0x80, 0x80, 0x81, 0x91, 0x90, 0x90, 0x91,
+  };
+  static const uint8 kEnemyArrow_Draw_Flags[32] = {
+    8,    8, 0x48, 0x48, 8, 8, 0x88, 0x88,    9, 0x49, 9, 0x49,    9, 0x89, 9, 0x89,
+    8, 0x88, 0xc8, 0x48, 8, 8, 0x88, 0x88, 0x49, 0x49, 9,    9, 0x89, 0x89, 9,    9,
+  };
+
+  PrepOamCoordsRet info;
+  if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
+    return;
+  OamEnt *oam = GetOamCurPtr();
+  uint8 r6 = sprite_D[k] * 2, r7 = sprite_A[k] * 8;
+  for (int i = 1; i >= 0; i--, oam++) {
+    int j = r6 + i;
+    SetOamHelper0(oam, info.x + kEnemyArrow_Draw_X[j], info.y + kEnemyArrow_Draw_Y[j],
+                  kEnemyArrow_Draw_Char[j + r7], kEnemyArrow_Draw_Flags[j + r7] | info.flags, 0);
+  }
+}
+
+void Sprite_1E_CrystalSwitch(int k) {  // 86b8d0
+  sprite_oam_flags[k] = sprite_oam_flags[k] & ~0xe | kCrystalSwitchPal[orange_blue_barrier_state & 1];
+  Oam_AllocateDeferToPlayer(k);
+  SpriteDraw_SingleLarge(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  if (Sprite_CheckDamageToLink_same_layer(k)) {
+    Sprite_NullifyHookshotDrag();
+    link_speed_setting = 0;
+    Sprite_RepelDash();
+  }
+  if (sprite_delay_main[k] == 0) {
+    Sprite_GarnishSpawn_Sparkle(k, frame_counter & 7, GetRandomNumber() & 7);
+    sprite_delay_main[k] = 31;
+  }
+  if (sprite_F[k] == 0) {
+    if (sign8(button_b_frames - 9))
+      Sprite_CheckDamageFromLink(k);
+  } else if (sprite_F[k]-- == 11) {
+    orange_blue_barrier_state ^= 1;
+    submodule_index = 22;
+    SpriteSfx_QueueSfx3WithPan(k, 0x25);
+  }
+}
+
+void Sprite_1F_SickKid(int k) {  // 86b94c
+  static const int8 kBugNetKid_Gfx[8] = {0, 1, 0, 1, 0, 1, 2, -1};
+  static const uint8 kBugNetKid_Delay[7] = {8, 12, 8, 12, 8, 96, 16};
+  int j;
+  BugNetKid_Draw(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  switch (sprite_ai_state[k]) {
+  case 0:  // resting
+    if (Sprite_CheckIfLinkIsBusy() || !Sprite_CheckDamageToLink_same_layer(k))
+      return;
+    if ((link_bottle_info[0] | link_bottle_info[1] | link_bottle_info[2] | link_bottle_info[3]) < 2) {
+      Sprite_ShowSolicitedMessage(k, 0x104);
+    } else {
+      flag_is_link_immobilized++;
+      sprite_ai_state[k] = 1;
+    }
+    break;
+  case 1:  // perk
+    if (sprite_delay_main[k])
+      return;
+    j = sprite_A[k];
+    if (kBugNetKid_Gfx[j] >= 0) {
+      sprite_graphics[k] = kBugNetKid_Gfx[j];
+      sprite_delay_main[k] = kBugNetKid_Delay[j];
+      sprite_A[k] = j + 1;
+    } else {
+      Sprite_ShowMessageUnconditional(0x105);
+      sprite_ai_state[k] = 2;
+    }
+    break;
+  case 2:  // grant
+    item_receipt_method = 0;
+    Link_ReceiveItem(0x21, 0);
+    flag_is_link_immobilized = 0;
+    sprite_ai_state[k] = 3;
+    break;
+  case 3:  // back to rest
+    sprite_graphics[k] = 1;
+    Sprite_ShowSolicitedMessage(k, 0x106);
+    break;
+  }
+}
+
+void Sprite_21_WaterSwitch(int k) {  // 86b9fa
+  PushSwitch_Draw(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  switch(sprite_ai_state[k]) {
+  case 0:
+    if (sprite_C[k]) {
+      if (!--sprite_B[k])
+        sprite_ai_state[k] = 1;
+      if (!(frame_counter & 3))
+        SpriteSfx_QueueSfx2WithPan(k, 0x22);
+    } else {
+      sprite_B[k] = 48;
+    }
+    break;
+  case 1:
+    if (!sprite_delay_main[k]) {
+      static const uint8 kPushSwitch_Delay[10] = {40, 6, 3, 3, 3, 5, 1, 1, 3, 12};
+      static const uint8 kPushSwitch_Dir[10] = {0, 1, 2, 3, 4, 5, 5, 6, 7, 6};
+      int j = ++sprite_A[k];
+      if (j == 10) {
+        sprite_ai_state[k] = 2;
+        dung_flag_statechange_waterpuzzle++;
+        SpriteSfx_QueueSfx3WithPan(k, 0x25);
+      } else {
+        sprite_delay_main[k] = kPushSwitch_Delay[j];
+        sprite_D[k] = kPushSwitch_Dir[j];
+        SpriteSfx_QueueSfx2WithPan(k, 0x22);
+      }
+    }
+    break;
+  case 2:
+    break;
+  }
+}
+
+void PushSwitch_Draw(int k) {  // 86bb22
+  static const OamEntSigned kPushSwitch_Oam[40] = {
+    {  4, 20, 0xdc, 0x20},
+    {  4, 12, 0xdd, 0x20},
+    {  4, 12, 0xdd, 0x20},
+    {  4, 12, 0xdd, 0x20},
+    {  0,  0, 0xca, 0x20},
+    {  3, 12, 0xdd, 0x20},
+    {  3, 20, 0xdc, 0x20},
+    {  3, 20, 0xdc, 0x20},
+    {  3, 20, 0xdc, 0x20},
+    {  0,  0, 0xca, 0x20},
+    { -8,  8, 0xea, 0x20},
+    {  0,  8, 0xeb, 0x20},
+    { -8, 16, 0xfa, 0x20},
+    {  0, 16, 0xfb, 0x20},
+    {  0,  0, 0xca, 0x20},
+    {-12,  4, 0xcc, 0x20},
+    { -4,  4, 0xcd, 0x20},
+    { -4,  4, 0xcd, 0x20},
+    { -4,  4, 0xcd, 0x20},
+    {  0,  0, 0xca, 0x20},
+    {-10,  4, 0xcc, 0x20},
+    { -4,  4, 0xcd, 0x20},
+    { -4,  4, 0xcd, 0x20},
+    { -4,  4, 0xcd, 0x20},
+    {  0,  0, 0xca, 0x20},
+    { -8,  4, 0xcc, 0x20},
+    { -4,  4, 0xcd, 0x20},
+    { -4,  4, 0xcd, 0x20},
+    { -4,  4, 0xcd, 0x20},
+    {  0,  0, 0xca, 0x20},
+    {  4,  3, 0xe2, 0x20},
+    { -6,  4, 0xcc, 0x20},
+    { -4,  4, 0xcd, 0x20},
+    { -4,  4, 0xcd, 0x20},
+    {  0,  0, 0xca, 0x20},
+    {  4,  3, 0xf1, 0x20},
+    { -6,  4, 0xcc, 0x20},
+    { -4,  4, 0xcd, 0x20},
+    { -4,  4, 0xcd, 0x20},
+    {  0,  0, 0xca, 0x20},
+  };
+  static const uint8 kPushSwitch_WH[16] = {8, 6, 0x10, 0x10, 0x10, 8, 0x10, 8, 0x10, 8, 0x10, 8, 0x10, 3, 0x10, 8};
+  Oam_AllocateDeferToPlayer(k);
+  PrepOamCoordsRet info;
+  if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
+    return;
+  uint8 flags;
+  sprite_oam_flags[k] = flags = palette_swap_flag ? sprite_oam_flags[k] | 0xe : sprite_oam_flags[k] & ~0xe;
+  uint8 r1 = sprite_B[k] >> 2 & 3;
+
+  oam_cur_ptr += 4, oam_ext_cur_ptr += 1;
+
+  OamEnt *oam = GetOamCurPtr();
+  memcpy(oam, &kPushSwitch_Oam[sprite_D[k] * 5], 20);
+
+  uint8 xv = -r1 + BYTE(dungmap_var7);
+  uint8 yv = HIBYTE(dungmap_var7) - (r1 >> 1);
+
+  oam[0].x += xv;
+  oam[1].x += xv;
+  oam[2].x += xv;
+  oam[3].x += xv;
+  oam[4].x += BYTE(dungmap_var7);
+
+  oam[0].y += yv;
+  oam[1].y += yv;
+  oam[2].y += yv;
+  oam[3].y += yv;
+  oam[4].y += HIBYTE(dungmap_var7);
+
+  oam[0].flags |= flags;
+  oam[1].flags |= flags;
+  oam[2].flags |= flags;
+  oam[3].flags |= flags;
+  oam[4].flags |= flags;
+
+  uint8 *big = &g_ram[oam_ext_cur_ptr];
+  big[0] = big[1] = big[2] = big[3] = 0;
+  big[4] = 2;
+
+  Sprite_CorrectOamEntries(k, 4, 0xff);
+
+  if (sprite_floor[k] == link_is_on_lower_level) {
+    sprite_C[k] = 0;
+    int d = sprite_D[k];
+    int x = Sprite_GetX(k) + (int8)kPushSwitch_Oam[d * 4].x;
+    int y = Sprite_GetY(k) + (int8)kPushSwitch_Oam[d * 4].y;
+
+    SpriteHitBox hb;
+    hb.r4_spr_xlo = x;
+    hb.r10_spr_xhi = x >> 8;
+    hb.r5_spr_ylo = y;
+    hb.r11_spr_yhi = y >> 8;
+    hb.r6_spr_xsize = kPushSwitch_WH[d * 2 + 0];
+    hb.r7_spr_ysize = kPushSwitch_WH[d * 2 + 1];
+    Link_SetupHitBox(&hb);
+    if (CheckIfHitBoxesOverlap(&hb)) {
+      uint16 oldy = Sprite_GetY(k);
+      Sprite_SetY(k, oldy + 19);
+      uint8 new_dir = Sprite_DirectionToFaceLink(k, NULL);
+      Sprite_SetY(k, oldy);
+      if (new_dir == 0 && link_direction_facing == 4)
+        sprite_C[k]++;
+    } else {
+      if (!Sprite_CheckDamageToLink_same_layer(k))
+        return;
+    }
+    Sprite_NullifyHookshotDrag();
+    link_speed_setting = 0;
+    Sprite_RepelDash();
+  }
+}
+
+void Sprite_39_Locksmith(int k) {  // 86bcac
+  uint8 bak;
+  int j;
+
+  MiddleAgedMan_Draw(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  Sprite_BehaveAsBarrier(k);
+
+  switch (sprite_ai_state[k]) {
+  case 0:  // chilling
+    Sprite_ShowSolicitedMessage(k, 0x107);
+    bak = sprite_x_lo[k];
+    sprite_x_lo[k] -= 16;
+    Sprite_Get16BitCoords(k);
+    sprite_x_vel[k] = 1;
+    sprite_y_vel[k] = 1;
+    if (!Sprite_CheckTileCollision(k)) {
+      sprite_ai_state[k]++;
+      if (follower_indicator != 0)
+        sprite_ai_state[k] = 5;
+    }
+    sprite_x_lo[k] = bak;
+    break;
+  case 1:  // transition to tagalong
+    follower_indicator = 9;
+    tagalong_var5 = 0;
+    LoadFollowerGraphics();
+    Follower_Initialize();
+    word_7E02CD = 0x40;
+    sprite_state[k] = 0;
+    break;
+  case 2:  // offer chest
+    if (Sprite_CheckIfLinkIsBusy())
+      return;
+    if (follower_dropped) {
+      j = Sprite_ShowSolicitedMessage(k, 0x109);
+    } else {
+      j = Sprite_ShowMessageOnContact(k, 0x109);
+    }
+    if (j & 0x100)
+      sprite_ai_state[k] = 3;
+    break;
+  case 3:  // react to secret keeping
+    if (!choice_in_multiselect_box) {
+      if (follower_dropped) {
+        Sprite_ShowMessageUnconditional(0x10c);
+        sprite_ai_state[k] = 2;
+      } else {
+        item_receipt_method = 0;
+        Link_ReceiveItem(0x16, 0);
+        sram_progress_indicator_3 |= 0x10;
+        sprite_ai_state[k] = 4;
+        follower_indicator = 0;
+      }
+    } else {
+      Sprite_ShowMessageUnconditional(0x10a);
+      sprite_ai_state[k] = 2;
+    }
+    break;
+  case 4:  // promise reminder
+    Sprite_ShowSolicitedMessage(k, 0x10b);
+    break;
+  case 5:  // silence other tagalong
+    Sprite_ShowSolicitedMessage(k, 0x107);
+    break;
+  }
+}
+
+void MiddleAgedMan_Draw(int k) {  // 86bdac
+  static const DrawMultipleData kMiddleAgedMan_Dmd[2] = {
+    {0, -8, 0x00ea, 2},
+    {0,  0, 0x00ec, 2},
+  };
+  PrepOamCoordsRet info;
+  Sprite_DrawMultiplePlayerDeferred(k, &kMiddleAgedMan_Dmd[0], 2, &info);
+  SpriteDraw_Shadow(k, &info);
+}
+
+void Sprite_2B_Hobo(int k) {  // 86bdc1
+  switch (sprite_subtype2[k]) {
+  case 0:
+    Sprite_Hobo_Bum(k);
+    break;
+  case 1:
+    Sprite_Hobo_Bubble(k);
+    break;
+  case 2:
+    Sprite_Hobo_Fire(k);
+    break;
+  case 3:
+    Sprite_Hobo_Smoke(k);
+    break;
+  }
+}
+
+void Sprite_Hobo_Bum(int k) {  // 86bdd0
+  Hobo_Draw(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  sprite_flags4[k] = 3;
+  if (Sprite_CheckDamageToLink_same_layer(k)) {
+    Sprite_NullifyHookshotDrag();
+    link_speed_setting = 0;
+    Link_CancelDash();
+  }
+  switch(sprite_ai_state[k]) {
+  case 0:  // sleeping
+    sprite_flags4[k] = 7;
+    if (Sprite_CheckDamageToLink_same_layer(k) && (filtered_joypad_L & 0x80)) {
+      sprite_ai_state[k] = 1;
+      int j = sprite_E[k];
+      sprite_delay_main[j] = 4;
+      flag_is_link_immobilized = 1;
+    }
+    if (!sprite_delay_aux2[k]) {
+      sprite_delay_aux2[k] = 160;
+      sprite_E[k] = Hobo_SpawnBubble(k);
+    }
+    break;
+  case 1: // wake up
+    if (!sprite_delay_main[k]) {
+      static const int8 kHobo_Gfx[7] = {0, 1, 0, 1, 0, 1, 2};
+      static const int8 kHobo_Delay[7] = {6, 2, 6, 6, 2, 100, 30};
+      int j = sprite_A[k];
+      if (j != 7) {
+        sprite_graphics[k] = kHobo_Gfx[j];
+        sprite_delay_main[k] = kHobo_Delay[j];
+        sprite_A[k]++;
+      } else {
+        Sprite_ShowMessageUnconditional(0xd7);
+        sprite_ai_state[k] = 2;
+      }
+    }
+    break;
+  case 2:  // grant bottle
+    sprite_ai_state[k] = 3;
+    sprite_graphics[k] = 1;
+    save_ow_event_info[BYTE(overworld_screen_index)] |= 0x20;
+    item_receipt_method = 0;
+    Link_ReceiveItem(0x16, 0);
+    sram_progress_indicator_3 |= 1;
+    break;
+  case 3:  // back to sleep
+    flag_is_link_immobilized = 0;
+    sprite_graphics[k] = 0;
+    if (!sprite_delay_main[k]) {
+      sprite_delay_main[k] = 160;
+      Hobo_SpawnBubble(k);
+    }
+    break;
+  }
+}
+
+void SpritePrep_Hobo_SpawnSmoke(int k) {  // 86be9d
+  SpriteSpawnInfo info;
+  int j = Sprite_SpawnDynamically(k, 0x2b, &info);
+  if (j >= 0) {
+    Sprite_SetSpawnedCoordinates(j, &info);
+    sprite_subtype2[j] = 0;
+    sprite_ignore_projectile[j] = 0;
+  }
+}
+
+void Sprite_Hobo_Bubble(int k) {  // 86beb4
+  Oam_AllocateFromRegionC(4);
+  SpriteDraw_SingleSmall(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  sprite_graphics[k] = (frame_counter >> 4 & 1) + 2;
+  if (!sprite_delay_aux1[k]) {
+    sprite_graphics[k]++;
+    Sprite_MoveZ(k);
+    if (!sprite_delay_main[k])
+      sprite_state[k] = 0;
+  }
+  if (sprite_delay_main[k] < 4)
+    sprite_graphics[k] = 3;
+}
+
+int Hobo_SpawnBubble(int k) {  // 86beed
+  SpriteSpawnInfo info;
+  int j = Sprite_SpawnDynamically(k, 0x2b, &info);
+  if (j >= 0) {
+    Sprite_SetSpawnedCoordinates(j, &info);
+    sprite_subtype2[j] = 1;
+    sprite_z_vel[j] = 2;
+    sprite_delay_main[j] = 96;
+    sprite_delay_aux1[j] = 96 >> 1;
+    sprite_ignore_projectile[j] = 96 >> 1;
+    sprite_flags2[j] = 0;
+  }
+  return j;
+}
+
+void Sprite_Hobo_Fire(int k) {  // 86bf15
+  SpriteDraw_SingleSmall(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  sprite_graphics[k] = frame_counter >> 3 & 1;
+  sprite_oam_flags[k] &= ~0x40;
+  if (!sprite_delay_main[k]) {
+    Hobo_SpawnSmoke(k);
+    sprite_delay_main[k] = 47;
+  }
+}
+
+void SpritePrep_Hobo_SpawnFire(int k) {  // 86bf4b
+  SpriteSpawnInfo info;
+  int j = Sprite_SpawnDynamically(k, 0x2b, &info);
+  if (j >= 0) {
+    Sprite_SetX(j, 0x194);
+    Sprite_SetY(j, 0x03f);
+    sprite_subtype2[j] = 2;
+    sprite_ignore_projectile[j] = 2;
+    sprite_flags2[j] = 0;
+    sprite_oam_flags[j] = sprite_oam_flags[j] & ~0xE | 2;
+  }
+}
+
+void Sprite_Hobo_Smoke(int k) {  // 86bf81
+  static const uint8 kHoboSmoke_OamFlags[4] = {0, 64, 128, 192};
+  sprite_graphics[k] = 6;
+  SpriteDraw_SingleSmall(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  Sprite_MoveXY(k);
+  Sprite_MoveZ(k);
+  sprite_oam_flags[k] = sprite_oam_flags[k] & 0x3f | kHoboSmoke_OamFlags[frame_counter >> 4 & 3];
+  if (!sprite_delay_main[k])
+    sprite_state[k] = 0;
+}
+
+void Hobo_SpawnSmoke(int k) {  // 86bfaf
+  SpriteSpawnInfo info;
+  int j = Sprite_SpawnDynamically(k, 0x2b, &info);
+  if (j >= 0) {
+    Sprite_SetSpawnedCoordinates(j, &info);
+    Sprite_SetY(j, info.r2_y - 4);
+    sprite_subtype2[j] = 3;
+    sprite_z_vel[j] = 7;
+    sprite_delay_main[j] = 96;
+    sprite_ignore_projectile[j] = 96;
+    sprite_flags2[j] = 0;
+  }
+}
+
+void Sprite_73_UncleAndPriest(int k) {  // 86bfe0
+  switch (sprite_E[k]) {
+  case 0:
+    Sprite_Uncle(k);
+    break;
+  case 1:
+    Sprite_Priest(k);
+    break;
+  case 2:
+    Sprite_SanctuaryMantle(k);
+    break;
+  }
+}
+
+void SpritePrep_UncleAndPriest_bounce(int k) {  // 86bfe5
+  if (BYTE(dungeon_room_index) == 18) {
+    Priest_SpawnMantle(k);
+    if (sram_progress_indicator >= 3)
+      sram_progress_flags |= 2;
+    if (sram_progress_flags & 2) {
+      sprite_state[k] = 0;
+      return;
+    }
+    sprite_E[k] = 1;
+    sprite_flags2[k] = sprite_flags2[k] & 0xf0 | 0x2;
+    sprite_flags4[k] = 3;
+    int j;
+    if (link_sword_type >= 2) {
+      sprite_D[k] = 4;
+      sprite_graphics[k] = 0;
+      j = 0;
+    } else {
+      sprite_D[k] = sprite_head_dir[k] = Sprite_DirectionToFaceLink(k, NULL) ^ 3;
+      if (follower_indicator == 1) {
+        sram_progress_flags |= 0x4;
+        save_ow_event_info[0x1b] |= 0x20;
+        sprite_delay_main[k] = 170;
+        j = 1;
+      } else {
+        j = 2;
+      }
+    }
+    sprite_subtype2[k] = j;
+    static const int16 kUncleAndSage_Y[3] = {0, -9, 0};
+    Sprite_SetX(k, Sprite_GetX(k) - 6);
+    Sprite_SetY(k, Sprite_GetY(k) + kUncleAndSage_Y[j]);
+    sprite_ignore_projectile[k]++;
+    byte_7FFE01 = 0;
+  } else if (BYTE(dungeon_room_index) == 4) {
+    if (!(sram_progress_flags & 0x10))
+      sprite_x_lo[k] += 8;
+    else
+      sprite_state[k] = 0;
+  } else {
+    if (!(sram_progress_flags & 1)) {
+      sprite_D[k] = 3;
+      sprite_subtype2[k] = 1;
+    } else {
+      sprite_state[k] = 0;
+    }
+  }
+}
+
+void SpritePrep_OldMan_bounce(int k) {  // 86bff9
+  sprite_ignore_projectile[k]++;
+  if (BYTE(dungeon_room_index) == 0xe4) {
+    sprite_subtype2[k] = 2;
+    return;
+  }
+  if (follower_indicator == 0) {
+    if (link_item_mirror == 2)
+      sprite_state[k] = 0;
+    follower_indicator = 4;
+    LoadFollowerGraphics();
+    follower_indicator = 0;
+  } else {
+    sprite_state[k] = 0;
+    LoadFollowerGraphics();
+  }
+}
+
+void Sprite_TutorialGuardOrBarrier(int k) {  // 86bffe
+  if (sprite_type[k] == 0x40) {
+    Sprite_EvilBarrier(k);
+    return;
+  }
+  int jbak = sprite_D[k];
+  if (sprite_delay_aux1[k])
+    sprite_D[k] = kSoldier_DirectionLockSettings[jbak];
+
+  sprite_graphics[k] = kSprite_TutorialEntities_Tab[sprite_D[k]];
+  TutorialSoldier_Draw(k);
+  sprite_D[k] = jbak;
+
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  Sprite_CheckDamageFromLink(k);
+
+  if (BYTE(overworld_area_index) == 0x1b && (sprite_y_lo[k] == 0x50 || sprite_y_lo[k] == 0x90)) {
+    Sprite_TutorialGuard_ShowMessageOnContact(k, sprite_y_lo[k] == 0x50 ? 0xB2 : 0xB3);
+  } else {
+    if (Sprite_TutorialGuard_ShowMessageOnContact(k, byte_7E0B69 + 0xf)) {
+      byte_7E0B69 = byte_7E0B69 != 6 ? byte_7E0B69 + 1 : 0;
+    }
+  }
+  Sprite_CheckDamageToAndFromLink(k);
+  if (((k ^ frame_counter) & 0x1f) == 0) {
+    uint8 jbak = sprite_D[k];
+    sprite_D[k] = Sprite_DirectionToFaceLink(k, NULL);
+    if (sprite_D[k] != jbak && !((sprite_D[k] ^ jbak) & 2))
+      sprite_delay_aux1[k] = 12;
+  }
+}
+
+void Sprite_F2_MedallionTablet(int k) {  // 86c00d
+  switch (sprite_subtype2[k]) {
+  case 0:
+    MedallionTablet_Main(k);
+    break;
+  case 1:
+    Sprite_DustCloud(k);
+    break;
+  }
+}
+
+void Sprite_33_RupeePull(int k) {  // 86c017
+  PrepOamCoordsRet info;
+  Sprite_PrepOamCoord(k, &info);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  if (Sprite_CheckIfLinkIsBusy())
+    return;
+  if (Sprite_CheckDamageToLink_same_layer(k)) {
+    link_need_for_pullforrupees_sprite = 1;
+    sprite_A[k] = 1;
+  } else {
+    if (sprite_A[k]) {
+      link_need_for_pullforrupees_sprite = 0;
+      if (link_state_bits & 1) {
+        sprite_state[k] = 0;
+        RupeePull_SpawnPrize(k);
+        Sprite_SpawnPoofGarnish(k);
+      }
+    }
+  }
+}
+
+void Sprite_14_ThievesTownGrate(int k) {  // 86c01c
+  PrepOamCoordsRet info;
+  Sprite_PrepOamCoord(k, &info);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  if (Sprite_CheckIfLinkIsBusy())
+    return;
+  if (Sprite_CheckDamageToLink_same_layer(k)) {
+    link_need_for_pullforrupees_sprite = 1;
+    sprite_A[k] = 1;
+  } else {
+    if (!sprite_A[k])
+      return;
+    link_need_for_pullforrupees_sprite = 0;
+    if (!(link_state_bits & 1))
+      return;
+    SpriteSfx_QueueSfx2WithPan(k, 0x1f);
+    OpenGargoylesDomain();
+    int j = Sprite_SpawnDustCloud(k);
+    Sprite_SetX(j, Sprite_GetX(k));
+    Sprite_SetY(j, Sprite_GetY(k));
+    sprite_state[k] = 0;
+  }
+}
+
+void SpritePrep_Snitch_bounce_2(int k) {  // 86c026
+  SpritePrep_Snitches(k);
+}
+
+void SpritePrep_Snitch_bounce_3(int k) {  // 86c030
+  SpritePrep_Snitches(k);
+}
+
+void Sprite_37_Waterfall(int k) {  // 86c03a
+  switch (sprite_subtype2[k]) {
+  case 0: Waterfall(k); break;
+  case 1: Sprite_BatCrash(k); break;
+  }
+}
+
+void Sprite_38_EyeStatue(int k) {  // 86c03f
+  if (!sprite_B[k]) {
+    PrepOamCoordsRet info;
+    Sprite_PrepOamCoord(k, &info);
+    if (Sprite_ReturnIfInactive(k))
+      return;
+    if (Sprite_DirectionToFaceLink(k, NULL) == 2 && sprite_unk2[k] == 9) {
+      dung_flag_statechange_waterpuzzle++;
+      sprite_B[k] = 1;
+    }
+  }
+}
+
+void Sprite_3A_MagicBat(int k) {  // 86c044
+  if (sprite_head_dir[k]) {
+    Sprite_MadBatterBolt(k);
+    return;
+  }
+
+  if (sprite_ai_state[k])
+    SpriteDraw_SingleLarge(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  Sprite_MoveXY(k);
+  Sprite_MoveZ(k);
+  switch(sprite_ai_state[k]) {
+  case 0:  // wait for summon
+    if (link_magic_consumption >= 2)
+      return;
+    if (!Sprite_CheckDamageToLink_same_layer(k))
+      return;
+    for (int i = 4; i >= 0; i--) {
+      if (ancilla_type[i] == 0x1a) {
+        Sprite_SpawnSuperficialBombBlast(k);
+        SpriteSfx_QueueSfx1WithPan(k, 0xd);
+        sprite_ai_state[k]++;
+        sprite_A[k] = 20;
+        flag_is_link_immobilized = 1;
+        sprite_oam_flags[k] |= 32;
+        return;
+      }
+    }
+    break;
+  case 1:  // RisingUp
+    if (!sprite_delay_main[k]) {
+      sprite_delay_main[k] = --sprite_A[k];
+      if (sprite_delay_main[k] != 1) {
+        static const int8 kMadBatter_RisingUp_XAccel[2] = {-8, 7};
+        sprite_z_vel[k] = sprite_delay_main[k] >> 2;
+        sprite_x_vel[k] += kMadBatter_RisingUp_XAccel[sprite_A[k] & 1];
+        sprite_graphics[k] ^= 1;
+      } else {
+        Sprite_ShowMessageUnconditional(0x110);
+        sprite_ai_state[k]++;
+        sprite_graphics[k] = 0;
+        sprite_z_vel[k] = 0;
+        sprite_x_vel[k] = 0;
+        sprite_delay_main[k] = 255;
+      }
+    }
+    break;
+  case 2: { // PseudoAttackPlayer
+    if (!sprite_delay_main[k]) {
+      sprite_ai_state[k]++;
+      sprite_delay_aux1[k] = 64;
+    }
+    static const int8 kMadBatter_PseudoAttack_OamFlags[8] = {0xa, 4, 2, 4, 2, 0xa, 4, 2};
+    sprite_oam_flags[k] = sprite_oam_flags[k] & ~0xE | kMadBatter_PseudoAttack_OamFlags[sprite_delay_main[k] >> 1 & 7];
+    if (sprite_delay_main[k] == 240)
+      Sprite_MagicBat_SpawnLightning(k);
+    break;
+  }
+  case 3:  // DoublePlayerMagicPower
+    if (!sprite_delay_aux1[k]) {
+      Sprite_ShowMessageUnconditional(0x111);
+      Palette_Restore_BG_And_HUD();
+      flag_update_cgram_in_nmi++;
+      sprite_ai_state[k]++;
+      link_magic_consumption = 1;
+      Hud_RefreshIcon();
+    } else if (sprite_delay_aux1[k] == 0x10) {
+      intro_times_pal_flash = 0x10;
+    }
+    break;
+  case 4:  // LaterBitches
+    Sprite_SpawnDummyDeathAnimation(k);
+    sprite_state[k] = 0;
+    flag_is_link_immobilized = 0;
+    break;
+  }
+}
+
+void SpritePrep_Zelda_bounce(int k) {  // 86c06c
+  if (link_sword_type >= 2) {
+    sprite_state[k] = 0;
+    return;
+  }
+  sprite_ignore_projectile[k]++;
+  sprite_D[k] = sprite_head_dir[k] = Sprite_DirectionToFaceLink(k, NULL) ^ 3;
+  uint8 bak0 = follower_indicator;
+  follower_indicator = 1;
+  LoadFollowerGraphics();
+  follower_indicator = bak0;
+
+  if (BYTE(dungeon_room_index) == 0x12) {
+    sprite_subtype2[k] = 2;
+    if (!(sram_progress_flags & 4)) {
+      sprite_state[k] = 0;
+    } else {
+      Sprite_SetX(k, Sprite_GetX(k) + 6);
+      Sprite_SetY(k, Sprite_GetY(k) + 15);
+      sprite_flags4[k] = 3;
+    }
+  } else {
+    sprite_subtype2[k] = 0;
+    if (follower_indicator == 1 || (sram_progress_flags & 4))
+      sprite_state[k] = 0;
+  }
+}
+
+void Sprite_78_MrsSahasrahla(int k) {  // 86c071
+  ElderWife_Draw(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  Sprite_BehaveAsBarrier(k);
+  switch (sprite_ai_state[k]) {
+  case 0:  // initial
+    if (link_sword_type < 2) {
+      if (Sprite_ShowSolicitedMessage(k, 0x2b) & 0x100)
+        sprite_ai_state[k] = 1;
+    } else {
+      Sprite_ShowSolicitedMessage(k, 0x2e);
+    }
+    sprite_graphics[k] = frame_counter >> 4 & 1;
+    break;
+  case 1:  // tell legend
+    Sprite_ShowMessageUnconditional(0x2c);
+    sprite_ai_state[k] = 2;
+    break;
+  case 2:  // loop until player not dumb
+    if (choice_in_multiselect_box == 0) {
+      sprite_ai_state[k] = 3;
+      Sprite_ShowMessageUnconditional(0x2d);
+    } else {
+      Sprite_ShowMessageUnconditional(0x2c);
+    }
+    break;
+  case 3:  // go away find old man
+    Sprite_ShowSolicitedMessage(k, 0x2d);
+    sprite_graphics[k] = frame_counter >> 4 & 1;
+    break;
+  }
+}
+
+void Sprite_16_Elder_bounce(int k) {  // 86c08a
+  Elder_Draw(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  Sprite_BehaveAsBarrier(k);
+  switch (sprite_subtype2[k]) {
+  case 0:
+    Sprite_Sahasrahla(k);
+    break;
+  case 1:
+    Sprite_Aginah(k);
+    break;
+  }
+}
+
+void SpritePrep_HeartPiece(int k) {  // 86c0a8
+  HeartUpgrade_CheckIfAlreadyObtained(k);
+}
+
+void Sprite_2D_TelepathicTile(int k) {  // 86c0b2
+  assert(0);
+}
+
+void Sprite_25_TalkingTree(int k) {  // 86c0d5
+  switch (sprite_subtype2[k]) {
+  case 0: TalkingTree_Mouth(k); break;
+  case 1: TalkingTree_Eye(k); break;
+  }
+}
+
+void Sprite_1C_Statue(int k) {  // 86c0e8
+  static const uint8 kMovableStatue_Dir[4] = {4, 6, 0, 2};
+  static const uint8 kMovableStatue_Joypad[4] = {1, 2, 4, 8};
+  static const int8 kMovableStatue_Xvel[4] = {-16, 16, 0, 0};
+  static const int8 kMovableStatue_Yvel[4] = {0, 0, -16, 16};
+  int j;
+  if (sprite_D[k]) {
+    sprite_D[k] = 0;
+    link_speed_setting = 0;
+    bitmask_of_dragstate = 0;
+  }
+  if (sprite_delay_main[k]) {
+    sprite_D[k] = 1;
+    bitmask_of_dragstate = 129;
+    link_speed_setting = 8;
+  }
+  MovableStatue_Draw(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  Statue_BlockSprites(k);
+  dung_flag_statechange_waterpuzzle = 0;
+  if (Statue_CheckForSwitch(k))
+    dung_flag_statechange_waterpuzzle = 1;
+  Sprite_MoveXY(k);
+  Sprite_Get16BitCoords(k);
+  Sprite_CheckTileCollision2(k);
+  Sprite_ZeroVelocity_XY(k);
+  if (Sprite_CheckDamageToLink_same_layer(k)) {
+    sprite_delay_main[k] = 7;
+    Sprite_RepelDash();
+    if (sprite_delay_aux1[k]) {
+      Sprite_NullifyHookshotDrag();
+      return;
+    }
+    j = Sprite_DirectionToFaceLink(k, NULL);
+    sprite_x_vel[k] = kMovableStatue_Xvel[j];
+    sprite_y_vel[k] = kMovableStatue_Yvel[j];
+  } else {
+    if (!sprite_delay_main[k])
+      sprite_delay_aux1[k] = 13;
+    if ((uint16)(cur_sprite_x - link_x_coord + 16) < 35 &&
+        (uint16)(cur_sprite_y - link_y_coord + 12) < 36 &&
+        link_direction_facing == kMovableStatue_Dir[j = Sprite_DirectionToFaceLink(k, NULL)] &&
+        !link_is_running) {
+      link_is_near_moveable_statue = 1;
+      sprite_A[k] = 1;
+      if (!(link_grabbing_wall & 2) || !(kMovableStatue_Joypad[j] & joypad1H_last) || (link_x_vel | link_y_vel) == 0)
+        return;
+      j ^= 1;
+      sprite_x_vel[k] = kMovableStatue_Xvel[j];
+      sprite_y_vel[k] = kMovableStatue_Yvel[j];
+    } else {
+      if (sprite_A[k]) {
+        sprite_A[k] = 0;
+        link_speed_setting = 0;
+        link_grabbing_wall = 0;
+        link_is_near_moveable_statue = 0;
+        link_cant_change_direction &= ~1;
+      }
+      return;
+    }
+  }
+  if (!(link_grabbing_wall & 2))
+    Sprite_NullifyHookshotDrag();
+  if (!(sprite_wallcoll[k] & 15) && !sprite_delay_aux4[k]) {
+    SpriteSfx_QueueSfx2WithPan(k, 0x22);
+    sprite_delay_aux4[k] = 8;
+  }
+}
+
+bool Statue_CheckForSwitch(int k) {  // 86c203
+  static const int8 kMovableStatue_SwitchX[4] = {3, 12, 3, 12};
+  static const int8 kMovableStatue_SwitchY[4] = {3, 3, 12, 12};
+  for (int j = 3; j >= 0; j--) {
+    uint16 x = Sprite_GetX(k) + kMovableStatue_SwitchX[j];
+    uint16 y = Sprite_GetY(k) + kMovableStatue_SwitchY[j];
+    uint8 t = GetTileAttribute(sprite_floor[k], &x, y);
+    if (t != 0x23 && t != 0x24 && t != 0x25 && t != 0x3b)
+      return false;
+  }
+  return true;
+}
+
+void MovableStatue_Draw(int k) {  // 86c264
+  static const DrawMultipleData kMovableStatue_Dmd[3] = {
+    {0, -8, 0x00c2, 0},
+    {8, -8, 0x40c2, 0},
+    {0,  0, 0x00c0, 2},
+  };
+  Sprite_DrawMultiplePlayerDeferred(k, &kMovableStatue_Dmd[0], 3, NULL);
+}
+
+void Statue_BlockSprites(int k) {  // 86c277
+  for (int j = 15; j >= 0; j--) {
+    if (sprite_type[j] == 0x1c || j == k || (j ^ frame_counter) & 1 || sprite_state[j] < 9)
+      continue;
+    int x = Sprite_GetX(j), y = Sprite_GetY(j);
+    if ((uint16)(cur_sprite_x - x + 12) < 24 &&
+        (uint16)(cur_sprite_y - y + 12) < 36) {
+      sprite_F[j] = 4;
+      ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLocation(k, x, y, 32);
+      sprite_y_recoil[j] = pt.y;
+      sprite_x_recoil[j] = pt.x;
+    }
+  }
+}
+
+void Sprite_1D_FluteQuest(int k) {  // 86c2e5
+  PrepOamCoordsRet info;
+  Sprite_PrepOamCoord(k, &info);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  if (BYTE(overworld_screen_index) == 0x18) {
+    if (link_item_flute == 3)
+      sprite_state[k] = 0;
+  } else {
+    if (link_item_flute & 2)
+      sprite_state[k] = 0;
+  }
+}
+
+void Sprite_72_FairyPond(int k) {  // 86c319
+  if (sprite_A[k]) {
+    if (!--sprite_C[k])
+      sprite_state[k] = 0;
+    sprite_graphics[k] = sprite_C[k] >> 3;
+    Oam_AllocateFromRegionC(4);
+    SpriteDraw_SingleSmall(k);
+    return;
+  }
+  if (sprite_B[k]) {
+    FaerieQueen_Draw(k);
+    sprite_graphics[k] = frame_counter >> 4 & 1;
+    if (frame_counter & 15)
+      return;
+    SpriteSpawnInfo info;
+    int j = Sprite_SpawnDynamically(k, 0x72, &info);
+    if (j >= 0) {
+      Sprite_SetX(j, info.r0_x + kWishPond_X[GetRandomNumber() & 7]);
+      Sprite_SetY(j, info.r2_y + kWishPond_Y[GetRandomNumber() & 7]);
+      sprite_C[j] = 31;
+      sprite_A[j] = 31;
+      sprite_flags2[j] = 0;
+      sprite_flags3[j] = 0x48;
+      sprite_oam_flags[j] = 0x48 & 0xf;
+      sprite_B[j] = 1;
+    }
+    return;
+  }
+  PrepOamCoordsRet info;
+  Sprite_PrepOamCoord(k, &info);
+  Sprite_WishPond2(k);
+}
+
+void Sprite_WishPond2(int k) {  // 86c41d
+  WishPond2_Draw(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  if (BYTE(dungeon_room_index) != 21)
+    Sprite_WishPond3(k);
+  else
+    Sprite_HappinessPond(k);
+}
+
+void Sprite_HappinessPond(int k) {  // 86c44c
+  static const uint8 kHappinessPondCost[4] = {5, 20, 25, 50};
+  static const uint8 kHappinessPondCostHex[4] = {5, 0x20, 0x25, 0x50};
+  switch (sprite_ai_state[k]) {
+  case 0:
+    flag_is_link_immobilized = 0;
+    if (sprite_delay_main[k] || Sprite_CheckIfLinkIsBusy())
+      return;
+    if (Sprite_ShowMessageOnContact(k, 0x89) & 0x100) {
+      sprite_ai_state[k] = 1;
+      Link_ResetProperties_A();
+      Ancilla_TerminateSparkleObjects();
+      link_direction_facing = 0;
+    }
+    break;
+  case 1:
+    if (choice_in_multiselect_box == 0) {
+      int i = (link_bomb_upgrades | link_arrow_upgrades) != 0;
+      sprite_graphics[k] = i * 2;
+      WORD(dialogue_number[0]) = WORD(kHappinessPondCostHex[i * 2]);
+      Sprite_ShowMessageUnconditional(0x14e);
+      sprite_ai_state[k] = 2;
+      flag_is_link_immobilized = 1;
+    } else {
+show_later_msg:
+      Sprite_ShowMessageUnconditional(0x14c);
+      sprite_ai_state[k] = 0;
+      sprite_delay_main[k] = 255;
+    }
+    break;
+  case 2: {
+    int i = sprite_graphics[k] + choice_in_multiselect_box;
+    dialogue_number[1] = kHappinessPondCostHex[i];
+    if (link_rupees_goal < kHappinessPondCost[i]) {
+      goto show_later_msg;
+    } else {
+      sprite_D[k] = kHappinessPondCost[i];
+      sprite_head_dir[k] = i;
+      sprite_ai_state[k] = 3;
+    }
+    break;
+  }
+  case 3: {
+    sprite_delay_main[k] = 80;
+    int i = sprite_D[k];
+    link_rupees_goal -= i;
+    link_rupees_in_pond += i;
+    AddHappinessPondRupees(sprite_head_dir[k]);
+    if (link_rupees_in_pond >= 100) {
+      link_rupees_in_pond -= 100;
+      sprite_ai_state[k] = 5;
+      return;
+    }
+    dialogue_number[0] = (link_rupees_in_pond / 10) * 16 + (link_rupees_in_pond % 10);
+    sprite_ai_state[k] = 4;
+    break;
+  }
+  case 4:
+    if (sprite_delay_main[k] == 0) {
+      Sprite_ShowMessageUnconditional(0x94);
+      sprite_ai_state[k] = 13;
+    }
+    break;
+  case 5:
+    if (sprite_delay_main[k] == 0) {
+      SpriteSpawnInfo info;
+      int j = Sprite_SpawnDynamically(k, 0x72, &info);
+      assert(j >= 0);
+      Sprite_SetX(j, info.r0_x);
+      Sprite_SetY(j, info.r2_y - 80);
+      music_control = 0x1b;
+      last_music_control = 0;
+      sprite_B[j] = 1;
+      Palette_AssertTranslucencySwap();
+      PaletteFilter_WishPonds();
+      sprite_E[k] = j;
+      sprite_ai_state[k] = 6;
+      sprite_delay_main[k] = 255;
+    }
+    break;
+  case 6:
+    if (!(frame_counter & 7)) {
+      PaletteFilter_SP5F();
+      if (!BYTE(palette_filter_countdown)) {
+        Sprite_ShowMessageUnconditional(0x95);
+        Palette_RevertTranslucencySwap();
+        TS_copy = 0;
+        CGADSUB_copy = 0x20;
+        flag_update_cgram_in_nmi++;
+        sprite_ai_state[k] = 7;
+      }
+    }
+    break;
+  case 7:
+    if (!choice_in_multiselect_box)
+      sprite_ai_state[k] = 8;
+    else
+      sprite_ai_state[k] = 12;
+    break;
+  case 8: {
+    static const uint8 kMaxBombsForLevelHex[8] = {0x10, 0x15, 0x20, 0x25, 0x30, 0x35, 0x40, 0x50};
+    int i = link_bomb_upgrades + 1;
+    if (i != 8) {
+      link_bomb_upgrades = i;
+      dialogue_number[0] = link_bomb_filler = kMaxBombsForLevelHex[i];
+      Sprite_ShowMessageUnconditional(0x96);
+    } else {
+      link_rupees_goal += 100;
+      Sprite_ShowMessageUnconditional(0x98);
+    }
+    sprite_ai_state[k] = 9;
+    break;
+  }
+  case 9:
+    Palette_AssertTranslucencySwap();
+    TS_copy = 2;
+    CGADSUB_copy = 0x30;
+    flag_update_cgram_in_nmi++;
+    sprite_ai_state[k] = 10;
+    break;
+  case 10:
+    if (!(frame_counter & 7)) {
+      PaletteFilter_SP5F();
+      if (BYTE(palette_filter_countdown) == 30) {
+        sprite_state[sprite_E[k]] = 0;
+      } else if (BYTE(palette_filter_countdown) == 0) {
+        sprite_ai_state[k] = 11;
+      }
+    }
+    break;
+  case 11:
+    PaletteFilter_RestoreSP5F();
+    Palette_RevertTranslucencySwap();
+    sprite_ai_state[k] = 0;
+    sprite_delay_main[k] = 255;
+    break;
+  case 12: {
+    static const uint8 kMaxArrowsForLevelHex[8] = {0x30, 0x35, 0x40, 0x45, 0x50, 0x55, 0x60, 0x70};
+    int i = link_arrow_upgrades + 1;
+    if (i != 8) {
+      link_arrow_upgrades = i;
+      dialogue_number[0] = link_arrow_filler = kMaxArrowsForLevelHex[i];
+      Sprite_ShowMessageUnconditional(0x97);
+    } else {
+      link_rupees_goal += 100;
+      Sprite_ShowMessageUnconditional(0x98);
+    }
+    sprite_ai_state[k] = 9;
+    break;
+  }
+  case 13:
+    Sprite_ShowMessageUnconditional(0x154);
+    sprite_ai_state[k] = 14;
+    break;
+  case 14: {
+    static const uint16 kHappinessPondLuckMsg[4] = {0x150, 0x151, 0x152, 0x153};
+    static const uint8 kHappinessPondLuck[4] = {1, 0, 0, 2};
+    int i = GetRandomNumber() & 3;
+    item_drop_luck = kHappinessPondLuck[i];
+    luck_kill_counter = 0;
+    Sprite_ShowMessageUnconditional(kHappinessPondLuckMsg[i]);
+    sprite_ai_state[k] = 0;
+    sprite_delay_main[k] = 255;
+    break;
+  }
+  }
+}
+
+void WishPond2_Draw(int k) {  // 86c4b5
+  static const DrawMultipleData kWishPond2_Dmd[8] = {
+    {32, -64, 0x0024, 0},
+    {32, -56, 0x0034, 0},
+    {32, -64, 0x0024, 0},
+    {32, -56, 0x0034, 0},
+    {32, -64, 0x0024, 2},
+    {32, -64, 0x0024, 2},
+    {32, -64, 0x0024, 2},
+    {32, -64, 0x0024, 2},
+  };
+  if (BYTE(dungeon_room_index) == 21)
+    return;
+  uint8 t = sprite_ai_state[k];
+  if (t != 5 && t != 6 && t != 11 && t != 12)
+    return;
+  int g = sprite_graphics[k];
+  uint8 f = kWishPond2_OamFlags[g];
+  if (f == 0xff)
+    f = 5;
+  sprite_oam_flags[k] = (f & 7) * 2;
+  Sprite_DrawMultiple(k, &kWishPond2_Dmd[(kReceiveItem_Tab1[g] >> 1) * 4], 4, NULL);
+}
+
+void FaerieQueen_Draw(int k) {  // 86cb26
+  static const uint8 kFaerieQueen_Draw_X[24] = {
+    0, 16, 0, 8, 16, 24, 0,  8, 16, 24, 0, 16, 0, 16, 0, 8, 16, 24, 0, 8, 16, 24, 0, 16,
+  };
+  static const uint8 kFaerieQueen_Draw_Y[24] = {
+    0,  0, 16, 16, 16, 16, 24, 24, 24, 24, 32, 32, 0, 0, 16, 16, 16, 16, 24, 24, 24, 24, 32, 32,
+  };
+  static const uint8 kFaerieQueen_Draw_Char[24] = {
+    0xc7, 0xc7, 0xcf, 0xca, 0xca, 0xcf, 0xdf, 0xda, 0xda, 0xdf, 0xcb, 0xcb, 0xcd, 0xcd, 0xc9, 0xca,
+    0xca, 0xc9, 0xd9, 0xda, 0xda, 0xd9, 0xcb, 0xcb,
+  };
+  static const uint8 kFaerieQueen_Draw_Flags[24] = {
+    0, 0x40, 0, 0, 0x40, 0x40, 0, 0, 0x40, 0x40, 0, 0x40, 0, 0x40, 0, 0, 0x40, 0x40, 0, 0, 0x40, 0x40, 0, 0x40,
+  };
+  static const uint8 kFaerieQueen_Draw_Big[24] = {
+    2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2,
+  };
+  static const DrawMultipleData kFaerieQueen_Dmd[20] = {
+    { 0,  0, 0x00e9, 2},
+    {16,  0, 0x40e9, 2},
+    { 0,  0, 0x00e9, 2},
+    {16,  0, 0x40e9, 2},
+    { 0,  0, 0x00e9, 2},
+    {16,  0, 0x40e9, 2},
+    { 0, 16, 0x00eb, 2},
+    {16, 16, 0x40eb, 2},
+    { 0, 32, 0x00ed, 2},
+    {16, 32, 0x40ed, 2},
+    { 0,  0, 0x00ef, 0},
+    {24,  0, 0x40ef, 0},
+    { 0,  8, 0x00ff, 0},
+    {24,  8, 0x40ff, 0},
+    { 0,  0, 0x00e9, 2},
+    {16,  0, 0x40e9, 2},
+    { 0, 16, 0x00eb, 2},
+    {16, 16, 0x40eb, 2},
+    { 0, 32, 0x00ed, 2},
+    {16, 32, 0x40ed, 2},
+  };
+  if (!savegame_is_darkworld) {
+    PrepOamCoordsRet info;
+    if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
+      return;
+    OamEnt *oam = GetOamCurPtr();
+    int g = sprite_graphics[k];
+    for (int i = 11; i >= 0; i--, oam++) {
+      int j = g * 12 + i;
+      SetOamPlain(oam, kFaerieQueen_Draw_X[j] + info.x, kFaerieQueen_Draw_Y[j] + info.y,
+                   kFaerieQueen_Draw_Char[j], info.flags | kFaerieQueen_Draw_Flags[j], kFaerieQueen_Draw_Big[j]);
+    }
+    Sprite_CorrectOamEntries(k, 11, 0xff);
+  } else {
+    Sprite_DrawMultiple(k, &kFaerieQueen_Dmd[sprite_graphics[k] * 10], 10, NULL);
+  }
+}
+
+void Sprite_71_Leever(int k) {  // 86cba2
+  static const uint8 kLeever_EmergeGfx[16] = {10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, 1, 2, 1, 0, 0};
+  static const uint8 kLeever_AttackGfx[4] = {9, 10, 11, 12};
+  static const uint8 kLeever_AttackSpd[2] = {12, 8};
+  static const uint8 kLeever_SubmergeGfx[16] = {10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, 1, 2, 1, 0, 0};
+
+  if (sprite_ai_state[k])
+    Leever_Draw(k);
+  else {
+    PrepOamCoordsRet info;
+    Sprite_PrepOamCoord(k, &info);
+  }
+  if (sprite_pause[k])
+    sprite_state[k] = 8;
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  if (Sprite_ReturnIfRecoiling(k))
+    return;
+  switch(sprite_ai_state[k]) {
+  case 0:  // under sand
+    sprite_ignore_projectile[k] = sprite_delay_main[k];
+    if (!sprite_delay_main[k]) {
+      sprite_ai_state[k] = 1;
+      sprite_delay_main[k] = 127;
+    } else {
+      Sprite_ApplySpeedTowardsLink(k, 16);
+      Sprite_MoveXY(k);
+      Sprite_CheckTileCollision2(k);
+    }
+    break;
+  case 1:  // emerge
+    sprite_ignore_projectile[k] = sprite_delay_main[k];
+    if (!sprite_delay_main[k]) {
+      sprite_ai_state[k]++;
+      sprite_delay_main[k] = (GetRandomNumber() & 63) + 160;
+      Sprite_ZeroVelocity_XY(k);
+    } else {
+      sprite_graphics[k] = kLeever_EmergeGfx[sprite_delay_main[k] >> 3];
+    }
+    break;
+  case 2:  // attack
+    Sprite_CheckDamageToAndFromLink(k);
+    if (!sprite_delay_main[k]) {
+stop_attack:
+      sprite_ai_state[k]++;
+      sprite_delay_main[k] = 127;
+    } else {
+      if (!(sprite_subtype2[k] & 7))
+        Sprite_ApplySpeedTowardsLink(k, kLeever_AttackSpd[sprite_A[k]]);
+      Sprite_MoveXY(k);
+      if (Sprite_CheckTileCollision(k))
+        goto stop_attack;
+      sprite_graphics[k] = kLeever_AttackGfx[++sprite_subtype2[k] >> 2 & 3];
+    }
+    break;
+  case 3:  // submerge
+    sprite_ignore_projectile[k] = sprite_delay_main[k];
+    if (!sprite_delay_main[k]) {
+      sprite_ai_state[k] = 0;
+      sprite_delay_main[k] = (GetRandomNumber() & 31) + 64;
+    } else {
+      sprite_graphics[k] = kLeever_SubmergeGfx[sprite_delay_main[k] >> 3 ^ 15];
+    }
+    break;
+  }
+
+}
+
+void Leever_Draw(int k) {  // 86ce45
+  static const uint8 kLeever_Draw_Num[14] = {1, 1, 1, 3, 3, 3, 3, 3, 3, 1, 1, 1, 1, 1};
+  static const int8 kLeever_Draw_X[56] = {
+    2, 6, 6, 6, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 0, 8,
+    0, 8, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8,
+    0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0,
+  };
+  static const int8 kLeever_Draw_Y[56] = {
+    8,  8,  8, 8, 8,  8,  8, 8, 8,  8,  8, 8, 5,  5,  8, 8,
+    5,  5,  8, 8, 2,  2,  8, 8, 1,  1,  8, 8, 0,  0,  8, 8,
+    -1, -1,  8, 8, 8, -2, -2, 0, 8, -2, -2, 0, 8, -2, -2, 0,
+    8, -2, -2, 0, 8, -2, -2, 0,
+  };
+  static const uint8 kLeever_Draw_Char[56] = {
+    0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x38, 0x38, 0x38, 0x38,    8, 9, 0x28, 0x28,
+    8,    9, 0xd9, 0xd9,    8,    8, 0xd8, 0xd8,    8,    8, 0xda, 0xda,    6, 6, 0xd9, 0xd9,
+    0x26, 0x26, 0xd8, 0xd8, 0x6c,    6,    6,    0, 0x6c, 0x26, 0x26,    0, 0x6c, 6,    6,    0,
+    0x6c, 0x26, 0x26,    0, 0x6c,    8,    8,    0,
+  };
+  static const uint8 kLeever_Draw_Flags[56] = {
+    1, 0x41, 0x41, 0x41, 1, 0x41, 0x41, 0x41, 1, 0x41, 0x41, 0x41, 1, 1, 1, 0x41,
+    1,    1,    0, 0x40, 1,    1,    0, 0x40, 1,    1,    0, 0x40, 1, 1, 0, 0x40,
+    0,    1,    0, 0x40, 6, 0x41, 0x41,    0, 6, 0x41, 0x41,    0, 6, 1, 1,    0,
+    6,    1,    1,    0, 6,    1,    1,    0,
+  };
+  static const uint8 kLeever_Draw_Big[56] = {
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 2, 2, 0, 0, 2, 2, 0, 0, 2, 2, 0, 0,
+    2, 2, 0, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0,
+    2, 2, 2, 0, 2, 2, 2, 0,
+  };
+  PrepOamCoordsRet info;
+  if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
+    return;
+  OamEnt *oam = GetOamCurPtr();
+  int d = sprite_graphics[k];
+  for (int i = kLeever_Draw_Num[d]; i >= 0; i--, oam++) {
+    int j = d * 4 + i;
+    uint8 charnum = kLeever_Draw_Char[j];
+    uint8 f = info.flags;
+    if (charnum >= 0x60 || charnum == 0x28 || charnum == 0x38)
+      f &= 0xf0;
+    SetOamHelper0(oam, info.x + kLeever_Draw_X[j], info.y + kLeever_Draw_Y[j],
+                  charnum, kLeever_Draw_Flags[j] | f, kLeever_Draw_Big[j]);
+  }
+}
+
+void Sprite_D8_Heart(int k) {  // 86cec0
+  if (SpriteDraw_AbsorbableTransient(k, true))
+    return;
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  Sprite_CheckAbsorptionByPlayer(k);
+
+  // Avoid calling Sprite_HandleAbsorptionByPlayer twice, it's called
+  // also from within Sprite_HandleDraggingByAncilla
+  if (sprite_state[k] == 0 && (enhanced_features0 & kFeatures0_MiscBugFixes))
+    return;
+
+  if (Sprite_HandleDraggingByAncilla(k))
+    return;
+  Sprite_MoveXY(k);
+  Sprite_MoveZ(k);
+  if (sign8(sprite_z[k])) {
+    sprite_z[k] = 0;
+    sprite_ai_state[k]++;
+    sprite_graphics[k] = 0;
+  }
+  sprite_oam_flags[k] &= ~0x40;
+  if (!sign8(sprite_x_vel[k]))
+    sprite_oam_flags[k] |= 0x40;
+  switch (sprite_ai_state[k] >= 3 ? 3 : sprite_ai_state[k]) {
+  case 0:  // InitializeAscent
+    sprite_ai_state[k]++;
+    sprite_delay_main[k] = 18;
+    sprite_z_vel[k] = 20;
+    sprite_graphics[k] = 1;
+    sprite_D[k] = 0;
+    break;
+  case 1:  // BeginDescending
+    if (sprite_delay_main[k] != 0) {
+      sprite_z_vel[k]--;
+    } else {
+      sprite_ai_state[k]++;
+      sprite_z_vel[k] = 253;
+      sprite_x_vel[k] = 0;
+    }
+    break;
+  case 2:  // GlideGroundward
+    if (sprite_delay_main[k] == 0) {
+      int j = sprite_D[k] & 1;
+      sprite_x_vel[k] += kHeartRefill_AccelX[j];
+      if (sprite_x_vel[k] == (uint8)kHeartRefill_VelTarget[j]) {
+        sprite_D[k]++;
+        sprite_delay_main[k] = 8;
+      }
+    }
+    break;
+  case 3:  // Grounded
+    sprite_z_vel[k] = sprite_x_vel[k] = sprite_y_vel[k] = 0;
+    break;
+  }
+}
+
+void Sprite_E3_Fairy(int k) {  // 86cf94
+  sprite_ignore_projectile[k] = 1;
+  if (!sprite_ai_state[k]) {
+    if (!player_is_indoors)
+      sprite_obj_prio[k] = 48;
+    if (SpriteDraw_AbsorbableTransient(k, true))
+      return;
+  }
+  Fairy_CheckIfTouchable(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  switch (sprite_ai_state[k]) {
+  case 0: // normal
+    if (!sprite_delay_aux4[k]) {
+      if (Sprite_CheckDamageToLink(k)) {
+        Sprite_HandleAbsorptionByPlayer(k);
+      } else if (Sprite_CheckDamageFromLink(k) & kCheckDamageFromPlayer_Ne) {
+        sprite_ai_state[k]++;
+        Sprite_ShowMessageUnconditional(0xc9);
+        return;
+      }
+    }
+    // Avoid calling Sprite_HandleAbsorptionByPlayer twice, it's called
+    // also from within Sprite_HandleDraggingByAncilla
+    if (sprite_state[k] == 0 && (enhanced_features0 & kFeatures0_MiscBugFixes))
+      return;
+    if (Sprite_HandleDraggingByAncilla(k))
+      return;
+    Faerie_HandleMovement(k);
+    break;
+  case 1: // capture
+    if (choice_in_multiselect_box == 0) {
+      int j = Sprite_Find_EmptyBottle();
+      if (j >= 0) {
+        link_bottle_info[j] = 6;
+        Hud_RefreshIcon();
+        sprite_state[k] = 0;
+        return;
+      }
+      Sprite_ShowMessageUnconditional(0xca);
+    }
+    sprite_delay_aux4[k] = 48;
+    sprite_ai_state[k] = 0;
+    break;
+  }
+}
+
+void Fairy_CheckIfTouchable(int k) {  // 86d011
+  if (submodule_index == 2 && (dialogue_message_index == 0xc9 || dialogue_message_index == 0xca))
+    sprite_delay_aux4[k] = 40;
+}
+
+void Sprite_E4_SmallKey(int k) {  // 86d032
+  if (dung_savegame_state_bits & (kAbsorbBigKey[sprite_die_action[k]] << 8)) {
+    sprite_state[k] = 0;
+    return;
+  }
+  Sprite_DrawRippleIfInWater(k);
+  if (SpriteDraw_AbsorbableTransient(k, false))
+    return;
+  Sprite_Absorbable_Main(k);
+}
+
+void Sprite_D9_GreenRupee(int k) {  // 86d04a
+  Sprite_DrawRippleIfInWater(k);
+  if (SpriteDraw_AbsorbableTransient(k, true))
+    return;
+  Sprite_Absorbable_Main(k);
+}
+
+void Sprite_Absorbable_Main(int k) {  // 86d051
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  Sprite_MoveZ(k);
+  Sprite_MoveXY(k);
+  if (sprite_delay_aux3[k] == 0) {
+    Sprite_CheckTileCollision2(k);
+    Sprite_BounceOffWall(k);
+  }
+  sprite_z_vel[k] -= 2;
+  if (sign8(sprite_z[k])) {
+    sprite_z[k] = 0;
+    sprite_x_vel[k] = (int8)sprite_x_vel[k] >> 1;
+    sprite_y_vel[k] = (int8)sprite_y_vel[k] >> 1;
+    uint8 t = -sprite_z_vel[k];
+    t >>= 1;
+    if (t < 9) {
+      sprite_z_vel[k] = sprite_x_vel[k] = sprite_y_vel[k] = 0;
+    } else {
+      sprite_z_vel[k] = t;
+      if (sprite_I[k] == 8 || sprite_I[k] == 9) {
+        sprite_z_vel[k] = 0;
+        int j = Sprite_SpawnSmallSplash(k);
+        if (j >= 0 && sprite_flags3[k] & 0x20) {
+          // wtf carry propagation
+          Sprite_SetX(j, Sprite_GetX(j) - 4);
+          Sprite_SetY(j, Sprite_GetY(j) - 4);
+        }
+      } else {
+        if (sprite_type[k] >= 0xe4 && player_is_indoors)
+          SpriteSfx_QueueSfx2WithPan(k, 5);
+      }
+    }
+  }
+  if (Sprite_HandleDraggingByAncilla(k))
+    return;
+  Sprite_CheckAbsorptionByPlayer(k);
+}
+
+void Sprite_08_Octorok(int k) {  // 86d377
+  static const uint8 kOctorock_Tab0[20] = {
+    0, 2, 2, 2, 1, 1, 1, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 1, 1, 0,
+  };
+  static const uint8 kOctorock_Tab1[10] = {2, 2, 2, 2, 2, 2, 2, 2, 1, 0};
+  static const uint8 kOctorock_NextDir[4] = {2, 3, 1, 0};
+  static const uint8 kOctorock_Dir[4] = {3, 2, 0, 1};
+  static const int8 kOctorock_Xvel[4] = {24, -24, 0, 0};
+  static const int8 kOctorock_Yvel[4] = {0, 0, 24, -24};
+  static const uint8 kOctorock_OamFlags[4] = {0x40, 0, 0, 0};
+
+  int j = sprite_D[k];
+  if (sprite_delay_aux1[k])
+    sprite_D[k] = kOctorock_Dir[j];
+  sprite_oam_flags[k] = sprite_oam_flags[k] & ~0x40 | kOctorock_OamFlags[j] | (sprite_graphics[k] == 7 ? 0x40 : 0);
+  Octorock_Draw(k);
+  sprite_D[k] = j;
+
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  if (Sprite_ReturnIfRecoiling(k))
+    return;
+  Sprite_MoveXY(k);
+  Sprite_CheckDamageToAndFromLink(k);
+  if (!(sprite_ai_state[k] & 1)) {
+    sprite_graphics[k] = ++sprite_subtype2[k] >> 3 & 3 | (sprite_D[k] & 2) << 1;
+    if (!sprite_delay_main[k]) {
+      sprite_ai_state[k]++;
+      sprite_delay_main[k] = sprite_type[k] == 8 ? 60 : 160;
+    } else {
+      j = sprite_D[k];
+      sprite_x_vel[k] = kOctorock_Xvel[j];
+      sprite_y_vel[k] = kOctorock_Yvel[j];
+      if (Sprite_CheckTileCollision(k))
+        sprite_D[k] ^= 1;
+    }
+    return;
+  } else {
+    Sprite_ZeroVelocity_XY(k);
+    if (!sprite_delay_main[k]) {
+      sprite_ai_state[k]++;
+      sprite_delay_main[k] = (GetRandomNumber() & 0x3f) + 48;
+      sprite_D[k] = sprite_delay_main[k] & 3;
+    } else {
+      switch (sprite_type[k]) {
+      case 8:  // normal
+        j = sprite_delay_main[k];
+        if (j == 28)
+          Octorok_FireLoogie(k);
+        sprite_C[k] = kOctorock_Tab0[j >> 3];
+        break;
+      case 10:  // four shooter
+        j = sprite_delay_main[k];
+        if (j < 128) {
+          if (!(j & 15))
+            sprite_D[k] = kOctorock_NextDir[sprite_D[k]];
+          if ((j & 15) == 8)
+            Octorok_FireLoogie(k);
+        }
+        sprite_C[k] = kOctorock_Tab1[j >> 4];
+        break;
+      }
+    }
+  }
+}
+
+void Octorok_FireLoogie(int k) {  // 86d4cd
+  static const int8 kOctorock_Spit_X[4] = {12, -12, 0, 0};
+  static const int8 kOctorock_Spit_Y[4] = {4, 4, 12, -12};
+  static const int8 kOctorock_Spit_Xvel[4] = {44, -44, 0, 0};
+  static const int8 kOctorock_Spit_Yvel[4] = {0, 0, 44, -44};
+  SpriteSpawnInfo info;
+  SpriteSfx_QueueSfx2WithPan(k, 0x7);
+  int j = Sprite_SpawnDynamically(k, 0xc, &info);
+  if (j >= 0) {
+    int i = sprite_D[k];
+    Sprite_SetX(j, info.r0_x + kOctorock_Spit_X[i]);
+    Sprite_SetY(j, info.r2_y + kOctorock_Spit_Y[i]);
+    sprite_x_vel[j] = kOctorock_Spit_Xvel[i];
+    sprite_y_vel[j] = kOctorock_Spit_Yvel[i];
+  }
+}
+
+void Octorock_Draw(int k) {  // 86d54a
+  static const int8 kOctorock_Draw_X[9] = {8, 0, 4, 8, 0, 4, 9, -1, 4};
+  static const int8 kOctorock_Draw_Y[9] = {6, 6, 9, 6, 6, 9, 6, 6, 9};
+  static const uint8 kOctorock_Draw_Char[9] = {0xbb, 0xbb, 0xba, 0xab, 0xab, 0xaa, 0xa9, 0xa9, 0xb9};
+  static const uint8 kOctorock_Draw_Flags[9] = {0x65, 0x25, 0x25, 0x65, 0x25, 0x25, 0x65, 0x25, 0x25};
+  PrepOamCoordsRet info;
+  if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
+    return;
+  if (sprite_D[k] != 3) {
+    OamEnt *oam = GetOamCurPtr();
+    int j = sprite_C[k] * 3 + sprite_D[k];
+    SetOamHelper0(oam, info.x + kOctorock_Draw_X[j], info.y + kOctorock_Draw_Y[j],
+                  kOctorock_Draw_Char[j], kOctorock_Draw_Flags[j] | info.flags, 0);
+  }
+  oam_cur_ptr += 4;
+  oam_ext_cur_ptr++;
+  sprite_flags2[k]--;
+  Sprite_PrepAndDrawSingleLargeNoPrep(k, &info);
+  sprite_flags2[k]++;
+}
+
+void Sprite_0C_OctorokStone(int k) {  // 86d5b9
+  if (sprite_state[k] == 6) {
+    SpriteDraw_OctorokStoneCrumbling(k);
+    if (Sprite_ReturnIfPaused(k))
+      return;
+    if (sprite_delay_main[k] == 30)
+      SpriteSfx_QueueSfx2WithPan(k, 0x1f);
+  } else {
+    SpriteDraw_SingleLarge(k);
+    if (Sprite_ReturnIfInactive(k))
+      return;
+    Sprite_CheckDamageToLink(k);
+    Sprite_MoveXY(k);
+    if (!((k ^ frame_counter) & 3) && Sprite_CheckTileCollision(k))
+      Sprite_Func3(k);
+  }
+}
+
+void SpriteDraw_OctorokStoneCrumbling(int k) {  // 86d643
+  static const int8 kOctostone_Draw_X[16] = {0, 8, 0, 8, -8, 16, -8, 16, -12, 20, -12, 20, -14, 22, -14, 22};
+  static const int8 kOctostone_Draw_Y[16] = {0, 0, 8, 8, -8, -8, 16, 16, -12, -12, 20, 20, -14, -14, 22, 22};
+  static const uint8 kOctostone_Draw_Flags[16] = {0, 0x40, 0x80, 0xc0, 0, 0x40, 0x80, 0xc0, 0, 0x40, 0x80, 0xc0, 0, 0x40, 0x80, 0xc0};
+
+  PrepOamCoordsRet info;
+  if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
+    return;
+  OamEnt *oam = GetOamCurPtr();
+  int g = ((sprite_delay_main[k] >> 1 & 0xc) ^ 0xc);
+  for (int i = 3; i >= 0; i--, oam++) {
+    int j = g + i;
+    SetOamHelper0(oam, info.x + kOctostone_Draw_X[j], info.y + kOctostone_Draw_Y[j],
+                  0xbc, kOctostone_Draw_Flags[j] | 0x2d, 0);
+  }
+
+}
+
+void Sprite_0F_Octoballoon(int k) {  // 86d6aa
+  static const uint8 kSprite_Octoballoon_Z[8] = {16, 17, 18, 19, 20, 19, 18, 17};
+  sprite_z[k] = kSprite_Octoballoon_Z[sprite_subtype2[k] >> 3 & 7];
+  Octoballoon_Draw(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  if (!sprite_delay_main[k]) {
+    sprite_delay_main[k] = 3;
+    if (!Octoballoon_Find()) {
+      sprite_state[k] = 6;
+      sprite_hit_timer[k] = 0;
+      sprite_delay_main[k] = 15;
+      return;
+    }
+  }
+  if (Sprite_ReturnIfRecoiling(k))
+    return;
+  sprite_subtype2[k]++;
+  if (!((k ^ frame_counter) & 15)) {
+    ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLink(k, 4);
+    if (sprite_x_vel[k] - pt.x)
+      sprite_x_vel[k] += sign8(sprite_x_vel[k] - pt.x) ? 1 : -1;
+    if (sprite_y_vel[k] - pt.y)
+      sprite_y_vel[k] += sign8(sprite_y_vel[k] - pt.y) ? 1 : -1;
+  }
+  Sprite_MoveXY(k);
+  if (Sprite_CheckDamageToLink(k))
+    Octoballoon_RecoilLink(k);
+  Sprite_CheckDamageFromLink(k);
+  Sprite_CheckTileCollision2(k);
+  Sprite_BounceOffWall(k);
+}
+
+void Octoballoon_RecoilLink(int k) {  // 86d72b
+  if (!link_incapacitated_timer) {
+    link_incapacitated_timer = 4;
+    Sprite_ApplyRecoilToLink(k, 16);
+    Sprite_InvertSpeed_XY(k);
+  }
+}
+
+void Octoballoon_Draw(int k) {  // 86d784
+  static const int8 kOctoballoon_Draw_X[12] = {-4, 4, -4, 4, -8, 8, -8, 8, -4, 4, -4, 4};
+  static const int8 kOctoballoon_Draw_Y[12] = {-4, -4, 4, 4, -8, -8, 8, 8, -4, -4, 4, 4};
+  static const uint8 kOctoballoon_Draw_Char[12] = {0x8c, 0x8c, 0x9c, 0x9c, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86};
+  static const uint8 kOctoballoon_Draw_Flags[12] = {0, 0x40, 0, 0x40, 0, 0x40, 0x80, 0xc0, 0, 0x40, 0x80, 0xc0};
+  int d = 0;
+  if (sprite_state[k] == 6) {
+    if (sprite_delay_main[k] == 6 && !submodule_index)
+      Octoballoon_FormBabby(k);
+    d = (sprite_delay_main[k] >> 1 & 4) + 4;
+  }
+  PrepOamCoordsRet info;
+  if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
+    return;
+  OamEnt *oam = GetOamCurPtr();
+  for (int i = 3; i >= 0; i--, oam++) {
+    int j = d + i;
+    SetOamHelper0(oam, info.x + kOctoballoon_Draw_X[j], info.y + kOctoballoon_Draw_Y[j],
+                  kOctoballoon_Draw_Char[j], kOctoballoon_Draw_Flags[j] | info.flags, 2);
+  }
+  SpriteDraw_Shadow(k, &info);
+}
+
+void Octoballoon_FormBabby(int k) {  // 86d80e
+  static const int8 kOctoballoon_Spawn_Xv[6] = {16, 11, -11, -16, -11, 11};
+  static const int8 kOctoballoon_Spawn_Yv[6] = {0, 11, 11, 0, -11, -11};
+
+  SpriteSfx_QueueSfx2WithPan(k, 0xc);
+  for (int i = 5; i >= 0; i--) {
+    SpriteSpawnInfo info;
+    int j = Sprite_SpawnDynamically(k, 0x10, &info);
+    if (j >= 0) {
+      Sprite_SetSpawnedCoordinates(j, &info);
+      sprite_x_vel[j] = kOctoballoon_Spawn_Xv[i];
+      sprite_y_vel[j] = kOctoballoon_Spawn_Yv[i];
+      sprite_z_vel[j] = 48;
+      sprite_subtype2[j] = 255;
+    }
+  }
+}
+
+void Sprite_10_OctoballoonBaby(int k) {  // 86d853
+  if (!sprite_subtype2[k])
+    sprite_state[k] = 0;
+  if (sprite_subtype2[k] >= 64 || !(sprite_subtype2[k] & 1))
+    SpriteDraw_SingleSmall(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  sprite_subtype2[k]--;
+  if (Sprite_ReturnIfRecoiling(k))
+    return;
+  sprite_z_vel[k]--;
+  Sprite_MoveZ(k);
+  if (sign8(sprite_z[k])) {
+    sprite_z[k] = 0;
+    sprite_z_vel[k] = 16;
+  }
+  Sprite_MoveXY(k);
+  Sprite_CheckTileCollision2(k);
+  Sprite_BounceOffWall(k);
+  Sprite_CheckDamageToAndFromLink(k);
+}
+
+void Sprite_0D_Buzzblob(int k) {  // 86d89a
+  static const uint8 kBuzzBlob_Gfx[4] = {0, 1, 0, 2};
+  static const uint8 kBuzzBlob_ObjPrio[4] = {10, 2, 8, 2};
+  if (sprite_delay_aux1[k])
+    sprite_obj_prio[k] = sprite_obj_prio[k] & 0xf1 | kBuzzBlob_ObjPrio[sprite_delay_aux1[k] >> 1 & 3];
+  Sprite_Cukeman(k);
+  BuzzBlob_Draw(k);
+  sprite_graphics[k] = kBuzzBlob_Gfx[sprite_subtype2[k] >> 3 & 3] + (sprite_delay_aux1[k] ? 3 : 0);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  if (Sprite_ReturnIfRecoiling(k))
+    return;
+  sprite_subtype2[k]++;
+  if (!sprite_delay_main[k])
+    Buzzblob_SelectNewDirection(k);
+  if (!sprite_delay_aux1[k])
+    Sprite_MoveXY(k);
+  Sprite_CheckTileCollision2(k);
+  Sprite_BounceOffWall(k);
+  Sprite_CheckDamageToAndFromLink(k);
+}
+
+void Buzzblob_SelectNewDirection(int k) {  // 86d906
+  static const int8 kBuzzBlob_Xvel[8] = {3, 2, -2, -3, -2, 2, 0, 0};
+  static const int8 kBuzzBlob_Yvel[8] = {0, 2, 2, 0, -2, -2, 0, 0};
+  static const uint8 kBuzzBlob_Delay[8] = {48, 48, 48, 48, 48, 48, 64, 64};
+  int j = GetRandomNumber() & 7;
+  sprite_x_vel[k] = kBuzzBlob_Xvel[j];
+  sprite_y_vel[k] = kBuzzBlob_Yvel[j];
+  sprite_delay_main[k] = kBuzzBlob_Delay[j];
+}
+
+void BuzzBlob_Draw(int k) {  // 86d953
+  static const uint16 kBuzzBlob_DrawX[3] = {0, 8, 0};
+  static const int16 kBuzzBlob_DrawY[3] = {-8, -8, 0};
+  static const uint8 kBuzzBlob_DrawChar[18] = { 0xf0, 0xf0, 0xe1, 0, 0, 0xce, 0, 0, 0xce, 0xe3, 0xe3, 0xca, 0xe4, 0xe5, 0xcc, 0xe5, 0xe4, 0xcc };
+  static const uint8 kBuzzBlob_DrawFlags[18] = { 0, 0x40, 0, 0, 0, 0, 0, 0, 0x40, 0, 0x40, 0, 0, 0, 0, 0x40, 0x40, 0x40 };
+  static const uint8 kBuzzBlob_DrawExt[3] = {0, 0, 2};
+
+  PrepOamCoordsRet info;
+  if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
+    return;
+  OamEnt *oam = GetOamCurPtr();
+  int g = sprite_graphics[k];
+  for (int i = 2; i >= 0; i--, oam++) {
+    SetOamHelper0(oam, info.x + kBuzzBlob_DrawX[i], info.y + kBuzzBlob_DrawY[i],
+                  kBuzzBlob_DrawChar[g * 3 + i],
+                  kBuzzBlob_DrawFlags[g * 3 + i] | info.flags, kBuzzBlob_DrawExt[i]);
+    if (oam->charnum == 0)
+      oam->y = 240;
+  }
+  SpriteDraw_Shadow(k, &info);
+}
+
+void Sprite_02_StalfosHead(int k) {  // 86ddb7
+  static const uint8 kStalfosHead_OamFlags[4] = {0, 0, 0, 0x40};
+  static const uint8 kStalfosHead_Gfx[4] = {0, 1, 2, 1};
+
+  sprite_floor[k] = link_is_on_lower_level;
+  if (sprite_delay_aux1[k])
+    Oam_AllocateFromRegionC(8);
+  int j = sprite_subtype2[k] >> 3 & 3;
+  sprite_oam_flags[k] = sprite_oam_flags[k] & ~0x40 | kStalfosHead_OamFlags[j];
+  sprite_graphics[k] = kStalfosHead_Gfx[j];
+  sprite_obj_prio[k] = 0x30;
+  SpriteDraw_SingleLarge(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  if (Sprite_ReturnIfRecoiling(k))
+    return;
+  Sprite_CheckDamageToAndFromLink(k);
+  if (sprite_F[k])
+    Sprite_ZeroVelocity_XY(k);
+  Sprite_MoveXY(k);
+  sprite_subtype2[k]++;
+  ProjectSpeedRet pt;
+  if (sprite_delay_main[k]) {
+    if (sprite_delay_main[k] & 1)
+      return;
+    pt = Sprite_ProjectSpeedTowardsLink(k, 16);
+  } else {
+    if ((k ^ frame_counter) & 3)
+      return;
+    pt = Sprite_ProjectSpeedTowardsLink(k, 16);
+    pt.x = -pt.x;
+    pt.y = -pt.y;
+  }
+  if (sprite_x_vel[k] - pt.x != 0)
+    sprite_x_vel[k] += sign8(sprite_x_vel[k] - pt.x) ? 1 : -1;
+  if (sprite_y_vel[k] - pt.y != 0)
+    sprite_y_vel[k] += sign8(sprite_y_vel[k] - pt.y) ? 1 : -1;
+}
+
+bool Pipe_ValidateEntry() {  // 87f4f1
+  for (int k = 4; k >= 0; k--) {
+    if (ancilla_type[k] == 0x31) {
+      link_position_mode = 0;
+      link_cant_change_direction = 0;
+      ancilla_type[k] = 0;
+      break;
+    }
+  }
+  return ((link_state_bits & 0x80) | link_auxiliary_state) != 0;
+}
+
+void Ancilla_TerminateSparkleObjects() {  // 89adc7
+  for (int i = 4; i >= 0; i--) {
+    uint8 t = ancilla_type[i];
+    if (t == 0x2a || t == 0x2b || t == 0x30 || t == 0x31 || t == 0x18 || t == 0x19 || t == 0xc)
+      ancilla_type[i] = 0;
+  }
+}
+
+int Sprite_SpawnSuperficialBombBlast(int k) {  // 89ae40
+  SpriteSpawnInfo info;
+  int j = Sprite_SpawnDynamically(k, 0x4a, &info);
+  if (j >= 0) {
+    sprite_state[j] = 6;
+    sprite_delay_aux1[j] = 31;
+    sprite_C[j] = 3;
+    sprite_flags2[j] = 3;
+    sprite_oam_flags[j] = 4;
+    SpriteSfx_QueueSfx2WithPan(k, 0x15);
+    Sprite_SetSpawnedCoordinates(j, &info);
+  }
+  return j;
+}
+
+void Sprite_SpawnDummyDeathAnimation(int k) {  // 89ae7e
+  SpriteSpawnInfo info;
+  int j = Sprite_SpawnDynamically(k, 0xb, &info);
+  if (j >= 0) {
+    Sprite_SetSpawnedCoordinates(j, &info);
+    sprite_state[j] = 6;
+    sprite_delay_main[j] = 15;
+    SpriteSfx_QueueSfx2WithPan(k, 0x14);
+    sprite_floor[j] = 2;
+  }
+}
+
+void Sprite_MagicBat_SpawnLightning(int k) {  // 89aea8
+  static const int8 kSpawnMadderBolts_Xvel[4] = {-8, -4, 4, 8};
+  static const int8 kSpawnMadderBolts_St2[4] = {0, 0x11, 0x22, 0x33};
+  for (int i = 0; i < 4; i++) {
+    SpriteSpawnInfo info;
+    int j = Sprite_SpawnDynamically(k, 0x3a, &info);
+    if (j >= 0) {
+      SpriteSfx_QueueSfx3WithPan(k, 0x1);
+      Sprite_SetSpawnedCoordinates(j, &info);
+      Sprite_SetX(j, info.r0_x + 4);
+      Sprite_SetY(j, info.r2_y + 12 - sprite_z[k]);
+      sprite_z[j] = 0;
+      sprite_y_vel[j] = 24;
+      sprite_head_dir[j] = 24;
+      sprite_ignore_projectile[j] = 24;
+      sprite_flags2[j] = 0x80;
+      sprite_flags3[j] = 3;
+      sprite_oam_flags[j] = 3;
+      sprite_delay_main[j] = 32;
+      sprite_graphics[j] = 2;
+      int i = sprite_G[k];
+      sprite_x_vel[j] = kSpawnMadderBolts_Xvel[i];
+      sprite_subtype2[j] = kSpawnMadderBolts_St2[i];
+      sprite_floor[j] = 2;
+      sprite_G[k]++;
+    }
+  }
+}
+
+void Fireball_SpawnTrailGarnish(int k) {  // 89b020
+  if ((k ^ frame_counter) & 3)
+    return;
+  int j = GarnishAlloc();
+  garnish_type[j] = 8;
+  garnish_active = 8;
+  garnish_countdown[j] = 11;
+  garnish_x_lo[j] = cur_sprite_x;
+  garnish_x_hi[j] = cur_sprite_x >> 8;
+  garnish_y_lo[j] = cur_sprite_y + 16;
+  garnish_y_hi[j] = (cur_sprite_y + 16) >> 8;
+  garnish_sprite[j] = k;
+}
+
+void GarnishSpawn_PyramidDebris(int8 x, int8 y, int8 xvel, int8 yvel) {  // 89b1bd
+  int k = GarnishAllocForce();
+  sound_effect_2 = 3;
+  sound_effect_1 = 31;
+  sound_effect_ambient = 5;
+
+  garnish_type[k] = 19;
+  garnish_active = 19;
+  garnish_x_lo[k] = 232 + x;
+  garnish_y_lo[k] = 96 + y;
+  garnish_x_vel[k] = xvel;
+  garnish_y_vel[k] = yvel;
+  garnish_countdown[k] = (GetRandomNumber() & 31) + 48;
+}
+
+void Snitch_SpawnGuard(int k) {  // 89c02f
+  static const uint16 kCrazyVillageSoldier_X[3] = {0x120, 0x340, 0x2e0};
+  static const uint16 kCrazyVillageSoldier_Y[3] = {0x100, 0x3b0, 0x160};
+  SpriteSpawnInfo info;
+  int j = Sprite_SpawnDynamicallyEx(k, 0x45, &info, 0);
+  if (j < 0)
+    return;
+  int i = sprite_type[k] == 0x3d ? 0 :
+          sprite_type[k] == 0x35 ? 1 : 2;
+  Sprite_SetX(j, kCrazyVillageSoldier_X[i] + (sprcoll_x_base & 0xff00));
+  Sprite_SetY(j, kCrazyVillageSoldier_Y[i] + (sprcoll_y_base & 0xff00));
+  sprite_floor[j] = 0;
+  sprite_health[j] = 4;
+  sprite_defl_bits[j] = 0x80;
+  sprite_flags5[j] = 0x90;
+  sprite_oam_flags[j] = 0xb;
+}
+
+void Babusu_Draw(int k) {  // 8dbd20
+  static const DrawMultipleData kBabusu_Dmd[40] = {
+    { 0,  4, 0x4380, 0},
+    { 0,  4, 0x4380, 0},
+    { 0,  4, 0x43b6, 0},
+    { 0,  4, 0x43b6, 0},
+    { 0,  4, 0x43b7, 0},
+    { 8,  4, 0x0380, 0},
+    { 0,  4, 0x4380, 0},
+    { 8,  4, 0x03b6, 0},
+    { 8,  4, 0x03b7, 0},
+    { 8,  4, 0x03b7, 0},
+    { 8,  4, 0x0380, 0},
+    { 8,  4, 0x0380, 0},
+    { 4,  0, 0x8380, 0},
+    { 4,  0, 0x8380, 0},
+    { 4,  0, 0x83b6, 0},
+    { 4,  0, 0x83b6, 0},
+    { 4,  0, 0x83b7, 0},
+    { 4,  8, 0x0380, 0},
+    { 4,  0, 0x8380, 0},
+    { 4,  8, 0x03b6, 0},
+    { 4,  8, 0x03b7, 0},
+    { 4,  8, 0x03b7, 0},
+    { 4,  8, 0x0380, 0},
+    { 4,  8, 0x0380, 0},
+    { 0, -8, 0x0a4e, 2},
+    { 0,  0, 0x0a5e, 2},
+    { 0, -8, 0x4a4e, 2},
+    { 0,  0, 0x4a5e, 2},
+    { 8,  0, 0x0a6c, 2},
+    { 0,  0, 0x0a6b, 2},
+    { 8,  0, 0x8a6c, 2},
+    { 0,  0, 0x8a6b, 2},
+    { 0,  8, 0x8a4e, 2},
+    { 0,  0, 0x8a5e, 2},
+    { 0,  8, 0xca4e, 2},
+    { 0,  0, 0xca5e, 2},
+    {-8,  0, 0x4a6c, 2},
+    { 0,  0, 0x4a6b, 2},
+    {-8,  0, 0xca6c, 2},
+    { 0,  0, 0xca6b, 2},
+  };
+  if (sprite_graphics[k] != 0xff) {
+    Sprite_DrawMultiple(k, &kBabusu_Dmd[sprite_graphics[k] * 2], 2, NULL);
+  } else {
+    PrepOamCoordsRet info;
+    Sprite_PrepOamCoord(k, &info);
+  }
+}
+
+void Wizzrobe_Draw(int k) {  // 8dbe06
+  static const DrawMultipleData kWizzrobe_Dmd[24] = {
+    {0, -8, 0x00b2, 0},
+    {8, -8, 0x00b3, 0},
+    {0,  0, 0x0088, 2},
+    {0, -8, 0x00b2, 0},
+    {8, -8, 0x00b3, 0},
+    {0,  0, 0x0086, 2},
+    {0, -8, 0x00b2, 0},
+    {8, -8, 0x00b3, 0},
+    {0,  0, 0x008c, 2},
+    {0, -8, 0x00b2, 0},
+    {8, -8, 0x00b3, 0},
+    {0,  0, 0x008a, 2},
+    {0, -8, 0x00b2, 0},
+    {8, -8, 0x00b3, 0},
+    {0,  0, 0x408c, 2},
+    {0, -8, 0x00b2, 0},
+    {8, -8, 0x00b3, 0},
+    {0,  0, 0x408a, 2},
+    {0, -8, 0x00b2, 0},
+    {8, -8, 0x00b3, 0},
+    {0,  0, 0x00a4, 2},
+    {0, -8, 0x00b2, 0},
+    {8, -8, 0x00b3, 0},
+    {0,  0, 0x008e, 2},
+  };
+  Sprite_DrawMultiple(k, &kWizzrobe_Dmd[sprite_graphics[k] * 3], 3, NULL);
+}
+
+void Wizzbeam_Draw(int k) {  // 8dbe68
+  static const DrawMultipleData kWizzbeam_Dmd[8] = {
+    { 0, -4, 0x00c5, 0},
+    { 0,  4, 0x80c5, 0},
+    { 0, -4, 0x40c5, 0},
+    { 0,  4, 0xc0c5, 0},
+    {-4,  0, 0x40d2, 0},
+    { 4,  0, 0x00d2, 0},
+    {-4,  0, 0xc0d2, 0},
+    { 4,  0, 0x80d2, 0},
+  };
+  Sprite_DrawMultiple(k, &kWizzbeam_Dmd[sprite_D[k] * 2], 2, NULL);
+}
+
+void Freezor_Draw(int k) {  // 8dbfa6
+
+  static const DrawMultipleData kFreezor_Dmd0[28] = {
+    {-8,  0, 0x00a6, 2},
+    { 8,  0, 0x40a6, 2},
+    {-8,  0, 0x00a6, 2},
+    { 8,  0, 0x40a6, 2},
+    {-8,  0, 0x00a6, 2},
+    { 8,  0, 0x40a6, 2},
+    { 0, 11, 0x00ab, 0},
+    { 8, 11, 0x40ab, 0},
+    {-8,  0, 0x00ac, 2},
+    { 8,  0, 0x40a8, 2},
+    { 0, 11, 0x00ba, 0},
+    { 8, 11, 0x00bb, 0},
+    {-8,  0, 0x00a8, 2},
+    { 8,  0, 0x40ac, 2},
+    { 0, 11, 0x40bb, 0},
+    { 8, 11, 0x40ba, 0},
+    { 0,  2, 0x00ae, 0},
+    { 8,  2, 0x40ae, 0},
+    { 0, 10, 0x00be, 0},
+    { 8, 10, 0x40be, 0},
+    { 0,  4, 0x00af, 0},
+    { 8,  4, 0x40af, 0},
+    { 0, 12, 0x00bf, 0},
+    { 8, 12, 0x40bf, 0},
+    { 0,  8, 0x00aa, 0},
+    { 8,  8, 0x40aa, 0},
+    { 0,  8, 0x00aa, 0},
+    { 8,  8, 0x40aa, 0},
+  };
+  static const DrawMultipleData kFreezor_Dmd1[8] = {
+    { 0, 0, 0x00ae, 0},
+    { 8, 0, 0x40ae, 0},
+    { 0, 8, 0x00be, 0},
+    { 8, 8, 0x40be, 0},
+    {-2, 0, 0x00ae, 0},
+    {10, 0, 0x40ae, 0},
+    {-2, 8, 0x00be, 0},
+    {10, 8, 0x40be, 0},
+  };
+  if (sprite_graphics[k] != 7) {
+    Sprite_DrawMultiple(k, &kFreezor_Dmd0[sprite_graphics[k] * 4], 4, NULL);
+  } else {
+    Sprite_DrawMultiple(k, kFreezor_Dmd1, 8, NULL);
+  }
+}
+
+void Zazak_Draw(int k) {  // 8dc0a6
+  static const uint8 kZazak_Char[8] = {0x82, 0x82, 0x80, 0x84, 0x88, 0x88, 0x86, 0x84};
+  static const uint8 kZazak_Flags[8] = {0x40, 0, 0, 0, 0x40, 0, 0, 0};
+  static const DrawMultipleData kZazak_Dmd[24] = {
+    { 0, -8, 0x0008, 2},
+    {-4,  0, 0x00a0, 2},
+    { 4,  0, 0x00a1, 2},
+    { 0, -7, 0x0008, 2},
+    {-4,  1, 0x40a1, 2},
+    { 4,  1, 0x40a0, 2},
+    { 0, -8, 0x000e, 2},
+    {-4,  0, 0x00a3, 2},
+    { 4,  0, 0x00a4, 2},
+    { 0, -7, 0x000e, 2},
+    {-4,  1, 0x40a4, 2},
+    { 4,  1, 0x40a3, 2},
+    { 0, -9, 0x000c, 2},
+    { 0,  0, 0x00a6, 2},
+    { 0,  0, 0x00a6, 2},
+    { 0, -8, 0x000c, 2},
+    { 0,  0, 0x00a8, 2},
+    { 0,  0, 0x00a8, 2},
+    { 0, -9, 0x400c, 2},
+    { 0,  0, 0x40a6, 2},
+    { 0,  0, 0x40a6, 2},
+    { 0, -8, 0x400c, 2},
+    { 0,  0, 0x40a8, 2},
+    { 0,  0, 0x40a8, 2},
+  };
+  PrepOamCoordsRet info;
+  Sprite_DrawMultiple(k, &kZazak_Dmd[sprite_graphics[k] * 3], 3, &info);
+  if (sprite_pause[k])
+    return;
+  int i = sprite_head_dir[k] + (sprite_delay_aux1[k] == 0 ? 0 : 4);
+  OamEnt *oam = GetOamCurPtr();
+  oam->charnum = kZazak_Char[i];
+  oam->flags = (oam->flags & ~0x40) | kZazak_Flags[i];
+  SpriteDraw_Shadow(k, &info);
+}
+
+void Stalfos_Draw(int k) {  // 8dc21c
+  static const uint8 kStalfos_Char[4] = {2, 2, 0, 4};
+  static const uint8 kStalfos_Flags[4] = {0x70, 0x30, 0x30, 0x30};
+  static const DrawMultipleData kStalfos_Dmd[36] = {
+    { 0, -10, 0x0000, 2},
+    { 0,   0, 0x0006, 2},
+    { 0,   0, 0x0006, 2},
+    { 0,  -9, 0x0000, 2},
+    { 0,   1, 0x4006, 2},
+    { 0,   1, 0x4006, 2},
+    { 0, -10, 0x0004, 2},
+    { 0,   0, 0x0006, 2},
+    { 0,   0, 0x0006, 2},
+    { 0,  -9, 0x0004, 2},
+    { 0,   1, 0x4006, 2},
+    { 0,   1, 0x4006, 2},
+    { 0, -10, 0x0002, 2},
+    { 5,   5, 0x002e, 0},
+    { 0,   0, 0x0024, 2},
+    { 0, -10, 0x0002, 2},
+    { 0,   0, 0x000e, 2},
+    { 0,   0, 0x000e, 2},
+    { 0, -10, 0x4002, 2},
+    { 3,   5, 0x402e, 0},
+    { 0,   0, 0x4024, 2},
+    { 0, -10, 0x4002, 2},
+    { 0,   0, 0x400e, 2},
+    { 0,   0, 0x000e, 2},
+    { 2,  -8, 0x4002, 2},
+    { 0,   0, 0x4008, 2},
+    { 0,   0, 0x4008, 2},
+    {-2,  -8, 0x0002, 2},
+    { 0,   0, 0x0008, 2},
+    { 0,   0, 0x0008, 2},
+    { 0,  -6, 0x0000, 2},
+    { 0,   0, 0x000a, 2},
+    { 0,   0, 0x000a, 2},
+    { 0,   0, 0x000a, 2},
+    { 0,  -6, 0x0004, 2},
+    { 0,  -6, 0x0004, 2},
+  };
+  PrepOamCoordsRet info;
+  if (sprite_delay_aux2[k]) {
+    Sprite_PrepOamCoord(k, &info);
+    return;
+  }
+  Sprite_DrawMultiple(k, &kStalfos_Dmd[sprite_graphics[k] * 3], 3, &info);
+  if (sprite_graphics[k] < 8 && !sprite_pause[k]) {
+    OamEnt *oam = GetOamCurPtr();
+    int i = sprite_head_dir[k];
+    oam->charnum = kStalfos_Char[i];
+    oam->flags = (oam->flags & ~0x70) | kStalfos_Flags[i];
+  }
+  SpriteDraw_Shadow(k, &info);
+}
+
+bool Probe_CheckTileSolidity(int k) {  // 8dc26e
+  uint8 tiletype;
+  if (player_is_indoors) {
+    int t = (sprite_floor[k] >= 1) ? 0x1000 : 0;
+    t += (cur_sprite_x & 0x1f8) >> 3;
+    t += (cur_sprite_y & 0x1f8) << 3;
+    tiletype = dung_bg2_attr_table[t];
+  } else {
+    tiletype = Overworld_ReadTileAttribute(cur_sprite_x >> 3, cur_sprite_y);
+  }
+  sprite_tiletype = tiletype;
+  return kSprite_SimplifiedTileAttr[tiletype] >= 1;
+}
+
+void Sprite_HumanMulti_1(int k) {  // 8dc2d9
+  switch (sprite_subtype2[k]) {
+  case 0: Sprite_FluteDad(k); break;
+  case 1: Sprite_ThiefHideoutGuy(k); break;
+  case 2: Sprite_BlindsHutGuy(k); break;
+  }
+
+}
+
+void Sprite_BlindsHutGuy(int k) {  // 8dc2e6
+  BlindHideoutGuy_Draw(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  Sprite_BehaveAsBarrier(k);
+  Sprite_TrackBodyToHead(k);
+  sprite_head_dir[k] = 0;
+  int j = Sprite_ShowSolicitedMessage(k, 0x172);
+  if (j & 0x100)
+    sprite_D[k] = sprite_head_dir[k] = j;
+}
+
+void Sprite_ThiefHideoutGuy(int k) {  // 8dc308
+  if (!(frame_counter & 3)) {
+    sprite_graphics[k] = 2;
+    uint8 dir = Sprite_DirectionToFaceLink(k, NULL);
+    sprite_head_dir[k] = dir == 3 ? 2 : dir;
+  }
+  sprite_oam_flags[k] = 15;
+  Oam_AllocateDeferToPlayer(k);
+  Thief_Draw(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  Sprite_BehaveAsBarrier(k);
+  Sprite_ShowSolicitedMessage(k, 0x171);
+  sprite_graphics[k] = 2;
+}
+
+void Sprite_FluteDad(int k) {  // 8dc343
+  FluteBoyFather_Draw(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  Sprite_BehaveAsBarrier(k);
+  sprite_graphics[k] = (frame_counter < 48) ? 2 : (frame_counter >> 7) & 1;
+
+  if (sprite_ai_state[k]) {
+    Sprite_ShowSolicitedMessage(k, 0xa3);
+    sprite_graphics[k] = 2;
+  } else if (link_item_flute < 2) {
+    Sprite_ShowSolicitedMessage(k, 0xa1);
+  } else if (!(Sprite_ShowSolicitedMessage(k, 0xa4) & 0x100) &&
+             hud_cur_item == kHudItem_Flute && (joypad1H_last&0x40) && Sprite_CheckDamageToLink_same_layer(k)) {
+    Sprite_ShowMessageUnconditional(0xa2);
+    sprite_ai_state[k]++;
+    sprite_graphics[k] = 2;
+  }
+}
+
+void FluteBoyFather_Draw(int k) {  // 8dc3e1
+  static const DrawMultipleData kFluteBoyFather_Dmd[6] = {
+    {0, -7, 0x0086, 2},
+    {0,  0, 0x0088, 2},
+    {0, -6, 0x0086, 2},
+    {0,  0, 0x0088, 2},
+    {0, -8, 0x0084, 2},
+    {0,  0, 0x0088, 2},
+  };
+  PrepOamCoordsRet info;
+  Sprite_DrawMultiplePlayerDeferred(k, &kFluteBoyFather_Dmd[sprite_graphics[k] * 2], 2, &info);
+  SpriteDraw_Shadow(k, &info);
+}
+
+void BlindHideoutGuy_Draw(int k) {  // 8dc481
+  static const DrawMultipleData kBlindHideoutGuy_Dmd[16] = {
+    {0, -8, 0x000c, 2},
+    {0,  0, 0x00ca, 2},
+    {0, -8, 0x000c, 2},
+    {0,  0, 0x40ca, 2},
+    {0, -8, 0x000c, 2},
+    {0,  0, 0x00ca, 2},
+    {0, -8, 0x000c, 2},
+    {0,  0, 0x40ca, 2},
+    {0, -8, 0x000e, 2},
+    {0,  0, 0x00ca, 2},
+    {0, -8, 0x000e, 2},
+    {0,  0, 0x40ca, 2},
+    {0, -8, 0x400e, 2},
+    {0,  0, 0x00ca, 2},
+    {0, -8, 0x400e, 2},
+    {0,  0, 0x40ca, 2},
+  };
+  PrepOamCoordsRet info;
+  Sprite_DrawMultiplePlayerDeferred(k, &kBlindHideoutGuy_Dmd[sprite_graphics[k] * 2 + sprite_D[k] * 4], 2, &info);
+  SpriteDraw_Shadow(k, &info);
+}
+
+void Sprite_SweepingLady(int k) {  // 8dc4ad
+  SweepingLady_Draw(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  Sprite_ShowSolicitedMessage(k, 0xa5);
+  Sprite_BehaveAsBarrier(k);
+  sprite_graphics[k] = frame_counter >> 4 & 1;
+}
+
+void SweepingLady_Draw(int k) {  // 8dc4eb
+  static const DrawMultipleData kSweepingLadyDmd[4] = {
+    {0, -7, 0x008e, 2},
+    {0,  5, 0x008a, 2},
+    {0, -8, 0x008e, 2},
+    {0,  4, 0x008c, 2},
+  };
+  PrepOamCoordsRet info;
+  Sprite_DrawMultiplePlayerDeferred(k, &kSweepingLadyDmd[sprite_graphics[k] * 2], 2, &info);
+  SpriteDraw_Shadow(k, &info);
+}
+
+void Sprite_Lumberjacks(int k) {  // 8dc51b
+  static const uint16 kLumberJackMsg[4] = {0x12c, 0x12d, 0x12e, 0x12d};
+  Lumberjacks_Draw(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  if (Lumberjack_CheckProximity(k, 0)) {
+    Sprite_NullifyHookshotDrag();
+    link_speed_setting = 0;
+    Link_CancelDash();
+  }
+  if (!Sprite_CheckIfLinkIsBusy() && Lumberjack_CheckProximity(k, 1) && (filtered_joypad_L & 0x80)) {
+    int msg = (BYTE(link_x_coord) >= sprite_x_lo[k]) + (link_sword_type >= 2) * 2;
+    Sprite_ShowMessageUnconditional(kLumberJackMsg[msg]);
+  }
+  sprite_graphics[k] = frame_counter >> 5 & 1;
+}
+
+bool Lumberjack_CheckProximity(int k, int j) {  // 8dc58f
+  static const uint8 kLumberJacks_X[2] = {48, 52};
+  static const uint8 kLumberJacks_Y[2] = {19, 20};
+  static const uint8 kLumberJacks_W[2] = {98, 106};
+  static const uint8 kLumberJacks_H[2] = {37, 40};
+  return (uint16)(cur_sprite_x - link_x_coord + kLumberJacks_X[j]) < kLumberJacks_W[j] &&
+         (uint16)(cur_sprite_y - link_y_coord + kLumberJacks_Y[j]) < kLumberJacks_H[j];
+}
+
+void Lumberjacks_Draw(int k) {  // 8dc6ba
+  static const DrawMultipleData kLumberJacks_Dmd[33] = {
+    {-23,  5, 0x02be, 0},
+    {-15,  5, 0x02bf, 0},
+    { -7,  5, 0x02bf, 0},
+    {  1,  5, 0x02bf, 0},
+    {  9,  5, 0x02bf, 0},
+    { 17,  5, 0x02bf, 0},
+    { 25,  5, 0x42be, 0},
+    {-32, -8, 0x40a8, 2},
+    {-32,  4, 0x40a6, 2},
+    { 30, -8, 0x00a8, 2},
+    { 31,  4, 0x00a4, 2},
+    {-19,  5, 0x02be, 0},
+    {-11,  5, 0x02bf, 0},
+    { -3,  5, 0x02bf, 0},
+    {  5,  5, 0x02bf, 0},
+    { 13,  5, 0x02bf, 0},
+    { 21,  5, 0x02bf, 0},
+    { 29,  5, 0x42be, 0},
+    {-31, -8, 0x40a8, 2},
+    {-32,  4, 0x40a4, 2},
+    { 31, -8, 0x00a8, 2},
+    { 31,  4, 0x00a6, 2},
+    {-19,  5, 0x02be, 0},
+    {-11,  5, 0x02bf, 0},
+    { -3,  5, 0x02bf, 0},
+    {  5,  5, 0x02bf, 0},
+    { 13,  5, 0x02bf, 0},
+    { 21,  5, 0x02bf, 0},
+    { 29,  5, 0x42be, 0},
+    {-32, -8, 0x400e, 2},
+    {-32,  4, 0x40a4, 2},
+    { 32, -8, 0x000e, 2},
+    { 31,  4, 0x00a6, 2},
+  };
+  Sprite_DrawMultiple(k, &kLumberJacks_Dmd[sprite_graphics[k] * 11], 11, NULL);
+}
+
+void Sprite_FortuneTeller(int k) {  // 8dc762
+  switch (sprite_subtype2[k]) {
+  case 0: // fortuneteller main
+    FortuneTeller_Draw(k);
+    if (Sprite_ReturnIfInactive(k))
+      return;
+    FortuneTeller_LightOrDarkWorld(k, savegame_is_darkworld >> 6 & 1);
+    break;
+  case 1: // dwarf solidity
+    if (Sprite_ReturnIfInactive(k))
+      return;
+    if (Sprite_CheckDamageToLink_same_layer(k)) {
+      Sprite_NullifyHookshotDrag();
+      link_speed_setting = 0;
+      Link_CancelDash();
+    }
+    break;
+  }
+}
+
+void FortuneTeller_PerformPseudoScience(int k) {  // 8dc849
+  sprite_graphics[k] = 0;
+  sprite_ai_state[k]++;
+
+  static const uint8 kFortuneTeller_Readings[16] = {0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd};
+
+  uint8 slots[2] = { 0, 0 };
+  int n = 0;
+#define ADD_MSG(q) { slots[n++]=(q); if (n==2) goto done; }
+
+  if (savegame_map_icons_indicator < 3)
+    goto done;
+  if (!link_item_book_of_mudora) ADD_MSG(2);
+  if (!(link_which_pendants & 2)) ADD_MSG(1);
+  if (link_item_mushroom < 2) ADD_MSG(3);
+  if (!link_item_flippers) ADD_MSG(4);
+  if (!link_item_moon_pearl) ADD_MSG(5);
+  if (sram_progress_indicator < 3) ADD_MSG(6);
+  if (!link_magic_consumption) ADD_MSG(7);
+  if (!link_item_bombos_medallion) ADD_MSG(8);
+  if (!(sram_progress_indicator_3 & 0x10)) ADD_MSG(9);
+  if (!(sram_progress_indicator_3 & 0x20)) ADD_MSG(10);
+  if (!link_item_cape) ADD_MSG(11);
+  if (!(save_ow_event_info[0x5b] & 2)) ADD_MSG(12);
+  if (link_sword_type < 4) ADD_MSG(13);
+  ADD_MSG(14);
+  ADD_MSG(15);
+  int j;
+done:
+  j = ((sram_progress_flags ^= 0x40) & 0x40) != 0;
+  Sprite_ShowMessageUnconditional(kFortuneTeller_Readings[slots[j]]);
+}
+
+void FortuneTeller_Draw(int k) {  // 8dcb01
+  static const DrawMultipleData kFortuneTeller_Dmd[12] = {
+    { 0, -48, 0x000c, 2},
+    { 0, -32, 0x002c, 0},
+    { 8, -32, 0x402c, 0},
+    { 0, -48, 0x000a, 2},
+    { 0, -32, 0x002a, 0},
+    { 8, -32, 0x402a, 0},
+    {-4, -40, 0x0066, 2},
+    { 4, -40, 0x4066, 2},
+    {-4, -40, 0x0066, 2},
+    {-4, -40, 0x0068, 2},
+    { 4, -40, 0x4068, 2},
+    {-4, -40, 0x0068, 2},
+  };
+  int j = (savegame_is_darkworld >> 6 & 1) * 2 + sprite_graphics[k];
+  Sprite_DrawMultiple(k, &kFortuneTeller_Dmd[j * 3], 3, NULL);
+}
+
+void Smithy_SpawnDumbBarrierSprite(int k) {  // 8dcb2a
+  SpriteSpawnInfo info;
+  int j = Sprite_SpawnDynamically(k, 0x31, &info);
+  if (j < 0)
+    return;
+  Sprite_SetX(j, info.r0_x);
+  Sprite_SetY(j, info.r2_y);
+  sprite_subtype2[j] = 1;
+  sprite_flags4[j] = 0;
+  sprite_ignore_projectile[j] = 1;
+}
+
+void Sprite_MazeGameLady(int k) {  // 8dcb5c
+  Lady_Draw(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  Sprite_TrackBodyToHead(k);
+  sprite_head_dir[k] = Sprite_DirectionToFaceLink(k, NULL) ^ 3;
+  switch (sprite_ai_state[k]) {
+  case 0:  // startup
+    if (sprite_x_lo[k] < BYTE(link_x_coord)) {
+      int j = Sprite_ShowMessageOnContact(k, 0xcc);
+      if (j & 0x100) {
+        sprite_D[k] = sprite_head_dir[k] = (uint8)j;
+        sprite_ai_state[k] = 1;
+        word_7FFE00 = 0;
+        word_7FFE02 = 0;
+        sprite_A[k] = 0;
+        flag_overworld_area_did_change = 0;
+      }
+    } else {
+      Sprite_ShowMessageOnContact(k, 0xd0);
+    }
+    break;
+  case 1:  // sound
+    SpriteSfx_QueueSfx3WithPan(k, 0x7);
+    sprite_ai_state[k] = 2;
+    break;
+  case 2:  // accumulate time
+    if (++sprite_A[k] == 63) {
+      sprite_A[k] = 0;
+      word_7FFE00 += 1;
+      if (word_7FFE00 == 0)
+        word_7FFE02++;
+    }
+    break;
+  }
+}
+
+void Sprite_MazeGameGuy(int k) {  // 8dcbf2
+  int j;
+  MazeGameGuy_Draw(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  Sprite_TrackBodyToHead(k);
+  sprite_head_dir[k] = 0;
+  Sprite_BehaveAsBarrier(k);
+  sprite_graphics[k] = frame_counter >> 3 & 1;
+  if (flag_overworld_area_did_change) {
+    Sprite_ShowMessageOnContact(k, 0xd0);
+    return;
+  }
+  switch (sprite_ai_state[k]) {
+  case 0: {  // parse time
+    word_7FFE04 = word_7FFE00;
+    word_7FFE06 = word_7FFE02;
+    int t = word_7FFE04 % 6000;
+    int a = t / 600;
+    t %= 600;
+    int b = t / 60;
+    t %= 60;
+    int c = t / 10;
+    t %= 10;
+    dialogue_number[0] = t | c << 4;
+    dialogue_number[1] = b | a << 4;
+    t = Sprite_ShowMessageOnContact(k, 0xcb);
+    if (t & 0x100) {
+      sprite_D[k] = sprite_head_dir[k] = (uint8)t;
+      sprite_ai_state[k] = 1;
+    }
+    break;
+  }
+  case 1:  // check qualify
+    if (save_ow_event_info[BYTE(overworld_screen_index)] & 0x40) {
+      Sprite_ShowMessageUnconditional(0xcf);
+      sprite_ai_state[k] = 4;
+    } else if (word_7FFE04 < 16) {
+      Sprite_ShowMessageUnconditional(0xcd);
+      sprite_D[k] = sprite_head_dir[k] = (uint8)link_player_handler_state;  // wtf
+      sprite_ai_state[k] = 3;
+    } else {
+      Sprite_ShowMessageUnconditional(0xce);
+      sprite_D[k] = sprite_head_dir[k] = (uint8)link_player_handler_state;  // wtf
+      sprite_ai_state[k] = 2;
+    }
+    break;
+  case 2:  // sorry
+    j = Sprite_ShowMessageOnContact(k, 0xce);
+    if (j & 0x100)
+      sprite_D[k] = sprite_head_dir[k] = (uint8)j;
+    break;
+  case 3:  // can have it
+    j = Sprite_ShowSolicitedMessage(k, 0xcd);
+    if (j & 0x100)
+      sprite_D[k] = sprite_head_dir[k] = (uint8)j;
+    break;
+  case 4:  // nothing more
+    j = Sprite_ShowSolicitedMessage(k, 0xcf);
+    if (j & 0x100)
+      sprite_D[k] = sprite_head_dir[k] = (uint8)j;
+    break;
+  }
+}
+
+void MazeGameGuy_Draw(int k) {  // 8dcda7
+  static const DrawMultipleData kMazeGameGuy_Dmd[16] = {
+    {0, -10, 0x0000, 2},
+    {0,   0, 0x0020, 2},
+    {0, -10, 0x0000, 2},
+    {0,   0, 0x0020, 2},
+    {0, -10, 0x0000, 2},
+    {0,   0, 0x0020, 2},
+    {0, -10, 0x0000, 2},
+    {0,   0, 0x0020, 2},
+    {0, -10, 0x4002, 2},
+    {0,   0, 0x0020, 2},
+    {0, -10, 0x4002, 2},
+    {0,   0, 0x0020, 2},
+    {0, -10, 0x0002, 2},
+    {0,   0, 0x0020, 2},
+    {0, -10, 0x0002, 2},
+    {0,   0, 0x0020, 2},
+  };
+  PrepOamCoordsRet info;
+  Sprite_DrawMultiplePlayerDeferred(k, &kMazeGameGuy_Dmd[sprite_graphics[k] * 2 + sprite_D[k] * 4], 2, &info);
+  SpriteDraw_Shadow(k, &info);
+}
+
+void CrystalMaiden_Draw(int k) {  // 8dce5f
+  int j = sprite_D[k] * 2 + sprite_graphics[k];
+  BYTE(dma_var6) = kCrystalMaiden_Dma[j * 2 + 0];
+  BYTE(dma_var7) = kCrystalMaiden_Dma[j * 2 + 1];
+  Sprite_DrawMultiplePlayerDeferred(k, kCrystalMaiden_SpriteData + j * 2, 2, NULL);
+}
+
+void Priest_Draw(int k) {  // 8dcf31
+  int j = sprite_D[k] * 2 + sprite_graphics[k];
+  PrepOamCoordsRet info;
+  Sprite_DrawMultiplePlayerDeferred(k, kPriest_Dmd + j * 2, 2, &info);
+  SpriteDraw_Shadow(k, &info);
+}
+
+uint8 FluteBoy_Draw(int k) {  // 8dcfd9
+  static const DrawMultipleData kFluteBoy_Dmd[16] = {
+    {-1,  -1, 0x0abe, 0},
+    { 0,   0, 0x0aaa, 2},
+    { 0, -10, 0x0aa8, 2},
+    { 0,   0, 0x0aaa, 2},
+    {-1,  -1, 0x0abe, 0},
+    { 0,   8, 0x0abf, 0},
+    { 0, -10, 0x0aa8, 2},
+    { 0,   0, 0x0aaa, 2},
+    {-1,  -1, 0x0abe, 0},
+    { 0,   0, 0x0aaa, 2},
+    { 0, -10, 0x0aa8, 2},
+    { 0,   0, 0x0aaa, 2},
+    {-1,  -1, 0x0abe, 0},
+    { 0,   8, 0x0abf, 0},
+    { 0, -10, 0x0aa8, 2},
+    { 0,   0, 0x0aaa, 2},
+  };
+  Oam_AllocateFromRegionB(0x10);
+  PrepOamCoordsRet info;
+  Sprite_DrawMultiple(k, &kFluteBoy_Dmd[sprite_D[k] * 8 + sprite_graphics[k] * 4], 4, &info);
+  return (info.x | info.y) >> 8;
+}
+
+void FluteAardvark_Draw(int k) {  // 8dd040
+  static const DrawMultipleData kFluteAardvark_Dmd[8] = {
+    {0, -16, 0x06e6, 2},
+    {0,  -8, 0x06c8, 2},
+    {0, -16, 0x06e6, 2},
+    {0,  -8, 0x06ca, 2},
+    {0, -16, 0x06e8, 2},
+    {0,  -8, 0x06ca, 2},
+    {0, -16, 0x00cc, 2},
+    {0,  -8, 0x00dc, 2},
+  };
+  Sprite_DrawMultiplePlayerDeferred(k, &kFluteAardvark_Dmd[sprite_graphics[k] * 2], 2, NULL);
+}
+
+void DustCloud_Draw(int k) {  // 8dd120
+  static const DrawMultipleData kDustCloud_Dmd[24] = {
+    { 0, -3, 0x008b, 0},
+    { 3,  0, 0x009b, 0},
+    {-3,  0, 0xc08b, 0},
+    { 0,  3, 0xc09b, 0},
+    { 0, -5, 0x008a, 2},
+    { 5,  0, 0x008a, 2},
+    {-5,  0, 0x008a, 2},
+    { 0,  5, 0x008a, 2},
+    { 0, -7, 0x0086, 2},
+    { 7,  0, 0x0086, 2},
+    {-7,  0, 0x0086, 2},
+    { 0,  7, 0x0086, 2},
+    { 0, -9, 0x8086, 2},
+    { 9,  0, 0x8086, 2},
+    {-9,  0, 0x8086, 2},
+    { 0,  9, 0x8086, 2},
+    { 0, -9, 0xc086, 2},
+    { 9,  0, 0xc086, 2},
+    {-9,  0, 0xc086, 2},
+    { 0,  9, 0xc086, 2},
+    { 0, -7, 0x4086, 2},
+    { 7,  0, 0x4086, 2},
+    {-7,  0, 0x4086, 2},
+    { 0,  7, 0x4086, 2},
+  };
+  sprite_oam_flags[k] = 0x14;
+  Sprite_DrawMultiple(k, &kDustCloud_Dmd[sprite_graphics[k] * 4], 4, NULL);
+}
+
+void MedallionTablet_Draw(int k) {  // 8dd1e2
+  static const DrawMultipleData kMedallionTablet_Dmd[20] = {
+    {-8, -16, 0x008c, 2},
+    { 8, -16, 0x408c, 2},
+    {-8,   0, 0x00ac, 2},
+    { 8,   0, 0x40ac, 2},
+    {-8, -13, 0x008a, 2},
+    { 8, -13, 0x408a, 2},
+    {-8,   0, 0x00ac, 2},
+    { 8,   0, 0x40ac, 2},
+    {-8,  -8, 0x008a, 2},
+    { 8,  -8, 0x408a, 2},
+    {-8,   0, 0x00ac, 2},
+    { 8,   0, 0x40ac, 2},
+    {-8,  -4, 0x008a, 2},
+    { 8,  -4, 0x408a, 2},
+    {-8,   0, 0x00aa, 2},
+    { 8,   0, 0x40aa, 2},
+    {-8,   0, 0x00aa, 2},
+    { 8,   0, 0x40aa, 2},
+    {-8,   0, 0x00aa, 2},
+    { 8,   0, 0x40aa, 2},
+  };
+  Sprite_DrawMultiplePlayerDeferred(k, &kMedallionTablet_Dmd[sprite_graphics[k] * 4], 4, NULL);
+}
+
+void Uncle_Draw(int k) {  // 8dd391
+  static const DrawMultipleData kUncleDraw_Table[48] = {
+    {  0, -10, 0x0e00, 2},
+    {  0,   0, 0x0c06, 2},
+    {  0, -10, 0x0e00, 2},
+    {  0,   0, 0x0c06, 2},
+    {  0, -10, 0x0e00, 2},
+    {  0,   0, 0x0c06, 2},
+    {  0, -10, 0x0e02, 2},
+    {  0,   0, 0x0c06, 2},
+    {  0, -10, 0x0e02, 2},
+    {  0,   0, 0x0c06, 2},
+    {  0, -10, 0x0e02, 2},
+    {  0,   0, 0x0c06, 2},
+    { -7,   2, 0x0d07, 2},
+    { -7,   2, 0x0d07, 2},
+    { 10,  12, 0x8d05, 0},
+    { 10,   4, 0x8d15, 0},
+    {  0, -10, 0x0e00, 2},
+    {  0,   0, 0x0c04, 2},
+    { -7,   1, 0x0d07, 2},
+    { -7,   1, 0x0d07, 2},
+    { 10,  13, 0x8d05, 0},
+    { 10,   5, 0x8d15, 0},
+    {  0,  -9, 0x0e00, 2},
+    {  0,   1, 0x4c04, 2},
+    { -7,   8, 0x8d05, 0},
+    {  1,   8, 0x8d06, 0},
+    {  0, -10, 0x0e02, 2},
+    { -6,  -1, 0x4d07, 2},
+    {  0,   0, 0x0c23, 2},
+    {  0,   0, 0x0c23, 2},
+    { -9,   7, 0x8d05, 0},
+    { -1,   7, 0x8d06, 0},
+    {  0,  -9, 0x0e02, 2},
+    { -6,   0, 0x4d07, 2},
+    {  0,   1, 0x0c25, 2},
+    {  0,   1, 0x0c25, 2},
+    {-10, -17, 0x0d07, 2},
+    { 15, -12, 0x8d15, 0},
+    { 15,  -4, 0x8d05, 0},
+    {  0, -28, 0x0e08, 2},
+    { -8, -19, 0x0c20, 2},
+    {  8, -19, 0x4c20, 2},
+    {  0, -28, 0x0e08, 2},
+    {  0, -28, 0x0e08, 2},
+    { -8, -19, 0x0c20, 2},
+    {  8, -19, 0x4c20, 2},
+    { -8, -19, 0x0c20, 2},
+    {  8, -19, 0x4c20, 2},
+  };
+  static const uint8 kUncleDraw_Dma3[8] = { 8, 8, 0, 0, 6, 6, 0, 0 };
+  static const uint8 kUncleDraw_Dma4[8] = { 0, 0, 0, 0, 4, 4, 0, 0x8b }; // wtf
+
+  Oam_AllocateFromRegionB(0x18);
+  const DrawMultipleData *src = &kUncleDraw_Table[sprite_D[k] * 12 + sprite_graphics[k] * 6];
+
+  int j = sprite_D[k] * 2 + sprite_graphics[k];
+  link_dma_var3 = kUncleDraw_Dma3[j];
+  link_dma_var4 = kUncleDraw_Dma4[j];
+  PrepOamCoordsRet info;
+  Sprite_DrawMultiple(k, src, 6, &info);
+
+  if (sprite_D[k] != 0 && sprite_D[k] != 3)
+    SpriteDraw_Shadow(k, &info);
+}
+
+void BugNetKid_Draw(int k) {  // 8dd47b
+  static const DrawMultipleData kBugNetKid_Dmd[18] = {
+    { 4,  0, 0x0027, 0},
+    { 0, -5, 0x000e, 2},
+    {-8,  6, 0x040a, 2},
+    { 8,  6, 0x440a, 2},
+    {-8, 14, 0x840a, 2},
+    { 8, 14, 0xc40a, 2},
+    { 0, -5, 0x000e, 2},
+    { 0, -5, 0x000e, 2},
+    {-8,  6, 0x040a, 2},
+    { 8,  6, 0x440a, 2},
+    {-8, 14, 0x840a, 2},
+    { 8, 14, 0xc40a, 2},
+    { 0, -5, 0x002e, 2},
+    { 0, -5, 0x002e, 2},
+    {-8,  7, 0x040a, 2},
+    { 8,  7, 0x440a, 2},
+    {-8, 14, 0x840a, 2},
+    { 8, 14, 0xc40a, 2},
+  };
+  Sprite_DrawMultiplePlayerDeferred(k, &kBugNetKid_Dmd[sprite_graphics[k] * 6], 6, NULL);
+}
+
+void Bomber_Draw(int k) {  // 8dd56c
+  static const DrawMultipleData kBomber_Dmd[22] = {
+    { 0, 0, 0x40c6, 2},
+    { 0, 0, 0x40c6, 2},
+    { 0, 0, 0x40c4, 2},
+    { 0, 0, 0x40c4, 2},
+    { 0, 0, 0x00c6, 2},
+    { 0, 0, 0x00c6, 2},
+    { 0, 0, 0x00c4, 2},
+    { 0, 0, 0x00c4, 2},
+    {-8, 0, 0x00c0, 2},
+    { 8, 0, 0x40c0, 2},
+    {-8, 0, 0x00c2, 2},
+    { 8, 0, 0x40c2, 2},
+    {-8, 0, 0x00e0, 2},
+    { 8, 0, 0x40e0, 2},
+    {-8, 0, 0x00e2, 2},
+    { 8, 0, 0x40e2, 2},
+    {-8, 0, 0x00e4, 2},
+    { 8, 0, 0x40e4, 2},
+    { 0, 0, 0x40e6, 2},
+    { 0, 0, 0x40e6, 2},
+    { 0, 0, 0x00e6, 2},
+    { 0, 0, 0x00e6, 2},
+  };
+  PrepOamCoordsRet info;
+  Sprite_DrawMultiple(k, &kBomber_Dmd[sprite_graphics[k] * 2], 2, &info);
+  SpriteDraw_Shadow(k, &info);
+}
+
+void SpriteDraw_ZirroBomb(int k) {  // 8dd606
+  static const DrawMultipleData kBomberPellet_Dmd[15] = {
+    {-11,   0, 0x019b, 0},
+    {  0,  -8, 0xc19b, 0},
+    {  6,   6, 0x419b, 0},
+    {-15,  -6, 0x018a, 2},
+    { -4, -14, 0x018a, 2},
+    {  2,   0, 0x018a, 2},
+    {-15,  -6, 0x0186, 2},
+    { -4, -14, 0x0186, 2},
+    {  2,   0, 0x0186, 2},
+    { -4,  -4, 0x0186, 2},
+    { -4,  -4, 0x0186, 2},
+    { -4,  -4, 0x0186, 2},
+    { -4,  -4, 0x01aa, 2},
+    { -4,  -4, 0x01aa, 2},
+    { -4,  -4, 0x01aa, 2},
+  };
+  if (!sprite_delay_main[k])
+    sprite_state[k] = 0;
+  Sprite_DrawMultiple(k, &kBomberPellet_Dmd[(sprite_delay_main[k] >> 2) * 3], 3, NULL);
+}
+
+void PlayerBee_HoneInOnTarget(int j, int k) {  // 8dd631
+  if (sprite_type[j] != 0x88 && (sprite_flags[j] & 2))
+    return;
+  uint16 x = Sprite_GetX(j);
+  uint16 y = Sprite_GetY(j);
+  if ((uint16)(cur_sprite_x - x + 16) >= 24 ||
+      (uint16)(cur_sprite_y - y - 8) >= 24)
+    return;
+  if (sprite_type[j] == 0x75) {
+    sprite_E[j] = k + 1;
+    return;
+  }
+  Ancilla_CheckDamageToSprite_preset(j, 1);
+  sprite_F[j] = 15;
+  sprite_x_recoil[j] = sprite_x_vel[k] << 1;
+  sprite_y_recoil[j] = sprite_y_vel[k] << 1;
+  sprite_B[k]++;
+}
+
+void Pikit_Draw(int k) {  // 8dd6e6
+  static const DrawMultipleData kPikit_Dmd[8] = {
+    { 0, 0, 0x00c8, 2},
+    { 0, 0, 0x00c8, 2},
+    { 0, 0, 0x00ca, 2},
+    { 0, 0, 0x00ca, 2},
+    {-8, 0, 0x00cc, 2},
+    { 8, 0, 0x40cc, 2},
+    {-8, 0, 0x00ce, 2},
+    { 8, 0, 0x40ce, 2},
+  };
+  PrepOamCoordsRet info;
+  if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
+    return;
+  SpriteDraw_Pikit_Tongue(k, &info);
+  OamEnt *oam = GetOamCurPtr();
+  tmp_counter = oam->x;
+  byte_7E0FB6 = oam->y;
+  oam_cur_ptr += 24;
+  oam_ext_cur_ptr += 6;
+  Sprite_DrawMultiple(k, &kPikit_Dmd[sprite_graphics[k] * 2], 2, &info);
+  uint8 bak = sprite_flags2[k];
+  sprite_flags2[k] -= 6;
+  SpriteDraw_Shadow(k, &info);
+  sprite_flags2[k] = bak;
+  SpriteDraw_Pikit_Loot(k, &info);
+}
+
+void SpriteDraw_Pikit_Tongue(int k, PrepOamCoordsRet *info) {  // 8dd74a
+  static const uint8 kPikit_TongueMult[4] = {0x33, 0x66, 0x99, 0xcc};
+  static const uint8 kPikit_Draw_Char[8] = {0xee, 0xfd, 0xed, 0xfd, 0xee, 0xfd, 0xed, 0xfd};
+  static const uint8 kPikit_Draw_Flags[8] = {0, 0, 0, 0x40, 0x40, 0xc0, 0x80, 0x80};
+  if (sprite_ai_state[k] != 2 || sprite_pause[k])
+    return;
+  OamEnt *oam = GetOamCurPtr();
+  int x = info->x + 4, y = info->y + 3;
+  oam[5].x = x;
+  oam[5].y = y;
+  oam[0].x = x + sprite_A[k];
+  oam[0].y = y + sprite_B[k];
+  oam[0].charnum = oam[5].charnum = 0xfe;
+  oam[0].flags = oam[5].flags = info->flags;
+  oam++;
+  int g = sprite_D[k];
+  for (int i = 3; i >= 0; i--, oam++) {
+    oam->x = x + (int8)sprite_A[k] * kPikit_TongueMult[i] / 256;
+    oam->y = y + (int8)sprite_B[k] * kPikit_TongueMult[i] / 256;
+    oam->charnum = kPikit_Draw_Char[g];
+    oam->flags = kPikit_Draw_Flags[g] | info->flags;
+  }
+  Sprite_CorrectOamEntries(k, 5, 0);
+}
+
+void SpriteDraw_Pikit_Loot(int k, PrepOamCoordsRet *info) {  // 8dd858
+  static const int8 kPikit_DrawGrabbedItem_X[20] = {
+    -4, 4, -4, 4, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, -4, 4, -4, 4,
+  };
+  static const int8 kPikit_DrawGrabbedItem_Y[20] = {
+    -4, -4, 4, 4, -4, -4, 4, 4, -4, -4, 4, 4, -4, -4, 4, 4, -4, -4, 4, 4,
+  };
+  static const uint8 kPikit_DrawGrabbedItem_Char[20] = {
+    0x6e, 0x6f, 0x7e, 0x7f, 0x63, 0x7c, 0x73, 0x7c, 0xb, 0x7c, 0x1b, 0x7c, 0xec, 0xf9, 0xfc, 0xf9,
+    0xea, 0xeb, 0xfa, 0xfb,
+  };
+  static const uint8 kPikit_DrawGrabbedItem_Flags[5] = {0x24, 0x24, 0x28, 0x29, 0x2f};
+  if (!sprite_G[k])
+    return;
+  int g = sprite_G[k] - 1;
+  if (g == 3)
+    g = sprite_subtype[k] + 2;
+  Oam_AllocateFromRegionC(0x10);
+  OamEnt *oam = GetOamCurPtr();
+  for (int i = 3; i >= 0; i--, oam++) {
+    int j = g * 4 + i;
+    oam->x = tmp_counter + kPikit_DrawGrabbedItem_X[j];
+    oam->y = byte_7E0FB6 + kPikit_DrawGrabbedItem_Y[j];
+    oam->charnum = kPikit_DrawGrabbedItem_Char[j];
+    oam->flags = kPikit_DrawGrabbedItem_Flags[g];
+  }
+  Sprite_CorrectOamEntries(k, 3, 0);
+}
+
+void Kholdstare_Draw(int k) {  // 8dd98f
+  static const DrawMultipleData kKholdstare_Dmd[16] = {
+    {-8, -8, 0x0080, 2},
+    { 8, -8, 0x0082, 2},
+    {-8,  8, 0x00a0, 2},
+    { 8,  8, 0x00a2, 2},
+    {-7, -7, 0x0080, 2},
+    { 7, -7, 0x0082, 2},
+    {-7,  7, 0x00a0, 2},
+    { 7,  7, 0x00a2, 2},
+    {-7, -7, 0x0084, 2},
+    { 7, -7, 0x0086, 2},
+    {-7,  7, 0x00a4, 2},
+    { 7,  7, 0x00a6, 2},
+    {-8, -8, 0x0084, 2},
+    { 8, -8, 0x0086, 2},
+    {-8,  8, 0x00a4, 2},
+    { 8,  8, 0x00a6, 2},
+  };
+  static const int8 kKholdstare_Draw_X[16] = {8, 7, 4, 2, 0, -2, -4, -7, -8, -7, -4, -2, 0, 2, 4, 7};
+  static const int8 kKholdstare_Draw_Y[16] = {0, 2, 4, 7, 8, 7, 4, 2, 0, -2, -4, -7, -8, -7, -4, -2};
+  static const uint8 kKholdstare_Draw_Char[16] = {0xac, 0xac, 0xaa, 0x8c, 0x8c, 0x8c, 0xaa, 0xac, 0xac, 0xaa, 0xaa, 0x8c, 0x8c, 0x8c, 0xaa, 0xac};
+  static const uint8 kKholdstare_Draw_Flags[16] = {0x40, 0x40, 0x40, 0, 0, 0, 0, 0, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xc0, 0xc0};
+  PrepOamCoordsRet info;
+  if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
+    return;
+  OamEnt *oam = GetOamCurPtr();
+  int j = sprite_A[k];
+  SetOamHelper0(oam, info.x + kKholdstare_Draw_X[j], info.y + kKholdstare_Draw_Y[j],
+                kKholdstare_Draw_Char[j], kKholdstare_Draw_Flags[j] | info.flags, 2);
+  oam_cur_ptr += 4, oam_ext_cur_ptr += 1;
+  Sprite_DrawMultiple(k, &kKholdstare_Dmd[sprite_graphics[k] * 4], 4, &info);
+}
+
+int Sprite_SpawnFireball(int k) {  // 8dda06
+  SpriteSpawnInfo info;
+  SpriteSfx_QueueSfx3WithPan(k, 0x19);
+  int j = Sprite_SpawnDynamicallyEx(k, 0x55, &info, 13);
+  if (j < 0)
+    return j;
+  Sprite_SetX(j, info.r0_x + 4);
+  Sprite_SetY(j, info.r2_y + 4 - info.r4_z);
+
+  sprite_flags3[j] = sprite_flags3[j] & 0xfe | 0x40;
+  sprite_oam_flags[j] = 6;
+  sprite_flags4[j] = 0x54;
+  sprite_E[j] = 0x54;
+  sprite_flags2[j] = 0x20;
+  Sprite_ApplySpeedTowardsLink(j, 0x20);
+  sprite_delay_main[j] = 20;
+  sprite_delay_aux1[j] = 16;
+  sprite_flags5[j] = 0;
+  sprite_defl_bits[j] = 0x48;
+  return j;
+}
+
+void ArcheryGameGuy_Draw(int k) {  // 8ddac4
+  static const int8 kArcheryGameGuy_Draw_X[15] = {0, 0, 0, 0, 0, -5, 0, -1, -1, 0, 0, 0, 0, 1, 1};
+  static const int8 kArcheryGameGuy_Draw_Y[15] = {0, -10, -10, 0, -10, -3, 0, -10, -10, 0, -10, -10, 0, -10, -10};
+  static const uint8 kArcheryGameGuy_Draw_Char[15] = {0x26, 6, 6, 8, 6, 0x3a, 0x26, 6, 6, 0x26, 6, 6, 0x26, 6, 6};
+  static const uint8 kArcheryGameGuy_Draw_Flags[15] = {8, 6, 6, 8, 6, 8, 8, 6, 6, 8, 6, 6, 8, 6, 6};
+  static const uint8 kArcheryGameGuy_Draw_Big[15] = {2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2};
+
+  Oam_AllocateDeferToPlayer(k);
+  PrepOamCoordsRet info;
+  Sprite_PrepOamCoord(k, &info);
+  OamEnt *oam = GetOamCurPtr();
+  int g = sprite_graphics[k];
+  for (int i = 2; i >= 0; i--, oam++) {
+    int j = g * 3 + i;
+    SetOamPlain(oam, info.x + kArcheryGameGuy_Draw_X[j], info.y + kArcheryGameGuy_Draw_Y[j],
+                 kArcheryGameGuy_Draw_Char[j], kArcheryGameGuy_Draw_Flags[j] | info.flags, kArcheryGameGuy_Draw_Big[j]);
+  }
+  SpriteDraw_Shadow(k, &info);
+}
+
+void ShopKeeper_RapidTerminateReceiveItem() {  // 8ffaea
+  for (int i = 4; i >= 0; i--) {
+    if (ancilla_type[i] == 0x22)
+      ancilla_aux_timer[i] = 1;
+  }
+}
+
+void Sprite_InitializeSecondaryItemMinigame(int what) {  // 8ffd86
+  is_archer_or_shovel_game = what;
+  Link_ResetProperties_C();
+  for (int k = 4; k >= 0; k--) {
+    if (ancilla_type[k] == 0x30 || ancilla_type[k] == 0x31) {
+      ancilla_type[k] = 0;
+    } else if (ancilla_type[k] == 5) {
+      flag_for_boomerang_in_place = 0;
+      ancilla_type[k] = 0;
+    }
+  }
+}
+
+void Waterfall(int k) {  // 9af5b8
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  if (Sprite_CheckDamageToLink_same_layer(k)) {
+    if (BYTE(overworld_screen_index) == 0x43)
+      AncillaAdd_GTCutscene();
+    else
+      AncillaAdd_WaterfallSplash();
+  }
+}
+
+void Sprite_BatCrash(int k) {  // 9af5d9
+  static const uint16 kRetreatBat_Xpos[4] = {0x7dc, 0x7f0, 0x820, 0x818};
+  static const uint16 kRetreatBat_Ypos[4] = {0x62e, 0x636, 0x630, 0x5e0};
+  static const uint8 kRetreatBat_Delay[5] = {4, 3, 4, 6, 0};
+  int j;
+  RetreatBat_Draw(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  Sprite_MoveXY(k);
+  BatCrash_DrawHardcodedGarbage(k);
+  bg1_y_offset = 0;
+  if (sprite_delay_aux3[k]) {
+    if (sprite_delay_aux3[k] == 1)
+      sound_effect_ambient = 5;
+    bg1_y_offset = sprite_delay_aux3[k] & 1 ? 1 : -1;
+  }
+  if (!sprite_delay_main[k]) {
+    sprite_graphics[k] = sprite_graphics[k] + 1 & 3;
+    if (sprite_graphics[k] == 0 && sprite_ai_state[k] < 2)
+      SpriteSfx_QueueSfx2WithPan(k, 0x3);
+    sprite_delay_main[k] = kRetreatBat_Delay[sprite_D[k]];
+  }
+  switch(sprite_ai_state[k]) {
+  case 0: {
+    j = sprite_A[k];
+    if (kRetreatBat_Xpos[j] < cur_sprite_x) {
+      if (j >= 2) {
+        sprite_ai_state[k]++;
+        sprite_delay_aux1[k] = 208;
+      }
+      sprite_A[k]++;
+      sprite_D[k]++;
+    }
+update_pos:
+    if (!(frame_counter & 7))
+      sprite_y_vel[k] += (kRetreatBat_Ypos[j] >= cur_sprite_y) ? 1 : -1;
+    if (!(frame_counter & 15))
+      sprite_x_vel[k]++;
+    break;
+  }
+  case 1:
+    if (!sprite_delay_aux1[k]) {
+      sprite_ai_state[k]++;
+      SpriteSfx_QueueSfx3WithPan(k, 0x26);
+      sprite_D[k]++;
+      sprite_x_lo[k] = 232;
+      sprite_x_hi[k] = 7;
+      sprite_y_lo[k] = 224;
+      sprite_y_hi[k] = 5;
+      sprite_x_vel[k] = 0;
+      sprite_y_vel[k] = 64;
+      sprite_delay_aux1[k] = 45;
+    } else {
+      if (!(frame_counter & 3))
+        sprite_x_vel[k]--;
+      j = sprite_A[k];
+      goto update_pos;
+    }
+    break;
+  case 2:
+    if (!sprite_delay_aux1[k]) {
+      sprite_y_vel[k] = 0;
+      sprite_delay_aux1[k] = 96;
+      sprite_ai_state[k]++;
+    }
+    if (sprite_delay_aux1[k] == 9) {
+      BatCrash_SpawnDebris(k);
+      CreatePyramidHole();
+    }
+    break;
+  case 3:  // Finishing Up
+    if (!sprite_delay_aux1[k]) {
+      sprite_state[k] = 0;
+      overworld_map_state++;
+    }
+    break;
+  }
+}
+
+void Sprite_SpawnBatCrashCutscene() {  // 9af6f5
+  SpriteSpawnInfo info;
+  int j = Sprite_SpawnDynamically(0, 0x37, &info);
+  if (j >= 0) {
+    sprite_y_vel[j] = 0;
+    sprite_B[j] = 0;
+    sprite_D[j] = 0;
+    sprite_floor[j] = 0;
+    sprite_subtype2[j] = 1;
+    sprite_flags2[j] = 1;
+    sprite_flags3[j] = 1;
+    sprite_oam_flags[j] = 1;
+    sprite_x_lo[j] = 204;
+    sprite_x_hi[j] = 7;
+    sprite_y_lo[j] = 50;
+    sprite_y_hi[j] = 6;
+    sprite_defl_bits[j] = 128;
+  }
+}
+
+void BatCrash_DrawHardcodedGarbage(int k) {  // 9af750
+  static const OamEntSigned kRetreatBat_Oams[8] = {
+    { 104, -105, 0x57, 0x01},
+    { 120, -105, 0x57, 0x01},
+    {-120, -105, 0x57, 0x01},
+    { 104,  -89, 0x57, 0x01},
+    { 120,  -89, 0x57, 0x01},
+    {-120,  -89, 0x57, 0x01},
+    { 101, -112, 0x57, 0x01},
+    {-117, -112, 0x57, 0x01},
+  };
+  memcpy(oam_buf + 76, kRetreatBat_Oams, 32);
+  for (int i = 0; i < 9; i++) // wtf 9
+    bytewise_extended_oam[i + 76] = 2;
+}
+
+void BatCrash_SpawnDebris(int k) {  // 9af7e5
+  static const int8 kPyramidDebris_X[30] = {
+    -8,  0,  8, 16, 24, 32, -8,  0,  8, 16, 24, 32, -8,  0, 8, 16,
+    24, 32, -8,  0,  8, 16, 24, 32, -8,  0,  8, 16, 24, 32,
+  };
+  static const int8 kPyramidDebris_Y[30] = {
+    0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
+  };
+  static const int8 kPyramidDebris_Xvel[30] = {
+    -30, -25,  -8,   8,  25, 30, -50, -45, -20,  20,  45, 50, -50, -35, -25, 25,
+     35,  50, -45, -50, -60, 60,  50,  45, -30, -35, -40, 40,  35,  30,
+  };
+  static const int8 kPyramidDebris_Yvel[30] = {
+     2,  5,  10,  10,   5,   2,   5,  20,  30,  30,  20,   5,  10,  30, 40, 40,
+    30, 10, -20, -40, -60, -60, -40, -20, -10, -20, -40, -40, -20, -10,
+  };
+  for (int j = 29; j >= 0; j--) {
+    GarnishSpawn_PyramidDebris(kPyramidDebris_X[j], kPyramidDebris_Y[j], kPyramidDebris_Xvel[j], kPyramidDebris_Yvel[j]);
+  }
+  sprite_delay_aux3[k] = 32;
+}
+
+void RetreatBat_Draw(int k) {  // 9af833
+  static const DrawMultipleData kRetreatBat_Dmds[18] = {
+    { 0,  0, 0x044b, 0},
+    { 5, -4, 0x045b, 0},
+    {-2, -4, 0x0464, 2},
+    {-2, -4, 0x0449, 2},
+    {-8, -9, 0x046c, 2},
+    { 8, -9, 0x446c, 2},
+    {-8, -7, 0x044c, 2},
+    { 8, -7, 0x444c, 2},
+    {-8, -9, 0x0444, 2},
+    { 8, -9, 0x4444, 2},
+    {-8, -8, 0x0462, 2},
+    { 8, -8, 0x4462, 2},
+    {-8, -7, 0x0460, 2},
+    { 8, -7, 0x4460, 2},
+    { 0,  0, 0x044e, 2},
+    {16,  0, 0x444e, 2},
+    { 0, 16, 0x046e, 2},
+    {16, 16, 0x446e, 2},
+  };
+  static const uint8 kOffs[] = {0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 6, 6, 8, 10, 12, 10, 14, 14, 14, 14};
+  static const uint8 kCount[20] = { 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 4, 4, 4, 4, };
+  oam_cur_ptr = 0x960;
+  oam_ext_cur_ptr = 0xa78;
+  int j = sprite_D[k] * 4 + sprite_graphics[k];
+  Sprite_DrawMultiple(k, &kRetreatBat_Dmds[kOffs[j]], kCount[j], NULL);
+}
+
+void DrinkingGuy_Draw(int k) {  // 9af88c
+  static const DrawMultipleData kDrinkingGuy_Dmd[6] = {
+    {8,  2, 0x00ae, 0},
+    {0, -9, 0x0822, 2},
+    {0,  0, 0x0006, 2},
+    {7,  0, 0x00af, 0},
+    {0, -9, 0x0822, 2},
+    {0,  0, 0x0006, 2},
+  };
+  PrepOamCoordsRet info;
+  Sprite_DrawMultiplePlayerDeferred(k, &kDrinkingGuy_Dmd[sprite_graphics[k] * 3], 3, &info);
+  SpriteDraw_Shadow(k, &info);
+}
+
+void Lady_Draw(int k) {  // 9af92c
+  static const DrawMultipleData kLadyDmd[16] = {
+    {0, -8, 0x00e0, 2},
+    {0,  0, 0x00e8, 2},
+    {0, -7, 0x00e0, 2},
+    {0,  1, 0x40e8, 2},
+    {0, -8, 0x00c0, 2},
+    {0,  0, 0x00c2, 2},
+    {0, -7, 0x00c0, 2},
+    {0,  1, 0x40c2, 2},
+    {0, -8, 0x00e2, 2},
+    {0,  0, 0x00e4, 2},
+    {0, -7, 0x00e2, 2},
+    {0,  1, 0x00e6, 2},
+    {0, -8, 0x40e2, 2},
+    {0,  0, 0x40e4, 2},
+    {0, -7, 0x40e2, 2},
+    {0,  1, 0x40e6, 2},
+  };
+  PrepOamCoordsRet info;
+  Sprite_DrawMultiplePlayerDeferred(k, &kLadyDmd[sprite_graphics[k] * 2 + sprite_D[k] * 4], 2, &info);
+  SpriteDraw_Shadow(k, &info);
+}
+
+void Lanmola_SpawnShrapnel(int k) {  // 9af981
+  static const int8 kLanmolaShrapnel_Yvel[8] = {28, -28, 28, -28, 0, 36, 0, -36};
+  static const int8 kLanmolaShrapnel_Xvel[8] = {-28, -28, 28, 28, -36, 0, 36, 0};
+
+  tmp_counter = (sprite_state[0] + sprite_state[1] + sprite_state[2]) < 10 ? 7 : 3;
+  do {
+    SpriteSpawnInfo info;
+    int j = Sprite_SpawnDynamically(k, 0xC2, &info);
+    if (j >= 0) {
+      Sprite_SetSpawnedCoordinates(j, &info);
+      sprite_x_lo[j] = info.r0_x + 4;
+      sprite_y_lo[j] = info.r2_y + 4;
+      sprite_ignore_projectile[j] = 1;
+      sprite_bump_damage[j] = 1;
+      sprite_flags4[j] = 1;
+      sprite_z[j] = 0;
+      sprite_flags2[j] = 0x20;
+      sprite_x_vel[j] = kLanmolaShrapnel_Xvel[tmp_counter];
+      sprite_y_vel[j] = kLanmolaShrapnel_Yvel[tmp_counter];
+      sprite_graphics[j] = GetRandomNumber() & 1;
+    }
+  } while (!sign8(--tmp_counter));
+}
+
+void Sprite_Cukeman(int k) {  // 9afa0c
+  if (sprite_head_dir[k] == 0)
+    return;
+
+  if (sprite_state[k] == 9 && !(submodule_index | flag_unk1) &&
+      (uint16)(cur_sprite_x - link_x_coord + 0x18) < 0x30 &&
+      (uint16)(link_y_coord - cur_sprite_y + 0x20) < 0x30 &&
+      (filtered_joypad_L & 0x80)) {
+    dialogue_message_index = 0x17a + (sprite_subtype[k]++ & 1);
+    Sprite_ShowMessageMinimal();
+  }
+
+  uint8 old = sprite_oam_flags[k] & 0xf0;
+  sprite_oam_flags[k] = old | 8;
+  Cukeman_Draw(k);
+  sprite_oam_flags[k] = old | 0xd;
+  Oam_AllocateFromRegionA(0x10);
+}
+
+void Cukeman_Draw(int k) {  // 9afb0e
+  static const DrawMultipleData kCukeman_Dmd[18] = {
+    { 0, 0, 0x01f3, 0},
+    { 7, 0, 0x41f3, 0},
+    { 4, 7, 0x07e0, 0},
+    {-1, 2, 0x01f3, 0},
+    { 6, 1, 0x41f3, 0},
+    { 4, 8, 0x07e0, 0},
+    { 1, 1, 0x01f3, 0},
+    { 8, 2, 0x41f3, 0},
+    { 4, 8, 0x07e0, 0},
+    {-2, 0, 0x01f3, 0},
+    {10, 0, 0x41f3, 0},
+    { 4, 7, 0x07e0, 0},
+    { 0, 0, 0x01f3, 0},
+    { 8, 0, 0x41f3, 0},
+    { 4, 6, 0x07e0, 0},
+    {-5, 0, 0x01f3, 0},
+    {16, 0, 0x41f3, 0},
+    { 4, 8, 0x07e0, 0},
+  };
+  Sprite_DrawMultiple(k, &kCukeman_Dmd[sprite_graphics[k] * 3], 3, NULL);
+}
+
+void RunningBoy_SpawnDustGarnish(int k) {  // 9afb2c
+  if (++sprite_die_action[k] & 0xf)
+    return;
+  int j = GarnishAllocForce();
+  garnish_type[j] = 20;
+  garnish_active = 20;
+  Garnish_SetX(j, Sprite_GetX(k) + 4);
+  Garnish_SetY(j, Sprite_GetY(k) + 28);
+  garnish_countdown[j] = 10;
+}
+
+void MovableMantle_Draw(int k) {  // 9afcb3
+  Oam_AllocateFromRegionB(0x20);
+  PrepOamCoordsRet info;
+  if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
+    return;
+  OamEnt *oam = GetOamCurPtr();
+  for (int i = 5; i >= 0; i--, oam++) {
+    oam->x = kMovableMantle_X[i] + info.x;
+    oam->y = kMovableMantle_Y[i] + info.y;
+    oam->charnum = kMovableMantle_Char[i];
+    oam->flags = kMovableMantle_Flags[i];
+  }
+  Sprite_CorrectOamEntries(k, 5, 2);
+}
+
+void Mothula_Draw(int k) {  // 9afdb5
+  static const DrawMultipleData kMothula_Dmd[24] = {
+    {-24, -8, 0x0080, 2},
+    { -8, -8, 0x0082, 2},
+    {  8, -8, 0x4082, 2},
+    { 24, -8, 0x4080, 2},
+    {-24,  8, 0x00a0, 2},
+    { -8,  8, 0x00a2, 2},
+    {  8,  8, 0x40a2, 2},
+    { 24,  8, 0x40a0, 2},
+    {-24, -8, 0x0084, 2},
+    { -8, -8, 0x0086, 2},
+    {  8, -8, 0x4086, 2},
+    { 24, -8, 0x4084, 2},
+    {-24,  8, 0x00a4, 2},
+    { -8,  8, 0x00a6, 2},
+    {  8,  8, 0x40a6, 2},
+    { 24,  8, 0x40a4, 2},
+    { -8, -8, 0x0088, 2},
+    { -8, -8, 0x0088, 2},
+    {  8, -8, 0x4088, 2},
+    {  8, -8, 0x4088, 2},
+    { -8,  8, 0x00a8, 2},
+    { -8,  8, 0x00a8, 2},
+    {  8,  8, 0x40a8, 2},
+    {  8,  8, 0x40a8, 2},
+  };
+  oam_cur_ptr = 0x920;
+  oam_ext_cur_ptr = 0xa68;
+  PrepOamCoordsRet info;
+  Sprite_DrawMultiple(k, &kMothula_Dmd[sprite_graphics[k] * 8], 8, &info);
+  if (sprite_pause[k])
+    return;
+  info.y += sprite_z[k];
+  static const int8 kMothula_Draw_X[27] = {
+    0,  3, 6, 9, 12, -3, -6, -9, -12,  0,  2, 4, 6, 8, -2, -4,
+    -6, -8, 0, 1,  2,  3,  4, -1,  -2, -3, -4,
+  };
+  OamEnt *oam = GetOamCurPtr() + 10;
+  int g = sprite_graphics[k];
+  for (int i = 8; i >= 0; i--, oam++) {
+    SetOamHelper0(oam, info.x + kMothula_Draw_X[g * 9 + i], info.y + 16,
+                  0x6c, 0x24, 2);
+  }
+}
+
+void BottleMerchant_BuyBee(int k) {  // 9afe88
+  static const int8 kBottleVendor_GoodBeeX[5] = {-6, -3, 0, 4, 7};
+  static const int8 kBottleVendor_GoodBeeY[5] = {11, 14, 16, 14, 11};
+  SpriteSpawnInfo info;
+  SpriteSfx_QueueSfx3WithPan(k, 0x13);
+  tmp_counter = 4;
+  do {
+    int j = Sprite_SpawnDynamically(k, 0xdb, &info);
+    if (j >= 0) {
+      Sprite_SetSpawnedCoordinates(j, &info);
+      sprite_x_lo[j] = info.r0_x + 4;
+      sprite_stunned[j] = 0xff;
+      sprite_x_vel[j] = kBottleVendor_GoodBeeX[tmp_counter];
+      sprite_y_vel[j] = kBottleVendor_GoodBeeY[tmp_counter];
+      sprite_z_vel[j] = 32;
+      sprite_delay_aux4[j] = 32;
+    }
+  } while (!sign8(--tmp_counter));
+}
+
+void Sprite_ChickenLady(int k) {  // 9afed3
+  sprite_D[k] = 1;
+  Lady_Draw(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  if (sprite_delay_main[k] == 1) {
+    dialogue_message_index = 0x17d;
+    Sprite_ShowMessageMinimal();
+  }
+  sprite_graphics[k] = frame_counter >> 4 & 1;
+}
+
+void Overworld_DrawWoodenDoor(uint16 pos, bool unlocked) {  // 9bc952
+  Overworld_DrawMap16_Persist(pos, unlocked ? 0xda5 : 0xda4);
+  Overworld_DrawMap16_Persist(pos+2, unlocked ? 0xda7 : 0xda6);
+  nmi_load_bg_from_vram = 1;
+}
+
+void Sprite_D4_Landmine(int k) {  // 9d8099
+  static const uint8 kLandMine_OamFlags[4] = {4, 2, 8, 2};
+
+  Landmine_Draw(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  if (!Landmine_CheckDetonationFromHammer(k)) {
+    if (!sprite_delay_main[k]) {
+      sprite_oam_flags[k] = 4;
+      if (Sprite_CheckDamageToLink(k))
+        sprite_delay_main[k] = 8;
+      return;
+    }
+    if (sprite_delay_main[k] != 1) {
+      sprite_oam_flags[k] = kLandMine_OamFlags[sprite_delay_main[k] >> 1 & 3];
+      return;
+    }
+  }
+  sprite_state[k] = 0;
+  int j = Sprite_SpawnBomb(k);
+  if (j >= 0) {
+    sprite_state[j] = 6;
+    sprite_C[j] = 2;
+    sprite_oam_flags[j] = 2;
+    sprite_flags4[j] = 9;
+    sprite_delay_aux1[j] = 31;
+    sprite_flags2[j] = 3;
+    sound_effect_1 = Sprite_CalculateSfxPan(k) | 12;
+  }
+}
+
+void Landmine_Draw(int k) {  // 9d810c
+  static const DrawMultipleData kLandmine_Dmd[2] = {
+    {0, 4, 0x0070, 0},
+    {8, 4, 0x4070, 0},
+  };
+  Oam_AllocateFromRegionB(8);
+  if (byte_7E0FC6 >= 3)
+    return;
+  Sprite_DrawMultiple(k, kLandmine_Dmd, 2, NULL);
+}
+
+void Sprite_D3_Stal(int k) {  // 9d8129
+  static const uint8 kStal_Gfx[5] = {2, 2, 1, 0, 1};
+  if (byte_7E0FC6 < 3) {
+    if (!sprite_ai_state[k])
+      Oam_AllocateFromRegionB(4);
+    Stal_Draw(k);
+  }
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  if (Sprite_ReturnIfRecoiling(k))
+    return;
+  switch(sprite_ai_state[k]) {
+  case 0: // dormant
+    sprite_ignore_projectile[k] = 1;
+    if (Sprite_CheckDamageToLink_same_layer(k)) {
+      Sprite_NullifyHookshotDrag();
+      Sprite_RepelDash();
+      if (!sprite_delay_main[k]) {
+        sprite_delay_main[k] = 64;
+        SpriteSfx_QueueSfx2WithPan(k, 0x22);
+      }
+    }
+    if (sprite_delay_main[k] != 0) {
+      if (sprite_delay_main[k] - 1) {
+        sprite_hit_timer[k] = (sprite_delay_main[k] - 1) | 64;
+      } else {
+        sprite_ignore_projectile[k] = 0;
+        sprite_ai_state[k]++;
+        sprite_hit_timer[k] = 0;
+        sprite_flags3[k] &= ~0x40;
+        sprite_flags2[k] &= ~0x80;
+      }
+    }
+    break;
+  case 1: // active
+    Sprite_CheckDamageToAndFromLink(k);
+    Sprite_MoveXYZ(k);
+    Sprite_CheckTileCollision(k);
+    sprite_z_vel[k]-=2;
+    if (sign8(sprite_z[k])) {
+      sprite_z[k] = 0;
+      sprite_z_vel[k] = 16;
+      Sprite_ApplySpeedTowardsLink(k, 12);
+    }
+    if (!(frame_counter & 3) && ++sprite_subtype2[k] == 5)
+      sprite_subtype2[k] = 0;
+    sprite_graphics[k] = kStal_Gfx[sprite_subtype2[k]];
+    break;
+  }
+}
+
+void Stal_Draw(int k) {  // 9d820c
+  static const DrawMultipleData kStal_Dmd[6] = {
+    {0,  0, 0x0044, 2},
+    {4, 11, 0x0070, 0},
+    {0,  0, 0x0044, 2},
+    {4, 12, 0x0070, 0},
+    {0,  0, 0x0044, 2},
+    {4, 13, 0x0070, 0},
+  };
+  PrepOamCoordsRet info;
+  int n = sprite_ai_state[k] ? 2 : 1;
+  Sprite_DrawMultiple(k, &kStal_Dmd[sprite_graphics[k] * 2], n, &info);
+  if (sprite_ai_state[k])
+    SpriteDraw_Shadow(k, &info);
+}
+
+void Sprite_D2_FloppingFish(int k) {  // 9d8235
+  static const int8 kFish_Xvel[8] = {0, 12, 16, 12, 0, -12, -16, -12};
+  static const int8 kFish_Yvel[8] = {-16, -12, 0, 12, 16, 12, 0, -12};
+  static const uint8 kFish_Tab1[2] = {2, 0};
+  static const uint8 kFish_Gfx[3] = {1, 5, 3};
+  static const uint8 kFish_Gfx2[17] = {5, 5, 6, 6, 5, 5, 4, 4, 3, 7, 7, 8, 8, 7, 7, 8, 8 };
+
+  if (byte_7E0FC6 < 3)
+    Fish_Draw(k);
+  if (sprite_state[k] == 10) {
+    sprite_ai_state[k] = 4;
+    sprite_graphics[k] = (frame_counter >> 4 & 1) + 3;
+  }
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  switch (sprite_ai_state[k]) {
+  case 0:  // check deep water
+    Sprite_CheckTileCollision(k);
+    if (sprite_tiletype == 8)
+      sprite_state[k] = 0;
+    else
+      sprite_ai_state[k] = 1;
+    break;
+  case 1:  // flop around
+    Sprite_CheckIfLifted_permissive(k);
+    Sprite_BounceFromTileCollision(k);
+    Sprite_MoveXYZ(k);
+    sprite_z_vel[k] -= 2;
+    if (sign8(sprite_z[k])) {
+      sprite_z[k] = 0;
+      if (sprite_tiletype == 9) {
+        Sprite_SpawnSmallSplash(k);
+      } else if (sprite_tiletype == 8) {
+        sprite_state[k] = 0;
+        Sprite_SpawnSmallSplash(k);
+      }
+      sprite_z_vel[k] = (GetRandomNumber() & 15) + 16;
+      int j = GetRandomNumber() & 7;
+      sprite_x_vel[k] = kFish_Xvel[j];
+      sprite_y_vel[k] = kFish_Yvel[j];
+      sprite_D[k]++;
+      sprite_subtype2[k] = 3;
+    }
+    sprite_subtype2[k]++;
+    if (!(sprite_subtype2[k] & 7)) {
+      int j = sprite_D[k] & 1;
+      if (sprite_A[k] != kFish_Tab1[j])
+        sprite_A[k] += j ? -1 : 1;
+    }
+    sprite_graphics[k] = kFish_Gfx[sprite_A[k]] + (frame_counter >> 3 & 1);
+    break;
+  case 2:  // pause before leap
+    if (!sprite_delay_main[k]) {
+      sprite_ai_state[k] = 3;
+      sprite_z_vel[k] = 48;
+      Sprite_SpawnSmallSplash(k);
+    }
+    break;
+  case 3:  // leaping
+    Sprite_MoveZ(k);
+    sprite_z_vel[k] -= 2;
+    if (sprite_z_vel[k] == 0 && sprite_A[k] != 0) {
+      dialogue_message_index = 0x176;
+      Sprite_ShowMessageMinimal();
+    }
+    if (sign8(sprite_z[k])) {
+      sprite_z[k] = 0;
+      Sprite_SpawnSmallSplash(k);
+      if (sprite_A[k]) {
+        SpriteSpawnInfo info;
+        int j = Sprite_SpawnDynamically(k, 0xdb, &info);
+        if (j >= 0) {
+          Sprite_SetSpawnedCoordinates(j, &info);
+          Sprite_SetX(j, info.r0_x + 4);
+          sprite_stunned[j] = 255;
+          sprite_z_vel[j] = 48;
+          sprite_delay_aux3[j] = 48;
+          Sprite_ApplySpeedTowardsLink(j, 16);
+        }
+      }
+      sprite_state[k] = 0;
+    }
+    sprite_graphics[k] = kFish_Gfx2[++sprite_subtype2[k] >> 2];
+    break;
+  case 4:  // wiggle
+    if (!sprite_z[k])
+      sprite_ai_state[k] = 1;
+    Sprite_MoveXY(k);
+    ThrownSprite_TileAndSpriteInteraction(k);
+    break;
+  }
+}
+
+void Fish_Draw(int k) {  // 9d8483
+  static const DrawMultipleData kFish_Dmd[16] = {
+    {-4, 8, 0x045e, 0},
+    { 4, 8, 0x045f, 0},
+    {-4, 8, 0x845e, 0},
+    { 4, 8, 0x845f, 0},
+    {-4, 8, 0x445f, 0},
+    { 4, 8, 0x445e, 0},
+    {-4, 8, 0xc45f, 0},
+    { 4, 8, 0xc45e, 0},
+    { 0, 0, 0x0461, 0},
+    { 0, 8, 0x0471, 0},
+    { 0, 0, 0x4461, 0},
+    { 0, 8, 0x4471, 0},
+    { 0, 0, 0x8471, 0},
+    { 0, 8, 0x8461, 0},
+    { 0, 0, 0xc471, 0},
+    { 0, 8, 0xc461, 0},
+  };
+  static const DrawMultipleData kFish_Dmd2[9] = {
+    {-2, 11, 0x0438, 0},
+    { 0, 11, 0x0438, 0},
+    { 2, 11, 0x0438, 0},
+    {-1, 11, 0x0438, 0},
+    { 0, 11, 0x0438, 0},
+    { 1, 11, 0x0438, 0},
+    { 0, 11, 0x0438, 0},
+    { 0, 11, 0x0438, 0},
+    { 0, 11, 0x0438, 0},
+  };
+  PrepOamCoordsRet info;
+  if (sprite_graphics[k] == 0) {
+    Sprite_PrepOamCoord(k, &info);
+    return;
+  }
+  cur_sprite_x += 4;
+  Sprite_DrawMultiple(k, &kFish_Dmd[(sprite_graphics[k] - 1) * 2], 2, &info);
+  cur_sprite_y += sprite_z[k];
+  int j = sprite_z[k] >> 2;
+  oam_cur_ptr += 8, oam_ext_cur_ptr += 2;
+  Sprite_DrawMultiple(k, &kFish_Dmd2[((j >= 2) ? 2 : j) * 3], 3, &info);
+  Sprite_Get16BitCoords(k);
+}
+
+void ChimneySmoke_Draw(int k) {  // 9d8531
+  static const DrawMultipleData kChimneySmoke_Dmd[8] = {
+    {0, 0, 0x0086, 0},
+    {8, 0, 0x0087, 0},
+    {0, 8, 0x0096, 0},
+    {8, 8, 0x0097, 0},
+    {1, 1, 0x0086, 0},
+    {7, 1, 0x0087, 0},
+    {1, 7, 0x0096, 0},
+    {7, 7, 0x0097, 0},
+  };
+  Sprite_DrawMultiple(k, &kChimneySmoke_Dmd[(sprite_graphics[k] & 1) * 4], 4, NULL);
+}
+
+void Sprite_D1_BunnyBeam(int k) {  // 9d858b
+  if (player_is_indoors)
+    Sprite_BunnyBeam(k);
+  else
+    Sprite_Chimney(k);
+
+}
+
+void Sprite_Chimney(int k) {  // 9d858f
+  sprite_flags3[k] = 64;
+  sprite_ignore_projectile[k] = 64;
+  if (!sprite_ai_state[k]) {
+    if (Sprite_ReturnIfInactive(k))
+      return;
+    if (sprite_delay_main[k])
+      return;
+    sprite_delay_main[k] = 67;
+    SpriteSpawnInfo info;
+    int j = Sprite_SpawnDynamically(k, 0xd1, &info);
+    if (j < 0)
+      return;
+    Sprite_SetSpawnedCoordinates(j, &info);
+    int t = (uint8)info.r0_x + 8;
+    sprite_x_lo[j] = t;
+    sprite_y_lo[j] = info.r2_y + 4 + (t >> 8);
+    sprite_oam_flags[j] = 4;
+    sprite_ai_state[j] = 4;
+    sprite_flags2[j] = 67;
+    sprite_flags3[j] = 67;
+    sprite_x_vel[j] = -4;
+    sprite_y_vel[j] = -6;
+  } else {
+    sprite_obj_prio[k] = 0x30;
+    ChimneySmoke_Draw(k);
+    if (Sprite_ReturnIfInactive(k))
+      return;
+    Sprite_MoveXY(k);
+    if (!(++sprite_subtype2[k] & 7)) {
+      int j = sprite_D[k] & 1;
+      sprite_x_vel[k] += j ? -1 : 1;
+      if (sprite_x_vel[k] == (uint8)(j ? -4 : 4))
+        sprite_D[k]++;
+    }
+    if (!(sprite_subtype2[k] & 31))
+      sprite_graphics[k]++;
+  }
+}
+
+void Sprite_BunnyBeam(int k) {  // 9d85e0
+  static const uint8 kRabbitBeam_Gfx[6] = {0xd7, 0xd7, 0xd7, 0x91, 0x91, 0x91};
+  PrepOamCoordsRet info;
+  if (!sprite_ai_state[k]) {
+    Sprite_PrepOamCoord(k, &info);
+    if (Sprite_ReturnIfInactive(k))
+      return;
+    if (!Sprite_CheckTileCollision(k)) {
+      sprite_ai_state[k]++;
+      sprite_delay_main[k] = 128;
+    }
+    return;
+  }
+
+  SpriteDraw_Antfairy(k);
+  if (!sprite_pause[k]) {
+    OamEnt *oam = GetOamCurPtr();
+    uint8 charnum = kRabbitBeam_Gfx[sprite_graphics[k]];
+    for (int i = 0; i < 5; i++) {
+      oam[i].charnum = charnum;
+      oam[i].flags = oam[i].flags & 0xf0 | 2;
+    }
+  }
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  if (!sprite_delay_main[k]) {
+    sprite_bump_damage[k] = 0x30;
+    if (Sprite_CheckDamageToLink(k)) {
+      sprite_state[k] = 0;
+      link_timer_tempbunny = 256;
+    }
+    if (link_is_on_lower_level == sprite_floor[k])
+      Sprite_ApplySpeedTowardsLink(k, 16);
+    Sprite_MoveXY(k);
+    if (Sprite_CheckTileCollision(k)) {
+      sprite_state[k] = 0;
+      Sprite_SpawnPoofGarnish(k);
+      SpriteSfx_QueueSfx2WithPan(k, 0x15);
+    }
+  }
+}
+
+void Sprite_D0_Lynel(int k) {  // 9d866a
+  static const int8 kLynel_AttackGfx[4] = {5, 2, 8, 10};
+  static const int8 kLynel_Gfx[8] = {3, 0, 6, 9, 4, 1, 7, 10};
+  Lynel_Draw(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  if (Sprite_ReturnIfRecoiling(k))
+    return;
+  sprite_D[k] = Sprite_DirectionToFaceLink(k, NULL);
+  Sprite_CheckDamageToAndFromLink(k);
+  switch(sprite_ai_state[k]) {
+  case 0:  // target
+    if (!sprite_delay_main[k]) {
+      static const int8 kLynel_Xtarget[4] = {-96, 96, 0, 0};
+      static const int8 kLynel_Ytarget[4] = {8, 8, -96, 112};
+      int j = sprite_D[k];
+      int x = link_x_coord + kLynel_Xtarget[j];
+      sprite_A[k] = x, sprite_B[k] = x >> 8;
+      int y = link_y_coord + kLynel_Ytarget[j];
+      sprite_C[k] = y, sprite_E[k] = y >> 8;
+      sprite_ai_state[k]++;
+      sprite_delay_main[k] = 80;
+    }
+    sprite_graphics[k] = kLynel_Gfx[sprite_subtype2[k] & 4 | sprite_D[k]];
+    break;
+  case 1:  // approach
+    if (sprite_delay_main[k]) {
+      if (!((k ^ frame_counter) & 3)) {
+        uint16 x = sprite_A[k] | sprite_B[k] << 8;
+        uint16 y = sprite_C[k] | sprite_E[k] << 8;
+        if ((uint16)(x - cur_sprite_x + 5) < 10 && (uint16)(y - cur_sprite_y + 5) < 10)
+          goto incr_state;
+        ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLocation(k, x, y, 24);
+        sprite_x_vel[k] = pt.x;
+        sprite_y_vel[k] = pt.y;
+      }
+      Sprite_MoveXY(k);
+      if (Sprite_CheckTileCollision(k))
+        goto incr_state;
+      sprite_graphics[k] = kLynel_Gfx[++sprite_subtype2[k] & 4 | sprite_D[k]];
+    } else {
+incr_state:
+      sprite_ai_state[k]++;
+      sprite_delay_main[k] = 32;
+    }
+    break;
+  case 2:  // attack
+    if (!sprite_delay_main[k]) {
+      sprite_delay_main[k] = (GetRandomNumber() & 15) + 16;
+      sprite_ai_state[k] = 0;
+      return;
+    }
+    if (sprite_delay_main[k] == 16) {
+      int j = Sprite_SpawnFirePhlegm(k);
+      if (j >= 0 && link_shield_type != 3)
+        sprite_flags5[j] = 0;
+    }
+    sprite_graphics[k] = kLynel_AttackGfx[sprite_D[k]];
+    Sprite_CheckTileCollision(k);
+    break;
+  }
+}
+
+void Lynel_Draw(int k) {  // 9d8880
+  static const DrawMultipleData kLynel_Dmd[33] = {
+    {-5, -11, 0x00cc, 2},
+    {-4,   0, 0x00e4, 2},
+    { 4,   0, 0x00e5, 2},
+    {-5, -10, 0x00cc, 2},
+    {-4,   0, 0x00e7, 2},
+    { 4,   0, 0x00e8, 2},
+    {-5, -11, 0x00c8, 2},
+    {-4,   0, 0x00e4, 2},
+    { 4,   0, 0x00e5, 2},
+    { 5, -11, 0x40cc, 2},
+    {-4,   0, 0x40e5, 2},
+    { 4,   0, 0x40e4, 2},
+    { 5, -10, 0x40cc, 2},
+    {-4,   0, 0x40e8, 2},
+    { 4,   0, 0x40e7, 2},
+    { 5, -11, 0x40c8, 2},
+    {-4,   0, 0x40e8, 2},
+    { 4,   0, 0x40e7, 2},
+    { 0,  -9, 0x00ce, 2},
+    {-4,   0, 0x00ea, 2},
+    { 4,   0, 0x00eb, 2},
+    { 0,  -9, 0x00ce, 2},
+    {-4,   0, 0x40eb, 2},
+    { 4,   0, 0x40ea, 2},
+    { 0,  -9, 0x00ca, 2},
+    {-4,   0, 0x40eb, 2},
+    { 4,   0, 0x00eb, 2},
+    { 0, -14, 0x00c6, 2},
+    {-4,   0, 0x00ed, 2},
+    { 4,   0, 0x00ee, 2},
+    { 0, -14, 0x00c6, 2},
+    {-4,   0, 0x40ee, 2},
+    { 4,   0, 0x40ed, 2},
+  };
+  PrepOamCoordsRet info;
+  Sprite_DrawMultiple(k, &kLynel_Dmd[sprite_graphics[k] * 3], 3, &info);
+  SpriteDraw_Shadow(k, &info);
+}
+
+void Sprite_SpawnPhantomGanon(int k) {  // 9d88a1
+  SpriteSpawnInfo info;
+  int j = Sprite_SpawnDynamically(k, 0xc9, &info);
+  Sprite_SetSpawnedCoordinates(j, &info);
+  sprite_flags2[j] = 2;
+  sprite_ignore_projectile[j] = 2;
+  sprite_anim_clock[j] = 1;
+  sprite_oam_flags[j] = 0;
+}
+
+void Sprite_PhantomGanon(int k) {  // 9d88bc
+  static const uint8 kGanonBat_Gfx[4] = {0, 1, 2, 1};
+  static const int8 kGanonBat_TargetXvel[2] = {32, -32};
+  static const int8 kGanonBat_TargetYvel[2] = {16, -16};
+
+  if (!sprite_ai_state[k]) {
+    PhantomGanon_Draw(k);
+    if (Sprite_ReturnIfInactive(k))
+      return;
+    Sprite_MoveY(k);
+    if (!(++sprite_subtype2[k] & 31)) {
+      if (--sprite_y_vel[k] == 252) {
+        int j = SpawnBossPoof(k);
+        Sprite_SetY(j, Sprite_GetY(j) - 20);
+      } else if (sprite_y_vel[k] == 251) {
+        sprite_ai_state[k]++;
+        sprite_delay_main[k] = 255;
+        sprite_y_vel[k] = -4;
+      }
+    }
+  } else {
+    GanonBat_Draw(k);
+    if (sprite_pause[k]) {
+      sprite_state[k] = 0;
+      dung_savegame_state_bits |= 0x8000;
+    }
+    if (Sprite_ReturnIfInactive(k))
+      return;
+    sprite_graphics[k] = kGanonBat_Gfx[frame_counter >> 2 & 3];
+    if (sprite_delay_main[k]) {
+      if (sprite_delay_main[k] < 208) {
+        int j = sprite_head_dir[k] & 1;
+        sprite_y_vel[k] += j ? -1 : 1;
+        if (sprite_y_vel[k] == (uint8)kGanonBat_TargetYvel[j])
+          sprite_head_dir[k]++;
+        j = sprite_D[k] & 1;
+        sprite_x_vel[k] += j ? -1 : 1;
+        if (sprite_x_vel[k] == (uint8)kGanonBat_TargetXvel[j])
+          sprite_D[k]++;
+        if (sprite_x_vel[k] == 0)
+          SpriteSfx_QueueSfx3WithPan(k, 0x1e);
+      }
+      ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLocation(k, link_x_coord & 0xff00 | 0x78, link_y_coord & 0xff00 | 0x50, 5);
+      uint8 xvel = sprite_x_vel[k], yvel = sprite_y_vel[k];
+      sprite_x_vel[k] = xvel + pt.x, sprite_y_vel[k] = yvel + pt.y;
+      Sprite_MoveXY(k);
+      sprite_x_vel[k] = xvel, sprite_y_vel[k] = yvel;
+    } else {
+      Sprite_MoveXY(k);
+      if (sprite_x_vel[k] != 64) {
+        sprite_x_vel[k]++;
+        sprite_y_vel[k]--;
+      }
+    }
+  }
+}
+
+void GanonBat_Draw(int k) {  // 9d89eb
+  static const DrawMultipleData kGanonBat_Dmd[6] = {
+    {-8, 0, 0x0560, 2},
+    { 8, 0, 0x4560, 2},
+    {-8, 0, 0x0562, 2},
+    { 8, 0, 0x4562, 2},
+    {-8, 0, 0x0544, 2},
+    { 8, 0, 0x4544, 2},
+  };
+  Sprite_DrawMultiple(k, &kGanonBat_Dmd[sprite_graphics[k] * 2], 2, NULL);
+}
+
+void PhantomGanon_Draw(int k) {  // 9d8a84
+  static const DrawMultipleData kPhantomGanon_Dmd[16] = {
+    {-16, -8, 0x0d46, 2},
+    { -8, -8, 0x0d47, 2},
+    {  8, -8, 0x4d47, 2},
+    { 16, -8, 0x4d46, 2},
+    {-16,  8, 0x0d69, 2},
+    { -8,  8, 0x0d6a, 2},
+    {  8,  8, 0x4d6a, 2},
+    { 16,  8, 0x4d69, 2},
+    {-16, -8, 0x0d46, 2},
+    { -8, -8, 0x0d47, 2},
+    {  8, -8, 0x4d47, 2},
+    { 16, -8, 0x4d46, 2},
+    {-16,  8, 0x0d66, 2},
+    { -8,  8, 0x0d67, 2},
+    {  8,  8, 0x4d67, 2},
+    { 16,  8, 0x4d66, 2},
+  };
+  oam_cur_ptr = 0x950;
+  oam_ext_cur_ptr = 0xa74;
+  Sprite_DrawMultiple(k, &kPhantomGanon_Dmd[sprite_graphics[k] * 8], 8, NULL);
+}
+
+void SwishEvery16Frames(int k) {  // 9d8aa9
+  if (!(frame_counter & 15))
+    SpriteSfx_QueueSfx3WithPan(k, 0x6);
+}
+
+void Sprite_GanonTrident(int k) {  // 9d8ab6
+  Trident_Draw(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  Sprite_CheckDamageToAndFromLink(k);
+  SwishEvery16Frames(k);
+  Sprite_MoveXY(k);
+  sprite_G[k] = kGanon_G_Func2[--sprite_subtype2[k] >> 2 & 7];
+  if (sprite_delay_main[k]) {
+    if (sprite_delay_main[k] & 1)
+      return;
+    ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLink(k, 32);
+    Sprite_ApproachTargetSpeed(k, pt.x, pt.y);
+  } else {
+    int x = Sprite_GetX(0) + (sprite_D[0] ? -16 : 24);
+    int y = Sprite_GetY(0) - 16;
+    if (Ganon_AttemptTridentCatch(x, y)) {
+      sprite_state[k] = 0;
+      sprite_ai_state[0] = 3;
+      sprite_delay_main[0] = 16;
+    }
+    ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLocation(k, x, y, 32);
+    Sprite_ApproachTargetSpeed(k, pt.x, pt.y);
+  }
+}
+
+void Sprite_FireBat_Trailer(int k) {  // 9d8b49
+  FireBat_Draw(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  FireBat_Move(k);
+}
+
+void Sprite_SpiralFireBat(int k) {  // 9d8b52
+  FireBat_Draw(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  {
+    uint16 x = sprite_A[k] | sprite_B[k] << 8;
+    uint16 y = sprite_C[k] | sprite_E[k] << 8;
+    ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLocation(k, x, y, 2);
+    ProjectSpeedRet pt2 = Sprite_ProjectSpeedTowardsLocation(k, x, y, 80);
+    sprite_x_vel[k] = pt2.y - pt.x;
+    sprite_y_vel[k] = -pt2.x - pt.y;
+  }
+  FireBat_Move(k);
+}
+
+void FireBat_Move(int k) {  // 9d8b90
+  FireBat_Animate(k);
+  Sprite_MoveXY(k);
+  if (sprite_subtype2[k] & 7)
+    return;
+  int j = Garnish_FlameTrail(k, true);
+//  garnish_type[j] = 0x10;
+  garnish_countdown[j] = (sprite_anim_clock[k] == 5) ? 0x2f : 0x4f;
+}
+
+void Sprite_FireBat_Launched(int k) {  // 9d8bd7
+  FireBat_Draw(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  Sprite_CheckDamageToLink(k);
+  switch (sprite_ai_state[k]) {
+  case 0:
+    GetPositionRelativeToTheGreatOverlordGanon(k);
+    if (!sprite_delay_main[k]) {
+      sprite_ai_state[k] = 1;
+    } else {
+      sprite_graphics[k] = sprite_delay_main[k] >> 2 & 1;
+    }
+    break;
+  case 1:
+    GetPositionRelativeToTheGreatOverlordGanon(k);
+    sprite_graphics[k] = ++sprite_subtype2[k] >> 2 & 1;
+    break;
+  case 2:
+    Sprite_MoveXY(k);
+    sprite_defl_bits[k] = 64;
+    if (sprite_delay_aux1[k] == 0) {
+      if (sprite_delay_main[k] == 0) {
+        FireBat_Animate(k);
+        FireBat_Animate(k);
+
+      } else {
+        uint8 t = sprite_delay_main[k] - 1;
+        if (t == 0)
+          sprite_delay_aux1[k] = t = 35;
+        sprite_graphics[k] = t >> 2 & 1;
+      }
+    } else if (sprite_delay_aux1[k] == 1) {
+      Sprite_ApplySpeedTowardsLink(k, 48);
+      SpriteSfx_QueueSfx3WithPan(k, 0x1e);
+      FireBat_Animate(k);
+      FireBat_Animate(k);
+    } else {
+      static const uint8 kFirebat_Gfx2[9] = { 4, 4, 4, 3, 3, 3, 2, 2, 2 };
+      sprite_graphics[k] = kFirebat_Gfx2[sprite_delay_aux1[k] >> 2];
+    }
+    break;
+  }
+}
+
+void GetPositionRelativeToTheGreatOverlordGanon(int k) {  // 9d8bee
+  static const int8 kFirebat_X[2] = { 20, -18 };
+  static const int8 kFirebat_Y[2] = { -20, -20 };
+
+  int j = sprite_D[0];
+  Sprite_SetX(k, (overlord_x_hi[k] | overlord_y_hi[k] << 8) + kFirebat_X[j]);
+  Sprite_SetY(k, (overlord_gen2[k] | overlord_floor[k] << 8) + kFirebat_Y[j]);
+}
+
+void FireBat_Animate(int k) {  // 9d8c43
+  static const uint8 kFirebat_Gfx[4] = { 4, 5, 6, 5 };
+  sprite_graphics[k] = kFirebat_Gfx[++sprite_subtype2[k] >> 2 & 3];
+}
+
+void FireBat_Draw(int k) {  // 9d8ca9
+  static const int8 kFirebat_Draw_X[2] = { -8, 8 };
+  static const uint8 kFirebat_Draw_Char[7] = { 0x88, 0x88, 0x8a, 0x8c, 0x68, 0xaa, 0xa8 };
+  static const uint8 kFirebat_Draw_Flags[14] = { 0, 0xc0, 0x80, 0x40, 0, 0x40, 0, 0x40, 0, 0x40, 0, 0x40, 0, 0x40 };
+
+  PrepOamCoordsRet info;
+  if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
+    return;
+  OamEnt *oam = GetOamCurPtr();
+  int g = sprite_graphics[k];
+  for (int i = 1; i >= 0; i--, oam++) {
+    SetOamHelper0(oam, info.x + kFirebat_Draw_X[i], info.y, kFirebat_Draw_Char[g],
+                  kFirebat_Draw_Flags[g * 2 + i] | info.flags, 2);
+  }
+}
+
+bool Ganon_AttemptTridentCatch(uint16 x, uint16 y) {  // 9d8d06
+  return (uint16)(cur_sprite_x - x + 4) < 8 && (uint16)(cur_sprite_y - y + 4) < 8;
+}
+
+void Ganon_HandleFireBatCircle(int k) {  // 9d8d70
+  static const int8 kGanonMath_X[16] = { 0, 16, 24, 28, 32, 28, 24, 16, 0, -16, -24, -28, -32, -28, -24, -16 };
+  static const int8 kGanonMath_Y[16] = { 32, 28, 24, 16, 0, -16, -24, -28, -32, -28, -24, -16, 0, 16, 24, 28 };
+
+  WORD(overlord_x_lo[0]) -= 4;
+
+  for (int i = 0; i != 8; i++) {
+    int t = WORD(overlord_x_lo[0]) + i * 64 & 0x1ff;
+    if (sprite_ai_state[i + 1] != 2) {
+      int j = (t >> 5) - 4 & 0xf;
+      sprite_x_vel[i + 1] = (int8)kGanonMath_X[j] >> 2;
+      sprite_y_vel[i + 1] = (int8)kGanonMath_Y[j] >> 2;
+    }
+    int x = Sprite_GetX(0) + GanonSin(t, overlord_x_lo[2]);
+    overlord_x_hi[i + 1] = x;
+    overlord_y_hi[i + 1] = x >> 8;
+
+    int y = Sprite_GetY(0) + GanonSin(t + 0x80, overlord_x_lo[2]);
+    overlord_gen2[i + 1] = y;
+    overlord_floor[i + 1] = y >> 8;
+  }
+  tmp_counter = 8;
+}
+
+void Ganon_SpawnSpiralBat(int k) {  // 9d8e7c
+  SpriteSpawnInfo info;
+  int j = Sprite_SpawnDynamicallyEx(k, 0xc9, &info, 8);
+  if (j < 0)
+    return;
+  Sprite_SetSpawnedCoordinates(j, &info);
+  sprite_anim_clock[j] = 4;
+  sprite_oam_flags[j] = 3;
+  sprite_flags3[j] = 0x40;
+  sprite_flags2[j] = 1;
+  sprite_defl_bits[j] = 0x80;
+  sprite_y_hi[j] = 128;
+  sprite_delay_main[j] = 48;
+  sprite_bump_damage[j] = 7;
+  sprite_ignore_projectile[j] = 7;
+}
+
+void Sprite_D6_Ganon(int k) {  // 9d8eb4
+  int j;
+
+  if (sign8(sprite_ai_state[k])) {
+    if (Sprite_ReturnIfInactive(k))
+      return;
+    if (!sprite_delay_main[k])
+      sprite_state[k] = 0;
+    if (!(sprite_delay_main[k] & 1))
+      Ganon_Draw(k);
+    return;
+  }
+
+  if (sprite_delay_aux4[k]) {
+    static const uint8 kGanon_GfxB[2] = { 16, 10 };
+    sprite_graphics[k] = kGanon_GfxB[sprite_D[k]];
+  }
+
+  if (byte_7E04C5 == 2 && byte_7E04C5 != sprite_room[k])
+    sprite_delay_aux1[k] = 64;
+
+  sprite_room[k] = byte_7E04C5;
+
+  Ganon_Draw(k);
+  if (sprite_delay_aux1[k]) {
+    sprite_graphics[k] = 15;
+    Ganon_EnableInvincibility(k);
+    Sprite_CheckDamageToAndFromLink(k);
+    return;
+  }
+
+  if (Sprite_ReturnIfInactive(k))
+    return;
+
+  if (sprite_delay_aux2[k] == 1)
+    Ganon_ExtinguishTorch();
+  else if (sprite_delay_aux2[k] == 16)
+    Ganon_ExtinguishTorch_adjust_translucency();
+
+  PairU8 pair = Sprite_IsRightOfLink(k);
+  static const uint8 kGanon_HeadDir0[2] = { 2, 0 };
+  sprite_head_dir[k] = (uint8)(pair.b + 32) < 64 ? 1 : kGanon_HeadDir0[pair.a];
+
+  if (sprite_delay_aux4[k]) {
+    sprite_ignore_projectile[k] = sprite_delay_aux4[k];
+    if (Sprite_ReturnIfRecoiling(k))
+      return;
+    sprite_delay_main[k] = 0;
+    return;
+  }
+
+  if (!(sprite_ignore_projectile[k] | flag_is_link_immobilized) && byte_7E04C5 == 2)
+    Sprite_CheckDamageToAndFromLink(k);
+  sprite_ignore_projectile[k] = 0;
+  switch (sprite_ai_state[k]) {
+  case 0:  //
+    if (sprite_delay_main[k] == 0) {
+      sprite_ai_state[k] = 1;
+      sprite_delay_main[k] = 128;
+    } else if (sprite_delay_main[k] == 32) {
+      music_control = 0x1f;
+    } else if (sprite_delay_main[k] == 64) {
+      dialogue_message_index = 0x16f;
+      Sprite_ShowMessageMinimal();
+    }
+    break;
+  case 1:  //
+    if (sprite_health[k] < 209)
+      sprite_health[k] = 208;
+    if (sprite_delay_main[k] < 64) {
+      static const uint8 kGanon_Gfx1[2] = { 2, 10 };
+      if (sprite_delay_main[k] == 0) {
+        Ganon_SelectWarpLocation(k, 5);
+      } else {
+        sprite_graphics[k] = kGanon_Gfx1[sprite_D[k]];
+      }
+    } else if (sprite_delay_main[k] != 64) {
+      Ganon_Phase1_AnimateTridentSpin(k);
+    } else {
+      static const int8 kGanon_X1[2] = { 24, -16 };
+      static const int8 kGanon_Y1[2] = { 4, 4 };
+      static const int8 kGanon_Xvel1[16] = { 32, 28, 24, 16, 0, -16, -24, -28, -32, -28, -24, -16, 0, 16, 24, 28 };
+      static const int8 kGanon_Yvel1[16] = { 0, 16, 24, 28, 32, 28, 24, 16, 0, -16, -24, -28, -32, -28, -24, -16 };
+      sprite_G[k] = 0;
+      SpriteSpawnInfo info;
+      int j = Sprite_SpawnDynamically(k, 0xc9, &info);
+      int i = sprite_D[k];
+      Sprite_SetX(j, info.r0_x + kGanon_X1[i]);
+      Sprite_SetY(j, info.r2_y + kGanon_Y1[i]);
+      Sprite_ApplySpeedTowardsLink(k, 31);
+      uint8 angle = Sprite_ConvertVelocityToAngle(sprite_x_vel[k], sprite_y_vel[k]);
+      sprite_x_vel[j] = kGanon_Xvel1[angle - 2 & 0xf];
+      sprite_y_vel[j] = kGanon_Yvel1[angle - 2 & 0xf];
+      sprite_delay_main[j] = 112;
+      sprite_anim_clock[j] = 2;
+      sprite_oam_flags[j] = 1;
+      sprite_flags2[j] = 4;
+      sprite_defl_bits[j] = 0x84;
+      sprite_D[j] = 2;
+      sprite_bump_damage[j] = 7;
+      sprite_ignore_projectile[j] = 7;
+    }
+    break;
+  case 2: {  //
+    static const uint8 kGanon_Gfx2_0[2] = { 0, 8 };
+    if (sprite_health[k] < 209)
+      sprite_health[k] = 208;
+    sprite_graphics[k] = kGanon_Gfx2_0[sprite_D[k]];
+    if (sprite_delay_main[k]) {
+      sprite_ignore_projectile[k]++;
+      if (sprite_delay_main[k] & 1)
+        sprite_graphics[k] = 255;
+    }
+    break;
+  }
+  case 3:  //
+    if (sprite_health[k] < 209)
+      sprite_health[k] = 208;
+    if (sprite_delay_main[k] != 0) {
+      Ganon_Phase1_AnimateTridentSpin(k);
+    } else {
+      sprite_ai_state[k] = 6;
+      sprite_delay_main[k] = 127;
+      Ganon_HandleAnimation_Idle(k);
+    }
+    break;
+  case 4:  //
+    if (sprite_health[k] < 209)
+      sprite_health[k] = 208;
+    if (sprite_delay_main[k] != 0)
+      Ganon_ShakeHead(k);
+    else
+      Ganon_SelectWarpLocation(k, 5);
+    break;
+  case 13:  //
+    sprite_health[k] = 100;
+    // fall through
+  case 5:  //
+  case 10:  //
+  case 18: { //
+    sprite_ignore_projectile[k]++;
+    uint16 x = sprite_x_hi[k] << 8 | swamola_target_x_lo[0];
+    uint16 y = sprite_y_hi[k] << 8 | swamola_target_y_lo[0];
+    if (Ganon_AttemptTridentCatch(x, y)) {
+      sprite_D[k] = sprite_subtype[k] >> 2;
+      if (sprite_ai_state[k] == 5) {
+        sprite_ai_state[k] = 2;
+        sprite_delay_main[k] = 32;
+      } else if (sprite_health[k] >= 161) {
+        sprite_ai_state[k] = 11;
+        sprite_delay_main[k] = 40;
+      } else if (sprite_health[k] >= 97) {
+        sprite_ai_state[k] = 14;
+        sprite_delay_main[k] = 40;
+      } else {
+        sprite_ai_state[k] = 17;
+        sprite_delay_main[k] = 104;
+      }
+    } else {
+      ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLocation(k, x, y, 32);
+      Sprite_ApproachTargetSpeed(k, pt.x, pt.y);
+      Sprite_MoveXY(k);
+      if (sprite_delay_main[k] == 0 || frame_counter & 1) {
+        sprite_graphics[k] = 255;
+        return;
+      }
+      static const uint8 kGanon_Gfx5[2] = { 2, 10 };
+      sprite_graphics[k] = kGanon_Gfx5[sprite_D[k]];
+      if (!(frame_counter & 7)) {
+        SpriteSpawnInfo info;
+        int j = Sprite_SpawnDynamically(k, 0xd6, &info);
+        if (j >= 0) {
+          Sprite_SetSpawnedCoordinates(j, &info);
+          sprite_ignore_projectile[j] = 24;
+          sprite_delay_main[j] = 24;
+          sprite_ai_state[j] = 255;
+          sprite_graphics[j] = sprite_graphics[k];
+          sprite_head_dir[j] = sprite_head_dir[k];
+        }
+      }
+    }
+    break;
+  }
+  case 6:  //
+    if (sprite_health[k] < 209)
+      sprite_health[k] = 208;
+    if (!sprite_delay_main[k]) {
+      if (sprite_health[k] >= 209) {
+        sprite_ai_state[k] = 1;
+        sprite_delay_main[k] = 128;
+      } else {
+        sprite_delay_main[k] = 255;
+        sprite_ai_state[k] = 7;
+      }
+    } else {
+      Ganon_ShakeHead(k);
+    }
+    break;
+  case 7:  //
+    if (sprite_health[k] < 161)
+      sprite_health[k] = 160;
+    overlord_x_lo[2] = 40;
+    if (!sprite_delay_main[k]) {
+      sprite_ai_state[k] = 8;
+      sprite_delay_main[k] = 255;
+    } else {
+      if (sprite_delay_main[k] < 0xc0 && (sprite_delay_main[k] & 0xf) == 0)
+        Ganon_SpawnSpiralBat(k);
+      Ganon_Phase1_AnimateTridentSpin(k);
+      Ganon_HandleFireBatCircle(k);
+    }
+    break;
+  case 8: {  //
+    static const int8 kGanon_Tab2[16] = { 0, 0, 0, 0, -1, -1, -2, -1, 0, 0, 0, 0, 1, 2, 1, 1 };
+    static const uint8 kGanon_Delay8[8] = { 0x10, 0x30, 0x50, 0x70, 0x90, 0xb0, 0xd0, 0xbd };
+
+    if (sprite_health[k] < 161)
+      sprite_health[k] = 160;
+    if (!sprite_delay_main[k]) {
+      sprite_ai_state[k] = 9;
+      sprite_delay_main[k] = 127;
+      Ganon_HandleAnimation_Idle(k);
+      for (int j = 8; j != 0; j--) {
+        sprite_ai_state[j] = 2;
+        sprite_delay_main[j] = kGanon_Delay8[j - 1];
+      }
+    } else {
+      overlord_x_lo[2] += kGanon_Tab2[sprite_delay_main[k] >> 4 & 15];
+      Ganon_Phase1_AnimateTridentSpin(k);
+      Ganon_HandleFireBatCircle(k);
+    }
+    break;
+  }
+  case 9:  //
+    if (sprite_health[k] < 161)
+      sprite_health[k] = 160;
+    if (!sprite_delay_main[k]) {
+      Ganon_SelectWarpLocation(k, 10);
+    } else {
+      Ganon_ShakeHead(k);
+    }
+    break;
+  case 11:  //
+    sprite_ignore_projectile[k]++;
+    Ganon_HandleAnimation_Idle(k);
+    if (!sprite_delay_main[k]) {
+      sprite_delay_main[k] = 255;
+      sprite_ai_state[k] = 7;
+    } else if (sprite_delay_main[k] & 1) {
+      sprite_graphics[k] = 255;
+    }
+    break;
+  case 12: { //
+    j = sprite_delay_main[k];
+    if (j == 0) {
+      Ganon_SelectWarpLocation(k, 13);
+      return;
+    }
+    int t = 0;
+    if (j < 96) {
+      t = 1;
+      if (j < 72) {
+        if (j == 66)
+          Ganon_Func1(k, 3);
+        t = 2;
+      }
+    }
+    if (sprite_D[k])
+      t += 3;
+    static const uint8 kGanon_Gfx12[6] = { 5, 6, 7, 13, 14, 10 };
+    sprite_graphics[k] = kGanon_Gfx12[t];
+    if ((sprite_hit_timer[k] & 127) == 1) {
+      sprite_ai_state[k] = 15;
+      sprite_z_vel[k] = 24;
+      sprite_delay_main[k] = 0;
+    }
+    break;
+  }
+  case 14:  //
+    sprite_ignore_projectile[k]++;
+    Ganon_HandleAnimation_Idle(k);
+    sprite_G[k] = 0;
+    if (!sprite_delay_main[k]) {
+      if (GetRandomNumber() & 1) {
+        Ganon_SelectWarpLocation(k, 13);
+      } else {
+        sprite_delay_main[k] = 127;
+        sprite_ai_state[k] = 12;
+      }
+    } else if (sprite_delay_main[k] & 1) {
+      sprite_graphics[k] = 255;
+    }
+    break;
+  case 15: {  //
+    static const uint8 kGanon_Gfx15[2] = { 6, 14 };
+    if (sprite_delay_main[k]) {
+      if (sprite_delay_main[k] == 1) {
+        sprite_ai_state[k] = 16;
+        sprite_z_vel[k] = 160;
+        return;
+      }
+    } else {
+      Sprite_MoveZ(k);
+      if (--sprite_z_vel[k] == 0)
+        sprite_delay_main[k] = 32;
+
+    }
+    sprite_graphics[k] = kGanon_Gfx15[sprite_D[k]];
+    break;
+  }
+  case 16: { //
+    bg1_y_offset = 0;
+    if (sprite_delay_main[k]) {
+      if (sprite_delay_main[k] == 1) {
+        sound_effect_ambient = 5;
+        Ganon_SelectWarpLocation(k, 13);
+        flag_is_link_immobilized = 0;
+        Ganon_SpawnFallingTilesOverlord(k);
+        if (sprite_anim_clock[k] >= 4) {
+          Ganon_SelectWarpLocation(k, 10);
+          sprite_health[k] = 96;
+          sprite_delay_aux2[k] = 224;
+          dialogue_message_index = 0x170;
+          Sprite_ShowMessageMinimal();
+        }
+      } else {
+        bg1_y_offset = (sprite_delay_main[k] - 1) & 1 ? -1 : 1;
+        flag_is_link_immobilized = 1;
+      }
+    } else {
+      static const uint8 kGanon_Gfx16[2] = { 2, 10 };
+
+      Sprite_MoveZ(k);
+      if (sign8(sprite_z[k])) {
+        sprite_z_vel[k] = 0;
+        sprite_z[k] = 0;
+        sprite_delay_main[k] = 96;
+        sound_effect_ambient = 7;
+        SpriteSfx_QueueSfx2WithPan(k, 0xc);
+      }
+      sprite_graphics[k] = kGanon_Gfx16[sprite_D[k]];
+    }
+    break;
+  }
+  case 17: {  //
+    static const uint8 kGanon_Gfx17b[2] = { 6, 14 };
+    static const uint8 kGanon_Gfx17[2] = { 7, 10 };
+    sprite_graphics[k] = kGanon_Gfx17b[sprite_D[k]];
+    if (!sprite_delay_main[k]) {
+      Ganon_SelectWarpLocation(k, 0x12);
+      return;
+    } else if (sprite_delay_main[k] == 52) {
+      Ganon_Func1(k, 5);
+    } else if (sprite_delay_main[k] < 52) {
+      sprite_graphics[k] = kGanon_Gfx17[sprite_D[k]];
+    }
+    if (sprite_delay_main[k] >= 72 || sprite_delay_main[k] < 40) {
+      sprite_ignore_projectile[k]++;
+      if (sprite_delay_main[k] & 1)
+        sprite_graphics[k] = 0xff;
+    }
+    Ganon_EnableInvincibility(k);
+    break;
+  }
+  case 19:  //
+    sprite_oam_flags[k] = 5;
+    sprite_flags[k] = 2;
+    if (!sprite_delay_main[k]) {
+      sprite_oam_flags[k] = 1;
+      Ganon_SelectWarpLocation(k, 18);
+      sprite_type[k] = 0xd6;
+      sprite_hit_timer[k] = 0;
+    } else {
+      static const uint8 kGanon_Gfx19[2] = { 5, 13 };
+      sprite_graphics[k] = kGanon_Gfx19[sprite_D[k]];
+    }
+    break;
+  }
+}
+
+void Ganon_EnableInvincibility(int k) {  // 9d8ffa
+  if ((sprite_hit_timer[k] & 127) == 26) {
+    sprite_hit_timer[k] = 0;
+    sprite_ai_state[k] = 19;
+    sprite_delay_main[k] = 127;
+    sprite_type[k] = 215;
+  }
+}
+
+void Ganon_SpawnFallingTilesOverlord(int k) {  // 9d90d0
+  static const uint8 kGanon_Ov_Type[4] = { 12, 13, 14, 15 };
+  static const uint8 kGanon_Ov_X[4] = { 0x18, 0xd8, 0xd8, 0x18 };
+  static const uint8 kGanon_Ov_Y[4] = { 0x28, 0x28, 0xd8, 0xd8 };
+
+  int j;
+  for (j = 7; j >= 0 && overlord_type[j] != 0; j--);
+
+  int t = sprite_anim_clock[k];
+  if (t >= 4)
+    return;
+  sprite_anim_clock[k] = t + 1;
+
+  overlord_type[j] = kGanon_Ov_Type[t];
+  overlord_x_lo[j] = kGanon_Ov_X[t];
+  overlord_x_hi[j] = link_x_coord >> 8;
+  overlord_y_lo[j] = kGanon_Ov_Y[t];
+  overlord_y_hi[j] = link_y_coord >> 8;
+  overlord_gen1[j] = 0;
+  overlord_gen2[j] = 0;
+}
+
+void Ganon_Func1(int k, int t) {  // 9d9162
+  tmp_counter = t;
+  SpriteSpawnInfo info;
+  int j = Sprite_SpawnDynamicallyEx(k, 0xC9, &info, 8);
+  if (j < 0)
+    return;
+  SpriteSfx_QueueSfx2WithPan(k, 0x2a);
+  Sprite_SetSpawnedCoordinates(j, &info);
+  sprite_ignore_projectile[j] = sprite_anim_clock[j] = t;
+  sprite_oam_flags[j] = 3;
+  sprite_flags3[j] = 0x40;
+  sprite_flags2[j] = 0x21;
+  sprite_defl_bits[j] = 0x40;
+  static const int8 kGanon_Gfx16_Y[2] = { 0, -16 };
+  Sprite_SetY(j, info.r2_y + kGanon_Gfx16_Y[sprite_D[k]]);
+  Sprite_ApplySpeedTowardsLink(j, 32);
+  sprite_delay_main[j] = 16;
+  sprite_A[j] = sprite_x_lo[0];
+  sprite_B[j] = sprite_x_hi[0];
+  sprite_C[j] = sprite_y_lo[0];
+  sprite_E[j] = sprite_y_hi[0];
+  sprite_bump_damage[j] = 7;
+  sprite_ignore_projectile[j] = 7;
+}
+
+void Ganon_Phase1_AnimateTridentSpin(int k) {  // 9d93db
+  static const uint8 kGanon_GfxFunc2[16] = { 0, 0, 1, 1, 0, 0, 1, 1, 8, 8, 9, 9, 8, 8, 9, 9 };
+
+  int j = (sprite_delay_main[k] >> 2 & 7) + (sprite_D[k] ? 8 : 0);
+  sprite_G[k] = kGanon_G_Func2[j];
+  sprite_graphics[k] = kGanon_GfxFunc2[j];
+  SwishEvery16Frames(k);
+}
+
+void Ganon_HandleAnimation_Idle(int k) {  // 9d9443
+  static const uint8 kGanon_G[2] = { 9, 10 };
+  static const uint8 kGanon_Gfx[2] = { 2, 10 };
+  sprite_G[k] = kGanon_G[sprite_D[k]];
+  sprite_graphics[k] = kGanon_Gfx[sprite_D[k]];
+}
+
+void Ganon_SelectWarpLocation(int k, int a) {  // 9d947f
+  int j;
+  static const uint8 kGanon_NextSubtype[32] = {
+    4, 5, 6, 7, 4, 5, 6, 7, 4, 5, 6, 7, 4, 5, 6, 7,
+    0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3,
+  };
+  static const uint8 kGanon_NextY[8] = { 0x40, 0x30, 0x30, 0x40, 0xb0, 0xc0, 0xc0, 0xb0 };
+  static const uint8 kGanon_NextX[8] = { 0x30, 0x50, 0xa0, 0xc0, 0x40, 0x60, 0x90, 0xb0 };
+
+  sprite_subtype[k] = j = kGanon_NextSubtype[GetRandomNumber() & 3 | sprite_subtype[k] << 2];
+  swamola_target_x_lo[0] = kGanon_NextX[j];
+  swamola_target_y_lo[0] = kGanon_NextY[j];
+  sprite_ai_state[k] = a;
+  sprite_x_vel[k] = sprite_y_vel[k] = 0;
+  sprite_delay_main[k] = 48;
+  SpriteSfx_QueueSfx3WithPan(k, 0x28);
+}
+
+void Ganon_ShakeHead(int k) {  // 9d94ba
+  static const uint8 kGanon_HeadDir[18] = {
+    0,  0, 0, 1, 2, 2, 2, 1, 0, 0, 0, 1, 1, 1, 1, 1,
+    0, 16,
+  };
+  sprite_head_dir[k] = kGanon_HeadDir[sprite_delay_main[k] >> 3];
+}
+
+void Ganon_Draw(int k) {  // 9d9adf
+  PrepOamCoordsRet info;
+  if (sign8(sprite_graphics[k]) ||
+      sprite_ai_state[k] != 19 && sprite_delay_aux4[k] == 0 && byte_7E04C5 == 0) {
+    Sprite_PrepOamCoordOrDoubleRet(k, &info);
+    return;
+  }
+  Trident_Draw(k);
+  if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
+    return;
+  OamEnt *oam = GetOamCurPtr() + 5;
+  int g = sprite_graphics[k];
+  for (int i = 0; i < 12; i++, oam++) {
+    int j = g * 12 + i;
+    SetOamPlain(oam, info.x + kGanon_Draw_X[j], info.y + kGanon_Draw_Y[j], kGanon_Draw_Char[j],
+                 info.flags | (kGanon_Draw_Flags[j] & ((info.flags & 0xf) >= 5 ? 0xf0 : 0xff)), 2);
+  }
+  static const uint8 kGanon_SprOffs[17] = {
+    1, 1, 1, 1, 1, 1, 15, 1, 4, 4, 4, 4, 4, 4, 4, 15, 15,
+  };
+  if (kGanon_SprOffs[g] != 15) {
+    oam = oam - 12 + kGanon_SprOffs[g];
+    int j = sprite_head_dir[k] * 2 + (sprite_D[k] ? 6 : 0);
+    oam[0].charnum = kGanon_Draw_Char2[j];
+    oam[0].flags = (oam[0].flags & 0x3f) | kGanon_Draw_Flags2[j];
+
+    oam[1].charnum = kGanon_Draw_Char2[j + 1];
+    oam[1].flags = (oam[1].flags & 0x3f) | kGanon_Draw_Flags2[j + 1];
+
+  }
+  if (submodule_index)
+    Sprite_CorrectOamEntries(k, 9, 0xff);
+
+  if (sprite_G[k] == 9) {
+    static const DrawMultipleData kGanon_Dmd[2] = {
+      {16, -3, 0x4c0a, 2},
+      {16,  5, 0x4c1a, 2},
+    };
+    oam_cur_ptr = 0x828, oam_ext_cur_ptr = 0xa2a;
+    Sprite_DrawMultiple(k, kGanon_Dmd, 2, NULL);
+  }
+
+  uint16 z = sprite_z[k] - 1;
+  int frame = (z >> 11) > 4 ? 4 : (z >> 11);
+  cur_sprite_y += z;
+  oam_cur_ptr = 0x9f4;
+  oam_ext_cur_ptr = 0xa9d;
+  uint8 bak = sprite_oam_flags[k];
+  sprite_oam_flags[k] = 0;
+  sprite_obj_prio[k] = 48;
+  Sprite_DrawMultiple(k, &kLargeShadow_Dmd[frame * 3], 3, NULL);
+  sprite_oam_flags[k] = bak;
+  Sprite_Get16BitCoords(k);
+}
+
+void Trident_Draw(int k) {  // 9d9c1c
+  static const DrawMultipleData kTrident_Dmd[50] = {
+  { 10, -10, 0x0864, 0},
+  {  5, -15, 0x0864, 0},
+  {  0, -20, 0x0864, 0},
+  { -5, -25, 0x0864, 0},
+  {-18, -38, 0x0844, 2},
+  {  1,  -4, 0x0865, 0},
+  {  1, -11, 0x0865, 0},
+  {  1, -18, 0x0865, 0},
+  {  1, -25, 0x0865, 0},
+  { -3, -40, 0x0862, 2},
+  { -8,  -9, 0x4864, 0},
+  { -3, -14, 0x4864, 0},
+  {  3, -20, 0x4864, 0},
+  {  9, -26, 0x4864, 0},
+  { 12, -37, 0x4844, 2},
+  {-10, -20, 0x4874, 0},
+  { -3, -20, 0x4874, 0},
+  {  4, -20, 0x4874, 0},
+  { 11, -20, 0x4874, 0},
+  { 18, -23, 0x4860, 2},
+  {-10, -30, 0xc864, 0},
+  { -4, -24, 0xc864, 0},
+  {  2, -18, 0xc864, 0},
+  {  8, -12, 0xc864, 0},
+  { 12,  -8, 0xc844, 2},
+  {  1, -32, 0x8865, 0},
+  {  1, -25, 0x8865, 0},
+  {  1, -18, 0x8865, 0},
+  {  1, -11, 0x8865, 0},
+  { -3,  -5, 0x8862, 2},
+  { 13, -30, 0x8864, 0},
+  {  8, -25, 0x8864, 0},
+  {  2, -19, 0x8864, 0},
+  { -4, -13, 0x8864, 0},
+  {-16,  -9, 0x8844, 2},
+  { 14, -20, 0x0874, 0},
+  {  7, -20, 0x0874, 0},
+  {  0, -20, 0x0874, 0},
+  { -7, -20, 0x0874, 0},
+  {-21, -23, 0x0860, 2},
+  { 13, -30, 0x8864, 0},
+  {  8, -25, 0x8864, 0},
+  {  2, -19, 0x8864, 0},
+  { -4, -13, 0x8864, 0},
+  {-16,  -9, 0x8844, 2},
+  {-10, -30, 0xc864, 0},
+  { -4, -24, 0xc864, 0},
+  { -4, -24, 0xc864, 0},
+  { -4, -24, 0xc864, 0},
+  { -4, -24, 0xc864, 0},
+  };
+  int g = sprite_G[k];
+  if (g == 0)
+    return;
+  static const int8 kTrident_Draw_X[5] = { 24, -16, 0, 16, -8 };
+  static const int8 kTrident_Draw_Y[5] = { 4, 4, 16, 21, 19 };
+
+  int j = sprite_G[k] == 9 ? 3 :
+          sprite_G[k] >= 9 ? 4 : sprite_D[k];
+  cur_sprite_x += kTrident_Draw_X[j];
+  cur_sprite_y += kTrident_Draw_Y[j];
+  uint8 bak = sprite_obj_prio[k];
+  sprite_obj_prio[k] &= ~0xf;
+  Sprite_DrawMultiple(k, &kTrident_Dmd[(g - 1) * 5], 5, NULL);
+  sprite_obj_prio[k] = bak;
+  Sprite_Get16BitCoords(k);
+}
+
+void SpritePrep_Swamola_InitializeSegments(int k) {  // 9d9c80
+  int j;
+
+  // The snes code uses the wrong bank.. Causes glitches with lanmolas in misery mire
+  if (enhanced_features0 & kFeatures0_MiscBugFixes) {
+    j = k * 32;
+  } else {
+    static const uint8 kBuggySwamolaLookup[6] = { 0x1c, 0xa9, 0x03, 0x9d, 0x90, 0x0d };  // wrong bank
+    j = kBuggySwamolaLookup[k];
+  }
+  for (int i = 0; i < 32; i++, j++) {
+    swamola_x_lo[j] = sprite_x_lo[k];
+    swamola_x_hi[j] = sprite_x_hi[k];
+    swamola_y_lo[j] = sprite_y_lo[k];
+    swamola_y_hi[j] = sprite_y_hi[k];
+  }
+}
+
+void Sprite_CF_Swamola(int k) {  // 9d9cb0
+  static const uint8 kSwamola_Target_Dir[8] = {1, 2, 3, 4, 5, 6, 7, 8};
+  static const int8 kSwamola_Target_X[9] = {0, 0, 32, 32, 32, 0, -32, -32, -32};
+  static const int8 kSwamola_Target_Y[9] = {0, -32, -32, 0, 32, 32, 32, 0, -32};
+  int j;
+
+  if (sprite_ai_state[k]) {
+    if (sign8(sprite_ai_state[k])) {
+      Sprite_Swamola_Ripples(k);
+      return;
+    }
+    Swamola_Draw(k);
+  }
+  Sprite_Get16BitCoords(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  sprite_subtype2[k]++;
+  Sprite_CheckDamageToAndFromLink(k);
+  uint8 old_vel = sprite_y_vel[k];
+  sprite_y_vel[k] += sprite_z_vel[k];
+  Sprite_MoveXY(k);
+  sprite_y_vel[k] = old_vel;
+  switch(sprite_ai_state[k]) {
+  case 0: {  // emerge
+    if (!sprite_delay_main[k] && (j = kSwamola_Target_Dir[GetRandomNumber() & 7]) != sprite_D[k]) {
+      int t = (sprite_B[k] << 8 | sprite_A[k]) + kSwamola_Target_X[j];
+      swamola_target_x_lo[k] = t, swamola_target_x_hi[k] = t >> 8;
+      t = (sprite_head_dir[k] << 8 | sprite_C[k]) + kSwamola_Target_Y[j];
+      swamola_target_y_lo[k] = t, swamola_target_y_hi[k] = t >> 8;
+      sprite_ai_state[k] = 1;
+      sprite_x_vel[k] = sprite_y_vel[k] = 0;
+      sprite_z_vel[k] = -15;
+      Swamola_SpawnRipples(k);
+    }
+    break;
+  }
+  case 1:  // ascending
+    if (!(sprite_subtype2[k] & 3)) {
+      if (!++sprite_z_vel[k])
+        sprite_ai_state[k] = 2;
+      ProjectSpeedRet pt = Swamola_ProjectVelocityTowardsTarget(k);
+      Sprite_ApproachTargetSpeed(k, pt.x, pt.y);
+    }
+    break;
+  case 2: {  // wiggle
+    static const int8 kSwamola_Z_Accel[2] = {2, -2};
+    static const int8 kSwamola_Z_Vel_Target[2] = {12, -12};
+    int j = sprite_G[k] & 1;
+    sprite_z_vel[k] += kSwamola_Z_Accel[j];
+    if (sprite_z_vel[k] == (uint8)kSwamola_Z_Vel_Target[j])
+      sprite_G[k]++;
+    uint16 x = swamola_target_x_hi[k] << 8 | swamola_target_x_lo[k];
+    uint16 y = swamola_target_y_hi[k] << 8 | swamola_target_y_lo[k];
+    if ((uint16)(cur_sprite_x - x + 8) < 16 && (uint16)(cur_sprite_y - y + 8) < 16)
+      sprite_ai_state[k] = 3;
+    ProjectSpeedRet pt = Swamola_ProjectVelocityTowardsTarget(k);
+    sprite_x_vel[k] = pt.x;
+    sprite_y_vel[k] = pt.y;
+    break;
+  }
+  case 3:  // descending
+    if (!(sprite_subtype2[k] & 3) && ++sprite_z_vel[k] == 16) {
+      sprite_ai_state[k] = 4;
+      Swamola_SpawnRipples(k);
+      sprite_y_hi[k] = 128;
+      sprite_delay_main[k] = 80;
+    }
+    if (!(sprite_subtype2[k] & 3))
+      Sprite_ApproachTargetSpeed(k, 0, 0);
+    break;
+  case 4:  // submerge
+    if (!sprite_delay_main[k]) {
+      sprite_D[k] = j = kSwamola_Target_Dir[GetRandomNumber() & 7];
+      Sprite_SetX(k, (sprite_B[k] << 8 | sprite_A[k]) + kSwamola_Target_X[j]);
+      Sprite_SetY(k, (sprite_head_dir[k] << 8 | sprite_C[k]) + kSwamola_Target_Y[j]);
+      sprite_ai_state[k] = 0;
+      sprite_delay_main[k] = 48;
+      sprite_x_vel[k] = sprite_y_vel[k] = 0;
+      sprite_z_vel[k] = 0;
+    }
+    break;
+  }
+}
+
+ProjectSpeedRet Swamola_ProjectVelocityTowardsTarget(int k) {  // 9d9e13
+  uint16 x = swamola_target_x_hi[k] << 8 | swamola_target_x_lo[k];
+  uint16 y = swamola_target_y_hi[k] << 8 | swamola_target_y_lo[k];
+  return Sprite_ProjectSpeedTowardsLocation(k, x, y, 15);
+}
+
+void Swamola_SpawnRipples(int k) {  // 9d9eaa
+  SpriteSpawnInfo info;
+  int j = Sprite_SpawnDynamically(k, 0xcf, &info);
+  if (j >= 0) {
+    Sprite_SetSpawnedCoordinates(j, &info);
+    sprite_ai_state[j] = 128;
+    sprite_delay_main[j] = 32;
+    sprite_oam_flags[j] = 4;
+    sprite_ignore_projectile[j] = 4;
+    sprite_flags2[j] = 0;
+  }
+}
+
+void Sprite_Swamola_Ripples(int k) {  // 9d9ece
+  SwamolaRipples_Draw(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  if (!sprite_delay_main[k])
+    sprite_state[k] = 0;
+}
+
+void SwamolaRipples_Draw(int k) {  // 9d9f1d
+  static const DrawMultipleData kSwamolaRipples_Dmd[8] = {
+    {0, 4, 0x00d8, 0},
+    {8, 4, 0x40d8, 0},
+    {0, 4, 0x00d9, 0},
+    {8, 4, 0x40d9, 0},
+    {0, 4, 0x00da, 0},
+    {8, 4, 0x40da, 0},
+    {0, 4, 0x00d9, 0},
+    {8, 4, 0x40d9, 0},
+  };
+  Oam_AllocateFromRegionB(8);
+  Sprite_DrawMultiple(k, &kSwamolaRipples_Dmd[(sprite_delay_main[k] >> 2 & 3) * 2], 2, NULL);
+}
+
+void Swamola_Draw(int k) {  // 9d9f64
+  static const uint8 kSwamola_Gfx[16] = {7, 6, 5, 4, 3, 4, 5, 6, 7, 6, 5, 4, 3, 4, 5, 6};
+  static const uint8 kSwamola_Gfx2[4] = {0, 0, 1, 2};
+  static const uint8 kSwamola_Draw_OamFlags[16] = {0xc0, 0xc0, 0xc0, 0xc0, 0x80, 0x80, 0x80, 0x80, 0, 0, 0, 0, 0, 0x40, 0x40, 0x40};
+  static const uint8 kSwamola_HistOffs[4] = {8, 16, 22, 26};
+  int j = Sprite_ConvertVelocityToAngle(sprite_x_vel[k], sprite_y_vel[k] + sprite_z_vel[k]);
+  sprite_graphics[k] = kSwamola_Gfx[j];
+  sprite_oam_flags[k] = sprite_oam_flags[k] & 63 | kSwamola_Draw_OamFlags[j];
+  SpriteDraw_SingleLarge(k);
+  j = (sprite_subtype2[k] & 0x1f) + k * 32;
+  swamola_x_lo[j] = sprite_x_lo[k];
+  swamola_x_hi[j] = sprite_x_hi[k];
+  swamola_y_lo[j] = sprite_y_lo[k];
+  swamola_y_hi[j] = sprite_y_hi[k];
+  j = sign8(sprite_y_vel[k]) ? 5 : 0;
+  int delta = sign8(sprite_y_vel[k]) ? -1 : 1;
+  oam_cur_ptr += j * 4, oam_ext_cur_ptr += j;
+  for (int i = 0; i < 4; i++) {
+    sprite_graphics[k] = kSwamola_Gfx2[i];
+    j = (sprite_subtype2[k] - kSwamola_HistOffs[i] & 31) + k * 32;
+    cur_sprite_x = swamola_x_hi[j] << 8 | swamola_x_lo[j];
+    cur_sprite_y = swamola_y_hi[j] << 8 | swamola_y_lo[j];
+    oam_cur_ptr += delta * 4, oam_ext_cur_ptr += delta;
+    SpriteDraw_SingleLarge(k);
+  }
+  byte_7E0FB6 = 4;
+}
+
+void SpritePrep_Blind_PrepareBattle(int k) {  // 9da081
+  if (follower_indicator != 6 && dung_savegame_state_bits & 0x2000) {
+    sprite_delay_aux2[k] = 96;
+    sprite_C[k] = 1;
+    sprite_D[k] = 2;
+    sprite_head_dir[k] = 4;
+    sprite_graphics[k] = 7;
+    byte_7E0B69 = 0;
+  } else {
+    sprite_state[k] = 0;
+  }
+}
+
+void BlindLaser_SpawnTrailGarnish(int j) {  // 9da0b1
+  int k = GarnishAllocOverwriteOld();
+  garnish_type[k] = 15;
+  garnish_active = 15;
+  garnish_oam_flags[k] = sprite_graphics[j];
+  garnish_sprite[k] = j;
+  garnish_x_lo[k] = sprite_x_lo[j];
+  garnish_x_hi[k] = sprite_x_hi[j];
+  uint16 y = Sprite_GetY(j) + 16;
+  garnish_y_lo[k] = y;
+  garnish_y_hi[k] = y >> 8;
+  garnish_countdown[k] = 10;
+}
+
+void Sprite_Blind_Head(int k) {  // 9da118
+  static const uint8 kBlindHead_XposLimit[2] = {0x98, 0x58};
+  static const uint8 kBlindHead_YposLimit[2] = {0xb0, 0x50};
+  static const int8 kBlindHead_YvelLimit[2] = {24, -24};
+  static const int8 kBlindHead_XvelLimit[2] = {32, -32};
+
+  sprite_obj_prio[k] |= 48;
+  SpriteDraw_SingleLarge(k);
+  OamEnt *oam = GetOamCurPtr();
+  int j = sprite_head_dir[k];
+  oam->charnum = kBlindHead_Draw_Char[j];
+  oam->flags = oam->flags & 0x3f | kBlindHead_Draw_Flags[j];
+
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  if (sprite_F[k] == 14)
+    sprite_F[k] = 8;
+  if (Sprite_ReturnIfRecoiling(k))
+    return;
+  if (sign8(--sprite_subtype[k])) {
+    sprite_subtype[k] = 2;
+    sprite_head_dir[k] = sprite_head_dir[k] + 1 & 15;
+  }
+  if (sprite_delay_main[k])
+    return;
+  Sprite_CheckDamageToAndFromLink(k);
+  sprite_subtype2[k]++;
+  j = Blind_SpitFireball(k, 0x1f);
+  if (j >= 0 && sign8(--sprite_z_subpos[k])) {
+    sprite_z_subpos[k] = 4;
+    ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLink(k, 32);
+    sprite_x_vel[j] = pt.x;
+    sprite_y_vel[j] = pt.y;
+  }
+  j = sprite_G[k] & 1;
+  if (sprite_x_vel[k] != (uint8)kBlindHead_XvelLimit[j])
+    sprite_x_vel[k] += j ? -1 : 1;
+  if ((sprite_x_lo[k] & ~1) == kBlindHead_XposLimit[j])
+    sprite_G[k]++;
+  j = sprite_anim_clock[k] & 1;
+  if (sprite_y_vel[k] != (uint8)kBlindHead_YvelLimit[j])
+    sprite_y_vel[k] += j ? -1 : 1;
+  if ((sprite_y_lo[k] & ~1) == kBlindHead_YposLimit[j])
+    sprite_anim_clock[k]++;
+  if (!sprite_F[k])
+    Sprite_MoveXY(k);
+}
+
+void Blind_SpawnHead(int k) {  // 9da1ed
+  SpriteSpawnInfo info;
+  int j = Sprite_SpawnDynamically(k, 0xce, &info);
+  if (j >= 0) {
+    Sprite_SetSpawnedCoordinates(j, &info);
+    sprite_flags3[j] = 0x5b;
+    sprite_oam_flags[j] = 0x5b & 15;
+    sprite_defl_bits[j] = 4;
+    sprite_A[j] = 2;
+    sprite_flags2[j] = 1;
+    sprite_flags4[j] = 0;
+    sprite_flags[j] = 0;
+    sprite_z[j] = 23;
+    sprite_y_lo[j] = 23 + info.r2_y;
+    sprite_G[j] = (info.r0_x >> 7) & 1;
+    sprite_anim_clock[j] = (info.r2_y >> 7) & 1;
+    sprite_delay_main[j] = 48;
+  }
+}
+
+void Sprite_CE_Blind(int k) {  // 9da263
+  if (sign8(sprite_A[k]))
+    Sprite_BlindLaser(k);
+  else if (sprite_A[k] == 2)
+    Sprite_Blind_Head(k);
+  else
+    Sprite_Blind_Blind_Blind(k);
+}
+
+void Sprite_BlindLaser(int k) {  // 9da268
+  static const uint8 kBlindLaser_Gfx[16] = {7, 7, 8, 9, 10, 9, 8, 7, 7, 7, 8, 9, 10, 9, 8, 7};
+  static const uint8 kBlindLaser_OamFlags[16] = {0, 0, 0, 0, 0, 0x40, 0x40, 0x40, 0x40, 0x40, 0xc0, 0xc0, 0x80, 0x80, 0x80, 0x80};
+  int j = sprite_head_dir[k];
+  sprite_graphics[k] = kBlindLaser_Gfx[j];
+  sprite_oam_flags[k] = kBlindLaser_OamFlags[j] | 3;
+  PrepOamCoordsRet info;
+  Sprite_PrepOamCoord(k, &info);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  if (sprite_delay_main[k]) {
+    if (sprite_delay_main[k] == 1)
+      sprite_state[k] = 0;
+    return;
+  }
+  Sprite_CheckDamageToLink_same_layer(k);
+  Sprite_SetX(k, Sprite_GetX(k) + (int8)sprite_x_vel[k]);
+  Sprite_SetY(k, Sprite_GetY(k) + (int8)sprite_y_vel[k]);
+  if (Sprite_CheckTileCollision(k))
+    sprite_delay_main[k] = 12;
+  BlindLaser_SpawnTrailGarnish(k);
+}
+
+void Sprite_Blind_Blind_Blind(int k) {  // 9da2d2
+  int j;
+
+  sprite_obj_prio[k] |= 0x30;
+  Blind_Draw(k);
+  sprite_oam_flags[k] = 1;
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  uint8 a = sprite_F[k];
+  if (a)
+    sprite_F[k]--;
+
+  if (a == 11) {
+    sprite_hit_timer[k] = 0;
+    sprite_wallcoll[k] = 0;
+    if (!sprite_delay_aux4[k]) {
+      sprite_health[k] = 128;
+      sprite_delay_aux4[k] = 48;
+      sprite_oam_flags[k] &= 1;
+      if (++sprite_z_subpos[k] < 3) {
+        sprite_wallcoll[k] = 96;
+        sprite_subtype[k] = 1;
+      } else {
+        sprite_z_subpos[k] = 0;
+        if (++sprite_limit_instance == 3) {
+          Sprite_KillFriends();
+          sprite_state[k] = 4;
+          sprite_A[k] = 0;
+          sprite_delay_main[k] = 255;
+          sprite_hit_timer[k] = 255;
+          flag_block_link_menu++;
+          SpriteSfx_QueueSfx3WithPan(k, 0x22);
+          return;
+        }
+        sprite_y_vel[k] = sprite_x_vel[k] = 0;
+        sprite_C[k] = 6;
+        sprite_delay_aux2[k] = 255;
+        sprite_ignore_projectile[k] = 255;
+        Blind_SpawnHead(k);
+      }
+    }
+  }
+
+  if (sprite_A[k]) {
+    static const uint8 kBlind_Gfx0[7] = {20, 19, 18, 17, 16, 15, 15};
+    if (!sprite_delay_main[k])
+      sprite_state[k] = 0;
+    sprite_graphics[k] = kBlind_Gfx0[sprite_delay_main[k] >> 3];
+    return;
+  }
+  if (!(++sprite_subtype2[k] & 1))
+    sprite_delay_main[k]++;
+
+  if (sprite_delay_aux1[k]) {
+    sprite_ai_state[k] = 0;
+    if (sprite_delay_aux1[k] == 8)
+      Blind_SpawnLaser(k);
+    Blind_CheckBumpDamage(k);
+    return;
+  }
+  byte_7E0B69++;
+  if (!sprite_stunned[k]) {
+    if (sprite_ai_state[k]) {
+      sprite_delay_aux1[k] = 16;
+      sprite_stunned[k] = 128;
+      sprite_ai_state[k] = 0;
+    }
+  } else {
+    sprite_stunned[k]--;
+    sprite_ai_state[k] = 0;
+  }
+  sprite_x_hi[k] = HIBYTE(link_x_coord);
+  sprite_y_hi[k] = HIBYTE(link_y_coord);
+  switch(sprite_C[k]) {
+  case 0:  // blinded
+    BYTE(dma_var6) = 0;
+    BYTE(dma_var7) = 0xA0;
+    if (sprite_delay_aux2[k] == 0) {
+      sprite_C[k]++;
+      sprite_delay_aux2[k] = 96;
+    } else if (sprite_delay_aux2[k] == 80) {
+      dialogue_message_index = 0x123;
+      Sprite_ShowMessageMinimal();
+    } else if (sprite_delay_aux2[k] == 24) {
+      SpawnBossPoof(k);
+    }
+    break;
+  case 1:  // retreat to back wall
+    Blind_CheckBumpDamage(k);
+    sprite_graphics[k] = 9;
+    if (sprite_delay_aux2[k] == 0) {
+      sprite_C[k]++;
+      sprite_delay_main[k] = 255;
+      sprite_ignore_projectile[k] = 0;
+    } else if (sprite_delay_aux2[k] < 64) {
+      sprite_y_vel[k] = -8;
+      Sprite_MoveY(k);
+    }
+    Blind_Animate(k);
+    sprite_head_dir[k] = 4;
+    break;
+  case 2: { // oscillate
+    static const int8 kBlind_Oscillate_YVelTarget[2] = {18, -18};
+    static const int8 kBlind_Oscillate_XVelTarget[2] = {24, -24};
+    static const uint8 kBlind_Oscillate_XPosTarget[2] = {164, 76};
+    Blind_CheckBumpDamage(k);
+    Blind_Animate(k);
+    if ((!(sprite_subtype2[k] & 127) && Sprite_IsBelowLink(k).a + 2 != sprite_D[k] || sprite_delay_main[k] == 0) && sprite_x_lo[k] < 0x78) {
+      sprite_C[k]++;
+      sprite_y_vel[k] &= ~1;
+      sprite_x_vel[k] &= ~1;
+      sprite_delay_aux2[k] = 0x30;
+      return;
+    }
+    j = sprite_B[k] & 1;
+    sprite_y_vel[k] += j ? -1 : 1;
+    if (sprite_y_vel[k] == (uint8)kBlind_Oscillate_YVelTarget[j])
+      sprite_B[k]++;
+    j = sprite_G[k] & 1;
+    if (sprite_x_vel[k] != (uint8)kBlind_Oscillate_XVelTarget[j])
+      sprite_x_vel[k] += j ? -1 : 1;
+    if ((sprite_x_lo[k] & ~1) == kBlind_Oscillate_XPosTarget[j])
+      sprite_G[k]++;
+    Sprite_MoveXY(k);
+    if (sprite_wallcoll[k]) {
+      Blind_FireballFlurry(k, sprite_wallcoll[k]);
+    } else if (!(sprite_subtype2[k] & 7)) {
+      Sprite_SpawnProbeAlways(k, sprite_head_dir[k] << 2);
+    }
+    break;
+  }
+  case 3:  // switch walls
+    Blind_CheckBumpDamage(k);
+    if (sprite_delay_aux2[k]) {
+      Blind_Decelerate_X(k);
+      Sprite_MoveX(k);
+      Blind_Decelerate_Y(k);
+    } else {
+      static const int8 kBlind_SwitchWall_YVelTarget[2] = {64, -64};
+      static const uint8 kBlind_SwitchWall_YPosTarget[2] = {0x90, 0x50};
+      j = sprite_D[k] - 2;
+      if (sprite_y_vel[k] != (uint8)kBlind_SwitchWall_YVelTarget[j])
+        sprite_y_vel[k] += j ? -2 : 2;
+      if ((sprite_y_lo[k] & ~3) == kBlind_SwitchWall_YPosTarget[j]) {
+        sprite_C[k]++;
+        sprite_B[k] = sprite_D[k] - 1;
+      }
+      Sprite_MoveXY(k);
+      Blind_Decelerate_X(k);
+    }
+    break;
+  case 4: { // whirl around
+    Blind_CheckBumpDamage(k);
+    if (!(sprite_subtype2[k] & 7)) {
+      static const uint8 kBlind_WhirlAround_Gfx[2] = {0, 9};
+      j = sprite_D[k] - 2;
+      if (sprite_graphics[k] == kBlind_WhirlAround_Gfx[j]) {
+        sprite_delay_main[k] = 254;
+        sprite_C[k] = 2;
+        sprite_D[k] ^= 1;
+        sprite_G[k] = sprite_x_lo[k] >> 7;
+      } else {
+        sprite_graphics[k] += j ? 1 : -1;
+      }
+    }
+    Blind_Decelerate_Y(k);
+    break;
+  }
+  case 5:  // fireball reprisal
+    Blind_FireballFlurry(k, 0x65); // wtf: argument
+    break;
+  case 6:  // behind the curtain
+    sprite_hit_timer[k] = 0;
+    sprite_head_dir[k] = 12;
+    if (sprite_delay_aux2[k] == 0) {
+      sprite_C[k]++;
+      sprite_delay_aux2[k] = 39;
+      SpriteSfx_QueueSfx1WithPan(k, 0x13);
+    } else if (sprite_delay_aux2[k] >= 224) {
+      static const uint8 kBlind_Gfx_BehindCurtain[4] = {14, 13, 12, 10};
+      sprite_graphics[k] = kBlind_Gfx_BehindCurtain[(sprite_delay_aux2[k] - 224) >> 3];
+    } else {
+      sprite_graphics[k] = 14;
+    }
+    break;
+  case 7:  // rerobe
+    if (sprite_delay_aux2[k] == 0) {
+      sprite_C[k] = 2;
+      sprite_delay_main[k] = 128;
+      sprite_D[k] = (sprite_y_lo[k] >> 7) + 2;
+      sprite_G[k] = (sprite_x_lo[k] << 2) | (sprite_x_lo[k] >> 7);
+      sprite_x_vel[k] = sprite_y_vel[k] = 0;
+      sprite_ignore_projectile[k] = 0;
+    } else {
+      static const uint8 kBlind_Gfx_Rerobe[5] = {10, 11, 12, 13, 14};
+      sprite_graphics[k] = kBlind_Gfx_Rerobe[sprite_delay_aux2[k] >> 3];
+    }
+    break;
+  }
+
+
+}
+
+void Blind_FireballFlurry(int k, uint8 a) {  // 9da465
+  sprite_wallcoll[k]--;
+  sprite_oam_flags[k] = (a & 7) * 2 + 1;
+  if (sign8(--sprite_E[k])) {
+    sprite_E[k] = sprite_subtype[k];
+    sprite_head_dir[k] = sprite_head_dir[k] + 1 & 15;
+  }
+  if (!(sprite_subtype2[k] & 31) && sprite_subtype[k] != 5)
+    sprite_subtype[k]++;
+  Blind_AnimateRobes(k);
+  Blind_SpitFireball(k, 0xf);
+}
+
+int Blind_SpitFireball(int k, uint8 a) {  // 9da49d
+  static const int8 kBlindHead_SpawnFireball_Xvel[16] = {-32, -28, -24, -16, 0, 16, 24, 28, 32, 28, 24, 16, 0, -16, -24, -28};
+  static const int8 kBlindHead_SpawnFireball_Yvel[16] = {0, 16, 24, 28, 32, 28, 24, 16, 0, -16, -24, -28, -32, -28, -24, -16};
+  if (sprite_subtype2[k] & a)
+    return -1;
+  int j = Sprite_SpawnFireball(k);
+  if (j >= 0) {
+    SpriteSfx_QueueSfx3WithPan(k, 0x19);
+    int i = sprite_head_dir[k];
+    sprite_x_vel[j] = kBlindHead_SpawnFireball_Xvel[i];
+    sprite_y_vel[j] = kBlindHead_SpawnFireball_Yvel[i];
+    sprite_defl_bits[j] |= 8;
+    sprite_bump_damage[j] = 4;
+  }
+  return j;
+}
+
+int SpawnBossPoof(int k) {  // 9da4f9
+  SpriteSpawnInfo info;
+  int j = Sprite_SpawnDynamically(k, 0xce, &info);
+  Sprite_SetX(j, info.r0_x + 16);
+  Sprite_SetY(j, info.r2_y + 40);
+  sprite_graphics[j] = 0xf;
+  sprite_A[j] = 1;
+  sprite_delay_main[j] = 47;
+  sprite_flags2[j] = 9;
+  sprite_ignore_projectile[j] = 9;
+  sound_effect_1 = 12;
+  return j;
+}
+
+void Blind_Decelerate_X(int k) {  // 9da647
+  if (sprite_x_vel[k] != 0)
+    sprite_x_vel[k] += sign8(sprite_x_vel[k]) ? 2 : -2;
+  Blind_AnimateRobes(k);
+  if (sprite_wallcoll[k])
+    Blind_FireballFlurry(k, sprite_wallcoll[k]);
+}
+
+void Blind_Decelerate_Y(int k) {  // 9da6a4
+  if (sprite_y_vel[k] != 0)
+    sprite_y_vel[k] += sign8(sprite_y_vel[k]) ? 4 : -4;
+  Sprite_MoveY(k);
+  if (sprite_wallcoll[k])
+    Blind_FireballFlurry(k, sprite_wallcoll[k]);
+}
+
+void Blind_CheckBumpDamage(int k) {  // 9da6c0
+  if (!(sprite_delay_aux4[k] | sprite_F[k]))
+    Sprite_CheckDamageToAndFromLink(k);
+  if ((uint16)(link_x_coord - cur_sprite_x + 14) < 28 &&
+      (uint16)(link_y_coord - cur_sprite_y) < 28 &&
+      !(countdown_for_blink | link_disable_sprite_damage)) {
+    link_auxiliary_state = 1;
+    link_give_damage = 8;
+    link_incapacitated_timer = 16;
+    link_actual_vel_x ^= 255;
+    link_actual_vel_y ^= 255;
+  }
+}
+
+void Blind_Animate(int k) {  // 9da6ef
+  static const uint8 kBlind_HeadDir[17] = {0, 1, 2, 3, 4, 3, 2, 1, 0, 15, 14, 13, 12, 13, 14, 15, 0};
+  static const uint8 kBlind_Animate_Tab[8] = {0, 1, 1, 2, 2, 3, 3, 4};
+
+  if (!sprite_wallcoll[k]) {
+    int t1 = kBlind_Animate_Tab[BYTE(link_x_coord) >> 5];
+    t1 = (sprite_D[k] == 3) ? -t1 : t1;
+    int t0 = (sprite_D[k] - 2) * 8;
+    int idx = (byte_7E0B69 >> 3 & 7) + (byte_7E0B69 >> 2 & 1) + t0;
+    sprite_head_dir[k] = (kBlind_HeadDir[idx] + t1) & 15;
+  }
+  Blind_AnimateRobes(k);
+}
+
+void Blind_AnimateRobes(int k) {  // 9da729
+  static const uint8 kBlind_Gfx_Animate[8] = {7, 8, 9, 8, 0, 1, 2, 1};
+  sprite_graphics[k] = kBlind_Gfx_Animate[(sprite_subtype2[k] >> 3 & 3) + ((sprite_D[k] - 2) << 2)];
+}
+
+void Blind_SpawnLaser(int k) {  // 9da765
+  static const int8 kBlind_Laser_Xvel[16] = {-8, -8, -8, -4, 0, 4, 8, 8, 8, 8, 8, 4, 0, -4, -8, -8};
+  static const int8 kBlind_Laser_Yvel[16] = {0, 0, 4, 8, 8, 8, 4, 0, 0, 0, -4, -8, -8, -8, -4, 0};
+  SpriteSpawnInfo info;
+  int j = Sprite_SpawnDynamically(k, 0xce, &info), i;
+  if (j >= 0) {
+    sound_effect_2 = Sprite_CalculateSfxPan(k) | 0x26;
+    Sprite_SetSpawnedCoordinates(j, &info);
+    sprite_x_lo[j] = info.r0_x + 4;
+    sprite_head_dir[j] = i = sprite_head_dir[k];
+    sprite_x_vel[j] = kBlind_Laser_Xvel[i];
+    sprite_y_vel[j] = kBlind_Laser_Yvel[i];
+    sprite_A[j] = 128;
+    sprite_ignore_projectile[j] = 128;
+    sprite_flags2[j] = 0x40;
+    sprite_flags4[j] = 0x14;
+  }
+}
+
+void Blind_Draw(int k) {  // 9dac6c
+
+  if (sprite_graphics[k] >= 15) {
+    static const DrawMultipleData kBlindPoof_Dmd[37] = {
+      {-16, -20, 0x0586, 2},
+      {-11, -28, 0x0586, 2},
+      {-23, -26, 0x0586, 2},
+      { -8, -17, 0x0586, 2},
+      {-20, -13, 0x0586, 2},
+      {-16, -37, 0x0586, 2},
+      {-27, -31, 0x0586, 2},
+      {-10, -28, 0x0586, 2},
+      { -5, -28, 0x0586, 2},
+      {-20, -27, 0x0586, 2},
+      {-27, -17, 0x0586, 2},
+      { -4, -17, 0x0586, 2},
+      {-16, -13, 0x0586, 2},
+      {-18, -37, 0x458a, 2},
+      { -5, -33, 0x458a, 2},
+      {-32, -32, 0x058a, 2},
+      {-23, -31, 0x458a, 2},
+      {-15, -24, 0x458a, 2},
+      {-23, -31, 0x458a, 2},
+      {-15, -24, 0x458a, 2},
+      {-29, -22, 0x058a, 2},
+      { -5, -22, 0x058a, 2},
+      {-16, -14, 0x058a, 2},
+      {-12, -32, 0x458a, 2},
+      {-26, -29, 0x458a, 2},
+      { -6, -22, 0x458a, 2},
+      {-19, -20, 0x058a, 2},
+      {-26, -29, 0x458a, 2},
+      { -6, -22, 0x458a, 2},
+      {-19, -20, 0x058a, 2},
+      {-17, -27, 0x059b, 0},
+      {-10, -26, 0x059b, 0},
+      {  0, -22, 0x459b, 0},
+      {-19, -16, 0x459b, 0},
+      { -6, -12, 0x059b, 0},
+      {  0,  13, 0x0b20, 2},
+      {  0,  23, 0x0b22, 2},
+    };
+    static const uint8 kOffs[] = { 0, 1, 5, 13, 23, 30, 35, 37 };
+    int j = sprite_graphics[k] - 15;
+    Sprite_DrawMultiple(k, &kBlindPoof_Dmd[kOffs[j]], kOffs[j + 1] - kOffs[j], NULL);
+    return;
+  }
+  static const DrawMultipleData kBlind_Dmd[105] = {
+    { -8,  7, 0x0c8e, 2},
+    {  8,  7, 0x4c8e, 2},
+    { -8, 23, 0x0ca0, 2},
+    {  8, 23, 0x4ca4, 2},
+    {  0,  0, 0x0a8c, 2},
+    {-19,  3, 0x0aa6, 2},
+    { 19,  3, 0x4aa6, 2},
+    { -8,  7, 0x0c8e, 2},
+    {  8,  7, 0x4c8e, 2},
+    { -8, 23, 0x0ca2, 2},
+    {  8, 23, 0x4ca0, 2},
+    {  0,  0, 0x0a8c, 2},
+    {-19,  3, 0x0aa8, 2},
+    { 19,  3, 0x4aa8, 2},
+    { -8,  7, 0x0c8e, 2},
+    {  8,  7, 0x4c8e, 2},
+    { -8, 23, 0x0ca4, 2},
+    {  8, 23, 0x4ca2, 2},
+    {  0,  0, 0x0a8c, 2},
+    {-19,  3, 0x0aaa, 2},
+    { 19,  3, 0x4aaa, 2},
+    {-15,  5, 0x0aa6, 2},
+    { -6,  7, 0x0c8e, 2},
+    {  6,  7, 0x4c8e, 2},
+    { -6, 23, 0x0ca4, 2},
+    {  6, 23, 0x4ca0, 2},
+    {  0,  0, 0x0a8a, 2},
+    { 16, -1, 0x4aa6, 2},
+    {-11,  9, 0x0aa6, 2},
+    { -4,  7, 0x0c8e, 2},
+    {  5,  7, 0x4c8e, 2},
+    { -4, 23, 0x0ca4, 2},
+    {  5, 23, 0x4ca0, 2},
+    {  0,  0, 0x0a88, 2},
+    { 10, -2, 0x4aa6, 2},
+    {  0,  0, 0x0a84, 2},
+    { 13,  8, 0x4aa6, 2},
+    {-10, -2, 0x0aa6, 2},
+    { -5,  7, 0x0c8e, 2},
+    {  5,  7, 0x4c8e, 2},
+    { -5, 23, 0x0ca0, 2},
+    {  5, 23, 0x4ca4, 2},
+    {  0,  0, 0x0a82, 2},
+    { 18,  4, 0x4aa6, 2},
+    {-15, -1, 0x0aa6, 2},
+    { -6,  7, 0x0c8e, 2},
+    {  6,  7, 0x4c8e, 2},
+    { -6, 23, 0x0ca0, 2},
+    {  6, 23, 0x4ca4, 2},
+    {  0,  0, 0x0a80, 2},
+    {-19,  3, 0x0aa6, 2},
+    { 19,  3, 0x4aa6, 2},
+    { -8,  7, 0x0c8e, 2},
+    {  8,  7, 0x4c8e, 2},
+    { -8, 23, 0x0ca0, 2},
+    {  8, 23, 0x4ca4, 2},
+    {  0,  0, 0x0a80, 2},
+    {-19,  3, 0x0aa8, 2},
+    { 19,  3, 0x4aa8, 2},
+    { -8,  7, 0x0c8e, 2},
+    {  8,  7, 0x4c8e, 2},
+    { -8, 23, 0x0ca2, 2},
+    {  8, 23, 0x4ca0, 2},
+    {  0,  0, 0x0a80, 2},
+    {-19,  3, 0x0aaa, 2},
+    { 19,  3, 0x4aaa, 2},
+    { -8,  7, 0x0c8e, 2},
+    {  8,  7, 0x4c8e, 2},
+    { -8, 23, 0x0ca0, 2},
+    {  8, 23, 0x4ca4, 2},
+    { -8,  9, 0x0c8e, 2},
+    {  8,  9, 0x4c8e, 2},
+    { -8, 23, 0x0cae, 2},
+    {  8, 23, 0x4cae, 2},
+    {  8, 23, 0x4cae, 2},
+    {  8, 23, 0x4cae, 2},
+    {  0,  2, 0x0a8c, 2},
+    { -8, 16, 0x0c8e, 2},
+    {  8, 16, 0x4c8e, 2},
+    { -8, 23, 0x0cae, 2},
+    {  8, 23, 0x4cae, 2},
+    {  8, 23, 0x4cae, 2},
+    {  8, 23, 0x4cae, 2},
+    {  0,  9, 0x0a8c, 2},
+    { -8, 23, 0x0cae, 2},
+    {  8, 23, 0x4cae, 2},
+    {  8, 23, 0x4cae, 2},
+    {  8, 23, 0x4cae, 2},
+    {  8, 23, 0x4cae, 2},
+    {  8, 23, 0x4cae, 2},
+    {  0, 16, 0x0a8c, 2},
+    { -8, 23, 0x0cac, 2},
+    {  8, 23, 0x4cac, 2},
+    {  8, 23, 0x4cac, 2},
+    {  8, 23, 0x4cac, 2},
+    {  8, 23, 0x4cac, 2},
+    {  8, 23, 0x4cac, 2},
+    {  0, 20, 0x0a8c, 2},
+    { -8, 23, 0x0cac, 2},
+    {  8, 23, 0x4cac, 2},
+    {  8, 23, 0x4cac, 2},
+    {  8, 23, 0x4cac, 2},
+    {  8, 23, 0x4cac, 2},
+    {  8, 23, 0x4cac, 2},
+    {  0, 23, 0x0a8c, 2},
+  };
+  Sprite_DrawMultiple(k, &kBlind_Dmd[sprite_graphics[k] * 7], 7, NULL);
+  OamEnt *oam = GetOamCurPtr();
+  if (sprite_wallcoll[k] == 0) {
+    if (sprite_C[k] == 6) {
+      oam[6].y = 0xf0;
+      return;
+    }
+    if (sprite_C[k] == 4)
+      return;
+  }
+  if (sprite_graphics[k] >= 10)
+    return;
+  static const uint8 kBlind_OamIdx[10] = {4, 4, 4, 5, 5, 0, 0, 0, 0, 0};
+  oam += kBlind_OamIdx[sprite_graphics[k]];
+  int j = sprite_head_dir[k];
+  oam->charnum = kBlindHead_Draw_Char[j];
+  oam->flags = oam->flags & 0x3f | kBlindHead_Draw_Flags[j];
+}
+
+void TrinexxComponents_Initialize(int k) {  // 9dad16
+  switch (sprite_type[k]) {
+  case 0xcb: {
+    sprite_x_lo[k] += 8;
+    sprite_y_lo[k] += 16;
+    Trinexx_CachePosition(k);
+    overlord_x_lo[2] = 0;
+    overlord_x_lo[3] = 0;
+    overlord_x_lo[5] = 0;
+    overlord_x_lo[7] = 0;
+    overlord_x_hi[0] = 0;
+    overlord_x_lo[6] = 255;
+    Trinexx_RestoreXY(k);
+    break;
+  }
+  case 0xcc:
+    sprite_graphics[k] = 3;
+    sprite_delay_main[k] = 128;
+common:
+    for (int j = 0x1a; j >= 0; j--) {
+      alt_sprite_type[j] = 0x40;
+      alt_sprite_x_hi[j] = 0;
+      alt_sprite_y_hi[j] = 0;
+    }
+    sprite_subtype2[k] = 1;
+    Trinexx_CachePosition(k);
+    break;
+  case 0xcd:
+    sprite_delay_main[k] = 255;
+    goto common;
+  }
+}
+
+void Trinexx_RestoreXY(int k) {  // 9dad4f
+  sprite_x_lo[k] = sprite_A[k];
+  Sprite_SetY(k, (sprite_G[k] << 8) + sprite_C[k] + 12);
+}
+
+void Trinexx_CachePosition(int k) {  // 9dad8c
+  sprite_A[k] = sprite_x_lo[k];
+  sprite_B[k] = sprite_x_hi[k];
+  sprite_C[k] = sprite_y_lo[k];
+  sprite_G[k] = sprite_y_hi[k];
+}
+
+void Sprite_Trinexx_FinalPhase(int k) {  // 9dadb5
+  static const uint8 kSprite_TrinexxD_Gfx3[8] = {6, 7, 0, 1, 2, 3, 4, 5};
+  static const uint8 kSprite_TrinexxD_Gfx[8] = {7, 7, 1, 1, 3, 3, 5, 5};
+  static const int8 kSprite_TrinexxD_Xvel[4] = {0, -31, 0, 31};
+  static const int8 kSprite_TrinexxD_Yvel[4] = {31, 0, -31, 0};
+
+  int j = Sprite_ConvertVelocityToAngle(sprite_x_vel[k], sprite_y_vel[k]) >> 1;
+  uint8 gfx = kSprite_TrinexxD_Gfx3[j];
+  sprite_graphics[k] = sprite_delay_aux1[k] ? kSprite_TrinexxD_Gfx[gfx] : gfx;
+
+  Sprite_TrinexxD_Draw(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  if (sign8(sprite_ai_state[k])) {
+    uint8 t = sprite_delay_main[k];
+    sprite_hit_timer[k] = t | 0xe0;
+    if (t == 0) {
+      sprite_delay_main[k] = 12;
+      if (sprite_anim_clock[k] == 0) {
+        sprite_hit_timer[k] = 255;
+        Sprite_ScheduleBossForDeath(k);
+      } else {
+        sprite_anim_clock[k]--;
+        Sprite_MakeBossExplosion(k);
+      }
+    }
+    return;
+  }
+  if (!(frame_counter & 7))
+    SpriteSfx_QueueSfx3WithPan(k, 0x31);
+
+  j = ++sprite_subtype2[k] & 0x7f;
+  moldorm_x_lo[j] = sprite_x_lo[k];
+  moldorm_y_lo[j] = sprite_y_lo[k];
+  moldorm_x_hi[j] = sprite_x_hi[k];
+  moldorm_y_hi[j] = sprite_y_hi[k];
+
+  if (sprite_F[k] == 14) {
+    sprite_F[k] = 8;
+    if (sprite_ai_state[k] == 0)
+      sprite_ai_state[k] = 2;
+  }
+  Sprite_MoveXY(k);
+  Sprite_CheckDamageToAndFromLink(k);
+  switch(sprite_ai_state[k]) {
+  case 0:
+    if (!--sprite_A[k]) {
+      sprite_ai_state[k] = 1;
+      sprite_delay_main[k] = 192;
+    }
+    Sprite_Get16BitCoords(k);
+    if (Sprite_CheckTileCollision(k)) {
+      sprite_D[k] = sprite_D[k] + 1 & 3;
+      sprite_delay_aux1[k] = 8;
+    }
+    j = sprite_D[k];
+    sprite_x_vel[k] = kSprite_TrinexxD_Xvel[j];
+    sprite_y_vel[k] = kSprite_TrinexxD_Yvel[j];
+    break;
+  case 1:
+    if (!(frame_counter & 1)) {
+      ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLink(k, 31);
+      Sprite_ApproachTargetSpeed(k, pt.x, pt.y);
+    }
+    break;
+  }
+}
+
+void Sprite_TrinexxD_Draw(int k) {  // 9daf84
+  static const int8 kTrinexxD_HistPos[24] = {
+    8,  0xc, 0x10, 0x18, 0x20, 0x28, 0x30, 0x34, 0x38, 0x3c, 0x40, 0x44, 0x48, 0x4c, 0x50, 0x54,
+    0x58, 0x5c, 0x60, 0x64, 0x68, 0x6c, 0x70, 0x74,
+  };
+  static const int8 kSprite_TrinexxD_Gfx2[24] = {
+    2, 2, 2, 3, 3, 3, 2, 2, 1, 1, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0,
+  };
+  static const int16 kTrinexxD_OamOffs[24] = {
+    0x10, 4, 4, 4, 0x10, 0x10, 0x10, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+    4, 4, 4, 4,    4,    4,    4, 4,
+  };
+
+  sprite_obj_prio[k] |= 0x30;
+  PrepOamCoordsRet info;
+  SpriteDraw_TrinexxRockHead(k, &info);
+  for (int i = 0; i != sprite_anim_clock[k]; i++) {
+    int j = sprite_subtype2[k] - kTrinexxD_HistPos[i] & 0x7f;
+    cur_sprite_x = moldorm_x_hi[j] << 8 | moldorm_x_lo[j];
+    cur_sprite_y = moldorm_y_hi[j] << 8 | moldorm_y_lo[j];
+
+    if ((uint16)(link_x_coord - cur_sprite_x + 8) < 16 &&
+        (uint16)(link_y_coord - cur_sprite_y + 16) < 16 &&
+        !sign8(sprite_ai_state[k]) &&
+        !(countdown_for_blink | link_disable_sprite_damage | submodule_index | flag_unk1)) {
+      link_auxiliary_state = 1;
+      link_give_damage = 8;
+      link_incapacitated_timer = 16;
+      link_actual_vel_x ^= 255;
+      link_actual_vel_y ^= 255;
+    }
+    oam_cur_ptr += kTrinexxD_OamOffs[i];
+    oam_ext_cur_ptr += (kTrinexxD_OamOffs[i] >> 2);
+    sprite_oam_flags[k] = 1;
+    if (i == 4 && sprite_ai_state[k] != 0) {
+      Sprite_Trinexx_CheckDamageToFlashingSegment(k);
+      sprite_oam_flags[k] = (sprite_subtype2[k] & 6) ^ sprite_oam_flags[k];
+    }
+    sprite_graphics[k] = kSprite_TrinexxD_Gfx2[i];
+    if (sprite_graphics[k] != 3) {
+      SpriteDraw_SingleLarge(k);
+    } else {
+      sprite_graphics[k] = 8;
+      SpriteDraw_TrinexxRockHead(k, &info);
+    }
+  }
+  byte_7E0FB6 = sprite_anim_clock[k];
+}
+
+void Sprite_Trinexx_CheckDamageToFlashingSegment(int k) {  // 9db079
+  uint16 old_x = Sprite_GetX(k);
+  uint16 old_y = Sprite_GetY(k);
+  Sprite_SetX(k, cur_sprite_x);
+  Sprite_SetY(k, cur_sprite_y);
+  sprite_defl_bits[k] = 0x80;
+  sprite_flags3[k] = 0;
+  Sprite_CheckDamageFromLink(k);
+  sprite_defl_bits[k] = 0x84;
+  sprite_flags3[k] = 0x40;
+  Sprite_SetX(k, old_x);
+  Sprite_SetY(k, old_y);
+}
+
+void Sprite_CB_TrinexxRockHead(int k) {  // 9db0ca
+  if (overlord_x_hi[0]) {
+    Sprite_Trinexx_FinalPhase(k);
+    return;
+  }
+  TM_copy = 0x17;
+  TS_copy = 0;
+  SpriteDraw_TrinexxRockHeadAndBody(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  if (sign8(sprite_ai_state[k])) {
+    flag_block_link_menu = sprite_ai_state[k];
+    if (!sprite_delay_main[k]) {
+      overlord_x_hi[0]++;
+      Sprite_InitializedSegmented(k);
+      sprite_subtype2[k] = 0;
+      sprite_head_dir[k] = 0;
+      sprite_flags3[k] &= ~0x40;
+      sprite_defl_bits[k] = 0x80;
+      sprite_ai_state[k] = 0;
+      sprite_D[k] = 0;
+      sprite_A[k] = 0;
+      sprite_anim_clock[k] = 16;
+      sprite_x_vel[k] = sprite_y_vel[k] = 0;
+      sprite_A[k] = 128;
+      HIBYTE(dung_floor_y_vel) = 255;
+    } else if (sprite_delay_main[k] >= 0xff) {
+    } else if (sprite_delay_main[k] >= 0xe0) {
+      if (!(sprite_delay_main[k] & 3)) {
+        dung_floor_y_vel = -1;
+        dung_hdr_collision_2_mirror = 1;
+      }
+      sprite_y_vel[k] = -8;
+      Sprite_MoveY(k);
+      Trinexx_CachePosition(k);
+      sprite_C[k] = sprite_y_lo[k] - 12;
+      overlord_x_lo[7] += 2;
+    } else {
+      if (!(sprite_delay_main[k] & 3))
+        SpriteSfx_QueueSfx2WithPan(k, 0xc);
+      if (!(sprite_delay_main[k] & 1)) {
+        static const int8 kTrinexx_X0[8] = {0, 8, 16, 24, -24, -16, -8, 0};
+        static const int8 kTrinexx_Y0[8] = {0, 8, 16, 24, -24, -16, -8, 0};
+        cur_sprite_x = Sprite_GetX(k) + kTrinexx_X0[GetRandomNumber() & 7];
+        cur_sprite_y = Sprite_GetY(k) + kTrinexx_Y0[GetRandomNumber() & 7] - 8;
+        Sprite_MakeBossDeathExplosion_NoSound(k);
+      }
+      sprite_head_dir[k] = 255;
+    }
+    return;
+  }
+  if ((sprite_state[1] | sprite_state[2]) == 0 && sprite_ai_state[k] < 2) {
+    sprite_delay_main[k] = 255;
+    sprite_ai_state[k] = 255;
+    sound_effect_2 = 0x22;
+    return;
+  }
+
+  Trinexx_WagTail(k);
+  Trinexx_HandleShellCollision(k);
+  Sprite_CheckDamageToAndFromLink(k);
+  if (!(frame_counter & 63)) {
+    PairU8 pair = Sprite_IsRightOfLink(k);
+    sprite_graphics[k] = (uint8)(pair.b + 24) < 48 ? 0 : pair.a ? 1 : 7;
+  }
+  if (overlord_x_lo[6]) {
+    if (!(frame_counter & 1))
+      overlord_x_lo[6]--;
+    return;
+  }
+  if (sprite_state[1] && sprite_ai_state[1] == 3)
+    return;
+  if (sprite_state[2] && sprite_ai_state[2] == 3)
+    return;
+
+  switch (sprite_ai_state[k]) {
+  case 0:
+    if (!sprite_delay_main[k]) {
+      int j = GetRandomNumber() & 3;
+      if ((sprite_subtype[k] & 0x7f) == j)
+        return;
+      if (++sprite_anim_clock[k] == 2) {
+        sprite_anim_clock[k] = 0;
+        sprite_ai_state[k] = 2;
+        sprite_delay_main[k] = 80;
+        return;
+      }
+      static const uint8 kTrinexx_Tab0[4] = {0x60, 0x78, 0x78, 0x90};
+      static const uint8 kTrinexx_Tab1[4] = {0x80, 0x70, 0x60, 0x80};
+      overlord_x_lo[0] = kTrinexx_Tab0[j];
+      overlord_x_lo[1] = kTrinexx_Tab1[j];
+      sprite_subtype[k] = j + ((GetRandomNumber() & 3) == 0) * 0x80;
+      sprite_ai_state[k] = 1;
+    }
+    break;
+  case 1: {
+    if (sprite_subtype[k] == 0xff && (sprite_delay_main[k] == 0 || Sprite_IsBelowLink(k).a == 0)) {
+      sprite_subtype[k] = 0;
+      sprite_ai_state[k] = 0;
+      sprite_delay_main[k] = 48;
+    } else {
+      uint16 x = sprite_x_hi[k] << 8 | overlord_x_lo[0];
+      uint16 y = sprite_y_hi[k] << 8 | overlord_x_lo[1];
+      ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLocation(k, x, y, sign8(sprite_subtype[k]) ? 16 : 8);
+      sprite_x_vel[k] = pt.x;
+      sprite_y_vel[k] = pt.y;
+
+      uint8 bakx = sprite_x_lo[k];
+      uint8 baky = sprite_y_lo[k];
+      Sprite_MoveXY(k);
+      dung_floor_y_vel = (int8)(baky - sprite_y_lo[k]);
+      dung_floor_x_vel = (int8)(bakx - sprite_x_lo[k]);
+
+      dung_hdr_collision_2_mirror = 1;
+      Trinexx_CachePosition(k);
+      sprite_C[k] = sprite_y_lo[k] - 12;
+      if ((uint8)(overlord_x_lo[0] - sprite_x_lo[k] + 2) < 4 &&
+          (uint8)(overlord_x_lo[1] - sprite_y_lo[k] + 2) < 4) {
+        sprite_ai_state[k] = 0;
+        sprite_delay_main[k] = 48;
+      }
+    }
+    int i = sign8(sprite_subtype[k]) ? 2 : 1;
+    do {
+      sprite_subtype2[k] += sign8(sprite_x_vel[k]) ? 1 : -1;
+      if (!(sprite_subtype2[k] & 0xf))
+        SpriteSfx_QueueSfx2WithPan(k, 0x21);
+    } while (--i);
+    break;
+  }
+  case 2:
+    Trinexx_WagTail(k);
+    Trinexx_WagTail(k);
+    if (!sprite_delay_main[k]) {
+      sprite_ai_state[k] = 3;
+      Sprite_ApplySpeedTowardsLink(k, 48);
+      sprite_delay_main[k] = 64;
+      sound_effect_2 = 0x26;
+    }
+    break;
+  case 3:
+    Sprite_MoveXY(k);
+    if (!sprite_delay_main[k]) {
+      Trinexx_RestoreXY(k);
+      sprite_ai_state[k] = 0;
+      sprite_delay_main[k] = 48;
+    } else if (sprite_delay_main[k] == 0x20) {
+      sprite_x_vel[k] = -sprite_x_vel[k];
+      sprite_y_vel[k] = -sprite_y_vel[k];
+    }
+    break;
+  }
+}
+
+void Trinexx_WagTail(int k) {  // 9db3b5
+  if (!overlord_x_lo[5]) {
+    if (!(++overlord_x_lo[4] & 3)) {
+      int j = overlord_x_lo[3] & 1;
+      overlord_x_lo[2] += j ? -1 : 1;
+      if (overlord_x_lo[2] == (j ? 0 : 6)) {
+        overlord_x_lo[3] += 1;
+        overlord_x_lo[5] = 8;
+      }
+    }
+  } else {
+    --overlord_x_lo[5];
+  }
+}
+
+void Trinexx_HandleShellCollision(int k) {  // 9db3e6
+  uint16 x = sprite_A[k] | sprite_B[k] << 8;
+  uint16 y = sprite_C[k] | sprite_G[k] << 8;
+  if ((uint16)(x - link_x_coord + 40) < 80 && (uint16)(y - link_y_coord + 16) < 64 && !(countdown_for_blink | link_disable_sprite_damage)) {
+    link_auxiliary_state = 1;
+    link_give_damage = 8;
+    link_incapacitated_timer = 16;
+    ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLink(k, 32);
+    link_actual_vel_x = pt.x;
+    link_actual_vel_y = pt.y;
+  }
+}
+
+void SpriteDraw_TrinexxRockHead(int k, PrepOamCoordsRet *info) {  // 9db560
+  static const DrawMultipleData kTrinexx_Draw1_Dmd[36] = {
+    {-8, -8, 0x40c0, 2},
+    { 8, -8, 0x00c0, 2},
+    {-8,  8, 0x40e0, 2},
+    { 8,  8, 0x00e0, 2},
+
+    {-8, -8, 0x0000, 2},
+    { 8, -8, 0x0002, 2},
+    {-8,  8, 0x0020, 2},
+    { 8,  8, 0x0022, 2},
+
+    {-8, -8, 0x00c2, 2},
+    { 8, -8, 0x00c4, 2},
+    {-8,  8, 0x80c2, 2},
+    { 8,  8, 0x80c4, 2},
+
+    {-8, -8, 0x8020, 2},
+    { 8, -8, 0x8022, 2},
+    {-8,  8, 0x8000, 2},
+    { 8,  8, 0x8002, 2},
+    {-8, -8, 0xc0e0, 2},
+    { 8, -8, 0x80e0, 2},
+    {-8,  8, 0xc0c0, 2},
+    { 8,  8, 0x80c0, 2},
+    {-8, -8, 0xc022, 2},
+    { 8, -8, 0xc020, 2},
+    {-8,  8, 0xc002, 2},
+    { 8,  8, 0xc000, 2},
+    {-8, -8, 0x40c4, 2},
+    { 8, -8, 0x40c2, 2},
+    {-8,  8, 0xc0c4, 2},
+    { 8,  8, 0xc0c2, 2},
+    {-8, -8, 0x4002, 2},
+    { 8, -8, 0x4000, 2},
+    {-8,  8, 0x4022, 2},
+    { 8,  8, 0x4020, 2},
+    {-8, -8, 0x0026, 2},
+    { 8, -8, 0x4026, 2},
+    {-8,  8, 0x8026, 2},
+    { 8,  8, 0xc026, 2},
+  };
+  if (!sign8(sprite_ai_state[k]))
+    sprite_obj_prio[k] |= 0x30;
+  Sprite_DrawMultiple(k, &kTrinexx_Draw1_Dmd[sprite_graphics[k] * 4], 4, info);
+}
+
+void SpriteDraw_TrinexxRockHeadAndBody(int k) {  // 9db587
+  static const int8 kTrinexx_Draw_X[35] = {
+    0,   3,   9, 16, 24,  0,  2,  7,  13, 20,  0,  1,   4,   9, 15,  0,
+    0,   0,   0,  0,  0, -1, -4, -9, -15,  0, -2, -7, -13, -20,  0, -3,
+    -9, -16, -24,
+  };
+  static const int8 kTrinexx_Draw_Y[35] = {
+    0x18, 0x20, 0x25, 0x25, 0x21, 0x18, 0x20, 0x27, 0x2a, 0x2c, 0x18, 0x20, 0x28, 0x2f, 0x34, 0x18,
+    0x21, 0x2a, 0x34, 0x3d, 0x18, 0x20, 0x28, 0x2f, 0x34, 0x18, 0x20, 0x27, 0x2a, 0x2c, 0x18, 0x20,
+    0x25, 0x25, 0x21,
+  };
+  static const uint8 kTrinexx_Draw_Char[5] = {6, 0x28, 0x28, 0x2c, 0x2c};
+  static const uint8 kTrinexx_Mults[8] = {0xfc, 0xe0, 0xc0, 0xa0, 0x80, 0x60, 0x40, 0x20};
+  static const int8 kTrinexx_Draw_Xoffs[16] = {0, 2, 3, 4, 4, 4, 3, 2, 0, -2, -3, -4, -4, -4, -3, -2};
+  static const int8 kTrinexx_Draw_Yoffs[16] = {-4, -4, -3, -2, 0, 2, 3, 4, 4, 4, 3, 2, 0, -2, -3, -4};
+  if (sign8(sprite_head_dir[k]))
+    return;
+
+  PrepOamCoordsRet info;
+  SpriteDraw_TrinexxRockHead(k, &info);
+
+  info.flags &= ~0x10;
+
+  if (sprite_ai_state[k] == 3) {
+    OamEnt *oam = GetOamCurPtr() + 4;
+    uint8 xb = sprite_A[k] - sprite_x_lo[k];
+    uint8 yb = sprite_C[k] - sprite_y_lo[k];
+    for (int i = 7; i >= 0; i--, oam++) {
+      SetOamPlain(oam, info.x + TrinexxMult(xb, kTrinexx_Mults[i]), info.y + TrinexxMult(yb, kTrinexx_Mults[i]), 0x28, info.flags, 2);
+    }
+    byte_7E0FB6 = 0x30;
+  }
+  oam_cur_ptr = 0x9f0;
+  oam_ext_cur_ptr = 0xa9c;
+  OamEnt *oam = GetOamCurPtr();
+  uint8 xb = sprite_A[k] - BG2HOFS_copy2;
+  uint16 yb = (sprite_C[k] | sprite_y_hi[k] << 8) - BG2VOFS_copy2;
+
+  uint8 xidx = (uint8)(sprite_x_vel[k] + 3) < 7 ? 0 : (sprite_subtype2[k] >> 2);
+  uint8 yidx = sprite_subtype2[k] >> 2;
+
+  for (int i = 1; i >= 0; i--, oam += 2) {
+    uint8 x = xb + (i ? -28 : 28) + kTrinexx_Draw_Xoffs[xidx + (1 - i) * 8 & 0xf];
+    uint8 y = yb - 8 + kTrinexx_Draw_Yoffs[yidx + i * 8 & 0xf];
+    uint8 f = info.flags | (i ? 0 : 0x40);
+    SetOamPlain(oam + 0, x, y, 0xc, f, 2);
+    SetOamPlain(oam + 1, x, y + 16, 0x2a, f, 2);
+  }
+
+  oam = (OamEnt *)&g_ram[0x800] + 91;
+  int g = overlord_x_lo[2];
+  for (int i = 0; i < 5; i++, oam++) {
+    int j = g * 5 + i;
+    SetOamHelper0(oam,
+                  xb + kTrinexx_Draw_X[j], yb - kTrinexx_Draw_Y[j] - 0x20 + WORD(overlord_x_lo[7]),
+                  kTrinexx_Draw_Char[i], info.flags, 2);
+  }
+  tmp_counter = 0xff;
+
+  if (submodule_index)
+    Sprite_CorrectOamEntries(k, 3, 2);
+}
+
+void Sprite_Sidenexx(int k) {  // 9db8a7
+  static const int8 kTrinexxHead_Xoffs[2] = {-14, 13};
+
+  int xx = (sprite_B[0] << 8 | sprite_A[0]) + kTrinexxHead_Xoffs[sprite_type[k] - 0xcc];
+  sprite_A[k] = xx, sprite_B[k] = xx >> 8;
+
+  int yy = (sprite_G[0] << 8 | sprite_C[0]) - 0x20;
+  sprite_C[k] = yy, sprite_G[k] = yy >> 8;
+  sprite_obj_prio[k] |= 0x30;
+  TrinexxHead_Draw(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  if (sign8(sprite_ai_state[k])) {
+    sprite_ignore_projectile[k] = sprite_ai_state[k];
+    Sidenexx_Explode(k);
+    return;
+  }
+
+  if (sprite_hit_timer[k] && sprite_ai_state[k] != 4) {
+    sprite_hit_timer[k] = 0;
+    sprite_delay_main[k] = 128;
+    sprite_ai_state[k] = 4;
+    sprite_z_vel[k] = sprite_oam_flags[k];
+    sprite_oam_flags[k] = 3;
+  }
+  Sprite_CheckDamageToAndFromLink(k);
+  sprite_defl_bits[k] |= 4;
+  switch(sprite_ai_state[k]) {
+  case 0:
+    sprite_flags3[k] |= 0x40;
+    if (!sprite_delay_main[k]) {
+      sprite_ai_state[k] = 2;
+      sprite_subtype2[k] = 9;
+      sprite_flags3[k] &= ~0x40;
+    }
+    break;
+  case 1:
+    if (!sprite_delay_main[k]) {
+      int i = (GetRandomNumber() & 7) + 1;
+      int j = sprite_D[k];
+      if (i < 5 && sprite_D[k] != i) {
+        sprite_D[k] = i;
+        sprite_ai_state[k] = 2;
+        if (j == 1 && !(GetRandomNumber() & 1) && sprite_ai_state[0] < 2) {
+          sprite_graphics[k] = 0;
+          sprite_ai_state[k] = 3;
+          sprite_delay_main[k] = 127;
+        }
+      }
+    }
+    break;
+  case 2: {
+    static const uint8 kTrinexxHead_Target0[45] = {
+      0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x58, 0x64, 0x6a, 0x6f, 0x74, 0x7a, 0x7e,
+      0x80, 0x80, 0x39, 0x48, 0x52, 0x5c, 0x65, 0x73, 0x77, 0x7a, 0x80, 0x1e, 0x24, 0x29, 0x2e, 0x34,
+      0x3a, 0x44, 0x4d, 0x80,  0xa, 0x11, 0x17, 0x1c, 0x22, 0x2a, 0x36, 0x3a, 0x80,
+    };
+    static const uint8 kTrinexxHead_Target1[45] = {
+      0x30, 0x28, 0x23, 0x1e, 0x19, 0x13,  0xc,    6,    0, 0x2f, 0x26, 0x21, 0x1d, 0x18, 0x12,  0xc,
+      6,    0, 0x2f, 0x27, 0x22, 0x1d, 0x18, 0x12,  0xc,    6,    0, 0x2f, 0x27, 0x22, 0x1d, 0x18,
+      0x12,  0xc,    6,    0, 0x48, 0x3a, 0x32, 0x29, 0x22, 0x19, 0x10,    7,    0,
+    };
+
+    int j = sprite_D[k] * 9, f = k * 9;
+    int n = 0;
+    for (int i = 8; i >= 0; i--, j++, f++) {
+      if (alt_sprite_type[f] - kTrinexxHead_Target0[j]) {
+        alt_sprite_type[f] += sign8(alt_sprite_type[f] - kTrinexxHead_Target0[j]) ? 1 : -1;
+        n++;
+      }
+      if (alt_sprite_type[f] - kTrinexxHead_Target0[j]) {
+        alt_sprite_type[f] += sign8(alt_sprite_type[f] - kTrinexxHead_Target0[j]) ? 1 : -1;
+        n++;
+      }
+      if (alt_sprite_y_hi[f] - kTrinexxHead_Target1[j]) {
+        alt_sprite_y_hi[f] += sign8(alt_sprite_y_hi[f] - kTrinexxHead_Target1[j]) ? 1 : -1;
+        n++;
+      }
+    }
+    if (n == 0) {
+      sprite_ai_state[k] = 1;
+      sprite_delay_main[k] = GetRandomNumber() & 15;
+    }
+    break;
+  }
+  case 3: {
+    static const uint8 kTrinexxHead_FrameMask[8] = {1, 1, 3, 3, 7, 0xf, 0x1f, 0x1f};
+    int j = sprite_delay_main[k];
+    if (!j) {
+      sprite_ai_state[k] = 0;
+      sprite_delay_main[k] = 32;
+      return;
+    }
+    if (j == 64)
+      Sidenexx_ExhaleDanger(k);
+    sprite_subtype[k] = (j < 8) ? j : (j < 121) ? 8 : ~(sprite_delay_main[k] + 0x80);
+    if (j >= 64 && !(frame_counter & kTrinexxHead_FrameMask[(j - 64) >> 3])) {
+      int x = (GetRandomNumber() & 0xf) - 3;
+      int y = (GetRandomNumber() & 0xf) + 12;
+      int j = Sprite_GarnishSpawn_Sparkle(k, x, y);
+      if (sprite_type[k] == 0xcc)
+        garnish_type[j] = 0xe;
+    }
+    break;
+  }
+  case 4: {
+    sprite_defl_bits[k] &= ~4;
+    sprite_subtype[k] = 0;
+    int j = sprite_delay_main[k];
+    if (!j) {
+      sprite_ai_state[k] = 1;
+      sprite_delay_main[k] = 32;
+      sprite_oam_flags[k] = sprite_z_vel[k];
+      sprite_hit_timer[k] = 0;
+    }
+    if (j >= 15) {
+      if (j >= 63 && j < 78) {
+        if (sprite_type[k] == 0xcd)
+          Trinexx_FlashShellPalette_Blue();
+        else
+          Trinexx_FlashShellPalette_Red();
+      }
+    } else {
+      if (sprite_type[k] == 0xcd)
+        Trinexx_UnflashShellPalette_Blue();
+      else
+        Trinexx_UnflashShellPalette_Red();
+    }
+  }
+  }
+}
+
+void Sidenexx_ExhaleDanger(int k) {  // 9dbae8
+  SpriteSpawnInfo info;
+  if (sprite_type[k] == 0xcd) {
+    for (int i = 0; i < 2; i++) {
+      int j = Sprite_SpawnDynamically(k, 0xcd, &info);
+      if (j >= 0) {
+        Sprite_SetSpawnedCoordinates(j, &info);
+        sprite_C[j] = i ? 1 : -2;
+        SpriteSfx_QueueSfx3WithPan(k, 0x19);
+        sprite_ignore_projectile[j] = sprite_E[j] = 1;
+        sprite_y_vel[j] = 24;
+        sprite_flags2[j] = 0;
+        sprite_flags3[j] = 0x40;
+      }
+    }
+    byte_7E0FB6 = 1;
+  } else {
+    int j = Sprite_SpawnDynamically(k, sprite_type[k], &info);
+    if (j >= 0) {
+      Sprite_SetSpawnedCoordinates(j, &info);
+      SpriteSfx_QueueSfx2WithPan(k, 0x2a);
+      sprite_ignore_projectile[j] = sprite_E[j] = 1;
+      sprite_y_vel[j] = 24;
+      sprite_flags2[j] = 0;
+      sprite_flags3[j] = 0x40;
+    }
+  }
+}
+
+void Sidenexx_Explode(int k) {  // 9dbb3f
+  if (!sprite_delay_main[k]) {
+    sprite_delay_main[k] = 12;
+    if (sprite_subtype2[k] == 1)
+      sprite_state[k] = 0;
+    sprite_subtype2[k]--;
+    BYTE(cur_sprite_x) += BG2HOFS_copy2;
+    BYTE(cur_sprite_y) += BG2VOFS_copy2;
+    Sprite_MakeBossExplosion(k);
+  }
+}
+
+void TrinexxHead_Draw(int k) {  // 9dbb70
+  sprite_x_lo[k] = sprite_A[k];
+  sprite_x_hi[k] = sprite_B[k];
+  sprite_y_lo[k] = sprite_C[k];
+  sprite_y_hi[k] = sprite_G[k];
+  Sprite_Get16BitCoords(k);
+  PrepOamCoordsRet info;
+  if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
+    return;
+  OamEnt *oam = GetOamCurPtr();
+  int i = 0;
+  do {
+    int j = i + k * 9;
+
+    uint16 r6 = (k != 2) ? 0x100 + (uint8)(-alt_sprite_type[j]) : alt_sprite_type[j];
+    uint8 r15 = alt_sprite_y_hi[j];
+
+    BYTE(dungmap_var7) = TrinexxHeadSin(r6, r15);
+    HIBYTE(dungmap_var7) = TrinexxHeadSin(r6 + 0x80, r15);
+
+    if (i == 0) {
+      static const int8 kTrinexxHead_FirstPart_X[5] = {-8, 8, -8, 8, 0};
+      static const int8 kTrinexxHead_FirstPart_Y[5] = {-8, -8, 8, 8, 2};
+      static const uint8 kTrinexxHead_FirstPart_Char[5] = {4, 4, 0x24, 0x24, 0xa};
+      static const uint8 kTrinexxHead_FirstPart_Flags[5] = {0x40, 0, 0x40, 0, 0};
+
+      for (int m = 0; m < 5; m++) {
+        BYTE(cur_sprite_x) = info.x + BYTE(dungmap_var7);
+        uint8 x = BYTE(cur_sprite_x) + kTrinexxHead_FirstPart_X[m];
+
+        BYTE(cur_sprite_y) = info.y + HIBYTE(dungmap_var7);
+        uint8 y = BYTE(cur_sprite_y) + kTrinexxHead_FirstPart_Y[m] + (m == 4 ? sprite_subtype[k] : 0);
+
+        SetOamPlain(oam, x, y, kTrinexxHead_FirstPart_Char[m], info.flags | kTrinexxHead_FirstPart_Flags[m], 2);
+        oam++;
+      }
+      Sprite_SetX(k, (sprite_B[k] << 8 | sprite_A[k]) + (int8)BYTE(dungmap_var7));
+      Sprite_SetY(k, (sprite_G[k] << 8 | sprite_C[k]) + (int8)HIBYTE(dungmap_var7));
+    } else {
+      uint8 x = info.x + BYTE(dungmap_var7);
+      uint8 y = info.y + HIBYTE(dungmap_var7);
+      BYTE(cur_sprite_x) = x;
+      BYTE(cur_sprite_y) = y;
+      SetOamPlain(oam, x, y, 8, info.flags, 2);
+      oam++;
+    }
+  } while (++i != sprite_subtype2[k]);
+
+  tmp_counter = i;
+  byte_7E0FB6 = i * 4 + 16;
+  if (submodule_index)
+    Sprite_CorrectOamEntries(k, 4, 2);
+}
+
+void Sprite_CC_CD_Common(int k) {  // 9dbd44
+  if (!(frame_counter & 3)) {
+    int m = Sprite_IsRightOfLink(k).a ? -1 : 1;
+    if (sprite_x_vel[k] != (uint8)(m * 16))
+      sprite_x_vel[k] += m;
+  }
+  if (Sprite_CheckTileCollision(k))
+    sprite_state[k] = 0;
+}
+
+void Sprite_CD_SpawnGarnish(int k) {  // 9dbd65
+  if (++sprite_subtype2[k] & 7)
+    return;
+  SpriteSfx_QueueSfx3WithPan(k, 0x14);
+  int j = GarnishAllocOverwriteOld();
+  garnish_active = garnish_type[j] = 0xc;
+  garnish_sprite[j] = k;
+  Garnish_SetX(j, Sprite_GetX(k));
+  Garnish_SetY(j, Sprite_GetY(k) + 16);
+  garnish_countdown[j] = 127;
+}
+
+void Sprite_TrinexxFire_AddFireGarnish(int k) {  // 9dbdd6
+  if (++sprite_subtype2[k] & 7)
+    return;
+  SpriteSfx_QueueSfx2WithPan(k, 0x2a);
+  Garnish_FlameTrail(k, false);
+}
+
+int Garnish_FlameTrail(int k, bool is_low) {  // 9dbde8
+  int j = is_low ? GarnishAllocOverwriteOldLow() : GarnishAllocOverwriteOld();
+  garnish_active = garnish_type[j] = 0x10;
+  garnish_sprite[j] = k;
+  Garnish_SetX(j, Sprite_GetX(k));
+  Garnish_SetY(j, Sprite_GetY(k) + 16);
+  garnish_countdown[j] = 127;
+  return j;
+}
+
+void Sprite_CA_ChainChomp(int k) {  // 9dbe7d
+  ChainChomp_Draw(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  Sprite_CheckDamageToAndFromLink(k);
+  ChainChomp_HandleLeash(k);
+  if (!((k ^ frame_counter) & 3) && (sprite_x_vel[k] | sprite_y_vel[k]))
+    sprite_D[k] = Sprite_ConvertVelocityToAngle(sprite_x_vel[k], sprite_y_vel[k]) & 0xf;
+  Sprite_MoveXYZ(k);
+  sprite_z_vel[k] -= 2;
+  if (sign8(sprite_z[k])) {
+    sprite_z[k] = 0;
+    sprite_z_vel[k] = 0;
+  }
+  Sprite_Get16BitCoords(k);
+  uint16 x = sprite_A[k] | sprite_B[k] << 8;
+  uint16 y = sprite_C[k] | sprite_G[k] << 8;
+  sprite_anim_clock[k] = (uint16)(cur_sprite_x - x + 48) < 96 && (uint16)(cur_sprite_y - y + 48) < 96;
+  switch(sprite_ai_state[k]) {
+  case 0:  //
+    if (!sprite_delay_main[k]) {
+      static const int8 kChainChomp_Xvel[16] = {0, 8, 11, 14, 16, 14, 11, 8, 0, -8, -11, -14, -16, -14, -11, -8};
+      static const int8 kChainChomp_Yvel[16] = {-16, -14, -11, -8, 0, 8, 11, 14, 16, 14, 11, 8, 0, -9, -11, -14};
+      if (++sprite_subtype2[k] == 4) {
+        sprite_subtype2[k] = 0;
+        sprite_ai_state[k] = 2;
+        int j = GetRandomNumber() & 15;
+        sprite_x_vel[k] = kChainChomp_Xvel[j] << 2;
+        sprite_y_vel[k] = kChainChomp_Yvel[j] << 2;
+        GetRandomNumber();
+        Sprite_ApplySpeedTowardsLink(k, 64);
+        SpriteSfx_QueueSfx3WithPan(k, 0x4);
+      } else {
+        sprite_delay_main[k] = (GetRandomNumber() & 31) + 16;
+        int j = GetRandomNumber() & 15;
+        sprite_x_vel[k] = kChainChomp_Xvel[j];
+        sprite_y_vel[k] = kChainChomp_Yvel[j];
+        sprite_ai_state[k] = 1;
+      }
+    } else {
+      sprite_x_vel[k] = 0;
+      sprite_y_vel[k] = 0;
+    }
+    break;
+  case 1:  //
+    if (!sprite_delay_main[k]) {
+      sprite_delay_main[k] = 32;
+      sprite_ai_state[k] = 0;
+    }
+    if (!(sprite_delay_main[k] & 15))
+      ChainChomp_MoveChain(k);
+    if (!sprite_z[k])
+      sprite_z_vel[k] = 16;
+    if (!sprite_anim_clock[k]) {
+      uint16 x = sprite_A[k] | sprite_B[k] << 8;
+      uint16 y = sprite_C[k] | sprite_G[k] << 8;
+      ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLocation(k, x, y, 16);
+      sprite_x_vel[k] = pt.x;
+      sprite_y_vel[k] = pt.y;
+      Sprite_MoveXY(k);
+      sprite_delay_main[k] = 12;
+    }
+    break;
+  case 2:  //
+    if (!sprite_anim_clock[k]) {
+      sprite_x_vel[k] = -sprite_x_vel[k];
+      sprite_y_vel[k] = -sprite_y_vel[k];
+      Sprite_MoveXY(k);
+      sprite_x_vel[k] = sprite_y_vel[k] = 0;
+      sprite_ai_state[k] = 3;
+      sprite_delay_aux1[k] = 48;
+    }
+    ChainChomp_MoveChain(k);
+    ChainChomp_MoveChain(k);
+    break;
+  case 3:  //
+    if (!sprite_delay_aux1[k]) {
+      sprite_ai_state[k] = 0;
+      sprite_delay_main[k] = 48;
+    }
+    ChainChomp_MoveChain(k);
+    ChainChomp_MoveChain(k);
+    break;
+  }
+
+}
+
+void ChainChomp_MoveChain(int k) {  // 9dc02a
+  static const uint8 kChainChomp_Muls[6] = {205, 154, 102, 51, 8, 0xbd}; // wtf
+  uint16 x = sprite_A[k] | sprite_B[k] << 8;
+  uint16 y = sprite_C[k] | sprite_G[k] << 8;
+  int pos = k * 8;
+  uint16 x2 = chainchomp_x_hist[pos] - x;
+  uint16 y2 = chainchomp_y_hist[pos] - y;
+  pos++;
+  for (int i = 5; i >= 0; i--) {
+    uint16 x3 = x + ChainChomp_OneMult(x2, kChainChomp_Muls[(pos & 7) - 1]);
+    uint16 y3 = y + ChainChomp_OneMult(y2, kChainChomp_Muls[(pos & 7) - 1]);
+    if (chainchomp_x_hist[pos] - x3)
+      chainchomp_x_hist[pos] += sign16(chainchomp_x_hist[pos] - x3) ? 1 : -1;
+    if (chainchomp_y_hist[pos] - y3)
+      chainchomp_y_hist[pos] += sign16(chainchomp_y_hist[pos] - y3) ? 1 : -1;
+    pos++;
+  }
+}
+
+void ChainChomp_HandleLeash(int k) {  // 9dc0f2
+  int pos = k * 8;
+  chainchomp_x_hist[pos] = cur_sprite_x;
+  chainchomp_y_hist[pos] = cur_sprite_y;
+  for (int i = 0; i < 6; i++, pos++) {
+    uint16 x = chainchomp_x_hist[pos] - chainchomp_x_hist[pos + 1];
+    if (!sign16(x - 8))
+      chainchomp_x_hist[pos + 1] = chainchomp_x_hist[pos] - 8;
+    else if (sign16(x + 8))
+      chainchomp_x_hist[pos + 1] = chainchomp_x_hist[pos] + 8;
+
+    uint16 y = chainchomp_y_hist[pos] - chainchomp_y_hist[pos + 1];
+    if (!sign16(y - 8))
+      chainchomp_y_hist[pos + 1] = chainchomp_y_hist[pos] - 8;
+    else if (sign16(y + 8))
+      chainchomp_y_hist[pos + 1] = chainchomp_y_hist[pos] + 8;
+  }
+}
+
+void ChainChomp_Draw(int k) {  // 9dc192
+  static const uint8 kChainChomp_Gfx[16] = {0, 1, 2, 3, 3, 3, 2, 1, 0, 0, 0, 4, 4, 4, 0, 0};
+  static const uint8 kChainChomp_OamFlags[16] = {0x40, 0x40, 0x40, 0x40, 0, 0, 0, 0, 0, 0, 0, 0, 0x40, 0x40, 0x40, 0x40};
+
+  int j = sprite_D[k];
+  sprite_graphics[k] = kChainChomp_Gfx[j];
+  sprite_oam_flags[k] = sprite_oam_flags[k] & 0x3f | kChainChomp_OamFlags[j];
+  SpriteDraw_SingleLarge(k);
+  OamEnt *oam = GetOamCurPtr() + 1;
+  uint8 flags = sprite_oam_flags[k] ^ sprite_obj_prio[k];
+  int r8 = (sprite_delay_aux1[k] & 1) + 4;
+  int pos = k * 8;
+  for (int i = 5; i >= 0; i--, pos++, oam++) {
+    SetOamHelper0(oam,
+                  chainchomp_x_hist[pos] + r8 - BG2HOFS_copy2,
+                  chainchomp_y_hist[pos] + r8 - BG2VOFS_copy2,
+                  0x8b,
+                  flags & 0xf0 | 0xd, 0);
+  }
+}
+
+void Sprite_C9_Tektite(int k) {  // 9dc275
+  int j = sprite_anim_clock[k];
+  if (j) {
+    sprite_ignore_projectile[k] = j;
+    sprite_obj_prio[k] = 0x30;
+  }
+  switch (j) {
+  case 0: Sprite_Tektite(k); break;
+  case 1: Sprite_PhantomGanon(k); break;
+  case 2: Sprite_GanonTrident(k); break;
+  case 3: Sprite_SpiralFireBat(k); break;
+  case 4: Sprite_FireBat_Launched(k); break;
+  case 5: Sprite_FireBat_Trailer(k); break;
+  }
+}
+
+void Sprite_Tektite(int k) {  // 9dc293
+  int j;
+
+  if (sprite_delay_aux1[k])
+    sprite_graphics[k] = 0;
+  Tektite_Draw(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  if (Sprite_ReturnIfRecoiling(k))
+    return;
+  Sprite_CheckDamageToAndFromLink(k);
+  Sprite_MoveXYZ(k);
+  Sprite_BounceFromTileCollision(k);
+  sprite_z_vel[k] -= 1;
+  if (sign8(sprite_z[k])) {
+    sprite_z[k] = 0;
+    sprite_z_vel[k] = 0;
+  }
+  switch(sprite_ai_state[k]) {
+  case 0: { // Stationary
+    static const uint8 kTektite_Dir[4] = {3, 2, 1, 0};
+    static const int8 kTektite_Xvel[4] = {16, -16, 16, -16};
+    static const int8 kTektite_Yvel[4] = {16, 16, -16, -16};
+    PointU8 pt;
+    j = Sprite_DirectionToFaceLink(k, &pt);
+    if ((uint8)(pt.x + 40) < 80 && (uint8)(pt.y + 40) < 80 && player_oam_y_offset != 0x80 &&
+        !(sprite_z[k] | sprite_pause[k]) && link_is_on_lower_level == sprite_floor[k] && j != kTektite_Dir[link_direction_facing >> 1]) {
+      ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLink(k, 32);
+      sprite_x_vel[k] = -pt.x;
+      sprite_y_vel[k] = -pt.y;
+      sprite_z_vel[k] = 16;
+      sprite_ai_state[k] = 1;
+      return;
+    }
+    if (!sprite_delay_main[k]) {
+      sprite_ai_state[k]++;
+      sprite_B[k]++;
+      if (sprite_B[k] == 4) {
+        sprite_B[k] = 0;
+        sprite_ai_state[k]++;
+        sprite_delay_main[k] = (GetRandomNumber() & 63) + 48;
+        sprite_z_vel[k] = 12;
+        j = Sprite_IsBelowLink(k).a * 2 + Sprite_IsRightOfLink(k).a;
+      } else {
+        sprite_z_vel[k] = (GetRandomNumber() & 7) + 24;
+        j = GetRandomNumber() & 3;
+      }
+      sprite_x_vel[k] = kTektite_Xvel[j];
+      sprite_y_vel[k] = kTektite_Yvel[j];
+    } else {
+      sprite_graphics[k] = sprite_delay_main[k] >> 4 & 1;
+    }
+    break;
+  }
+  case 1: // Aloft
+    if (!sprite_z[k]) {
+reset_state:
+      sprite_ai_state[k] = 0;
+      sprite_delay_main[k] = (GetRandomNumber() & 63) + 72;
+      sprite_y_vel[k] = 0;
+      sprite_x_vel[k] = 0;
+    } else {
+      sprite_graphics[k] = 2;
+    }
+    break;
+  case 2: // RepeatingHop
+    if (!sprite_delay_main[k])
+      goto reset_state;
+    if (!sprite_z[k]) {
+      sprite_z_vel[k] = 12;
+      sprite_z[k]++;
+      sprite_delay_aux1[k] = 8;
+    }
+    sprite_graphics[k] = 2;
+    break;
+  }
+}
+
+void Tektite_Draw(int k) {  // 9dc3f5
+  static const DrawMultipleData kTektite_Dmd[6] = {
+    {-8, 0, 0x00c8, 2},
+    { 8, 0, 0x40c8, 2},
+    {-8, 0, 0x00ca, 2},
+    { 8, 0, 0x40ca, 2},
+    {-8, 0, 0x00ea, 2},
+    { 8, 0, 0x40ea, 2},
+  };
+  PrepOamCoordsRet info;
+  Sprite_DrawMultiple(k, &kTektite_Dmd[sprite_graphics[k] * 2], 2, &info);
+  SpriteDraw_Shadow(k, &info);
+}
+
+void Sprite_C8_BigFairy(int k) {  // 9dc414
+  if (sprite_head_dir[k])
+    Sprite_FairyCloud(k);
+  else
+    Sprite_BigFairy(k);
+}
+
+void Sprite_FairyCloud(int k) {  // 9dc41c
+  PrepOamCoordsRet info;
+  Sprite_PrepOamCoord(k, &info);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  sprite_subtype2[k]++;
+  FaerieCloud_Draw(k);
+  if (!(sprite_subtype2[k] & 31))
+    SpriteSfx_QueueSfx2WithPan(k, 0x31);
+  switch (sprite_ai_state[k]) {
+  case 0:
+    sprite_A[k] = 0;
+    Sprite_ApplySpeedTowardsLink(k, 8);
+    Sprite_MoveXY(k);
+    Sprite_Get16BitCoords(k);
+    if ((uint16)(link_x_coord - cur_sprite_x + 3) < 6 &&
+        (uint16)(link_y_coord - cur_sprite_y + 11) < 6) {
+      WORD(link_hearts_filler) += 0xa0;
+      sprite_ai_state[k] = 1;
+    }
+    break;
+  case 1:
+    if (link_health_current == link_health_capacity) {
+      sprite_ai_state[k]++;
+      sprite_delay_aux2[0] = 112; // zelda bug
+    }
+    break;
+  case 2:
+    if ((sprite_subtype2[k] & 15) || sign8(sprite_A[k]))
+      return;
+    sprite_A[k] = sprite_A[k] * 2 + 1;
+    if (sprite_A[k] >= 0x80) {
+      sprite_A[k] = 255;
+      flag_is_link_immobilized = 0;
+      sprite_state[k] = 0;
+    }
+    break;
+  }
+}
+
+void Sprite_BigFairy(int k) {  // 9dc4bf
+  PointU8 pt;
+  int i = sprite_delay_aux2[k];
+  if (i != 0 && i < 0x40) {
+    if (--i == 0)
+      sprite_state[k] = 0;
+    if (i & 1)
+      return;
+  }
+  BigFaerie_Draw(k);
+  if (sign8(--sprite_G[k])) {
+    sprite_G[k] = 5;
+    sprite_graphics[k] = sprite_graphics[k] + 1 & 3;
+  }
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  sprite_subtype2[k]++;
+  switch (sprite_ai_state[k]) {
+  case 0:  // await close player
+    FaerieCloud_Draw(k);
+    sprite_A[k] = 1;
+    Sprite_DirectionToFaceLink(k, &pt);
+    if ((uint8)(pt.x + 0x30) < 0x60 && (uint8)(pt.y + 0x30) < 0x60) {
+      Link_CancelDash();
+      sprite_ai_state[k] = 1;
+      dialogue_message_index = 0x15a;
+      Sprite_ShowMessageMinimal();
+      flag_is_link_immobilized = 1;
+      SpriteSpawnInfo info;
+      int j = Sprite_SpawnDynamically(k, 0xC8, &info);
+      Sprite_SetSpawnedCoordinates(j, &info);
+      sprite_head_dir[j] = 1;
+      sprite_y_lo[j] -= sprite_z[k];
+      sprite_z[j] = 0;
+    }
+    break;
+  case 1:  // dormant
+    break;
+  }
+}
+
+void BigFaerie_Draw(int k) {  // 9dc5d0
+  static const DrawMultipleData kBigFaerie_Dmd[16] = {
+    {-4, -8, 0x008e, 2},
+    { 4, -8, 0x408e, 2},
+    {-4,  8, 0x00ae, 2},
+    { 4,  8, 0x40ae, 2},
+    {-4, -8, 0x008c, 2},
+    { 4, -8, 0x408c, 2},
+    {-4,  8, 0x00ac, 2},
+    { 4,  8, 0x40ac, 2},
+    {-4, -8, 0x008a, 2},
+    { 4, -8, 0x408a, 2},
+    {-4,  8, 0x00aa, 2},
+    { 4,  8, 0x40aa, 2},
+    {-4, -8, 0x008c, 2},
+    { 4, -8, 0x408c, 2},
+    {-4,  8, 0x00ac, 2},
+    { 4,  8, 0x40ac, 2},
+  };
+  PrepOamCoordsRet info;
+  Sprite_DrawMultiple(k, &kBigFaerie_Dmd[sprite_graphics[k] * 4], 4, &info);
+  SpriteDraw_Shadow(k, &info);
+}
+
+void FaerieCloud_Draw(int k) {  // 9dc616
+  static const int8 kFaerieCloud_Draw_XY[8] = {-12, -6, 0, 6, 12, 18, 0, 6};
+  if (!sign8(sprite_A[k]) && !(sprite_A[k] & sprite_subtype2[k])) {
+    int x = kFaerieCloud_Draw_XY[GetRandomNumber() & 7];
+    int y = kFaerieCloud_Draw_XY[GetRandomNumber() & 7];
+    Sprite_GarnishSpawn_Sparkle(k, x, y);
+  }
+}
+
+void Sprite_C7_Pokey(int k) {  // 9dc64f
+  if (sprite_C[k]) {
+    SpriteDraw_SingleLarge(k);
+    if (Sprite_ReturnIfInactive(k))
+      return;
+    Sprite_CheckDamageToAndFromLink(k);
+    Sprite_MoveXYZ(k);
+    sprite_z_vel[k] -= 2;
+    if (sign8(sprite_z[k])) {
+      sprite_z_vel[k] = 16;
+      sprite_z[k] = 0;
+    }
+    if (Sprite_BounceFromTileCollision(k))
+      SpriteSfx_QueueSfx2WithPan(k, 0x21);
+    if (sprite_G[k] >= 3) {
+      sprite_state[k] = 6;
+      sprite_delay_main[k] = 10;
+      sprite_flags5[k] = 0;
+      SpriteSfx_QueueSfx2WithPan(k, 0x1e);
+    }
+    return;
+  }
+
+  Hokbok_Draw(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  if (sprite_A[k] && sprite_F[k] == 15) {
+    sprite_F[k] = 6;
+    sprite_z[k] += sprite_B[k];
+    if (!--sprite_A[k])
+      sprite_health[k] = 17;
+    sprite_x_vel[k] += sign8(sprite_x_vel[k]) ? -4 : 4;
+    sprite_y_vel[k] += sign8(sprite_y_vel[k]) ? -4 : 4;
+
+    SpriteSpawnInfo info;
+    int j = Sprite_SpawnDynamically(k, 0xc7, &info);
+    if (j >= 0) {
+      Sprite_SetSpawnedCoordinates(j, &info);
+      sprite_C[j] = 1;
+      sprite_health[j] = 1;
+      sprite_x_vel[j] = sprite_x_recoil[k];
+      sprite_y_vel[j] = sprite_y_recoil[k];
+      sprite_defl_bits[j] = 64;
+    }
+  }
+  if (Sprite_ReturnIfRecoiling(k))
+    return;
+  Sprite_CheckDamageToAndFromLink(k);
+  switch(sprite_ai_state[k]) {
+  case 0:
+    if (!sprite_delay_main[k]) {
+      sprite_ai_state[k] = 1;
+      sprite_z_vel[k] = 16;
+    } else {
+      static const uint8 kHokbok_B[8] = {8, 7, 6, 5, 4, 5, 6, 7};
+      sprite_B[k] = kHokbok_B[sprite_delay_main[k] >> 1];
+    }
+    break;
+  case 1:
+    Sprite_MoveXYZ(k);
+    sprite_z_vel[k] -= 2;
+    if (sign8(sprite_z[k])) {
+      sprite_z[k] = 0;
+      sprite_ai_state[k] = 0;
+      sprite_delay_main[k] = 15;
+    }
+    Sprite_BounceFromTileCollision(k);
+    break;
+  }
+}
+
+void Hokbok_Draw(int k) {  // 9dc77d
+  PrepOamCoordsRet info;
+  if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
+    return;
+  OamEnt *oam = GetOamCurPtr() + 3;
+  int d = sprite_B[k];
+  uint16 y = info.y;
+  for (int i = sprite_A[k]; i >= 0; i--, oam--) {
+    SetOamHelper0(oam, info.x, y,
+                  ((i == 0) ? 0xa2 : 0xa0) - ((d < 7) ? 0x20 : 0), info.flags, 2);
+    y -= d;
+  }
+  SpriteDraw_Shadow(k, &info);
+}
+
+void Sprite_C5_Medusa(int k) {  // 9dc7eb
+  PrepOamCoordsRet info;
+  Sprite_PrepOamCoord(k, &info);
+  if (!player_is_indoors) {
+    sprite_x_vel[k] = 255;
+    sprite_subtype[k] = 255;
+    if (!Sprite_CheckTileCollision(k))
+      return;
+    if (Sprite_ReturnIfInactive(k))
+      return;
+    sprite_type[k] = 0x19;
+    SpritePrep_LoadProperties(k);
+    sprite_E[k]++;
+    sprite_x_lo[k] += 8;
+    sprite_y_lo[k] -= 8;
+    SpriteSfx_QueueSfx3WithPan(k, 0x19);
+    sprite_defl_bits[k] = 0x80;
+  } else {
+    if (Sprite_ReturnIfInactive(k))
+      return;
+    sprite_subtype2[k]++;
+    if (!(sprite_subtype2[k] & 0x7f) && sprite_floor[k] == link_is_on_lower_level) {
+      int j = Sprite_SpawnFireball(k);
+      if (j >= 0) {
+        sprite_defl_bits[j] = sprite_defl_bits[j] | 8;
+        sprite_bump_damage[j] = 4;
+      }
+    }
+  }
+}
+
+void Sprite_C6_4WayShooter(int k) {  // 9dc869
+  static const int8 kFireballJunction_X[4] = {12, -12, 0, 0};
+  static const int8 kFireballJunction_Y[4] = {0, 0, 12, -12};
+  static const int8 kFireballJunction_XYvel[6] = {0, 0, 40, -40, 0, 0};
+  PrepOamCoordsRet info;
+  Sprite_PrepOamCoord(k, &info);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  if (sprite_delay_main[k] == 24) {
+    int j = Sprite_SpawnFireball(k);
+    if (j >= 0) {
+      sprite_defl_bits[j] |= 8;
+      sprite_bump_damage[j] = 4;
+      int i = Sprite_DirectionToFaceLink(j, NULL);
+      sprite_x_vel[j] = kFireballJunction_XYvel[i + 2];
+      sprite_y_vel[j] = kFireballJunction_XYvel[i];
+      Sprite_SetX(j, Sprite_GetX(j) + kFireballJunction_X[i]);
+      Sprite_SetY(j, Sprite_GetY(j) + kFireballJunction_Y[i]);
+    }
+  } else if (sprite_delay_main[k] == 0) {
+    if (button_b_frames && sprite_floor[k] == link_is_on_lower_level)
+      sprite_delay_main[k] = 32;
+  }
+}
+
+void Sprite_C4_Thief(int k) {  // 9dc8d8
+  int j;
+
+
+
+  Thief_Draw(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  if (Sprite_ReturnIfRecoiling(k))
+    return;
+  Sprite_CheckDamageFromLink(k);
+  if (sprite_ai_state[k] != 3) {
+    j = Sprite_DirectionToFaceLink(k, NULL);
+    sprite_head_dir[k] = j;
+    if ((j ^ sprite_D[k]) == 1)
+      sprite_D[k] = j;
+  }
+  switch (sprite_ai_state[k]) {
+  case 0:  // loitering
+    Thief_CheckCollisionWithLink(k);
+    if (!sprite_delay_main[k]) {
+      if ((uint16)(link_x_coord - cur_sprite_x + 0x50) < 0xa0 &&
+        (uint16)(link_y_coord - cur_sprite_y + 0x50) < 0xa0) {
+        sprite_ai_state[k]++;
+        sprite_delay_main[k] = 16;
+      }
+    }
+    sprite_graphics[k] = kThief_Gfx[sprite_D[k]];
+    break;
+  case 1:  // watch player
+    Thief_CheckCollisionWithLink(k);
+    sprite_D[k] = sprite_head_dir[k] = Sprite_DirectionToFaceLink(k, NULL);
+    if (!sprite_delay_main[k]) {
+      sprite_ai_state[k] = 2;
+      sprite_delay_main[k] = 32;
+    }
+thief_common:
+    if (!(frame_counter & 31))
+      sprite_D[k] = sprite_head_dir[k];
+    sprite_graphics[k] = kThief_Gfx[4 + sprite_D[k] + (++sprite_subtype2[k] & 4)];
+    break;
+  case 2:  // chase player
+    Sprite_ApplySpeedTowardsLink(k, 18);
+    if (!sprite_wallcoll[k])
+      Sprite_MoveXY(k);
+    Sprite_CheckTileCollision(k);
+    if (!sprite_delay_main[k]) {
+      if ((uint16)(link_x_coord - cur_sprite_x + 0x50) >= 0xa0 ||
+        (uint16)(link_y_coord - cur_sprite_y + 0x50) >= 0xa0) {
+        sprite_ai_state[k] = 0;
+        sprite_delay_main[k] = 128;
+      }
+    }
+    if (Sprite_CheckDamageToLink(k)) {
+      sprite_ai_state[k]++;
+      sprite_delay_main[k] = 32;
+      Thief_SpillItems(k);
+      SpriteSfx_QueueSfx2WithPan(k, 0xb);
+    }
+    goto thief_common;
+  case 3:  // steal
+    Thief_CheckCollisionWithLink(k);
+    j = Thief_ScanForBooty(k);
+
+    if (!sprite_delay_main[k]) {
+      sprite_graphics[k] = kThief_Gfx[4 + sprite_D[k] + (++sprite_subtype2[k] & 4)];
+      if (!sprite_wallcoll[k])
+        Sprite_MoveXY(k);
+      Sprite_CheckTileCollision(k);
+      sprite_D[k] = sprite_head_dir[k];
+    }
+    if (!((k ^ frame_counter) & 3))
+      sprite_head_dir[k] = Sprite_DirectionToFaceLocation(k, Sprite_GetX(j), Sprite_GetY(j));
+    break;
+  }
+}
+
+uint8 Thief_ScanForBooty(int k) {  // 9dca24
+  for (int j = 15; j >= 0; j--) {
+    if (sprite_state[j] && (sprite_type[j] == 0xdc || sprite_type[j] == 0xe1 || sprite_type[j] == 0xd9)) {
+      Thief_TargetBooty(k, j);
+      return j;
+    }
+  }
+  sprite_ai_state[k] = 0;
+  sprite_delay_main[k] = 64;
+  return 0xff;
+}
+
+void Thief_TargetBooty(int k, int j) {  // 9dca4c
+  if (!((k ^ frame_counter) & 3)) {
+    ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLocation(k, Sprite_GetX(j), Sprite_GetY(j), 19);
+    sprite_x_vel[k] = pt.x;
+    sprite_y_vel[k] = pt.y;
+  }
+  for (j = 15; j >= 0; j--) {
+    if (!((j ^ frame_counter) & 3 | sprite_delay_aux4[j]) && sprite_state[j] &&
+        (sprite_type[j] == 0xdc || sprite_type[j] == 0xe1 || sprite_type[j] == 0xd9)) {
+      Thief_GrabBooty(k, j);
+    }
+  }
+}
+
+void Thief_GrabBooty(int k, int j) {  // 9dca9e
+  if ((uint16)(Sprite_GetX(j) - cur_sprite_x + 8) < 16 &&
+      (uint16)(Sprite_GetY(j) - cur_sprite_y + 12) < 24) {
+    sprite_state[j] = 0;
+
+    int t = sprite_type[j] - 0xd8;
+    SpriteSfx_QueueSfx3WithPan(t, kAbsorptionSfx[t]);
+    sprite_delay_main[k] = 14;
+  }
+}
+
+void Thief_CheckCollisionWithLink(int k) {  // 9dcaf2
+  if (Sprite_CheckDamageToLink_same_layer(k)) {
+    ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLink(k, 32);
+    link_actual_vel_y = pt.y;
+    sprite_y_recoil[k] = pt.y ^ 0xff;
+    link_actual_vel_x = pt.x;
+    sprite_x_recoil[k] = pt.x ^ 0xff;
+    link_incapacitated_timer = 4;
+    sprite_F[k] = 12;
+    SpriteSfx_QueueSfx2WithPan(k, 0xb);
+  }
+}
+
+void Thief_SpillItems(int k) {  // 9dcb30
+  static const uint8 kThiefSpawn_Items[4] = {0xd9, 0xe1, 0xdc, 0xd9};
+  static const int8 kThiefSpawn_Xvel[6] = {0, 24, 24, 0, -24, -24};
+  static const int8 kThiefSpawn_Yvel[6] = {-32, -16, 16, 32, 16, -16};
+
+  tmp_counter = 5;
+  do {
+    byte_7E0FB6 = GetRandomNumber() & 3;
+    int j;
+    if (byte_7E0FB6 == 1) {
+      j = link_num_arrows;
+    } else if (byte_7E0FB6 == 2) {
+      j = link_item_bombs;
+    } else {
+      j = link_rupees_goal;
+    }
+    if (!j)
+      return;
+    SpriteSpawnInfo info;
+    j = Sprite_SpawnDynamicallyEx(k, kThiefSpawn_Items[byte_7E0FB6], &info, 7);
+    if (j < 0)
+      return;
+    if (byte_7E0FB6 == 1)
+      link_num_arrows--;
+    else if (byte_7E0FB6 == 2)
+      link_item_bombs--;
+    else
+      link_rupees_goal--;
+    Sprite_SetX(j, link_x_coord);
+    Sprite_SetY(j, link_y_coord);
+    sprite_z_vel[j] = 0x18;
+    sprite_x_vel[j] = kThiefSpawn_Xvel[tmp_counter];
+    sprite_y_vel[j] = kThiefSpawn_Yvel[tmp_counter];
+    sprite_delay_aux4[j] = 32;
+    sprite_head_dir[j] = 1;
+    sprite_stunned[j] = 255;
+  } while (!sign8(--tmp_counter));
+}
+
+void Thief_Draw(int k) {  // 9dcc9e
+  static const DrawMultipleData kThief_Dmd[24] = {
+    {0, -6, 0x0000, 2},
+    {0,  0, 0x0006, 2},
+    {0, -6, 0x0000, 2},
+    {0,  0, 0x4006, 2},
+    {0, -6, 0x0000, 2},
+    {0,  0, 0x0020, 2},
+    {0, -7, 0x0004, 2},
+    {0,  0, 0x0022, 2},
+    {0, -7, 0x0004, 2},
+    {0,  0, 0x4022, 2},
+    {0, -7, 0x0004, 2},
+    {0,  0, 0x0024, 2},
+    {0, -8, 0x0002, 2},
+    {0,  0, 0x000a, 2},
+    {0, -7, 0x0002, 2},
+    {0,  0, 0x000e, 2},
+    {0, -7, 0x0002, 2},
+    {0,  0, 0x000a, 2},
+    {0, -8, 0x4002, 2},
+    {0,  0, 0x400a, 2},
+    {0, -7, 0x4002, 2},
+    {0,  0, 0x400e, 2},
+    {0, -7, 0x4002, 2},
+    {0,  0, 0x400a, 2},
+  };
+  static const uint8 kThief_DrawChar[4] = {2, 2, 0, 4};
+  static const uint8 kThief_DrawFlags[4] = {0x40, 0, 0, 0};
+  PrepOamCoordsRet info;
+  Sprite_DrawMultiple(k, &kThief_Dmd[sprite_graphics[k] * 2], 2, &info);
+  if (!sprite_pause[k]) {
+    OamEnt *oam = GetOamCurPtr();
+    int j = sprite_head_dir[k];
+    oam->charnum = kThief_DrawChar[j];
+    oam->flags = (oam->flags & ~0x40) | kThief_DrawFlags[j];
+    SpriteDraw_Shadow(k, &info);
+  }
+}
+
+void Sprite_C3_Gibo(int k) {  // 9dcce1
+  if (sprite_B[k]) {
+    SpriteDraw_SingleLarge(k);
+    if (Sprite_ReturnIfInactive(k))
+      return;
+    Sprite_CheckDamageToAndFromLink(k);
+    sprite_oam_flags[k] = sprite_oam_flags[k] & 0x3f | kGibo_OamFlags[++sprite_subtype2[k] >> 2 & 3];
+    if (sprite_delay_main[k]) {
+      Sprite_MoveXY(k);
+      Sprite_BounceFromTileCollision(k);
+    }
+    return;
+  }
+  Gibo_Draw(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  sprite_anim_clock[k]++;
+  int j = sprite_head_dir[k], i;
+  if (sprite_state[j] == 6) {
+    sprite_state[k] = sprite_state[j];
+    sprite_delay_main[k] = sprite_delay_main[j];
+    sprite_flags2[k] += 4;
+    return;
+  }
+  sprite_subtype2[k] = frame_counter >> 3 & 3;
+  if (!(frame_counter & 63))
+    sprite_D[k] = Sprite_IsRightOfLink(k).a << 2;
+  Sprite_CheckDamageToLink(k);  // original destroys y which is a bug
+  switch(sprite_ai_state[k]) {
+  case 0:  // expel nucleus
+    if (sprite_delay_main[k] == 0) {
+      sprite_ai_state[k]++;
+      sprite_delay_main[k] = 48;
+      sprite_A[k]++;
+      SpriteSpawnInfo info;
+      j = Sprite_SpawnDynamically(k, 0xc3, &info);
+      if (j >= 0) {
+        static const int8 kGibo_Xvel[8] = {16, 16, 0, -16, -16, -16, 0, 16};
+        static const int8 kGibo_Yvel[8] = {0, 0, 16, -16, 16, 16, -16, -16};
+        Sprite_SetSpawnedCoordinates(j, &info);
+        sprite_head_dir[k] = j;
+        sprite_flags2[j] = 1;
+        sprite_B[j] = 1;
+        sprite_flags3[j] = 16;
+        sprite_health[j] = sprite_G[k];
+        sprite_oam_flags[j] = 7;
+        sprite_delay_main[j] = 48;
+        if (++sprite_C[k] == 3) {
+          sprite_C[k] = 0;
+          i = Sprite_DirectionToFaceLink(k, NULL);
+        } else {
+          i = GetRandomNumber() & 7;
+        }
+        sprite_x_vel[j] = kGibo_Xvel[i];
+        sprite_y_vel[j] = kGibo_Yvel[i];
+      }
+    } else if (sprite_delay_main[k] == 32) {
+      sprite_delay_aux1[k] = 32;
+    }
+    break;
+  case 1:  // delay pursuit
+    if (!sprite_delay_main[k])
+      sprite_ai_state[k]++;
+    break;
+  case 2:  // pursue nucleus
+    if (!((k ^ frame_counter) & 3)) {
+      uint16 x = Sprite_GetX(j), y = Sprite_GetY(j);
+      if ((uint16)(cur_sprite_x - x + 2) < 4 &&
+          (uint16)(cur_sprite_y - y + 2) < 4) {
+        j = sprite_head_dir[k];
+        sprite_state[j] = 0;
+        sprite_A[k] = 0;
+        sprite_ai_state[k] = 0;
+        sprite_G[k] = sprite_health[j];
+        sprite_delay_main[k] = (GetRandomNumber() & 31) + 32;
+        return;
+      }
+      ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLocation(k, x, y, 16);
+      sprite_x_vel[k] = pt.x;
+      sprite_y_vel[k] = pt.y;
+    }
+    Sprite_MoveXY(k);
+    break;
+  }
+}
+
+void Gibo_Draw(int k) {  // 9dcf5e
+  static const DrawMultipleData kGibo_Dmd[32] = {
+    { 4, -4, 0x408a, 2},
+    {-4, -4, 0x408f, 0},
+    {12, 12, 0x408e, 0},
+    {-4,  4, 0x408c, 2},
+    { 4, -4, 0x40aa, 2},
+    {-4, -4, 0x409f, 0},
+    {12, 12, 0x409e, 0},
+    {-4,  4, 0x40ac, 2},
+    { 3, -3, 0x40aa, 2},
+    {-3, -3, 0x409f, 0},
+    {11, 11, 0x409e, 0},
+    {-3,  3, 0x40ac, 2},
+    { 3, -3, 0x408a, 2},
+    {-3, -3, 0x408f, 0},
+    {11, 11, 0x408e, 0},
+    {-3,  3, 0x408c, 2},
+    {-3, -4, 0x008a, 2},
+    {13, -4, 0x008f, 0},
+    {-3, 12, 0x008e, 0},
+    { 5,  4, 0x008c, 2},
+    {-3, -4, 0x00aa, 2},
+    {13, -4, 0x009f, 0},
+    {-3, 12, 0x009e, 0},
+    { 5,  4, 0x00ac, 2},
+    {-2, -3, 0x00aa, 2},
+    {12, -3, 0x009f, 0},
+    {-2, 11, 0x009e, 0},
+    { 4,  3, 0x00ac, 2},
+    {-2, -3, 0x008a, 2},
+    {12, -3, 0x008f, 0},
+    {-2, 11, 0x008e, 0},
+    { 4,  3, 0x008c, 2},
+  };
+  if (!sprite_A[k]) {
+    uint8 bak0 = sprite_flags2[k];
+    sprite_flags2[k] = 1;
+    uint8 bak1 = sprite_oam_flags[k];
+    sprite_oam_flags[k] = kGibo_OamFlags[sprite_anim_clock[k] >> 2 & 3] |
+                          kGibo_OamFlags2[sprite_delay_aux1[k] >> 2 & 1];
+    SpriteDraw_SingleLarge(k);
+    sprite_oam_flags[k] = bak1;
+    sprite_flags2[k] = bak0;
+  }
+  oam_cur_ptr += 8;
+  oam_ext_cur_ptr += 2;
+  Sprite_DrawMultiple(k, &kGibo_Dmd[(sprite_subtype2[k] + sprite_D[k]) * 4], 4, NULL);
+}
+
+void Sprite_C2_Boulder(int k) {  // 9dcfcb
+  if (!player_is_indoors) {
+    Boulder_OutdoorsMain(k);
+    return;
+  }
+  if (byte_7E0FC6 < 3)
+    SpriteDraw_SingleSmall(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  sprite_oam_flags[k] = frame_counter << 2 & 0xc0;
+  Sprite_MoveXYZ(k);
+  if ((k ^ frame_counter) & 3)
+    return;
+  if ((uint16)(cur_sprite_x - link_x_coord + 4) < 16 && (uint16)(cur_sprite_y - link_y_coord - 4) < 12)
+    Sprite_AttemptDamageToLinkPlusRecoil(k);
+  if (!((k ^ frame_counter) & 3) && Sprite_CheckTileCollision(k))
+    sprite_state[k] = 0;
+}
+
+void Boulder_OutdoorsMain(int k) {  // 9dd02a
+  static const int8 kBoulder_Zvel[2] = {32, 48};
+  static const int8 kBoulder_Yvel[2] = {8, 32};
+  static const int8 kBoulder_Xvel[4] = {24, 16, -24, -16};
+  sprite_obj_prio[k] = 0x30;
+  Boulder_Draw(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  sprite_subtype2[k] -= sprite_D[k];
+  Sprite_CheckDamageToAndFromLink(k);
+  Sprite_MoveXYZ(k);
+  sprite_z_vel[k]-=2;
+  if (sign8(sprite_z[k])) {
+    sprite_z[k] = 0;
+    int j = Sprite_CheckTileCollision(k) != 0;
+    sprite_z_vel[k] = kBoulder_Zvel[j];
+    sprite_y_vel[k] = kBoulder_Yvel[j];
+    j += (GetRandomNumber() & 1) * 2;
+    sprite_x_vel[k] = kBoulder_Xvel[j];
+    sprite_D[k] = (j & 2) - 1;
+    SpriteSfx_QueueSfx2WithPan(k, 0xb);
+
+  }
+}
+
+void Boulder_Draw(int k) {  // 9dd185
+  static const DrawMultipleData kBoulder_Dmd[16] = {
+    {-8, -8, 0x01cc, 2},
+    { 8, -8, 0x01ce, 2},
+    {-8,  8, 0x01ec, 2},
+    { 8,  8, 0x01ee, 2},
+    {-8, -8, 0x41ce, 2},
+    { 8, -8, 0x41cc, 2},
+    {-8,  8, 0x41ee, 2},
+    { 8,  8, 0x41ec, 2},
+    {-8, -8, 0xc1ee, 2},
+    { 8, -8, 0xc1ec, 2},
+    {-8,  8, 0xc1ce, 2},
+    { 8,  8, 0xc1cc, 2},
+    {-8, -8, 0x81ec, 2},
+    { 8, -8, 0x81ee, 2},
+    {-8,  8, 0x81cc, 2},
+    { 8,  8, 0x81ce, 2},
+  };
+  PrepOamCoordsRet info;
+  Sprite_DrawMultiple(k, &kBoulder_Dmd[(sprite_subtype2[k] >> 3 & 3) * 4], 4, &info);
+  Sprite_DrawLargeShadow2(k);
+}
+
+void SpriteDraw_BigShadow(int k, int anim) {  // 9dd1a8
+  cur_sprite_y += sprite_z[k];
+  oam_cur_ptr += 16;
+  oam_ext_cur_ptr += 4;
+  Sprite_DrawMultiple(k, &kLargeShadow_Dmd[anim * 3], 3, NULL);
+  Sprite_Get16BitCoords(k);
+}
+
+void Sprite_DrawLargeShadow2(int k) {  // 9dd1af
+  int z = sprite_z[k] >> 3;
+  SpriteDraw_BigShadow(k, (z > 4) ? 4 : z);
+}
+
+void CutsceneAgahnim_SpawnZeldaOnAltar(int k) {  // 9dd1fd
+  sprite_x_lo[k] += 8;
+  sprite_y_lo[k] += 6;
+  SpriteSpawnInfo info;
+  int j = Sprite_SpawnDynamically(k, 0xc1, &info);
+  sprite_A[j] = 1;
+  sprite_ignore_projectile[j] = 1;
+  Sprite_SetSpawnedCoordinates(j, &info);
+  sprite_y_lo[j] = info.r2_y + 40;
+  sprite_flags2[j] = 0;
+  sprite_oam_flags[j] = 12;
+}
+
+void Sprite_C1_CutsceneAgahnim(int k) {  // 9dd234
+  switch (sprite_A[k]) {
+  case 0: CutsceneAgahnim_Agahnim(k); break;
+  case 1: Sprite_CutsceneAgahnim_Zelda(k); break;
+  }
+
+}
+
+void CutsceneAgahnim_Agahnim(int k) {  // 9dd23f
+  static const uint8 kChattyAgahnim_LevitateGfx[4] = {2, 0, 3, 0};
+  int j;
+  PrepOamCoordsRet info;
+
+  if (sprite_C[k]) {
+    if (!sprite_delay_main[k])
+      sprite_state[k] = 0;
+    if (!(sprite_delay_main[k] & 1))
+      ChattyAgahnim_Draw(k, &info);
+    return;
+  }
+  ChattyAgahnim_Draw(k, &info);
+  SpriteDraw_CutsceneAgahnimSpell(k, &info);
+  if (sprite_pause[k]) {
+    sprite_ai_state[k] = 0;
+    sprite_B[k] = 0;
+    sprite_graphics[k] = 0;
+    sprite_delay_main[k] = 64;
+  }
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  switch(sprite_ai_state[k]) {
+  case 0:  // problab
+    if (!sprite_delay_main[k]) {
+      flag_is_link_immobilized = 1;
+      dialogue_message_index = 0x13d;
+      Sprite_ShowMessageMinimal();
+      sprite_ai_state[k]++;
+    }
+    break;
+  case 1:  // levitate zelda
+    j = ++sprite_B[k];
+    sprite_graphics[k] = sprite_z[15] < 16 ? kChattyAgahnim_LevitateGfx[j >> 5 & 3] : 1;
+    if ((j & 15) == 0) {
+      sprite_graphics[15] = 1;
+      if (++sprite_z[15] == 22) {
+        sound_effect_2 = 0x27;
+        sprite_ai_state[k]++;
+        sprite_delay_main[k] = 255;
+        sprite_subtype2[k] = 2;
+        sprite_subtype[k] = 255;
+      }
+    }
+    break;
+  case 2:  // do telewarp
+    if (!sprite_delay_main[k]) {
+      sprite_ai_state[k]++;
+      sprite_delay_main[k] = 80;
+    } else if (sprite_delay_main[k] == 120) {
+      intro_times_pal_flash = 120;
+    } else if (sprite_delay_main[k] < 128 && (sprite_delay_main[k] & 3) == 0) {
+      sound_effect_2 = 0x2b;
+      if (sprite_subtype2[k] != 14)
+        sprite_subtype2[k] += 4;
+    }
+    break;
+  case 3:  // complete telewarp
+    if (sprite_delay_main[k]) {
+      if (!(sprite_delay_main[k] & 3) && sprite_subtype[k] != 9)
+        sprite_subtype[k] += 2;
+    } else {
+      sprite_delay_main[15] = 19;
+      sprite_ai_state[k]++;
+      sprite_delay_main[k] = 80;
+      sprite_subtype2[k] = 0;
+      sound_effect_1 = 0x33;
+    }
+    break;
+  case 4:  // epiblab
+    if (!sprite_delay_main[k]) {
+      dialogue_message_index = 0x13e;
+      Sprite_ShowMessageMinimal();
+      sprite_ai_state[k]++;
+      sprite_delay_main[k] = 2;
+    }
+    break;
+  case 5:  // teleport to curtains
+    if (sprite_delay_main[k] == 1)
+      sound_effect_2 = 0x28;
+    sprite_y_vel[k] = -32;
+    Sprite_MoveY(k);
+    if (sprite_y_lo[k] < 48) {
+      sprite_delay_aux4[k] = 66;
+      sprite_ai_state[k]++;
+    }
+    Sprite_Agahnim_ApplyMotionBlur(k);
+    break;
+  case 6:  // linger then terminate
+    if (!sprite_delay_aux4[k]) {
+      flag_is_link_immobilized = 0;
+      sprite_state[k] = 0;
+      Sprite_ManuallySetDeathFlagUW(k);
+      dung_savegame_state_bits |= 0x4000;
+    }
+    break;
+  }
+}
+
+int Sprite_Agahnim_ApplyMotionBlur(int k) {  // 9dd392
+  if (frame_counter & 3)
+    return -1;
+  SpriteSpawnInfo info;
+  int j = Sprite_SpawnDynamically(k, 0xc1, &info);
+  if (j >= 0) {
+    Sprite_SetSpawnedCoordinates(j, &info);
+    sprite_graphics[j] = sprite_graphics[k];
+    sprite_delay_main[j] = 32;
+    sprite_ignore_projectile[j] = 32;
+    sprite_C[j] = 32;
+  }
+  return j;
+}
+
+void ChattyAgahnim_Draw(int k, PrepOamCoordsRet *info) {  // 9dd451
+  static const DrawMultipleData kChattyAgahnim_Dmd[16] = {
+    {-8, -8, 0x0b82, 2},
+    { 8, -8, 0x4b82, 2},
+    {-8,  8, 0x0ba2, 2},
+    { 8,  8, 0x4ba2, 2},
+    {-8, -8, 0x0b80, 2},
+    { 8, -8, 0x4b80, 2},
+    {-8,  8, 0x0ba0, 2},
+    { 8,  8, 0x4ba0, 2},
+    {-8, -8, 0x0b80, 2},
+    { 8, -8, 0x4b82, 2},
+    {-8,  8, 0x0ba0, 2},
+    { 8,  8, 0x4ba2, 2},
+    {-8, -8, 0x0b82, 2},
+    { 8, -8, 0x4b80, 2},
+    {-8,  8, 0x0ba2, 2},
+    { 8,  8, 0x4ba0, 2},
+  };
+  if (sprite_delay_aux4[k] & 1)
+    return;
+
+  if (sprite_C[k] == 0) {
+    oam_cur_ptr = 0x900;
+    oam_ext_cur_ptr = 0xa60;
+  }
+  Sprite_DrawMultiple(k, &kChattyAgahnim_Dmd[sprite_graphics[k] * 4], 4, info);
+  SpriteDraw_Shadow_custom(k, info, 18);
+}
+
+void SpriteDraw_CutsceneAgahnimSpell(int k, PrepOamCoordsRet *info) {  // 9dd516
+  static const OamEntSigned kChattyAgahnim_Telewarp_Data[28] = {
+    {-10, -16, 0xce, 0x06},
+    { 18, -16, 0xce, 0x06},
+    { 20, -13, 0x26, 0x06},
+    { 20,  -5, 0x36, 0x06},
+    {-12, -13, 0x26, 0x46},
+    {-12,  -5, 0x36, 0x46},
+    { 18,   0, 0x26, 0x06},
+    { 18,   8, 0x36, 0x06},
+    {-10,   0, 0x26, 0x46},
+    {-10,   8, 0x36, 0x46},
+    { -8,   0, 0x22, 0x06},
+    {  8,   0, 0x22, 0x46},
+    { -8,  16, 0x22, 0x86},
+    {  8,  16, 0x22, 0xc6},
+    {-10, -16, 0xce, 0x04},
+    { 18, -16, 0xce, 0x04},
+    { 20, -13, 0x26, 0x44},
+    { 20,  -5, 0x36, 0x44},
+    {-12, -13, 0x26, 0x04},
+    {-12,  -5, 0x36, 0x04},
+    { 18,   0, 0x26, 0x44},
+    { 18,   8, 0x36, 0x44},
+    {-10,   0, 0x26, 0x04},
+    {-10,   8, 0x36, 0x04},
+    { -8,   0, 0x20, 0x04},
+    {  8,   0, 0x20, 0x44},
+    { -8,  16, 0x20, 0x84},
+    {  8,  16, 0x20, 0xc4},
+  };
+  static const uint8 kChattyAgahnim_Telewarp_Data_Big[14] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2};
+  Oam_AllocateFromRegionA(0x38);
+  const OamEntSigned *data = kChattyAgahnim_Telewarp_Data;
+  if (!(frame_counter & 2))
+    data += 14;
+  const uint8 *bigp = kChattyAgahnim_Telewarp_Data_Big;
+  if (!sprite_subtype2[k])
+    return;
+  OamEnt *oam = GetOamCurPtr();
+  uint8 kn = sprite_subtype2[k] - 1;
+  uint8 end = sprite_subtype[k];
+  uint8 t = end + 1;
+  oam += t;
+  bigp += t;
+  data += t;
+  do {
+    SetOamPlain(oam, info->x + data->x, info->y + data->y - 8, data->charnum, data->flags | 0x31, *bigp);
+  } while (data++, bigp++, oam++, --kn != end);
+}
+
+void Sprite_CutsceneAgahnim_Zelda(int k) {  // 9dd57d
+  static const DrawMultipleData kAltarZelda_Dmd[4] = {
+    {-4, 0, 0x0103, 2},
+    { 4, 0, 0x0104, 2},
+    {-4, 0, 0x0100, 2},
+    { 4, 0, 0x0101, 2},
+  };
+  int j = sprite_delay_main[k];
+  if (j != 0) {
+    SpriteDraw_AltarZeldaWarp(k);
+    if (j == 1)
+      sprite_state[k] = 0;
+    if (j < 12)
+      return;
+  }
+  Oam_AllocateFromRegionA(8);
+  PrepOamCoordsRet info;
+  Sprite_DrawMultiple(k, &kAltarZelda_Dmd[sprite_graphics[k] * 2], 2, &info);
+  AltarZelda_DrawBody(k, &info);
+}
+
+void AltarZelda_DrawBody(int k, PrepOamCoordsRet *info) {  // 9dd5e9
+  static const uint8 kAltarZelda_XOffs[16] = {4, 4, 3, 3, 2, 2, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0};
+  Oam_AllocateFromRegionA(8);
+  int z = sprite_z[k] < 31 ? sprite_z[k] : 31;
+  uint8 xoffs = kAltarZelda_XOffs[z >> 1];
+  int y = Sprite_GetY(k) - BG2VOFS_copy2;
+  OamEnt *oam = GetOamCurPtr();
+  SetOamHelper0(oam + 0, info->x + xoffs, y + 7, 0x6c, 0x24, 2);
+  SetOamHelper0(oam + 1, info->x - xoffs, y + 7, 0x6c, 0x24, 2);
+}
+
+void SpriteDraw_AltarZeldaWarp(int k) {  // 9dd6b1
+  static const DrawMultipleData kAltarZelda_Warp_Dmd[10] = {
+    { 4, 4, 0x0480, 0},
+    { 4, 4, 0x0480, 0},
+    { 4, 4, 0x04b7, 0},
+    { 4, 4, 0x04b7, 0},
+    {-6, 0, 0x0524, 2},
+    { 6, 0, 0x4524, 2},
+    {-8, 0, 0x0524, 2},
+    { 8, 0, 0x4524, 2},
+    { 0, 0, 0x05c6, 2},
+    { 0, 0, 0x05c6, 2},
+  };
+  Oam_AllocateFromRegionA(8);
+  Sprite_DrawMultiple(k, &kAltarZelda_Warp_Dmd[(sprite_delay_main[k] >> 2) * 2], 2, NULL);
+}
+
+void Sprite_InitializedSegmented(int k) {  // 9dd6d1
+  for (int i = 0; i < 128; i++) {
+    moldorm_x_lo[i] = sprite_x_lo[k];
+    moldorm_x_hi[i] = sprite_x_hi[k];
+    moldorm_y_lo[i] = sprite_y_lo[k];
+    moldorm_y_hi[i] = sprite_y_hi[k];
+  }
+}
+
+void GiantMoldorm_Draw(int k) {  // 9dd881
+  PrepOamCoordsRet info;
+  if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
+    return;
+  sprite_oam_flags[k] = 11;
+  SpriteDraw_Moldorm_Eyeballs(k, &info);
+  oam_cur_ptr += 8, oam_ext_cur_ptr += 2;
+
+  int j = sprite_subtype2[k] & 0x7f;
+  moldorm_x_lo[j] = sprite_x_lo[k];
+  moldorm_x_hi[j] = sprite_x_hi[k];
+  moldorm_y_lo[j] = sprite_y_lo[k];
+  moldorm_y_hi[j] = sprite_y_hi[k];
+
+  SpriteDraw_Moldorm_Head(k);
+  if (sprite_B[k] < 4) {
+    GiantMoldorm_DrawSegment_AB(k, 16);
+    if (sprite_B[k] < 3) {
+      GiantMoldorm_DrawSegment_AB(k, 28);
+      if (sprite_B[k] < 2) {
+        SpriteDraw_Moldorm_SegmentC(k);
+        if (sprite_B[k] == 0)
+          Moldorm_HandleTail(k);
+      }
+    }
+  }
+  GiantMoldorm_IncrementalSegmentExplosion(k);
+  Sprite_Get16BitCoords(k);
+}
+
+void GiantMoldorm_IncrementalSegmentExplosion(int k) {  // 9dd8f2
+  if (sprite_state[k] == 9 && sprite_delay_aux4[k] && sprite_delay_aux4[k] < 80 &&
+      !(sprite_delay_aux4[k] & 15 | submodule_index | flag_unk1)) {
+    sprite_B[k]++;
+    Sprite_MakeBossExplosion(k);
+  }
+}
+
+void SpriteDraw_Moldorm_Head(int k) {  // 9dd993
+  static const DrawMultipleData kGiantMoldorm_Head_Dmd[16] = {
+    {-8, -8, 0x0080, 2},
+    { 8, -8, 0x0082, 2},
+    {-8,  8, 0x00a0, 2},
+    { 8,  8, 0x00a2, 2},
+    {-8, -8, 0x4082, 2},
+    { 8, -8, 0x4080, 2},
+    {-8,  8, 0x40a2, 2},
+    { 8,  8, 0x40a0, 2},
+    {-6, -6, 0x0080, 2},
+    { 6, -6, 0x0082, 2},
+    {-6,  6, 0x00a0, 2},
+    { 6,  6, 0x00a2, 2},
+    {-6, -6, 0x4082, 2},
+    { 6, -6, 0x4080, 2},
+    {-6,  6, 0x40a2, 2},
+    { 6,  6, 0x40a0, 2},
+  };
+  int t = (sprite_subtype2[k] >> 1 & 1) + (sprite_delay_aux1[k] & 2);
+  Sprite_DrawMultiple(k, &kGiantMoldorm_Head_Dmd[t * 4], 4, NULL);
+}
+
+void SpriteDraw_Moldorm_SegmentC(int k) {  // 9dda5f
+  sprite_graphics[k] = 0;
+  oam_cur_ptr += 0x10;
+  oam_ext_cur_ptr += 4;
+  GiantMoldorm_DrawSegment_C_OrTail(k, 0x28);
+}
+
+void Moldorm_HandleTail(int k) {  // 9ddaba
+  SpriteDraw_Moldorm_Tail(k);
+  if (!sprite_delay_aux2[k]) {
+    sprite_A[k] = 1;
+    sprite_flags4[k] = 0;
+    sprite_defl_bits[k] = 0;
+    uint16 oldx = Sprite_GetX(k);
+    uint16 oldy = Sprite_GetY(k);
+    Sprite_SetX(k, cur_sprite_x);
+    Sprite_SetY(k, cur_sprite_y);
+    Sprite_CheckDamageFromLink(k);
+    sprite_A[k] = 0;
+    sprite_flags4[k] = 9;
+    sprite_defl_bits[k] = 4;
+    Sprite_SetX(k, oldx);
+    Sprite_SetY(k, oldy);
+  }
+}
+
+void SpriteDraw_Moldorm_Tail(int k) {  // 9ddb17
+  oam_cur_ptr += 4;
+  oam_ext_cur_ptr += 1;
+  sprite_graphics[k]++;
+  sprite_oam_flags[k] = 13;
+  GiantMoldorm_DrawSegment_C_OrTail(k, 0x30);
+}
+
+void SpriteDraw_Moldorm_Eyeballs(int k, PrepOamCoordsRet *info) {  // 9ddb9e
+  static const int16 kGiantMoldorm_Eye_X[16] = {16, 15, 12, 6, 0, -6, -12, -13, -16, -13, -12, -6, 0, 6, 12, 15};
+  static const int16 kGiantMoldorm_Eye_Y[16] = {0, 6, 12, 15, 16, 15, 12, 6, 0, -6, -12, -13, -16, -13, -12, -6};
+  static const uint8 kGiantMoldorm_Eye_Char[16] = {0xaa, 0xaa, 0xa8, 0xa8, 0x8a, 0x8a, 0xa8, 0xa8, 0xaa, 0xaa, 0xa8, 0xa8, 0x8a, 0x8a, 0xa8, 0xa8};
+  static const uint8 kGiantMoldorm_Eye_Flags[16] = {0, 0, 0, 0, 0x80, 0x80, 0x40, 0x40, 0x40, 0x40, 0xc0, 0xc0, 0, 0, 0x80, 0x80};
+  OamEnt *oam = GetOamCurPtr();
+  int r7 = sprite_F[k] ? frame_counter : 0;
+  int r6 = sprite_D[k] - 1;
+  for (int i = 1; i >= 0; i--, oam++, r6 += 2) {
+    uint16 x = info->x + kGiantMoldorm_Eye_X[r6 & 0xf];
+    uint16 y = info->y + kGiantMoldorm_Eye_Y[r6 & 0xf];
+    SetOamHelper0(oam, x, y, kGiantMoldorm_Eye_Char[(r6 + r7) & 0xf], info->flags | kGiantMoldorm_Eye_Flags[(r6 + r7) & 0xf], 2);
+  }
+}
+
+void Sprite_ScheduleBossForDeath(int k) {  // 9ddc16
+  sprite_state[k] = 4;
+  sprite_A[k] = 0;
+  sprite_delay_main[k] = 224;
+}
+
+void Sprite_MakeBossExplosion(int k) {  // 9ddc2a
+  SpriteSfx_QueueSfx2WithPan(k, 0xc);
+  Sprite_MakeBossDeathExplosion_NoSound(k);
+}
+
+void Sprite_MakeBossDeathExplosion_NoSound(int k) {  // 9ddc30
+  SpriteSpawnInfo info;
+  int j = Sprite_SpawnDynamically(k, 0x00, &info);
+  if (j >= 0) {
+    load_chr_halfslot_even_odd = 11;
+    sprite_state[j] = 4;
+    sprite_flags2[j] = 3;
+    sprite_oam_flags[j] = 12;
+    Sprite_SetX(j, cur_sprite_x);
+    Sprite_SetY(j, cur_sprite_y);
+    sprite_delay_main[j] = 31;
+    sprite_A[j] = 31;
+    sprite_floor[j] = 2;
+  }
+}
+
+void Vulture_Draw(int k) {  // 9ddd5e
+  static const DrawMultipleData kVulture_Dmd[8] = {
+    {-8, 0, 0x0086, 2},
+    { 8, 0, 0x4086, 2},
+    {-8, 0, 0x0080, 2},
+    { 8, 0, 0x4080, 2},
+    {-8, 0, 0x0082, 2},
+    { 8, 0, 0x4082, 2},
+    {-8, 0, 0x0084, 2},
+    { 8, 0, 0x4084, 2},
+  };
+  PrepOamCoordsRet info;
+  Sprite_DrawMultiple(k, &kVulture_Dmd[sprite_graphics[k] * 2], 2, &info);
+  SpriteDraw_Shadow(k, &info);
+
+}
+
+void Sprite_Raven(int k) {  // 9ddd85
+  static const uint8 kRaven_AscendTime[2] = {16, 248};
+  int j;
+  bool fleeing = false;
+  sprite_obj_prio[k] |= 0x30;
+  SpriteDraw_SingleLarge(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  if (Sprite_ReturnIfRecoiling(k))
+    return;
+  Sprite_CheckDamageToAndFromLink(k);
+  Sprite_MoveXY(k);
+  switch (sprite_ai_state[k]) {
+  case 0: { // inwait
+    PairU8 r = Sprite_IsRightOfLink(k);
+    sprite_oam_flags[k] = sprite_oam_flags[k] & ~0x40 | r.a * 0x40;
+    int x = link_x_coord - cur_sprite_x;
+    int y = link_y_coord - cur_sprite_y;
+    if ((uint16)(x + 0x50 + (x >= 0)) < 0xa0 && (uint16)(y + 0x58 + (y >= 0)) < 0xa0) {
+      sprite_ai_state[k]++;
+      sprite_delay_main[k] = 24;
+      SpriteSfx_QueueSfx3WithPan(k, 0x1e);
+    }
+    break;
+  }
+  case 1:  // ascend
+    if (!sprite_delay_main[k]) {
+      sprite_ai_state[k]++;
+      int j = sprite_A[k];
+      sprite_delay_main[k] = kRaven_AscendTime[j];
+      Sprite_ApplySpeedTowardsLink(k, 32);
+    }
+    sprite_z[k]++;
+    sprite_graphics[k] = (frame_counter >> 1 & 1) + 1;
+    break;
+  case 2:  // attack
+    if (!sprite_delay_main[k] && !(is_in_dark_world && sprite_A[k]) )
+      sprite_ai_state[k]++;
+fly:
+    if (!((k ^ frame_counter) & 1)) {
+      ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLink(k, fleeing ? 48 : 32);
+      if (fleeing)
+        pt.x = -pt.x, pt.y = -pt.y;
+      if (sprite_x_vel[k] - pt.x)
+        sprite_x_vel[k] += sign8(sprite_x_vel[k] - pt.x) ? 1 : -1;
+      if (sprite_y_vel[k] - pt.y)
+        sprite_y_vel[k] += sign8(sprite_y_vel[k] - pt.y) ? 1 : -1;
+    }
+    sprite_graphics[k] = (frame_counter >> 1 & 1) + 1;
+    j = (sprite_x_vel[k] >> 7) & 1;
+    sprite_oam_flags[k] = sprite_oam_flags[k] & ~0x40 | j * 0x40;
+    break;
+  case 3:  // flee
+    fleeing = true;
+    goto fly;
+  }
+}
+
+void Vitreous_SpawnSmallerEyes(int k) {  // 9ddecb
+  sprite_G[k] = 9;
+  sprite_graphics[k] = 4;
+
+  SpriteSpawnInfo info;
+  int j = Sprite_SpawnDynamicallyEx(k, 0x4, &info, 13);
+
+  static const int8 kVitreous_SpawnSmallerEyes_X[13] = {8, 22, -8, -22, 0, 14, 19, 33, 26, -14, -19, -33, -26};
+  static const int8 kVitreous_SpawnSmallerEyes_Y[13] = {-8, -12, -8, -12, 0, -20, -1, -12, -24, -20, -1, -12, -24};
+  static const int8 kVitreous_SpawnSmallerEyes_Gfx[13] = {1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+
+  for (j = 13; j != 0; j--) {
+    sprite_state[j] = 9;
+    sprite_type[j] = 0xbe;
+    SpritePrep_LoadProperties(j);
+    sprite_floor[j] = 0;
+    Sprite_SetX(j, info.r0_x + kVitreous_SpawnSmallerEyes_X[j - 1]);
+    Sprite_SetY(j, info.r2_y + kVitreous_SpawnSmallerEyes_Y[j - 1] + 32);
+    sprite_A[j] = sprite_x_lo[j];
+    sprite_B[j] = sprite_x_hi[j];
+    sprite_C[j] = sprite_y_lo[j];
+    sprite_D[j] = sprite_y_hi[j];
+    sprite_ignore_projectile[j] = sprite_graphics[j] = kVitreous_SpawnSmallerEyes_Gfx[j - 1];
+    sprite_subtype2[j] = (j - 1) * 8 + GetRandomNumber();
+  }
+}
+
+void Sprite_C0_Catfish(int k) {  // 9ddf49
+  if (sprite_A[k] & 0x80)
+    Sprite_Catfish_SplashOfWater(k);
+  else if (sprite_A[k] == 0)
+    Catfish_BigFish(k);
+  else
+    Sprite_Catfish_QuakeMedallion(k);
+}
+
+void Sprite_Catfish_QuakeMedallion(int k) {  // 9ddf54
+  if (!sprite_z[k]) {
+    SpriteDraw_WaterRipple_WithOamAdjust(k);
+    if (!submodule_index && Sprite_CheckDamageToLink_same_layer(k)) {
+      sprite_state[k] = 0;
+      item_receipt_method = 0;
+      Link_ReceiveItem(sprite_A[k], 0);
+    }
+  }
+  if (sprite_delay_aux3[k])
+    Oam_AllocateFromRegionC(8);
+  SpriteDraw_SingleLarge(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  Sprite_MoveXYZ(k);
+  sprite_z_vel[k] -= 2;
+  if (sign8(sprite_z[k])) {
+    sprite_z[k] = 0;
+    sprite_x_vel[k] = (int8)sprite_x_vel[k] >> 1;
+    sprite_y_vel[k] = (int8)sprite_y_vel[k] >> 1;
+    int j = sprite_ai_state[k];
+    if (j == 4) {
+      sprite_x_vel[k] = 0;
+      sprite_y_vel[k] = 0;
+      sprite_z_vel[k] = 0;
+    } else {
+      sprite_ai_state[k]++;
+      static const uint8 kStandaloneItem_Zvel[4] = {0x20, 0x10, 8, 0};
+      sprite_z_vel[k] = kStandaloneItem_Zvel[j];
+      if (j < 2 && (j = Sprite_SpawnWaterSplash(k)) >= 0)
+        sprite_delay_main[j] = 16;
+    }
+  }
+}
+
+void Catfish_BigFish(int k) {  // 9ddfd1
+  GreatCatfish_Draw(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  switch(sprite_ai_state[k]) {
+  case 0:  // AwaitSpriteThrownInCircle
+    for (int j = 15; j >= 0; j--) {
+      if (j == k || sprite_state[j] != 3)
+        continue;
+      if ((uint16)(cur_sprite_x - Sprite_GetX(j) + 32) < 64 && (uint16)(cur_sprite_y - Sprite_GetY(j) + 32) < 64) {
+        sprite_ai_state[k] = 1;
+        sprite_delay_main[k] = 255;
+        return;
+      }
+    }
+    break;
+  case 1: { // RumbleBeforeEmergence
+    int j = sprite_delay_main[k];
+    if (!sprite_delay_main[k]) {
+      sprite_ai_state[k] = 2;
+      sprite_delay_main[k] = 255;
+      bg1_x_offset = 0;
+      sound_effect_ambient = 5;
+      sprite_z_vel[k] = 48;
+      sprite_x_vel[k] = 0;
+      Catfish_SpawnPlop(k);
+    } else if (sprite_delay_main[k] < 0xc0) {
+      if (sprite_delay_main[k] == 0xbf)
+        sound_effect_ambient = 7;
+      bg1_x_offset = (j & 1) ? -1 : 1;
+      flag_is_link_immobilized = 1;
+    }
+    break;
+  }
+  case 2: { // Emerge
+    static const uint8 kGreatCatfish_Emerge_Gfx[16] = {1, 2, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 0, 0, 0, 0};
+    sprite_subtype2[k]++;
+    Sprite_MoveXYZ(k);
+    sprite_z_vel[k] -= 2;
+    if (sprite_z_vel[k] == (uint8)(-48))
+      Catfish_SpawnPlop(k);
+    if (sign8(sprite_z[k])) {
+      sprite_z[k] = 0;
+      sprite_ai_state[k]++;
+      sprite_delay_main[k] = 255;
+    }
+    sprite_graphics[k] = kGreatCatfish_Emerge_Gfx[sprite_subtype2[k] >> 2];
+    break;
+  }
+  case 3: { // ConversateThenSubmerge
+    int j = sprite_delay_main[k];
+    static const uint8 kGreatCatfish_Conversate_Gfx[20] = { 0, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 6, 6 };
+    if (j == 0) {
+      sprite_state[k] = 0;
+    } else {
+      if (j == 160 || j == 252 || j == 4) {
+        Sprite_SpawnWaterSplash(k);
+      } else if (j == 10) {
+        Catfish_SpawnPlop(k);
+      } else if (j == 96) {
+        flag_is_link_immobilized = 0;
+        dialogue_message_index = link_item_quake_medallion ? 0x12b : 0x12a;
+        Sprite_ShowMessageMinimal();
+        return;
+      } else if (j == 80) {
+        if (link_item_quake_medallion) {
+          if (GetRandomNumber() & 1)
+            Sprite_SpawnBomb(k);
+          else
+            Sprite_SpawnFireball(k);
+        } else {
+          Catfish_RegurgitateMedallion(k);
+        }
+      }
+      if (j < 160)
+        sprite_graphics[k] = kGreatCatfish_Conversate_Gfx[j >> 3];
+    }
+    break;
+  }
+  }
+}
+
+int Sprite_SpawnBomb(int k) {  // 9de144
+  SpriteSpawnInfo info;
+  int j = Sprite_SpawnDynamically(k, 0x4a, &info);
+  if (j >= 0) {
+    Sprite_SetSpawnedCoordinates(j, &info);
+    Sprite_TransmuteToBomb(j);
+    sprite_delay_aux1[j] = 80;
+    sprite_x_vel[j] = 24;
+    sprite_z_vel[j] = 48;
+  }
+  return j;
+}
+
+void Catfish_RegurgitateMedallion(int k) {  // 9de16c
+  SpriteSpawnInfo info;
+  int j = Sprite_SpawnDynamically(k, 0xc0, &info);
+  if (j >= 0) {
+    Sprite_SetSpawnedCoordinates(j, &info);
+    sprite_x_vel[j] = 24;
+    sprite_z_vel[j] = 48;
+    sprite_A[j] = 17;
+    SpriteSfx_QueueSfx2WithPan(j, 0x20);
+    sprite_flags2[j] = 0x83;
+    sprite_flags3[j] = 0x58;
+    sprite_oam_flags[j] = 0x58 & 0xf;
+    DecodeAnimatedSpriteTile_variable(0x1c);
+  }
+}
+
+void Sprite_Zora_RegurgitateFlippers(int k) {  // 9de1aa
+  SpriteSpawnInfo info;
+  int j = Sprite_SpawnDynamically(k, 0xc0, &info);
+  if (j < 0)
+    return;
+  Sprite_SetSpawnedCoordinates(j, &info);
+  sprite_z_vel[j] = 32;
+  sprite_y_vel[j] = 16;
+  sprite_A[j] = 30;
+  SpriteSfx_QueueSfx2WithPan(j, 0x20);
+  sprite_flags2[j] = 0x83;
+  sprite_flags3[j] = 0x54;
+  sprite_oam_flags[j] = 0x54 & 15;
+  sprite_delay_aux3[j] = 0x30;
+  DecodeAnimatedSpriteTile_variable(0x11);
+}
+
+void Catfish_SpawnPlop(int k) {  // 9de1ed
+  SpriteSpawnInfo info;
+  int j = Sprite_SpawnDynamically(k, 0xec, &info);
+  if (j >= 0) {
+    Sprite_SetSpawnedCoordinates(j, &info);
+    sprite_state[j] = 3;
+    sprite_delay_main[j] = 15;
+    sprite_ai_state[j] = 0;
+    sprite_flags2[j] = 3;
+    SpriteSfx_QueueSfx2WithPan(k, 0x28);
+  }
+}
+
+int Sprite_SpawnWaterSplash(int k) {  // 9de21c
+  SpriteSpawnInfo info;
+  int j = Sprite_SpawnDynamically(k, 0xc0, &info);
+  if (j >= 0) {
+    Sprite_SetSpawnedCoordinates(j, &info);
+    sprite_A[j] = 0x80;
+    sprite_flags2[j] = 2;
+    sprite_ignore_projectile[j] = 2;
+    sprite_oam_flags[j] = 4;
+    sprite_delay_main[j] = 31;
+  }
+  return j;
+}
+
+void GreatCatfish_Draw(int k) {  // 9de320
+  static const DrawMultipleData kGreatCatfish_Dmd[28] = {
+    {-4,  4, 0x008c, 2},
+    { 4,  4, 0x008d, 2},
+    {-4,  4, 0x008c, 2},
+    { 4,  4, 0x008d, 2},
+    {-4, -4, 0x008c, 2},
+    { 4, -4, 0x008d, 2},
+    {-4,  4, 0x009c, 2},
+    { 4,  4, 0x009d, 2},
+    {-4, -4, 0x408d, 2},
+    { 4, -4, 0x408c, 2},
+    {-4,  4, 0x409d, 2},
+    { 4,  4, 0x409c, 2},
+    {-4, -4, 0xc09d, 2},
+    { 4, -4, 0xc09c, 2},
+    {-4,  4, 0xc08d, 2},
+    { 4,  4, 0xc08c, 2},
+    {-4,  4, 0xc09d, 2},
+    { 4,  4, 0xc09c, 2},
+    {-4,  4, 0xc09d, 2},
+    { 4,  4, 0xc09c, 2},
+    { 0,  8, 0x00bd, 0},
+    { 8,  8, 0x40bd, 0},
+    { 8,  8, 0x40bd, 0},
+    { 8,  8, 0x40bd, 0},
+    {-8,  0, 0x0086, 2},
+    { 8,  0, 0x4086, 2},
+    { 8,  0, 0x4086, 2},
+    { 8,  0, 0x4086, 2},
+  };
+  if (sprite_graphics[k])
+    Sprite_DrawMultiple(k, &kGreatCatfish_Dmd[(sprite_graphics[k] - 1) * 4], 4, NULL);
+}
+
+void Sprite_Catfish_SplashOfWater(int k) {  // 9de37d
+  static const DrawMultipleData kWaterSplash_Dmd[8] = {
+    {-8, -4, 0x0080, 0},
+    {18, -7, 0x0080, 0},
+    {-5, -2, 0x00bf, 0},
+    {15, -4, 0x40af, 0},
+    { 0, -4, 0x00e7, 2},
+    { 0, -4, 0x00e7, 2},
+    { 0, -4, 0x00c0, 2},
+    { 0, -4, 0x00c0, 2},
+  };
+  if (!sprite_delay_main[k])
+    sprite_state[k] = 0;
+  Sprite_DrawMultiple(k, &kWaterSplash_Dmd[(sprite_delay_main[k] >> 3) * 2], 2, NULL);
+}
+
+void Sprite_BF_Lightning(int k) {  // 9de3ed
+  static const uint8 kSpriteLightning_Gfx[8] = {0, 1, 2, 3, 0, 1, 2, 3};
+  static const uint8 kSpriteLightning_OamFlags[8] = {0, 0, 0, 0, 0x40, 0x40, 0x40, 0x40};
+  static const int8 kSpriteLightning_Xoff[64] = {
+    -15,  0,  0, -15,  0, -15, -15,  0, -15,  0,  0, -15,  0, -15, -15,  0,
+    0, 15, 15,   0, 15,   0,   0, 15,   0, 15, 15,   0, 15,   0,   0, 15,
+    0, 15, 15,   0, 15,   0,   0, 15,   0, 15, 15,   0, 15,   0,   0, 15,
+    -15,  0,  0, -15,  0, -15, -15,  0, -15,  0,  0, -15,  0, -15, -15,  0,
+  };
+  int j = sprite_A[k];
+  sprite_oam_flags[k] = sprite_oam_flags[k] & 0xb1 | kSpriteLightning_OamFlags[j] | frame_counter << 1 & 14;
+  sprite_graphics[k] = kSpriteLightning_Gfx[j] + (BYTE(dungeon_room_index2) == 0x20 ? 4 : 0);
+  SpriteDraw_SingleLarge(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  if (sprite_delay_main[k])
+    return;
+  Lightning_SpawnGarnish(k);
+  sprite_delay_main[k] = 2;
+  Sprite_SetY(k, Sprite_GetY(k) + 16);
+  if ((uint8)(sprite_y_lo[k] - BG2VOFS_copy2) >= 0xd0) {
+    sprite_state[k] = 0;
+    return;
+  }
+  int rr = GetRandomNumber() & 7;
+  Sprite_SetX(k, Sprite_GetX(k) + kSpriteLightning_Xoff[sprite_A[k] << 3 | rr]);
+  sprite_A[k] = rr;
+}
+
+void Lightning_SpawnGarnish(int k) {  // 9de475
+  int j = GarnishAllocOverwriteOld();
+  garnish_type[j] = 9;
+  garnish_active = 9;
+  garnish_sprite[j] = sprite_A[k];
+  garnish_x_lo[j] = sprite_x_lo[k];
+  garnish_x_hi[j] = sprite_x_hi[k];
+  int y = Sprite_GetY(k) + 16;
+  garnish_y_lo[j] = y;
+  garnish_y_hi[j] = y >> 8;
+  garnish_countdown[j] = 32;
+}
+
+void Sprite_BD_Vitreous(int k) {  // 9de4c8
+  if (sprite_delay_aux4[k])
+    sprite_graphics[k] = 3;
+  Vitreous_Draw(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  Vitreous_SetMinionsForth(k);
+  Sprite_CheckDamageToAndFromLink(k);
+  switch(sprite_ai_state[k]) {
+  case 0:  // dormant
+    byte_7E0FF8 = 0;
+    sprite_F[k] = 0;
+    sprite_flags3[k] |= 64;
+    if (!(frame_counter & 1) && !--sprite_A[k]) {
+      sprite_flags3[k] &= ~0x40;
+      sprite_delay_aux4[k] = 16;
+      sprite_ai_state[k] = 1;
+      sprite_delay_main[k] = 128;
+      if (!sprite_G[k]) {
+        sprite_ai_state[k] = 2;
+        sprite_delay_main[k] = 64;
+        sprite_ignore_projectile[k] = 0;
+        sound_effect_1 = 0x35;
+        return;
+      }
+    }
+    sprite_graphics[k] = frame_counter & 0x30 ? 4 : 5;
+    break;
+  case 1:  // spew lighting
+    sprite_F[k] = 0;
+    if (!sprite_delay_main[k]) {
+      static const uint8 kVitreous_AfromG[10] = {0x20, 0x20, 0x20, 0x40, 0x60, 0x80, 0xa0, 0xc0, 0xe0, 0};
+      sprite_delay_aux4[k] = 16;
+      sprite_ai_state[k] = 0;
+      sprite_A[k] = kVitreous_AfromG[sprite_G[k]];
+    } else {
+      Vitreous_Animate(k, sprite_delay_main[k]);
+    }
+    break;
+  case 2:  // pursue player
+    Vitreous_Animate(k, 0x8B);
+    if (Sprite_ReturnIfRecoiling(k))
+      return;
+    if (sprite_delay_main[k]) {
+      static const int8 kVitreous_Xvel[2] = {8, -8};
+      sprite_x_vel[k] = kVitreous_Xvel[(sprite_delay_main[k] & 2) >> 1];
+      Sprite_MoveX(k);
+    } else {
+      Sprite_MoveXYZ(k);
+      Sprite_CheckTileCollision(k);
+      sprite_z_vel[k] -= 2;
+      if (sign8(sprite_z[k])) {
+        sprite_z[k] = 0;
+        sprite_z_vel[k] = 32;
+        Sprite_ApplySpeedTowardsLink(k, 16);
+        SpriteSfx_QueueSfx2WithPan(k, 0x21);
+      }
+    }
+    break;
+  }
+}
+
+void Vitreous_Animate(int k, uint8 a) {  // 9de563
+  static const int8 kVitreous_Animate_Gfx[2] = {2, 1};
+  if (a == 0x40 || a == 0x41 || a == 0x42)
+    Sprite_SpawnLightning(k);
+  sprite_graphics[k] = 0;
+  PairU8 pair = Sprite_IsRightOfLink(k);
+  if ((uint8)(pair.b + 16) >= 32)
+    sprite_graphics[k] = kVitreous_Animate_Gfx[pair.a];
+}
+
+void Vitreous_SetMinionsForth(int k) {  // 9de5da
+  static const uint8 kVitreous_WhichToActivate[16] = {5, 6, 7, 8, 9, 10, 11, 12, 13, 5, 6, 7, 8, 9, 10, 11};
+  if (!(++sprite_subtype2[k] & 63)) {
+    int j = kVitreous_WhichToActivate[GetRandomNumber() & 15];
+    if (sprite_ai_state[j] == 0) {
+      sprite_ai_state[j] = 1;
+      sound_effect_1 = 0x15;
+    } else {
+      sprite_subtype2[k]--;
+    }
+  }
+}
+
+void Sprite_SpawnLightning(int k) {  // 9de612
+  static const int8 kAgahnim_Lighting_X[8] = {-8, 8, 8, -8, 8, -8, -8, 8};
+
+  SpriteSpawnInfo info;
+  int j = Sprite_SpawnDynamically(k, 0xBF, &info), i;
+  if (j >= 0) {
+    sound_effect_2 = 0x26;
+    Sprite_SetSpawnedCoordinates(j, &info);
+    sprite_A[j] = i = GetRandomNumber() & 7;
+    int t = info.r0_x + (uint16)kAgahnim_Lighting_X[i];
+    Sprite_SetX(j, info.r0_x + kAgahnim_Lighting_X[i]);
+    sprite_y_lo[j] = info.r2_y + 12 + (t >> 16);
+    sprite_delay_main[j] = 2;
+    intro_times_pal_flash = 32;
+  }
+}
+
+void Vitreous_Draw(int k) {  // 9de716
+  static const DrawMultipleData kVitreous_Dmd[24] = {
+    {-8, -8, 0x01c0, 2},
+    { 8, -8, 0x41c0, 2},
+    {-8,  8, 0x01e0, 2},
+    { 8,  8, 0x41e0, 2},
+    {-8, -8, 0x01c8, 2},
+    { 8, -8, 0x01ca, 2},
+    {-8,  8, 0x01e8, 2},
+    { 8,  8, 0x01ea, 2},
+    {-8, -8, 0x41ca, 2},
+    { 8, -8, 0x41c8, 2},
+    {-8,  8, 0x41ea, 2},
+    { 8,  8, 0x41e8, 2},
+    {-8, -8, 0x01c2, 2},
+    { 8, -8, 0x41c2, 2},
+    {-8,  8, 0x01e2, 2},
+    { 8,  8, 0x41e2, 2},
+    {-8, -8, 0x01c4, 2},
+    { 8, -8, 0x41c4, 2},
+    {-8,  8, 0x01e4, 2},
+    { 8,  8, 0x41e4, 2},
+    {-7, -7, 0x01c4, 2},
+    { 7, -7, 0x41c4, 2},
+    {-7,  7, 0x01e4, 2},
+    { 7,  7, 0x41e4, 2},
+  };
+  if (sprite_ai_state[k] == 2 && sprite_state[k] == 9)
+    oam_cur_ptr = 0x800, oam_ext_cur_ptr = 0xa20;
+  Sprite_DrawMultiple(k, &kVitreous_Dmd[sprite_graphics[k] * 4], 4, NULL);
+  if (sprite_ai_state[k] == 2) {
+    sprite_obj_prio[k] &= ~0xe;
+    Sprite_DrawLargeShadow2(k);
+  }
+}
+
+void Sprite_BE_VitreousEye(int k) {  // 9de773
+  static const int8 kSprite_Vitreolus_Dx[4] = {1, 0, -1, 0};
+  static const int8 kSprite_Vitreolus_Dy[4] = {0, 1, 0, -1};
+  int j = sprite_subtype2[k] >> 4 & 3;
+  cur_sprite_x += kSprite_Vitreolus_Dx[j];
+  cur_sprite_y += kSprite_Vitreolus_Dy[j];
+  SpriteDraw_SingleLarge(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  sprite_subtype2[k]++;
+  if (sprite_graphics[k])
+    return;
+  Sprite_CheckDamageFromLink(k);
+  Sprite_CheckDamageToLink(k);
+  if (sprite_F[k] == 14)
+    sprite_F[k] = 5;
+  switch (sprite_ai_state[k]) {
+  case 0:  // target player
+    sprite_G[k] = link_x_coord;
+    sprite_head_dir[k] = link_x_coord >> 8;
+    sprite_anim_clock[k] = link_y_coord;
+    sprite_subtype[k] = link_y_coord >> 8;
+    break;
+  case 1:  // pursue player
+    if (Sprite_ReturnIfRecoiling(k))
+      return;
+    if (!((k ^ frame_counter) & 1)) {
+      uint16 x = sprite_head_dir[k] << 8 | sprite_G[k];
+      uint16 y = sprite_subtype[k] << 8 | sprite_anim_clock[k];
+      ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLocation(k, x, y, 16);
+      sprite_x_vel[k] = pt.x;
+      sprite_y_vel[k] = pt.y;
+    }
+    Sprite_MoveXY(k);
+    if ((uint8)(sprite_G[k] - sprite_x_lo[k] + 4) < 8 && (uint8)(sprite_anim_clock[k] - sprite_y_lo[k] + 4) < 8)
+      sprite_ai_state[k] = 2;
+    break;
+  case 2:  // return
+    if (Sprite_ReturnIfRecoiling(k))
+      return;
+    if (!((k ^ frame_counter) & 1)) {
+      uint16 x = sprite_A[k] | sprite_B[k] << 8;
+      uint16 y = sprite_C[k] | sprite_D[k] << 8;
+      ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLocation(k, x, y, 16);
+      sprite_x_vel[k] = pt.x;
+      sprite_y_vel[k] = pt.y;
+    }
+    Sprite_MoveXY(k);
+    if ((uint8)(sprite_A[k] - sprite_x_lo[k] + 4) < 8 && (uint8)(sprite_C[k] - sprite_y_lo[k] + 4) < 8) {
+      sprite_x_lo[k] = sprite_A[k];
+      sprite_x_hi[k] = sprite_B[k];
+      sprite_y_lo[k] = sprite_C[k];
+      sprite_y_hi[k] = sprite_D[k];
+      sprite_ai_state[k] = 0;
+    }
+    break;
+  }
+}
+
+void HelmasaurFireball_TriSplit(int k) {  // 9deed3
+  static const int8 kHelmasaurFireball_TriSplit_Xvel[3] = {0, 28, -28};
+  static const int8 kHelmasaurFireball_TriSplit_Yvel[3] = {-32, 24, 24};
+  static const uint8 kHelmasaurFireball_TriSplit_Delay[6] = {32, 80, 128, 32, 80, 128};
+
+  SpriteSfx_QueueSfx3WithPan(k, 0x36);
+  sprite_state[k] = 0;
+
+  byte_7E0FB6 = GetRandomNumber();
+  for (int i = 2; i >= 0; i--) {
+    SpriteSpawnInfo info;
+    int j = Sprite_SpawnDynamically(k, 0x70, &info);
+    if (j >= 0) {
+      Sprite_SetSpawnedCoordinates(j, &info);
+      sprite_x_vel[j] = kHelmasaurFireball_TriSplit_Xvel[i];
+      sprite_y_vel[j] = kHelmasaurFireball_TriSplit_Yvel[i];
+      sprite_ai_state[j] = 3;
+      sprite_ignore_projectile[j] = 3;
+      sprite_delay_main[j] = kHelmasaurFireball_TriSplit_Delay[(byte_7E0FB6 & 3) + i];
+      sprite_head_dir[j] = 0;
+      sprite_graphics[j] = 1;
+    }
+  }
+  tmp_counter = -1;
+}
+
+void HelmasaurFireball_QuadSplit(int k) {  // 9def3d
+  static const int8 kHelmasaurFireball_QuadSplit_Xvel[4] = {32, 32, -32, -32};
+  static const int8 kHelmasaurFireball_QuadSplit_Yvel[4] = {-32, 32, -32, 32};
+  SpriteSfx_QueueSfx3WithPan(k, 0x36);
+  sprite_state[k] = 0;
+  for (int i = 3; i >= 0; i--) {
+    SpriteSpawnInfo info;
+    int j = Sprite_SpawnDynamically(k, 0x70, &info);
+    if (j >= 0) {
+      Sprite_SetSpawnedCoordinates(j, &info);
+      sprite_x_vel[j] = kHelmasaurFireball_QuadSplit_Xvel[i];
+      sprite_y_vel[j] = kHelmasaurFireball_QuadSplit_Yvel[i];
+      sprite_ai_state[j] = 4;
+      sprite_ignore_projectile[j] = 4;
+    }
+  }
+  tmp_counter = -1;
+}
+
+void Sprite_ArmosCrusher(int k) {  // 9def7e
+  sprite_oam_flags[k] = 7;
+  bg1_y_offset = sprite_delay_aux4[k] ? (sprite_delay_aux4[k] & 1 ? -1 : 1) : 0;
+  switch (sprite_G[k]) {
+  case 0:  // retarget
+    Sprite_CheckDamageToAndFromLink(k);
+    if (!(sprite_delay_main[k] | sprite_z[k])) {
+      Sprite_ApplySpeedTowardsLink(k, 32);
+      sprite_z_vel[k] = 32;
+      sprite_G[k]++;
+      sprite_B[k] = link_x_coord;
+      sprite_C[k] = link_x_coord >> 8;
+      sprite_E[k] = link_y_coord;
+      sprite_head_dir[k] = link_y_coord >> 8;
+      SpriteSfx_QueueSfx2WithPan(k, 0x20);
+    }
+    break;
+  case 1:  // approach target
+    sprite_z_vel[k] += 3;
+    if (Sprite_CheckTileCollision(k))
+      goto advance;
+    Sprite_Get16BitCoords(k);
+    uint16 x, y;
+    x = sprite_B[k] | sprite_C[k] << 8;
+    y = sprite_E[k] | sprite_head_dir[k] << 8;
+    if ((uint16)(x - cur_sprite_x + 16) < 32 && (uint16)(y - cur_sprite_y + 16) < 32) {
+advance:
+      sprite_G[k]++;
+      sprite_delay_main[k] = 16;
+      sprite_x_vel[k] = 0;
+      sprite_y_vel[k] = 0;
+    }
+    break;
+  case 2:  // hover
+    sprite_z_vel[k] = 0;
+    if (!sprite_delay_main[k])
+      sprite_G[k]++;
+    break;
+  case 3:  // crush
+    sprite_z_vel[k] = -104;
+    if (!sign8(sprite_z[k])) {
+      sprite_delay_main[k] = 32;
+      sprite_delay_aux4[k] = 32;
+      sprite_G[k] = 0;
+      SpriteSfx_QueueSfx2WithPan(k, 0xc);
+    }
+    break;
+  }
+}
+
+void Sprite_EvilBarrier(int k) {  // 9df06b
+  EvilBarrier_Draw(k);
+  if (sprite_graphics[k] == 4)
+    return;
+
+  sprite_graphics[k] = frame_counter >> 1 & 3;
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  if (Sprite_CheckDamageFromLink(k) && link_sword_type < 2) {
+    sprite_hit_timer[k] = 0;
+    Sprite_AttemptDamageToLinkPlusRecoil(k);
+    if (!countdown_for_blink)
+      link_electrocute_on_touch = 64;
+  }
+
+  if ((uint16)(link_y_coord - cur_sprite_y + 8) < 24 &&
+      (uint16)(link_x_coord - cur_sprite_x + 32) < 64 &&
+      sign8(link_actual_vel_y - 1)) {
+    link_electrocute_on_touch = 64;
+    link_incapacitated_timer = 12;
+    link_auxiliary_state = 1;
+    link_give_damage = 2;
+    link_actual_vel_x = 0;
+    link_actual_vel_y = 48;
+  }
+}
+
+void EvilBarrier_Draw(int k) {  // 9df249
+  static const DrawMultipleData kEvilBarrier_Dmd[45] = {
+    {  0,  0, 0x00e8, 2},
+    {-29,  3, 0x00ca, 0},
+    {-29, 11, 0x00da, 0},
+    { 37,  3, 0x40ca, 0},
+    { 37, 11, 0x40da, 0},
+    {-24, -2, 0x00e6, 2},
+    { -8, -2, 0x00e6, 2},
+    {  8, -2, 0x40e6, 2},
+    { 24, -2, 0x40e6, 2},
+    {  0,  0, 0x00cc, 2},
+    {-29,  3, 0x00cb, 0},
+    {-29, 11, 0x00db, 0},
+    { 37,  3, 0x40cb, 0},
+    { 37, 11, 0x40db, 0},
+    {  0,  0, 0x00cc, 2},
+    {  0,  0, 0x00cc, 2},
+    {  0,  0, 0x00cc, 2},
+    {  0,  0, 0x00cc, 2},
+    {  0,  0, 0x00cc, 2},
+    {-29,  3, 0x00cb, 0},
+    {-29, 11, 0x00db, 0},
+    { 37,  3, 0x40cb, 0},
+    { 37, 11, 0x40db, 0},
+    {-24, -2, 0x80e6, 2},
+    { -8, -2, 0x80e6, 2},
+    {  8, -2, 0xc0e6, 2},
+    { 24, -2, 0xc0e6, 2},
+    {  0,  0, 0x00e8, 2},
+    {-29,  3, 0x00ca, 0},
+    {-29, 11, 0x00da, 0},
+    { 37,  3, 0x40ca, 0},
+    { 37, 11, 0x40da, 0},
+    {  0,  0, 0x00e8, 2},
+    {  0,  0, 0x00e8, 2},
+    {  0,  0, 0x00e8, 2},
+    {  0,  0, 0x00e8, 2},
+    {-29,  3, 0x00cb, 0},
+    {-29, 11, 0x00db, 0},
+    { 37,  3, 0x40cb, 0},
+    { 37, 11, 0x40db, 0},
+    { 37, 11, 0x40db, 0},
+    { 37, 11, 0x40db, 0},
+    { 37, 11, 0x40db, 0},
+    { 37, 11, 0x40db, 0},
+    { 37, 11, 0x40db, 0},
+  };
+  cur_sprite_y += 8;
+  Sprite_DrawMultiple(k, &kEvilBarrier_Dmd[sprite_graphics[k] * 9], 9, NULL);
+  Sprite_Get16BitCoords(k);
+}
+
+void SpriteDraw_Antfairy(int k) {  // 9df395
+  static const DrawMultipleData kDrawFourAroundOne_Dmd[30] = {
+    { 4,  2, 0x02e1, 0},
+    { 4, -3, 0x02e3, 0},
+    {-1,  2, 0x02e3, 0},
+    { 9,  2, 0x02e3, 0},
+    { 4,  7, 0x02e3, 0},
+    { 4,  2, 0x02e1, 0},
+    { 3, -3, 0x02e3, 0},
+    { 9,  1, 0x02e3, 0},
+    {-1,  3, 0x02e3, 0},
+    { 5,  7, 0x02e3, 0},
+    { 4,  2, 0x02e1, 0},
+    { 1, -3, 0x02e3, 0},
+    { 9, -1, 0x02e3, 0},
+    {-1,  5, 0x02e3, 0},
+    { 7,  7, 0x02e3, 0},
+    { 4,  2, 0x02e1, 0},
+    { 0, -2, 0x02e3, 0},
+    { 8, -2, 0x02e3, 0},
+    { 0,  6, 0x02e3, 0},
+    { 8,  6, 0x02e3, 0},
+    { 4,  2, 0x02e1, 0},
+    { 7, -3, 0x02e3, 0},
+    {-1, -1, 0x02e3, 0},
+    { 9,  5, 0x02e3, 0},
+    { 1,  7, 0x02e3, 0},
+    { 4,  2, 0x02e1, 0},
+    { 5, -3, 0x02e3, 0},
+    {-1,  1, 0x02e3, 0},
+    { 9,  3, 0x02e3, 0},
+    { 3,  7, 0x02e3, 0},
+  };
+  if (!(++sprite_subtype2[k] & 1 | submodule_index | flag_unk1)) {
+    if (++sprite_graphics[k] == 6)
+      sprite_graphics[k] = 0;
+  }
+  Sprite_DrawMultiple(k, &kDrawFourAroundOne_Dmd[sprite_graphics[k] * 5], 5, NULL);
+}
+
+void Toppo_Flustered(int k) {  // 9df3d4
+  sprite_flags2[k] = 130;
+  sprite_ignore_projectile[k] = 130;
+  sprite_flags3[k] = 73;
+  if (!sprite_subtype[k]) {
+    if (Sprite_CheckDamageToLink(k)) {
+      dialogue_message_index = 0x174;
+      Sprite_ShowMessageMinimal();
+      sprite_subtype[k] = 1;
+    }
+  } else if (sprite_subtype[k] < 16) {
+    sprite_subtype[k]++;
+  } else if (sprite_subtype[k] == 16) {
+    sprite_flags5[k] = 0;
+    sprite_state[k] = 6;
+    sprite_delay_main[k] = 15;
+    sprite_flags2[k] += 4;
+    SpriteSfx_QueueSfx2WithPan(k, 0x15);
+    SpriteSpawnInfo info;
+    int j = Sprite_SpawnDynamically(k, 0x4d, &info);
+    if (j >= 0) {
+      Sprite_SetSpawnedCoordinates(j, &info);
+      ForcePrizeDrop(j, 6, 6);
+    }
+    sprite_subtype[k]++;
+  }
+  sprite_graphics[k] = ((++sprite_subtype2[k] & 4) >> 2) + 3;
+}
+
+void Goriya_Draw(int k) {  // 9df589
+  static const DrawMultipleData kGoriya_Dmd2[3] = {
+    {10, 4, 0x4077, 0},
+    {-2, 4, 0x0077, 0},
+    { 4, 4, 0x0076, 0},
+  };
+  static const DrawMultipleData kGoriya_Dmd[32] = {
+    {-4, -8, 0x0044, 2},
+    {12, -8, 0x4044, 0},
+    {-4,  8, 0x0064, 0},
+    { 4,  0, 0x4054, 2},
+    {-4, -8, 0x0044, 2},
+    {12, -8, 0x4044, 0},
+    {-4,  8, 0x4074, 0},
+    { 4,  0, 0x4062, 2},
+    {-4, -8, 0x0044, 0},
+    { 4, -8, 0x4044, 2},
+    {-4,  0, 0x0062, 2},
+    {12,  8, 0x4064, 0},
+    {-4, -8, 0x0046, 2},
+    {12, -8, 0x4046, 0},
+    {-4,  8, 0x0066, 0},
+    { 4,  0, 0x4056, 2},
+    {-4, -8, 0x0046, 2},
+    {12, -8, 0x4046, 0},
+    {-4,  8, 0x4075, 0},
+    { 4,  0, 0x406a, 2},
+    {-4, -8, 0x0046, 0},
+    { 4, -8, 0x4046, 2},
+    {-4,  0, 0x006a, 2},
+    {12,  8, 0x0075, 0},
+    {-2, -8, 0x004e, 2},
+    { 0,  0, 0x006c, 2},
+    {-2, -7, 0x004e, 2},
+    { 0,  0, 0x006e, 2},
+    { 2, -8, 0x404e, 2},
+    { 0,  0, 0x406c, 2},
+    { 2, -7, 0x404e, 2},
+    { 0,  0, 0x406e, 2},
+  };
+  static const uint8 kGoriyaDmdOffs[] = { 0, 4, 8, 12, 16, 20, 24, 26, 28, 30, 32 };
+  if (sprite_delay_aux1[k] && sprite_D[k] != 3)
+    Sprite_DrawMultiple(k, &kGoriya_Dmd2[sprite_D[k]], 1, NULL);
+
+  PrepOamCoordsRet info;
+  oam_cur_ptr += 4, oam_ext_cur_ptr++;
+  int g = sprite_graphics[k];
+  Sprite_DrawMultiple(k, &kGoriya_Dmd[kGoriyaDmdOffs[g]], kGoriyaDmdOffs[g + 1] - kGoriyaDmdOffs[g], &info);
+  sprite_flags2[k]--;
+  SpriteDraw_Shadow(k, &info);
+  sprite_flags2[k]++;
+}
+
+void Moldorm_Draw(int k) {  // 9df822
+  static const int8 kMoldorm_Draw_X[16] = {11, 10, 9, 6, 3, 0, -2, -3, -4, -3, -2, 1, 4, 7, 9, 10};
+  static const int8 kMoldorm_Draw_Y[16] = {4, 6, 9, 10, 11, 10, 9, 6, 3, 0, -2, -3, -4, -3, -2, 1};
+  static const uint8 kMoldorm_Draw_Char[3] = {0x5d, 0x62, 0x60};
+  static const int8 kMoldorm_Draw_XY[3] = {4, 0, 0};
+  static const uint8 kMoldorm_Draw_Big[3] = {0, 2, 2};
+  static const uint8 kMoldorm_Draw_GetOffs[3] = {21, 26, 0};
+
+  PrepOamCoordsRet info;
+  if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
+    return;
+  OamEnt *oam = GetOamCurPtr();
+  uint8 base = sprite_D[k] - 1;
+  for (int i = 1; i >= 0; i--, oam++, base += 2) {
+    SetOamHelper0(oam, info.x + kMoldorm_Draw_X[base & 0xf], info.y + kMoldorm_Draw_Y[base & 0xf],
+                  0x4d, info.flags, 0);
+  }
+  oam_cur_ptr += 8;
+  oam_ext_cur_ptr += 2;
+
+  int j = (sprite_subtype2[k] & 0x1f) + k * 32;
+  moldorm_x_lo[j] = sprite_x_lo[k];
+  moldorm_x_hi[j] = sprite_x_hi[k];
+  moldorm_y_lo[j] = sprite_y_lo[k];
+  moldorm_y_hi[j] = sprite_y_hi[k];
+
+  for (int i = 2; i >= 0; i--, oam++) {
+    j = ((sprite_subtype2[k] + kMoldorm_Draw_GetOffs[i]) & 0x1f) + k * 32;
+    uint16 x = (moldorm_x_lo[j] | moldorm_x_hi[j] << 8) - BG2HOFS_copy2 + kMoldorm_Draw_XY[i];
+    uint16 y = (moldorm_y_lo[j] | moldorm_y_hi[j] << 8) - BG2VOFS_copy2 + kMoldorm_Draw_XY[i];
+    SetOamHelper0(oam, x, y, kMoldorm_Draw_Char[i], info.flags, kMoldorm_Draw_Big[i]);
+  }
+}
+
+void TalkingTree_Mouth(int k) {  // 9df956
+  static const int8 kTalkingTree_Gfx2[4] = {0, 2, 3, 1};
+  int j;
+  TalkingTree_Draw(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  sprite_flags4[k] = 0;
+  switch(sprite_ai_state[k]) {
+  case 0:
+    sprite_graphics[k] = 0;
+    if (Sprite_CheckDamageToLink_same_layer(k)) {
+      Link_CancelDash();
+      link_incapacitated_timer = 16;
+      ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLink(k, 48);
+      link_actual_vel_y = pt.y;
+      link_actual_vel_x = pt.x;
+      SpriteSfx_QueueSfx3WithPan(k, 0x32);
+      sprite_ai_state[k]++;
+      sprite_delay_main[k] = 48;
+    }
+    break;
+  case 1:
+    if (!sprite_delay_main[k]) {
+      sprite_ai_state[k]++;
+      sprite_delay_main[k] = 8;
+    }
+    sprite_graphics[k] = sprite_delay_main[k] >> 1 & 3;
+    break;
+  case 2:
+    sprite_graphics[k] = kTalkingTree_Gfx2[sprite_delay_main[k] >> 1]; // zelda bug wtf
+    if (sprite_delay_main[k] == 7)
+      TalkingTree_SpawnBomb(k);
+    if (!sprite_delay_main[k])
+      sprite_ai_state[k]++;
+    break;
+  case 3:
+    sprite_flags4[k] = 7;
+    if (!sprite_A[k]) {
+      static const uint8 kTalkingTree_Msgs2[2] = { 0x82, 0x7d };
+      j = sprite_x_lo[k] >> 4 & 1 ^ 1;
+      sprite_A[k] = j;
+      if (!(Sprite_ShowSolicitedMessage(k, kTalkingTree_Msgs2[j]) & 0x100))
+        sprite_A[k] = 0;
+    } else {
+      static const uint8 kTalkingTree_Msgs[4] = {0x7e, 0x7f, 0x80, 0x81};
+      static const uint8 kTalkingTree_Screens[4] = {0x58, 0x5d, 0x72, 0x6b};
+      j = FindInByteArray(kTalkingTree_Screens, BYTE(overworld_screen_index), 4);
+      Sprite_ShowMessageUnconditional(kTalkingTree_Msgs[j]);
+      sprite_A[k] = 0;
+    }
+    if (!sprite_delay_main[k]) {
+      static const uint8 kTalkingTree_Gfx[8] = { 1, 2, 3, 1, 3, 1, 2, 3 };
+      static const uint8 kTalkingTree_Delay[8] = { 13, 13, 13, 11, 11, 6, 16, 8 };
+      sprite_B[k] = j = sprite_B[k] + 1 & 7;
+      sprite_graphics[k] = kTalkingTree_Gfx[j];
+      sprite_delay_main[k] = kTalkingTree_Delay[j];
+    }
+    break;
+  }
+}
+
+void TalkingTree_SpawnBomb(int k) {  // 9dfa4e
+  SpriteSpawnInfo info;
+  int j = Sprite_SpawnDynamically(k, 0x4a, &info);
+  if (j >= 0) {
+    Sprite_TransmuteToBomb(j);
+    Sprite_SetSpawnedCoordinates(j, &info);
+    sprite_delay_aux1[j] = 64;
+    sprite_y_vel[j] = 24;
+    sprite_z_vel[j] = 18;
+  }
+}
+
+void TalkingTree_Draw(int k) {  // 9dfadb
+  static const DrawMultipleData kTalkingTree_Dmd[12] = {
+    {1, -1, 0x00e8, 0},
+    {1,  7, 0x00f8, 0},
+    {7, -1, 0x40e8, 0},
+    {7,  7, 0x40f8, 0},
+    {0, -1, 0x00e8, 0},
+    {0,  7, 0x00f8, 0},
+    {8, -1, 0x40e8, 0},
+    {8,  7, 0x40f8, 0},
+    {0,  0, 0x00e8, 0},
+    {0,  7, 0x00f8, 0},
+    {8,  0, 0x40e8, 0},
+    {8,  7, 0x40f8, 0},
+  };
+  int g = sprite_graphics[k] - 1;
+  if (g < 0)
+    return;
+  Sprite_DrawMultiplePlayerDeferred(k, &kTalkingTree_Dmd[g * 4], 4, NULL);
+}
+
+void TalkingTree_Eye(int k) {  // 9dfb0a
+  static const int8 kTalkingTree_Type1_X[2] = {9, -9};
+  SpriteDraw_SingleSmall(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  int j = sprite_head_dir[k];
+  Sprite_SetX(k, (sprite_A[k] | sprite_B[k] << 8) + kTalkingTree_Type1_X[j]);
+  Sprite_SetY(k, (sprite_C[k] | sprite_E[k] << 8));
+  ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLink(k, 2);
+  if (!sign8(pt.y)) {
+    sprite_D[k] = pt.x + 2;
+  } else if (sprite_D[k] != 2) {
+    sprite_D[k] += (sprite_D[k] >= 2) ? -1 : 1;
+  }
+  static const int8 kTalkingTree_X1[5] = {-2, -1, 0, 1, 2};
+  static const int8 kTalkingTree_Y1[5] = {-1, 0, 0, 0, -1};
+  j = sprite_D[k];
+  Sprite_SetX(k, (sprite_A[k] | sprite_B[k] << 8) + kTalkingTree_X1[j]);
+  Sprite_SetY(k, (sprite_C[k] | sprite_E[k] << 8) + kTalkingTree_Y1[j]);
+}
+
+void SpritePrep_TalkingTree_SpawnEyeball(int k, int dir) {  // 9dfb8a
+  static const int8 kTalkingTree_SpawnX[2] = {-4, 14};
+  SpriteSpawnInfo info;
+  int j = Sprite_SpawnDynamically(k, 0x25, &info);
+  if (j >= 0) {
+    sprite_head_dir[j] = dir;
+    int x = info.r0_x + kTalkingTree_SpawnX[dir];
+    int y = info.r2_y - 11;
+    Sprite_SetX(j, x);
+    Sprite_SetY(j, y);
+    sprite_A[j] = x;
+    sprite_B[j] = x >> 8;
+    sprite_C[j] = y;
+    sprite_E[j] = y >> 8;
+    sprite_subtype2[j] = 1;
+  }
+}
+
+void RupeePull_SpawnPrize(int k) {  // 9dfbd7
+  static const int8 kSpawnRupees_Xvel[4] = {-18, -12, 12, 18};
+  static const int8 kSpawnRupees_Yvel[4] = {16, 24, 24, 16};
+  static const uint8 kSpawnRupees_Type[3] = {0xd9, 0xda, 0xdb};
+  if (num_sprites_killed) {
+    byte_7E0FB6 = num_sprites_killed < 4 ? 0 :
+                  number_of_times_hurt_by_sprites ? 1 : 2;
+    tmp_counter = 3;
+    do {
+      SpriteSpawnInfo info;
+      int j = Sprite_SpawnDynamically(k, kSpawnRupees_Type[byte_7E0FB6], &info);
+      if (j < 0)
+        break;
+      Sprite_SetSpawnedCoordinates(j, &info);
+      sprite_x_vel[j] = kSpawnRupees_Xvel[tmp_counter];
+      sprite_y_vel[j] = kSpawnRupees_Yvel[tmp_counter];
+      sprite_stunned[j] = 255;
+      sprite_delay_aux4[j] = 32;
+      sprite_delay_aux3[j] = 32;
+      sprite_z_vel[j] = 32;
+    } while (!sign8(--tmp_counter));
+  }
+  num_sprites_killed = 0;
+  number_of_times_hurt_by_sprites = 0;
+}
+
+void Sprite_D5_DigGameGuy(int k) {  // 9dfc38
+  DiggingGameGuy_Draw(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  Sprite_BehaveAsBarrier(k);
+  Sprite_MoveXY(k);
+  sprite_x_vel[k] = 0;
+  switch(sprite_ai_state[k]) {
+  case 0:  // intro
+    if ((uint8)(sprite_y_lo[k] + 7) < BYTE(link_y_coord) && Sprite_DirectionToFaceLink(k, NULL) == 2) {
+      if (follower_indicator == 0) {
+        if (Sprite_ShowSolicitedMessage(k, 0x187) & 0x100)
+          sprite_ai_state[k]++;
+      } else {
+        Sprite_ShowSolicitedMessage(k, 0x18c);
+      }
+    }
+    break;
+  case 1:  // do you want to play
+    if (choice_in_multiselect_box == 0 && link_rupees_goal >= 80) {
+      link_rupees_goal -= 80;
+      Sprite_ShowMessageUnconditional(0x188);
+      sprite_ai_state[k] = 2;
+      sprite_graphics[k] = 1;
+      sprite_delay_main[k] = 80;
+      beamos_x_hi[0] = 0;
+      beamos_x_hi[1] = 0;
+      sprite_delay_aux1[k] = 5;
+      Sprite_InitializeSecondaryItemMinigame(1);
+      music_control = 14;
+    } else {
+      Sprite_ShowMessageUnconditional(0x189);
+      sprite_ai_state[k] = 0;
+    }
+    break;
+  case 2:  // move out of the way
+    if (!sprite_delay_main[k]) {
+      sprite_ai_state[k]++;
+      sprite_graphics[k] = 1;
+    } else if (!sprite_delay_aux1[k]) {
+      sprite_graphics[k] ^= 3;
+      if (sprite_graphics[k] & 1)
+        sprite_x_vel[k] = -16;
+      sprite_delay_aux1[k] = 5;
+    }
+    break;
+  case 3:  // start timer
+    sprite_ai_state[k]++;
+    super_bomb_indicator_unk1 = 0;
+    super_bomb_indicator_unk2 = 30;
+    break;
+  case 4:  // terminate
+    if ((int8)super_bomb_indicator_unk2 > 0 || link_position_mode & 1)
+      return;
+    music_control = 9;
+    sprite_ai_state[k]++;
+    is_archer_or_shovel_game = 0;
+    dialogue_message_index = 0x18a;
+    Sprite_ShowMessageMinimal();
+    super_bomb_indicator_unk2 = 254;
+    break;
+  case 5:  // come back later
+    Sprite_ShowSolicitedMessage(k, 0x18b);
+    break;
+  }
+}
+
+void DiggingGameGuy_Draw(int k) {  // 9dfe4b
+  static const DrawMultipleData kDiggingGameGuy_Dmd[9] = {
+    { 0, -8, 0x0a40, 2},
+    { 4,  9, 0x0c56, 0},
+    { 0,  0, 0x0a42, 2},
+    { 0, -8, 0x0a40, 2},
+    { 0,  0, 0x0a42, 2},
+    { 0,  0, 0x0a42, 2},
+    {-1, -7, 0x0a40, 2},
+    {-1,  0, 0x0a44, 2},
+    {-1,  0, 0x0a44, 2},
+  };
+  PrepOamCoordsRet info;
+  Sprite_DrawMultiplePlayerDeferred(k, &kDiggingGameGuy_Dmd[sprite_graphics[k] * 3], 3, &info);
+  SpriteDraw_Shadow(k, &info);
+}
+
+void OldMountainMan_Draw(int k) {  // 9dff0e
+  static const DrawMultipleData kOldMountainMan_Dmd0[2] = {
+    {0, 0, 0x00ac, 2},
+    {0, 8, 0x00ae, 2},
+  };
+  static const DrawMultipleData kOldMountainMan_Dmd1[16] = {
+    { 0, 0, 0x0120, 2},
+    { 0, 8, 0x0122, 2},
+    { 0, 1, 0x0120, 2},
+    { 0, 9, 0x4122, 2},
+    { 0, 0, 0x0120, 2},
+    { 0, 8, 0x0122, 2},
+    { 0, 1, 0x0120, 2},
+    { 0, 9, 0x4122, 2},
+    {-2, 0, 0x0120, 2},
+    { 0, 8, 0x0122, 2},
+    {-2, 1, 0x0120, 2},
+    { 0, 9, 0x0122, 2},
+    { 2, 0, 0x4120, 2},
+    { 0, 8, 0x4122, 2},
+    { 2, 1, 0x4120, 2},
+    { 0, 9, 0x4122, 2},
+  };
+  static const uint8 kOldMountainMan_Dma[16] = {0x20, 0xc0, 0x20, 0xc0, 0, 0xa0, 0, 0xa0, 0x40, 0x80, 0x40, 0x60, 0x40, 0x80, 0x40, 0x60};
+  if (sprite_subtype2[k] != 2) {
+    int j = sprite_D[k] * 4 + sprite_graphics[k] * 2;
+    BYTE(dma_var6) = kOldMountainMan_Dma[j + 0];
+    BYTE(dma_var7) = kOldMountainMan_Dma[j + 1];
+    Sprite_DrawMultiplePlayerDeferred(k, &kOldMountainMan_Dmd1[j], 2, NULL);
+  } else {
+    Sprite_DrawMultiplePlayerDeferred(k, kOldMountainMan_Dmd0, 2, NULL);
+  }
+
+}
+
+void HelmasaurKing_Initialize(int k) {  // 9e8000
+  overlord_gen1[7] = 0x30;
+  overlord_gen1[5] = 0x80;
+  overlord_gen1[6] = 0;
+  overlord_gen2[0] = 0;
+  overlord_gen2[3] = 0;
+  overlord_gen2[1] = 0;
+  overlord_gen2[2] = 0;
+  HelmasaurKing_Reinitialize(k);
+}
+
+void HelmasaurKing_Reinitialize(int k) {  // 9e8019
+  uint8 t = sprite_subtype2[k];
+  for (int i = 3; i >= 0; i--) {
+    overlord_x_lo[i] = kHelmasaur_Tab0[t + i * 8 & 0x1f];
+  }
+}
+
+void Sprite_92_HelmasaurKing(int k) {  // 9e8039
+  int t, j;
+
+  if (sign8(sprite_C[k])) {
+    if (sprite_delay_main[k] == 1)
+      sprite_state[k] = 0;
+    SpriteDraw_SingleLarge(k);
+    if (Sprite_ReturnIfInactive(k))
+      return;
+    if (!(frame_counter & 7 | sprite_delay_aux1[k]))
+      sprite_oam_flags[k] ^= 0x40;
+    Sprite_MoveXYZ(k);
+    sprite_z_vel[k] -= 2;
+    if (sign8(sprite_z[k])) {
+      sprite_z[k] = 0;
+      sprite_delay_main[k] = 12;
+      sprite_z_vel[k] = 24;
+      sprite_graphics[k] = 6;
+    }
+    return;
+  }
+  if (sprite_C[k] < 3) {
+    sprite_obj_prio[k] &= ~0xE;
+    sprite_flags[k] = 0xA;
+  } else {
+    sprite_flags4[k] = 0x1F;
+    sprite_flags[k] = 2;
+  }
+  HelmasaurKing_Draw(k);
+  if (sprite_state[k] == 6) {
+    t = sprite_delay_main[k];
+    if (!t) {
+      sprite_state[k] = 4;
+      sprite_A[k] = 0;
+      sprite_delay_main[k] = 224;
+      return;
+    }
+    sprite_hit_timer[k] = t | 240;
+    if (t < 128 && (t & 7) == 0 && (j = overlord_gen2[3]) != 0x10) {
+      overlord_gen2[3]++;
+      cur_sprite_x = Sprite_GetX(k) + (int8)overlord_x_lo[5 + j];
+      cur_sprite_y = Sprite_GetY(k) + (int8)overlord_y_lo[5 + j];
+      Sprite_MakeBossExplosion(k);
+    }
+    return;
+  }
+
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  static const uint8 kHelmasaurKing_Tab1[13] = {3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 1, 1, 0};
+  t = kHelmasaurKing_Tab1[sprite_health[k] >> 2];
+  sprite_C[k] = t;
+  if (t == 3) {
+    if (t != sprite_E[k]) {
+      sprite_hit_timer[k] = 0;
+      HelmasaurKing_ExplodeMask(k);
+    }
+  } else {
+    if (t != sprite_E[k])
+      HelmasaurKing_ChipAwayAtMask(k);
+  }
+  sprite_E[k] = sprite_C[k];
+  Sprite_CheckDamageFromLink(k);
+  HelmasaurKing_SwingTail(k);
+  HelmasaurKing_AttemptDamage(k);
+  HelmasaurKing_CheckMaskDamageFromHammer(k);
+  if (sprite_delay_aux1[k] == 0) {
+    if (sprite_delay_aux2[k] != 0) {
+      if (sprite_delay_aux2[k] == 0x40) {
+        HelmasaurKing_SpitFireball(k);
+        if (sprite_C[k] >= 3) {
+anim_clk:
+          if (!sprite_anim_clock[k]) {
+            sprite_anim_clock[k]++;
+            sprite_delay_aux3[k] = 32;
+          }
+        }
+      }
+      return;
+    }
+  } else {
+    if (sprite_delay_aux1[k] == 96)
+      goto anim_clk;
+    return;
+  }
+  static const int8 kHelmasaurKing_Xvel0[8] = {-12, -12, -4, 0, 4, 12, 12, 0};
+  static const int8 kHelmasaurKing_Yvel0[8] = {0, 4, 12, 12, 12, 4, 0, 12};
+  switch (sprite_ai_state[k]) {
+  case 0:
+    if ((sprite_hit_timer[k] || !sprite_delay_main[k]) && !HelmasaurKing_MaybeFireball(k)) {
+      j = GetRandomNumber() & 7;
+      sprite_x_vel[k] = kHelmasaurKing_Xvel0[j];
+      sprite_y_vel[k] = kHelmasaurKing_Yvel0[j];
+      sprite_delay_main[k] = 64;
+      if (sprite_C[k] >= 3) {
+        sprite_x_vel[k] <<= 1;
+        sprite_y_vel[k] <<= 1;
+        sprite_delay_main[k] >>= 1;
+      }
+      sprite_ai_state[k]++;
+    }
+    break;
+  case 1:
+    HelmasaurKing_HandleMovement(k);
+    if (!sprite_delay_main[k]) {
+      sprite_delay_main[k] = 32;
+      sprite_ai_state[k]++;
+    }
+    break;
+  case 2:
+    if ((sprite_hit_timer[k] || !sprite_delay_main[k]) && !HelmasaurKing_MaybeFireball(k)) {
+      sprite_delay_main[k] = 64;
+      if (sprite_E[k] >= 3)
+        sprite_delay_main[k] >>= 1;
+      sprite_x_vel[k] = -sprite_x_vel[k];
+      sprite_y_vel[k] = -sprite_y_vel[k];
+      sprite_ai_state[k]++;
+    }
+    break;
+  case 3:
+    HelmasaurKing_HandleMovement(k);
+    if (!sprite_delay_main[k]) {
+      sprite_ai_state[k] = 0;
+      sprite_delay_main[k] = 64;
+    }
+    break;
+  }
+}
+
+void HelmasaurKing_HandleMovement(int k) {  // 9e81e6
+  int n = 1 + ((frame_counter & 3) == 0) + (sprite_C[k] >= 3);
+  do {
+    if (!(++sprite_subtype2[k] & 15))
+      sound_effect_1 = 0x21;
+  } while (--n);
+  Sprite_MoveXY(k);
+}
+
+bool HelmasaurKing_MaybeFireball(int k) {  // 9e8253
+  if (++sprite_subtype[k] != 4)
+    return false;
+  sprite_subtype[k] = 0;
+  if (GetRandomNumber() & 1) {
+    sprite_delay_aux2[k] = 127;
+    SpriteSfx_QueueSfx3WithPan(k, 0x2a);
+  } else {
+    sprite_delay_aux1[k] = 160;
+  }
+  return true;
+}
+
+void HelmasaurKing_SwingTail(int k) {  // 9e82a0
+  overlord_x_lo[4]++;
+  HelmasaurKing_Reinitialize(k);
+  uint8 mask = sprite_anim_clock[k] ? 0 : 1;
+  if (!(frame_counter & mask)) {
+    int j = sprite_D[k] & 1;
+    overlord_gen2[0] += j ? -1 : 1;
+    if (overlord_gen2[0] == (uint8)kFluteBoyAnimal_Xvel[j])
+      sprite_D[k]++;
+    WORD(overlord_gen1[5]) += (int8)overlord_gen2[0];
+  }
+  if (!sprite_anim_clock[k])
+    return;
+  if (!overlord_gen2[0])
+    SpriteSfx_QueueSfx3WithPan(k, 0x6);
+
+  if (sprite_anim_clock[k] == 2) {
+    int j = sprite_head_dir[k];
+    WORD(overlord_gen2[1]) += j ? -4 : 4;
+    if (overlord_gen2[1] == (uint8)(j ? -124 : 124))
+      sprite_anim_clock[k] = 3;
+    overlord_gen1[7] += 3;
+  } else if (sprite_anim_clock[k] == 3) {
+    int j = sprite_head_dir[k] ^ 1;
+    WORD(overlord_gen2[1]) += j ? -4 : 4;
+    if (overlord_gen2[1] == 0)
+      sprite_anim_clock[k] = 0;
+    overlord_gen1[7] -= 3;
+  } else {
+    if (!(overlord_gen2[0] | sprite_delay_aux3[k])) {
+      sprite_head_dir[k] = overlord_gen1[6] & 1;
+      uint8 dir = Sprite_IsRightOfLink(k).a ^ 1;
+      if (dir == sprite_head_dir[k]) {
+        sprite_anim_clock[k] = 2;
+        sound_effect_2 = Sprite_CalculateSfxPan(k) | 0x26;
+      }
+    }
+  }
+}
+
+void HelmasaurKing_CheckMaskDamageFromHammer(int k) {  // 9e8385
+  if (sprite_C[k] >= 3 || !(link_item_in_hand & 10) || (player_oam_y_offset == 0x80))
+    return;
+  SpriteHitBox hb;
+  Player_SetupActionHitBox(&hb);
+  uint8 bak  = sprite_y_lo[k];
+  sprite_y_lo[k] += 8;
+  Sprite_SetupHitBox(k, &hb);
+  sprite_y_lo[k] = bak;
+  if (CheckIfHitBoxesOverlap(&hb)) {
+    sprite_health[k]--;
+    sound_effect_2 = 0x21;
+    ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLink(k, 0x30);
+    link_actual_vel_y = pt.y;
+    link_actual_vel_x = pt.x;
+    link_incapacitated_timer = 8;
+    if (!repulsespark_timer) {
+      repulsespark_x_lo = pt.y;
+      repulsespark_y_lo = pt.x;
+      repulsespark_timer = 5;
+    }
+    SpriteSfx_QueueSfx2WithPan(k, 0x5);
+  }
+}
+
+void HelmasaurKing_AttemptDamage(int k) {  // 9e83eb
+  if (!(frame_counter & 7) &&
+      (uint16)(link_x_coord - cur_sprite_x + 36) < 72 &&
+      (uint16)(link_y_coord - cur_sprite_y + 40) < 64)
+    Sprite_AttemptDamageToLinkPlusRecoil(k);
+}
+
+void HelmasaurKing_ChipAwayAtMask(int k) {  // 9e847e
+  tmp_counter = sprite_C[k] + 7;
+  HelmasaurKing_SpawnMaskDebris(k);
+  SpriteSfx_QueueSfx2WithPan(k, 0x1f);
+}
+
+void HelmasaurKing_ExplodeMask(int k) {  // 9e848c
+  for (int j = 1; j < 16; j++)
+    sprite_state[j] = 0;
+  tmp_counter = 7;
+  do {
+    HelmasaurKing_SpawnMaskDebris(k);
+  } while (!sign8(--tmp_counter));
+  SpriteSfx_QueueSfx2WithPan(k, 0x1f);
+}
+
+void HelmasaurKing_SpawnMaskDebris(int k) {  // 9e84aa
+  static const int8 kHelmasaurKing_Mask_X[10] = {-16, 0, 16, -16, 0, 16, -8, 8, -16, 16};
+  static const int8 kHelmasaurKing_Mask_Y[10] = {24, 27, 24, 24, 27, 24, 27, 27, 24, 24};
+  static const int8 kHelmasaurKing_Mask_Z[10] = {29, 32, 29, 13, 16, 13, 0, 0, 13, 13};
+  static const int8 kHelmasaurKing_Mask_Xvel[10] = {-16, -4, 14, -12, 4, 18, -2, 2, -12, 18};
+  static const int8 kHelmasaurKing_Mask_Yvel[10] = {-8, -4, -6, 4, 2, 7, 6, 8, 4, 7};
+  static const int8 kHelmasaurKing_Mask_Zvel[10] = {32, 40, 36, 37, 39, 34, 30, 33, 37, 34};
+  static const uint8 kHelmasaurKing_Mask_OamFlags[10] = {0, 0, 0x40, 0, 0, 0x40, 0, 0x40, 0, 0x40};
+  static const uint8 kHelmasaurKing_Mask_Gfx[10] = {0, 1, 0, 2, 3, 2, 4, 4, 5, 5};
+  SpriteSpawnInfo info;
+  int j = Sprite_SpawnDynamically(k, 0x92, &info);
+  if (j >= 0) {
+    int i = tmp_counter;
+    Sprite_SetX(j, info.r0_x + kHelmasaurKing_Mask_X[i]);
+    Sprite_SetY(j, info.r2_y + kHelmasaurKing_Mask_Y[i]);
+    sprite_z[j] = kHelmasaurKing_Mask_Z[i];
+    sprite_x_vel[j] = kHelmasaurKing_Mask_Xvel[i];
+    sprite_y_vel[j] = kHelmasaurKing_Mask_Yvel[i];
+    sprite_z_vel[j] = kHelmasaurKing_Mask_Zvel[i];
+    sprite_oam_flags[j] = kHelmasaurKing_Mask_OamFlags[i] | 13;
+    sprite_graphics[j] = kHelmasaurKing_Mask_Gfx[i];
+    sprite_C[j] = 128;
+    sprite_flags2[j] = 0;
+    sprite_delay_aux1[j] = 12;
+    sprite_ignore_projectile[j] = 12;
+    sprite_subtype[j] = tmp_counter;
+  }
+}
+
+void HelmasaurKing_SpitFireball(int k) {  // 9e8517
+  SpriteSpawnInfo info;
+  int j = Sprite_SpawnDynamically(k, 0x70, &info);
+  if (j >= 0) {
+    Sprite_SetSpawnedCoordinates(j, &info);
+    Sprite_SetY(j, info.r2_y + 28);
+    sprite_delay_main[j] = 32;
+    sprite_ignore_projectile[j] = 32;
+  }
+}
+
+void HelmasaurKing_Draw(int k) {  // 9e853b
+  oam_cur_ptr = 0x89c;
+  oam_ext_cur_ptr = 0xa47;
+  PrepOamCoordsRet info;
+  if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
+    return;
+  KingHelmasaur_OperateTail(k, &info);
+  SpriteDraw_KingHelmasaur_Eyes(k, &info);
+  KingHelmasaurMask(k, &info);
+  SpriteDraw_KingHelmasaur_Body(k, &info);
+  SpriteDraw_KingHelmasaur_Legs(k, &info);
+  SpriteDraw_KingHelmasaur_Mouth(k, &info);
+}
+
+void SpriteDraw_KingHelmasaur_Eyes(int k, PrepOamCoordsRet *info) {  // 9e856b
+  static const int8 kHelmasaurKing_DrawB_X[2] = {-3, 11};
+  static const uint8 kHelmasaurKing_DrawB_Char[8] = {0xce, 0xcf, 0xde, 0xde, 0xde, 0xde, 0xcf, 0xce};
+  static const uint8 kHelmasaurKing_DrawB_Flags[2] = {0x3b, 0x7b};
+  oam_cur_ptr += 0x40, oam_ext_cur_ptr += 0x10;
+  OamEnt *oam = GetOamCurPtr();
+  for (int i = 1; i >= 0; i--, oam++) {
+    int j = overlord_x_lo[4] >> 2 & 7;
+    SetOamPlain(oam, info->x + kHelmasaurKing_DrawB_X[i], info->y + 0x14, kHelmasaurKing_DrawB_Char[j], kHelmasaurKing_DrawB_Flags[i], 0);
+  }
+  if (submodule_index)
+    Sprite_CorrectOamEntries(k, 1, 0);
+}
+
+void KingHelmasaurMask(int k, PrepOamCoordsRet *info) {  // 9e8686
+  static const DrawMultipleData kHelmasaurKing_DrawC_Dmd[24] = {
+    {-16, -5, 0x0dae, 2},
+    {  0, -5, 0x0dc0, 2},
+    { 16, -5, 0x4dae, 2},
+    {-16, 11, 0x0dc2, 2},
+    {  0, 11, 0x0dc4, 2},
+    { 16, 11, 0x4dc2, 2},
+    { -8, 27, 0x0dc6, 2},
+    {  8, 27, 0x4dc6, 2},
+    {-16, -5, 0x0dae, 2},
+    {  0, -5, 0x0dc0, 2},
+    { 16, -5, 0x4dae, 2},
+    {-16, 11, 0x0dc8, 2},
+    {  0, 11, 0x0dc4, 2},
+    { 16, 11, 0x4dc2, 2},
+    { -8, 27, 0x0dc6, 2},
+    {  8, 27, 0x4dc6, 2},
+    {-16, -5, 0x0dae, 2},
+    {  0, -5, 0x0dc0, 2},
+    { 16, -5, 0x4dae, 2},
+    {-16, 11, 0x0dc8, 2},
+    {  0, 11, 0x0dc4, 2},
+    { 16, 11, 0x4dc8, 2},
+    { -8, 27, 0x0dc6, 2},
+    {  8, 27, 0x4dc6, 2},
+  };
+  oam_cur_ptr += 8, oam_ext_cur_ptr += 2;
+  if (sprite_C[k] >= 3)
+    return;
+  Sprite_DrawMultiple(k, &kHelmasaurKing_DrawC_Dmd[sprite_C[k] * 8], 8, info);
+  oam_cur_ptr += 0x20, oam_ext_cur_ptr += 8;
+  if (sprite_delay_aux4[k])
+    return;
+  for (int i = 1; i >= 0; i--) {
+    if (ancilla_type[i] == 7 && (ancilla_x_vel[i] | ancilla_y_vel[i])) {
+      KingHelmasaur_CheckBombDamage(k, i);
+    }
+  }
+}
+
+void KingHelmasaur_CheckBombDamage(int k, int j) {  // 9e86e5
+  SpriteHitBox hb;
+  Sprite_SetupHitBox(k, &hb);
+  int x = (ancilla_x_lo[j] | ancilla_x_hi[j] << 8) - 6;
+  int y = (ancilla_y_lo[j] | ancilla_y_hi[j] << 8) - ancilla_z[j];
+  hb.r0_xlo = x, hb.r8_xhi = x >> 8;
+  hb.r1_ylo = y, hb.r9_yhi = y >> 8;
+  hb.r2 = 2;
+  hb.r3 = 15;
+  if (CheckIfHitBoxesOverlap(&hb)) {
+    ancilla_x_vel[j] = -ancilla_x_vel[j];
+    ancilla_y_vel[j] = (int8)-ancilla_y_vel[j] >> 1;
+    sprite_delay_aux4[k] = 32;
+    repulsespark_timer = 5;
+    repulsespark_x_lo = ancilla_x_lo[j];
+    repulsespark_y_lo = ancilla_y_lo[j] - ancilla_z[j];
+    sound_effect_1 = 5;
+  }
+}
+
+void SpriteDraw_KingHelmasaur_Body(int k, PrepOamCoordsRet *info) {  // 9e87e5
+  static const DrawMultipleData kHelmasaurKing_DrawD_Dmd[19] = {
+    {-24, -32, 0x0b80, 2},
+    { -8, -32, 0x0b82, 2},
+    {  8, -32, 0x4b82, 2},
+    { 24, -32, 0x4b80, 2},
+    {-24, -16, 0x0b84, 2},
+    { -8, -16, 0x0b86, 2},
+    {  8, -16, 0x4b86, 2},
+    { 24, -16, 0x4b84, 2},
+    {-24,   0, 0x0b88, 2},
+    { -8,   0, 0x0b8a, 2},
+    {  8,   0, 0x4b8a, 2},
+    { 24,   0, 0x4b88, 2},
+    {-24,  16, 0x0b8c, 2},
+    { -8,  16, 0x0b8e, 2},
+    {  8,  16, 0x4b8e, 2},
+    { 24,  16, 0x4b8c, 2},
+    { -8,  32, 0x0ba0, 2},
+    {  8,  32, 0x4ba0, 2},
+    {  0, -40, 0x0bac, 2},
+  };
+  Sprite_DrawMultiple(k, kHelmasaurKing_DrawD_Dmd, 19, info);
+}
+
+void SpriteDraw_KingHelmasaur_Legs(int k, PrepOamCoordsRet *info) {  // 9e8805
+  static const int8 kHelmasaurKing_DrawE_X[4] = {-28, -28, 28, 28};
+  static const int8 kHelmasaurKing_DrawE_Y[4] = {-28, 4, -28, 4};
+  static const uint8 kHelmasaurKing_DrawE_Char[4] = {0xa2, 0xa6, 0xa2, 0xa6};
+  static const uint8 kHelmasaurKing_DrawE_Flags[4] = {0xb, 0xb, 0x4b, 0x4b};
+
+  oam_cur_ptr += 19 * 4;
+  oam_ext_cur_ptr += 19;
+  OamEnt *oam = GetOamCurPtr();
+  for (int i = 3; i >= 0; i--, oam += 2) {
+    uint8 x = info->x + kHelmasaurKing_DrawE_X[i];
+    uint8 y = info->y + kHelmasaurKing_DrawE_Y[i] + overlord_x_lo[i];
+    uint8 f = kHelmasaurKing_DrawE_Flags[i] ^ info->flags;
+    SetOamPlain(oam + 0, x, y, kHelmasaurKing_DrawE_Char[i], f, 2);
+    SetOamPlain(oam + 1, x, y + 16, kHelmasaurKing_DrawE_Char[i] + 2, f, 2);
+  }
+  tmp_counter = 0xff;
+  if (submodule_index) {
+    Sprite_CorrectOamEntries(k, 7, 2);
+    Sprite_PrepOamCoordOrDoubleRet(k, info);
+  }
+}
+
+void SpriteDraw_KingHelmasaur_Mouth(int k, PrepOamCoordsRet *info) {  // 9e88bc
+  static const uint8 kHelmasaurKing_DrawF_Y[32] = {
+    1,  2,  3,  4,  5,  6,  7, 8, 9, 10, 10, 10, 10, 10, 10, 10,
+    10, 10, 10, 10, 10, 10, 10, 9, 8,  7,  6,  5,  4,  3,  2,  1,
+  };
+  if (!sprite_delay_aux2[k])
+    return;
+  uint8 yd = kHelmasaurKing_DrawF_Y[sprite_delay_aux2[k] >> 2];
+  Oam_AllocateFromRegionB(4);
+  OamEnt *oam = GetOamCurPtr();
+  SetOamPlain(oam, info->x, info->y + yd + 0x13, 0xaa, info->flags ^ 0xb, 2);
+}
+
+void KingHelmasaur_OperateTail(int k, PrepOamCoordsRet *info) {  // 9e8920
+  static const uint8 kHelmasaurKing_DrawA_Mult[32] = {
+    0xff, 0xf0, 0xe0, 0xd0, 0xc0, 0xb0, 0xa0, 0x90, 0x80, 0x70, 0x60, 0x50, 0x40, 0x30, 0x20, 0x10,
+    0xff, 0xf8, 0xf0, 0xe8, 0xe0, 0xd8, 0xd0, 0xc8, 0xbc, 0xb0, 0xa0, 0x90, 0x70, 0x40, 0x20, 0x10,
+  };
+  static const uint8 kHelmasaurKing_DrawA_MultB[16] = {
+    0xff, 0xf0, 0xe0, 0xd0, 0xc0, 0xb0, 0xa0, 0x90, 0x80, 0x70, 0x60, 0x50, 0x40, 0x30, 0x20, 0x10
+  };
+
+  for (int i = 0; i < 16; i++) {
+    int j = i + (sprite_anim_clock[k] ? 16 : 0);
+    uint16 rs = WORD(overlord_gen1[5]) + WORD(overlord_gen2[1]);
+    uint8 f = (rs >> 8) - 1;
+    uint8 r6 = (uint8)(sign8(f) ? -rs : rs) * kHelmasaurKing_DrawA_Mult[j] >> 8;
+    uint16 angle = (rs & 0xff00) | (sign8(f) ? r6 ^ 0xff : r6);
+    uint8 r15 = overlord_gen1[7] * kHelmasaurKing_DrawA_MultB[i] >> 8;
+    overlord_x_lo[i+5] = HelmasaurSin(angle, r15);
+    overlord_y_lo[i+5] = HelmasaurSin(angle + 0x80, r15) - 40;
+  }
+
+  OamEnt *oam = GetOamCurPtr();
+  bool is_hit = false;
+  for (int i = overlord_gen2[3]; i != 16; i++, oam++) {
+    uint8 x = overlord_x_lo[i + 5] + info->x;
+    uint8 y = overlord_y_lo[i + 5] + info->y;
+    oam->x = x;
+    oam->y = y;
+    oam->charnum = (i == overlord_gen2[3]) ? 0xe4 : 0xac;
+    oam->flags = info->flags ^ 0x1b;
+
+    if (!countdown_for_blink && sprite_anim_clock[k]) {
+      if ((uint8)(link_x_coord - BG2HOFS_copy2 - x + 12) < 24 &&
+          (uint8)(link_y_coord - BG2VOFS_copy2 + 8 - y + 8) < 16) {
+        is_hit = true;
+        link_actual_vel_x = 0;
+        link_actual_vel_y = 56;
+      }
+    }
+  }
+
+  if (is_hit && !flag_block_link_menu)
+    Sprite_AttemptDamageToLinkPlusRecoil(k);
+  Sprite_CorrectOamEntries(k, 16, 2);
+  Sprite_PrepOamCoordOrDoubleRet(k, info);
+  tmp_counter = 16;
+}
+
+void Sprite_MadBatterBolt(int k) {  // 9e8a96
+  static const int8 kMadderBolt_X[8] = {0, 4, 8, 12, 12, 4, 8, 0};
+  static const int8 kMadderBolt_Y[8] = {0, 4, 8, 12, 12, 4, 8, 0};
+
+  if (sprite_subtype2[k] & 16)
+    Oam_AllocateFromRegionB(4);
+  SpriteDraw_SingleSmall(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  if (!sprite_ai_state[k]) {
+    Sprite_MoveXY(k);
+    if (!sprite_delay_main[k])
+      sprite_ai_state[k] = 1;
+  } else {
+    if (++sprite_ai_state[k] == 0)
+      sprite_state[k] = 0;
+    int j = ++sprite_subtype2[k];
+    if (!(j & 7))
+      sound_effect_2 = 48;
+    Sprite_SetX(k, link_x_coord + kMadderBolt_X[j >> 2 & 7]);
+    Sprite_SetY(k, link_y_coord + kMadderBolt_Y[j >> 4 & 7]);
+  }
+}
+
+void Sprite_AA_Pikit(int k) {  // 9e8bbf
+  static const uint8 kPikit_Gfx[24] = {
+    2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+    3, 3, 3, 3, 2, 2, 2, 2,
+  };
+  static const int8 kPikit_XyOffs[72] = {
+     0,  0,  0,  0,  0,  0,  0,  0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,  0,  0,  0,  0,  0,  0,  0,   0,   0,   0,   0,   0,   0,   0,   0,
+    12, 16, 24, 32, 32, 24, 16, 12,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,  0,  0,  0,  0,  0,  0,  0, -12, -16, -24, -32, -32, -24, -16, -12,
+     0,  0,  0,  0,  0,  0,  0,  0,
+  };
+  static const uint8 kPikit_Tab0[8] = {24, 24, 0, 48, 48, 48, 0, 24};
+  static const uint8 kPikit_Tab1[8] = {0, 24, 24, 24, 0, 48, 48, 48};
+  int j;
+  Pikit_Draw(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  if (Sprite_ReturnIfRecoiling(k))
+    return;
+  Sprite_CheckDamageToAndFromLink(k);
+  switch(sprite_ai_state[k]) {
+  case 0:  // set next vel
+    if (!sprite_delay_main[k]) {
+      int j;
+      sprite_ai_state[k]++;
+      if (++sprite_C[k] == 4) {
+        sprite_C[k] = 0;
+        j = Sprite_DirectionToFaceLink(k, NULL);
+      } else {
+        j = GetRandomNumber() & 3;
+      }
+      sprite_x_vel[k] = kFluteBoyAnimal_Xvel[j];
+      sprite_y_vel[k] = kZazak_Yvel[j];
+      sprite_z_vel[k] = (GetRandomNumber() & 7) + 19;
+    }
+    sprite_graphics[k] = ++sprite_subtype2[k] >> 3 & 1;
+    break;
+  case 1:  // finish jump then attack
+    Sprite_MoveXYZ(k);
+    Sprite_CheckTileCollision(k);
+    sprite_z_vel[k]--;
+    sprite_z_vel[k]--;
+    if (sign8(sprite_z[k])) {
+      sprite_z[k] = 0;
+      sprite_z_vel[k] = 0;
+      PointU8 pt;
+      Sprite_DirectionToFaceLink(k, &pt);
+      if ((uint8)(pt.x + 48) < 96 && (uint8)(pt.y + 48) < 96) {
+        sprite_ai_state[k]++;
+        ProjectSpeedRet pp = Sprite_ProjectSpeedTowardsLink(k, 31);
+        sprite_D[k] = Sprite_ConvertVelocityToAngle(pp.x, pp.y) >> 1;
+        sprite_delay_main[k] = 95;
+        return;
+      }
+      sprite_ai_state[k] = 0;
+      sprite_delay_main[k] = 16;
+    }
+    sprite_graphics[k] = ++sprite_subtype2[k] >> 3 & 1;
+    break;
+  case 2: { // attempt item grab
+    j = sprite_delay_main[k];
+    if (!j) {
+      sprite_ai_state[k] = 0;
+      sprite_delay_main[k] = 16;
+      sprite_A[k] = 0;
+      sprite_B[k] = 0;
+      sprite_G[k] = 0;
+      return;
+    }
+    j >>= 2;
+    sprite_graphics[k] = kPikit_Gfx[j];
+    int8 xo = kPikit_XyOffs[j + kPikit_Tab0[sprite_D[k]]];
+    int8 yo = kPikit_XyOffs[j + kPikit_Tab1[sprite_D[k]]];
+    sprite_A[k] = xo;
+    sprite_B[k] = yo;
+    if (!sprite_G[k] &&
+        (uint16)(cur_sprite_x + xo - link_x_coord + 12) < 24 &&
+        (uint16)(cur_sprite_y + yo - link_y_coord + 12) < 32 &&
+        sprite_delay_main[k] < 46) {
+      sound_effect_1 = Link_CalculateSfxPan() | 0x26;
+      j = (GetRandomNumber() & 3) + 1;
+      sprite_E[k] = sprite_G[k] = j;
+      if (j == 1) {
+        if (link_item_bombs)
+          link_item_bombs--;
+        else
+          sprite_G[k] = 0;
+      } else if (j == 2) {
+        if (link_num_arrows)
+          link_num_arrows--;
+        else
+          sprite_G[k] = 0;
+      } else if (j == 3) {
+        if (link_rupees_goal)
+          link_rupees_goal--;
+        else
+          sprite_G[k] = 0;
+      } else {
+        sprite_subtype[k] = link_shield_type;
+        if (link_shield_type != 0 && link_shield_type != 3)
+          link_shield_type = 0;
+        else
+          sprite_G[k] = 0;
+      }
+    }
+    break;
+  }
+  }
+}
+
+void Sprite_A8_GreenZirro(int k) {  // 9e8dd2
+  static const uint8 kBomber_Gfx[4] = {9, 10, 8, 7};
+
+  sprite_obj_prio[k] = 0x30;
+  if (sprite_A[k]) {
+    switch (sprite_ai_state[k]) {
+    case 0: // bomberpellet falling
+      SpriteDraw_SingleSmall(k);
+      if (Sprite_ReturnIfInactive(k))
+        return;
+      Sprite_MoveXY(k);
+      Sprite_MoveZ(k);
+      sprite_z_vel[k] -= 2;
+      if (sign8(sprite_z[k])) {
+        sprite_z[k] = 0;
+        sprite_ai_state[k]++;
+        sprite_delay_main[k] = 19;
+        sprite_flags2[k]++;
+        SpriteSfx_QueueSfx2WithPan(k, 0xc);
+      }
+      break;
+    case 1: // bomberpellet exploding
+      SpriteDraw_ZirroBomb(k);
+      if (Sprite_ReturnIfInactive(k))
+        return;
+      if (!(frame_counter & 3))
+        sprite_delay_main[k]++;
+      Sprite_CheckDamageToLink(k);
+      break;
+    }
+    return;
+  }
+
+  if (sprite_delay_aux1[k])
+    sprite_graphics[k] = kBomber_Gfx[sprite_D[k]];
+  sprite_obj_prio[k] |= 0x30;
+  Bomber_Draw(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  if (Sprite_ReturnIfRecoiling(k))
+    return;
+  if (sprite_delay_aux1[k] == 8)
+    Zirro_DropBomb(k);
+  Sprite_CheckDamageToAndFromLink(k);
+  if (!(frame_counter & 1)) {
+    int j = sprite_G[k] & 1;
+    sprite_z_vel[k] += j ? -1 : 1;
+    if (sprite_z_vel[k] == (uint8)(j ? -8 : 8))
+      sprite_G[k]++;
+  }
+  Sprite_MoveZ(k);
+  PointU8 pt;
+  Sprite_DirectionToFaceLink(k, &pt);
+  if ((uint8)(pt.x + 40) < 80 && (uint8)(pt.y + 40) < 80 && player_oam_y_offset != 0x80 &&
+      (link_is_running || sign8(button_b_frames - 9))) {
+    ProjectSpeedRet pp = Sprite_ProjectSpeedTowardsLink(k, 0x30);
+    sprite_x_vel[k] = -pp.x;
+    sprite_y_vel[k] = -pp.y;
+    sprite_delay_main[k] = 8;
+    sprite_ai_state[k] = 2;
+  }
+  switch(sprite_ai_state[k]) {
+  case 0:
+    if (!sprite_delay_main[k]) {
+      static const int8 kBomber_Xvel[8] = {16, 12, 0, -12, -16, -12, 0, 12};
+      static const int8 kBomber_Yvel[8] = {0, 12, 16, 12, 0, -12, -16, -12};
+      static const uint8 kBomber_Tab0[4] = {0, 4, 2, 6};
+      int j;
+      sprite_ai_state[k]++;
+      sprite_B[k]++;
+      if (sprite_B[k] == 3) {
+        sprite_B[k] = 0;
+        sprite_delay_main[k] = 48;
+        j = kBomber_Tab0[Sprite_DirectionToFaceLink(k, NULL)];
+      } else {
+        j = GetRandomNumber();
+        sprite_delay_main[k] = j & 0x1f | 0x20;
+        j &= 7;
+      }
+      sprite_x_vel[k] = kBomber_Xvel[j];
+      sprite_y_vel[k] = kBomber_Yvel[j];
+    }
+    goto set_dir;
+  case 1:
+    if (!sprite_delay_main[k]) {
+      sprite_ai_state[k] = 0;
+      sprite_delay_main[k] = 10;
+      if (sprite_type[k] == 0xa8)
+        sprite_delay_aux1[k] = 16;
+    } else {
+      Sprite_MoveXY(k);
+set_dir:
+      sprite_D[k] = Sprite_DirectionToFaceLink(k, NULL);
+      sprite_graphics[k] = sprite_D[k] << 1 | ++sprite_subtype2[k] >> 3 & 1;
+    }
+    break;
+  case 2:
+    if (!sprite_delay_main[k])
+      sprite_ai_state[k] = 0;
+    sprite_subtype2[k] += 2;
+    Sprite_MoveXY(k);
+    goto set_dir;
+  }
+}
+
+void Zirro_DropBomb(int k) {  // 9e8f81
+  static const int8 kBomber_SpawnPellet_X[4] = {14, -6, 4, 4};
+  static const int8 kBomber_SpawnPellet_Y[4] = {7, 7, 12, -4};
+  SpriteSpawnInfo info;
+  int j = Sprite_SpawnDynamically(k, 0xa8, &info);
+  if (j >= 0) {
+    SpriteSfx_QueueSfx2WithPan(k, 0x20);
+    sprite_z[j] = info.r4_z;
+    int i = sprite_D[j];
+    Sprite_SetX(j, info.r0_x + kBomber_SpawnPellet_X[i]);
+    Sprite_SetY(j, info.r2_y + kBomber_SpawnPellet_Y[i]);
+    sprite_x_vel[j] = kFluteBoyAnimal_Xvel[i];
+    sprite_y_vel[j] = kZazak_Yvel[i];
+    sprite_A[j] = 1;
+    sprite_ignore_projectile[j] = 1;
+    sprite_flags4[j] = 9;
+    sprite_flags3[j] = 0x33;
+    sprite_oam_flags[j] = 0x33 & 15;
+  }
+}
+
+void Sprite_StalfosBone(int k) {  // 9e8fdf
+  StalfosBone_Draw(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  Sprite_CheckDamageToLink(k);
+  sprite_subtype2[k]++;
+  Sprite_MoveXY(k);
+  if (!sprite_delay_main[k] && Sprite_CheckTileCollision(k)) {
+    sprite_state[k] = 0;
+    Sprite_PlaceWeaponTink(k);
+  }
+}
+
+void StalfosBone_Draw(int k) {  // 9e9040
+  static const DrawMultipleData kStalfosBone_Dmd[8] = {
+    {-4, -2, 0x802f, 0},
+    { 4,  2, 0x402f, 0},
+    {-4,  2, 0x002f, 0},
+    { 4, -2, 0xc02f, 0},
+    { 2, -4, 0x403f, 0},
+    {-2,  4, 0x803f, 0},
+    {-2, -4, 0x003f, 0},
+    { 2,  4, 0xc03f, 0},
+  };
+  Sprite_DrawMultiple(k, &kStalfosBone_Dmd[(sprite_subtype2[k] >> 2 & 3) * 2], 2, NULL);
+}
+
+void Sprite_A7_Stalfos(int k) {  // 9e906c
+  if (sprite_A[k]) {
+    Sprite_StalfosBone(k);
+    return;
+  }
+  if (!sprite_E[k]) {
+    Stalfos_Skellington(k);
+    return;
+  }
+  if (!sprite_delay_main[k]) {
+    sprite_x_vel[k] = 1;
+    sprite_y_vel[k] = 1;
+    if (Sprite_CheckTileCollision(k)) {
+      sprite_state[k] = 0;
+      return;
+    }
+    sprite_E[k] = 0;
+    SpriteSfx_QueueSfx2WithPan(k, 0x15);
+    Sprite_SpawnPoofGarnish(k);
+    sprite_delay_aux2[k] = 8;
+    sprite_delay_main[k] = 64;
+    sprite_y_vel[k] = 0;
+    sprite_x_vel[k] = 0;
+  }
+  PrepOamCoordsRet info;
+  Sprite_PrepOamCoord(k, &info);
+}
+
+void Stalfos_Skellington(int k) {  // 9e90b5
+  static const uint8 kStalfos_AnimState2[4] = {8, 9, 10, 11};
+  static const uint8 kStalfos_CheckDir[4] = {3, 2, 1, 0};
+  if (sprite_state[k] == 9 &&
+      (uint16)(link_x_coord - cur_sprite_x + 40) < 80 &&
+      (uint16)(link_y_coord - cur_sprite_y + 48) < 80 &&
+      player_oam_y_offset != 0x80 &&
+      !(sprite_z[k] | sprite_pause[k]) &&
+      sprite_floor[k] == link_is_on_lower_level) {
+    uint8 dir = Sprite_DirectionToFaceLink(k, NULL);
+    if (!link_is_running) {
+      if (button_b_frames >= 0x90)
+        goto if_1;
+      if (!sign8(button_b_frames - 9))
+        goto endif_1;
+    }
+    if (dir != kStalfos_CheckDir[link_direction_facing >> 1]) {
+if_1:
+      sprite_D[k] = dir;
+      ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLink(k, 32);
+      sprite_x_vel[k] = -pt.x;
+      sprite_y_vel[k] = -pt.y;
+      sprite_z_vel[k] = 32;
+      SpriteSfx_QueueSfx3WithPan(k, 0x13);
+      sprite_z[k]++;
+    }
+  }
+endif_1:
+  if (sprite_z[k] == 0) {
+    Sprite_Zazak_Main(k);
+    return;
+  }
+  sprite_graphics[k] = kStalfos_AnimState2[sprite_D[k]];
+  Stalfos_Draw(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  if (sprite_F[k])
+    sprite_z_vel[k] = 0;
+  if (Sprite_ReturnIfRecoiling(k))
+    return;
+  Sprite_CheckDamageToAndFromLink(k);
+  uint8 t = Sprite_CheckTileCollision(k);
+  if (t & 3)
+    sprite_x_vel[k] = 0;
+  if (t & 12)
+    sprite_y_vel[k] = 0;
+  Sprite_MoveXYZ(k);
+  sprite_z_vel[k] -= 2;
+  if (sign8(sprite_z[k] - 1)) {
+    sprite_z[k] = 0;
+    Sprite_ZeroVelocity_XY(k);
+    SpriteSfx_QueueSfx2WithPan(k, 0x21);
+    if (sprite_subtype[k]) {
+      sprite_delay_aux3[k] = 16;
+      sprite_subtype2[k] = 0;
+    }
+  }
+}
+
+void Sprite_Zazak_Main(int k) {  // 9e919f
+  static const uint8 kStalfos_AnimState1[8] = {6, 4, 0, 2, 7, 5, 1, 3};
+  static const uint8 kStalfos_Delay[4] = {16, 32, 64, 32};
+
+  static const int8 kZazak_Yvel[4] = {0, 0, 16, -16};
+  if (sprite_B[k]) {
+    FirePhlegm_Draw(k);
+    if (Sprite_ReturnIfInactive(k))
+      return;
+    sprite_graphics[k] = frame_counter >> 1 & 1;
+    Sprite_CheckDamageToLink(k);
+    Sprite_MoveXY(k);
+    if (Sprite_CheckTileCollision(k)) {
+      sprite_state[k] = 0;
+      Sprite_PlaceRupulseSpark_2(k);
+    }
+    return;
+  }
+  int t = sprite_delay_aux3[k];
+  if (t != 0) {
+    sprite_ai_state[k] = 0;
+    sprite_delay_main[k] = 32;
+    Sprite_ZeroVelocity_XY(k);
+    sprite_head_dir[k] = Sprite_DirectionToFaceLink(k, NULL);
+  }
+  if (t == 1) {
+    Stalfos_ThrowBone(k);
+    sprite_subtype2[k] = 1;
+  }
+  sprite_graphics[k] = kStalfos_AnimState1[(sprite_subtype2[k] & 1) * 4 + sprite_D[k]];
+  if (sprite_type[k] == 0xa7)
+    Stalfos_Draw(k);
+  else
+    Zazak_Draw(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  if (Sprite_ReturnIfRecoiling(k))
+    return;
+  Sprite_CheckDamageToAndFromLink(k);
+  Sprite_MoveXY(k);
+  Sprite_CheckTileCollision(k);
+  switch (sprite_ai_state[k]) {
+  case 0:  // walk then track head
+    if (!sprite_delay_main[k]) {
+      sprite_delay_main[k] = kStalfos_Delay[GetRandomNumber() & 3];
+      sprite_ai_state[k] = 1;
+      int j = sprite_head_dir[k];
+      sprite_D[k] = j;
+      sprite_x_vel[k] = kFluteBoyAnimal_Xvel[j];
+      sprite_y_vel[k] = kZazak_Yvel[j];
+    }
+    break;
+  case 1:  // halt and change dir
+    if (sprite_wallcoll[k] != 0) {
+      sprite_delay_main[k] = 16;
+    } else {
+      if (sprite_delay_main[k] != 0) {
+        if (sign8(--sprite_G[k])) {
+          sprite_G[k] = 11;
+          sprite_subtype2[k]++;
+        }
+        return;
+      } else if (sprite_type[k] == 0xa6 &&
+                 sprite_D[k] == Sprite_DirectionToFaceLink(k, NULL) &&
+                 sprite_floor[k] == link_is_on_lower_level) {
+        sprite_ai_state[k] = 2;
+        sprite_delay_main[k] = 48;
+        sprite_delay_aux1[k] = 48;
+        sprite_y_vel[k] = sprite_x_vel[k] = 0;
+        return;
+      }
+      sprite_delay_main[k] = 32;
+    }
+    sprite_head_dir[k] = kZazak_Dir2[sprite_D[k] * 2 + (GetRandomNumber() & 1)];
+    sprite_ai_state[k] = 0;
+    if (++sprite_C[k] == 4) {
+      sprite_C[k] = 0;
+      sprite_head_dir[k] = Sprite_DirectionToFaceLink(k, NULL);
+      sprite_delay_main[k] = 24;
+    }
+    sprite_y_vel[k] = sprite_x_vel[k] = 0;
+    break;
+  case 2:  // shoot
+    if (!sprite_delay_main[k])
+      sprite_ai_state[k] = 0;
+    else if (sprite_delay_main[k] == 24)
+      Sprite_SpawnFirePhlegm(k);
+    break;
+  }
+}
+
+int Sprite_SpawnFirePhlegm(int k) {  // 9e92e4
+  static const int8 kSpawnFirePhlegm_X[4] = {16, -8, 4, 4};
+  static const int8 kSpawnFirePhlegm_Y[4] = {-2, -2, 8, -20};
+  static const int8 kSpawnFirePhlegm_Xvel[4] = {48, -48, 0, 0};
+  static const int8 kSpawnFirePhlegm_Yvel[4] = {0, 0, 48, -48};
+  SpriteSpawnInfo info;
+  int j = Sprite_SpawnDynamically(k, 0xa5, &info);
+  if (j >= 0) {
+    SpriteSfx_QueueSfx3WithPan(k, 0x5);
+    Sprite_SetSpawnedCoordinates(j, &info);
+    int i = sprite_D[k];
+    Sprite_SetX(j, info.r0_x + kSpawnFirePhlegm_X[i]);
+    Sprite_SetY(j, info.r2_y + kSpawnFirePhlegm_Y[i]);
+    sprite_x_vel[j] = kSpawnFirePhlegm_Xvel[i];
+    sprite_y_vel[j] = kSpawnFirePhlegm_Yvel[i];
+    sprite_flags3[j] |= 0x40;
+    sprite_defl_bits[j] = 0x40;
+    sprite_flags2[j] = 0x21;
+    sprite_B[j] = 0x21;
+    sprite_oam_flags[j] = 2;
+    sprite_flags4[j] = 0x14;
+    sprite_ignore_projectile[j] = 20;
+    sprite_bump_damage[j] = 37;
+    if (link_shield_type >= 3)
+      sprite_flags5[j] = 0x20;
+  }
+  return j;
+}
+
+void Stalfos_ThrowBone(int k) {  // 9e9379
+  SpriteSpawnInfo info;
+  int j = Sprite_SpawnDynamically(k, 0xa7, &info);
+  if (j >= 0) {
+    sprite_A[j] = 1;
+    Sprite_SetSpawnedCoordinates(j, &info);
+    Sprite_ApplySpeedTowardsLink(j, 32);
+    sprite_flags2[j] = 0x21;
+    sprite_ignore_projectile[j] = 33;
+    sprite_flags3[j] |= 0x40;
+    sprite_defl_bits[j] = 0x48;
+    sprite_delay_main[j] = 16;
+    sprite_flags4[j] = 0x14;
+    sprite_oam_flags[j] = 7;
+    sprite_bump_damage[j] = 32;
+    SpriteSfx_QueueSfx2WithPan(k, 0x2);
+  }
+}
+
+void FirePhlegm_Draw(int k) {  // 9e9443
+  static const DrawMultipleData kFirePhlegm_Dmd[16] = {
+    { 0,  0, 0x00c3, 0},
+    {-8,  0, 0x00c2, 0},
+    { 0,  0, 0x80c3, 0},
+    {-8,  0, 0x80c2, 0},
+    { 0,  0, 0x40c3, 0},
+    { 8,  0, 0x40c2, 0},
+    { 0,  0, 0xc0c3, 0},
+    { 8,  0, 0xc0c2, 0},
+    { 0,  0, 0x00d4, 0},
+    { 0, -8, 0x00d3, 0},
+    { 0,  0, 0x40d4, 0},
+    { 0, -8, 0x40d3, 0},
+    { 0,  0, 0x80d4, 0},
+    { 0,  8, 0x80d3, 0},
+    { 0,  0, 0xc0d4, 0},
+    { 0,  8, 0xc0d3, 0},
+  };
+  Sprite_DrawMultiple(k, &kFirePhlegm_Dmd[sprite_D[k] * 4 + sprite_graphics[k] * 2], 2, NULL);
+}
+
+void Sprite_A3_KholdstareShell(int k) {  // 9e9460
+  if (Sprite_ReturnIfPaused(k))
+    return;
+  PointU8 pt;
+  Sprite_DirectionToFaceLink(k, &pt);
+  if ((uint8)(pt.x + 32) < 64 && (uint8)(pt.y + 32) < 64) {
+    Sprite_NullifyHookshotDrag();
+    Sprite_RepelDash();
+  }
+  Sprite_CheckDamageFromLink(k);
+  if (sprite_ai_state[k] == 0) {
+    if (sprite_state[k] == 6) {
+      sprite_flags3[k] = 0xc0;
+      sprite_ai_state[k] = 1;
+      sprite_state[k] = 9;
+    } else if (sprite_hit_timer[k] != 0) {
+      dung_floor_x_offs = (sprite_hit_timer[k] & 2) ? -1 : 1;
+      dung_hdr_collision_2_mirror = 1;
+    } else {
+      dung_hdr_collision_2_mirror = 0;
+    }
+  } else if (sprite_ai_state[k]++ != 18) {
+    KholdstareShell_PaletteFiltering();
+  } else {
+    sprite_state[k] = 0;
+    sprite_ai_state[2] = 2;
+    sprite_delay_main[2] = 128;
+  }
+}
+
+void GenerateIceball(int k) {  // 9e94dd
+  if (++sprite_subtype2[k] & 127 | sprite_delay_aux1[k])
+    return;
+  SpriteSpawnInfo info;
+  int j = Sprite_SpawnDynamically(k, 0xa4, &info);
+  if (j >= 0) {
+    Sprite_SetX(j, link_x_coord);
+    Sprite_SetY(j, link_y_coord);
+    sprite_z[j] = -32;
+    sprite_C[j] = -32;
+    SpriteSfx_QueueSfx2WithPan(j, 0x20);
+  }
+}
+
+void Sprite_A2_Kholdstare(int k) {  // 9e9518
+  int j;
+
+  Kholdstare_Draw(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  if (sprite_ai_state[k] < 2) {
+    Kholdstare_SpawnPuffCloudGarnish(k);
+    if (!(frame_counter & 7))
+      sound_effect_1 = 2;
+  }
+  if (Sprite_ReturnIfRecoiling(k))
+    return;
+
+  if (sign8(--sprite_subtype2[k])) {
+    sprite_subtype2[k] = 10;
+    sprite_graphics[k] = sprite_graphics[k] + 1 & 3;
+  }
+
+  if (!(frame_counter & 3)) {
+    ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLink(k, 31);
+    sprite_A[k] = Sprite_ConvertVelocityToAngle(pt.x, pt.y);
+  }
+
+  Sprite_MoveXY(k);
+  switch(sprite_ai_state[k]) {
+  case 0:  // Accelerate
+    Sprite_CheckDamageToAndFromLink(k);
+    if (!sprite_delay_main[k]) {
+      sprite_ai_state[k] = 1;
+      sprite_delay_main[k] = (GetRandomNumber() & 63) + 32;
+      return;
+    }
+    if (sprite_x_vel[k] - sprite_z_vel[k])
+      sprite_x_vel[k] += sign8(sprite_x_vel[k] - sprite_z_vel[k]) ? 1 : -1;
+    if (sprite_y_vel[k] - sprite_z_subpos[k])
+      sprite_y_vel[k] += sign8(sprite_y_vel[k] - sprite_z_subpos[k]) ? 1 : -1;
+check_coll:
+    j = Sprite_CheckTileCollision(k);
+    if (j & 3) {
+      sprite_x_vel[k] = -sprite_x_vel[k];
+      sprite_z_vel[k] = -sprite_z_vel[k];
+    }
+    if (j & 12) {
+      sprite_y_vel[k] = -sprite_y_vel[k];
+      sprite_z_subpos[k] = -sprite_z_subpos[k];
+    }
+    break;
+  case 1:  // Decelerate
+    Sprite_CheckDamageToAndFromLink(k);
+    if (!sprite_delay_main[k]) {
+      sprite_ai_state[k] = 0;
+      sprite_delay_main[k] = (GetRandomNumber() & 63) + 96;
+      j = GetRandomNumber();
+      if (!(j & 0x1c)) {
+        ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLink(k, 24);
+        sprite_z_vel[k] = pt.x;
+        sprite_z_subpos[k] = pt.y;
+      } else {
+        static const int8 kKholdstare_Target_Xvel[4] = {16, 16, -16, -16};
+        static const int8 kKholdstare_Target_Yvel[4] = {-16, 16, 16, -16};
+        sprite_z_vel[k] = kKholdstare_Target_Xvel[j & 3];
+        sprite_z_subpos[k] = kKholdstare_Target_Yvel[j & 3];
+      }
+    } else {
+      if (sprite_x_vel[k])
+        sprite_x_vel[k] += sign8(sprite_x_vel[k]) ? 1 : -1;
+      if (sprite_y_vel[k])
+        sprite_y_vel[k] += sign8(sprite_y_vel[k]) ? 1 : -1;
+      goto check_coll;
+    }
+    break;
+  case 2:  // Triplicate
+    if (sprite_delay_main[k] == 1) {
+      sprite_state[k] = 0;
+      sprite_state[k + 1] = 0;
+      sprite_state[k + 2] = 0;
+      for (int i = 2; i >= 0; i--) {
+        static const int8 kKholdstare_Triplicate_Tab0[3] = {32, -32, 0};
+        static const int8 kKholdstare_Triplicate_Tab1[3] = {-32, -32, 48};
+        SpriteSpawnInfo info;
+        j = Sprite_SpawnDynamicallyEx(k, 0xa2, &info, 4);
+        assert(j >= 0);
+        if (j >= 0) {
+          Sprite_SetSpawnedCoordinates(j, &info);
+          sprite_z_vel[j] = kKholdstare_Triplicate_Tab0[i];
+          sprite_z_subpos[j] = kKholdstare_Triplicate_Tab1[i];
+          sprite_delay_main[j] = 32;
+        }
+      }
+      tmp_counter = 0xff;
+    } else {
+      sprite_hit_timer[k] |= 0xe0;
+    }
+    break;
+  }
+}
+
+void Kholdstare_SpawnPuffCloudGarnish(int k) {  // 9e96a5
+  static const int8 kNebuleGarnish_XY[8] = {-8, -6, -4, -2, 0, 2, 4, 6};
+  if ((k ^ frame_counter) & 3)
+    return;
+  int j = GarnishAllocLow();
+  if (j < 0)
+    return;
+  garnish_type[j] = 7;
+  garnish_active = 7;
+  garnish_countdown[j] = 31;
+  Garnish_SetX(j, cur_sprite_x + kNebuleGarnish_XY[GetRandomNumber() & 7]);
+  Garnish_SetY(j, cur_sprite_y + kNebuleGarnish_XY[GetRandomNumber() & 7] + 16);
+  garnish_floor[j] = 0;
+}
+
+void Sprite_A4_FallingIce(int k) {  // 9e9710
+  if (!sprite_C[k]) {
+    if (Sprite_ReturnIfInactive(k))
+      return;
+    if (sprite_state[2] < 9 && sprite_state[3] < 9 && sprite_state[4] < 9)
+      sprite_state[k] = 0;
+    GenerateIceball(k);
+    return;
+  }
+
+  sprite_ignore_projectile[k] = 1;
+  sprite_obj_prio[k] = 0x30;
+  SpriteDraw_SingleLarge(k);
+  if (!sprite_ai_state[k])
+    sprite_flags3[k] ^= 16;
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  if (sprite_delay_main[k]) {
+    if (sprite_delay_main[k] == 1)
+      sprite_state[k] = 0;
+    sprite_graphics[k] = (sprite_delay_main[k] >> 3) + 2;
+    return;
+  }
+
+  Sprite_MoveXY(k);
+  if (!sprite_ai_state[k] || (Sprite_CheckDamageToLink(k), !Sprite_CheckTileCollision(k))) {
+    uint8 old_z = sprite_z[k];
+    Sprite_MoveZ(k);
+    if (!sign8(sprite_z_vel[k] + 64))
+      sprite_z_vel[k] -= 3;
+    if (!(sign8(old_z ^ sprite_z[k]) && sign8(sprite_z[k])))
+      return;
+    sprite_z[k] = 0;
+    if (!sprite_ai_state[k]) {
+      sprite_state[k] = 0;
+      IceBall_Split(k);
+      return;
+    }
+  }
+  sprite_delay_main[k] = 15;
+  sprite_oam_flags[k] = 4;
+  if (!sound_effect_1) {
+    SpriteSfx_QueueSfx2WithPan(k, 0x1e);
+    sprite_graphics[k] = 3;
+  }
+}
+
+void IceBall_Split(int k) {  // 9e97cf
+  static const int8 kIceBall_Quadruplicate_Xvel[8] = {0, 32, 0, -32, 24, 24, -24, -24};
+  static const int8 kIceBall_Quadruplicate_Yvel[8] = {-32, 0, 32, 0, -24, 24, -24, 24};
+  SpriteSfx_QueueSfx2WithPan(k, 0x1f);
+  int b = GetRandomNumber() & 4;
+  for (int i = 3; i >= 0; i--) {
+    SpriteSpawnInfo info;
+    int j = Sprite_SpawnDynamically(k, 0xa4, &info);
+    if (j >= 0) {
+      Sprite_SetSpawnedCoordinates(j, &info);
+      sprite_ai_state[j] = 1;
+      sprite_graphics[j] = 1;
+      sprite_C[j] = 1;
+      sprite_z_vel[j] = 32;
+      sprite_x_vel[j] = kIceBall_Quadruplicate_Xvel[i + b];
+      sprite_y_vel[j] = kIceBall_Quadruplicate_Yvel[i + b];
+      sprite_flags4[j] = 0x1c;
+    }
+  }
+  tmp_counter = 0xff;
+}
+
+void Sprite_A1_Freezor(int k) {  // 9e981d
+  Freezor_Draw(k);
+  if (sprite_state[k] != 9) {
+    sprite_ai_state[k] = 3;
+    sprite_delay_main[k] = 31;
+    sprite_ignore_projectile[k] = 31;
+    sprite_state[k] = 9;
+    sprite_hit_timer[k] = 0;
+  }
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  if (sprite_ai_state[k] != 3) {
+    if (Sprite_ReturnIfRecoiling(k))
+      return;
+  }
+  switch(sprite_ai_state[k]) {
+  case 0:  // stasis
+    sprite_ignore_projectile[k]++;
+    if ((uint8)(Sprite_IsRightOfLink(k).b + 16) < 32) {
+      sprite_ai_state[k] = 1;
+      sprite_delay_main[k] = 32;
+    }
+    break;
+  case 1: { // awakening
+    sprite_ignore_projectile[k] = sprite_delay_main[k];
+    if (!sprite_delay_main[k]) {
+      sprite_ai_state[k] = 2;
+      uint16 x = Sprite_GetX(k) - 5;
+      uint16 y = Sprite_GetY(k);
+      Dungeon_UpdateTileMapWithCommonTile(x, y, 8);
+      sprite_delay_aux1[k] = 96;
+      sprite_D[k] = 2;
+      sprite_delay_main[k] = 80;
+    } else {
+      sprite_x_vel[k] = (sprite_delay_main[k] & 1) ? -16 : 16;
+      Sprite_MoveX(k);
+    }
+    break;
+  }
+  case 2: { // moving
+    static const int8 kFreezor_Xvel[4] = {8, -8, 0, 0};
+    static const int8 kFreezor_Yvel[4] = {0, 0, 18, -18};
+    static const uint8 kFreezor_Moving_Gfx[4] = {1, 2, 1, 3};
+    static const int8 kFreezor_Sparkle_X[8] = {-4, -2, 0, 2, 4, 6, 8, 10};
+    Sprite_CheckDamageToLink(k);
+    if (Sprite_CheckDamageFromLink(k))
+      sprite_hit_timer[k] = 0;
+    if (sprite_delay_aux1[k] && !((k ^ frame_counter) & 7)) {
+      Sprite_GarnishSpawn_Sparkle(k, kFreezor_Sparkle_X[GetRandomNumber() & 7], -4);
+    }
+    if (!sprite_delay_main[k])
+      sprite_D[k] = Sprite_DirectionToFaceLink(k, NULL);
+    int j = sprite_D[k];
+    sprite_x_vel[k] = kFreezor_Xvel[j];
+    sprite_y_vel[k] = kFreezor_Yvel[j];
+    if (!(sprite_wallcoll[k] & 15))
+      Sprite_MoveXY(k);
+    Sprite_CheckTileCollision(k);
+    sprite_graphics[k] = kFreezor_Moving_Gfx[(k ^ frame_counter) >> 2 & 3];
+    break;
+  }
+  case 3: {  // melting
+    static const uint8 kFreezor_Melting_Gfx[4] = { 6, 5, 4, 7 };
+    if (!sprite_delay_main[k]) {
+      Sprite_ManuallySetDeathFlagUW(k);
+      sprite_state[k] = 0;
+    }
+    sprite_graphics[k] = kFreezor_Melting_Gfx[sprite_delay_main[k] >> 3];
+    break;
+  }
+  }
+}
+
+void Sprite_9E_HauntedGroveOstritch(int k) {  // 9e995b
+  static const uint8 kFluteBoyOstrich_Gfx[4] = {0, 1, 0, 2};
+  FluteBoyOstrich_Draw(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  switch (sprite_ai_state[k]) {
+  case 0:  // wait
+    sprite_graphics[k] = (frame_counter & 0x18) ? 3 : 0;
+    if (byte_7E0FDD) {
+      sprite_ai_state[k] = 1;
+      sprite_y_vel[k] = -8;
+      sprite_x_vel[k] = -16;
+    }
+    break;
+  case 1:  // run away
+    Sprite_MoveXYZ(k);
+    sprite_z_vel[k] -= 2;
+    if (sign8(sprite_z[k])) {
+      sprite_z_vel[k] = 32;
+      sprite_z[k] = 0;
+      sprite_subtype2[k] = 0;
+      sprite_A[k] = 0;
+    }
+    if (!(++sprite_subtype2[k] & 7) && sprite_A[k] != 3)
+      sprite_A[k]++;
+    sprite_graphics[k] = kFluteBoyOstrich_Gfx[sprite_A[k]];
+    break;
+  }
+}
+
+void FluteBoyOstrich_Draw(int k) {  // 9e9a4b
+  static const DrawMultipleData kFluteBoyOstrich_Dmd[16] = {
+    {-4, -8, 0x0080, 2},
+    { 4, -8, 0x0081, 2},
+    {-4,  8, 0x00a3, 2},
+    { 4,  8, 0x00a4, 2},
+    {-4, -8, 0x0080, 2},
+    { 4, -8, 0x0081, 2},
+    {-4,  8, 0x00a0, 2},
+    { 4,  8, 0x00a1, 2},
+    {-4, -8, 0x0080, 2},
+    { 4, -8, 0x0081, 2},
+    {-4,  8, 0x0083, 2},
+    { 4,  8, 0x0084, 2},
+    {-4, -7, 0x0080, 2},
+    { 4, -7, 0x0081, 2},
+    {-4,  9, 0x00a3, 2},
+    { 4,  9, 0x00a4, 2},
+  };
+  PrepOamCoordsRet info;
+  Sprite_DrawMultiple(k, &kFluteBoyOstrich_Dmd[sprite_graphics[k] * 4], 4, &info);
+  SpriteDraw_Shadow_custom(k, &info, 18);
+}
+
+void Sprite_9F_HauntedGroveRabbit(int k) {  // 9e9a6d
+  sprite_oam_flags[k] = sprite_oam_flags[k] & ~0x40 | kFluteBoyAnimal_OamFlags[sprite_D[k]];
+  SpriteDraw_SingleLarge(k);
+  switch (sprite_ai_state[k]) {
+  case 0:  // wait
+    sprite_graphics[k] = 3;
+    if (byte_7E0FDD) {
+      sprite_ai_state[k] = 1;
+      sprite_D[k] ^= 1;
+      sprite_x_vel[k] = kFluteBoyAnimal_Xvel[sprite_D[k]];
+      sprite_y_vel[k] = -8;
+    }
+    break;
+  case 1:  // run
+    Sprite_MoveXYZ(k);
+    sprite_z_vel[k]-=3;
+    if (sign8(sprite_z[k])) {
+      sprite_z_vel[k] = 24;
+      sprite_z[k] = 0;
+      sprite_subtype2[k] = 0;
+      sprite_A[k] = 0;
+    }
+    sprite_subtype2[k]++;
+    if (!(sprite_subtype2[k] & 3) && sprite_A[k] != 2)
+      sprite_A[k]++;
+    sprite_graphics[k] = kFluteBoyAnimal_Gfx[sprite_A[k]];
+    break;
+  }
+}
+
+void Sprite_A0_HauntedGroveBird(int k) {  // 9e9aec
+  if (sprite_graphics[k] == 3)
+    HauntedGroveBird_Blink(k);
+  sprite_oam_flags[k] = sprite_oam_flags[k] & ~0x40 | kFluteBoyAnimal_OamFlags[sprite_D[k]];
+  oam_cur_ptr += 4;
+  oam_ext_cur_ptr++;
+  sprite_flags2[k]--;
+  SpriteDraw_SingleLarge(k);
+  sprite_flags2[k]++;
+  Sprite_MoveXYZ(k);
+  switch (sprite_ai_state[k]) {
+  case 0:  // wait
+    sprite_graphics[k] = (frame_counter & 0x18) ? 0 : 3;
+    if (byte_7E0FDD) {
+      sprite_ai_state[k] = 1;
+      sprite_D[k] ^= 1;
+      sprite_x_vel[k] = kFluteBoyAnimal_Xvel[sprite_D[k]];
+      sprite_delay_main[k] = 32;
+      sprite_z_vel[k] = 16;
+      sprite_y_vel[k] = -8;
+    }
+    break;
+  case 1:  // rising
+    if (!sprite_delay_main[k]) {
+      sprite_z_vel[k] += 2;
+      if (!sign8(sprite_z_vel[k] - 0x10))
+        sprite_ai_state[k] = 2;
+    }
+    sprite_graphics[k] = (++sprite_subtype2[k] >> 1 & 1) + 1;
+    break;
+  case 2:  // falling
+    sprite_graphics[k] = 1;
+    sprite_z_vel[k] -= 1;
+    if (sign8(sprite_z_vel[k] + 15))
+      sprite_ai_state[k] = 1;
+    break;
+  }
+}
+
+void HauntedGroveBird_Blink(int k) {  // 9e9b9c
+  static const int8 kFluteBoyBird_X[2] = {8, 0};
+  PrepOamCoordsRet info;
+  if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
+    return;
+  OamEnt *oam = GetOamCurPtr();
+  int j = sprite_D[k];
+  oam->x = info.x + kFluteBoyBird_X[j];
+  oam->y = info.y;
+  oam->charnum = 0xae;
+  oam->flags = info.flags | kFluteBoyAnimal_OamFlags[j];
+  Sprite_CorrectOamEntries(k, 0, 0);
+}
+
+void Sprite_9C_Zoro(int k) {  // 9e9bc8
+  if (sprite_E[k])
+    Zoro(k);
+  else
+    Babasu(k);
+//
+}
+
+void Zoro(int k) {  // 9e9bd0
+  if (!sprite_C[k]) {
+    sprite_C[k]++;
+    if (Sprite_IsBelowLink(k).a != 0) {
+      sprite_state[k] = 0;
+      return;
+    }
+  }
+  SpriteDraw_SingleSmall(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  Sprite_CheckDamageToAndFromLink(k);
+  sprite_graphics[k] = ++sprite_subtype2[k] >> 1 & 1;
+  sprite_x_vel[k] = kFluteBoyAnimal_Xvel[sprite_subtype2[k] >> 2 & 1];
+  Sprite_MoveXY(k);
+  if (!sprite_delay_main[k] && Sprite_CheckTileCollision(k))
+    sprite_state[k] = 0;
+
+  if (sprite_subtype2[k] & 3)
+    return;
+
+  int j = GarnishAlloc();
+  if (j < 0)
+    return;
+  garnish_type[j] = 6;
+  garnish_active = 6;
+  Garnish_SetX(j, Sprite_GetX(k));
+  Garnish_SetY(j, Sprite_GetY(k) + 16);
+  garnish_countdown[j] = 10;
+  garnish_sprite[j] = k;
+  garnish_floor[j] = sprite_floor[k];
+}
+
+void Babasu(int k) {  // 9e9c6b
+  static const uint8 kBabusu_Gfx[6] = {5, 4, 3, 2, 1, 0};
+  static const uint8 kBabusu_DirGfx[4] = {6, 6, 0, 0};
+  static const int8 kBabusu_XyVel[6] = {32, -32, 0, 0, 32, -32};
+
+  Babusu_Draw(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  switch(sprite_ai_state[k]) {
+  case 0:  // reset
+    sprite_ai_state[k]++;
+    sprite_delay_main[k] = 128;
+    sprite_graphics[k] = 255;
+    break;
+  case 1:  // hiding
+    if (!sprite_delay_main[k]) {
+      sprite_ai_state[k]++;
+      sprite_delay_main[k] = 55;
+    }
+    break;
+  case 2: { // terror sprinkles
+    int j = sprite_delay_main[k], i = sprite_D[k];
+    if (j == 0) {
+      sprite_ai_state[k] = 3;
+      sprite_x_vel[k] = kBabusu_XyVel[i];
+      sprite_y_vel[k] = kBabusu_XyVel[i + 2];
+      sprite_delay_main[k] = 32;
+    }
+    if (j >= 32) {
+      sprite_graphics[k] = kBabusu_Gfx[(j - 32) >> 2] + kBabusu_DirGfx[i];
+    } else {
+      sprite_graphics[k] = 0xff;
+    }
+    break;
+  }
+  case 3: { // scurry across
+    static const uint8 kBabusu_Scurry_Gfx[4] = {18, 14, 12, 16};
+    Sprite_CheckDamageToAndFromLink(k);
+    Sprite_MoveXY(k);
+    sprite_graphics[k] = (frame_counter >> 1 & 1) + kBabusu_Scurry_Gfx[sprite_D[k]];
+    if (!sprite_delay_main[k] && Sprite_CheckTileCollision(k)) {
+      sprite_D[k] ^= 1;
+      sprite_ai_state[k] = 0;
+    }
+    break;
+  }
+  }
+}
+
+void Sprite_9B_Wizzrobe(int k) {  // 9e9d1b
+  int j;
+  if (sprite_C[k]) {
+    Sprite_Wizzbeam(k);
+    return;
+  }
+  if (sprite_ai_state[k] == 0 || sprite_ai_state[k] & 1 && sprite_delay_main[k] & 1) {
+    PrepOamCoordsRet info;
+    Sprite_PrepOamCoord(k, &info);
+  } else {
+    Wizzrobe_Draw(k);
+  }
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  if (Sprite_ReturnIfRecoiling(k))
+    return;
+  sprite_ignore_projectile[k] = 1;
+  switch(sprite_ai_state[k]) {
+  case 0:  // cloaked
+    if (!sprite_delay_main[k]) {
+      sprite_y_vel[k] = sprite_x_vel[k] = 1;
+      if (!Sprite_CheckTileCollision(k)) {
+        static const uint8 kWizzrobe_Cloak_Gfx[4] = {4, 2, 0, 6};
+        sprite_ai_state[k] = 1;
+        sprite_delay_main[k] = 63;
+        sprite_D[k] = j = Sprite_DirectionToFaceLink(k, NULL);
+        sprite_graphics[k] = kWizzrobe_Cloak_Gfx[j];
+      } else {
+        sprite_state[k] = 0;
+      }
+    }
+    break;
+  case 1:  // phasing in
+    if (!sprite_delay_main[k]) {
+      sprite_ai_state[k] = 2;
+      sprite_delay_main[k] = 63;
+    }
+    break;
+  case 2: {  // attack
+    static const uint8 kWizzrobe_Attack_Gfx[8] = {0, 1, 1, 1, 1, 1, 1, 0};
+    static const uint8 kWizzrobe_Attack_DirGfx[4] = {4, 2, 0, 6};
+    sprite_ignore_projectile[k] = 0;
+    Sprite_CheckDamageToAndFromLink(k);
+    j = sprite_delay_main[k];
+    if (!j) {
+      sprite_ai_state[k] = 3;
+      sprite_delay_main[k] = 63;
+      return;
+    }
+    if (j == 32)
+      Wizzrobe_FireBeam(k);
+    sprite_graphics[k] = kWizzrobe_Attack_Gfx[j >> 3] + kWizzrobe_Attack_DirGfx[sprite_D[k]];
+    break;
+  }
+  case 3:  // phasing out
+    if (!sprite_delay_main[k]) {
+      if (sprite_B[k])
+        sprite_state[k] = 0;
+      sprite_ai_state[k] = 0;
+      sprite_delay_main[k] = (GetRandomNumber() & 31) + 32;
+    }
+    break;
+  }
+}
+
+void Wizzrobe_FireBeam(int k) {  // 9e9e15
+  static const int8 kWizzrobe_Beam_XYvel[6] = {32, -32, 0, 0, 32, -32};
+  SpriteSpawnInfo info;
+  int j = Sprite_SpawnDynamically(k, 0x9b, &info);
+  if (j >= 0) {
+    SpriteSfx_QueueSfx3WithPan(k, 0x36);
+    sprite_C[j] = 1;
+    sprite_ignore_projectile[j] = 1;
+    Sprite_SetX(j, info.r0_x + 4);
+    Sprite_SetY(j, info.r2_y);
+    int i = sprite_D[k];
+    sprite_x_vel[j] = kWizzrobe_Beam_XYvel[i];
+    sprite_y_vel[j] = kWizzrobe_Beam_XYvel[i + 2];
+    sprite_defl_bits[j] = 0x48;
+    sprite_oam_flags[j] = 2;
+    sprite_flags5[j] = link_shield_type == 3 ? 0x20 : 0;
+    sprite_flags4[j] = 0x14;
+  }
+}
+
+void Sprite_9A_Kyameron(int k) {  // 9e9e7b
+  PrepOamCoordsRet info;
+  if (!sprite_ai_state[k])
+    Sprite_PrepOamCoord(k, &info);
+  else
+    Kyameron_Draw(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  if (Sprite_ReturnIfRecoiling(k))
+    return;
+  sprite_ignore_projectile[k] = 1;
+  switch(sprite_ai_state[k]) {
+  case 0:  // reset
+    if (!sprite_delay_main[k]) {
+      sprite_ai_state[k] = 1;
+      sprite_delay_main[k] = (GetRandomNumber() & 63) + 96;
+      sprite_x_lo[k] = sprite_A[k];
+      sprite_x_hi[k] = sprite_B[k];
+      sprite_y_lo[k] = sprite_C[k];
+      sprite_y_hi[k] = sprite_head_dir[k];
+      sprite_subtype2[k] = 5;
+      sprite_graphics[k] = 8;
+    }
+    break;
+  case 1:  // puddleup
+    if (!sprite_delay_main[k]) {
+      sprite_delay_main[k] = 31;
+      sprite_ai_state[k] = 2;
+    }
+    if (sign8(--sprite_subtype2[k])) {
+      sprite_subtype2[k] = 5;
+      sprite_graphics[k] = (sprite_graphics[k] + 1 & 3) + 8;
+    }
+    break;
+  case 2: {  // coagulate
+    static const int8 kKyameron_Coagulate_Gfx[8] = {4, 7, 14, 13, 12, 6, 6, 5};
+    static const int8 kKyameron_Xvel[4] = {32, -32, 32, -32};
+    static const int8 kKyameron_Yvel[4] = {32, 32, -32, -32};
+    int j = sprite_delay_main[k];
+    if (j == 0) {
+      sprite_ai_state[k] = 3;
+      j = Sprite_IsBelowLink(k).a * 2 + Sprite_IsRightOfLink(k).a;
+      sprite_x_vel[k] = kKyameron_Xvel[j];
+      sprite_y_vel[k] = kKyameron_Yvel[j];
+    } else {
+      if (j == 7)
+        Sprite_SetY(k, Sprite_GetY(k) - 29);
+      sprite_graphics[k] = kKyameron_Coagulate_Gfx[j >> 2];
+    }
+    break;
+  }
+  case 3: {  // moving
+    sprite_ignore_projectile[k] = 0;
+    if (!Sprite_CheckDamageToAndFromLink(k)) {
+      Sprite_MoveXY(k);
+      int j = Sprite_CheckTileCollision(k);
+      if (j & 3) {
+        sprite_x_vel[k] = -sprite_x_vel[k];
+        sprite_anim_clock[k]++;
+      }
+      if (j & 12) {
+        sprite_y_vel[k] = -sprite_y_vel[k];
+        sprite_anim_clock[k]++;
+      }
+      if (sprite_anim_clock[k] < 3)
+        goto skip_sound;
+    }
+    sprite_ai_state[k] = 4;
+    sprite_delay_main[k] = 15;
+    SpriteSfx_QueueSfx2WithPan(k, 0x28);
+    static const uint8 kKyameron_Moving_Gfx[4] = {3, 2, 1, 0};
+skip_sound:
+    sprite_graphics[k] = kKyameron_Moving_Gfx[++sprite_subtype2[k] >> 3 & 3];
+    if (!((k ^ frame_counter) & 7)) {
+      uint16 x = (GetRandomNumber() & 0xf) - 4;
+      uint16 y = (GetRandomNumber() & 0xf) - 4;
+      Sprite_GarnishSpawn_Sparkle(k, x, y);
+    }
+    break;
+  }
+  case 4:  // disperse
+    if (!sprite_delay_main[k]) {
+      sprite_anim_clock[k] = 0;
+      sprite_ai_state[k] = 0;
+      sprite_z[k] = 0;
+      sprite_delay_main[k] = 64;
+    } else {
+      sprite_graphics[k] = (sprite_delay_main[k] >> 2) + 15;
+    }
+    break;
+  }
+}
+
+void Kyameron_Draw(int k) {  // 9ea158
+  static const uint8 kKyameron_OamFlags[12] = {0x40, 0, 0, 0, 0, 0, 0, 0, 0, 0x40, 0xc0, 0x80};
+  static const DrawMultipleData kKyameron_Dmd[28] = {
+    { 1,   8, 0x00b4, 0},
+    { 7,   8, 0x00b5, 0},
+    { 4,  -3, 0x0086, 0},
+    { 0, -13, 0x80a2, 2},
+    { 2,   8, 0x00b4, 0},
+    { 6,   8, 0x00b5, 0},
+    { 4,  -6, 0x0096, 0},
+    { 0, -20, 0x00a2, 2},
+    { 4,  -1, 0x0096, 0},
+    { 0, -27, 0x00a2, 2},
+    { 0, -27, 0x00a2, 2},
+    { 0, -27, 0x00a2, 2},
+    {-6,  -6, 0x01df, 0},
+    {14,  -6, 0x41df, 0},
+    {-6,  14, 0x81df, 0},
+    {14,  14, 0xc1df, 0},
+    {-6,  -6, 0x0096, 0},
+    {14,  -6, 0x4096, 0},
+    {-6,  14, 0x8096, 0},
+    {14,  14, 0xc096, 0},
+    {-4,  -4, 0x018d, 0},
+    {12,  -4, 0x418d, 0},
+    {-4,  12, 0x818d, 0},
+    {12,  12, 0xc18d, 0},
+    { 0,   0, 0x018d, 0},
+    { 8,   0, 0x418d, 0},
+    { 0,   8, 0x818d, 0},
+    { 8,   8, 0xc18d, 0},
+  };
+  int j = sprite_graphics[k];
+  if (j < 12) {
+    uint8 bak = sprite_oam_flags[k];
+    sprite_oam_flags[k] = sprite_oam_flags[k] & 0x3f | kKyameron_OamFlags[j];
+    SpriteDraw_SingleLarge(k);
+    sprite_oam_flags[k] = bak;
+  } else {
+    Sprite_DrawMultiple(k, &kKyameron_Dmd[(j - 12) * 4], 4, NULL);
+  }
+}
+
+void Sprite_99_Pengator(int k) {  // 9ea196
+  static const uint8 kPengator_Gfx[4] = {5, 0, 10, 15};
+  sprite_graphics[k] = sprite_A[k] + kPengator_Gfx[sprite_D[k]];
+  Pengator_Draw(k);
+  if (sprite_F[k] || sprite_wallcoll[k] & 15) {
+    sprite_ai_state[k] = 0;
+    sprite_x_vel[k] = 0;
+    sprite_y_vel[k] = 0;
+  }
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  if (Sprite_ReturnIfRecoiling(k))
+    return;
+  Sprite_CheckDamageToAndFromLink(k);
+  Sprite_MoveXYZ(k);
+  sprite_z_vel[k] -= 2;
+  if (sign8(sprite_z[k])) {
+    sprite_z_vel[k] = 0;
+    sprite_z[k] = 0;
+  }
+  Sprite_CheckTileCollision(k);
+  switch(sprite_ai_state[k]) {
+  case 0:  // face player
+    sprite_D[k] = Sprite_DirectionToFaceLink(k, NULL);
+    sprite_ai_state[k] = 1;
+    break;
+  case 1:  // speedup
+    if (!((k ^ frame_counter) & 3)) {
+      static const int8 kPengator_XYVel[6] = { 1, -1, 0, 0, 1, -1 };
+      bool flag = false;
+      int j = sprite_D[k];
+      if (sprite_x_vel[k] != (uint8)kFluteBoyAnimal_Xvel[j])
+        sprite_x_vel[k] += kPengator_XYVel[j], flag = true;
+      if (sprite_y_vel[k] != (uint8)kZazak_Yvel[j])
+        sprite_y_vel[k] += kPengator_XYVel[j + 2], flag = true;
+      if (!flag) {
+        sprite_delay_main[k] = 15;
+        sprite_ai_state[k] = 2;
+      }
+    }
+    sprite_A[k] = (frame_counter & 4) >> 2;
+    break;
+  case 2: { // jump
+    static const uint8 kPengator_Jump[4] = {4, 4, 3, 2};
+    if (!sprite_delay_main[k])
+      sprite_ai_state[k]++;
+    else if (sprite_delay_main[k] == 5)
+      sprite_z_vel[k] = 24;
+    sprite_A[k] = kPengator_Jump[sprite_delay_main[k] >> 2];
+    break;
+  }
+  case 3:  // slide and sparkle
+    if (!((k ^ frame_counter) & 7 | sprite_z[k])) {
+      static const int8 kPengator_Garnish_Y[8] = { 8, 10, 12, 14, 12, 12, 12, 12 };
+      static const int8 kPengator_Garnish_X[8] = { 4, 4, 4, 4, 0, 4, 8, 12 };
+      int i = sprite_D[k];
+      int x = kPengator_Garnish_X[(GetRandomNumber() & 3) + (i >= 2) * 4];
+      int y = kPengator_Garnish_Y[(GetRandomNumber() & 3) + (i >= 2) * 4];
+      Sprite_GarnishSpawn_Sparkle_limited(k, x, y);
+    }
+    break;
+  }
+}
+
+void Pengator_Draw(int k) {  // 9ea415
+  static const DrawMultipleData kPengator_Dmd0[40] = {
+    {-1, -8, 0x0082, 2},
+    { 0,  0, 0x0088, 2},
+    {-1, -7, 0x0082, 2},
+    { 0,  0, 0x008a, 2},
+    {-3, -6, 0x0082, 2},
+    { 0,  0, 0x0088, 2},
+    {-6, -4, 0x0082, 2},
+    { 0,  0, 0x008a, 2},
+    {-4,  0, 0x00a2, 2},
+    { 4,  0, 0x00a3, 2},
+    { 1, -8, 0x4082, 2},
+    { 0,  0, 0x4088, 2},
+    { 1, -7, 0x4082, 2},
+    { 0,  0, 0x408a, 2},
+    { 3, -6, 0x4082, 2},
+    { 0,  0, 0x4088, 2},
+    { 6, -4, 0x4082, 2},
+    { 0,  0, 0x408a, 2},
+    { 4,  0, 0x40a2, 2},
+    {-4,  0, 0x40a3, 2},
+    { 0, -7, 0x0080, 2},
+    { 0,  0, 0x0086, 2},
+    { 0, -7, 0x4080, 2},
+    { 0,  0, 0x4086, 2},
+    { 0, -4, 0x0080, 2},
+    { 0,  0, 0x0086, 2},
+    { 0, -1, 0x0080, 2},
+    { 0,  0, 0x0086, 2},
+    {-8,  0, 0x008e, 2},
+    { 8,  0, 0x408e, 2},
+    { 0, -8, 0x0084, 2},
+    { 0,  0, 0x008c, 2},
+    { 0, -8, 0x4084, 2},
+    { 0,  0, 0x408c, 2},
+    { 0, -7, 0x0084, 2},
+    { 0,  0, 0x008c, 2},
+    { 0,  0, 0x408c, 2},
+    { 0, -6, 0x4084, 2},
+    {-8,  0, 0x00a0, 2},
+    { 8,  0, 0x40a0, 2},
+  };
+  static const DrawMultipleData kPengator_Dmd1[4] = {
+    {0, 16, 0x00b5, 0},
+    {8, 16, 0x40b5, 0},
+    {0, -8, 0x00a5, 0},
+    {8, -8, 0x40a5, 0},
+  };
+  PrepOamCoordsRet info;
+  Sprite_DrawMultiple(k, &kPengator_Dmd0[sprite_graphics[k] * 2], 2, &info);
+  int i;
+  if ((i = 0, sprite_graphics[k] == 14) || (i = 1, sprite_graphics[k] == 19)) {
+    oam_cur_ptr += 8, oam_ext_cur_ptr += 2;
+    Sprite_DrawMultiple(k, &kPengator_Dmd1[i * 2], 2, &info);
+  }
+  SpriteDraw_Shadow(k, &info);
+}
+
+void Sprite_LaserBeam(int k) {  // 9ea462
+  SpriteDraw_SingleSmall(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  LaserBeam_BuildUpGarnish(k);
+  Sprite_MoveXY(k);
+  Sprite_CheckDamageToLink_same_layer(k);
+  if (!sprite_delay_main[k] && Sprite_CheckTileCollision(k)) {
+    sprite_state[k] = 0;
+    SpriteSfx_QueueSfx3WithPan(k, 0x26);
+  }
+}
+
+void LaserBeam_BuildUpGarnish(int k) {  // 9ea488
+  int j = GarnishAllocOverwriteOld();
+  garnish_type[j] = 4;
+  garnish_active = 4;
+  Garnish_SetX(j, Sprite_GetX(k));
+  Garnish_SetY(j, Sprite_GetY(k) + 16);
+  garnish_countdown[j] = 16;
+  garnish_oam_flags[j] = sprite_graphics[k];
+  garnish_sprite[j] = k;
+  garnish_floor[j] = sprite_floor[k];
+}
+
+void Sprite_95_LaserEyeLeft(int k) {  // 9ea541
+  static const uint8 kLaserEye_Dirs[4] = {2, 3, 0, 1};
+  if (sprite_A[k]) {
+    Sprite_LaserBeam(k);
+    return;
+  }
+  LaserEye_Draw(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  switch(sprite_ai_state[k]) {
+  case 0:  // monitor firing zone
+    if (sprite_head_dir[k] == 0 && sprite_D[k] != kLaserEye_Dirs[link_direction_facing >> 1]) {
+      sprite_graphics[k] = 0;
+    } else {
+      uint16 j = (sprite_D[k] < 2) ? link_y_coord - cur_sprite_y : link_x_coord - cur_sprite_x;
+      if ((uint16)(j + 16) < 32) {
+        sprite_delay_main[k] = 32;
+        sprite_ai_state[k] = 1;
+      } else {
+        sprite_graphics[k] = 0;
+      }
+    }
+    break;
+  case 1:  // firing beam
+    sprite_graphics[k] = 1;
+    if (!sprite_delay_main[k]) {
+      sprite_ai_state[k] = 0;
+      LaserEye_FireBeam(k);
+      sprite_delay_aux4[k] = 12;
+    }
+    break;
+  }
+}
+
+void LaserEye_FireBeam(int k) {  // 9ea5d8
+  static const int8 kLaserEye_SpawnXY[6] = {12, -4, 4, 4, 12, -4};
+  static const int8 kLaserEye_SpawnXYVel[6] = {112, -112, 0, 0, 112, -112};
+  SpriteSpawnInfo info;
+  int j = Sprite_SpawnDynamically(k, 0x95, &info);
+  if (j >= 0) {
+    int i = sprite_D[k];
+    sprite_graphics[j] = (i & 2) >> 1;
+    Sprite_SetX(j, info.r0_x + kLaserEye_SpawnXY[i]);
+    Sprite_SetY(j, info.r2_y + kLaserEye_SpawnXY[i + 2]);
+    sprite_x_vel[j] = kLaserEye_SpawnXYVel[i];
+    sprite_y_vel[j] = kLaserEye_SpawnXYVel[i + 2];
+    sprite_flags2[j] = 0x20;
+    sprite_A[j] = 0x20;
+    sprite_oam_flags[j] = 5;
+    sprite_defl_bits[j] = 0x48;
+    sprite_ignore_projectile[j] = 0x48;
+    sprite_delay_main[j] = 5;
+    if (link_shield_type == 3)
+      sprite_flags5[j] = 32;
+    SpriteSfx_QueueSfx3WithPan(k, 0x19);
+  }
+}
+
+void LaserEye_Draw(int k) {  // 9ea708
+  static const DrawMultipleData kLaserEye_Dmd[24] = {
+    { 8, -4, 0x40c8, 0},
+    { 8,  4, 0x40d8, 0},
+    { 8, 12, 0xc0c8, 0},
+    { 8, -4, 0x40c9, 0},
+    { 8,  4, 0x40d9, 0},
+    { 8, 12, 0xc0c9, 0},
+    { 0, -4, 0x00c8, 0},
+    { 0,  4, 0x00d8, 0},
+    { 0, 12, 0x80c8, 0},
+    { 0, -4, 0x00c9, 0},
+    { 0,  4, 0x00d9, 0},
+    { 0, 12, 0x80c9, 0},
+    {-4,  8, 0x00d6, 0},
+    { 4,  8, 0x00d7, 0},
+    {12,  8, 0x40d6, 0},
+    {-4,  8, 0x00c6, 0},
+    { 4,  8, 0x00c7, 0},
+    {12,  8, 0x40c6, 0},
+    {-4,  0, 0x80d6, 0},
+    { 4,  0, 0x80d7, 0},
+    {12,  0, 0xc0d6, 0},
+    {-4,  0, 0x80c6, 0},
+    { 4,  0, 0x80c7, 0},
+    {12,  0, 0xc0c6, 0},
+  };
+  if (sprite_head_dir[k])
+    sprite_graphics[k] = (sprite_delay_aux4[k] == 0);
+  sprite_obj_prio[k] = 0x30;
+  Sprite_DrawMultiple(k, &kLaserEye_Dmd[(sprite_graphics[k] + sprite_D[k] * 2) * 3], 3, NULL);
+}
+
+void Sprite_94_Pirogusu(int k) {  // 9ea742
+  static const uint8 kPirogusu_A0[4] = {2, 3, 0, 1};
+  static const uint8 kPirogusu_A1[8] = {9, 11, 5, 7, 5, 11, 7, 9};
+  static const uint8 kPirogusu_A2[8] = {16, 17, 18, 19, 12, 13, 14, 15};
+  static const int8 kPirogusu_XYvel[6] = {0, 0, 4, -4, 0, 0};
+  static const int8 kPirogusu_XYvel2[6] = {2, -2, 0, 0, 2, -2};
+  static const int8 kPirogusu_XYvel3[6] = {24, -24, 0, 0, 24, -24};
+
+  if (sprite_E[k]) {
+    Sprite_94_Tile(k);
+    return;
+  }
+  sprite_obj_prio[k] |= 0x30;
+  Pirogusu_Draw(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  switch(sprite_ai_state[k]) {
+  case 0:  // wriggle in hole
+    if (!sprite_delay_main[k]) {
+      sprite_ai_state[k] = 1;
+      sprite_delay_main[k] = 31;
+    }
+    sprite_ignore_projectile[k] = sprite_delay_main[k];
+    sprite_A[k] = kPirogusu_A0[sprite_D[k]];
+    break;
+  case 1: { // emerge
+    if (!sprite_delay_main[k]) {
+      sprite_ai_state[k] = 2;
+      sprite_delay_main[k] = 32;
+      sprite_ignore_projectile[k] = 0;
+      Sprite_ZeroVelocity_XY(k);
+    } else {
+      sprite_A[k] = kPirogusu_A1[sprite_delay_main[k] >> 3 & 1 | sprite_D[k] << 1];
+      int j = sprite_D[k];
+      sprite_x_vel[k] = kPirogusu_XYvel[j + 2];
+      sprite_y_vel[k] = kPirogusu_XYvel[j];
+      Sprite_MoveXY(k);
+    }
+    break;
+  }
+  case 2: {  // splash into play
+    Sprite_CheckDamageToAndFromLink(k);
+    Sprite_MoveXY(k);
+    int j = sprite_D[k];
+    sprite_x_vel[k] += kPirogusu_XYvel2[j];
+    sprite_y_vel[k] += kPirogusu_XYvel2[j + 2];
+    if (!sprite_delay_main[k]) {
+      Sprite_SpawnSmallSplash(k);
+      sprite_delay_aux1[k] = 16;
+      sprite_ai_state[k] = 3;
+    }
+    sprite_A[k] = kPirogusu_A2[frame_counter >> 2 & 1 | sprite_D[k] << 1];
+    break;
+  }
+  case 3: { // swim
+    if (Sprite_ReturnIfRecoiling(k))
+      return;
+    Sprite_CheckDamageToAndFromLink(k);
+    sprite_A[k] = kPirogusu_A2[frame_counter >> 2 & 1 | sprite_D[k] << 1] + 8;
+    if (!sprite_delay_aux1[k]) {
+      Pirogusu_SpawnSplash(k);
+      Sprite_MoveXY(k);
+      if (Sprite_CheckTileCollision(k) & 15) {
+        static const uint8 kPirogusu_Dir[8] = {2, 3, 2, 3, 0, 1, 0, 1};
+        sprite_D[k] = kPirogusu_Dir[sprite_D[k] << 1 | GetRandomNumber() & 1];
+      }
+      int j = sprite_D[k];
+      sprite_x_vel[k] = kPirogusu_XYvel3[j];
+      sprite_y_vel[k] = kPirogusu_XYvel3[j + 2];
+    }
+    break;
+  }
+  }
+}
+
+void Pirogusu_SpawnSplash(int k) {  // 9ea897
+  static const uint8 kPirogusu_Tab0[4] = {3, 4, 5, 4};
+  if ((k ^ frame_counter) & 3)
+    return;
+  int x = kPirogusu_Tab0[GetRandomNumber() & 3];
+  int y = kPirogusu_Tab0[GetRandomNumber() & 3];
+  int j = GarnishAllocLow();
+  if (j >= 0) {
+    garnish_type[j] = 11;
+    garnish_active = 11;
+    Garnish_SetX(j, Sprite_GetX(k) + x);
+    Garnish_SetY(j, Sprite_GetY(k) + y + 16);
+    garnish_countdown[j] = 15;
+  }
+}
+
+void Pirogusu_Draw(int k) {  // 9ea93b
+  static const uint8 kPirogusu_OamFlags[28] = {
+       0, 0x80, 0x40,    0, 0,    0,    0, 0x80, 0x80, 0xc0, 0x40, 0x40, 0, 0x40, 0x80, 0xc0,
+    0x40, 0xc0,    0, 0x80, 0, 0x40, 0x80, 0xc0, 0x40, 0xc0,    0, 0x80,
+  };
+  static const uint8 kPirogusu_Gfx[28] = {
+    0, 0, 1, 1, 2, 3, 4, 3, 2, 3, 4, 3, 5, 5, 5, 5,
+    7, 7, 7, 7, 6, 6, 6, 6, 8, 8, 8, 8,
+  };
+  int j = sprite_A[k];
+  sprite_oam_flags[k] = sprite_oam_flags[k] & 0x3f | kPirogusu_OamFlags[j];
+  sprite_graphics[k] = kPirogusu_Gfx[j];
+  if (j < 4) {
+    cur_sprite_x += 4, cur_sprite_y += 4;
+    SpriteDraw_SingleSmall(k);
+  } else {
+    SpriteDraw_SingleLarge(k);
+  }
+}
+
+void Sprite_93_Bumper(int k) {  // 9ea982
+  static const int8 kBumper_Vels[4] = { 0, 2, -2, 0 };
+  Bumper_Draw(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  Sprite_CheckTileCollision(k);
+  if (!link_cape_mode && Sprite_CheckDamageToLink_same_layer(k)) {
+    Link_CancelDash();
+    sprite_delay_main[k] = 32;
+    ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLink(k, 0x30);
+    link_actual_vel_y = pt.y + kBumper_Vels[joypad1H_last >> 2 & 3];
+    link_actual_vel_x = pt.x + kBumper_Vels[joypad1H_last & 3];
+    link_incapacitated_timer = 20;
+    Link_ResetSwimmingState();
+    SpriteSfx_QueueSfx3WithPan(k, 0x32);
+  }
+  for (int j = 15; j >= 0; j--) {
+    if ((j ^ frame_counter) & 3 | sprite_z[j])
+      continue;
+    if (sprite_state[j] < 9 || (sprite_flags3[j] | sprite_flags4[j]) & 0x40)
+      continue;
+    int x = Sprite_GetX(j), y = Sprite_GetY(j);
+    if ((uint16)(cur_sprite_x - x + 16) < 32 && (uint16)(cur_sprite_y - y + 16) < 32) {
+      sprite_F[j] = 15;
+      ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLocation(k, x, y, 0x40);
+      sprite_y_recoil[j] = pt.y;
+      sprite_x_recoil[j] = pt.x;
+      sprite_delay_main[k] = 32;
+      SpriteSfx_QueueSfx3WithPan(k, 0x32);
+    }
+  }
+}
+
+void Bumper_Draw(int k) {  // 9eaa8b
+  static const DrawMultipleData kBumper_Dmd[8] = {
+    {-8, -8, 0x00ec, 2},
+    { 8, -8, 0x40ec, 2},
+    {-8,  8, 0x80ec, 2},
+    { 8,  8, 0xc0ec, 2},
+    {-7, -7, 0x00ec, 2},
+    { 7, -7, 0x40ec, 2},
+    {-7,  7, 0x80ec, 2},
+    { 7,  7, 0xc0ec, 2},
+  };
+  Sprite_DrawMultiple(k, &kBumper_Dmd[(sprite_delay_main[k] >> 1 & 1) * 4], 4, NULL);
+}
+
+void Sprite_91_StalfosKnight(int k) {  // 9eaaa7
+  int j;
+  if (!sprite_ai_state[k]) {
+    PrepOamCoordsRet info;
+    Sprite_PrepOamCoord(k, &info);
+  } else {
+    StalfosKnight_Draw(k);
+  }
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  if ((sprite_hit_timer[k] & 127) == 1) {
+    sprite_hit_timer[k] = 0;
+    sprite_ai_state[k] = 6;
+    sprite_delay_main[k] = 255;
+    sprite_x_vel[k] = 0;
+    sprite_y_vel[k] = 0;
+    enemy_damage_data[0x918] = 2;
+  }
+  if (Sprite_ReturnIfRecoiling(k))
+    return;
+  switch(sprite_ai_state[k]) {
+  case 0: { // waiting for player
+    sprite_flags4[k] = 9;
+    sprite_ignore_projectile[k] = 9;
+    uint8 bak0 = sprite_flags2[k];
+    sprite_flags2[k] |= 128;
+    bool flag = Sprite_CheckDamageToLink(k);
+    sprite_flags2[k] = bak0;
+    if (flag) {
+      sprite_z[k] = 144;
+      sprite_ai_state[k] = 1;
+      sprite_head_dir[k] = 2;
+      sprite_graphics[k] = 2;
+      SpriteSfx_QueueSfx2WithPan(k, 0x20);
+    }
+    break;
+  }
+  case 1: { // falling
+    uint8 old_z = sprite_z[k];
+    Sprite_MoveZ(k);
+    if (!sign8(sprite_z_vel[k] + 64))
+      sprite_z_vel[k] -= 3;
+    if (sign8(old_z ^ sprite_z[k]) && sign8(sprite_z[k])) {
+      sprite_ai_state[k] = 2;
+      sprite_ignore_projectile[k] = 0;
+      sprite_z[k] = 0;
+      sprite_z_vel[k] = 0;
+      sprite_delay_main[k] = 63;
+    }
+    break;
+  }
+  case 2: {  //
+    static const uint8 kStalfosKnight_Case2_Gfx[2] = {0, 1};
+    enemy_damage_data[0x918] = 0;
+    Sprite_CheckDamageToAndFromLink(k);
+    if (!sprite_delay_main[k]) {
+      sprite_ai_state[k] = 3;
+      sprite_B[k] = GetRandomNumber() & 63;
+      sprite_delay_main[k] = 127;
+    } else {
+      sprite_C[k] = sprite_graphics[k] = kStalfosKnight_Case2_Gfx[sprite_delay_main[k] >> 5];
+      sprite_head_dir[k] = 2;
+    }
+    break;
+  }
+  case 3:  //
+    Sprite_CheckDamageToAndFromLink(k);
+    if (sprite_delay_main[k] == sprite_B[k]) {
+      sprite_head_dir[k] = Sprite_IsRightOfLink(k).a;
+      sprite_ai_state[k] = 4;
+      sprite_delay_main[k] = 32;
+    } else {
+      static const uint8 kStalfosKnight_Case2_Dir[16] = {0, 0, 0, 2, 1, 1, 1, 2, 0, 0, 0, 2, 1, 1, 1, 2};
+      sprite_head_dir[k] = kStalfosKnight_Case2_Dir[sprite_delay_main[k] >> 3];
+      sprite_C[k] = 0;
+      sprite_graphics[k] = 0;
+    }
+    break;
+  case 4:  //
+    Sprite_CheckDamageToAndFromLink(k);
+    if (!sprite_delay_main[k]) {
+      sprite_ai_state[k] = 5;
+      sprite_delay_main[k] = 255;
+      sprite_delay_aux1[k] = 32;
+    }
+    sprite_C[k] = 1;
+    sprite_graphics[k] = 1;
+    break;
+  case 5:  //
+    Sprite_CheckDamageToAndFromLink(k);
+    if (sprite_delay_aux1[k] == 0) {
+      Sprite_MoveXYZ(k);
+      Sprite_CheckTileCollision(k);
+      if (!sign8(sprite_z_vel[k] + 64))
+        sprite_z_vel[k] -= 2;
+      if (sign8(sprite_z[k] - 1)) {
+        sprite_z[k] = 0;
+        sprite_z_vel[k] = 0;
+        if (!sprite_delay_main[k])
+          goto SetToGround;
+        sprite_delay_aux1[k] = 16;
+      }
+      sprite_graphics[k] = sign8(sprite_z_vel[k] - 24) ? 2 : 0;
+    } else {
+      if (sprite_delay_aux1[k] == 1) {
+        sprite_z_vel[k] = 48;
+        Sprite_ApplySpeedTowardsLink(k, 16);
+        sprite_head_dir[k] = Sprite_IsRightOfLink(k).a;
+        SpriteSfx_QueueSfx3WithPan(k, 0x13);
+      }
+      sprite_C[k] = 1;
+      sprite_graphics[k] = 1;
+    }
+    break;
+  case 6:  //
+    Sprite_MoveXYZ(k);
+    Sprite_CheckTileCollision(k);
+    if (!sign8(sprite_z_vel[k] + 64))
+      sprite_z_vel[k] -= 2;
+    if (sign8(sprite_z[k] - 1)) {
+      sprite_z[k] = 0;
+      sprite_z_vel[k] = 0;
+    }
+    j = sprite_delay_main[k];
+    if (!j) {
+      if (GetRandomNumber() & 1)
+        goto SetToGround;
+      sprite_ai_state[k] = 7;
+      sprite_delay_main[k] = 80;
+    } else {
+      if (j >= 224 && (j & 3) == 0)
+        SpriteSfx_QueueSfx3WithPan(k, 0x14);
+      static const uint8 kStalfosKnight_Case6_C[32] = {
+        0,  4,  8, 12, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+        14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 14, 12,  8,  4,  0,
+      };
+      sprite_C[k] = kStalfosKnight_Case6_C[j >> 3];
+      sprite_graphics[k] = 3;
+      sprite_head_dir[k] = 2;
+    }
+    break;
+  case 7:  //
+    if (!sprite_delay_main[k]) {
+SetToGround:
+      sprite_ai_state[k] = 2;
+      sprite_ignore_projectile[k] = 0;
+      sprite_z[k] = 0;
+      sprite_z_vel[k] = 0;
+      sprite_delay_main[k] = 63;
+    } else {
+      static const uint8 kStalfosKnight_Case7_Gfx[2] = {1, 4};
+      sprite_graphics[k] = kStalfosKnight_Case7_Gfx[sprite_delay_main[k] >> 2 & 1];
+    }
+    break;
+  }
+}
+
+void StalfosKnight_Draw(int k) {  // 9eae04
+  static const DrawMultipleData kStalfosKnight_Dmd[35] = {
+    {-4, -8, 0x0064, 0},
+    {-4,  0, 0x0061, 2},
+    { 4,  0, 0x0062, 2},
+    {-3, 16, 0x0074, 0},
+    {11, 16, 0x4074, 0},
+    {-4, -7, 0x0064, 0},
+    {-4,  1, 0x0061, 2},
+    { 4,  1, 0x0062, 2},
+    {-3, 16, 0x0065, 0},
+    {11, 16, 0x4065, 0},
+    {-4, -8, 0x0048, 2},
+    { 4, -8, 0x0049, 2},
+    {-4,  8, 0x004b, 2},
+    { 4,  8, 0x004c, 2},
+    { 4,  8, 0x004c, 2},
+    {-4,  8, 0x0068, 2},
+    { 4,  8, 0x0069, 2},
+    { 4,  8, 0x0069, 2},
+    { 4,  8, 0x0069, 2},
+    { 4,  8, 0x0069, 2},
+    {12, -7, 0x4064, 0},
+    {-4,  1, 0x4062, 2},
+    { 4,  1, 0x4061, 2},
+    {-3, 16, 0x0065, 0},
+    {11, 16, 0x4065, 0},
+    {12, -8, 0x4064, 0},
+    {-4,  0, 0x4062, 2},
+    { 4,  0, 0x4061, 2},
+    {-3, 16, 0x0074, 0},
+    {11, 16, 0x4074, 0},
+    {-4, -8, 0x4049, 2},
+    { 4, -8, 0x4048, 2},
+    {-4,  8, 0x404c, 2},
+    { 4,  8, 0x404b, 2},
+    { 4,  8, 0x404b, 2},
+  };
+  PrepOamCoordsRet info;
+  if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
+    return;
+  SpriteDraw_StalfosKnight_Head(k, &info);
+  oam_cur_ptr += 4, oam_ext_cur_ptr += 1;
+  Sprite_DrawMultiple(k, &kStalfosKnight_Dmd[sprite_graphics[k] * 5], 5, &info);
+  oam_cur_ptr -= 4, oam_ext_cur_ptr -= 1;
+  SpriteDraw_Shadow_custom(k, &info, 18);
+}
+
+void SpriteDraw_StalfosKnight_Head(int k, PrepOamCoordsRet *info) {  // 9eae4e
+  static const uint8 kStalfosKnight_DrawHead_Char[4] = {0x66, 0x66, 0x46, 0x46};
+  static const uint8 kStalfosKnight_DrawHead_Flags[4] = {0x40, 0, 0, 0};
+  if (sprite_graphics[k] == 2)
+    return;
+  int i = sprite_head_dir[k];
+  OamEnt *oam = GetOamCurPtr();
+  SetOamHelper0(oam, info->x, info->y + sprite_C[k] - 12,
+                kStalfosKnight_DrawHead_Char[i],
+                info->flags | kStalfosKnight_DrawHead_Flags[i], 2);
+}
+
+void Sprite_90_Wallmaster(int k) {  // 9eaea4
+  sprite_obj_prio[k] |= 0x30;
+  WallMaster_Draw(k);
+  if (sprite_state[k] != 9) {
+    flag_is_link_immobilized = 0;
+    link_disable_sprite_damage = 0;
+  }
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  if (sprite_A[k]) {
+    link_x_coord = Sprite_GetX(k);
+    link_y_coord = Sprite_GetY(k) - sprite_z[k] + 3;
+    flag_is_link_immobilized = 1;
+    link_disable_sprite_damage = 1;
+    link_incapacitated_timer = 0;
+    link_actual_vel_x = link_actual_vel_y = 0;
+    link_y_vel = link_x_vel = 0;
+    if ((uint16)(link_y_coord - BG2VOFS_copy2 - 16) >= 0x100) {
+      flag_is_link_immobilized = 0;
+      link_disable_sprite_damage = 0;
+      WallMaster_SendPlayerToLastEntrance();
+      Link_Initialize();
+      return;
+    }
+  } else {
+    Sprite_CheckDamageFromLink(k);
+  }
+  switch(sprite_ai_state[k]) {
+  case 0: {  // Descend
+    uint8 old_z = sprite_z[k];
+    Sprite_MoveZ(k);
+    if (!sign8(sprite_z_vel[k] + 64))
+      sprite_z_vel[k] -= 3;
+    if (sign8(old_z ^ sprite_z[k]) && sign8(sprite_z[k])) {
+      sprite_ai_state[k] = 1;
+      sprite_z[k] = 0;
+      sprite_z_vel[k] = 0;
+      sprite_delay_main[k] = 63;
+    }
+    break;
+  }
+  case 1:  // Attempt Grab
+    if (!sprite_delay_main[k])
+      sprite_ai_state[k] = 2;
+
+    sprite_graphics[k] = (sprite_delay_main[k] & 0x20) ? 0 : 1;
+    if (Sprite_CheckDamageToLink(k)) {
+      sprite_A[k] = 1;
+      sprite_flags3[k] = 64;
+      SpriteSfx_QueueSfx3WithPan(k, 0x2a);
+    }
+    break;
+  case 2: {  // Ascend
+    uint8 old_z = sprite_z[k];
+    Sprite_MoveZ(k);
+    if (sign8(sprite_z_vel[k] - 64))
+      sprite_z_vel[k] += 2;
+    if (sign8(old_z ^ sprite_z[k]) && !sign8(sprite_z[k])) {
+      sprite_state[k] = 0;
+    }
+    break;
+  }
+  }
+}
+
+void WallMaster_Draw(int k) {  // 9eafe4
+  static const DrawMultipleData kWallMaster_Dmd[8] = {
+    {-4,  0, 0x01a6, 2},
+    {12,  0, 0x01aa, 0},
+    {-4, 16, 0x01ba, 0},
+    { 4,  8, 0x01a8, 2},
+    {-4,  0, 0x01ab, 2},
+    {12,  0, 0x01af, 0},
+    {-4, 16, 0x01bf, 0},
+    { 4,  8, 0x01ad, 2},
+  };
+  Sprite_DrawMultiple(k, &kWallMaster_Dmd[sprite_graphics[k] * 4], 4, NULL);
+  Sprite_DrawLargeShadow2(k);
+}
+
+void Sprite_8F_Blob(int k) {  // 9eb002
+  if (sprite_state[k] == 9 && sprite_E[k]) {
+    sprite_E[k] = 0;
+    sprite_x_vel[k] = 1;
+    uint8 t = Sprite_CheckTileCollision(k);
+    sprite_x_vel[k] = 0;
+    if (t) {
+      sprite_state[k] = 0;
+      return;
+    }
+    SpriteSfx_QueueSfx2WithPan(k, 0x20);
+  }
+  if (sprite_C[k])
+    sprite_obj_prio[k] = 0x30;
+  Zol_Draw(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+
+  if (sprite_ai_state[k] >= 2) {
+    Sprite_CheckDamageFromLink(k);
+  }
+  if (Sprite_ReturnIfRecoiling(k))
+    return;
+  switch(sprite_ai_state[k]) {
+  case 0: { // hiding unseen
+    uint8 bak = sprite_flags4[k];
+    sprite_flags4[k] |= 9;
+    sprite_flags2[k] |= 0x80;
+    uint8 t = Sprite_CheckDamageToLink(k);
+    sprite_flags4[k] = bak;
+    if (t) {
+      sprite_ai_state[k]++;
+      sprite_delay_main[k] = 127;
+      sprite_flags2[k] &= ~0x80;
+      Sprite_SetX(k, link_x_coord);
+      Sprite_SetY(k, link_y_coord + 8);
+      sprite_delay_aux4[k] = 48;
+      sprite_ignore_projectile[k] = 0;
+    }
+    break;
+  }
+  case 1: { // popping out
+    if (!sprite_delay_main[k]) {
+      sprite_ai_state[k]++;
+      sprite_z_vel[k] = 32;
+      Sprite_ApplySpeedTowardsLink(k, 16);
+      SpriteSfx_QueueSfx3WithPan(k, 0x30);
+    } else {
+      static const int8 kZol_PoppingOutGfx[16] = {0, 1, 7, 7, 6, 6, 5, 5, 6, 6, 5, 5, 4, 4, 4, 4};
+      sprite_graphics[k] = kZol_PoppingOutGfx[sprite_delay_main[k] >> 3];
+    }
+    break;
+  }
+  case 2: { // falling
+    if (sprite_delay_main[k] == 0) {
+      Sprite_CheckDamageFromLink(k);
+      Sprite_MoveXY(k);
+      Sprite_CheckTileCollision(k);
+      uint8 oldz = sprite_z[k];
+      Sprite_MoveZ(k);
+      if (!sign8(sprite_z_vel[k] + 64))
+        sprite_z_vel[k] -= 2;
+      if (sign8(sprite_z[k] ^ oldz) && sign8(sprite_z[k])) {
+        sprite_z_vel[k] = 0;
+        sprite_z[k] = 0;
+        sprite_C[k] = 0;
+        sprite_delay_main[k] = 31;
+        sprite_head_dir[k] = 8;
+      }
+    } else if (sprite_delay_main[k] == 1) {
+      sprite_delay_main[k] = 32;
+      sprite_ai_state[k]++;
+      sprite_graphics[k] = 0;
+    } else {
+      static const int8 kZol_FallingXvel[2] = {-8, 8};
+      static const int8 kZol_FallingGfx[2] = {0, 1};
+      sprite_graphics[k] = kZol_FallingGfx[(sprite_delay_main[k] - 1) >> 4];
+      sprite_x_vel[k] = kZol_FallingXvel[frame_counter >> 1 & 1];
+      Sprite_MoveX(k);
+    }
+    break;
+  }
+  case 3:  // active
+    Sprite_CheckDamageToLink(k);
+    if (!sprite_delay_aux1[k]) {
+      Sprite_ApplySpeedTowardsLink(k, 48);
+      sprite_delay_aux1[k] = GetRandomNumber() & 63 | 96;
+      sprite_oam_flags[k] = sprite_oam_flags[k] & 0x3f | (sign8(sprite_x_vel[k]) ? 0x40 : 0);
+    }
+    if (!sprite_delay_aux2[k]) {
+      sprite_subtype2[k]++;
+      if (!(sprite_subtype2[k] & 14 | sprite_wallcoll[k])) {
+        Sprite_MoveXY(k);
+        if (++sprite_G[k] == sprite_head_dir[k]) {
+          sprite_G[k] = 0;
+          sprite_delay_aux2[k] = (GetRandomNumber() & 31) + 64;
+          sprite_head_dir[k] = GetRandomNumber() & 31 | 16;
+        }
+      }
+      Sprite_CheckTileCollision(k);
+      sprite_graphics[k] = (sprite_subtype2[k] & 8) >> 3;
+    } else {
+      sprite_graphics[k] = sprite_delay_aux2[k] & 0x10 ? 1 : 0;
+    }
+    break;
+  }
+}
+
+void Zol_Draw(int k) {  // 9eb1c5
+  PrepOamCoordsRet info;
+  if (!(sprite_oam_flags[k] & 1) && byte_7E0FC6 >= 3)
+    return;
+
+  if (sprite_delay_aux4[k])
+    Oam_AllocateFromRegionB(8);
+
+  if (!sprite_ai_state[k]) {
+    Sprite_PrepOamCoord(k, &info);
+    return;
+  }
+  uint8 gfx = sprite_graphics[k];
+  if (gfx < 4) {
+    static const uint8 kZol_OamFlags[4] = {0, 0, 0x40, 0x40};
+    uint8 bak1 = sprite_oam_flags[k];
+    sprite_oam_flags[k] = bak1 ^ kZol_OamFlags[gfx];
+    sprite_graphics[k] = gfx + ((sprite_oam_flags[k] & 1 ^ 1) << 2);
+    SpriteDraw_SingleLarge(k);
+    sprite_graphics[k] = gfx;
+    sprite_oam_flags[k] = bak1;
+  } else {
+    static const DrawMultipleData kZol_Dmd[8] = {
+      {0, 8, 0x036c, 0},
+      {8, 8, 0x036d, 0},
+      {0, 8, 0x0060, 0},
+      {8, 8, 0x0070, 0},
+      {0, 8, 0x4070, 0},
+      {8, 8, 0x4060, 0},
+      {0, 0, 0x0040, 2},
+      {0, 0, 0x0040, 2},
+    };
+    Sprite_DrawMultiple(k, &kZol_Dmd[(gfx - 4) * 2], 2, NULL);
+  }
+}
+
+void Sprite_8E_Terrorpin(int k) {  // 9eb26f
+  int j;
+  static const int8 kTerrorpin_Xvel[8] = {8, -8, 0, 0, 12, -12, 0, 0};
+  static const int8 kTerrorpin_Yvel[8] = {0, 0, 8, -8, 0, 0, 12, -12};
+  static const uint8 kTerrorpin_Oamflags[2] = {0, 0x40};
+  static const int8 kTerrorpin_Overturned_Xvel[2] = {8, -8};
+  SpriteDraw_SingleLarge(k);
+  Sprite_CheckTileCollision(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  if (Sprite_ReturnIfRecoiling(k))
+    return;
+  if (!sprite_delay_aux2[k])
+    Sprite_CheckDamageFromLink(k);
+  Terrorpin_CheckForHammer(k);
+  Sprite_MoveXYZ(k);
+  switch (sprite_B[k]) {
+  case 0:  // upright
+    if (!sprite_delay_aux4[k]) {
+      sprite_delay_aux4[k] = (GetRandomNumber() & 31) + 32;
+      sprite_D[k] = Sprite_DirectionToFaceLink(k, NULL);
+    }
+    j = sprite_D[k] + sprite_G[k];
+    sprite_x_vel[k] = kTerrorpin_Xvel[j];
+    sprite_y_vel[k] = kTerrorpin_Yvel[j];
+    sprite_z_vel[k] -= 2;
+    if (sign8(sprite_z[k])) {
+      sprite_z[k] = 0;
+      sprite_z_vel[k] = 0;
+    }
+    sprite_graphics[k] = frame_counter >> (sprite_G[k] ? 2 : 3) & 1;
+    sprite_flags3[k] |= 64;
+    sprite_defl_bits[k] = 4;
+    Sprite_CheckDamageToLink(k);
+    break;
+  case 1:  // overturned
+    sprite_flags3[k] &= 191;
+    sprite_defl_bits[k] = 0;
+    if (!sprite_delay_aux4[k]) {
+      sprite_B[k] = 0;
+      sprite_z_vel[k] = 32;
+      sprite_delay_aux4[k] = 64;
+      return;
+    }
+    sprite_z_vel[k] -= 2;
+    if (sign8(sprite_z[k])) {
+      sprite_z[k] = 0;
+      uint8 t = (uint8)-sprite_z_vel[k] >> 1;
+      sprite_z_vel[k] = (t < 9) ? 0 : t;
+      sprite_x_vel[k] = (int8)sprite_x_vel[k] >> 1;
+      if (sprite_x_vel[k] == 0xff)
+        sprite_x_vel[k] = 0;
+      sprite_y_vel[k] = (int8)sprite_y_vel[k] >> 1;
+      if (sprite_y_vel[k] == 0xff)
+        sprite_y_vel[k] = 0;
+    }
+    if (sprite_delay_aux4[k] < 64) {
+      sprite_x_vel[k] = kTerrorpin_Overturned_Xvel[sprite_delay_aux4[k] >> 1 & 1];
+      sprite_subtype2[k]++;
+    }
+    sprite_graphics[k] = 2;
+    sprite_oam_flags[k] = sprite_oam_flags[k] & ~0x40 | kTerrorpin_Oamflags[++sprite_subtype2[k] >> 3 & 1];
+    break;
+  }
+}
+
+void Terrorpin_CheckForHammer(int k) {  // 9eb3a3
+  if (!(sprite_z[k] | sprite_delay_aux2[k]) &&
+      sprite_floor[k] == link_is_on_lower_level &&
+      player_oam_y_offset != 0x80 &&
+      link_item_in_hand & 0xa) {
+    SpriteHitBox hb;
+    Player_SetupActionHitBox(&hb);
+    Terrorpin_SetUpHammerHitBox(k, &hb);
+    if (CheckIfHitBoxesOverlap(&hb)) {
+      sprite_x_vel[k] = -sprite_x_vel[k];
+      sprite_y_vel[k] = -sprite_y_vel[k];
+      sprite_delay_aux2[k] = 32;
+      sprite_z_vel[k] = 32;
+      sprite_G[k] = 4;
+      sprite_B[k] ^= 1;
+      sprite_delay_aux4[k] = sprite_B[k] ? 0xff : 0x40;
+    }
+  }
+  sprite_head_dir[k] = 0;
+}
+
+void Terrorpin_SetUpHammerHitBox(int k, SpriteHitBox *hb) {  // 9eb405
+  int x = Sprite_GetX(k) - 16;
+  int y = Sprite_GetY(k) - 16;
+  hb->r4_spr_xlo = x;
+  hb->r10_spr_xhi = x >> 8;
+  hb->r5_spr_ylo = y;
+  hb->r11_spr_yhi = y >> 8;
+  hb->r6_spr_xsize = hb->r7_spr_ysize = 48;
+}
+
+void Sprite_8C_Arrghus(int k) {  // 9eb433
+  static const uint8 kArrghus_Gfx[9] = {1, 1, 1, 2, 2, 1, 1, 0, 0};
+  sprite_obj_prio[k] |= 0x30;
+  Arrghus_Draw(k);
+  if (sprite_state[k] != 9 || sprite_z[k] < 96) {
+    if (Sprite_ReturnIfInactive(k))
+      return;
+  }
+  Arrghus_HandlePuffs(k);
+  overlord_x_lo[4] = 1;
+  if ((sprite_hit_timer[k] & 127) == 2) {
+    sprite_ai_state[k] = 3;
+    SpriteSfx_QueueSfx3WithPan(k, 0x32);
+    sprite_subtype2[k] = 0;
+    sprite_flags3[k] = 64;
+  }
+  if (Sprite_ReturnIfRecoiling(k))
+    return;
+  Sprite_CheckDamageToLink(k);
+  if (!(sprite_subtype2[k]++ & 3)) {
+    if (++sprite_G[k] == 9)
+      sprite_G[k] = 0;
+    sprite_graphics[k] = kArrghus_Gfx[sprite_G[k]];
+  }
+
+  uint8 a = Sprite_CheckTileCollision(k);
+  if (a) {
+    if (sprite_ai_state[k] == 5) {
+      if (a & 3)
+        sprite_x_vel[k] = -sprite_x_vel[k];
+      else
+        sprite_y_vel[k] = -sprite_y_vel[k];
+    } else {
+      Sprite_ZeroVelocity_XY(k);
+    }
+  }
+
+  switch (sprite_ai_state[k]) {
+  case 0:  // approach speed
+    if (!sprite_delay_main[k]) {
+      sprite_ai_state[k] = 1;
+      sprite_delay_main[k] = 48;
+    }
+    Sprite_MoveXY(k);
+    Sprite_ApproachTargetSpeed(k, sprite_head_dir[k], sprite_D[k]);
+    break;
+  case 1:  // decelerate
+    if (!sprite_delay_main[k]) {
+      sprite_ai_state[k] = 0;
+      if (!Sprite_CheckIfScreenIsClear()) {
+        if (++overlord_x_lo[3] == 4) {
+          overlord_x_lo[3] = 0;
+          sprite_ai_state[k] = 2;
+          sprite_delay_main[k] = 176;
+        } else {
+          sprite_delay_main[k] = (GetRandomNumber() & 63) + 48;
+          ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLink(k, (sprite_delay_main[k] & 3) + 8);
+          sprite_head_dir[k] = pt.x;
+          sprite_D[k] = pt.y;
+        }
+      } else {
+        sprite_ai_state[k] = 3;
+        SpriteSfx_QueueSfx3WithPan(k, 0x32);
+        sprite_subtype2[k] = 0;
+      }
+    } else {
+      Sprite_MoveXY(k);
+      Sprite_ApproachTargetSpeed(k, 0, 0);
+    }
+    break;
+  case 2:  // case2
+    overlord_x_lo[4] = 8;
+    if (sprite_delay_main[k] < 32) {
+      if (sign8(--overlord_x_lo[2])) {
+        overlord_x_lo[2] = 0;
+        sprite_ai_state[k] = 1;
+        sprite_delay_main[k] = 112;
+      }
+    } else if (sprite_delay_main[k] < 96) {
+      overlord_x_lo[2]++;
+    } else if (sprite_delay_main[k] == 96) {
+      SpriteSfx_QueueSfx3WithPan(k, 0x26);
+    } else if ((sprite_delay_main[k] & 0xf) == 0) {
+      SpriteSfx_QueueSfx3WithPan(k, 0x6);
+    }
+    break;
+  case 3:  // jump way up
+    sprite_z_vel[k] = 120;
+    Sprite_MoveZ(k);
+    if (sprite_z[k] >= 224) {
+      sprite_delay_main[k] = 64;
+      sprite_ai_state[k] = 4;
+      sprite_z_vel[k] = 0;
+      sprite_x_lo[k] = link_x_coord;
+      sprite_y_lo[k] = link_y_coord;
+    }
+    break;
+  case 4: {  // swoosh from above
+    if (!(a = sprite_delay_main[k])) {
+      sprite_z_vel[k] = 144;
+      uint8 old_z = sprite_z[k];
+      Sprite_MoveZ(k);
+      if (sign8(a = old_z ^ sprite_z[k]) && sign8(a = sprite_z[k])) {
+        sprite_z[k] = 0;
+        Sprite_SpawnBigSplash(k);
+        sprite_ai_state[k] = 5;
+        sprite_delay_main[k] = 32;
+        SpriteSfx_QueueSfx3WithPan(k, 0x3);
+        sprite_x_vel[k] = 32;
+        sprite_y_vel[k] = 32;
+      }
+    }
+    if (a == 1) {  // wtf
+      SpriteSfx_QueueSfx2WithPan(k, 0x20);
+    }
+    break;
+  }
+  case 5:  // swim frantically
+    if (!sprite_delay_main[k]) {
+      sprite_flags3[k] = 0;
+      Sprite_MoveXY(k);
+      Sprite_CheckDamageFromLink(k);
+      if (!(frame_counter & 7)) {
+        SpriteSfx_QueueSfx2WithPan(k, 0x28);
+        int j = GarnishAllocLimit(sign8(sprite_y_vel[k]) ? 29 : 14);
+        if (j >= 0) {
+          garnish_type[j] = 21;
+          garnish_active = 21;
+          garnish_x_lo[j] = sprite_x_lo[k];
+          garnish_x_hi[j] = sprite_x_hi[k];
+          garnish_y_lo[j] = sprite_y_lo[k] + 24;  // why no carry propagation
+          garnish_y_hi[j] = sprite_y_hi[k];
+          garnish_countdown[j] = 15;
+        }
+      }
+    }
+    break;
+  }
+}
+
+void Arrghus_Draw(int k) {  // 9eb840
+  static const DrawMultipleData kArrghus_Dmd[5] = {
+    {-8, -4, 0x0080, 2},
+    { 8, -4, 0x4080, 2},
+    {-8, 12, 0x00a0, 2},
+    { 8, 12, 0x40a0, 2},
+    { 0, 24, 0x00a8, 2},
+  };
+  Sprite_DrawMultiple(k, kArrghus_Dmd, 5, NULL);
+  OamEnt *oam = GetOamCurPtr();
+  uint8 chr = sprite_graphics[k] * 2;
+  for (int i = 0; i < 4; i++)
+    oam[i].charnum += chr;
+  if (sprite_ai_state[k] == 5)
+    oam[4].y = 0xf0;
+  if (sprite_subtype2[k] & 8)
+    oam[4].flags |= 0x40;
+
+  if (sprite_ai_state[k] != 5) {
+    oam_cur_ptr += 4, oam_ext_cur_ptr += 1;
+    if (sprite_z[k] < 0xa0) {
+      uint8 bak = sprite_oam_flags[k];
+      sprite_oam_flags[k] &= ~1;
+      SpriteDraw_BigShadow(k, 0);
+      sprite_oam_flags[k] = bak;
+    }
+  } else {
+    Sprite_DrawLargeWaterTurbulence(k);
+  }
+
+}
+
+void Arrghus_HandlePuffs(int k) {  // 9eb8b4
+  static const uint16 kArrgi_Tab0[13] = {0, 0x40, 0x80, 0xc0, 0x100, 0x140, 0x180, 0x1c0, 0, 0x66, 0xcc, 0x132, 0x198};
+  static const uint16 kArrgi_Tab1[13] = {0, 0, 0, 0, 0, 0, 0, 0, 0x1ff, 0x1ff, 0x1ff, 0x1ff, 0x1ff};
+  static const uint8 kArrgi_Tab2[13] = {0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0xc, 0xc, 0xc, 0xc, 0xc};
+  static const int8 kArrgi_Tab3[52] = {
+    0, -1, -2, -3, -4, -5, -6, -6, -5, -4, -3, -2, -1,  0, -1, -2,
+    -3, -4, -5, -6, -6, -5, -4, -3, -2, -1,  0, -1, -2, -3, -4, -5,
+    -6, -6, -5, -4, -3, -2, -1,  0, -1, -2, -3, -4, -5, -6, -6, -5,
+    -4, -3, -2, -1,
+  };
+
+  WORD(overlord_x_lo[0]) += overlord_x_lo[4];
+  if (!(frame_counter & 3) && ++sprite_A[k] == 13)
+    sprite_A[k] = 0;
+  if (!(frame_counter & 7) && ++sprite_B[k] == 13)
+    sprite_B[k] = 0;
+  for(int i = 0; i != 13; i++) {
+    uint16 r0 = (WORD(overlord_x_lo[0]) + kArrgi_Tab0[i]) ^ kArrgi_Tab1[i];
+    uint8 r14 = overlord_x_lo[2] + kArrgi_Tab2[i];
+
+    int8 sin_val = ArrgiSin(r0 + 0x00, r14 + kArrgi_Tab3[sprite_A[k] + i]);
+    int8 cos_val = ArrgiSin(r0 + 0x80, r14 + kArrgi_Tab3[sprite_B[k] + i]);
+
+    int tx = Sprite_GetX(k) + sin_val;
+    overlord_x_hi[i] = tx;
+    overlord_y_hi[i] = tx >> 8;
+
+    int ty = Sprite_GetY(k) + cos_val - 0x10;
+    overlord_gen2[i] = ty;
+    overlord_floor[i] = ty >> 8;
+  }
+  tmp_counter = 13;
+}
+
+void Sprite_8D_Arrghi(int k) {  // 9eb8c4
+  static const uint8 kArrgi_Gfx[8] = {0, 1, 2, 2, 2, 2, 2, 1};
+
+  sprite_obj_prio[k] |= 0x30;
+  SpriteDraw_SingleLarge(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  sprite_graphics[k] = kArrgi_Gfx[++sprite_subtype2[k] >> 3 & 7];
+  if (sprite_B[k]) {
+    int j = sprite_B[k] - 1;
+    if (ancilla_type[j]) {
+      sprite_x_lo[k] = ancilla_x_lo[j];
+      sprite_x_hi[k] = ancilla_x_hi[j];
+      sprite_y_lo[k] = ancilla_y_lo[j];
+      sprite_y_hi[k] = ancilla_y_hi[j];
+      sprite_oam_flags[k] = 5;
+      sprite_flags3[k] &= ~0x40;
+      return;
+    }
+    sprite_ai_state[k] = 1;
+    sprite_B[k] = 0;
+    sprite_delay_main[k] = 32;
+  }
+  if (!sprite_delay_main[k])
+    Sprite_CheckDamageToLink(k);
+
+  if (!sprite_ai_state[k]) {
+    sprite_x_lo[k] = overlord_x_lo[k + 7];
+    sprite_x_hi[k] = overlord_y_lo[k + 7];
+    sprite_y_lo[k] = overlord_gen1[k + 7];
+    sprite_y_hi[k] = overlord_gen3[k + 7];
+    return;
+  }
+  Sprite_CheckDamageFromLink(k);
+  if (!((k ^ frame_counter) & 3)) {
+    uint16 x = overlord_y_lo[k + 7] << 8 | overlord_x_lo[k + 7];
+    uint16 y = overlord_gen3[k + 7] << 8 | overlord_gen1[k + 7];
+    ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLocation(k, x, y, 4);
+    sprite_y_vel[k] = pt.y;
+    sprite_x_vel[k] = pt.x;
+    if ((uint8)(sprite_x_lo[k] - overlord_x_lo[k + 7] + 8) < 16 && (uint8)(sprite_y_lo[k] - overlord_gen1[k + 7] + 8) < 16) {
+      sprite_ai_state[k] = 0;
+      sprite_oam_flags[k] = 0xd;
+      sprite_flags3[k] |= 0x40;
+    }
+  }
+  Sprite_MoveXY(k);
+
+}
+
+void Sprite_8B_Gibdo(int k) {  // 9eb9a9
+  Gibdo_Draw(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  if (Sprite_ReturnIfRecoiling(k))
+    return;
+  Sprite_CheckDamageToAndFromLink(k);
+  switch(sprite_ai_state[k]) {
+  case 0: {
+    static const uint8 kGibdo_DirTarget[4] = {2, 6, 4, 0};
+    static const uint8 kGibdo_Gfx[8] = {4, 8, 11, 10, 0, 6, 3, 7};
+    sprite_graphics[k] = kGibdo_Gfx[sprite_D[k]];
+    if (!(frame_counter & 7)) {
+      int j = sprite_A[k];
+      if (sprite_D[k] - kGibdo_DirTarget[j]) {
+        sprite_D[k] += sign8(sprite_D[k] - kGibdo_DirTarget[j]) ? 1 : -1;
+      } else {
+        sprite_delay_main[k] = (GetRandomNumber() & 31) + 48;
+        sprite_ai_state[k] = 1;
+      }
+    }
+    break;
+  }
+  case 1: {
+    static const int8 kGibdo_XyVel[10] = {-16, 0, 0, 0, 16, 0, 0, 0, -16, 0};
+    static const uint8 kGibdo_Gfx2[8] = {9, 2, 0, 4, 11, 3, 1, 5};
+    int j = sprite_D[k];
+    sprite_x_vel[k] = kGibdo_XyVel[j + 2];
+    sprite_y_vel[k] = kGibdo_XyVel[j];
+    Sprite_MoveXY(k);
+    Sprite_CheckTileCollision(k);
+    if ((!sprite_delay_main[k] || sprite_wallcoll[k]) && (j = Sprite_DirectionToFaceLink(k, NULL)) != sprite_A[k]) {
+      sprite_A[k] = j;
+      sprite_ai_state[k] = 0;
+    } else {
+      if (sign8(--sprite_B[k])) {
+        sprite_B[k] = 14;
+        sprite_subtype2[k]++;
+      }
+      sprite_graphics[k] = kGibdo_Gfx2[(sprite_subtype2[k] & 1) << 2 | sprite_A[k]];
+    }
+    break;
+  }
+  }
+}
+
+void Gibdo_Draw(int k) {  // 9ebb20
+  static const DrawMultipleData kGibdo_Dmd[24] = {
+    {0, -9, 0x0080, 2},
+    {0,  0, 0x008a, 2},
+    {0, -8, 0x0080, 2},
+    {0,  1, 0x408a, 2},
+    {0, -9, 0x0082, 2},
+    {0,  0, 0x008c, 2},
+    {0, -8, 0x0082, 2},
+    {0,  0, 0x008e, 2},
+    {0, -9, 0x0084, 2},
+    {0,  0, 0x00a0, 2},
+    {0, -8, 0x0084, 2},
+    {0,  1, 0x40a0, 2},
+    {0, -9, 0x0086, 2},
+    {0,  0, 0x00a2, 2},
+    {0, -9, 0x0088, 2},
+    {0,  0, 0x00a4, 2},
+    {0, -9, 0x4088, 2},
+    {0,  0, 0x40a4, 2},
+    {0, -9, 0x4082, 2},
+    {0,  0, 0x408c, 2},
+    {0, -9, 0x4086, 2},
+    {0,  0, 0x40a2, 2},
+    {0, -8, 0x4082, 2},
+    {0,  1, 0x408e, 2},
+  };
+  PrepOamCoordsRet info;
+  Sprite_DrawMultiple(k, &kGibdo_Dmd[sprite_graphics[k] * 2], 2, &info);
+  if (!sprite_pause[k])
+    SpriteDraw_Shadow(k, &info);
+}
+
+void Sprite_89_MothulaBeam(int k) {  // 9ebb42
+  SpriteDraw_SingleLarge(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  Sprite_CheckDamageToLink(k);
+  if (!(frame_counter & 1))
+    sprite_oam_flags[k] ^= 0x80;
+  Sprite_MoveXY(k);
+  if (!sprite_delay_main[k] && Sprite_CheckTileCollision(k))
+    sprite_state[k] = 0;
+  if ((k ^ frame_counter) & 3)
+    return;
+  for (int i = 14; i >= 0; i--) {
+    if (garnish_type[i] == 0) {
+      garnish_type[i] = 2;
+      garnish_active = 2;
+      garnish_x_lo[i] = sprite_x_lo[k];
+      garnish_x_hi[i] = sprite_x_hi[k];
+      garnish_y_lo[i] = sprite_y_lo[k];
+      garnish_y_hi[i] = sprite_y_hi[k];
+      garnish_countdown[i] = 16;
+      garnish_sprite[i] = k;
+      garnish_floor[i] = sprite_floor[k];
+      break;
+    }
+  }
+}
+
+void Sprite_94_Tile(int k) {  // 9ebbb9
+  sprite_obj_prio[k] = 0x30;
+  FlyingTile_Draw(k);
+  if (Sprite_ReturnIfPaused(k))
+    return;
+  if (sprite_hit_timer[k])
+    goto lbl_a;
+  sprite_ignore_projectile[k] = 1;
+  switch (sprite_ai_state[k]) {
+  case 0:  // erase tilemap
+    Dungeon_UpdateTileMapWithCommonTile(Sprite_GetX(k), (sprite_y_lo[k] + 8) & 0xff | (sprite_y_hi[k] << 8), 6);
+    sprite_ai_state[k] = 1;
+    sprite_delay_main[k] = 128;
+    break;
+  case 1:  // rise up
+    if (!sprite_delay_main[k]) {
+      sprite_ai_state[k] = 2;
+      sprite_delay_main[k] = 16;
+      Sprite_ApplySpeedTowardsLink(k, 32);
+    } else {
+      if (sprite_delay_main[k] >= 0x40) {
+        sprite_z_vel[k] = 4;
+        Sprite_MoveZ(k);
+      }
+lbl_b:
+      sprite_graphics[k] = ++sprite_subtype2[k] >> 2 & 1;
+      if (!((k ^ frame_counter) & 7))
+        SpriteSfx_QueueSfx2WithPan(k, 0x7);
+    }
+    break;
+  case 2:  // towards player
+    sprite_ignore_projectile[k] = 0;
+    if (sprite_delay_main[k] && (sprite_delay_main[k] & 3) == 0)
+      Sprite_ApplySpeedTowardsLink(k, 32);
+    if (!Sprite_CheckDamageToAndFromLink(k)) {
+      Sprite_MoveXY(k);
+      cur_sprite_y -= sprite_z[k];
+      if (!Sprite_CheckTileCollision(k))
+        goto lbl_b;
+    }
+lbl_a:
+    SpriteSfx_QueueSfx2WithPan(k, 0x1f);
+    sprite_state[k] = 6;
+    sprite_delay_main[k] = 31;
+    sprite_type[k] = 0xec;
+    sprite_hit_timer[k] = 0;
+    sprite_C[k] = 0x80;
+    break;
+  }
+}
+
+void FlyingTile_Draw(int k) {  // 9ebcca
+  static const DrawMultipleData kFlyingTile_Dmd[8] = {
+    {0, 0, 0x00d3, 0},
+    {8, 0, 0x40d3, 0},
+    {0, 8, 0x80d3, 0},
+    {8, 8, 0xc0d3, 0},
+    {0, 0, 0x00c3, 0},
+    {8, 0, 0x40c3, 0},
+    {0, 8, 0x80c3, 0},
+    {8, 8, 0xc0c3, 0},
+  };
+  PrepOamCoordsRet info;
+  Sprite_DrawMultiple(k, &kFlyingTile_Dmd[sprite_graphics[k] * 4], 4, &info);
+  SpriteDraw_Shadow(k, &info);
+}
+
+void Sprite_8A_SpikeBlock(int k) {  // 9ebce8
+  if (!sprite_E[k]) {
+    SpriteDraw_SingleLarge(k);
+    if (Sprite_ReturnIfInactive(k))
+      return;
+    Sprite_CheckDamageToAndFromLink(k);
+    Sprite_MoveXY(k);
+    Sprite_CheckTileCollision(k);
+    if (!sprite_delay_main[k] && (!SpikeBlock_CheckStatueCollision(k) || (sprite_wallcoll[k] & 0xf))) {
+      sprite_delay_main[k] = 4;
+      sprite_x_vel[k] = -sprite_x_vel[k];
+      SpriteSfx_QueueSfx2WithPan(k, 0x5);
+    }
+    return;
+  }
+  Oam_AllocateFromRegionB(4);
+  SpriteDraw_SingleLarge(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  Sprite_CheckDamageToAndFromLink(k);
+  if (sprite_ai_state[k] == 0) {
+    Dungeon_UpdateTileMapWithCommonTile(Sprite_GetX(k), Sprite_GetY(k), 0);
+    sprite_ai_state[k] = 1;
+    sprite_delay_main[k] = 64;
+    sprite_delay_aux1[k] = 105;
+  } else if (sprite_delay_main[k] != 0) {
+    if (sprite_delay_main[k] == 1) {
+      sprite_x_lo[k] = sprite_A[k];
+      sprite_y_lo[k] = sprite_B[k];
+    } else {
+      sprite_x_vel[k] = (sprite_delay_main[k] >> 1) & 1 ? -8 : 8;
+      Sprite_MoveX(k);
+      sprite_x_vel[k] = 0;
+    }
+  } else if (sprite_ai_state[k] == 1) {
+    static const int8 kSpikeBlock_XVelTarget[4] = {32, -32, 0, 0};
+    static const int8 kSpikeBlock_YVelTarget[4] = {0, 0, 32, -32};
+    static const int8 kSpikeBlock_XVelDelta[4] = {1, -1, 0, 0};
+    static const int8 kSpikeBlock_YVelDelta[4] = {0, 0, 1, -1};
+
+    int j = sprite_D[k];
+    if (sprite_x_vel[k] != (uint8)kSpikeBlock_XVelTarget[j])
+      sprite_x_vel[k] += kSpikeBlock_XVelDelta[j];
+    if (sprite_y_vel[k] != (uint8)kSpikeBlock_YVelTarget[j])
+      sprite_y_vel[k] += kSpikeBlock_YVelDelta[j];
+    Sprite_MoveXY(k);
+    if (!sprite_delay_aux1[k]) {
+      Sprite_Get16BitCoords(k);
+      if (Sprite_CheckTileCollision(k)) {
+        sprite_ai_state[k] = 2;
+        sprite_delay_aux1[k] = 64;
+      }
+    }
+  } else if (sprite_delay_aux1[k] == 0) {
+    static const int8 kSpikeBlock_XVel[4] = {-16, 16, 0, 0};
+    static const int8 kSpikeBlock_YVel[4] = {0, 0, -16, 16};
+    int j = sprite_D[k];
+    sprite_x_vel[k] = kSpikeBlock_XVel[j];
+    sprite_y_vel[k] = kSpikeBlock_YVel[j];
+    Sprite_MoveXY(k);
+    if (sprite_x_lo[k] == sprite_A[k] && sprite_y_lo[k] == sprite_B[k]) {
+      sprite_state[k] = 0;
+      Dungeon_UpdateTileMapWithCommonTile(Sprite_GetX(k), Sprite_GetY(k), 2);
+    }
+  }
+}
+
+bool SpikeBlock_CheckStatueCollision(int k) {  // 9ebe19
+  for (int j = 15; j >= 0; j--) {
+    if (!((j ^ frame_counter) & 1) && sprite_state[j] && sprite_type[j] == 0x1c) {
+      int x0 = Sprite_GetX(k), y0 = Sprite_GetY(k);
+      int x1 = Sprite_GetX(j), y1 = Sprite_GetY(j);
+      if ((uint16)(x0 - x1 + 16) < 32 && (uint16)(y0 - y1 + 16) < 32)
+        return false;
+    }
+  }
+  return true;
+}
+
+void Sprite_88_Mothula(int k) {  // 9ebe7e
+  if (enhanced_features0 & kFeatures0_MiscBugFixes) {
+    // L4 sword and L3 spin slash can now damage Mothula
+    enemy_damage_data[0x884] = 1;
+    enemy_damage_data[0x885] = 1;
+  }
+  Mothula_Main(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  Mothula_HandleSpikes(k);
+}
+
+void Mothula_Main(int k) {  // 9ebe88
+  int j;
+  Mothula_Draw(k);
+  if (sprite_state[k] == 11)
+    sprite_ai_state[k] = 0;
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  sprite_flags3[k] = 0;
+  if (sprite_delay_aux3[k])
+    sprite_flags3[k] = 64;
+  if ((sprite_F[k] & 127) == 6) {
+    sprite_F[k] = 0;
+    sprite_delay_aux3[k] = 32;
+    sprite_ai_state[k] = 2;
+    sprite_delay_main[k] = 0;
+    sprite_G[k] = 64;
+  }
+  if (Sprite_ReturnIfRecoiling(k))
+    return;
+  switch(sprite_ai_state[k]) {
+  case 0: // Delay
+    if (!sprite_delay_main[k])
+      sprite_ai_state[k] = 1;
+    break;
+  case 1: // Ascend
+    sprite_z_vel[k] = 8;
+    Sprite_MoveZ(k);
+    sprite_z_vel[k] = 0;
+    if (sprite_z[k] >= 24) {
+      sprite_G[k] = 128;
+      sprite_ai_state[k] = 2;
+      sprite_ignore_projectile[k] = 0;
+      sprite_delay_main[k] = 64;
+    }
+    Mothula_FlapWings(k);
+    break;
+  case 2: // FlyAbout
+    if (!sprite_G[k]) {
+      sprite_delay_main[k] = 63;
+      sprite_ai_state[k] = 3;
+      return;
+    }
+    sprite_G[k]--;
+    Mothula_FlapWings(k);
+    j = sprite_A[k] & 1;
+    sprite_z_vel[k] += j ? -1 : 1;
+    if (sprite_z_vel[k] == (uint8)(j ? -16 : 16))
+      sprite_A[k]++;
+    if (!sprite_delay_main[k]) {
+      if (++sprite_C[k] == 7) {
+        sprite_C[k] = 0;
+        Sprite_ApplySpeedTowardsLink(k, 32);
+        sprite_delay_main[k] = 128;
+      } else {
+        static const int8 kMothula_XYvel[10] = {-16, -12, 0, 12, 16, 12, 0, -12, -16, -12};
+        j = GetRandomNumber() & 7;
+        sprite_x_vel[k] = kMothula_XYvel[j + 2];
+        sprite_y_vel[k] = kMothula_XYvel[j];
+        sprite_delay_main[k] = (GetRandomNumber() & 31) + 64;
+      }
+    }
+    if (!sprite_wallcoll[k])
+      Sprite_MoveXY(k);
+    Sprite_MoveZ(k);
+    if (Sprite_CheckTileCollision(k))
+      sprite_delay_main[k] = 0;
+    Sprite_CheckDamageToAndFromLink(k);
+    sprite_subtype2[k] += 2;
+    break;
+  case 3: // FireBeams
+    Sprite_CheckDamageToAndFromLink(k);
+    if (!sprite_delay_main[k]) {
+      sprite_ai_state[k]--;
+      sprite_G[k] = GetRandomNumber() & 31 | 64;
+    } else {
+      if (sprite_delay_main[k] == 0x20)
+        Mothula_SpawnBeams(k);
+      Mothula_FlapWings(k);
+    }
+    break;
+  }
+}
+
+void Mothula_FlapWings(int k) {  // 9ebf9f
+  static const uint8 kMothula_FlapWingsGfx[4] = {0, 1, 2, 1};
+  int j = ++sprite_subtype2[k] >> 2 & 3;
+  if (j == 0)
+    SpriteSfx_QueueSfx3WithPan(k, 0x2);
+  sprite_graphics[k] = kMothula_FlapWingsGfx[j];
+}
+
+void Mothula_SpawnBeams(int k) {  // 9ebfdf
+  static const int8 kMothula_Beam_Xvel[3] = {-16, 0, 16};
+  static const int8 kMothula_Beam_Yvel[3] = {24, 32, 24};
+  SpriteSfx_QueueSfx3WithPan(k, 0x36);
+  for (int i = 2; i >= 0; i--) {
+    SpriteSpawnInfo info;
+    int j = Sprite_SpawnDynamically(k, 0x89, &info);
+    if (j >= 0) {
+      Sprite_SetSpawnedCoordinates(j, &info);
+      sprite_y_lo[j] = info.r2_y - info.r4_z + 3;
+      sprite_delay_main[j] = 16;
+      sprite_ignore_projectile[j] = 16;
+      sprite_x_lo[j] = info.r0_x + kMothula_Beam_Xvel[i];
+      sprite_x_vel[j] = kMothula_Beam_Xvel[i];
+      sprite_y_vel[j] = kMothula_Beam_Yvel[i];
+      sprite_z[j] = 0;
+    }
+  }
+  tmp_counter = 0xff;
+}
+
+void Mothula_HandleSpikes(int k) {  // 9ec088
+  static const uint8 kMothula_Spike_XLo[30] = {
+    0x38, 0x48, 0x58, 0x68, 0x88, 0x98, 0xa8, 0xb8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xb8,
+    0xa8, 0x98, 0x78, 0x68, 0x58, 0x48, 0x38, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28,
+  };
+  static const uint8 kMothula_Spike_YLo[30] = {
+    0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x48, 0x58, 0x68, 0x78, 0x98, 0xa8, 0xb8, 0xc8,
+    0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xb8, 0xa8, 0x98, 0x78, 0x68, 0x58, 0x48,
+  };
+  static const uint8 kMothula_Spike_Dir[30] = {
+    2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 3,
+    3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0,
+  };
+
+  if (--sprite_head_dir[k])
+    return;
+  sprite_head_dir[k] = 0x40;
+  SpriteSpawnInfo info;
+  int j = Sprite_SpawnDynamically(k, 0x8a, &info);
+  if (j < 0)
+    return;
+  int i = GetRandomNumber() & 0x1f;
+  if (i >= 30) i -= 30;
+  sprite_A[j] = sprite_x_lo[j] = kMothula_Spike_XLo[i];
+  sprite_B[j] = sprite_y_lo[j] = kMothula_Spike_YLo[i] - 1;
+  sprite_D[j] = kMothula_Spike_Dir[i];
+  sprite_E[j] = 1;
+  sprite_x_hi[j] = byte_7E0FB0 + 1;
+  sprite_y_hi[j] = byte_7E0FB1 + 1;
+  sprite_x_vel[j] = 1;
+  Sprite_Get16BitCoords(j);
+  Sprite_CheckTileCollision(j);
+  sprite_x_vel[j] = 0;
+  sprite_x_lo[j] = sprite_A[j];
+  sprite_y_lo[j] = sprite_B[j];
+  if (!sprite_wallcoll[j]) {
+    sprite_state[j] = 0;
+    sprite_head_dir[k] = 1;
+  }
+}
+
+void Sprite_86_Kodongo(int k) {  // 9ec103
+  static const int8 kKodondo_Xvel[4] = {1, -1, 0, 0};
+  static const int8 kKodondo_Yvel[4] = {0, 0, 1, -1};
+  static const uint8 kKodondo_Gfx[8] = {2, 2, 0, 5, 3, 3, 0, 5};
+  static const uint8 kKodondo_OamFlags[8] = {0x40, 0, 0, 0, 0x40, 0, 0x40, 0x40};
+  static const uint8 kKodondo_FlameGfx[8] = {2, 2, 0, 5, 4, 4, 1, 6};
+  int j;
+  SpriteDraw_SingleLarge(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  if (Sprite_ReturnIfRecoiling(k))
+    return;
+  Sprite_CheckDamageToAndFromLink(k);
+  sprite_flags[k] = 0;
+  switch(sprite_ai_state[k]) {
+  case 0:  // choose dir
+    sprite_ai_state[k]++;
+    sprite_D[k] = GetRandomNumber() & 3;
+    sprite_flags[k] = 176;
+    for(;;) {
+      j = sprite_D[k];
+      sprite_x_vel[k] = kKodondo_Xvel[j];
+      sprite_y_vel[k] = kKodondo_Yvel[j];
+      if (!Sprite_CheckTileCollision(k))
+        break;
+      sprite_D[k] = (sprite_D[k] + 1) & 3;
+    }
+    Kodongo_SetDirection(k);
+    break;
+  case 1:  // move
+    Sprite_MoveXY(k);
+    if (Sprite_CheckTileCollision(k)) {
+      sprite_D[k] ^= 1;
+      Kodongo_SetDirection(k);
+    }
+    if ((sprite_x_lo[k] & 0x1f) == 4 && (sprite_y_lo[k] & 0x1f) == 0x1b && (GetRandomNumber() & 3) == 0) {
+      sprite_delay_main[k] = 111;
+      sprite_ai_state[k] = 2;
+      sprite_A[k] = 0;
+    }
+    j = ++sprite_subtype2[k] & 4 | sprite_D[k];
+    sprite_graphics[k] = kKodondo_Gfx[j];
+    sprite_oam_flags[k] = sprite_oam_flags[k] & ~0x40 | kKodondo_OamFlags[j];
+    break;
+  case 2:  // breathe flame
+    if (!sprite_delay_main[k])
+      sprite_ai_state[k] = 0;
+    j = (uint8)(sprite_delay_main[k] - 0x20) < 0x30;
+    if (j && (sprite_delay_main[k] & 0xf) == 0)
+      Kodongo_SpawnFire(k);
+    sprite_graphics[k] = kKodondo_FlameGfx[j * 4 + sprite_D[k]];
+    break;
+  }
+}
+
+void Kodongo_SetDirection(int k) {  // 9ec158
+  int j = sprite_D[k];
+  sprite_x_vel[k] = kFluteBoyAnimal_Xvel[j];
+  sprite_y_vel[k] = kZazak_Yvel[j];
+}
+
+void Kodongo_SpawnFire(int k) {  // 9ec223
+  static const int8 kKodondo_Flame_X[4] = {8, -8, 0, 0};
+  static const int8 kKodondo_Flame_Y[4] = {0, 0, 8, -8};
+  static const int8 kKodondo_Flame_Xvel[4] = {24, -24, 0, 0};
+  static const int8 kKodondo_Flame_Yvel[4] = {0, 0, 24, -24};
+  SpriteSpawnInfo info;
+  int j = Sprite_SpawnDynamicallyEx(k, 0x87, &info, 13);
+  if (j >= 0) {
+    int i = sprite_D[k];
+    Sprite_SetX(j, info.r0_x + kKodondo_Flame_X[i]);
+    Sprite_SetY(j, info.r2_y + kKodondo_Flame_Y[i]);
+    sprite_x_vel[j] = kKodondo_Flame_Xvel[i];
+    sprite_y_vel[j] = kKodondo_Flame_Yvel[i];
+    sprite_ignore_projectile[j] = 1;
+  }
+}
+
+void Sprite_87_KodongoFire(int k) {  // 9ec274
+  static const uint8 kFlame_OamFlags[4] = { 0, 0x40, 0xc0, 0x80 };
+  static const int8 kFlame_Gfx[32] = {
+    5, 4, 3, 1, 2, 0, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0,
+    1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0,
+  };
+
+  if (!sprite_delay_main[k]) {
+    SpriteDraw_SingleLarge(k);
+    if (Sprite_ReturnIfInactive(k))
+      return;
+    sprite_oam_flags[k] = sprite_oam_flags[k] & 0x3f | kFlame_OamFlags[frame_counter >> 2 & 3];
+    if (!Sprite_CheckDamageToLink(k)) {
+      Sprite_MoveXY(k);
+      if (!Sprite_CheckTileCollision(k))
+        return;
+    }
+    sprite_delay_main[k] = 127;
+    sprite_oam_flags[k] &= 63;
+    SpriteSfx_QueueSfx2WithPan(k, 0x2a);
+  } else {
+    if (Sprite_CheckDamageFromLink(k) & kCheckDamageFromPlayer_Carry && !--sprite_delay_main[k] || sprite_delay_main[k] == 1)
+      sprite_state[k] = 0;
+    sprite_graphics[k] = kFlame_Gfx[sprite_delay_main[k] >> 3];
+    Flame_Draw(k);
+    Sprite_CheckDamageToLink(k);
+  }
+}
+
+void Flame_Draw(int k) {  // 9ec35c
+  static const DrawMultipleData kFlame_Dmd[12] = {
+    {0,  0, 0x018e, 2},
+    {0,  0, 0x018e, 2},
+    {0,  0, 0x01a0, 2},
+    {0,  0, 0x01a0, 2},
+    {0,  0, 0x418e, 2},
+    {0, 0, 0x418e, 2},
+    { 0,  0, 0x41a0, 2 },
+    { 0,  0, 0x41a0, 2 },
+    { 0,  0, 0x01a2, 2 },
+    { 0,  0, 0x01a2, 2 },
+    { 0, -6, 0x01a4, 0 },
+    { 8, -6, 0x01a5, 0 },
+  };
+  Sprite_DrawMultiple(k, &kFlame_Dmd[sprite_graphics[k] * 2], 2, NULL);
+}
+
+void Sprite_85_YellowStalfos(int k) {  // 9ec37f
+  static const int8 kYellowStalfos_ObjPrio[6] = {0x30, 0, 0, 0, 0x30, 0};
+  static const int8 kYellowStalfos_Gfx[32] = {
+    8, 5, 1, 1, 8, 5, 1, 1, 8, 5, 1, 1, 7, 4, 2, 2,
+    7, 4, 2, 2, 7, 4, 2, 2, 7, 4, 2, 2, 7, 4, 2, 2,
+  };
+  static const int8 kYellowStalfos_HeadX[32] = {
+    -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, -0x80, 0, 0, 0, 0,
+    0,     0,     0,     0,    -1,     0,     1,     0,    -1,     0,     1,     0, 0, 0, 0, 0,
+  };
+  static const uint8 kYellowStalfos_HeadY[32] = {
+    13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+    13, 12, 11, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+  };
+  static const int8 kYellowStalfos_NeutralizedGfx[16] = {1, 1, 1, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 9};
+  static const int8 kYellowStalfos_NeutralizedHeadY[16] = {10, 10, 10, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7};
+  int j;
+
+  if (!sprite_A[k]) {
+    sprite_x_vel[k] = 1;
+    sprite_y_vel[k] = 1;
+    if (Sprite_CheckTileCollision(k)) {
+      sprite_state[k] = 0;
+      return;
+    }
+    sprite_A[k]++;
+    sprite_C[k] = 10;
+    sprite_flags3[k] |= 64;
+    SpriteSfx_QueueSfx2WithPan(k, 0x20);
+  }
+
+  sprite_obj_prio[k] |= kYellowStalfos_ObjPrio[sprite_ai_state[k]];
+  YellowStalfos_Draw(k);  
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  if (link_sword_type >= 3) {
+    if (Sprite_ReturnIfRecoiling(k))
+      return;
+  } else if (sprite_ai_state[k] != 5 && sprite_hit_timer[k]) {
+    sprite_hit_timer[k] = 0;
+    sprite_ai_state[k] = 5;
+    sprite_delay_main[k] = 255;
+  }
+  sprite_ignore_projectile[k] = 1;
+  switch (sprite_ai_state[k]) {
+  case 0: { // descend
+    sprite_head_dir[k] = 2;
+    uint8 bak0 = sprite_z[k];
+    Sprite_MoveZ(k);
+    if (!sign8(sprite_z_vel[k] - 192))
+      sprite_z_vel[k] -= 3;
+    if (!sign8(bak0) && sign8(sprite_z[k])) {
+      sprite_ai_state[k]++;
+      sprite_z[k] = 0;
+      sprite_z_vel[k] = 0;
+      sprite_delay_main[k] = 64;
+      YellowStalfos_Animate(k);
+    }
+    break;
+  }
+  case 1:  // face player
+    sprite_ignore_projectile[k] = 0;
+    Sprite_CheckDamageToAndFromLink(k);
+    sprite_head_dir[k] = sprite_D[k] = Sprite_DirectionToFaceLink(k, NULL);
+    if (!sprite_delay_main[k]) {
+      sprite_ai_state[k]++;
+      sprite_delay_main[k] = 127;
+    }
+    sprite_flags3[k] &= ~0x40;
+    break;
+  case 2:  // pause then detach head
+    sprite_ignore_projectile[k] = 0;
+    Sprite_CheckDamageToAndFromLink(k);
+    j = sprite_delay_main[k];
+    if (!j) {
+      sprite_ai_state[k]++;
+      sprite_delay_main[k] = 64;
+      return;
+    }
+    if (j == 48)
+      YellowStalfos_EmancipateHead(k);
+    sprite_graphics[k] = kYellowStalfos_Gfx[j >> 2 & ~3 | sprite_D[k]];
+    j = sprite_delay_main[k] >> 2;
+    sprite_B[k] = kYellowStalfos_HeadX[j];
+    sprite_C[k] = kYellowStalfos_HeadY[j];
+    sprite_flags3[k] &= ~0x40;
+    break;
+  case 3:  // delay before ascending
+    sprite_ignore_projectile[k] = 0;
+    Sprite_CheckDamageToAndFromLink(k);
+    if (!sprite_delay_main[k])
+      sprite_ai_state[k]++;
+    YellowStalfos_Animate(k);
+    break;
+  case 4:  // ascend
+    sprite_graphics[k] = 0;
+    sprite_head_dir[k] = 2;
+    j = sprite_z[k];
+    Sprite_MoveZ(k);
+    if (sign8(sprite_z_vel[k] - 64))
+      sprite_z_vel[k] += 2;
+    if (sign8(j) && !sign8(sprite_z[k]))
+      sprite_state[k] = 0;
+    break;
+  case 5:  // neutralized
+    sprite_ignore_projectile[k] = 0;
+    Sprite_CheckDamageFromLink(k);
+    j = sprite_delay_main[k];
+    if (!j)
+      sprite_ai_state[k]--;
+    sprite_graphics[k] = kYellowStalfos_NeutralizedGfx[j >> 4];
+    sprite_C[k] = kYellowStalfos_NeutralizedHeadY[j >> 4];
+    break;
+  }
+}
+
+void YellowStalfos_Animate(int k) {  // 9ec509
+  static const uint8 kYellowStalfos_Gfx2[4] = {6, 3, 1, 1};
+  sprite_graphics[k] = kYellowStalfos_Gfx2[sprite_D[k]];
+  sprite_flags3[k] &= ~0x40;
+}
+
+void YellowStalfos_EmancipateHead(int k) {  // 9ec580
+  SpriteSpawnInfo info;
+  int j = Sprite_SpawnDynamically(k, 2, &info);
+  if (j >= 0) {
+    Sprite_SetSpawnedCoordinates(j, &info);
+    sprite_z[j] = 13;
+    Sprite_ApplySpeedTowardsLink(j, 16);
+    sprite_delay_main[j] = 255;
+    sprite_delay_aux1[j] = 32;
+  }
+}
+
+void YellowStalfos_Draw(int k) {  // 9ec655
+  static const DrawMultipleData kYellowStalfos_Dmd[22] = {
+    {0, 0, 0x000a, 2},
+    {0, 0, 0x000a, 2},
+    {0, 0, 0x000c, 2},
+    {0, 0, 0x000c, 2},
+    {0, 0, 0x002c, 2},
+    {0, 0, 0x002c, 2},
+    {5, 5, 0x002e, 0},
+    {0, 0, 0x0024, 2},
+    {4, 1, 0x003e, 0},
+    {0, 0, 0x0024, 2},
+    {0, 0, 0x000e, 2},
+    {0, 0, 0x000e, 2},
+    {3, 5, 0x402e, 0},
+    {0, 0, 0x4024, 2},
+    {4, 1, 0x403e, 0},
+    {0, 0, 0x4024, 2},
+    {0, 0, 0x400e, 2},
+    {0, 0, 0x400e, 2},
+    {0, 0, 0x002a, 2},
+    {0, 0, 0x002a, 2},
+    {0, 0, 0x002a, 2},
+    {0, 0, 0x002a, 2},
+  };
+  oam_cur_ptr += 4, oam_ext_cur_ptr++;
+  PrepOamCoordsRet info;
+  Sprite_DrawMultiple(k, &kYellowStalfos_Dmd[sprite_graphics[k] * 2], 2, &info);
+  oam_cur_ptr -= 4, oam_ext_cur_ptr--;
+  if (!sprite_pause[k]) {
+    YellowStalfos_DrawHead(k, &info);
+    SpriteDraw_Shadow(k, &info);
+  }
+}
+
+void YellowStalfos_DrawHead(int k, PrepOamCoordsRet *info) {  // 9ec69a
+  static const uint8 kYellowStalfos_Head_Char[4] = {2, 2, 0, 4};
+  static const uint8 kYellowStalfos_Head_Flags[4] = {0x40, 0, 0, 0};
+  OamEnt *oam = GetOamCurPtr();
+  if (sprite_graphics[k] == 10 || sprite_B[k] == 0x80)
+    return;
+  int j = sprite_head_dir[k];
+  SetOamHelper0(oam, info->x + (int8)sprite_B[k], info->y - sprite_C[k],
+                kYellowStalfos_Head_Char[j],
+                kYellowStalfos_Head_Flags[j] | info->flags, 2);
+}
+
+void SpritePrep_Eyegore(int k) {  // 9ec700
+  uint8 t = BYTE(dungeon_room_index2);
+  if (t == 12 || t == 27 || t == 75 || t == 107) {
+    sprite_B[k]++;
+    if (sprite_type[k] == 0x83)
+      sprite_defl_bits[k] = 0;
+  }
+}
+
+void Sprite_83_GreenEyegore(int k) {  // 9ec79b
+  static const int8 kGoriya_Xvel[32] = {
+    0,  16, -16, 0, 0,  13, -13, 0, 0,  13, -13, 0, 0, 0, 0, 0,
+    0, -24,  24, 0, 0, -16,  16, 0, 0, -16,  16, 0, 0, 0, 0, 0,
+  };
+  static const int8 kGoriya_Yvel[32] = {
+    0, 0, 0, 0, -16,  -5,  -5, 0, 16, 13, 13, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, -24, -16, -16, 0, 24, 16, 16, 0, 0, 0, 0, 0,
+  };
+  static const uint8 kGoriya_Dir[32] = {
+    0, 0, 1, 0, 3, 3, 3, 0, 2, 2, 2, 0, 0, 0, 0, 0,
+    0, 1, 0, 0, 3, 3, 3, 0, 2, 2, 2, 0, 0, 0, 0, 0,
+  };
+  static const uint8 kGoriya_Gfx[16] = {8, 6, 0, 3, 9, 7, 1, 4, 8, 6, 0, 3, 9, 7, 2, 5};
+
+  if (!sprite_B[k]) {
+    Eyegore_Main(k);
+    return;
+  }
+  Goriya_Draw(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  if (Sprite_ReturnIfRecoiling(k))
+    return;
+  if (sprite_delay_aux1[k] == 8)
+    Sprite_SpawnFirePhlegm(k);
+  if (bitmask_of_dragstate != 0 || !(joypad1H_last & 0xf)) {
+    sprite_A[k] = 0;
+    Sprite_CheckDamageToAndFromLink(k);
+    Sprite_CheckTileCollision(k);
+    return;
+  }
+
+  int j = (joypad1H_last & 0xf) | (sprite_type[k] == 0x84) * 16;
+  sprite_D[k] = kGoriya_Dir[j];
+  sprite_x_vel[k] = kGoriya_Xvel[j];
+  sprite_y_vel[k] = kGoriya_Yvel[j];
+  if (!sprite_wallcoll[k])
+    Sprite_MoveXY(k);
+  Sprite_CheckDamageToAndFromLink(k);
+  Sprite_CheckTileCollision(k);
+  sprite_graphics[k] = kGoriya_Gfx[++sprite_subtype2[k] & 12 | sprite_D[k]];
+  if (sprite_type[k] == 0x84) {
+    PointU8 pt;
+    uint8 dir = Sprite_DirectionToFaceLink(k, &pt);
+    if (((uint8)(pt.x + 8) < 16 || (uint8)(pt.y + 8) < 16) && sprite_D[k] == dir) {
+      if (!(sprite_A[k] & 0x1f))
+        sprite_delay_aux1[k] = 16;
+      sprite_A[k]++;
+      return;
+    }
+  }
+  sprite_A[k] = 0;
+}
+
+void Eyegore_Main(int k) {  // 9ec839
+  static const uint8 kEyeGore_Closing_Gfx[8] = {0, 0, 1, 1, 2, 2, 2, 2};
+  static const uint8 kEyeGore_Opening_Gfx[8] = {2, 2, 2, 2, 1, 1, 0, 0};
+  static const uint8 kEyeGore_Chasing_Gfx[16] = {7, 5, 2, 9, 8, 6, 3, 10, 7, 5, 2, 9, 8, 6, 4, 11};
+  static const uint8 kEyeGore_Opening_Delay[4] = {0x60, 0x80, 0xa0, 0x80};
+  Eyegore_Draw(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  if (Sprite_ReturnIfRecoiling(k))
+    return;
+  Sprite_CheckDamageToAndFromLink(k);
+  sprite_flags3[k] |= 64;
+  sprite_defl_bits[k] |= 4;
+  switch (sprite_ai_state[k]) {
+  case 0:  // wait until player
+    if (!sprite_delay_main[k]) {
+      PointU8 pt;
+      Sprite_DirectionToFaceLink(k, &pt);
+      if ((uint8)(pt.x + 48) < 96 &&
+          (uint8)(pt.y + 48) < 96) {
+        sprite_ai_state[k]++;
+        sprite_delay_main[k] = 63;
+      }
+    }
+    break;
+  case 1:  // openig eye
+    if (!sprite_delay_main[k]) {
+      sprite_D[k] = Sprite_DirectionToFaceLink(k, NULL);
+      sprite_ai_state[k] = 2;
+      sprite_delay_main[k] = kEyeGore_Opening_Delay[GetRandomNumber() & 3];
+    } else {
+      sprite_graphics[k] = kEyeGore_Opening_Gfx[sprite_delay_main[k] >> 3];
+    }
+    break;
+  case 2:  // chase player
+    sprite_flags3[k] &= ~0x40;
+    if (sprite_type[k] != 0x84)
+      sprite_defl_bits[k] &= ~4;
+    if (!sprite_delay_main[k]) {
+      sprite_delay_main[k] = 63;
+      sprite_ai_state[k]++;
+      sprite_graphics[k] = 0;
+    } else {
+      if (!((k ^ frame_counter) & 31))
+        sprite_D[k] = Sprite_DirectionToFaceLink(k, NULL);
+      int j = sprite_D[k];
+      sprite_x_vel[k] = kFluteBoyAnimal_Xvel[j];
+      sprite_y_vel[k] = kZazak_Yvel[j];
+      if (!sprite_wallcoll[k])
+        Sprite_MoveXY(k);
+      Sprite_CheckTileCollision(k);
+      sprite_graphics[k] = kEyeGore_Chasing_Gfx[++sprite_subtype2[k] & 12 | sprite_D[k]];
+    }
+    break;
+  case 3:  // closing eye
+    if (!sprite_delay_main[k]) {
+      sprite_ai_state[k] = 0;
+      sprite_delay_main[k] = 96;
+    } else {
+      sprite_graphics[k] = kEyeGore_Closing_Gfx[sprite_delay_main[k] >> 3];
+    }
+    break;
+  }
+}
+
+void Eyegore_Draw(int k) {  // 9ecacf
+  static const DrawMultipleData kEyeGore_Dmd[48] = {
+    {-4, -4, 0x00a2, 2},
+    { 4, -4, 0x40a2, 2},
+    {-4,  4, 0x009c, 2},
+    { 4,  4, 0x409c, 2},
+    {-4, -4, 0x00a4, 2},
+    { 4, -4, 0x40a4, 2},
+    {-4,  4, 0x009c, 2},
+    { 4,  4, 0x409c, 2},
+    {-4, -4, 0x008c, 2},
+    { 4, -4, 0x408c, 2},
+    {-4,  4, 0x009c, 2},
+    { 4,  4, 0x409c, 2},
+    {-4, -3, 0x008c, 2},
+    {12, -3, 0x408c, 0},
+    {-4, 13, 0x00bc, 0},
+    { 4,  5, 0x408a, 2},
+    {-4, -3, 0x008c, 0},
+    { 4, -3, 0x408c, 2},
+    {-4,  5, 0x008a, 2},
+    {12, 13, 0x40bc, 0},
+    { 0, -4, 0x00aa, 2},
+    { 0,  4, 0x00a6, 2},
+    { 0, -4, 0x00aa, 2},
+    { 0,  4, 0x00a6, 2},
+    { 0, -3, 0x00aa, 2},
+    { 0,  4, 0x00a8, 2},
+    { 0, -3, 0x00aa, 2},
+    { 0,  4, 0x00a8, 2},
+    { 0, -4, 0x40aa, 2},
+    { 0,  4, 0x40a6, 2},
+    { 0, -4, 0x40aa, 2},
+    { 0,  4, 0x40a6, 2},
+    { 0, -3, 0x40aa, 2},
+    { 0,  4, 0x40a8, 2},
+    { 0, -3, 0x40aa, 2},
+    { 0,  4, 0x40a8, 2},
+    {-4, -4, 0x008e, 2},
+    { 4, -4, 0x408e, 2},
+    {-4,  4, 0x009e, 2},
+    { 4,  4, 0x409e, 2},
+    {-4, -3, 0x008e, 2},
+    {12, -3, 0x408e, 0},
+    {-4, 13, 0x00bd, 0},
+    { 4,  5, 0x40a0, 2},
+    {-4, -3, 0x008e, 0},
+    { 4, -3, 0x408e, 2},
+    {-4,  5, 0x00a0, 2},
+    {12, 13, 0x40bd, 0},
+  };
+  PrepOamCoordsRet info;
+  Sprite_DrawMultiple(k, &kEyeGore_Dmd[sprite_graphics[k] * 4], 4, &info);
+  if (!sprite_pause[k])
+    SpriteDraw_Shadow_custom(k, &info, 14);
+}
+
+void SpritePrep_AntifairyCircle(int k) {  // 9ecb0c
+  static const int8 kBubbleGroup_X[3] = {10, 20, 10};
+  static const int8 kBubbleGroup_Y[3] = {-10, 0, 10};
+  static const int8 kBubbleGroup_Xvel[3] = {18, 0, -18};
+  static const int8 kBubbleGroup_Yvel[3] = {0, 18, 0};
+  static const int8 kBubbleGroup_A[3] = {1, 1, 0};
+  static const int8 kBubbleGroup_B[3] = { 0, 1, 1 };
+  Sprite_SetX(k, Sprite_GetX(k) - 10);
+  sprite_y_vel[k] = -18;
+  sprite_x_vel[k] = 0;
+  sprite_A[k] = 0;
+  sprite_B[k] = 0;
+  tmp_counter = 2;
+  do {
+    SpriteSpawnInfo info;
+    int j = Sprite_SpawnDynamically(k, 0x82, &info);
+    if (j >= 0) {
+      int i = tmp_counter;
+      Sprite_SetX(j, info.r0_x + kBubbleGroup_X[i]);
+      Sprite_SetY(j, info.r2_y + kBubbleGroup_Y[i]);
+      sprite_x_vel[j] = kBubbleGroup_Xvel[i];
+      sprite_y_vel[j] = kBubbleGroup_Yvel[i];
+      sprite_A[j] = kBubbleGroup_A[i];
+      sprite_B[j] = kBubbleGroup_B[i];
+    }
+  } while (!sign8(--tmp_counter));
+}
+
+void Sprite_82_AntifairyCircle(int k) {  // 9ecb97
+  static const int8 kBubbleGroup_Vel[2] = {1, -1};
+  static const uint8 kBubbleGroup_VelTarget[2] = {18, (uint8)-18};
+
+  SpriteDraw_Antfairy(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  int j = sprite_A[k] & 1;
+  if ((sprite_x_vel[k] += kBubbleGroup_Vel[j]) == kBubbleGroup_VelTarget[j])
+    sprite_A[k]++;
+
+  j = sprite_B[k] & 1;
+  if ((sprite_y_vel[k] += kBubbleGroup_Vel[j]) == kBubbleGroup_VelTarget[j])
+    sprite_B[k]++;
+
+  Sprite_MoveXY(k);
+  if (sprite_x_vel[k] && sprite_y_vel[k] && Sprite_CheckIfRoomIsClear()) {
+    sprite_type[k] = 0x15;
+    sprite_x_vel[k] = sign8(sprite_x_vel[k]) ? -16 : 16;
+    sprite_y_vel[k] = sign8(sprite_y_vel[k]) ? -16 : 16;
+  }
+  Sprite_CheckDamageToLink(k);
+}
+
+void Sprite_81_Hover(int k) {  // 9ecc02
+  static const int8 kHover_OamFlags[4] = {0x40, 0, 0x40, 0};
+  sprite_obj_prio[k] |= 48;
+  SpriteDraw_SingleLarge(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  if (sprite_F[k])
+    sprite_ai_state[k] = 0;
+  if (Sprite_ReturnIfRecoiling(k))
+    return;
+  Sprite_CheckDamageToAndFromLink(k);
+  if (!sprite_wallcoll[k])
+    Sprite_MoveXY(k);
+  Sprite_CheckTileCollision(k);
+  sprite_graphics[k] = ++sprite_subtype2[k] >> 3 & 2;
+  switch(sprite_ai_state[k]) {
+  case 0:  // stopped
+    if (!sprite_delay_main[k]) {
+      sprite_ai_state[k] = 1;
+      int j = Sprite_IsRightOfLink(k).a + Sprite_IsBelowLink(k).a * 2;
+      sprite_D[k] = j;
+      sprite_oam_flags[k] = sprite_oam_flags[k] & ~0x40 | kHover_OamFlags[j];
+      sprite_delay_main[k] = (GetRandomNumber() & 15) + 12;
+      Sprite_ZeroVelocity_XY(k);
+    }
+    break;
+  case 1: {  // moving
+    static const int8 kHover_AccelX0[4] = {1, -1, 1, -1};
+    static const int8 kHover_AccelY0[4] = {1, 1, -1, -1};
+    static const int8 kHover_AccelX1[4] = {-1, 1, -1, 1};
+    static const int8 kHover_AccelY1[4] = {-1, -1, 1, 1};
+    int j = sprite_D[k];
+    if (sprite_delay_main[k]) {
+      sprite_x_vel[k] += kHover_AccelX0[j];
+      sprite_y_vel[k] += kHover_AccelY0[j];
+      sprite_graphics[k] = sprite_subtype2[k] >> 3 & 1;
+    } else {
+      sprite_x_vel[k] += kHover_AccelX1[j];
+      sprite_y_vel[k] += kHover_AccelY1[j];
+      if (!sprite_y_vel[k]) {
+        sprite_ai_state[k] = 0;
+        sprite_delay_main[k] = 64;
+      }
+    }
+    break;
+  }
+  }
+}
+
+void Sprite_AB_CrystalMaiden(int k) {  // 9ece03
+  cur_sprite_x -= dung_floor_x_offs;
+  cur_sprite_y -= dung_floor_y_offs;
+
+  if (sprite_ai_state[k] >= 3)
+    CrystalMaiden_Draw(k);
+  is_nmi_thread_active = 1;
+  if (!BYTE(intro_did_run_step)) {
+    CrystalMaiden_RunCutscene(k);
+    BYTE(intro_did_run_step) = 1;
+  }
+}
+
+void CrystalMaiden_RunCutscene(int k) {  // 9ece39
+  sprite_E[k]++;
+  poly_b += 6;
+  if (submodule_index)
+    return;
+  switch (sprite_ai_state[k]) {
+  case 0:  // disable subscreen
+    TS_copy = 0;
+    sprite_ai_state[k]++;
+    break;
+  case 1:  // enable subscreen
+    TS_copy = 1;
+    sprite_ai_state[k]++;
+    break;
+  case 2:  // generate sparkles
+    if (poly_config1 < 6) {
+      poly_config1 = 0;
+      sprite_ai_state[k]++;
+    } else {
+      poly_config1 -= 3;
+      if (poly_config1 >= 64)
+        AncillaAdd_SwordChargeSparkle(sprite_A[k]);
+    }
+    break;
+  case 3:  // filter palette
+    sprite_ai_state[k]++;
+  case 4:
+    if (!(sprite_E[k] & 1)) {
+      PaletteFilter_SP5F();
+      if (!BYTE(palette_filter_countdown)) {
+        sprite_ai_state[k]++;
+        flag_is_link_immobilized = 1;
+        link_receiveitem_index = 0;
+        link_pose_for_item = 0;
+        link_animation_steps = 0;
+        link_direction_facing = 0;
+      }
+    }
+    break;
+  case 5: { // show message
+    static const uint16 kCrystalMaiden_Msgs[9] = {0x133, 0x132, 0x137, 0x134, 0x136, 0x132, 0x135, 0x138, 0x13c};
+    int j = BYTE(cur_palace_index_x2) - 10;
+    if (j == 2 && savegame_map_icons_indicator < 7)
+      savegame_map_icons_indicator = 7;
+    if (j == 14 && (link_has_crystals & 0x7f) != 0x7f)
+      j = 16;
+    Sprite_ShowMessageUnconditional(kCrystalMaiden_Msgs[j >> 1]);
+    sprite_ai_state[k]++;
+    if ((link_has_crystals & 0x7f) == 0x7f)
+      savegame_map_icons_indicator = 8;
+    break;
+  }
+  case 6:  // reading comprehension exam
+    Sprite_ShowMessageUnconditional(0x13a);
+    sprite_ai_state[k]++;
+    break;
+  case 7:  // may the way of the hero
+    if (choice_in_multiselect_box) {
+      sprite_ai_state[k] = 5;
+    } else {
+      Sprite_ShowMessageUnconditional(0x139);
+      sprite_ai_state[k]++;
+    }
+    break;
+  case 8:  // initiate dungeon exit
+    TS_copy = 0;
+    PrepareDungeonExitFromBossFight();
+    sprite_state[k] = 0;
+    break;
+  }
+}
+
+void Sprite_7D_BigSpike(int k) {  // 9ecf47
+  static const int8 kSpikeTrap_Xvel[4] = {32, -32, 0, 0};
+  static const int8 kSpikeTrap_Xvel2[4] = {-16, 16, 0, 0};
+  static const int8 kSpikeTrap_Yvel[4] = {0, 0, 32, -32};
+  static const int8 kSpikeTrap_Yvel2[4] = {0, 0, -16, 16};
+  static const uint8 kSpikeTrap_Delay[4] = {0x40, 0x40, 0x38, 0x38};
+  int j;
+
+  SpikeTrap_Draw(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  Sprite_CheckDamageToAndFromLink(k);
+  if (sprite_ai_state[k] == 0) {
+    PointU8 pt;
+    sprite_D[k] = j = Sprite_DirectionToFaceLink(k, &pt);
+    if ((uint8)(pt.x + 16) < 32 || (uint8)(pt.y + 16) < 32) {
+      sprite_delay_main[k] = kSpikeTrap_Delay[j];
+      sprite_ai_state[k] = 1;
+      sprite_x_vel[k] = kSpikeTrap_Xvel[j];
+      sprite_y_vel[k] = kSpikeTrap_Yvel[j];
+    }
+  } else if (sprite_ai_state[k] == 1) {
+    if (Sprite_CheckTileCollision(k) || !sprite_delay_main[k]) {
+      sprite_ai_state[k] = 2;
+      sprite_delay_main[k] = 96;
+    }
+    Sprite_MoveXY(k);
+  } else {
+    if (!sprite_delay_main[k]) {
+      j = sprite_D[k];
+      sprite_x_vel[k] = kSpikeTrap_Xvel2[j];
+      sprite_y_vel[k] = kSpikeTrap_Yvel2[j];
+      Sprite_MoveXY(k);
+      if (sprite_x_lo[k] == sprite_A[k] && sprite_y_lo[k] == sprite_C[k])
+        sprite_ai_state[k] = 0;
+    }
+  }
+}
+
+void SpikeTrap_Draw(int k) {  // 9ecfff
+  static const DrawMultipleData kSpikeTrap_Dmd[4] = {
+    {-8, -8, 0x00c4, 2},
+    { 8, -8, 0x40c4, 2},
+    {-8,  8, 0x80c4, 2},
+    { 8,  8, 0xc0c4, 2},
+  };
+  Sprite_DrawMultiple(k, kSpikeTrap_Dmd, 4, NULL);
+}
+
+void Sprite_7E_Firebar_Clockwise(int k) {  // 9ed01a
+  static const int8 kGuruguruBar_incr[4] = {-2, 2, -1, 1};
+  Firebar_Main(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  sprite_subtype2[k]++;
+  int j = (sprite_type[k] - 0x7e) + (BYTE(cur_palace_index_x2) == 18) * 2;
+
+  int t = sprite_A[k] | sprite_B[k] << 8;
+  t = (t + kGuruguruBar_incr[j]) & 0x1ff;
+  sprite_A[k] = t;
+  sprite_B[k] = t >> 8;
+}
+
+void Firebar_Main(int k) {  // 9ed049
+  PrepOamCoordsRet info;
+  if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
+    return;
+  OamEnt *oam = GetOamCurPtr();
+  byte_7E0FB6 = info.flags;
+  BYTE(dungmap_var7) = info.x;
+  HIBYTE(dungmap_var7) = info.y;
+  int angle = sprite_A[k] | sprite_B[k] << 8;
+  int8 sinval = GuruguruBarSin(angle, 0x40);
+  int8 cosval = GuruguruBarSin((angle + 0x80) & 0x1ff, 0x40);
+  uint8 flags = (sprite_subtype2[k] << 4 & 0xc0) | info.flags;
+  for (int i = 3; i >= 0; i--, oam++) {
+    SetOamPlain(oam, info.x + sinval * (i + 1) / 4, info.y + cosval * (i + 1) / 4, 0x28, flags, 2);
+  }
+  Sprite_CorrectOamEntries(k, 3, 0xff);
+  if (!((k ^ frame_counter) & 3 | submodule_index | flag_unk1)) {
+    OamEnt *oam = GetOamCurPtr();
+    for (int i = 0; i < 4; i++, oam++) {
+      if (bytewise_extended_oam[oam - oam_buf] & 1)
+        continue;
+      if ((uint8)(oam->x + BG2HOFS_copy2 - link_x_coord + 12) < 24 &&
+          oam->y < 0xf0 &&
+          (uint8)(oam->y + BG2VOFS_copy2 - link_y_coord + 4) < 16)
+        Sprite_AttemptDamageToLinkPlusRecoil(k);
+    }
+  }
+}
+
+void Sprite_80_Firesnake(int k) {  // 9ed1d1
+  static const uint8 kWinder_OamFlags[4] = {0, 0x40, 0x80, 0xc0};
+  static const int8 kWinder_Xvel[4] = {24, -24, 0, 0};
+  static const int8 kWinder_Yvel[4] = {0, 0, 24, -24};
+  SpriteDraw_SingleLarge(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  if (Sprite_ReturnIfRecoiling(k))
+    return;
+  sprite_oam_flags[k] = sprite_oam_flags[k] & 0x3f | kWinder_OamFlags[frame_counter >> 2 & 3];
+  if (sprite_A[k]) {
+    sprite_ignore_projectile[k] = sprite_delay_main[k];
+    if (sprite_delay_main[k] == 0)
+      sprite_state[k] = 0;
+    return;
+  }
+  Sprite_CheckDamageToAndFromLink(k);
+  Firesnake_SpawnFireball(k);
+  if (!sprite_wallcoll[k])
+    Sprite_MoveXY(k);
+  if (Sprite_CheckTileCollision(k))
+    sprite_D[k] = kZazak_Dir2[sprite_D[k] * 2 + (GetRandomNumber() & 1)];
+  int j = sprite_D[k];
+  sprite_x_vel[k] = kWinder_Xvel[j];
+  sprite_y_vel[k] = kWinder_Yvel[j];
+}
+
+void Firesnake_SpawnFireball(int j) {  // 9ed239
+  if ((j ^ frame_counter) & 7)
+    return;
+  int k = GarnishAlloc();
+  garnish_type[k] = 1;
+  garnish_active = 1;
+  garnish_x_lo[k] = sprite_x_lo[j];
+  garnish_x_hi[k] = sprite_x_hi[j];
+  int y = Sprite_GetY(j) + 16;
+  garnish_y_lo[k] = y;
+  garnish_y_hi[k] = y >> 8;
+  garnish_countdown[k] = 32;
+  garnish_sprite[k] = j;
+  garnish_floor[k] = sprite_floor[j];
+}
+
+void Sprite_7C_GreenStalfos(int k) {  // 9ed299
+  static const uint8 kGreenStalfos_Dir[4] = {4, 6, 0, 2};
+  static const uint8 kGreenStalfos_OamFlags[4] = {0x40, 0, 0, 0};
+  static const uint8 kGreenStalfos_Gfx[4] = {0, 0, 1, 2};
+  int j = sprite_D[k];
+  sprite_oam_flags[k] = sprite_oam_flags[k] & ~0x40 | kGreenStalfos_OamFlags[j];
+  sprite_graphics[k] = kGreenStalfos_Gfx[j];
+  SpriteDraw_SingleLarge(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  if (Sprite_ReturnIfRecoiling(k))
+    return;
+  Sprite_CheckDamageToAndFromLink(k);
+  j = Sprite_DirectionToFaceLink(k, NULL);
+  if (kGreenStalfos_Dir[j] != link_direction_facing) {
+    sprite_A[k] = 0;
+    if (!((k ^ frame_counter) & 7)) {
+      uint8 vel = sprite_B[k];
+      if (vel != 4)
+        sprite_B[k]++;
+      Sprite_ApplySpeedTowardsLink(k, vel);
+      sprite_D[k] = Sprite_IsRightOfLink(k).a;
+    }
+  } else {
+    sprite_A[k] = 1;
+    if (!((k ^ frame_counter) & 15)) {
+      uint8 vel = sprite_B[k];
+      if (vel)
+        sprite_B[k]--;
+      Sprite_ApplySpeedTowardsLink(k, vel);
+      sprite_D[k] = Sprite_IsRightOfLink(k).a;
+    }
+  }
+  Sprite_MoveXY(k);
+}
+
+void Sprite_7A_Agahnim(int k) {  // 9ed330
+  int j;
+  uint8 t;
+  static const uint8 kAgahnim_StartState[2] = {1, 6};
+  static const uint8 kAgahnim_Gfx0[5] = {12, 13, 14, 15, 16};
+  static const int8 kAgahnim_Tab5[2] = {32, -32};
+  static const uint8 kAgahnim_Tab6[2] = {9, 11};
+  static const uint8 kAgahnim_Dir[25] = {
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 0, 1, 1, 4,
+    4, 0, 2, 2, 4, 4, 3, 2, 2,
+  };
+  static const uint8 kAgahnim_Gfx1[6] = {2, 10, 8, 0, 4, 6};
+  static const uint8 kAgahnim_Tab0[16] = {0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0};
+  static const uint8 kAgahnim_Tab1[16] = {0, 0, 0, 0, 0, 0, 0, 6, 5, 4, 3, 2, 1, 0, 0, 0};
+  static const uint8 kAgahnim_Tab2[6] = {30, 24, 12, 0, 6, 18};
+  static const uint8 kAgahnim_Gfx2[5] = {16, 15, 14, 13, 12};
+  static const uint8 kAgahnim_Tab3[16] = {0x38, 0x38, 0x38, 0x58, 0x78, 0x98, 0xb8, 0xb8, 0xb8, 0x98, 0x58, 0x58, 0x60, 0x90, 0x98, 0x78};
+  static const uint8 kAgahnim_Tab4[16] = {0xb8, 0x78, 0x58, 0x48, 0x48, 0x48, 0x58, 0x78, 0xb8, 0xb8, 0xb8, 0x90, 0x70, 0x70, 0x90, 0xa0};
+  static const uint8 kAgahnim_Gfx3[7] = {0, 8, 10, 2, 2, 6, 4};
+  Agahnim_Draw(k);
+  if (sprite_pause[k]) {
+    sprite_delay_main[k] = 32;
+    sprite_graphics[k] = 0;
+    sprite_D[k] = 3;
+  }
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  if (Sprite_ReturnIfRecoiling(k))
+    return;
+  sprite_ignore_projectile[k] = 1;
+  switch (sprite_ai_state[k]) {
+  case 0:
+    sprite_ai_state[k] = kAgahnim_StartState[is_in_dark_world];
+    break;
+  case 1:
+    if (!sprite_delay_main[k]) {
+      dialogue_message_index = 0x13f;
+      Sprite_ShowMessageMinimal();
+      sprite_ai_state[k] = 3;
+      sprite_delay_main[k] = 32;
+    }
+    break;
+  case 2:
+    byte_7E0FF8 = 0;
+    if (!sprite_delay_main[k]) {
+      sprite_ai_state[k]++;
+      sprite_delay_main[k] = 255;
+    } else {
+      sprite_graphics[k] = kAgahnim_Gfx0[sprite_delay_main[k] >> 3];
+    }
+    break;
+  case 3:
+    j = sprite_delay_main[k];
+    if (j == 192)
+      SpriteSfx_QueueSfx3WithPan(k, 0x27);
+    if (j >= 239 || j < 16) {
+      AgahnimWarpShadowFilter(is_in_dark_world ? k : 2);
+    } else {
+      if (!k) {
+        Sprite_CheckDamageToAndFromLink(k);
+        sprite_ignore_projectile[k] = 0;
+      }
+    }
+    if (!sprite_delay_main[k]) {
+      sprite_ai_state[k]++;
+      sprite_delay_main[k] = 39;
+      return;
+    }
+    if (sprite_delay_main[k] >= 128) {
+      Sprite_ApplySpeedTowardsLink(k, 2);
+      sprite_D[k] = kAgahnim_Dir[((int8)sprite_y_vel[k] + 2) * 5 + 2 + (int8)sprite_x_vel[k]];
+      Sprite_ApplySpeedTowardsLink(k, 32);
+      if (sprite_subtype[k] == 4)
+        sprite_D[k] = 3;
+    } else if (sprite_delay_main[k] == 112) {
+      Agahnim_PerformAttack(k);
+    }
+    j = sprite_delay_main[k] >> 4;
+    sprite_A[k] = kAgahnim_Tab0[j];
+    t = kAgahnim_Tab1[j];
+    sprite_head_dir[k] = t ? t + kAgahnim_Tab2[sprite_D[k]] : t ;
+    sprite_graphics[k] = kAgahnim_Gfx1[sprite_D[k]] + sprite_A[k];
+    break;
+  case 4:
+    sprite_ignore_projectile[k] = sprite_delay_main[k];
+    if (!sprite_delay_main[k]) {
+      sprite_ai_state[k]++;
+      j = sprite_subtype[k] == 4 ? 4 : GetRandomNumber() & 0xf;
+      sprite_C[k] = kAgahnim_Tab3[j];
+      sprite_E[k] = kAgahnim_Tab4[j];
+      sprite_G[k] = 8;
+    } else {
+      sprite_graphics[k] = kAgahnim_Gfx2[sprite_delay_main[k] >> 3];
+    }
+    break;
+  case 5: {
+    if ((uint16)(sprite_x_lo[k] - sprite_C[k] + 7) < 14 &&
+        (uint16)(sprite_y_lo[k] - sprite_E[k] + 7) < 14) {
+      sprite_x_lo[k] = sprite_C[k];
+      sprite_y_lo[k] = sprite_E[k];
+      sprite_ai_state[k] = 2;
+      sprite_delay_main[k] = 39;
+      return;
+    }
+    int x = sprite_x_hi[k] << 8 | sprite_C[k];
+    int y = sprite_y_hi[k] << 8 | sprite_E[k];
+    ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLocation(k, x, y, sprite_G[k]);
+    sprite_y_vel[k] = pt.y;
+    sprite_x_vel[k] = pt.x;
+    if (sprite_G[k] < 64)
+      sprite_G[k]++;
+    Sprite_MoveXY(k);
+    break;
+  }
+  case 6:
+    if (!sprite_delay_main[k]) {
+      dialogue_message_index = 0x141;
+      Sprite_ShowMessageMinimal();
+      sprite_ai_state[k]++;
+      sprite_delay_main[k] = 80;
+    }
+    break;
+  case 7:
+    if (sprite_anim_clock[k]) {
+      if (!sprite_delay_main[k]) {
+        sprite_ai_state[k] = 3;
+        sprite_delay_main[k] = 32;
+      } else {
+        sprite_x_vel[k] = kAgahnim_Tab5[k - 1];
+        sprite_y_vel[k] += 2;
+        Sprite_MoveXY(k);
+        j = Sprite_Agahnim_ApplyMotionBlur(k);
+        if (j >= 0)
+          sprite_oam_flags[j] = 4;
+      }
+    } else {
+      if (!sprite_delay_main[k]) {
+        sprite_ai_state[k] = 3;
+        sprite_delay_main[k] = 32;
+      } else if (sprite_delay_main[k] == 64) {
+        sound_effect_2 = 0x28;
+        tmp_counter = 1;
+        do {
+          SpriteSpawnInfo info;
+          j = Sprite_SpawnDynamicallyEx(k, 0x7A, &info, 2);
+          Sprite_SetSpawnedCoordinates(j, &info);
+          sprite_flags3[j] = kAgahnim_Tab6[j - 1];
+          sprite_anim_clock[j] = sprite_oam_flags[j] = sprite_flags3[j] & 15;
+          sprite_ai_state[j] = sprite_ai_state[k];
+          sprite_delay_main[j] = 32;
+        } while (!sign8(--tmp_counter));
+      }
+    }
+    break;
+  case 8:
+    flag_block_link_menu = 2;
+    sprite_head_dir[k] = 0;
+    if (sprite_delay_main[k] >= 64) {
+      sprite_hit_timer[k] |= 0xe0;
+    } else {
+      if (sprite_delay_main[k] == 1) {
+        Sprite_SpawnPhantomGanon(k);
+        music_control = 0x1d;
+      }
+      sprite_hit_timer[k] = 0;
+      sprite_graphics[k] = 17;
+    }
+    break;
+  case 9: {
+    sprite_head_dir[k] = 0;
+    int x = Sprite_GetX(0), y = Sprite_GetY(0);
+    if ((uint16)(cur_sprite_x - x + 4) < 8 &&
+        (uint16)(cur_sprite_y - y + 4) < 8)
+      sprite_state[k] = 0;
+    ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLocation(k, x, y, 0x20);
+    sprite_y_vel[k] = pt.y;
+    sprite_x_vel[k] = pt.x;
+    Sprite_MoveXY(k);
+    Sprite_Agahnim_ApplyMotionBlur(k);
+    break;
+  }
+  case 10:
+    if (!sprite_delay_main[k]) {
+      sprite_state[k] = 0;
+      PrepareDungeonExitFromBossFight();
+    }
+    if (sprite_delay_main[k] < 16) {
+      CGADSUB_copy = 0x7f;
+      TM_copy = 6;
+      TS_copy = 0x10;
+      PaletteFilter_SP5F();
+    }
+    if (sprite_z_vel[k] != 0xff)
+      sprite_z_vel[k]++;
+    j = sprite_z_subpos[k] + sprite_z_vel[k];
+    sprite_z_subpos[k] = j;
+    if (j & 0x100 && ++sprite_subtype2[k] == 7) {
+      sprite_subtype2[k] = 0;
+      SpriteSfx_QueueSfx2WithPan(k, 0x4);
+    }
+    sprite_graphics[k] = kAgahnim_Gfx3[sprite_subtype2[k]];
+    break;
+  }
+}
+
+void Agahnim_PerformAttack(int k) {  // 9ed67a
+  static const int8 kAgahnim_X0[6] = {0, 10, 8, 0, -10, -10};
+  static const int8 kAgahnim_Y0[6] = {-9, -2, -2, -9, -2, -2};
+
+  if (!k) {
+    sprite_subtype[k]++;
+    if (is_in_dark_world)
+      sprite_subtype[k] &= 3;
+  }
+  if (sprite_subtype[k] == 5) {
+    sprite_subtype[k] = 0;
+    SpriteSfx_QueueSfx3WithPan(k, 0x26);
+    for (int i = 0; i < 4; i++)
+      Sprite_SpawnLightning(k);
+  } else {
+    SpriteSpawnInfo info;
+    int j = Sprite_SpawnDynamically(k, 0x7B, &info);
+    if (j >= 0) {
+      SpriteSfx_QueueSfx3WithPan(k, 0x29);
+      int i = sprite_D[k];
+      Sprite_SetX(j, info.r0_x + kAgahnim_X0[i]);
+      Sprite_SetY(j, info.r2_y + kAgahnim_Y0[i]);
+      sprite_ignore_projectile[j] = sprite_y_hi[j];
+      sprite_x_vel[j] = sprite_x_vel[k];
+      sprite_y_vel[j] = sprite_y_vel[k];
+      if (sprite_subtype[k] >= 2 && !(GetRandomNumber() & 1)) {
+        sprite_B[j] = 1;
+        sprite_delay_main[j] = 32;
+      }
+    }
+  }
+}
+
+void Agahnim_Draw(int k) {  // 9ed978
+  static const int8 kAgahnim_Draw_X0[72] = {
+    -8, 8, -8, 8, -8, 8, -8, 8, -8, 8, -8, 8, -8, 8, -8, 8,
+    -8, 8, -8, 8, -8, 8, -8, 8, -8, 8, -8, 8, -8, 8, -8, 8,
+    -8, 8, -8, 8, -8, 8, -8, 8, -8, 8, -8, 8, -8, 8, -8, 8,
+    -8, 8, -8, 8, -6, 6, -6, 6, -8, 8, -8, 8, -6, 6, -6, 6,
+    0, 8,  0, 8, -8, 8, -8, 8,
+  };
+  static const int8 kAgahnim_Draw_Y0[72] = {
+    -8, -8, 8, 8, -8, -8, 8, 8, -8, -8, 8, 8, -8, -8, 8, 8,
+    -8, -8, 8, 8, -8, -8, 8, 8, -8, -8, 8, 8, -8, -8, 8, 8,
+    -8, -8, 8, 8, -8, -8, 8, 8, -8, -8, 8, 8, -8, -8, 8, 8,
+    -8, -8, 8, 8, -6, -6, 6, 6, -8, -8, 8, 8, -6, -6, 6, 6,
+    0,  0, 8, 8,  8,  8, 8, 8,
+  };
+  static const uint8 kAgahnim_Draw_Char0[72] = {
+    0x82, 0x82, 0xa2, 0xa2, 0x80, 0x80, 0xa0, 0xa0, 0x84, 0x84, 0xa4, 0xa4, 0x86, 0x86, 0xa6, 0xa6,
+    0x88, 0x8a, 0xa8, 0xaa, 0x8c, 0x8e, 0xac, 0xae, 0xc4, 0xc2, 0xe4, 0xe6, 0xc0, 0xc2, 0xe0, 0xe2,
+    0x8a, 0x88, 0xaa, 0xa8, 0x8e, 0x8c, 0xae, 0xac, 0xc2, 0xc4, 0xe6, 0xe4, 0xc2, 0xc0, 0xe2, 0xe0,
+    0xec, 0xec, 0xec, 0xec, 0xec, 0xec, 0xec, 0xec, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+    0xdf, 0xdf, 0xdf, 0xdf, 0x40, 0x42, 0x40, 0x42,
+  };
+  static const uint8 kAgahnim_Draw_Flags0[72] = {
+    0, 0x40,    0, 0x40,    0, 0x40,    0, 0x40,    0, 0x40,    0, 0x40,    0, 0x40,    0, 0x40,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
+    0, 0x40, 0x80, 0xc0,    0, 0x40, 0x80, 0xc0,    0, 0x40, 0x80, 0xc0,    0, 0x40, 0x80, 0xc0,
+    0, 0x40, 0x80, 0xc0,    0,    0,    0,    0,
+  };
+  static const int8 kAgahnim_Draw_X1[72] = {
+    -7, 15, -11, 11, -11, 11,  -8,   8,  -4,   4,   0,   0, -10,  -1, -14,  -5,
+    -14, -5, -12, -7, -10, -7, -10, -10,  16,   8,  12,   4,  12,   4,  10,   6,
+    9,  7,   8,  8,  -6, -6, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10,
+    14, 14,  10, 10,  10, 10,  10,  10,  10,  10,  10,  10,  -7,  15, -11,  11,
+    -11, 11,  -8,  8,  -4,  4,   0,   0,
+  };
+  static const int8 kAgahnim_Draw_Y1[72] = {
+    -5, -5, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -3,  9, -7,  5,
+    -7,  5, -5,  3, -3,  3, -2, -2, -3,  9, -7,  5, -7,  5, -5,  3,
+    -3,  3, -2, -2, -3,  9, -7,  5, -7,  5, -5,  3, -3,  3, -2, -2,
+    -3,  9, -7,  5, -7,  5, -5,  3, -3,  3, -2, -2, -5, -5, -9, -9,
+    -9, -9, -9, -9, -9, -9, -9, -9,
+  };
+  static const uint8 kAgahnim_Draw_Char1[36] = {
+    0xce, 0xcc, 0xc6, 0xc6, 0xc6, 0xc6, 0xce, 0xcc, 0xc6, 0xc6, 0xc6, 0xc6, 0xce, 0xcc, 0xc6, 0xc6,
+    0xc6, 0xc6, 0xce, 0xcc, 0xc6, 0xc6, 0xc6, 0xc6, 0xce, 0xcc, 0xc6, 0xc6, 0xc6, 0xc6, 0xce, 0xcc,
+    0xc6, 0xc6, 0xc6, 0xc6,
+  };
+  static const uint8 kAgahnim_Draw_Big1[36] = {
+    0, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 0, 2, 2, 2,
+    2, 2, 0, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 0, 2,
+    2, 2, 2, 2,
+  };
+  PrepOamCoordsRet info;
+  if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
+    return;
+  OamEnt *oam = GetOamCurPtr();
+  int g = sprite_graphics[k];
+  for (int i = 3; i >= 0; i--, oam++) {
+    int j = g * 4 + i;
+    SetOamPlain(oam, info.x + kAgahnim_Draw_X0[j], info.y + kAgahnim_Draw_Y0[j],
+                 kAgahnim_Draw_Char0[j], info.flags | kAgahnim_Draw_Flags0[j],
+                 (j >= 0x40 && j < 0x44) ? 0 : 2);
+  }
+  if (g < 12)
+    SpriteDraw_Shadow_custom(k, &info, 18);
+  if (submodule_index)
+    Sprite_CorrectOamEntries(k, 3, 0xff);
+
+  if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
+    return;
+
+  if (sprite_D[k])
+    Oam_AllocateFromRegionC(8);
+  else
+    Oam_AllocateFromRegionB(8);
+  oam = GetOamCurPtr();
+
+  if (!sprite_head_dir[k])
+    return;
+  g = sprite_head_dir[k] - 1;
+  uint8 flags = (((frame_counter >> 1) & 2) + 2) + 0x31;
+  for (int i = 1; i >= 0; i--, oam++) {
+    SetOamPlain(oam, info.x + kAgahnim_Draw_X1[g * 2 + i], info.y + kAgahnim_Draw_Y1[g * 2 + i],
+                 kAgahnim_Draw_Char1[g], flags, kAgahnim_Draw_Big1[g]);
+  }
+}
+
+void Sprite_7B_AgahnimBalls(int k) {  // 9eda42
+  if (sprite_B[k]) {
+    if (sprite_delay_main[k])
+      Sprite_ApplySpeedTowardsLink(k, 32);
+    sprite_oam_flags[k] = 5;
+  } else {
+    sprite_oam_flags[k] = (frame_counter >> 1 & 2) + 3;
+  }
+
+  if (sprite_ai_state[k]) {
+    static const uint8 kEnergyBall_Gfx[16] = {2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 0, 0, 0, 0};
+    if (sprite_graphics[k] != 2)
+      SpriteDraw_SingleLarge(k);
+    else
+      SpriteDraw_SingleSmall(k);
+    if (Sprite_ReturnIfInactive(k))
+      return;
+    sprite_ignore_projectile[k] = sprite_delay_main[k];
+    if (!sprite_delay_main[k]) {
+      sprite_state[k] = 0;
+    } else if (sprite_delay_main[k] == 6) {
+      sprite_x_vel[k] = sprite_y_vel[k] = 64;
+      Sprite_MoveXY(k);
+    }
+    sprite_graphics[k] = kEnergyBall_Gfx[sprite_delay_main[k]];
+    return;
+  }
+  if (sprite_B[k])
+    SeekerEnergyBall_Draw(k);
+  else
+    SpriteDraw_SingleLarge(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  sprite_subtype2[k]++;
+  Sprite_MoveXY(k);
+  if (Sprite_CheckTileCollision(k)) {
+    sprite_state[k] = 0;
+    if (sprite_B[k]) {
+      SpriteSfx_QueueSfx3WithPan(k, 0x36);
+      CreateSixBlueBalls(k);
+      return;
+    }
+  }
+
+  if (sprite_A[k] && !sprite_ignore_projectile[0]) {
+    SpriteHitBox hb;
+    hb.r0_xlo = sprite_x_lo[k];
+    hb.r8_xhi = sprite_x_hi[k];
+    hb.r2 = hb.r3 = 15;
+    hb.r1_ylo = sprite_y_lo[k];
+    hb.r9_yhi = sprite_y_hi[k];
+    Sprite_SetupHitBox(0, &hb);
+    if (CheckIfHitBoxesOverlap(&hb)) {
+      Sprite_GiveDamage(0, 16, 0xa0);
+      sprite_state[k] = 0;
+      sprite_x_recoil[0] = sprite_x_vel[k];
+      sprite_y_recoil[0] = sprite_y_vel[k];
+    }
+  } else {
+    Sprite_CheckDamageToLink(k);
+    if (Sprite_CheckDamageFromLink(k) & kCheckDamageFromPlayer_Carry) {
+      if (sprite_B[k]) {
+        sprite_state[k] = 0;
+        SpriteSfx_QueueSfx3WithPan(k, 0x36);
+        CreateSixBlueBalls(k);
+        return;
+      }
+      SpriteSfx_QueueSfx2WithPan(k, 0x5);
+      SpriteSfx_QueueSfx3WithPan(k, 0x29);
+      Sprite_ApplySpeedTowardsLink(k, 0x30);
+      sprite_x_vel[k] = -sprite_x_vel[k];
+      sprite_y_vel[k] = -sprite_y_vel[k];
+      sprite_A[k]++;
+    }
+  }
+  if ((k ^ frame_counter) & 3 | sprite_B[k])
+    return;
+  SpriteSpawnInfo info;
+  int j = Sprite_SpawnDynamically(k, 0x7B, &info);
+  if (j < 0)
+    return;
+  Sprite_SetSpawnedCoordinates(j, &info);
+  sprite_delay_main[j] = 15;
+  sprite_ai_state[j] = 15;
+  sprite_B[j] = sprite_B[k];
+}
+
+void CreateSixBlueBalls(int k) {  // 9edb96
+  static const int8 kEnergyBall_SplitXVel[6] = {0, 24, 24, 0, -24, -24};
+  static const int8 kEnergyBall_SplitYVel[6] = {-32, -16, 16, 32, 16, -16};
+  SpriteSfx_QueueSfx3WithPan(k, 0x36);
+  tmp_counter = 5;
+  do {
+    SpriteSpawnInfo info;
+    int j = Sprite_SpawnDynamically(k, 0x55, &info);
+    if (j >= 0) {
+      Sprite_SetX(j, info.r0_x + 4);
+      Sprite_SetY(j, info.r2_y + 4);
+      sprite_flags3[j] = sprite_flags3[j] & ~1 | 0x40;
+      sprite_oam_flags[j] = 4;
+      sprite_delay_aux1[j] = 4;
+      sprite_flags4[j] = 20;
+      sprite_C[j] = 20;
+      sprite_E[j] = 20;
+      sprite_x_vel[j] = kEnergyBall_SplitXVel[tmp_counter];
+      sprite_y_vel[j] = kEnergyBall_SplitYVel[tmp_counter];
+    }
+  } while (!sign8(--tmp_counter));
+  tmp_counter = 0;
+}
+
+void SeekerEnergyBall_Draw(int k) {  // 9edc3e
+  static const DrawMultipleData kEnergyBall_Dmd[8] = {
+    { 4, -3, 0x00ce, 0},
+    {11,  4, 0x00ce, 0},
+    { 4, 11, 0x00ce, 0},
+    {-3,  4, 0x00ce, 0},
+    {-1, -1, 0x00ce, 0},
+    { 9, -1, 0x00ce, 0},
+    {-1,  9, 0x00ce, 0},
+    { 9,  9, 0x00ce, 0},
+  };
+  Sprite_DrawMultiple(k, &kEnergyBall_Dmd[(sprite_subtype2[k] >> 2 & 1) * 4], 4, NULL);
+}
+
+void Sprite_79_Bee(int k) {  // 9edc5b
+  switch (sprite_ai_state[k]) {
+  case 0:
+    Bee_DormantHive(k);
+    break;
+  case 1:
+    Bee_Main(k);
+    break;
+  case 2:
+    Bee_PutInBottle(k);
+    break;
+  }
+}
+
+void Bee_DormantHive(int k) {  // 9edc68
+  if (sprite_E[k])
+    return;
+  sprite_state[k] = 0;
+  for (int i = 11; i >= 0; i--)
+    SpawnBeeFromHive(k);
+}
+
+void SpawnBeeFromHive(int k) {  // 9edc8f
+  SpriteSpawnInfo info;
+  int j = Sprite_SpawnDynamically(k, 0x79, &info);
+  if (j >= 0) {
+    Sprite_SetSpawnedCoordinates(j, &info);
+    InitializeSpawnedBee(j);
+  }
+}
+
+void InitializeSpawnedBee(int k) {  // 9edc9b
+  sprite_ai_state[k] = 1;
+  sprite_A[k] = sprite_delay_main[k] = kSpawnBee_InitDelay[k & 3];
+  sprite_delay_aux4[k] = 96;
+  sprite_x_vel[k] = kSpawnBee_InitVel[GetRandomNumber() & 7];
+  sprite_y_vel[k] = kSpawnBee_InitVel[GetRandomNumber() & 7];
+}
+
+int ReleaseBeeFromBottle(int x_value) {  // 9edccf
+  static const int8 kSpawnBee_XY[8] = {8, 2, -2, -8, 10, 5, -5, -10};
+
+  SpriteSpawnInfo info;
+  int j = Sprite_SpawnDynamically(x_value, 0xb2, &info);
+  if (j >= 0) {
+    sprite_floor[j] = link_is_on_lower_level;
+    Sprite_SetX(j, link_x_coord + 8);
+    Sprite_SetY(j, link_y_coord + 16);
+    if (link_bottle_info[link_item_bottle_index - 1] == 8)
+      sprite_head_dir[j] = 1;
+    InitializeSpawnedBee(j);
+    sprite_x_vel[j] = kSpawnBee_XY[GetRandomNumber() & 7];
+    sprite_y_vel[j] = kSpawnBee_XY[GetRandomNumber() & 7];
+    sprite_delay_main[j] = 64;
+    sprite_A[j] = 64;
+  }
+  return j;
+}
+
+void Bee_Main(int k) {  // 9edd45
+  Bee_HandleZ(k);
+  SpriteDraw_SingleSmall(k);
+  Bee_HandleInteractions(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  if (Sprite_ReturnIfRecoiling(k))
+    return;
+  if (sprite_head_dir[k])
+    Sprite_SpawnSparkleGarnish(k);
+  Bee_Bzzt(k);
+  Sprite_MoveXY(k);
+  sprite_graphics[k] = (k ^ frame_counter) >> 1 & 1;
+  if (!sprite_delay_aux4[k]) {
+    Sprite_CheckDamageToLink(k);
+    if (Sprite_CheckDamageFromLink(k) & kCheckDamageFromPlayer_Ne) {
+      Sprite_ShowMessageUnconditional(0xc8);
+      sprite_ai_state[k] = 2; // put in bottle
+      return;
+    }
+  }
+
+  if (!frame_counter && sprite_A[k] != 16)
+    sprite_A[k] -= 8;
+
+  if (sprite_delay_main[k] == 0) {
+    uint16 x = link_x_coord + (GetRandomNumber() & 3) * 5;
+    uint16 y = link_y_coord + (GetRandomNumber() & 3) * 5;
+    ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLocation(k, x, y, 20);
+    sprite_y_vel[k] = pt.y;
+    sprite_x_vel[k] = pt.x;
+    sprite_oam_flags[k] = sprite_oam_flags[k] & ~0x40 | (sign8(pt.x) ? 0 : 0x40);
+    sprite_delay_main[k] = k + sprite_A[k];
+  }
+}
+
+int Sprite_Find_EmptyBottle() {  // 9ede2e
+  for (int i = 0; i != 4; i++)
+    if (link_bottle_info[i] == 2)
+      return i;
+  return -1;
+}
+
+void Bee_HandleInteractions(int k) {  // 9ede44
+  if (submodule_index == 2 && (dialogue_message_index == 0xc8 || dialogue_message_index == 0xca))
+    sprite_delay_aux4[k] = 40;
+}
+
+void Sprite_B2_PlayerBee(int k) {  // 9ede63
+  static const uint8 kGoodBee_Tab0[2] = {0xa, 0x14};
+
+  switch (sprite_ai_state[k]) {
+  case 0:  // wait
+    if (!sprite_E[k]) {
+      sprite_state[k] = 0;
+      uint8 or_bottle = link_bottle_info[0] | link_bottle_info[1] | link_bottle_info[2] | link_bottle_info[3];
+      if (!(or_bottle & 8))
+        GoldBee_SpawnSelf(k);
+    }
+    break;
+  case 1: {// activated
+    sprite_ignore_projectile[k] = 1;
+    Bee_HandleZ(k);
+    SpriteDraw_SingleSmall(k);
+    Bee_HandleInteractions(k);
+    if (Sprite_ReturnIfInactive(k))
+      return;
+    Bee_Bzzt(k);
+    Sprite_MoveXY(k);
+    sprite_graphics[k] = (k ^ frame_counter) >> 1 & 1;
+    if (sprite_head_dir[k])
+      Sprite_SpawnSparkleGarnish(k);
+    if (sprite_B[k] >= kGoodBee_Tab0[sprite_head_dir[k]]) {
+      sprite_defl_bits[k] = 64;
+      return;
+    }
+    if (sprite_delay_aux4[k])
+      return;
+    if (Sprite_CheckDamageFromLink(k) & kCheckDamageFromPlayer_Ne) {
+      Sprite_ShowMessageUnconditional(0xc8);
+      sprite_ai_state[k]++;
+      return;
+    }
+    if ((k ^ frame_counter) & 3)
+      return;
+    Point16U pt2;
+    if (!PlayerBee_FindTarget(k, &pt2)) {
+      pt2.x = link_x_coord + (GetRandomNumber() & 3) * 5;
+      pt2.y = link_y_coord + (GetRandomNumber() & 3) * 5;
+    }
+    if ((k ^ frame_counter) & 7)
+      return;
+    ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLocation(k, pt2.x, pt2.y, 32);
+    sprite_x_vel[k] = pt.x;
+    sprite_y_vel[k] = pt.y;
+    sprite_oam_flags[k] = sprite_oam_flags[k] & ~0x40 | (sign8(pt.x) ? 0 : 0x40);
+    break;
+  }
+  case 2:  // bottle
+    Bee_PutInBottle(k);
+    break;
+  }
+}
+
+void GoldBee_SpawnSelf(int k) {  // 9ede90
+  SpriteSpawnInfo info;
+  int j = Sprite_SpawnDynamically(k, 0x79, &info);
+  if (j >= 0) {
+    Sprite_SetSpawnedCoordinates(j, &info);
+    sprite_ai_state[j] = 1;
+    sprite_delay_main[j] = 64;
+    sprite_A[j] = 64;
+    sprite_delay_aux4[j] = 96;
+    sprite_head_dir[j] = 1;
+    sprite_x_vel[j] = kSpawnBee_InitVel[GetRandomNumber() & 7];
+    sprite_y_vel[j] = kSpawnBee_InitVel[GetRandomNumber() & 7];
+  }
+}
+
+void Bee_HandleZ(int k) {  // 9edf8a
+  sprite_z[k] = 16;
+  if (sprite_head_dir[k])
+    sprite_oam_flags[k] = (sprite_oam_flags[k] & 0xf1) | (((frame_counter >> 4 & 3) + 1) << 1);
+}
+
+bool PlayerBee_FindTarget(int k, Point16U *pt) {  // 9edfab
+  int n = 16;
+  int j = k * 4 & 0xf;
+  do {
+    if (j == k || sprite_state[j] < 9 || sprite_pause[j])
+      continue;
+    if (!(sprite_flags2[j] & 0x80)) {
+      if (sprite_floor[k] != sprite_floor[j] || sprite_flags4[j] & 0x40 || sprite_ignore_projectile[j])
+        continue;
+    } else {
+      if (!sprite_head_dir[k] || !(sprite_bump_damage[j] & 0x40))
+        continue;
+    }
+    PlayerBee_HoneInOnTarget(j, k);
+    pt->x = Sprite_GetX(j) + (GetRandomNumber() & 3) * 5;
+    pt->y = Sprite_GetY(j) + (GetRandomNumber() & 3) * 5;
+    return true;
+  } while (j = (j - 1) & 0xf, --n);
+  return false;
+}
+
+void Bee_Bzzt(int k) {  // 9ee02e
+  if (!((k ^ frame_counter) & 31))
+    SpriteSfx_QueueSfx3WithPan(k, 0x2c);
+}
+
+void Sprite_B3_PedestalPlaque(int k) {  // 9ee044
+  PrepOamCoordsRet info;
+  Sprite_PrepOamCoord(k, &info);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  if (!flag_is_link_immobilized && Sprite_CheckIfLinkIsBusy())
+    return;
+
+  link_position_mode &= ~0x20;
+  if (BYTE(overworld_screen_index) != 48) {
+    if (link_direction_facing || !Sprite_CheckDamageToLink_same_layer(k))
+      return;
+    if (hud_cur_item != kHudItem_BookMudora || !(filtered_joypad_H & 0x40)) {
+      if (!(filtered_joypad_L & 0x80))
+        return;
+      Sprite_ShowMessageUnconditional(0xb6);
+    } else {
+      player_handler_timer = 0;
+      link_position_mode = 32;
+      sound_effect_1 = 0;
+      Sprite_ShowMessageUnconditional(0xb7);
+    }
+  } else {
+    if (link_direction_facing || !Sprite_CheckDamageToLink_same_layer(k))
+      return;
+    if (hud_cur_item != kHudItem_BookMudora || !(filtered_joypad_H & 0x40)) {
+      if (!(filtered_joypad_L & 0x80))
+        return;
+      Sprite_ShowMessageUnconditional(0xbc);
+    } else {
+      player_handler_timer = 0;
+      link_position_mode = 32;
+      sound_effect_1 = 0;
+      button_b_frames = 1;
+      link_delay_timer_spin_attack = 0;
+      link_player_handler_state = kPlayerState_OpeningDesertPalace;
+      Sprite_ShowMessageUnconditional(0xbd);
+    }
+  }
+}
+
+void Sprite_B4_PurpleChest(int k) {  // 9ee0dd
+  SpriteDraw_SingleLarge(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  if (!sprite_ai_state[k]) {
+    if (Sprite_ShowMessageOnContact(k, 0x116) & 0x100 && follower_indicator == 0)
+      sprite_ai_state[k] = 1;
+  } else {
+    sprite_state[k] = 0;
+    follower_indicator = 12;
+    LoadFollowerGraphics();
+    Sprite_BecomeFollower(k);
+  }
+}
+
+void Sprite_B5_BombShop(int k) {  // 9ee111
+  switch (sprite_subtype2[k]) {
+  case 0: Sprite_BombShop_Clerk(k); break;
+  case 1: Sprite_BombShop_Bomb(k); break;
+  case 2: Sprite_BombShop_SuperBomb(k); break;
+  case 3: Sprite_BombShop_Huff(k); break;
+  }
+}
+
+void Sprite_BombShop_Clerk(int k) {  // 9ee134
+  static const uint8 kBombShopGuy_Gfx[8] = {0, 1, 0, 1, 0, 1, 0, 1};
+  static const uint8 kBombShopGuy_Delay[8] = {255, 32, 255, 24, 15, 24, 255, 15};
+
+  BombShopEntity_Draw(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  if (!sprite_delay_main[k]) {
+    int j = sprite_E[k];
+    sprite_E[k] = j + 1 & 7;
+    sprite_delay_main[k] = kBombShopGuy_Delay[j];
+    sprite_graphics[k] = kBombShopGuy_Gfx[j];
+    if (sprite_graphics[k] == 0) {
+      SpriteSfx_QueueSfx3WithPan(k, 0x11);
+      BombShop_ClerkExhalation(k);
+    } else {
+      SpriteSfx_QueueSfx3WithPan(k, 0x12);
+    }
+  }
+  bool flag = ((link_has_crystals & 5) == 5 && sram_progress_indicator_3 & 32);
+  Sprite_ShowSolicitedMessage(k, flag ? 0x118 : 0x117);
+  Sprite_BehaveAsBarrier(k);
+}
+
+void Sprite_BombShop_Bomb(int k) {  // 9ee190
+  BombShopEntity_Draw(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  Sprite_BehaveAsBarrier(k);
+  if (!ShopItem_CheckForAPress(k))
+    return;
+
+  if (link_item_bombs != kMaxBombsForLevel[link_bomb_upgrades]) {
+    if (!ShopItem_HandleCost(100)) {
+      Sprite_ShowMessageUnconditional(0x17c);
+      ShopItem_PlayBeep(k);
+    } else {
+      link_bomb_filler = 27;
+      sprite_state[k] = 0;
+      Sprite_ShowMessageUnconditional(0x119);
+      ShopItem_HandleReceipt(k, 0x28);
+    }
+  } else {
+    Sprite_ShowMessageUnconditional(0x16e);
+    ShopItem_PlayBeep(k);
+  }
+
+}
+
+void Sprite_BombShop_SuperBomb(int k) {  // 9ee1df
+  BombShopEntity_Draw(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  Sprite_BehaveAsBarrier(k);
+  if (ShopItem_CheckForAPress(k)) {
+    if (!ShopItem_HandleCost(100)) {
+      Sprite_ShowMessageUnconditional(0x17c);
+      ShopItem_PlayBeep(k);
+    } else {
+      follower_indicator = 13;
+      LoadFollowerGraphics();
+      Sprite_BecomeFollower(k);
+      sprite_state[k] = 0;
+      Sprite_ShowMessageUnconditional(0x11a);
+    }
+  }
+}
+
+void Sprite_BombShop_Huff(int k) {  // 9ee21a
+  static const uint8 kSnoutPutt_Dmd[4] = {4, 0x44, 0xc4, 0x84};
+  Oam_AllocateFromRegionC(4);
+  SpriteDraw_SingleSmall(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  sprite_oam_flags[k] &= 0x30;
+  sprite_oam_flags[k] |= kSnoutPutt_Dmd[frame_counter >> 2 & 3];
+  sprite_z_vel[k]++;
+  Sprite_MoveZ(k);
+  if (!sprite_delay_main[k])
+    sprite_state[k] = 0;
+  sprite_graphics[k] = sprite_delay_main[k] >> 3 & 3;
+}
+
+void BombShop_ClerkExhalation(int k) {  // 9ee256
+  SpriteSpawnInfo info;
+  int j = Sprite_SpawnDynamically(k, 0xb5, &info);
+  if (j >= 0) {
+    Sprite_SetX(j, info.r0_x + 4);
+    Sprite_SetY(j, info.r2_y + 16);
+    sprite_subtype2[j] = 3;
+    sprite_ignore_projectile[j] = 3;
+    sprite_z[j] = 4;
+    sprite_z_vel[j] = -12;
+    sprite_delay_main[j] = 23;
+    sprite_flags3[j] &= ~0x11;
+  }
+}
+
+void BombShopEntity_Draw(int k) {  // 9ee2c6
+  static const DrawMultipleData kBombShopEntity_Dmd[6] = {
+    {0, 0, 0x0a48, 2},
+    {0, 0, 0x0a4c, 2},
+    {0, 0, 0x04c2, 2},
+    {0, 0, 0x04c2, 2},
+    {0, 0, 0x084e, 2},
+    {0, 0, 0x084e, 2},
+  };
+  PrepOamCoordsRet info;
+  Sprite_DrawMultiplePlayerDeferred(k, &kBombShopEntity_Dmd[sprite_subtype2[k] * 2 + sprite_graphics[k]], 1, &info);
+  SpriteDraw_Shadow(k, &info);
+
+}
+
+void Sprite_B6_Kiki(int k) {  // 9ee2ef
+  switch(sprite_subtype2[k]) {
+  case 0: Kiki_LyingInwait(k); break;
+  case 1: Kiki_OfferEntranceService(k); break;
+  case 2: Kiki_OfferInitialService(k); break;
+  case 3: Kiki_Flee(k); break;
+  }
+}
+
+void Kiki_Flee(int k) {  // 9ee2fe
+  bool flag = Kiki_Draw(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  if (!sprite_z[k] &&
+      (uint16)(cur_sprite_x - 0xc98) < 0xd0 &&
+      (uint16)(cur_sprite_y - 0x6a5) < 0xd0)
+    flag = true;
+
+  if (flag)
+    sprite_state[k] = 0;
+  sprite_z_vel[k]-=2;
+  Sprite_MoveXYZ(k);
+  if (sign8(sprite_z[k])) {
+    sprite_z[k] = 0;
+    sprite_z_vel[k] = GetRandomNumber() & 15 | 16;
+  }
+  ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLocation(k, 0xcf5, 0x6fe, 16);
+  sprite_x_vel[k] = pt.x << 1;
+  sprite_y_vel[k] = pt.y << 1;
+  tagalong_event_flags &= ~3;
+  if (sign8(pt.x)) pt.x = -pt.x;
+  if (sign8(pt.y)) pt.y = -pt.y;
+  sprite_D[k] = (pt.x >= pt.y) ? (sprite_x_vel[k] >> 7) ^ 3 : (sprite_y_vel[k] >> 7) ^ 1;
+  sprite_graphics[k] = frame_counter >> 3 & 1;
+}
+
+void Kiki_OfferInitialService(int k) {  // 9ee3af
+  if (!sign8(sprite_ai_state[k] - 2))
+    Kiki_Draw(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  Sprite_MoveXYZ(k);
+  sprite_z_vel[k]--;
+  if (sign8(sprite_z[k])) {
+    sprite_z_vel[k] = 0;
+    sprite_z[k] = 0;
+  }
+  sprite_graphics[k] = frame_counter >> 3 & 1;
+  switch(sprite_ai_state[k]) {
+  case 0:
+    Sprite_ShowMessageUnconditional(0x11e);
+    sprite_ai_state[k]++;
+    break;
+  case 1:
+    if (!choice_in_multiselect_box && ShopItem_HandleCost(10)) {
+      Sprite_ShowMessageUnconditional(0x11f);
+      tagalong_event_flags |= 3;
+      sprite_state[k] = 0;
+    } else {
+      Sprite_ShowMessageUnconditional(0x120);
+      tagalong_event_flags &= ~3;
+      follower_indicator = 0;
+      sprite_ai_state[k]++;
+      flag_is_link_immobilized++;
+    }
+    break;
+  case 2: {
+    sprite_ai_state[k]++;
+    ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLocation(k, 0xc45, 0x6fe, 9);
+    sprite_y_vel[k] = pt.y;
+    sprite_x_vel[k] = pt.x;
+    sprite_D[k] = (pt.x >> 7) ^ 3;
+    sprite_delay_main[k] = 32;
+    break;
+  }
+  case 3:
+    if (!sprite_delay_main[k]) {
+      sprite_ai_state[k]++;
+      sprite_z_vel[k] = 16;
+      sprite_delay_main[k] = 16;
+    }
+    break;
+  case 4:
+    if (!sprite_delay_main[k] && !sprite_z[k]) {
+      sprite_state[k] = 0;
+      flag_is_link_immobilized = 0;
+    }
+    break;
+  }
+}
+
+void Kiki_OfferEntranceService(int k) {  // 9ee4c9
+  int j, t;
+  Kiki_Draw(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  Sprite_MoveXYZ(k);
+  sprite_z_vel[k]--;
+  if (sign8(sprite_z[k])) {
+    sprite_z_vel[k] = 0;
+    sprite_z[k] = 0;
+  }
+  switch(sprite_ai_state[k]) {
+  case 0:  //
+    Sprite_ShowMessageUnconditional(0x11b);
+    sprite_ai_state[k]++;
+    break;
+  case 1:  //
+    if (choice_in_multiselect_box || !ShopItem_HandleCost(100)) {
+      Sprite_ShowMessageUnconditional(0x11c);
+      sprite_subtype2[k] = 3;
+    } else {
+      Sprite_ShowMessageUnconditional(0x11d);
+      flag_is_link_immobilized++;
+      sprite_ai_state[k]++;
+      sprite_D[k] = 0;
+    }
+    break;
+  case 2:  //
+  case 4:  //
+  case 6: { //
+    static const uint16 kKiki_Leave_X[3] = {0xf4f, 0xf70, 0xf5d};
+    static const uint16 kKiki_Leave_Y[3] = { 0x661, 0x64c, 0x624 };
+
+    sprite_graphics[k] = frame_counter >> 3 & 1;
+    j = (sprite_ai_state[k] >> 1) - 1;
+    if ((uint8)(kKiki_Leave_X[j] - sprite_x_lo[k] + 2) < 4 &&
+        (uint8)(kKiki_Leave_Y[j] - sprite_y_lo[k] + 2) < 4) {
+      sprite_ai_state[k]++;
+      sprite_x_vel[k] = sprite_y_vel[k] = 0;
+      sprite_delay_aux1[k] = 32;
+      SpriteSfx_QueueSfx2WithPan(k, 0x21);
+      return;
+    }
+    ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLocation(k, kKiki_Leave_X[j], kKiki_Leave_Y[j], 9);
+    sprite_x_vel[k] = pt.x;
+    sprite_y_vel[k] = pt.y;
+    break;
+  }
+  case 3:  //
+  case 5:  //
+    if (!sprite_delay_aux1[k]) {
+      static const uint8 kKiki_Zvel[2] = {32, 28};
+      sprite_z_vel[k] = kKiki_Zvel[sprite_ai_state[k]++ >> 1 & 1];
+      SpriteSfx_QueueSfx2WithPan(k, 0x20);
+      sprite_D[k] = sprite_ai_state[k] >> 1 & 1 | 4;
+    } else {
+      sprite_D[k] = sprite_ai_state[k] >> 1 & 1 | 6;
+      sprite_graphics[k] = frame_counter >> 3 & 1;
+    }
+    break;
+  case 7: { //
+    static const uint8 kKiki_Tab7[3] = {2, 1, 0xff};
+    static const uint8 kKiki_Delay7[2] = {82, 0};
+    static const int8 kKiki_Xvel7[4] = {0, 0, -9, 9};
+    static const int8 kKiki_Yvel7[4] = {-9, 9, 0, 0};
+    sprite_graphics[k] = frame_counter >> 3 & 1;
+    if (sprite_z[k] || sprite_delay_main[k])
+      return;
+    j = sprite_A[k]++;
+    t = kKiki_Tab7[j];
+    if (!sign8(t)) {
+      sprite_D[k] = t;
+      sprite_delay_main[k] = kKiki_Delay7[j];
+      sprite_x_vel[k] = kKiki_Xvel7[t];
+      sprite_y_vel[k] = kKiki_Yvel7[t];
+    } else {
+      sprite_ai_state[k]++;
+      sprite_x_vel[k] = sprite_y_vel[k] = 0;
+      trigger_special_entrance = 1;
+      subsubmodule_index = 0;
+      overworld_entrance_sequence_counter = 0;
+      sprite_D[k] = 0;
+      flag_is_link_immobilized = 0;
+    }
+    break;
+  }
+  case 8:  //
+    sprite_D[k] = 8;
+    sprite_graphics[k] = 0;
+    sprite_z_vel[k] = (GetRandomNumber() & 15) + 16;
+    sprite_ai_state[k]++;
+    break;
+  case 9:  //
+    if (sign8(sprite_z_vel[k]) && !sprite_z[k]) {
+      sprite_ai_state[k]++;
+      SpriteSfx_QueueSfx3WithPan(k, 0x25);
+    }
+    break;
+  case 10:  //
+    break;
+  }
+}
+
+bool Kiki_Draw(int k) {  // 9ee859
+  static const DrawMultipleData kKiki_Dmd1[32] = {
+    { 0, -6, 0x0020, 2},
+    { 0,  0, 0x0022, 2},
+    { 0, -6, 0x0020, 2},
+    { 0,  0, 0x4022, 2},
+    { 0, -6, 0x0020, 2},
+    { 0,  0, 0x0022, 2},
+    { 0, -6, 0x0020, 2},
+    { 0,  0, 0x4022, 2},
+    {-1, -6, 0x0020, 2},
+    { 0,  0, 0x0022, 2},
+    {-1, -6, 0x0020, 2},
+    { 0,  0, 0x0022, 2},
+    { 1, -6, 0x4020, 2},
+    { 0,  0, 0x4022, 2},
+    { 1, -6, 0x4020, 2},
+    { 0,  0, 0x4022, 2},
+    { 0, -6, 0x01ce, 2},
+    { 0,  0, 0x01ee, 2},
+    { 0, -6, 0x01ce, 2},
+    { 0,  0, 0x01ee, 2},
+    { 0, -6, 0x41ce, 2},
+    { 0,  0, 0x41ee, 2},
+    { 0, -6, 0x41ce, 2},
+    { 0,  0, 0x41ee, 2},
+    {-1, -6, 0x01ce, 2},
+    { 0,  0, 0x01ec, 2},
+    {-1, -6, 0x41ce, 2},
+    { 0,  0, 0x01ec, 2},
+    { 1, -6, 0x41ce, 2},
+    { 0,  0, 0x41ec, 2},
+    { 1, -6, 0x01ce, 2},
+    { 0,  0, 0x41ec, 2},
+  };
+  static const DrawMultipleData kKiki_Dmd2[12] = {
+    {0, -6, 0x01ca, 0},
+    {8, -6, 0x41ca, 0},
+    {0,  2, 0x01da, 0},
+    {8,  2, 0x41da, 0},
+    {0, 10, 0x01cb, 0},
+    {8, 10, 0x41cb, 0},
+    {0, -6, 0x01db, 0},
+    {8, -6, 0x41db, 0},
+    {0,  2, 0x01cc, 0},
+    {8,  2, 0x41cc, 0},
+    {0, 10, 0x01dc, 0},
+    {8, 10, 0x41dd, 0},
+  };
+  static const uint8 kKikiDma[32] = {
+    0x20, 0xc0, 0x20, 0xc0, 0, 0xa0, 0, 0xa0, 0x40, 0x80, 0x40, 0x60, 0x40, 0x80, 0x40, 0x60,
+    0, 0, 0xfa, 0xff, 0x20, 0, 0, 2, 0, 0, 0, 0, 0x22, 0, 0, 2  // zelda bug: OOB read
+  };
+  PrepOamCoordsRet info;
+  if (sprite_D[k] < 8) {
+    int j = sprite_D[k] * 2 + sprite_graphics[k];
+    BYTE(dma_var6) = kKikiDma[j * 2 + 0];
+    BYTE(dma_var7) = kKikiDma[j * 2 + 1];
+    Sprite_DrawMultiple(k, &kKiki_Dmd1[j * 2], 2, &info);
+    if (!sprite_pause[k])
+      SpriteDraw_Shadow(k, &info);
+  } else {
+    Sprite_DrawMultiple(k, &kKiki_Dmd2[sprite_graphics[k] * 6], 6, &info);
+    if (!sprite_pause[k])
+      SpriteDraw_Shadow(k, &info);
+  }
+
+  return ((info.x | info.y) & 0xff00) != 0;
+}
+
+void Sprite_B7_BlindMaiden(int k) {  // 9ee8b6
+  CrystalMaiden_Draw(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  Sprite_TrackBodyToHead(k);
+  sprite_head_dir[k] = Sprite_DirectionToFaceLink(k, NULL) ^ 3;
+  if (!sprite_ai_state[k]) {
+    if (Sprite_ShowMessageOnContact(k, 0x122) & 0x100)
+      sprite_ai_state[k] = 1;
+  } else {
+    sprite_state[k] = 0;
+    follower_indicator = 6;
+    LoadFollowerGraphics();
+    Sprite_BecomeFollower(k);
+  }
+}
+
+void OldMan_RevertToSprite(int k) {  // 9ee938
+  SpriteSpawnInfo info;
+  int j = Sprite_SpawnDynamically(k, 0xAD, &info);
+  sprite_D[j] = sprite_head_dir[j] = tagalong_layerbits[k] & 3;
+  Sprite_SetY(j, (tagalong_y_lo[k] | tagalong_y_hi[k] << 8) + 2);
+  Sprite_SetX(j, (tagalong_x_lo[k] | tagalong_x_hi[k] << 8) + 2);
+  sprite_floor[j] = link_is_on_lower_level;
+  sprite_ignore_projectile[j] = 1;
+  sprite_subtype2[j] = 1;
+  OldMan_EnableCutscene();
+  follower_indicator = 0;
+  link_speed_setting = 0;
+}
+
+void OldMan_EnableCutscene() {  // 9ee989
+  flag_is_link_immobilized = 1;
+  link_disable_sprite_damage = 1;
+}
+
+void Sprite_AD_OldMan(int k) {  // 9ee992
+  static const uint16 kOldMountainManMsgs[3] = {0x9e, 0x9f, 0xa0};
+  int j;
+  OldMountainMan_Draw(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  switch(sprite_subtype2[k]) {
+  case 0: // lost
+    switch (sprite_ai_state[k]) {
+    case 0: // supplicate
+      Sprite_TrackBodyToHead(k);
+      sprite_head_dir[k] = Sprite_DirectionToFaceLink(k, NULL) ^ 3;
+      j = Sprite_ShowMessageOnContact(k, 0x9c);
+      if (j & 0x100) {
+        sprite_D[k] = sprite_head_dir[k] = j;
+        sprite_ai_state[k] = 1;
+      }
+      break;
+    case 1: // switch to tagalong
+      follower_indicator = 4;
+      Sprite_BecomeFollower(k);
+      which_starting_point = 5;
+      sprite_state[k] = 0;
+      CacheCameraProperties();
+      break;
+    }
+    break;
+  case 1: // entering domicile
+    Sprite_MoveXY(k);
+    switch(sprite_ai_state[k]) {
+    case 0:  // grant mirror
+      sprite_ai_state[k]++;
+      item_receipt_method = 0;
+      Link_ReceiveItem(0x1a, 0);
+      which_starting_point = 1;
+      OldMan_EnableCutscene();
+      sprite_delay_main[k] = 48;
+      sprite_x_vel[k] = 8;
+      sprite_y_vel[k] = 4;
+      sprite_D[k] = sprite_head_dir[k] = 3;
+      break;
+    case 1:  // shuffle away
+      OldMan_EnableCutscene();
+      if (!sprite_delay_main[k])
+        sprite_ai_state[k]++;
+      sprite_graphics[k] = (k ^ frame_counter) >> 3 & 1;
+      break;
+    case 2: { // approach door
+      sprite_head_dir[k] = 0;
+      sprite_D[k] = 0;
+      j = byte_7E0FDE;
+      int x = overlord_x_lo[j] | overlord_x_hi[j] << 8;
+      int y = overlord_y_lo[j] | overlord_y_hi[j] << 8;
+      if (y >= Sprite_GetY(k)) {
+        sprite_ai_state[k]++;
+        sprite_y_vel[k] = sprite_x_vel[k] = 0;
+      } else {
+        ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLocation(k, x, y, 8);
+        sprite_y_vel[k] = pt.y;
+        sprite_x_vel[k] = pt.x;
+        sprite_graphics[k] = (k ^ frame_counter) >> 3 & 1;
+        OldMan_EnableCutscene();
+      }
+      break;
+    }
+    case 3:  // made it inside
+      sprite_state[k] = 0;
+      flag_is_link_immobilized = 0;
+      link_disable_sprite_damage = 0;
+      break;
+    }
+    break;
+  case 2: // sitting at home
+    Sprite_BehaveAsBarrier(k);
+    if (sprite_ai_state[k]) {
+      link_hearts_filler = 160;
+      sprite_ai_state[k] = 0;
+    }
+    j = sram_progress_indicator >= 3 ? 2 : link_item_moon_pearl;
+    if (Sprite_ShowSolicitedMessage(k, kOldMountainManMsgs[j]) & 0x100)
+      sprite_ai_state[k]++;
+
+    break;
+  }
+}
+
+void Sprite_B8_DialogueTester(int k) {  // 9eeae7
+  assert(0);
+}
+
+void Sprite_B9_BullyAndPinkBall(int k) {  // 9eeb33
+  switch(sprite_subtype2[k]) {
+  case 0: Sprite_PinkBall(k); return;
+  case 1: PinkBall_Distress(k); return;
+  case 2: Sprite_Bully(k); return;
+  }
+}
+
+void Sprite_PinkBall(int k) {  // 9eeb40
+  Oam_AllocateDeferToPlayer(k);
+  SpriteDraw_SingleLarge(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  PinkBall_HandleMessage(k);
+  sprite_oam_flags[k] = sprite_oam_flags[k] & ~0x80 | sprite_head_dir[k];
+  Sprite_MoveXYZ(k);
+  int t = Sprite_CheckTileCollision(k);
+  if (t) {
+    if (!(t & 3)) {
+      sprite_y_vel[k] = -sprite_y_vel[k];
+      if (sprite_E[k])
+        goto play_sound;
+    }
+    sprite_x_vel[k] = -sprite_x_vel[k];
+    if (sprite_E[k]) {
+play_sound:
+      BallGuy_PlayBounceNoise(k);
+    }
+  }
+
+  sprite_z_vel[k]--;
+  if (sign8(sprite_z[k])) {
+    sprite_z[k] = 0;
+    sprite_z_vel[k] = (uint8)-sprite_z_vel[k] >> 2;
+    if (sprite_z_vel[k] & 0xfc)
+      BallGuy_PlayBounceNoise(k);
+    PinkBall_HandleDeceleration(k);
+  }
+  if (!sprite_E[k]) {
+    if (!sprite_head_dir[k]) {
+      PinkBall_Distress(k);
+      sprite_graphics[k] = (k ^ frame_counter) >> 3 & 1;
+      if (!((k ^ frame_counter) & 0x3f)) {
+        uint16 x = (link_x_coord & 0xff00) | GetRandomNumber();
+        uint16 y = (link_y_coord & 0xff00) | GetRandomNumber();
+        ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLocation(k, x, y, 8);
+        sprite_B[k] = pt.x;
+        sprite_A[k] = pt.y;
+        if (pt.y) {
+          sprite_oam_flags[k] |= 64;
+          sprite_oam_flags[k] ^= sprite_x_vel[k] >> 1 & 64;
+        }
+      }
+      sprite_x_vel[k] = sprite_B[k];
+      sprite_y_vel[k] = sprite_A[k];
+    } else {
+      PinkBall_Distress(k);
+      if (k ^ frame_counter) {
+        sprite_graphics[k] = (k ^ frame_counter) >> 2 & 1;
+        sprite_x_vel[k] = 0;
+        sprite_y_vel[k] = 0;
+      } else {
+        sprite_head_dir[k] = 0;
+      }
+    }
+  } else {
+    if ((sprite_x_vel[k] | sprite_y_vel[k]) == 0) {
+      sprite_E[k] = 0;
+    } else {
+      sprite_graphics[k] = (k ^ frame_counter) >> 2 & 1;
+      sprite_head_dir[k] = (k ^ frame_counter) << 2 & 128;
+    }
+  }
+}
+
+void PinkBall_HandleDeceleration(int k) {  // 9eec4d
+  if (sprite_x_vel[k])
+    sprite_x_vel[k] += sign8(sprite_x_vel[k]) ? 2 : -2;
+  if (sprite_y_vel[k])
+    sprite_y_vel[k] += sign8(sprite_y_vel[k]) ? 2 : -2;
+}
+
+void PinkBall_Distress(int k) {  // 9eec74
+  PrepOamCoordsRet info;
+  if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
+    return;
+  Sprite_DrawDistress_custom(info.x, info.y, frame_counter);
+}
+
+void Sprite_Bully(int k) {  // 9eec7c
+  Bully_Draw(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  Bully_HandleMessage(k);
+  Sprite_MoveXYZ(k);
+  int t = Sprite_CheckTileCollision(k);
+  if (t) {
+    if (!(t & 3))
+      sprite_y_vel[k] = -sprite_y_vel[k];
+    else
+      sprite_x_vel[k] = -sprite_x_vel[k];
+  }
+  switch(sprite_ai_state[k]) {
+  case 0: { // chase
+    sprite_graphics[k] = (k ^ frame_counter) >> 3 & 1;
+    int j = sprite_head_dir[k];
+    if (!((k ^ frame_counter) & 0x1f)) {
+      ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLocation(k, Sprite_GetX(j), Sprite_GetY(j), 14);
+      sprite_y_vel[k] = pt.y;
+      sprite_x_vel[k] = pt.x;
+      if (pt.x)
+        sprite_D[k] = sprite_x_vel[k] >> 7;
+    }
+    if (!sprite_z[j]) {
+      if ((uint8)(sprite_x_lo[k] - sprite_x_lo[j] + 8) < 16 &&
+          (uint8)(sprite_y_lo[k] - sprite_y_lo[j] + 8) < 16) {
+        sprite_ai_state[k]++;
+        BallGuy_PlayBounceNoise(k);
+      }
+    }
+    break;
+  }
+  case 1: { // kick ball
+    sprite_ai_state[k] = 2;
+    int j = sprite_head_dir[k];
+    sprite_x_vel[j] = sprite_x_vel[k] << 1;
+    sprite_y_vel[j] = sprite_y_vel[k] << 1;
+    sprite_x_vel[k] = 0;
+    sprite_y_vel[k] = 0;
+    sprite_z_vel[j] = GetRandomNumber() & 31;
+    sprite_delay_main[k] = 96;
+    sprite_graphics[k] = 1;
+    sprite_E[j] = 1;
+    break;
+  }
+  case 2:  // waiting
+    if (!sprite_delay_main[k])
+      sprite_ai_state[k] = 0;
+    break;
+  }
+}
+
+void Bully_Draw(int k) {  // 9eed9e
+  static const DrawMultipleData kBully_Dmd[8] = {
+    {0, -7, 0x46e0, 2},
+    {0,  0, 0x46e2, 2},
+    {0, -7, 0x46e0, 2},
+    {0,  0, 0x46c4, 2},
+    {0, -7, 0x06e0, 2},
+    {0,  0, 0x06e2, 2},
+    {0, -7, 0x06e0, 2},
+    {0,  0, 0x06c4, 2},
+  };
+  PrepOamCoordsRet info;
+  Sprite_DrawMultiplePlayerDeferred(k, &kBully_Dmd[sprite_D[k] * 4 + sprite_graphics[k] * 2], 2, &info);
+  SpriteDraw_Shadow(k, &info);
+
+}
+
+void BallGuy_PlayBounceNoise(int k) {  // 9eedc2
+  SpriteSfx_QueueSfx3WithPan(k, 0x32);
+}
+
+void SpawnBully(int k) {  // 9eedc9
+  SpriteSpawnInfo info;
+  int j = Sprite_SpawnDynamically(k, 0xB9, &info);
+  if (j >= 0) {
+    Sprite_SetSpawnedCoordinates(j, &info);
+    sprite_subtype2[j] = 2;
+    sprite_head_dir[j] = k;
+    sprite_ignore_projectile[j] = 1;
+  }
+}
+
+void PinkBall_HandleMessage(int k) {  // 9eede8
+  if (sprite_delay_aux4[k])
+    return;
+  int msg = link_item_moon_pearl & 1 ? 0x15c : 0x15b;
+  if (Sprite_ShowMessageOnContact(k, msg) & 0x100) {
+    sprite_x_vel[k] ^= 255;
+    sprite_y_vel[k] ^= 255;
+    if (sprite_E[k])
+      BallGuy_PlayBounceNoise(k);
+    sprite_delay_aux4[k] = 64;
+  }
+}
+
+void Bully_HandleMessage(int k) {  // 9eee25
+  if (sprite_delay_aux4[k])
+    return;
+  int msg = link_item_moon_pearl & 1 ? 0x15e : 0x15d;
+  if (Sprite_ShowMessageOnContact(k, msg) & 0x100) {
+    sprite_x_vel[k] ^= 255;
+    sprite_y_vel[k] ^= 255;
+    sprite_delay_aux4[k] = 64;
+  }
+}
+
+void Sprite_BA_Whirlpool(int k) {  // 9eee5a
+  static const uint8 kWhirlpool_OamFlags[4] = {0, 0x40, 0xc0, 0x80};
+
+  if (BYTE(overworld_screen_index) == 0x1b) {
+    PrepOamCoordsRet info;
+    Sprite_PrepOamCoord(k, &info);
+    if (Sprite_ReturnIfInactive(k))
+      return;
+    uint16 x = cur_sprite_x - link_x_coord + 0x40;
+    uint16 y = cur_sprite_y - link_y_coord + 0xf;
+    if (x < 0x51 && y < 0x12) {
+      submodule_index = 35;
+      link_triggered_by_whirlpool_sprite = 1;
+      subsubmodule_index = 0;
+      link_actual_vel_y = 0;
+      link_actual_vel_x = 0;
+      link_player_handler_state = 20;
+      last_light_vs_dark_world = overworld_screen_index & 0x40;
+    }
+  } else {
+    sprite_oam_flags[k] = (sprite_oam_flags[k] & 0x3f) | kWhirlpool_OamFlags[frame_counter >> 3 & 3];
+    Oam_AllocateFromRegionB(4);
+    cur_sprite_x -= 5;
+    SpriteDraw_SingleLarge(k);
+    if (Sprite_ReturnIfInactive(k))
+      return;
+    if (Sprite_CheckDamageToLink_same_layer(k)) {
+      if (sprite_A[k] == 0) {
+        submodule_index = 46;
+        subsubmodule_index = 0;
+      }
+    } else {
+      sprite_A[k] = 0;
+    }
+  }
+}
+
+void Sprite_BB_Shopkeeper(int k) {  // 9eeeef
+  switch (sprite_subtype2[k]) {
+  case 0: Shopkeeper_StandardClerk(k); break;
+  case 1: ChestGameGuy(k); break;
+  case 2: NiceThiefWithGift(k); break;
+  case 3: MiniChestGameGuy(k); break;
+  case 4: LostWoodsChestGameGuy(k); break;
+  case 5:
+  case 6: NiceThiefUnderRock(k); break;
+  case 7: ShopItem_RedPotion150(k); break;
+  case 8: ShopItem_FighterShield(k); break;
+  case 9: ShopItem_FireShield(k); break;
+  case 10: ShopItem_Heart(k); break;
+  case 11: ShopItem_Arrows(k); break;
+  case 12: ShopItem_Bombs(k); break;
+  case 13: ShopItem_Bee(k); break;
+  }
+}
+
+void Shopkeeper_StandardClerk(int k) {  // 9eef12
+  if (is_in_dark_world) {
+    Oam_AllocateDeferToPlayer(k);
+    SpriteDraw_SingleLarge(k);
+    if (Sprite_ReturnIfInactive(k))
+      return;
+    sprite_oam_flags[k] = (sprite_oam_flags[k] & 63) | (frame_counter << 3 & 64);
+  } else {
+    sprite_oam_flags[k] = 7;
+    Shopkeeper_Draw(k);
+    if (Sprite_ReturnIfInactive(k))
+      return;
+    sprite_graphics[k] = frame_counter >> 4 & 1;
+  }
+  Sprite_BehaveAsBarrier(k);
+  int msg = is_in_dark_world == 0 ? 0x165 : 0x15f;
+  Sprite_ShowSolicitedMessage(k, msg);
+  if (sprite_ai_state[k] == 0 && (uint16)(cur_sprite_y + 0x60) >= link_y_coord) {
+    Sprite_ShowMessageUnconditional(msg);
+    sprite_ai_state[k] = 1;
+  }
+}
+
+void ChestGameGuy(int k) {  // 9eef90
+  Oam_AllocateDeferToPlayer(k);
+  SpriteDraw_SingleLarge(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  Sprite_BehaveAsBarrier(k);
+  sprite_oam_flags[k] = (sprite_oam_flags[k] & 63) | (frame_counter << 3 & 64);
+  switch (sprite_ai_state[k]) {
+  case 0:
+    if ((uint8)(minigame_credits - 1) >= 2 && Sprite_ShowSolicitedMessage(k, 0x160) & 0x100)
+      sprite_ai_state[k] = 1;
+    break;
+  case 1:
+    if (choice_in_multiselect_box == 0 && ShopItem_HandleCost(30)) {
+      minigame_credits = 2;
+      Sprite_ShowMessageUnconditional(0x164);
+      sprite_ai_state[k] = 2;
+    } else {
+      Sprite_ShowMessageUnconditional(0x161);
+      sprite_ai_state[k] = 0;
+    }
+    break;
+  case 2:
+    if (minigame_credits == 0)
+      Sprite_ShowSolicitedMessage(k, 0x163);
+    else
+      Sprite_ShowSolicitedMessage(k, 0x17f);
+    break;
+  }
+}
+
+void NiceThief_Animate(int k) {  // 9ef017
+  if (!(frame_counter & 3)) {
+    sprite_graphics[k] = 2;
+    uint8 dir = Sprite_DirectionToFaceLink(k, NULL);
+    sprite_head_dir[k] = (dir == 3) ? 2 : dir;
+  }
+  Oam_AllocateDeferToPlayer(k);
+  Thief_Draw(k);
+}
+
+void NiceThiefWithGift(int k) {  // 9ef038
+  NiceThief_Animate(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  Sprite_BehaveAsBarrier(k);
+  switch (sprite_ai_state[k]) {
+  case 0:
+    if (Sprite_ShowSolicitedMessage(k, 0x176) & 0x100)
+      sprite_ai_state[k] = 1;
+    break;
+  case 1:
+    if (!(dung_savegame_state_bits & 0x4000)) {
+      dung_savegame_state_bits |= 0x4000;
+      sprite_ai_state[k] = 2;
+      ShopItem_HandleReceipt(k, 0x46);
+    } else {
+      sprite_ai_state[k] = 0;
+    }
+    break;
+  case 2:
+    sprite_ai_state[k] = 0;
+    break;
+  }
+}
+
+void MiniChestGameGuy(int k) {  // 9ef078
+  sprite_D[k] = Sprite_DirectionToFaceLink(k, NULL) ^ 3;
+  sprite_graphics[k] = 0;
+  MazeGameGuy_Draw(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  Sprite_BehaveAsBarrier(k);
+  switch (sprite_ai_state[k]) {
+  case 0:
+    if ((uint8)(minigame_credits - 1) >= 2 && Sprite_ShowSolicitedMessage(k, 0x17e) & 0x100)
+      sprite_ai_state[k] = 1;
+    break;
+  case 1:
+    if (choice_in_multiselect_box == 0 && ShopItem_HandleCost(20)) {
+      minigame_credits = 1;
+      Sprite_ShowMessageUnconditional(0x17f);
+      sprite_ai_state[k] = 2;
+    } else {
+      Sprite_ShowMessageUnconditional(0x180);
+      sprite_ai_state[k] = 0;
+    }
+    break;
+  case 2:
+    Sprite_ShowSolicitedMessage(k, (minigame_credits == 0) ? 0x163 : 0x17f);
+    break;
+  }
+
+}
+
+void LostWoodsChestGameGuy(int k) {  // 9ef0f3
+  NiceThief_Animate(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  Sprite_BehaveAsBarrier(k);
+  switch (sprite_ai_state[k]) {
+  case 0:
+    if ((uint8)(minigame_credits - 1) >= 2 && Sprite_ShowSolicitedMessage(k, 0x181) & 0x100)
+      sprite_ai_state[k] = 1;
+    break;
+  case 1:
+    if (choice_in_multiselect_box == 0 && ShopItem_HandleCost(100)) {
+      minigame_credits = 1;
+      Sprite_ShowMessageUnconditional(0x17f);
+      sprite_ai_state[k] = 2;
+    } else {
+      Sprite_ShowMessageUnconditional(0x180);
+      sprite_ai_state[k] = 0;
+    }
+    break;
+  case 2:
+    Sprite_ShowSolicitedMessage(k, (minigame_credits == 0) ? 0x163 : 0x17f);
+    break;
+  }
+}
+
+void NiceThiefUnderRock(int k) {  // 9ef14f
+  NiceThief_Animate(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  Sprite_BehaveAsBarrier(k);
+  Sprite_ShowSolicitedMessage(k, sprite_subtype2[k] == 5 ? 0x177 : 0x178);
+}
+
+void ShopItem_RedPotion150(int k) {  // 9ef16e
+  SpriteDraw_ShopItem(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  Sprite_BehaveAsBarrier(k);
+  if (ShopItem_CheckForAPress(k)) {
+    if (Sprite_Find_EmptyBottle() < 0) {
+      Sprite_ShowMessageUnconditional(0x16d);
+      ShopItem_PlayBeep(k);
+    } else if (ShopItem_HandleCost(150)) {
+      sprite_state[k] = 0;
+      ShopItem_HandleReceipt(k, 0x2e);
+    } else {
+      Sprite_ShowMessageUnconditional(0x17c);
+      ShopItem_PlayBeep(k);
+    }
+  }
+}
+
+void ShopKeeper_SpawnShopItem(int k, int pos, int what) {  // 9ef1b3
+  static const int8 kShopKeeper_ItemX[3] = {-44, 8, 60};
+  SpriteSpawnInfo info;
+  int j = Sprite_SpawnDynamicallyEx(k, 0xbb, &info, 12);
+  assert(j >= 0);
+  sprite_ignore_projectile[j] = sprite_subtype2[j] = what;
+  Sprite_SetX(j, info.r0_x + kShopKeeper_ItemX[pos]);
+  Sprite_SetY(j, info.r2_y + 0x27);
+  sprite_flags2[j] |= 4;
+}
+
+void ShopItem_FighterShield(int k) {  // 9ef1f2
+  SpriteDraw_ShopItem(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  Sprite_BehaveAsBarrier(k);
+  ShopItem_MakeShieldsDeflect(k);
+  if (ShopItem_CheckForAPress(k)) {
+    if (link_shield_type) {
+      Sprite_ShowMessageUnconditional(0x166);
+      ShopItem_PlayBeep(k);
+      return;
+    }
+    if (!ShopItem_HandleCost(50)) {
+      Sprite_ShowMessageUnconditional(0x17c);
+      ShopItem_PlayBeep(k);
+      return;
+    }
+    sprite_state[k] = 0;
+    ShopItem_HandleReceipt(k, 4);
+  }
+  sprite_flags4[k] = 0x1c;
+}
+
+void ShopItem_FireShield(int k) {  // 9ef230
+  SpriteDraw_ShopItem(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  Sprite_BehaveAsBarrier(k);
+  ShopItem_MakeShieldsDeflect(k);
+  if (ShopItem_CheckForAPress(k)) {
+    if (link_shield_type >= 2) {
+      Sprite_ShowMessageUnconditional(0x166);
+      ShopItem_PlayBeep(k);
+      return;
+    }
+    if (!ShopItem_HandleCost(500)) {
+      Sprite_ShowMessageUnconditional(0x17c);
+      ShopItem_PlayBeep(k);
+      return;
+    }
+    sprite_state[k] = 0;
+    ShopItem_HandleReceipt(k, 5);
+  }
+  sprite_flags4[k] = 0x1c;
+}
+
+void ShopItem_MakeShieldsDeflect(int k) {  // 9ef261
+  sprite_ignore_projectile[k] = 0;
+  sprite_flags[k] = 8;
+  sprite_defl_bits[k] = 4;
+  sprite_flags4[k] = 0x1c;
+  Sprite_CheckDamageFromLink(k);
+  sprite_flags4[k] = 0xa;
+}
+
+void ShopItem_Heart(int k) {  // 9ef27d
+  SpriteDraw_ShopItem(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  Sprite_BehaveAsBarrier(k);
+  if (ShopItem_CheckForAPress(k)) {
+    if (link_health_current == link_health_capacity) {
+      ShopItem_PlayBeep(k);
+    } else if (ShopItem_HandleCost(10)) {
+      sprite_state[k] = 0;
+      ShopItem_HandleReceipt(k, 0x42);
+    } else {
+      Sprite_ShowMessageUnconditional(0x17c);
+      ShopItem_PlayBeep(k);
+    }
+  }
+}
+
+void ShopItem_Arrows(int k) {  // 9ef2af
+  SpriteDraw_ShopItem(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  Sprite_BehaveAsBarrier(k);
+  if (ShopItem_CheckForAPress(k)) {
+    if (link_num_arrows == kMaxArrowsForLevel[link_arrow_upgrades]) {
+      Sprite_ShowSolicitedMessage(k, 0x16e);
+      ShopItem_PlayBeep(k);
+    } else if (ShopItem_HandleCost(30)) {
+      sprite_state[k] = 0;
+      ShopItem_HandleReceipt(k, 0x44);
+    } else {
+      Sprite_ShowMessageUnconditional(0x17c);
+      ShopItem_PlayBeep(k);
+    }
+  }
+}
+
+void ShopItem_Bombs(int k) {  // 9ef2f0
+  SpriteDraw_ShopItem(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  Sprite_BehaveAsBarrier(k);
+  if (ShopItem_CheckForAPress(k)) {
+    if (link_item_bombs == kMaxBombsForLevel[link_bomb_upgrades]) {
+      Sprite_ShowSolicitedMessage(k, 0x16e);
+      ShopItem_PlayBeep(k);
+    } else if (ShopItem_HandleCost(50)) {
+      sprite_state[k] = 0;
+      ShopItem_HandleReceipt(k, 0x31);
+    } else {
+      Sprite_ShowMessageUnconditional(0x17c);
+      ShopItem_PlayBeep(k);
+    }
+  }
+}
+
+void ShopItem_Bee(int k) {  // 9ef322
+  SpriteDraw_ShopItem(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  Sprite_BehaveAsBarrier(k);
+  if (ShopItem_CheckForAPress(k)) {
+    if (Sprite_Find_EmptyBottle() < 0) {
+      Sprite_ShowSolicitedMessage(k, 0x16d);
+      ShopItem_PlayBeep(k);
+    } else if (ShopItem_HandleCost(10)) {
+      sprite_state[k] = 0;
+      ShopItem_HandleReceipt(k, 0xe);
+    } else {
+      Sprite_ShowMessageUnconditional(0x17c);
+      ShopItem_PlayBeep(k);
+    }
+  }
+}
+
+void ShopItem_HandleReceipt(int k, uint8 item) {  // 9ef366
+  static const uint16 kShopKeeper_GiveItemMsgs[7] = {0x168, 0x167, 0x167, 0x16c, 0x169, 0x16a, 0x16b};
+  item_receipt_method = 0;
+  Link_ReceiveItem(item, 0);
+  int j = sprite_subtype2[k];
+  if (j >= 7) {
+    Sprite_ShowMessageUnconditional(kShopKeeper_GiveItemMsgs[j - 7]);
+    ShopKeeper_RapidTerminateReceiveItem();
+  }
+}
+
+void ShopItem_PlayBeep(int k) {  // 9ef38a
+  SpriteSfx_QueueSfx2WithPan(k, 0x3c);
+}
+
+bool ShopItem_CheckForAPress(int k) {  // 9ef391
+  if (!(filtered_joypad_L & 0x80))
+    return false;
+  return Sprite_CheckDamageToLink_same_layer(k);
+}
+
+bool ShopItem_HandleCost(int amt) {  // 9ef39e
+  if (amt > link_rupees_goal)
+    return false;
+  link_rupees_goal -= amt;
+  return true;
+}
+
+void SpriteDraw_ShopItem(int k) {  // 9ef4ce
+  static const DrawMultipleData kShopKeeper_ItemWithPrice_Dmd[35] = {
+    {-4, 16, 0x0231, 0},
+    { 4, 16, 0x0213, 0},
+    {12, 16, 0x0230, 0},
+    { 0,  0, 0x02c0, 2},
+    { 0, 11, 0x036c, 2},
+    { 0, 16, 0x0213, 0},
+    { 0, 16, 0x0213, 0},
+    { 8, 16, 0x0230, 0},
+    { 0,  0, 0x04ce, 2},
+    { 4, 12, 0x0338, 0},
+    {-4, 16, 0x0213, 0},
+    { 4, 16, 0x0230, 0},
+    {12, 16, 0x0230, 0},
+    { 0,  0, 0x08cc, 2},
+    { 4, 12, 0x0338, 0},
+    { 0, 16, 0x0231, 0},
+    { 0, 16, 0x0231, 0},
+    { 8, 16, 0x0230, 0},
+    { 4,  8, 0x0329, 0},
+    { 4, 11, 0x0338, 0},
+    {-4, 16, 0x0203, 0},
+    {-4, 16, 0x0203, 0},
+    { 4, 16, 0x0230, 0},
+    { 0,  0, 0x04c4, 2},
+    { 0, 11, 0x0338, 0},
+    { 0, 16, 0x0213, 0},
+    { 0, 16, 0x0213, 0},
+    { 8, 16, 0x0230, 0},
+    { 0,  0, 0x04e8, 2},
+    { 0, 11, 0x036c, 2},
+    { 0, 16, 0x0231, 0},
+    { 0, 16, 0x0231, 0},
+    { 8, 16, 0x0230, 0},
+    { 4,  8, 0x0ff4, 0},
+    { 4, 11, 0x0338, 0},
+  };
+  Sprite_DrawMultiplePlayerDeferred(k, &kShopKeeper_ItemWithPrice_Dmd[(sprite_subtype2[k] - 7) * 5], 5, NULL);
+}
+
+void Sprite_AC_Apple(int k) {  // 9ef515
+  if (sprite_ai_state[k]) {
+    Sprite_Apple(k);
+    return;
+  }
+  if (sprite_E[k] == 0) {
+    sprite_state[k] = 0;
+    int n = (GetRandomNumber() & 3) + 2;
+    do {
+      SpawnApple(k);
+    } while (--n >= 0);
+  }
+}
+
+void SpawnApple(int k) {  // 9ef535
+  SpriteSpawnInfo info;
+  int j = Sprite_SpawnDynamically(k, 0xac, &info);
+  if (j < 0)
+    return;
+  Sprite_SetSpawnedCoordinates(j, &info);
+  sprite_ai_state[j] = 1;
+  sprite_A[j] = 255;
+  sprite_z[j] = 8;
+  sprite_z_vel[j] = 22;
+  uint16 x = info.r0_x & ~0xff | GetRandomNumber();
+  uint16 y = info.r2_y & ~0xff | GetRandomNumber();
+  ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLocation(k, x, y, 10);
+  sprite_x_vel[j] = pt.x;
+  sprite_y_vel[j] = pt.y;
+}
+
+void Sprite_Apple(int k) {  // 9ef57c
+  if (sprite_A[k] >= 16 || frame_counter & 2)
+    SpriteDraw_SingleLarge(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  if (sprite_A[k] == 0) {
+    sprite_state[k] = 0;
+    return;
+  }
+  Sprite_MoveXYZ(k);
+  if (Sprite_CheckDamageToLink(k)) {
+    SpriteSfx_QueueSfx3WithPan(k, 0xb);
+    link_hearts_filler += 8;
+    sprite_state[k] = 0;
+    return;
+  }
+  if (!(frame_counter & 1))
+    sprite_A[k]--;
+
+  if (!sign8(sprite_z[k] - 1)) {
+    sprite_z_vel[k] -= 1;
+    return;
+  }
+  sprite_z[k] = 0;
+  uint8 a = sign8(sprite_z_vel[k]) ? sprite_z_vel[k] : 0;
+  sprite_z_vel[k] = (uint8)(-a) >> 1;
+  if (sprite_x_vel[k])
+    sprite_x_vel[k] += sign8(sprite_x_vel[k]) ? 1 : -1;
+  if (sprite_y_vel[k])
+    sprite_y_vel[k] += sign8(sprite_y_vel[k]) ? 1 : -1;
+}
+
+void Sprite_BC_Drunkard(int k) {  // 9ef603
+  DrinkingGuy_Draw(k);
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  Sprite_BehaveAsBarrier(k);
+  if (!GetRandomNumber())
+    sprite_delay_main[k] = 32;
+  sprite_graphics[k] = sprite_delay_main[k] ? 1 : 0;
+  if (Sprite_ShowSolicitedMessage(k, 0x175) & 0x100)
+    sprite_graphics[k] = 0;
+}
+
+void SomariaPlatform_LocatePath(int k) {  // 9ef640
+  for (;;) {
+    uint8 tiletype = SomariaPlatformAndPipe_CheckTile(k);
+    sprite_E[k] = tiletype;
+    if (tiletype >= 0xb0 && tiletype < 0xbf)
+      break;
+    Sprite_SetX(k, Sprite_GetX(k) + 8);
+    Sprite_SetY(k, Sprite_GetY(k) + 8);
+  }
+  sprite_x_lo[k] = (sprite_x_lo[k] & ~7) + 4;
+  sprite_y_lo[k] = (sprite_y_lo[k] & ~7) + 4;
+  sprite_head_dir[k] = sprite_D[k];
+  SomariaPlatformAndPipe_HandleMovement(k);
+  sprite_ignore_projectile[k]++;
+  player_on_somaria_platform = 0;
+  sprite_delay_aux4[k] = 14;
+  sprite_graphics[k]++;
+}
+
+void Sprite_ED_SomariaPlatform(int k) {  // 9ef6d4
+  switch(sprite_graphics[k]) {
+  case 0: {
+    SomariaPlatform_LocatePath(k);
+    int j = Sprite_SpawnSuperficialBombBlast(k);
+    if (j >= 0) {
+      Sprite_SetX(j, Sprite_GetX(j) - 8);
+      Sprite_SetY(j, Sprite_GetY(j) - 8);
+    }
+    break;
+  }
+  case 1:
+    SomariaPlatform_Draw(k);
+    if (Sprite_ReturnIfInactive(k))
+      return;
+    if (!(drag_player_x | drag_player_y) && sign8(player_near_pit_state - 2) && Sprite_CheckDamageToLink_ignore_layer(k)) {
+      sprite_C[k] = 1;
+      Link_CancelDash();
+      if (link_player_handler_state != kPlayerState_Hookshot && link_player_handler_state != kPlayerState_SpinAttacking) {
+        if (sprite_ai_state[k]) {
+          SomariaPlatformAndPipe_HandleMovement(k);
+          return;
+        }
+        sprite_A[k]++;
+        player_on_somaria_platform = 2;
+        if (!(sprite_A[k] & 7)) {
+          uint8 a = SomariaPlatformAndPipe_CheckTile(k);
+          if (a != sprite_E[k]) {
+            sprite_E[k] = a;
+            sprite_head_dir[k] = sprite_D[k];
+            SomariaPlatformAndPipe_HandleMovement(k);
+            SomariaPlatform_HandleDrag(k);
+          }
+        }
+        if (BYTE(dungeon_room_index) != 36) {
+          static const int8 kSomariaPlatform_DragX[8] = {0, 0, -1, 1, -1, 1, 1, -1};
+          static const int8 kSomariaPlatform_DragY[8] = {-1, 1, 0, 0, -1, 1, -1, 1};
+          int j = sprite_D[k];
+          drag_player_x += kSomariaPlatform_DragX[j];
+          drag_player_y += kSomariaPlatform_DragY[j];
+          Sprite_MoveXY(k);
+          SomariaPlatform_DragLink(k);
+        } else {
+          player_on_somaria_platform = 1;
+        }
+        return;
+      }
+    }
+    if (sprite_C[k]) {
+      player_on_somaria_platform = 0;
+      sprite_C[k] = 0;
+    }
+    break;
+  }
+}
+
+void SomariaPlatformAndPipe_HandleMovement(int k) {  // 9ef7af
+  static const int8 kSomariaPlatform_Xvel[8] = {0, 0, -16, 16, -16, 16, 16, -16};
+  static const int8 kSomariaPlatform_Yvel[8] = {-16, 16, 0, 0, -16, 16, -16, 16};
+  SomariaPlatform_HandleJunctions(k);
+  int j = sprite_D[k];
+  sprite_x_vel[k] = kSomariaPlatform_Xvel[j];
+  sprite_y_vel[k] = kSomariaPlatform_Yvel[j];
+}
+
+uint8 SomariaPlatformAndPipe_CheckTile(int k) {  // 9ef7c2
+  uint16 x = Sprite_GetX(k), y = Sprite_GetY(k);
+  return GetTileAttribute(0, &x, y);
+}
+
+void SomariaPlatform_Draw(int k) {  // 9ef860
+  static const DrawMultipleData kSomariaPlatform_Dmd[16] = {
+    {-16, -16, 0x00ac, 2},
+    {  0, -16, 0x40ac, 2},
+    {-16,   0, 0x80ac, 2},
+    {  0,   0, 0xc0ac, 2},
+    {-13, -13, 0x00ac, 2},
+    { -3, -13, 0x40ac, 2},
+    {-13,  -3, 0x80ac, 2},
+    { -3,  -3, 0xc0ac, 2},
+    {-10, -10, 0x00ac, 2},
+    { -6, -10, 0x40ac, 2},
+    {-10,  -6, 0x80ac, 2},
+    { -6,  -6, 0xc0ac, 2},
+    { -8,  -8, 0x00ac, 2},
+    { -8,  -8, 0x40ac, 2},
+    { -8,  -8, 0x80ac, 2},
+    { -8,  -8, 0xc0ac, 2},
+  };
+  Oam_AllocateFromRegionB(0x10);
+  Sprite_DrawMultiple(k, &kSomariaPlatform_Dmd[sprite_delay_aux4[k] & 12], 4, NULL);
+}
+
+void SomariaPlatform_HandleJunctions(int k) {  // 9ef87d
+  switch (sprite_E[k]) {
+  case 0xb2:
+  case 0xb5:  // ZigZagRisingSlope
+    sprite_D[k] ^= 3;
+    break;
+  case 0xb3:
+  case 0xb4:  // ZigZagFallingSlope
+    sprite_D[k] ^= 2;
+    break;
+  case 0xb6: { // TransitTile
+    static const uint8 kSomariaPlatform_TransitDir[4] = {4, 8, 1, 2};
+    sprite_ai_state[k] = 1;
+    if (!link_auxiliary_state && joypad1H_last & kSomariaPlatform_TransitDir[sprite_D[k]]) {
+      sprite_ai_state[k] = 0;
+      sprite_D[k] ^= 1;
+    }
+    link_visibility_status = 0;
+    player_on_somaria_platform = 1;
+    break;
+  }
+  case 0xb7: {  // Tjunc_NoUp
+    static const uint8 kSomariaPlatform_Keys1[4] = {3, 7, 6, 5};
+    uint8 t = joypad1H_last & kSomariaPlatform_Keys1[sprite_D[k]];
+    if (t & 8) {
+      sprite_D[k] = 0;
+    } else if (t & 4) {
+      sprite_D[k] = 1;
+    } else if (t & 2) {
+      sprite_D[k] = 2;
+    } else if (t & 1) {
+      sprite_D[k] = 3;
+    } else if (sprite_D[k] == 0) {
+      sprite_D[k] = 2;
+    }
+    sprite_ai_state[k] = 0;
+    break;
+  }
+  case 0xb8: {  // Tjunc_NoDown
+    static const uint8 kSomariaPlatform_Keys2[4] = {11, 3, 10, 9};
+    uint8 t = joypad1H_last & kSomariaPlatform_Keys2[sprite_D[k]];
+    if (t & 8) {
+      sprite_D[k] = 0;
+    } else if (t & 4) {
+      sprite_D[k] = 1;
+    } else if (t & 2) {
+      sprite_D[k] = 2;
+    } else if (t & 1) {
+      sprite_D[k] = 3;
+    } else if (sprite_D[k] == 1) {
+      sprite_D[k] = 2;
+    }
+    sprite_ai_state[k] = 0;
+    break;
+  }
+  case 0xb9: {  // Tjunc_NoLeft
+    static const uint8 kSomariaPlatform_Keys3[4] = {9, 5, 12, 13};
+    uint8 t = joypad1H_last & kSomariaPlatform_Keys3[sprite_D[k]];
+    if (t & 8) {
+      sprite_D[k] = 0;
+    } else if (t & 4) {
+      sprite_D[k] = 1;
+    } else if (t & 2) {
+      sprite_D[k] = 2;
+    } else if (t & 1) {
+      sprite_D[k] = 3;
+    } else if (sprite_D[k] == 2) {
+      sprite_D[k] = 0;
+    }
+    sprite_ai_state[k] = 0;
+    break;
+  }
+  case 0xba: {  // Tjunc_NoRight
+    static const uint8 kSomariaPlatform_Keys4[4] = {0xa, 6, 0xe, 0xc};
+    uint8 t = joypad1H_last & kSomariaPlatform_Keys4[sprite_D[k]];
+    if (t & 8) {
+      sprite_D[k] = 0;
+    } else if (t & 4) {
+      sprite_D[k] = 1;
+    } else if (t & 2) {
+      sprite_D[k] = 2;
+    } else if (t & 1) {
+      sprite_D[k] = 3;
+    } else if (sprite_D[k] == 3) {
+      sprite_D[k] = 0;
+    }
+    sprite_ai_state[k] = 0;
+    break;
+  }
+  case 0xbb: {  // TransitTileNoBack
+    static const uint8 kSomariaPlatform_Keys5[4] = {0xb, 7, 0xe, 0xd};
+    uint8 t = joypad1H_last & kSomariaPlatform_Keys5[sprite_D[k]];
+    if (t & 8) {
+      sprite_D[k] = 0;
+    } else if (t & 4) {
+      sprite_D[k] = 1;
+    } else if (t & 2) {
+      sprite_D[k] = 2;
+    } else if (t & 1) {
+      sprite_D[k] = 3;
+    }
+    break;
+  }
+  case 0xbc: {  // TransitTileQuestion
+    static const uint8 kSomariaPlatform_Keys6[4] = {0xc, 0xc, 3, 3};
+    sprite_ai_state[k] = 1;
+    uint8 t = joypad1H_last & kSomariaPlatform_Keys6[sprite_D[k]];
+    if (t) {
+      if (t & 8) {
+        sprite_D[k] = 0;
+      } else if (t & 4) {
+        sprite_D[k] = 1;
+      } else if (t & 2) {
+        sprite_D[k] = 2;
+      } else {
+        sprite_D[k] = 3;
+      }
+      sprite_ai_state[k] = 0;
+    }
+    player_on_somaria_platform = 1;
+    break;
+  }
+  case 0xbe:  // endpoint
+    sprite_ai_state[k] = 0;
+    sprite_D[k] ^= 1;
+    link_visibility_status = 0;
+    player_on_somaria_platform = 1;
+    break;
+  }
+}
+
+void SomariaPlatform_HandleDragX(int k) {  // 9ef8ad
+  if ((sprite_D[k] ^ sprite_head_dir[k]) & 2) {
+    uint8 x = (sprite_x_lo[k] & ~7) + 4;
+    uint8 t = x - sprite_x_lo[k];
+    if (!t)
+      return;
+    drag_player_x = (int8)t;
+    sprite_x_lo[k] = x;
+  }
+}
+
+void SomariaPlatform_HandleDragY(int k) {  // 9ef8d7
+  if ((sprite_D[k] ^ sprite_head_dir[k]) & 2) {
+    uint8 y = (sprite_y_lo[k] & ~7) + 4;
+    uint8 t = y - sprite_y_lo[k];
+    if (!t)
+      return;
+    drag_player_y = (int8)t;
+    sprite_y_lo[k] = y;
+  }
+}
+
+void SomariaPlatform_HandleDrag(int k) {  // 9ef901
+  SomariaPlatform_HandleDragX(k);
+  SomariaPlatform_HandleDragY(k);
+}
+
+void SomariaPlatform_DragLink(int k) {  // 9efb49
+  uint16 x = cur_sprite_x - 8 - link_x_coord;
+  if (x)
+    drag_player_x += sign16(x) ? -1 : 1;
+  uint16 y = cur_sprite_y - 16 - link_y_coord;
+  if (y)
+    drag_player_y += sign16(y) ? -1 : 1;
+}
+
+void Sprite_AE_Pipe_Down(int k) {  // 9efb7e
+  static const uint8 kPipe_Dirs[4] = {8, 4, 2, 1};
+
+  uint8 t;
+  if (Sprite_ReturnIfInactive(k))
+    return;
+  switch(sprite_graphics[k]) {
+  case 0:  // locate transit tile
+    alt_sprite_spawned_flag[0] = 255;
+    sprite_D[k] = sprite_type[k] - 0xae;
+    SomariaPlatform_LocatePath(k);
+    break;
+  case 1:  // locate endpoint
+    t = SomariaPlatformAndPipe_CheckTile(k);
+    if (t == 0xbe) {
+      sprite_graphics[k]++;
+      t = (sprite_D[k] ^= 1);
+    }
+    sprite_E[k] = t;
+    sprite_head_dir[k] = sprite_D[k];
+    SomariaPlatformAndPipe_HandleMovement(k);
+    Sprite_MoveXY(k);
+    break;
+  case 2:  // wait for player
+    if (alt_sprite_spawned_flag[0] == 255 && Sprite_CheckDamageToLink_ignore_layer(k)) {
+      if (!Pipe_ValidateEntry()) {
+        sprite_graphics[k]++;
+        sprite_delay_aux1[k] = 4;
+        Link_ResetProperties_A();
+        flag_is_link_immobilized = 1;
+        link_disable_sprite_damage = 1;
+        alt_sprite_spawned_flag[0] = k;
+      } else {
+        Sprite_HaltAllMovement();
+      }
+    }
+    break;
+  case 3:  // draw player in
+    if (!sprite_delay_aux1[k]) {
+      sprite_graphics[k]++;
+      link_visibility_status = 12;
+    } else {
+      flag_is_link_immobilized = 1;
+      link_disable_sprite_damage = 1;
+      Pipe_HandlePlayerMovement(kPipe_Dirs[sprite_D[k]]);
+    }
+    break;
+  case 4: {  // draw player along
+    sprite_subtype2[k] = 3;
+    link_x_coord_safe_return_lo = link_x_coord;
+    link_x_coord_safe_return_hi = link_x_coord >> 8;
+    link_y_coord_safe_return_lo = link_y_coord;
+    link_y_coord_safe_return_hi = link_y_coord >> 8;
+    do {
+      if (!(++sprite_A[k] & 7)) {
+        uint8 t = SomariaPlatformAndPipe_CheckTile(k);
+        if (t >= 0xb2 && t < 0xb6)
+          SpriteSfx_QueueSfx2WithPan(k, 0xb);
+        if (t != sprite_E[k]) {
+          sprite_E[k] = t;
+          if (t == 0xbe) {
+            sprite_graphics[k]++;
+            sprite_delay_aux1[k] = 24;
+          }
+          sprite_head_dir[k] = sprite_D[k];
+          SomariaPlatformAndPipe_HandleMovement(k);
+          SomariaPlatform_HandleDrag(k);
+        }
+      }
+      Sprite_MoveXY(k);
+      uint16 x = Sprite_GetX(k) - 8;
+      uint16 y = Sprite_GetY(k) - 14;
+      if (x != link_x_coord)
+        link_x_coord += (x < link_x_coord) ? -1 : 1;
+      if (y != link_y_coord)
+        link_y_coord += (y < link_y_coord) ? -1 : 1;
+    } while (--sprite_subtype2[k]);
+    link_x_vel = link_x_coord - link_x_coord_safe_return_lo;
+    link_y_vel = link_y_coord - link_y_coord_safe_return_lo;
+    link_direction_last = kPipe_Dirs[sprite_D[k]];
+    Link_HandleMovingAnimation_FullLongEntry();
+    HandleIndoorCameraAndDoors();
+    Link_CancelDash();
+    break;
+  }
+  case 5:  //
+    if (!sprite_delay_aux1[k]) {
+      flag_is_link_immobilized = 0;
+      player_on_somaria_platform = 0;
+      link_disable_sprite_damage = 0;
+      link_visibility_status = 0;
+      link_x_vel = link_y_vel = 0;
+      alt_sprite_spawned_flag[0] = 255;
+      sprite_graphics[k] = 2;
+    } else {
+      Pipe_HandlePlayerMovement(kPipe_Dirs[sprite_D[k] ^ 1]);
+    }
+    break;
+  }
+}
+
+void Pipe_HandlePlayerMovement(uint8 dir) {  // 9efcff
+  link_direction_last = link_direction = dir;
+  Link_HandleVelocity();
+  Link_HandleMovingAnimation_FullLongEntry();
+  HandleIndoorCameraAndDoors();
+}
+
+void Faerie_HandleMovement(int k) {  // 9efd1c
+  sprite_graphics[k] = frame_counter >> 3 & 1;
+  if (player_is_indoors && !sprite_delay_aux1[k]) {
+    if (Sprite_CheckTileCollision(k) & 3) {
+      sprite_x_vel[k] = -sprite_x_vel[k];
+      sprite_D[k] = -sprite_D[k];
+      sprite_delay_aux1[k] = 32;
+    }
+    if (sprite_wallcoll[k] & 12) {
+      sprite_y_vel[k] = -sprite_y_vel[k];
+      sprite_A[k] = -sprite_A[k];
+      sprite_delay_aux1[k] = 32;
+    }
+  }
+  if (sprite_x_vel[k]) {
+    if (sign8(sprite_x_vel[k]))
+      sprite_oam_flags[k] &= ~0x40;
+    else
+      sprite_oam_flags[k] |= 0x40;
+  }
+  Sprite_MoveXY(k);
+  if (!(frame_counter & 63)) {
+    uint16 x = (link_x_coord & ~0xff) + GetRandomNumber();
+    uint16 y = (link_y_coord & ~0xff) + GetRandomNumber();
+    ProjectSpeedRet pt = Sprite_ProjectSpeedTowardsLocation(k, x, y, 16);
+    sprite_A[k] = pt.y;
+    sprite_D[k] = pt.x;
+  }
+  if (!(frame_counter & 15)) {
+    sprite_y_vel[k] = ((int8)sprite_A[k] + (int8)sprite_y_vel[k]) >> 1;
+    sprite_x_vel[k] = ((int8)sprite_D[k] + (int8)sprite_x_vel[k]) >> 1;
+  }
+  Sprite_MoveZ(k);
+  sprite_z_vel[k] += (GetRandomNumber() & 1) ? -1 : 1;
+  if (sprite_z[k] < 8) {
+    sprite_z[k] = 8;
+    sprite_z_vel[k] = 5;
+  } else if (sprite_z[k] >= 24) {
+    sprite_z[k] = 24;
+    sprite_z_vel[k] = -5;
+  }
+}
+
--- /dev/null
+++ b/src/sprite_main.h
@@ -1,0 +1,953 @@
+#pragma once
+#include "types.h"
+#include "sprite.h"
+
+void Sprite_PullSwitch_bounce(int k);
+void GiantMoldorm_DrawSegment_AB(int k, int lookback);
+void GiantMoldorm_DrawSegment_C_OrTail(int k, int lookback);
+void Chicken_IncrSubtype2(int k, int j);
+bool Octoballoon_Find();
+bool FluteBoy_CheckIfPlayerClose(int k);
+void FortuneTeller_LightOrDarkWorld(int k, bool dark_world);
+int GarnishAllocForce();
+int GarnishAlloc();
+int GarnishAllocLow();
+int GarnishAllocLimit(int k);
+int GarnishAllocOverwriteOldLow();
+int GarnishAllocOverwriteOld();
+void Garnish_SetX(int k, uint16 x);
+void Garnish_SetY(int k, uint16 y);
+void Sprite_WishPond3(int k);
+int Sprite_SpawnSmallSplash(int k);
+void HeartUpgrade_CheckIfAlreadyObtained(int k);
+void Sprite_EE_MovableMantle(int k);
+void Sprite_GoodOrBadArcheryTarget(int k);
+void ChainBallTrooper_Draw(int k);
+void Sprite_6B_CannonTrooper(int k);
+void Bee_PutInBottle(int k);
+void Sprite_Wizzbeam(int k);
+void Kiki_LyingInwait(int k);
+int ChainChomp_OneMult(uint8 a, uint8 b);
+void Sprite_CC(int k);
+void Sprite_CD(int k);
+void SpritePrep_IncrXYLow8(int k);
+void SpritePrep_FakeSword(int k);
+void SpritePrep_MedallionTable(int k);
+void Hobo_Draw(int k);
+bool Landmine_CheckDetonationFromHammer(int k);
+void Sprite_DrawLargeWaterTurbulence(int k);
+void Sprite_SpawnSparkleGarnish(int k);
+void Sprite_70_KingHelmasaurFireball(int k);
+void Sprite_66_WallCannonVerticalLeft(int k);
+void Sprite_65_ArcheryGame(int k);
+void ArcheryGame_Host(int k);
+void ArcheryGameGuy_ShowMsg(int k, int msg);
+void ArcheryGame_Host_ProctorGame(int k);
+void ArcheryGame_DrawPrize(int k);
+void Sprite_63_DebirandoPit(int k);
+void DebirandoPit_Draw(int k);
+void Sprite_64_Debirando(int k);
+void Debirando_Draw(int k);
+void Sprite_62_MasterSword(int k);
+void MasterSword_Main(int k);
+void Sprite_MasterSword_LightFountain(int k);
+void Sprite_MasterSword_LightWell(int k);
+void SpriteDraw_LightFountain(int k);
+void MasterSword_SpawnLightWell(int k);
+void MasterSword_SpawnLightFountain(int k);
+void Sprite_MasterSword_LightBeam(int k);
+void MasterSword_SpawnReplacementLightBeam(int k);
+void MasterSword_SpawnLightBeam(int k, uint8 ain, uint8 yin);
+void MasterSword_SpawnPendantProp(int k, uint8 ain);
+void Sprite_MasterSword_Prop(int k);
+void MasterSword_Draw(int k);
+void Sprite_5D_Roller_VerticalDownFirst(int k);
+void SpikeRoller_Draw(int k);
+void Sprite_61_Beamos(int k);
+void Beamos_FireLaser(int k);
+void Beamos_Draw(int k);
+void SpriteDraw_Beamos_Eyeball(int k, PrepOamCoordsRet *info);
+void Sprite_Beamos_Laser(int k);
+void BeamosLaser_Draw(int k);
+void Sprite_Beamos_LaserHit(int k);
+void Sprite_5B_Spark_Clockwise(int k);
+void Sprite_59_LostWoodsBird(int k);
+void Sprite_5A_LostWoodsSquirrel(int k);
+void Sprite_58_Crab(int k);
+void Crab_Draw(int k);
+void Sprite_57_DesertStatue(int k);
+void DesertBarrier_Draw(int k);
+void Sprite_55_Zora(int k);
+void Sprite_Fireball(int k);
+void Sprite_Zora_Main(int k);
+void Zora_Draw(int k);
+void Sprite_52_KingZora(int k);
+void Sprite_SpawnBigSplash(int k);
+void ZoraKing_Draw(int k);
+void Sprite_56_WalkingZora(int k);
+void WalkingZora_AdjustShadow(int k);
+void WalkingZora_Draw(int k);
+void WalkingZora_DrawWaterRipples(int k);
+void SpriteDraw_WaterRipple_WithOamAdjust(int k);
+void SpriteDraw_WaterRipple(int k);
+void Sprite_53_ArmosKnight(int k);
+void ArmosKnight_Draw(int k);
+void Sprite_54_Lanmolas(int k);
+void Lanmola_Draw(int k);
+void Sprite_6D_Rat(int k);
+void Sprite_6E_Rope(int k);
+void Sprite_6F_Keese(int k);
+void Sprite_Cannonball(int k);
+void Sprite_SpawnPoofGarnish(int j);
+void Sprite_6C_MirrorPortal(int k);
+void Sprite_6A_BallNChain(int k);
+void BallNChain_Animate(int k);
+void SpriteDraw_GuardHead(int k, PrepOamCoordsRet *info, int spr_offs);
+void SpriteDraw_BNCBody(int k, PrepOamCoordsRet *info, int spr_offs);
+void SpriteDraw_BNCFlail(int k, PrepOamCoordsRet *info);
+void Sprite_50_Cannonball(int k);
+void SpriteDraw_BigCannonball(int k);
+void Sprite_51_ArmosStatue(int k);
+void Armos_Draw(int k);
+void Sprite_4E_Popo(int k);
+void Bot_Draw(int k);
+void Sprite_4C_Geldman(int k);
+void GerudoMan_Draw(int k);
+void Sprite_4D_Toppo(int k);
+void Toppo_VerifyTile(int k);
+void Toppo_Draw(int k);
+void Sprite_4B_GreenKnifeGuard(int k);
+void GreenKnifeGuard_Moving(int k);
+void Recruit_Draw(int k);
+void Sprite_4A_BombGuard(int k);
+void SpriteBomb_CheckDamageToSprite(int k, int j);
+void SpriteBomb_ExplosionIncoming(int k);
+void BombGuard(int k);
+void BombGuard_CreateBomb(int k);
+void BombTrooper_Draw(int k);
+void SpriteDraw_BombGuard_Arm(int k, PrepOamCoordsRet *info);
+void SpriteDraw_SpriteBombExplosion(int k);
+void Sprite_41_BlueGuard(int k);
+void Probe(int k);
+void Guard_Main(int k);
+void Guard_SetGlanceTo12(int k);
+void Guard_ShootProbeAndStuff(int k);
+void Guard_TickAndUpdateBody(int k);
+void Guard_SetTimerAndAssertTileHitBox(int k, uint8 a);
+void Soldier_Func12(int k);
+void Guard_ApplySpeedInDirection(int k);
+void Sprite_Guard_SendOutProbe(int k);
+void Sprite_SpawnProbeAlways(int k, uint8 r15);
+void Guard_HandleAllAnimation(int k);
+void Guard_AnimateHead(int k, int oam_offs, const PrepOamCoordsRet *poc);
+void Guard_AnimateBody(int k, int oam_idx, const PrepOamCoordsRet *poc);
+void Guard_AnimateWeapon(int k, const PrepOamCoordsRet *poc);
+void Sprite_45_HogSpearMan(int k);
+void BoltGuard_TriggerChaseTheme(int k);
+void Sprite_44_BluesainBolt(int k);
+void PsychoTrooper_Draw(int k);
+void SpriteDraw_GuardSpear(int k, PrepOamCoordsRet *info, int spr_offs);
+void Sprite_48_RedJavelinGuard(int k);
+void Sprite_46_BlueArcher(int k);
+void SoldierThrowing_Common(int k);
+void Guard_LaunchProjectile(int k);
+void BushJavelinSoldier_Draw(int k);
+void JavelinTrooper_Draw(int k);
+void Sprite_49_RedBushGuard(int k);
+void Sprite_47_GreenBushGuard(int k);
+void Sprite_BushGuard_Main(int k);
+void BushGuard_SpawnFoliage(int k);
+void BushSoldierCommon_Draw(int k);
+void ArcherSoldier_Draw(int k);
+void SpriteDraw_Archer_Weapon(int k, int spr_offs, PrepOamCoordsRet *info);
+void TutorialSoldier_Draw(int k);
+void PullSwitch_FacingUp(int k);
+void PullSwitch_HandleUpPulling(int k);
+void BadPullDownSwitch_Draw(int k);
+void BadPullUpSwitch_Draw(int k);
+void PullSwitch_FacingDown(int k);
+void GoodPullSwitch_Draw(int k);
+void PullSwitch_HandleDownPulling(int k);
+void Priest_SpawnMantle(int k);
+void Sprite_SanctuaryMantle(int k);
+void SageMantle_Draw(int k);
+void Sprite_Priest(int k);
+void Priest_Dying(int k);
+void Priest_RunRescueCutscene(int k);
+void Priest_Chillin(int k);
+void Sprite_Uncle(int k);
+void Uncle_AtHouse(int k);
+void Uncle_InPassage(int k);
+void Sprite_QuarrelBros(int k);
+void QuarrelBros_Draw(int k);
+void Sprite_YoungSnitchLady(int k);
+void YoungSnitchLady_Draw(int k);
+void Sprite_InnKeeper(int k);
+void InnKeeper_Draw(int k);
+void Sprite_Witch(int k);
+void Witch_AcceptShroom(int k);
+void Witch_Draw(int k);
+void SpritePrep_Snitches(int k);
+void Sprite_OldSnitchLady(int k);
+void SpritePrep_RunningMan(int k);
+void Sprite_RunningMan(int k);
+void RunningMan_Draw(int k);
+void Sprite_BottleVendor(int k);
+uint8 BottleVendor_Draw(int k);
+void Priest_SpawnRescuedPrincess();
+void Sprite_76_Zelda(int k);
+void Zelda_InCell(int k);
+void Zelda_EnteringSanctuary(int k);
+void Zelda_AtSanctuary(int k);
+void SpritePrep_Mushroom(int k);
+void Sprite_E7_Mushroom(int k);
+void Sprite_E8_FakeSword(int k);
+void FakeSword_Draw(int k);
+void SpritePrep_HeartContainer(int k);
+void Sprite_HeartContainer(int k);
+void Sprite_HeartPiece(int k);
+void HeartUpgrade_SetObtainedFlag(int k);
+void Sprite_Aginah(int k);
+void Sprite_Sahasrahla(int k);
+void Sasha_Idle(int k);
+void Elder_Draw(int k);
+void Sprite_DustCloud(int k);
+int Sprite_SpawnDustCloud(int k);
+void MedallionTablet_Main(int k);
+void BombosTablet(int k);
+void EtherTablet(int k);
+void ElderWife_Draw(int k);
+void SpritePrep_PotionShop(int k);
+void MagicShopAssistant_SpawnPowder(int k);
+void MagicShopAssistant_SpawnGreenCauldron(int k);
+void MagicShopAssistant_SpawnBlueCauldron(int k);
+void MagicShopAssistant_SpawnRedCauldron(int k);
+void Sprite_E9_PotionShop(int k);
+void Sprite_BagOfPowder(int k);
+void MagicPowderItem_Draw(int k);
+void Sprite_GreenCauldron(int k);
+void GreenPotionItem_Draw(int k);
+void Sprite_BlueCauldron(int k);
+void BluePotionItem_Draw(int k);
+void Sprite_RedCauldron(int k);
+void PotionCauldron_GoBeep(int k);
+void RedPotionItem_Draw(int k);
+bool PotionCauldron_CheckBottles();
+void Sprite_MagicShopAssistant_Main(int k);
+void Shopkeeper_Draw(int k);
+void Sprite_DashItem(int k);
+void Sprite_BonkKey(int k);
+void Sprite_BookOfMudora(int k);
+void Sprite_LumberjackTree(int k);
+void DashTreeTop_Draw(int k);
+int LumberjackTree_SpawnLeaves(int k);
+void Sprite_TroughBoy(int k);
+void TroughBoy_Draw(int k);
+void BottleMerchant_DetectFish(int k);
+void BottleMerchant_BuyFish(int k);
+void SpritePrep_ThrowableScenery(int k);
+void SpriteModule_Initialize(int k);
+void SpritePrep_Mantle(int k);
+void SpritePrep_Switch(int k);
+void SpritePrep_SwitchFacingUp(int k);
+void SpritePrep_Snitch_bounce_1(int k);
+void SpritePrep_DoNothingA(int k);
+void SpritePrep_Rat(int k);
+void SpritePrep_Keese(int k);
+void SpritePrep_Rope(int k);
+void SpritePrep_Swamola(int k);
+void SpritePrep_Blind(int k);
+void SpritePrep_Ganon(int k);
+void SpritePrep_Pokey(int k);
+void SpritePrep_MiniVitreous(int k);
+void SpritePrep_Gibo(int k);
+void SpritePrep_Octoballoon(int k);
+void SpritePrep_AgahnimsBarrier(int k);
+void SpritePrep_Catfish(int k);
+void SpritePrep_CutsceneAgahnim(int k);
+void SpritePrep_Vitreous(int k);
+void SpritePrep_Raven(int k);
+void SpritePrep_Vulture(int k);
+void SpritePrep_Poe(int k);
+void SpritePrep_DoNothingC(int k);
+void SpritePrep_BlindMaiden(int k);
+void SpritePrep_MiniMoldorm_bounce(int k);
+void SpritePrep_Bomber(int k);
+void SpritePrep_BombShoppe(int k);
+void SpritePrep_BullyAndVictim(int k);
+void SpritePrep_PurpleChest(int k);
+void SpritePrep_Smithy(int k);
+void SpritePrep_Babasu(int k);
+void SpritePrep_Zoro(int k);
+void SpritePrep_LaserEye_bounce(int k);
+void SpritePrep_Popo(int k);
+void SpritePrep_Popo2(int k);
+void SpritePrep_Statue(int k);
+void SpritePrep_Bari(int k);
+void SpritePrep_GreenStalfos(int k);
+void SpritePrep_WaterLever(int k);
+void SpritePrep_FireDebirando(int k);
+void SpritePrep_DebirandoPit(int k);
+void SpritePrep_WeakGuard(int k);
+void SpritePrep_WallCannon(int k);
+void SpritePrep_ArrowGame_bounce(int k);
+void SpritePrep_IgnoreProjectiles(int k);
+void SpritePrep_HauntedGroveAnimal(int k);
+void SpritePrep_HauntedGroveOstritch(int k);
+void SpritePrep_DiggingGameGuy_bounce(int k);
+void SpritePrep_ThievesTownGrate(int k);
+void SpritePrep_RupeePull(int k);
+void SpritePrep_Shopkeeper(int k);
+void SpritePrep_Storyteller(int k);
+void SpritePrep_Adults(int k);
+void SpritePrep_Whirlpool(int k);
+void SpritePrep_Sage(int k);
+void SpritePrep_BonkItem(int k);
+void SpritePrep_Kiki(int k);
+void SpritePrep_Locksmith(int k);
+void SpritePrep_SickKid(int k);
+void SpritePrep_Tektite(int k);
+void SpritePrep_Chainchomp_bounce(int k);
+void SpritePrep_BigFairy(int k);
+void SpritePrep_MrsSahasrahla(int k);
+void SpritePrep_MagicBat(int k);
+void SpritePrep_FortuneTeller(int k);
+void SpritePrep_FairyPond(int k);
+void SpritePrep_Hobo(int k);
+void SpritePrep_MasterSword(int k);
+void SpritePrep_Roller_HorizontalRightFirst(int k);
+void SpritePrep_RollerLeftRight(int k);
+void SpritePrep_Roller_VerticalDownFirst(int k);
+void SpritePrep_RollerUpDown(int k);
+void SpritePrep_Kodongo(int k);
+void SpritePrep_Spark(int k);
+void SpritePrep_LostWoodsBird(int k);
+void SpritePrep_LostWoodsSquirrel(int k);
+void SpritePrep_Antifairy(int k);
+void SpritePrep_FallingIce(int k);
+void SpritePrep_KingZora(int k);
+bool Sprite_ReturnIfBossFinished(int k);
+void SpritePrep_ArmosKnight(int k);
+void SpritePrep_DesertStatue(int k);
+void SpritePrep_DoNothingD(int k);
+void SpritePrep_Octorok(int k);
+void SpritePrep_Moldorm(int k);
+void SpritePrep_Lanmolas(int k);
+void SpritePrep_BigSpike(int k);
+void SpritePrep_SwimmingZora(int k);
+void SpritePrep_Geldman(int k);
+void SpritePrep_Kyameron(int k);
+void SpritePrep_WalkingZora(int k);
+void SpritePrep_StandardGuard(int k);
+void SpritePrep_TrooperAndArcherSoldier(int k);
+void SpritePrep_TalkingTree(int k);
+void SpritePrep_CrystalSwitch(int k);
+void SpritePrep_FluteKid(int k);
+void SpritePrep_MoveDown_8px(int k);
+void SpritePrep_Zazakku(int k);
+void SpritePrep_PedestalPlaque(int k);
+void SpritePrep_Stalfos(int k);
+void SpritePrep_KholdstareShell(int k);
+void SpritePrep_Kholdstare(int k);
+void SpritePrep_Bumper(int k);
+void SpritePrep_MoveDown_8px_Right8px(int k);
+void SpritePrep_HardhatBeetle(int k);
+void SpritePrep_MiniHelmasaur(int k);
+void SpritePrep_Fairy(int k);
+void SpritePrep_Absorbable(int k);
+void SpritePrep_OverworldBonkItem(int k);
+void SpritePrep_ShieldPickup(int k);
+void SpritePrep_NiceBee(int k);
+void SpritePrep_Agahnim(int k);
+void SpritePrep_DoNothingG(int k);
+void SpritePrep_FireBar(int k);
+void SpritePrep_Trinexx(int k);
+void SpritePrep_HelmasaurKing(int k);
+void SpritePrep_Spike(int k);
+void SpritePrep_RockStal(int k);
+void SpritePrep_Blob(int k);
+void SpritePrep_Arrghus(int k);
+void SpritePrep_Arrghi(int k);
+void SpritePrep_Mothula(int k);
+void SpritePrep_DoNothingH(int k);
+void SpritePrep_BigKey(int k);
+void SpritePrep_BigKey_load_graphics(int k);
+void SpritePrep_SmallKey(int k);
+void SpritePrep_KeySetItemDrop(int k);
+void SpriteActive_Main(int k);
+void Sprite_09_GiantMoldorm(int k);
+void Sprite_01_Vulture_bounce(int k);
+void Sprite_27_Deadrock(int k);
+void Sprite_20_Sluggula(int k);
+void Sluggula_DropBomb(int k);
+void Sprite_19_Poe(int k);
+void Poe_Draw(int k);
+void Sprite_18_MiniMoldorm(int k);
+void Sprite_12_Moblin(int k);
+void Moblin_MaterializeSpear(int k);
+void Moblin_Draw(int k);
+void Sprite_0E_Snapdragon(int k);
+void SnapDragon_Draw(int k);
+void Sprite_22_Ropa(int k);
+void Ropa_Draw(int k);
+void Sprite_11_Hinox(int k);
+void Hinox_ThrowBomb(int k);
+void Hinox_FaceLink(int k);
+void Hinox_SetDirection(int k, uint8 dir);
+void Hinox_Draw(int k);
+void Sprite_23_RedBari(int k);
+void RedBari_Split(int k);
+void RedBari_Draw(int k);
+void Sprite_13_MiniHelmasaur(int k);
+void Sprite_26_HardhatBeetle(int k);
+void HelmasaurHardHatBeetleCommon(int k);
+void HardHatBeetle_Draw(int k);
+void Sprite_15_Antifairy(int k);
+void Sprite_0B_Cucco(int k);
+void Cucco_Calm(int k);
+void Chicken_Hopping(int k);
+void Cucco_Flee(int k);
+void Cucco_DrawPANIC(int k);
+void Cucco_Carried(int k);
+uint8 Cucco_DoMovement_XY(int k);
+void Cucco_SummonAvenger(int k);
+void BawkBawk(int k);
+void Sprite_17_Hoarder(int k);
+void Sprite_Hoarder_Covered(int k);
+void Sprite_Hoarder_Frantic(int k);
+void CoveredRupeeCrab_Draw(int k);
+void Sprite_EC_ThrownItem(int k);
+void SpriteDraw_ThrownItem_Gigantic(int k);
+void ThrowableScenery_ScatterIntoDebris(int k);
+void Sprite_TransmuteToBomb(int k);
+void Sprite_28_DarkWorldHintNPC(int k);
+void DarkWorldHintNPC_Idle(int k);
+void DarkWorldHintNPC_RestoreHealth(int k);
+bool DarkWorldHintNPC_HandlePayment();
+void StoryTeller_1_Draw(int k);
+void Sprite_2E_FluteKid(int k);
+void FluteKid_Human(int k);
+void Sprite_FluteKid_Stumpy(int k);
+void Sprite_FluteKid_Quaver(int k);
+void FluteKid_SpawnQuaver(int k);
+void Sprite_1A_Smithy(int k);
+void Smithy_Homecoming(int k);
+void Smithy_Frog(int k);
+void ReturningSmithy_Draw(int k);
+void SmithyFrog_Draw(int k);
+void Smithy_Main(int k);
+bool Smithy_ListenForHammer(int k);
+int Smithy_SpawnDwarfPal(int k);
+void Smithy_Draw(int k);
+void Smithy_Spark(int k);
+void Smithy_SpawnSpark(int k);
+void SmithySpark_Draw(int k);
+void Sprite_1B_Arrow(int k);
+void EnemyArrow_Draw(int k);
+void Sprite_1E_CrystalSwitch(int k);
+void Sprite_1F_SickKid(int k);
+void Sprite_21_WaterSwitch(int k);
+void PushSwitch_Draw(int k);
+void Sprite_39_Locksmith(int k);
+void MiddleAgedMan_Draw(int k);
+void Sprite_2B_Hobo(int k);
+void Sprite_Hobo_Bum(int k);
+void SpritePrep_Hobo_SpawnSmoke(int k);
+void Sprite_Hobo_Bubble(int k);
+int Hobo_SpawnBubble(int k);
+void Sprite_Hobo_Fire(int k);
+void SpritePrep_Hobo_SpawnFire(int k);
+void Sprite_Hobo_Smoke(int k);
+void Hobo_SpawnSmoke(int k);
+void Sprite_73_UncleAndPriest(int k);
+void SpritePrep_UncleAndPriest_bounce(int k);
+void SpritePrep_OldMan_bounce(int k);
+void Sprite_TutorialGuardOrBarrier(int k);
+void Sprite_F2_MedallionTablet(int k);
+void Sprite_33_RupeePull(int k);
+void Sprite_14_ThievesTownGrate(int k);
+void SpritePrep_Snitch_bounce_2(int k);
+void SpritePrep_Snitch_bounce_3(int k);
+void Sprite_37_Waterfall(int k);
+void Sprite_38_EyeStatue(int k);
+void Sprite_3A_MagicBat(int k);
+void SpritePrep_Zelda_bounce(int k);
+void Sprite_78_MrsSahasrahla(int k);
+void Sprite_16_Elder_bounce(int k);
+void SpritePrep_HeartPiece(int k);
+void Sprite_2D_TelepathicTile(int k);
+void Sprite_25_TalkingTree(int k);
+void Sprite_1C_Statue(int k);
+bool Statue_CheckForSwitch(int k);
+void MovableStatue_Draw(int k);
+void Statue_BlockSprites(int k);
+void Sprite_1D_FluteQuest(int k);
+void Sprite_72_FairyPond(int k);
+void Sprite_WishPond2(int k);
+void Sprite_HappinessPond(int k);
+void WishPond2_Draw(int k);
+void FaerieQueen_Draw(int k);
+void Sprite_71_Leever(int k);
+void Leever_Draw(int k);
+void Sprite_D8_Heart(int k);
+void Sprite_E3_Fairy(int k);
+void Fairy_CheckIfTouchable(int k);
+void Sprite_E4_SmallKey(int k);
+void Sprite_D9_GreenRupee(int k);
+void Sprite_Absorbable_Main(int k);
+void Sprite_08_Octorok(int k);
+void Octorok_FireLoogie(int k);
+void Octorock_Draw(int k);
+void Sprite_0C_OctorokStone(int k);
+void SpriteDraw_OctorokStoneCrumbling(int k);
+void Sprite_0F_Octoballoon(int k);
+void Octoballoon_RecoilLink(int k);
+void Octoballoon_Draw(int k);
+void Octoballoon_FormBabby(int k);
+void Sprite_10_OctoballoonBaby(int k);
+void Sprite_0D_Buzzblob(int k);
+void Buzzblob_SelectNewDirection(int k);
+void BuzzBlob_Draw(int k);
+void Sprite_02_StalfosHead(int k);
+bool Pipe_ValidateEntry();
+void Ancilla_TerminateSparkleObjects();
+int Sprite_SpawnSuperficialBombBlast(int k);
+void Sprite_SpawnDummyDeathAnimation(int k);
+void Sprite_MagicBat_SpawnLightning(int k);
+void Fireball_SpawnTrailGarnish(int k);
+void GarnishSpawn_PyramidDebris(int8 x, int8 y, int8 xvel, int8 yvel);
+void Snitch_SpawnGuard(int k);
+void Babusu_Draw(int k);
+void Wizzrobe_Draw(int k);
+void Wizzbeam_Draw(int k);
+void Freezor_Draw(int k);
+void Zazak_Draw(int k);
+void Stalfos_Draw(int k);
+bool Probe_CheckTileSolidity(int k);
+void Sprite_HumanMulti_1(int k);
+void Sprite_BlindsHutGuy(int k);
+void Sprite_ThiefHideoutGuy(int k);
+void Sprite_FluteDad(int k);
+void FluteBoyFather_Draw(int k);
+void BlindHideoutGuy_Draw(int k);
+void Sprite_SweepingLady(int k);
+void SweepingLady_Draw(int k);
+void Sprite_Lumberjacks(int k);
+bool Lumberjack_CheckProximity(int k, int j);
+void Lumberjacks_Draw(int k);
+void Sprite_FortuneTeller(int k);
+void FortuneTeller_PerformPseudoScience(int k);
+void FortuneTeller_Draw(int k);
+void Smithy_SpawnDumbBarrierSprite(int k);
+void Sprite_MazeGameLady(int k);
+void Sprite_MazeGameGuy(int k);
+void MazeGameGuy_Draw(int k);
+void CrystalMaiden_Draw(int k);
+void Priest_Draw(int k);
+uint8 FluteBoy_Draw(int k);
+void FluteAardvark_Draw(int k);
+void DustCloud_Draw(int k);
+void MedallionTablet_Draw(int k);
+void Uncle_Draw(int k);
+void BugNetKid_Draw(int k);
+void Bomber_Draw(int k);
+void SpriteDraw_ZirroBomb(int k);
+void PlayerBee_HoneInOnTarget(int j, int k);
+void Pikit_Draw(int k);
+void SpriteDraw_Pikit_Tongue(int k, PrepOamCoordsRet *info);
+void SpriteDraw_Pikit_Loot(int k, PrepOamCoordsRet *info);
+void Kholdstare_Draw(int k);
+int Sprite_SpawnFireball(int k);
+void ArcheryGameGuy_Draw(int k);
+void ShopKeeper_RapidTerminateReceiveItem();
+void Sprite_InitializeSecondaryItemMinigame(int what);
+void Waterfall(int k);
+void Sprite_BatCrash(int k);
+void Sprite_SpawnBatCrashCutscene();
+void BatCrash_DrawHardcodedGarbage(int k);
+void BatCrash_SpawnDebris(int k);
+void RetreatBat_Draw(int k);
+void DrinkingGuy_Draw(int k);
+void Lady_Draw(int k);
+void Lanmola_SpawnShrapnel(int k);
+void Sprite_Cukeman(int k);
+void Cukeman_Draw(int k);
+void RunningBoy_SpawnDustGarnish(int k);
+void MovableMantle_Draw(int k);
+void Mothula_Draw(int k);
+void BottleMerchant_BuyBee(int k);
+void Sprite_ChickenLady(int k);
+void Overworld_DrawWoodenDoor(uint16 pos, bool unlocked);
+void Sprite_D4_Landmine(int k);
+void Landmine_Draw(int k);
+void Sprite_D3_Stal(int k);
+void Stal_Draw(int k);
+void Sprite_D2_FloppingFish(int k);
+void Fish_Draw(int k);
+void ChimneySmoke_Draw(int k);
+void Sprite_D1_BunnyBeam(int k);
+void Sprite_Chimney(int k);
+void Sprite_BunnyBeam(int k);
+void Sprite_D0_Lynel(int k);
+void Lynel_Draw(int k);
+void Sprite_SpawnPhantomGanon(int k);
+void Sprite_PhantomGanon(int k);
+void GanonBat_Draw(int k);
+void PhantomGanon_Draw(int k);
+void SwishEvery16Frames(int k);
+void Sprite_GanonTrident(int k);
+void Sprite_FireBat_Trailer(int k);
+void Sprite_SpiralFireBat(int k);
+void FireBat_Move(int k);
+void Sprite_FireBat_Launched(int k);
+void GetPositionRelativeToTheGreatOverlordGanon(int k);
+void FireBat_Animate(int k);
+void FireBat_Draw(int k);
+bool Ganon_AttemptTridentCatch(uint16 x, uint16 y);
+void Ganon_HandleFireBatCircle(int k);
+void Ganon_SpawnSpiralBat(int k);
+void Sprite_D6_Ganon(int k);
+void Ganon_EnableInvincibility(int k);
+void Ganon_SpawnFallingTilesOverlord(int k);
+void Ganon_Func1(int k, int t);
+void Ganon_Phase1_AnimateTridentSpin(int k);
+void Ganon_HandleAnimation_Idle(int k);
+void Ganon_SelectWarpLocation(int k, int a);
+void Ganon_ShakeHead(int k);
+void Ganon_Draw(int k);
+void Trident_Draw(int k);
+void SpritePrep_Swamola_InitializeSegments(int k);
+void Sprite_CF_Swamola(int k);
+ProjectSpeedRet Swamola_ProjectVelocityTowardsTarget(int k);
+void Swamola_SpawnRipples(int k);
+void Sprite_Swamola_Ripples(int k);
+void SwamolaRipples_Draw(int k);
+void Swamola_Draw(int k);
+void SpritePrep_Blind_PrepareBattle(int k);
+void BlindLaser_SpawnTrailGarnish(int j);
+void Sprite_Blind_Head(int k);
+void Blind_SpawnHead(int k);
+void Sprite_CE_Blind(int k);
+void Sprite_BlindLaser(int k);
+void Sprite_Blind_Blind_Blind(int k);
+void Blind_FireballFlurry(int k, uint8 a);
+int Blind_SpitFireball(int k, uint8 a);
+int SpawnBossPoof(int k);
+void Blind_Decelerate_X(int k);
+void Blind_Decelerate_Y(int k);
+void Blind_CheckBumpDamage(int k);
+void Blind_Animate(int k);
+void Blind_AnimateRobes(int k);
+void Blind_SpawnLaser(int k);
+void Blind_Draw(int k);
+void TrinexxComponents_Initialize(int k);
+void Trinexx_RestoreXY(int k);
+void Trinexx_CachePosition(int k);
+void Sprite_Trinexx_FinalPhase(int k);
+void Sprite_TrinexxD_Draw(int k);
+void Sprite_Trinexx_CheckDamageToFlashingSegment(int k);
+void Sprite_CB_TrinexxRockHead(int k);
+void Trinexx_WagTail(int k);
+void Trinexx_HandleShellCollision(int k);
+void SpriteDraw_TrinexxRockHead(int k, PrepOamCoordsRet *info);
+void SpriteDraw_TrinexxRockHeadAndBody(int k);
+void Sprite_Sidenexx(int k);
+void Sidenexx_ExhaleDanger(int k);
+void Sidenexx_Explode(int k);
+void TrinexxHead_Draw(int k);
+void Sprite_CC_CD_Common(int k);
+void Sprite_CD_SpawnGarnish(int k);
+void Sprite_TrinexxFire_AddFireGarnish(int k);
+int Garnish_FlameTrail(int k, bool is_low);
+void Sprite_CA_ChainChomp(int k);
+void ChainChomp_MoveChain(int k);
+void ChainChomp_HandleLeash(int k);
+void ChainChomp_Draw(int k);
+void Sprite_C9_Tektite(int k);
+void Sprite_Tektite(int k);
+void Tektite_Draw(int k);
+void Sprite_C8_BigFairy(int k);
+void Sprite_FairyCloud(int k);
+void Sprite_BigFairy(int k);
+void BigFaerie_Draw(int k);
+void FaerieCloud_Draw(int k);
+void Sprite_C7_Pokey(int k);
+void Hokbok_Draw(int k);
+void Sprite_C5_Medusa(int k);
+void Sprite_C6_4WayShooter(int k);
+void Sprite_C4_Thief(int k);
+uint8 Thief_ScanForBooty(int k);
+void Thief_TargetBooty(int k, int j);
+void Thief_GrabBooty(int k, int j);
+void Thief_CheckCollisionWithLink(int k);
+void Thief_SpillItems(int k);
+void Thief_Draw(int k);
+void Sprite_C3_Gibo(int k);
+void Gibo_Draw(int k);
+void Sprite_C2_Boulder(int k);
+void Boulder_OutdoorsMain(int k);
+void Boulder_Draw(int k);
+void SpriteDraw_BigShadow(int k, int anim);
+void Sprite_DrawLargeShadow2(int k);
+void CutsceneAgahnim_SpawnZeldaOnAltar(int k);
+void Sprite_C1_CutsceneAgahnim(int k);
+void CutsceneAgahnim_Agahnim(int k);
+int Sprite_Agahnim_ApplyMotionBlur(int k);
+void ChattyAgahnim_Draw(int k, PrepOamCoordsRet *info);
+void SpriteDraw_CutsceneAgahnimSpell(int k, PrepOamCoordsRet *info);
+void Sprite_CutsceneAgahnim_Zelda(int k);
+void AltarZelda_DrawBody(int k, PrepOamCoordsRet *info);
+void SpriteDraw_AltarZeldaWarp(int k);
+void Sprite_InitializedSegmented(int k);
+void GiantMoldorm_Draw(int k);
+void GiantMoldorm_IncrementalSegmentExplosion(int k);
+void SpriteDraw_Moldorm_Head(int k);
+void SpriteDraw_Moldorm_SegmentC(int k);
+void Moldorm_HandleTail(int k);
+void SpriteDraw_Moldorm_Tail(int k);
+void SpriteDraw_Moldorm_Eyeballs(int k, PrepOamCoordsRet *info);
+void Sprite_ScheduleBossForDeath(int k);
+void Sprite_MakeBossExplosion(int k);
+void Sprite_MakeBossDeathExplosion_NoSound(int k);
+void Vulture_Draw(int k);
+void Sprite_Raven(int k);
+void Vitreous_SpawnSmallerEyes(int k);
+void Sprite_C0_Catfish(int k);
+void Sprite_Catfish_QuakeMedallion(int k);
+void Catfish_BigFish(int k);
+int Sprite_SpawnBomb(int k);
+void Catfish_RegurgitateMedallion(int k);
+void Sprite_Zora_RegurgitateFlippers(int k);
+void Catfish_SpawnPlop(int k);
+int Sprite_SpawnWaterSplash(int k);
+void GreatCatfish_Draw(int k);
+void Sprite_Catfish_SplashOfWater(int k);
+void Sprite_BF_Lightning(int k);
+void Lightning_SpawnGarnish(int k);
+void Sprite_BD_Vitreous(int k);
+void Vitreous_Animate(int k, uint8 a);
+void Vitreous_SetMinionsForth(int k);
+void Sprite_SpawnLightning(int k);
+void Vitreous_Draw(int k);
+void Sprite_BE_VitreousEye(int k);
+void HelmasaurFireball_TriSplit(int k);
+void HelmasaurFireball_QuadSplit(int k);
+void Sprite_ArmosCrusher(int k);
+void Sprite_EvilBarrier(int k);
+void EvilBarrier_Draw(int k);
+void SpriteDraw_Antfairy(int k);
+void Toppo_Flustered(int k);
+void Goriya_Draw(int k);
+void Moldorm_Draw(int k);
+void TalkingTree_Mouth(int k);
+void TalkingTree_SpawnBomb(int k);
+void TalkingTree_Draw(int k);
+void TalkingTree_Eye(int k);
+void SpritePrep_TalkingTree_SpawnEyeball(int k, int dir);
+void RupeePull_SpawnPrize(int k);
+void Sprite_D5_DigGameGuy(int k);
+void DiggingGameGuy_Draw(int k);
+void OldMountainMan_Draw(int k);
+void HelmasaurKing_Initialize(int k);
+void HelmasaurKing_Reinitialize(int k);
+void Sprite_92_HelmasaurKing(int k);
+void HelmasaurKing_HandleMovement(int k);
+bool HelmasaurKing_MaybeFireball(int k);
+void HelmasaurKing_SwingTail(int k);
+void HelmasaurKing_CheckMaskDamageFromHammer(int k);
+void HelmasaurKing_AttemptDamage(int k);
+void HelmasaurKing_ChipAwayAtMask(int k);
+void HelmasaurKing_ExplodeMask(int k);
+void HelmasaurKing_SpawnMaskDebris(int k);
+void HelmasaurKing_SpitFireball(int k);
+void HelmasaurKing_Draw(int k);
+void SpriteDraw_KingHelmasaur_Eyes(int k, PrepOamCoordsRet *info);
+void KingHelmasaurMask(int k, PrepOamCoordsRet *info);
+void KingHelmasaur_CheckBombDamage(int k, int j);
+void SpriteDraw_KingHelmasaur_Body(int k, PrepOamCoordsRet *info);
+void SpriteDraw_KingHelmasaur_Legs(int k, PrepOamCoordsRet *info);
+void SpriteDraw_KingHelmasaur_Mouth(int k, PrepOamCoordsRet *info);
+void KingHelmasaur_OperateTail(int k, PrepOamCoordsRet *info);
+void Sprite_MadBatterBolt(int k);
+void Sprite_AA_Pikit(int k);
+void Sprite_A8_GreenZirro(int k);
+void Zirro_DropBomb(int k);
+void Sprite_StalfosBone(int k);
+void StalfosBone_Draw(int k);
+void Sprite_A7_Stalfos(int k);
+void Stalfos_Skellington(int k);
+void Sprite_Zazak_Main(int k);
+int Sprite_SpawnFirePhlegm(int k);
+void Stalfos_ThrowBone(int k);
+void FirePhlegm_Draw(int k);
+void Sprite_A3_KholdstareShell(int k);
+void GenerateIceball(int k);
+void Sprite_A2_Kholdstare(int k);
+void Kholdstare_SpawnPuffCloudGarnish(int k);
+void Sprite_A4_FallingIce(int k);
+void IceBall_Split(int k);
+void Sprite_A1_Freezor(int k);
+void Sprite_9E_HauntedGroveOstritch(int k);
+void FluteBoyOstrich_Draw(int k);
+void Sprite_9F_HauntedGroveRabbit(int k);
+void Sprite_A0_HauntedGroveBird(int k);
+void HauntedGroveBird_Blink(int k);
+void Sprite_9C_Zoro(int k);
+void Zoro(int k);
+void Babasu(int k);
+void Sprite_9B_Wizzrobe(int k);
+void Wizzrobe_FireBeam(int k);
+void Sprite_9A_Kyameron(int k);
+void Kyameron_Draw(int k);
+void Sprite_99_Pengator(int k);
+void Pengator_Draw(int k);
+void Sprite_LaserBeam(int k);
+void LaserBeam_BuildUpGarnish(int k);
+void Sprite_95_LaserEyeLeft(int k);
+void LaserEye_FireBeam(int k);
+void LaserEye_Draw(int k);
+void Sprite_94_Pirogusu(int k);
+void Pirogusu_SpawnSplash(int k);
+void Pirogusu_Draw(int k);
+void Sprite_93_Bumper(int k);
+void Bumper_Draw(int k);
+void Sprite_91_StalfosKnight(int k);
+void StalfosKnight_Draw(int k);
+void SpriteDraw_StalfosKnight_Head(int k, PrepOamCoordsRet *info);
+void Sprite_90_Wallmaster(int k);
+void WallMaster_Draw(int k);
+void Sprite_8F_Blob(int k);
+void Zol_Draw(int k);
+void Sprite_8E_Terrorpin(int k);
+void Terrorpin_CheckForHammer(int k);
+void Terrorpin_SetUpHammerHitBox(int k, SpriteHitBox *hb);
+void Sprite_8C_Arrghus(int k);
+void Arrghus_Draw(int k);
+void Arrghus_HandlePuffs(int k);
+void Sprite_8D_Arrghi(int k);
+void Sprite_8B_Gibdo(int k);
+void Gibdo_Draw(int k);
+void Sprite_89_MothulaBeam(int k);
+void Sprite_94_Tile(int k);
+void FlyingTile_Draw(int k);
+void Sprite_8A_SpikeBlock(int k);
+bool SpikeBlock_CheckStatueCollision(int k);
+void Sprite_88_Mothula(int k);
+void Mothula_Main(int k);
+void Mothula_FlapWings(int k);
+void Mothula_SpawnBeams(int k);
+void Mothula_HandleSpikes(int k);
+void Sprite_86_Kodongo(int k);
+void Kodongo_SetDirection(int k);
+void Kodongo_SpawnFire(int k);
+void Sprite_87_KodongoFire(int k);
+void Flame_Draw(int k);
+void Sprite_85_YellowStalfos(int k);
+void YellowStalfos_Animate(int k);
+void YellowStalfos_EmancipateHead(int k);
+void YellowStalfos_Draw(int k);
+void YellowStalfos_DrawHead(int k, PrepOamCoordsRet *info);
+void SpritePrep_Eyegore(int k);
+void Sprite_83_GreenEyegore(int k);
+void Eyegore_Main(int k);
+void Eyegore_Draw(int k);
+void SpritePrep_AntifairyCircle(int k);
+void Sprite_82_AntifairyCircle(int k);
+void Sprite_81_Hover(int k);
+void Sprite_AB_CrystalMaiden(int k);
+void CrystalMaiden_RunCutscene(int k);
+void Sprite_7D_BigSpike(int k);
+void SpikeTrap_Draw(int k);
+void Sprite_7E_Firebar_Clockwise(int k);
+void Firebar_Main(int k);
+void Sprite_80_Firesnake(int k);
+void Firesnake_SpawnFireball(int j);
+void Sprite_7C_GreenStalfos(int k);
+void Sprite_7A_Agahnim(int k);
+void Agahnim_PerformAttack(int k);
+void Agahnim_Draw(int k);
+void Sprite_7B_AgahnimBalls(int k);
+void CreateSixBlueBalls(int k);
+void SeekerEnergyBall_Draw(int k);
+void Sprite_79_Bee(int k);
+void Bee_DormantHive(int k);
+void SpawnBeeFromHive(int k);
+void InitializeSpawnedBee(int k);
+int ReleaseBeeFromBottle(int x_value);
+void Bee_Main(int k);
+int Sprite_Find_EmptyBottle();
+void Bee_HandleInteractions(int k);
+void Sprite_B2_PlayerBee(int k);
+void GoldBee_SpawnSelf(int k);
+void Bee_HandleZ(int k);
+bool PlayerBee_FindTarget(int k, Point16U *pt);
+void Bee_Bzzt(int k);
+void Sprite_B3_PedestalPlaque(int k);
+void Sprite_B4_PurpleChest(int k);
+void Sprite_B5_BombShop(int k);
+void Sprite_BombShop_Clerk(int k);
+void Sprite_BombShop_Bomb(int k);
+void Sprite_BombShop_SuperBomb(int k);
+void Sprite_BombShop_Huff(int k);
+void BombShop_ClerkExhalation(int k);
+void BombShopEntity_Draw(int k);
+void Sprite_B6_Kiki(int k);
+void Kiki_Flee(int k);
+void Kiki_OfferInitialService(int k);
+void Kiki_OfferEntranceService(int k);
+bool Kiki_Draw(int k);
+void Sprite_B7_BlindMaiden(int k);
+void OldMan_RevertToSprite(int k);
+void OldMan_EnableCutscene();
+void Sprite_AD_OldMan(int k);
+void Sprite_B8_DialogueTester(int k);
+void Sprite_B9_BullyAndPinkBall(int k);
+void Sprite_PinkBall(int k);
+void PinkBall_HandleDeceleration(int k);
+void PinkBall_Distress(int k);
+void Sprite_Bully(int k);
+void Bully_Draw(int k);
+void BallGuy_PlayBounceNoise(int k);
+void SpawnBully(int k);
+void PinkBall_HandleMessage(int k);
+void Bully_HandleMessage(int k);
+void Sprite_BA_Whirlpool(int k);
+void Sprite_BB_Shopkeeper(int k);
+void Shopkeeper_StandardClerk(int k);
+void ChestGameGuy(int k);
+void NiceThief_Animate(int k);
+void NiceThiefWithGift(int k);
+void MiniChestGameGuy(int k);
+void LostWoodsChestGameGuy(int k);
+void NiceThiefUnderRock(int k);
+void ShopItem_RedPotion150(int k);
+void ShopKeeper_SpawnShopItem(int k, int pos, int what);
+void ShopItem_FighterShield(int k);
+void ShopItem_FireShield(int k);
+void ShopItem_MakeShieldsDeflect(int k);
+void ShopItem_Heart(int k);
+void ShopItem_Arrows(int k);
+void ShopItem_Bombs(int k);
+void ShopItem_Bee(int k);
+void ShopItem_HandleReceipt(int k, uint8 item);
+void ShopItem_PlayBeep(int k);
+bool ShopItem_CheckForAPress(int k);
+bool ShopItem_HandleCost(int amt);
+void SpriteDraw_ShopItem(int k);
+void Sprite_AC_Apple(int k);
+void SpawnApple(int k);
+void Sprite_Apple(int k);
+void Sprite_BC_Drunkard(int k);
+void SomariaPlatform_LocatePath(int k);
+void Sprite_ED_SomariaPlatform(int k);
+void SomariaPlatformAndPipe_HandleMovement(int k);
+uint8 SomariaPlatformAndPipe_CheckTile(int k);
+void SomariaPlatform_Draw(int k);
+void SomariaPlatform_HandleJunctions(int k);
+void SomariaPlatform_HandleDragX(int k);
+void SomariaPlatform_HandleDragY(int k);
+void SomariaPlatform_HandleDrag(int k);
+void SomariaPlatform_DragLink(int k);
+void Sprite_AE_Pipe_Down(int k);
+void Pipe_HandlePlayerMovement(uint8 dir);
+void Faerie_HandleMovement(int k);
--- /dev/null
+++ b/src/tagalong.c
@@ -1,0 +1,756 @@
+#include "tagalong.h"
+#include "sprite_main.h"
+#include "sprite.h"
+#include "zelda_rtl.h"
+#include "variables.h"
+#include "snes/snes_regs.h"
+#include "dungeon.h"
+#include "overworld.h"
+#include "ancilla.h"
+#include "player.h"
+#include "misc.h"
+
+static const uint8 kTagalongFlags[4] = {0x20, 0x10, 0x30, 0x20};
+static const uint8 kTagalong_Tab5[15] = {0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+static const uint8 kTagalong_Tab4[15] = {0, 0, 3, 3, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+static const uint8 kTagalong_Tab0[3] = {5, 9, 0xa};
+static const uint16 kTagalong_Tab1[3] = {0xdf3, 0x6f9, 0xdf3};
+static const uint16 kTagalong_Msg[3] = {0x20, 0x108, 0x11d};
+static const TagalongMessageInfo kTagalong_IndoorInfos[12] = {
+  {0x1ef0, 0x288, 1, 0x99, 4},
+  {0x1e58, 0x2f0, 2, 0x9a, 4},
+  {0x1ea8, 0x3b8, 4, 0x9b, 4},
+  {0xcf8, 0x25b, 1, 0x21, 1},
+  {0xcf8, 0x39d, 2, 0x21, 1},
+  {0xc78, 0x238, 4, 0x21, 1},
+  {0xa30, 0x2f8, 1, 0x22, 1},
+  {0x178, 0x550, 1, 0x23, 1},
+  {0x168, 0x4f8, 2, 0x2a, 1},
+  {0x1bd8, 0x16fc, 1, 0x124, 6},
+  {0x1520, 0x167c, 1, 0x124, 6},
+  {0x5ac, 0x4fc, 1, 0x29, 1},
+};
+static const TagalongMessageInfo kTagalong_OutdoorInfos[5] = {
+  {0x3c0, 0x730, 1, 0x9d, 4},
+  {0x648, 0xf50, 0, 0xffff, 0xa},
+  {0x6c8, 0xd78, 1, 0xffff, 0xa},
+  {0x688, 0xc78, 2, 0xffff, 0xa},
+  {0xe8, 0x90, 0, 0x28, 0xe},
+};
+static const uint8 kTagalong_IndoorOffsets[8] = {0, 3, 6, 7, 9, 10, 11, 12};
+static const uint8 kTagalong_OutdoorOffsets[4] = {0, 1, 4, 5};
+static const uint16 kTagalong_IndoorRooms[7] = {0xf1, 0x61, 0x51, 2, 0xdb, 0xab, 0x22};
+static const uint16 kTagalong_OutdoorRooms[3] = {3, 0x5e, 0};
+typedef struct TagalongSprXY {
+  int8 y1, x1, y2, x2;
+} TagalongSprXY;
+typedef struct TagalongDmaFlags {
+  uint8 dma6, dma7;
+  uint8 flags;
+} TagalongDmaFlags;
+static const TagalongSprXY kTagalongDraw_SprXY[56] = {
+  {-2, 0, 0, 0},
+  {-2, 0, 0, 0},
+  {-2, 0, 0, 0},
+  {-2, 0, 0, 0},
+  {-1, 0, 1, 0},
+  {-1, 0, 1, 0},
+  {-1, 0, 1, 0},
+  {-1, 0, 1, 0},
+  {0, 0, 0, 0},
+  {0, 0, 0, 0},
+  {0, 0, 0, 0},
+  {0, 0, 0, 0},
+  {1, 0, 0, 0},
+  {1, 0, 0, 0},
+  {1, 0, 0, 0},
+  {1, 0, 0, 0},
+  {0, 0, 0, 0},
+  {0, 0, 0, 0},
+  {0, -3, 0, 0},
+  {0, 3, 0, 0},
+  {1, 0, 0, 0},
+  {1, 0, 0, 0},
+  {1, -3, 1, 0},
+  {1, 3, 1, 0},
+  {0, 0, 0, 0},
+  {0, 0, 0, 0},
+  {0, 0, 0, 0},
+  {0, 0, 0, 0},
+  {0, 0, 1, 0},
+  {0, 0, 1, 0},
+  {0, 0, 1, 0},
+  {0, 0, 1, 0},
+  {-1, 0, 0, 0},
+  {-1, 0, 0, 0},
+  {-1, 0, 0, 0},
+  {-1, 0, 0, 0},
+  {0, 0, 1, 0},
+  {0, 0, 1, 0},
+  {0, 0, 1, 0},
+  {0, 0, 1, 0},
+  {0, 0, 0, 0},
+  {0, 0, 0, 0},
+  {0, 0, 0, 0},
+  {0, 0, 0, 0},
+  {0, 0, 0, 0},
+  {0, 0, 0, 0},
+  {0, 0, 0, 0},
+  {0, 0, 0, 0},
+  {2, 0, 0, 0},
+  {2, 0, 0, 0},
+  {2, -1, 0, 0},
+  {2, 1, 0, 0},
+  {3, 0, 1, 0},
+  {3, 0, 1, 0},
+  {3, -1, 1, 0},
+  {3, 1, 1, 0},
+};
+static const TagalongDmaFlags kTagalongDmaAndFlags[16] = {
+  {0x20, 0xc0, 0x00},
+  {0x00, 0xa0, 0x00},
+  {0x40, 0x60, 0x00},
+  {0x40, 0x60, 0x44},
+  {0x20, 0xc0, 0x04},
+  {0x00, 0xa0, 0x04},
+  {0x40, 0x80, 0x00},
+  {0x40, 0x80, 0x44},
+  {0x20, 0xe0, 0x00},
+  {0x00, 0xe0, 0x00},
+  {0x40, 0xe0, 0x00},
+  {0x40, 0xe0, 0x44},
+  {0x20, 0xe0, 0x04},
+  {0x00, 0xe0, 0x04},
+  {0x40, 0xe0, 0x04},
+  {0x40, 0xe0, 0x40},
+};
+static const uint8 kTagalongDraw_Pals[14] = {0, 4, 4, 4, 4, 0, 7, 4, 4, 3, 4, 4, 4, 4};
+static const uint16 kTagalongDraw_Offs[14] = {0, 0, 0x80, 0x80, 0x80, 0, 0, 0xc0, 0xc0, 0x100, 0x180, 0x180, 0x140, 0x140};
+static const uint8 kTagalongDraw_SprInfo0[24] = {
+  0xd8, 0x24, 0xd8, 0x64, 0xd9, 0x24, 0xd9, 0x64, 0xda, 0x24, 0xda, 0x64, 0xc8, 0x22, 0xc8, 0x62,
+  0xc9, 0x22, 0xc9, 0x62, 0xca, 0x22, 0xca, 0x62,
+};
+static const uint16 kTagalongDraw_SprOffs0[2] = {0x170, 0xc0};
+static const uint16 kTagalongDraw_SprOffs1[2] = {0x1c0, 0x110};
+bool Tagalong_IsFollowing() {
+  uint8 main = main_module_index;
+  uint8 sub = submodule_index;
+  return !flag_is_link_immobilized && sub != 10 && !(main == 9 && sub == 0x23) && !(main == 14 && (sub == 1 || sub == 2));
+}
+
+bool Follower_ValidateMessageFreedom() {  // 87f46f
+  uint8 ps = link_player_handler_state;
+  if (ps != kPlayerState_Ground && ps != kPlayerState_Swimming && ps != kPlayerState_StartDash)
+    return false;
+  uint8 t = button_mask_b_y & 0x80 | link_unk_master_sword | link_item_in_hand |
+            link_position_mode | flag_is_ancilla_to_pick_up | flag_is_sprite_to_pick_up |
+            link_state_bits | link_grabbing_wall;
+  return t == 0;
+}
+
+void Follower_MoveTowardsLink() {  // 88f91a
+  for(;;) {
+    int k = 9;
+    int j = tagalong_var1;
+    ancilla_y_lo[k] = tagalong_y_lo[j];
+    ancilla_y_hi[k] = tagalong_y_hi[j];
+    ancilla_x_lo[k] = tagalong_x_lo[j];
+    ancilla_x_hi[k] = tagalong_x_hi[j];
+
+    ProjectSpeedRet pt = Ancilla_ProjectSpeedTowardsPlayer(k, 24);
+    ancilla_x_vel[k] = pt.x;
+    ancilla_y_vel[k] = pt.y;
+    Ancilla_MoveY(k);
+    Ancilla_MoveX(k);
+
+    uint16 x = Ancilla_GetX(k);
+    uint16 y = Ancilla_GetY(k);
+    if (abs16(x - link_x_coord) < 2 && abs16(y - link_y_coord) < 2)
+      return;
+    k = ++tagalong_var1;
+    if (k == 18)
+      return;
+    tagalong_y_lo[k] = y;
+    tagalong_y_hi[k] = y >> 8;
+    tagalong_x_lo[k] = x;
+    tagalong_x_hi[k] = x >> 8;
+    static const uint8 kTagalongLayerBits[4] = {0x20, 0x10, 0x30, 0x20};
+    tagalong_layerbits[k] = kTagalongLayerBits[link_is_on_lower_level] >> 2 | 1;
+  }
+}
+
+bool Follower_CheckBlindTrigger() {  // 899e90
+  int k = tagalong_var2;
+  uint16 x = tagalong_x_hi[k] << 8 | tagalong_x_lo[k];
+  uint16 y = tagalong_y_hi[k] << 8 | tagalong_y_lo[k];
+  uint16 z = (int8)tagalong_z[k];
+  y += z + 12;
+  x += 8;
+  return abs16(0x1568 - y) < 24 && abs16(0x1980 - x) < 24;
+}
+
+void Follower_Initialize() {  // 899efc
+  tagalong_y_lo[0] = link_y_coord;
+  tagalong_y_hi[0] = link_y_coord >> 8;
+
+  tagalong_x_lo[0] = link_x_coord;
+  tagalong_x_hi[0] = link_x_coord >> 8;
+
+  tagalong_layerbits[0] = kTagalongFlags[link_is_on_lower_level] >> 2 | (link_direction_facing >> 1);
+  timer_tagalong_reacquire = 64;
+  tagalong_var2 = 0;
+  tagalong_var1 = 0;
+  tagalong_var3 = 0;
+  tagalong_var4 = 0;
+  link_speed_setting = 0;
+
+  if (enhanced_features0 & kFeatures0_TurnWhileDashing) {
+    link_player_handler_state = kPlayerState_Ground;
+    link_is_running = false;
+  }
+
+}
+
+void Sprite_BecomeFollower(int k) {  // 899f39
+  tagalong_var5 = 0;
+  int y = Sprite_GetY(k) - 6;
+  tagalong_y_lo[0] = y, tagalong_y_hi[0] = (y >> 8);
+  int x = Sprite_GetX(k) + 1;
+  tagalong_x_lo[0] = x, tagalong_x_hi[0] = (x >> 8);
+  tagalong_layerbits[0] = kTagalongFlags[link_is_on_lower_level] >> 2 | 1;
+  timer_tagalong_reacquire = 64;
+  tagalong_var1 = 0;
+  tagalong_var2 = 0;
+  tagalong_var3 = 0;
+  tagalong_var4 = 0;
+  link_speed_setting = 0;
+  tagalong_var5 = 0;
+  follower_dropped = 0;
+  Follower_MoveTowardsLink();
+}
+
+void Follower_Main() {  // 899fc4
+  if (!follower_indicator)
+    return;
+  if (follower_indicator == 0xe) {
+    Follower_HandleTrigger();
+    return;
+  }
+  int j = FindInByteArray(kTagalong_Tab0, follower_indicator, 3);
+  if (j >= 0 && submodule_index == 0 && !(j == 2 && overworld_screen_index & 0x40) && sign16(--word_7E02CD)) {
+    if (!Follower_ValidateMessageFreedom()) {
+      word_7E02CD = 0;
+    } else {
+      word_7E02CD = kTagalong_Tab1[j];
+      dialogue_message_index = kTagalong_Msg[j];
+      Main_ShowTextMessage();
+    }
+  }
+  if (j != 0)
+    Follower_NoTimedMessage();
+}
+
+void Follower_NoTimedMessage() {  // 89a02b
+  int k;
+
+  if (follower_dropped) {
+    Follower_NotFollowing();
+    return;
+  }
+
+  if (follower_indicator == 12) {
+    if (link_auxiliary_state != 0)
+      goto label_a;
+
+  } else if (follower_indicator == 13) {
+    if (link_auxiliary_state == 2 || player_near_pit_state == 2)
+      goto label_c;
+  } else {
+    goto label_a;
+  }
+
+  if (submodule_index != 0 || link_auxiliary_state == 1 || (link_state_bits & 0x80) || tagalong_var5 || tagalong_var3 ||
+    (int8)tagalong_z[tagalong_var2] > 0 || !(filtered_joypad_L & 0x80))
+    goto label_a;
+
+label_c:
+
+  if (follower_indicator == 13 && !player_is_indoors) {
+    if (link_player_handler_state == kPlayerState_Ether ||
+        link_player_handler_state == kPlayerState_Bombos ||
+        link_player_handler_state == kPlayerState_Quake)
+      goto label_a;
+    super_bomb_indicator_unk2 = 3;
+    super_bomb_indicator_unk1 = 0xbb;
+  }
+
+  follower_dropped = 128;
+  timer_tagalong_reacquire = 64;
+
+  k = tagalong_var2;
+  saved_tagalong_y = tagalong_y_lo[k] | tagalong_y_hi[k] << 8;
+  saved_tagalong_x = tagalong_x_lo[k] | tagalong_x_hi[k] << 8;
+  saved_tagalong_floor = link_is_on_lower_level;
+  saved_tagalong_indoors = player_is_indoors;
+  Follower_NotFollowing();
+  return;
+
+label_a:
+  Follower_CheckGameMode();
+}
+
+void Follower_CheckGameMode() {  // 89a0e1
+  if (Tagalong_IsFollowing() && (link_x_vel | link_y_vel)) {
+    int k = tagalong_var1 + 1;
+    if (k == 20)
+      k = 0;
+    tagalong_var1 = k;
+    uint8 z = link_z_coord;
+    if (z >= 0xf0)
+      z = 0;
+    tagalong_z[k] = z;
+    uint16 y = link_y_coord - z;
+    tagalong_y_lo[k] = y;
+    tagalong_y_hi[k] = y >> 8;
+    uint16 x = link_x_coord;
+    tagalong_x_lo[k] = x;
+    tagalong_x_hi[k] = x >> 8;
+    uint8 layerbits = link_direction_facing >> 1 | kTagalongFlags[link_is_on_lower_level] >> 2;
+    if (link_player_handler_state == kPlayerState_Swimming) {
+      layerbits |= 0x20;
+    } else {
+      if (link_player_handler_state == kPlayerState_Hookshot && related_to_hookshot)
+        layerbits |= 0x10;
+      if (draw_water_ripples_or_grass)
+        layerbits |= (draw_water_ripples_or_grass == 1) ? 0x80 : 0x40;
+    }
+    tagalong_layerbits[k] = layerbits;
+  }
+
+  switch (follower_indicator) {
+  case 2: case 4:
+    Follower_OldMan();
+    return;
+  case 3: case 11:
+    Follower_OldManUnused();
+    return;
+  case 5: case 14:
+    assert(0); // Y is unknown here...
+    return;
+  default:
+    Follower_BasicMover();
+    return;
+  }
+}
+
+void Follower_BasicMover() {  // 89a197
+  int k;
+  if (!Tagalong_IsFollowing()) {
+    Tagalong_Draw();
+    return;
+  }
+
+  Follower_HandleTrigger();
+
+  if (follower_indicator == 10 && link_auxiliary_state && countdown_for_blink) {
+    int k = tagalong_var2 + 1 == 20 ? 0 : tagalong_var2 + 1;
+    Kiki_SpawnHandler_B(k);
+    follower_indicator = 0;
+    return;
+  }
+
+  if (follower_indicator == 6 && dungeon_room_index == 0xac && (save_dung_info[101] & 0x100) && Follower_CheckBlindTrigger()) {
+    int k = tagalong_var2;
+    uint16 x = tagalong_x_lo[k] | tagalong_x_hi[k] << 8;
+    uint16 y = tagalong_y_lo[k] | tagalong_y_hi[k] << 8;
+    follower_indicator = 0;
+    Blind_SpawnFromMaiden(x, y);
+    BYTE(dung_flag_trapdoors_down)++;
+    BYTE(dung_cur_door_pos) = 0;
+    BYTE(door_animation_step_indicator) = 0;
+    submodule_index = 5;
+    music_control = 21;
+    return;
+  }
+
+  if (!tagalong_var3) {
+    if (link_player_handler_state == kPlayerState_Hookshot && related_to_hookshot) {
+      tagalong_var3 = 1;
+      goto label_e;
+    }
+  } else {
+    if (link_player_handler_state == kPlayerState_Hookshot)
+      goto label_e;
+    if (tagalong_var7 != tagalong_var2)
+      goto label_d;
+    tagalong_var3 = 0;
+  }
+
+  k = tagalong_var2;
+  if ((int8)tagalong_z[k] > 0) {
+    if (tagalong_var1 != k)
+      goto label_d;
+    tagalong_z[k] = 0;
+    uint16 y = link_y_coord, x = link_x_coord;
+    tagalong_y_lo[k] = y;
+    tagalong_y_hi[k] = y >> 8;
+    tagalong_x_lo[k] = x;
+    tagalong_x_hi[k] = x >> 8;
+  }
+
+  if (link_x_vel | link_y_vel) {
+    uint8 t;
+label_e:
+    t = tagalong_var1 - 15;
+    if (sign8(t))
+      t += 20;
+    if (t == tagalong_var2) {
+label_d:
+      tagalong_var2 = (tagalong_var2 + 1 == 20) ? 0 : tagalong_var2 + 1;
+    }
+  }
+  Tagalong_Draw();
+}
+
+void Follower_NotFollowing() {  // 89a2b2
+  if (saved_tagalong_indoors != player_is_indoors)
+    return;
+  if (!link_is_running && !Follower_CheckProximityToLink()) {
+    Follower_Initialize();
+    saved_tagalong_indoors = player_is_indoors;
+    if (follower_indicator == 13) {
+      super_bomb_indicator_unk2 = 254;
+      super_bomb_indicator_unk1 = 0;
+    }
+    follower_dropped = 0;
+    Tagalong_Draw();
+  } else {
+    if (follower_indicator == 13 && !player_is_indoors && !super_bomb_indicator_unk2) {
+      // Fixed so we wait a little bit if we can't spawn the ancilla
+      if (AncillaAdd_SuperBombExplosion(0x3a, 0) >= 0) {
+        follower_dropped = 0;
+
+        // A ticking super bomb will cancel and teleport back to you as a follower if you do
+        // any of these at count 0: (1) change screen via walking, mirror, or bird travel
+        // (2) fill all ancillary slots
+        // (3) die with a bottled faerie.
+        // Fixed this by clearing the follower indicator here, instead of in the ancilla
+        // bomb code.
+        if (enhanced_features0 & kFeatures0_MiscBugFixes) {
+          follower_indicator = 0;
+          return;
+        }
+      } else {
+        super_bomb_indicator_unk1 = 1;
+      }
+    }
+    Follower_DoLayers();
+  }
+}
+
+void Follower_OldMan() {  // 89a318
+  uint8 t;
+
+  if (!Tagalong_IsFollowing()) {
+    Tagalong_Draw();
+    return;
+  }
+
+  if (link_speed_setting != 4)
+    link_speed_setting = 12;
+
+  Follower_HandleTrigger();
+
+  if (follower_indicator == 0) {
+    return;
+  } else if (follower_indicator == 4) {
+    if ((int8)tagalong_z[tagalong_var2] > 0 && tagalong_var1 != tagalong_var2) {
+      tagalong_var2 = (tagalong_var2 + 1 >= 20) ? 0 : tagalong_var2 + 1;
+      Tagalong_Draw();
+      return;
+    }
+  } else {
+    // tagalong type 2
+    if ((link_auxiliary_state & 1) && link_player_handler_state == kPlayerState_RecoilOther) {
+      if (tagalong_var1 != tagalong_var2)
+        goto transform;
+      assert(0); // X is undefined here
+    }
+
+    if (link_auxiliary_state & 2) {
+transform:
+      follower_indicator = kTagalong_Tab4[follower_indicator];
+      timer_tagalong_reacquire = 64;
+      int k = tagalong_var2;
+      saved_tagalong_y = tagalong_y_lo[k] | tagalong_y_hi[k] << 8;
+      saved_tagalong_x = tagalong_x_lo[k] | tagalong_x_hi[k] << 8;
+      saved_tagalong_floor = link_is_on_lower_level;
+      Follower_OldManUnused();
+      return;
+    }
+  }
+
+  if (link_x_vel | link_y_vel) {
+    t = tagalong_var1 - 20;
+    if (sign8(t))
+      t += 20;
+    if (t == tagalong_var2) {
+      tagalong_var2 = (tagalong_var2 + 1 >= 20) ? 0 : tagalong_var2 + 1;
+    }
+  } else if ((frame_counter & 3) == 0 && tagalong_var1 != tagalong_var2) {
+    t = tagalong_var1 - 9;
+    if (sign8(t))
+      t += 20;
+    if (t != tagalong_var2) {
+      tagalong_var2 = (tagalong_var2 + 1 >= 20) ? 0 : tagalong_var2 + 1;
+    }
+  }
+  Tagalong_Draw();
+}
+
+void Follower_OldManUnused() {  // 89a41f
+  link_speed_setting = 16;
+  if (!link_is_running && !link_auxiliary_state && link_player_handler_state != kPlayerState_Swimming) {
+    link_speed_setting = 0;
+    if (link_player_handler_state != kPlayerState_Hookshot && !Follower_CheckProximityToLink()) {
+      Follower_Initialize();
+      follower_indicator = kTagalong_Tab5[follower_indicator];
+      return;
+    }
+  }
+  Follower_DoLayers();
+}
+
+void Follower_DoLayers() {  // 89a450
+  oam_priority_value = kTagalongFlags[saved_tagalong_floor] << 8;
+  uint8 a = (follower_indicator == 12 || follower_indicator == 13) ? 2 : 1;
+  Follower_AnimateMovement_preserved(a, saved_tagalong_x, saved_tagalong_y);
+}
+
+bool Follower_CheckProximityToLink() {  // 89a48e
+  if (!sign8(--timer_tagalong_reacquire))
+    return true;
+  timer_tagalong_reacquire = 0;
+  if ((uint16)(saved_tagalong_y - 1) >= link_y_coord ||
+      (uint16)(saved_tagalong_y + 19) < link_y_coord ||
+      (uint16)(saved_tagalong_x - 1) >= link_x_coord ||
+      (uint16)(saved_tagalong_x + 19) < link_x_coord)
+    return true;
+  return false;
+}
+
+void Follower_HandleTrigger() {  // 89a59e
+  if (submodule_index)
+    return;
+
+  const TagalongMessageInfo *tmi, *tmi_end;
+  if (player_is_indoors) {
+    int j = FindInWordArray(kTagalong_IndoorRooms, dungeon_room_index, 7);
+    if (j < 0)
+      return;
+    tmi = kTagalong_IndoorInfos + kTagalong_IndoorOffsets[j];
+    tmi_end = kTagalong_IndoorInfos + kTagalong_IndoorOffsets[j + 1];
+  } else {
+    int j = FindInWordArray(kTagalong_OutdoorRooms, overworld_screen_index, 3);
+    if (j < 0)
+      return;
+    tmi = kTagalong_OutdoorInfos + kTagalong_OutdoorOffsets[j];
+    tmi_end = kTagalong_OutdoorInfos + kTagalong_OutdoorOffsets[j + 1];
+  }
+  int st = (tagalong_var2 + 1 >= 20) ? 0 : tagalong_var2 + 1;
+  do {
+    if (tmi->tagalong == follower_indicator && Follower_CheckForTrigger(tmi)) {
+      if (tmi->bit & tagalong_event_flags)
+        return;
+      tagalong_event_flags |= tmi->bit;
+      dialogue_message_index = tmi->msg;
+      if (tmi->msg == 0xffff) {
+        if (!(tmi->bit & 3))
+          Kiki_RevertToSprite(st);
+        else if (!(save_ow_event_info[BYTE(overworld_screen_index)] & 1))
+          Kiki_SpawnHandler_A(st);
+        return;
+      }
+      if (tmi->msg == 0x9d) {
+        OldMan_RevertToSprite(st);
+      } else if (tmi->msg == 0x28) {
+        follower_indicator = 0;
+      }
+      Main_ShowTextMessage();
+      return;
+    }
+  } while (++tmi != tmi_end);
+}
+
+void Tagalong_Draw() {  // 89a907
+  if (tagalong_var5)
+    return;
+  oam_priority_value =
+    ((tagalong_z[tagalong_var2] && !player_is_indoors) ? 0x20 :
+    (submodule_index == 14) ? kTagalongFlags[link_is_on_lower_level] :
+                              (tagalong_layerbits[tagalong_var2] & 0xc) << 2) << 8;
+  int k = tagalong_var2;
+  if (sign8(k))
+    k = 0;
+  uint16 x = tagalong_x_lo[k] | tagalong_x_hi[k] << 8;
+  uint16 y = tagalong_y_lo[k] | tagalong_y_hi[k] << 8;
+  uint8 a = tagalong_layerbits[k];
+  Follower_AnimateMovement_preserved(a, x, y);
+}
+
+static inline void SetOam_Follower(OamEnt *oam, uint16 x, uint16 y, uint8 charnum, uint8 flags, uint8 big) {
+  oam->x = x;
+  oam->y = (uint16)(x + 0x80) < 0x180 && (big |= x >> 8 & 1, (uint16)(y + 0x10) < 0x100) ? y : 0xf0;
+  oam->charnum = charnum;
+  oam->flags = flags;
+  bytewise_extended_oam[oam - oam_buf] = big;
+}
+
+
+void Follower_AnimateMovement_preserved(uint8 ain, uint16 xin, uint16 yin) {  // 89a959
+
+  uint8 yt = 0, av = 0;
+  uint8 sc = 0;
+
+  if ((ain >> 2 & 8) && (follower_indicator == 6 || follower_indicator == 1)) {
+    yt = 8;
+    if (swimcoll_var7[0] | swimcoll_var7[1])
+      av = (frame_counter >> 1) & 4;
+    else
+      av = (frame_counter >> 2) & 4;
+  } else if (submodule_index == 8 || submodule_index == 14 || submodule_index == 16) {
+    av = link_is_running ? (frame_counter & 4) : ((frame_counter >> 1) & 4);
+  } else if (follower_indicator == 11) {
+    av = (frame_counter >> 1) & 4;
+  } else if ((follower_indicator == 12 || follower_indicator == 13) && follower_dropped || flag_is_link_immobilized ||
+             submodule_index == 10 || main_module_index == 9 && submodule_index == 0x23 ||
+             main_module_index == 14 && (submodule_index == 1 || submodule_index == 2) ||
+             (link_y_vel | link_x_vel) == 0) {
+    av = sc = 4;
+  } else {
+    av = link_is_running ? (frame_counter & 4) : ((frame_counter >> 1) & 4);
+  }
+  uint8 frame = (ain & 3) + av + yt;
+
+  int spr_offs =
+    (link_y_coord == yin && !(ain & 3) || link_y_coord < yin) ?
+      kTagalongDraw_SprOffs0[sort_sprites_setting] >> 2:
+      kTagalongDraw_SprOffs1[sort_sprites_setting] >> 2;
+  oam_ext_cur_ptr = 0xa20 + spr_offs;
+  oam_cur_ptr = 0x800 + spr_offs * 4;
+
+  OamEnt *oam = GetOamCurPtr();
+  uint16 scrolly = yin - BG2VOFS_copy2;
+  uint16 scrollx = xin - BG2HOFS_copy2;
+
+  const uint8 *sk = kTagalongDraw_SprInfo0;
+  if (follower_indicator == 1 || follower_indicator == 6 || !(ain & 0x20)) {
+    if (!(ain & 0xc0))
+      goto skip_first_sprites;
+    if ((ain & 0x80) || (sk += 12, sc == 0))
+      goto incr;
+    byte_7E02D7 = 0;
+  } else {
+incr:
+    if (!(frame_counter & 7) && ++byte_7E02D7 == 3)
+      byte_7E02D7 = 0;
+  }
+  sk += byte_7E02D7 * 4;
+  SetOam_Follower(oam + 0, scrollx, scrolly + 16, sk[0], sk[1], 0);
+  SetOam_Follower(oam + 1, scrollx + 8, scrolly + 16, sk[2], sk[3], 0);
+  oam += 2;
+ uint8 pal;
+skip_first_sprites:
+  pal = kTagalongDraw_Pals[follower_indicator];
+  if (pal == 7 && palette_swap_flag)
+    pal = 0;
+
+  if (follower_indicator == 13) {
+    // Display colorful superbomb palette also on frame 0.
+    if (enhanced_features0 & kFeatures0_MiscBugFixes ? (super_bomb_indicator_unk2 <= 1) : (super_bomb_indicator_unk2 == 1))
+     pal = (frame_counter & 7);
+  }
+
+  const TagalongSprXY *sprd = kTagalongDraw_SprXY + frame + (kTagalongDraw_Offs[follower_indicator] >> 3);
+  const TagalongDmaFlags *sprf = kTagalongDmaAndFlags + frame;
+
+  if (follower_indicator != 12 && follower_indicator != 13) {
+    SetOam_Follower(oam, scrollx + sprd->x1, scrolly + sprd->y1, 0x20, 
+                  (sprf->flags & 0xf0) | pal << 1 | (oam_priority_value >> 8), 2);
+    oam++;
+    BYTE(dma_var6) = sprf->dma6;
+  }
+  {
+    SetOam_Follower(oam, scrollx + sprd->x2, scrolly + sprd->y2 + 8, 0x22,
+                  ((sprf->flags & 0xf) << 4) | pal << 1 | (oam_priority_value >> 8), 2);
+    BYTE(dma_var7) = sprf->dma7;
+  }
+}
+
+bool Follower_CheckForTrigger(const TagalongMessageInfo *info) {  // 89ac26
+  uint16 x = link_x_coord + 12 - (info->x + 8);
+  uint16 y = link_y_coord + 12 - (info->y + 8);
+  if (sign16(x))
+    x = -x;
+  if (sign16(y))
+    y = -y;
+  return x < 24 && y < 28;
+}
+
+void Follower_Disable() {  // 89acf3
+  if (follower_indicator == 9 || follower_indicator == 10)
+    follower_indicator = 0;
+}
+
+void Blind_SpawnFromMaiden(uint16 x, uint16 y) {  // 9da03c
+  int k = 0;
+  sprite_state[k] = 9;
+  sprite_type[k] = 206;
+  Sprite_SetX(k, x);
+  Sprite_SetY(k, y - 16);
+  SpritePrep_LoadProperties(k);
+  sprite_delay_aux2[k] = 192;
+  sprite_graphics[k] = 21;
+  sprite_D[k] = 2;
+  sprite_ignore_projectile[k] = 2;
+  dung_savegame_state_bits |= 0x2000;
+  byte_7E0B69 = 0;
+}
+
+void Kiki_RevertToSprite(int k) {  // 9ee66b
+  int j = Kiki_SpawnHandlerMonke(k);
+  sprite_subtype2[j] = 1;
+  follower_indicator = 0;
+}
+
+int Kiki_SpawnHandlerMonke(int k) {  // 9ee67a
+  SpriteSpawnInfo info;
+  int j = Sprite_SpawnDynamically(k, 0xb6, &info);
+  if (j >= 0) {
+    sprite_head_dir[j] = tagalong_layerbits[k] & 3;
+    sprite_D[j] = tagalong_layerbits[k] & 3;
+    int x = tagalong_x_hi[k] << 8 | tagalong_x_lo[k];
+    int y = tagalong_y_hi[k] << 8 | tagalong_y_lo[k];
+    Sprite_SetX(j, x + 2);
+    Sprite_SetY(j, y + 2);
+    sprite_floor[j] = link_is_on_lower_level;
+    sprite_ignore_projectile[j] = 1;
+    sprite_floor[j] = 2;
+    link_speed_setting = 0;
+  }
+  return j;
+}
+
+void Kiki_SpawnHandler_A(int k) {  // 9ee6c7
+  int j = Kiki_SpawnHandlerMonke(k);
+  sprite_subtype2[j] = 2;
+}
+
+void Kiki_SpawnHandler_B(int k) {  // 9ee6d0
+  int j = Kiki_SpawnHandlerMonke(k);
+  sprite_z[j] = 1;
+  sprite_z_vel[j] = 16;
+  sprite_subtype2[j] = 3;
+  follower_indicator = 0;
+}
+
--- /dev/null
+++ b/src/tagalong.h
@@ -1,0 +1,32 @@
+#pragma once
+#include "types.h"
+
+typedef struct TagalongMessageInfo {
+  uint16 y, x, bit, msg, tagalong;
+} TagalongMessageInfo;
+
+bool Tagalong_IsFollowing();
+bool Follower_ValidateMessageFreedom();
+void Follower_MoveTowardsLink();
+bool Follower_CheckBlindTrigger();
+void Follower_Initialize();
+void Sprite_BecomeFollower(int k);
+void Follower_Main();
+void Follower_NoTimedMessage();
+void Follower_CheckGameMode();
+void Follower_BasicMover();
+void Follower_NotFollowing();
+void Follower_OldMan();
+void Follower_OldManUnused();
+void Follower_DoLayers();
+bool Follower_CheckProximityToLink();
+void Follower_HandleTrigger();
+void Tagalong_Draw();
+void Follower_AnimateMovement_preserved(uint8 ain, uint16 xin, uint16 yin);
+bool Follower_CheckForTrigger(const TagalongMessageInfo *info);
+void Follower_Disable();
+void Blind_SpawnFromMaiden(uint16 x, uint16 y);
+void Kiki_RevertToSprite(int k);
+int Kiki_SpawnHandlerMonke(int k);
+void Kiki_SpawnHandler_A(int k);
+void Kiki_SpawnHandler_B(int k);
--- /dev/null
+++ b/src/tile_detect.c
@@ -1,0 +1,527 @@
+#include "tile_detect.h"
+#include "zelda_rtl.h"
+#include "ancilla.h"
+#include "variables.h"
+#include "overworld.h"
+
+static const uint8 kDetectTiles_tab0[] = { 8, 24, 0, 15 };
+static const uint8 kDetectTiles_tab1[] = { 0, 0, 8, 8 };
+static const uint8 kDetectTiles_tab2[] = { 8, 8, 16, 16 };
+static const uint8 kDetectTiles_tab3[] = { 15, 15, 23, 23 };
+static const int8 kDetectTiles_tab4[] = { 7, 24, -1, 16 };
+static const uint8 kDetectTiles_tab5[] = { 0, 0, 8, 8 };
+static const uint8 kDetectTiles_tab6[] = { 15, 15, 23, 23 };
+uint8 Overworld_GetTileAttributeAtLocation(uint16 x, uint16 y) {  // 80882e
+  uint16 t;
+
+  t = ((y - overworld_offset_base_y) & overworld_offset_mask_y) * 8;
+  t |= ((x - overworld_offset_base_x) & overworld_offset_mask_x);
+  t = overworld_tileattr[t >> 1] * 4;
+  t |= (y & 8) >> 2;
+  t |= (x & 1);
+  t = GetMap16toMap8Table()[t];
+
+  uint8 rv = GetMap8toTileAttr()[t & 0x1ff];
+  if (rv >= 0x10 && rv < 0x1C) {
+    rv |= (t >> 14) & 1;
+  }
+  return rv;
+}
+
+void TileDetect_Movement_Y(uint16 direction) {  // 87cdcb
+  assert(direction < 4);
+  TileDetect_ResetState();
+  tiledetect_pit_tile = 0;
+
+  tiledetect_which_y_pos[0] = (link_y_coord + kDetectTiles_tab0[direction]);
+  uint16 y = tiledetect_which_y_pos[0] & tilemap_location_calc_mask;
+  uint16 x0 = ((link_x_coord + kDetectTiles_tab1[direction]) & tilemap_location_calc_mask) >> 3;
+  uint16 x1 = ((link_x_coord + kDetectTiles_tab2[direction]) & tilemap_location_calc_mask) >> 3;
+  uint16 x2 = ((link_x_coord + kDetectTiles_tab3[direction]) & tilemap_location_calc_mask) >> 3;
+  scratch_1 = x2;
+  TileDetection_Execute(x0, y, 1);
+  TileDetection_Execute(x1, y, 2);
+  TileDetection_Execute(x2, y, 4);
+}
+
+void TileDetect_Movement_X(uint16 direction) {  // 87ce2a
+  assert(direction < 4);
+  TileDetect_ResetState();
+  tiledetect_pit_tile = 0;
+
+  uint16 x = ((link_x_coord + kDetectTiles_tab0[direction]) & tilemap_location_calc_mask) >> 3;
+  uint16 y0 = ((link_y_coord + kDetectTiles_tab1[direction]) & tilemap_location_calc_mask);
+  tiledetect_which_y_pos[0] = link_y_coord + kDetectTiles_tab2[direction];
+  uint16 y1 = tiledetect_which_y_pos[0] & tilemap_location_calc_mask;
+  tiledetect_which_y_pos[1] = link_y_coord + kDetectTiles_tab3[direction];
+  uint16 y2 = tiledetect_which_y_pos[1] & tilemap_location_calc_mask;
+  TileDetection_Execute(x, y0, 1);
+  TileDetection_Execute(x, y1, 2);
+  TileDetection_Execute(x, y2, 4);
+}
+
+void TileDetect_Movement_VerticalSlopes(uint16_t direction) {  // 87ce85
+  assert(direction < 4);
+  TileDetect_ResetState();
+  tiledetect_pit_tile = 0;
+
+  uint16 y = (link_y_coord + kDetectTiles_tab4[direction]) & tilemap_location_calc_mask;
+  uint16 x0 = ((link_x_coord + kDetectTiles_tab5[direction]) & tilemap_location_calc_mask) >> 3;
+  uint16 x1 = ((link_x_coord + kDetectTiles_tab6[direction]) & tilemap_location_calc_mask) >> 3;
+  TileDetection_Execute(x0, y, 1);
+  TileDetection_Execute(x1, y, 2);
+}
+
+void TileDetect_Movement_HorizontalSlopes(uint16_t direction) {  // 87cec9
+  assert(direction < 4);
+  TileDetect_ResetState();
+  tiledetect_pit_tile = 0;
+
+  uint16 x = ((link_x_coord + kDetectTiles_tab4[direction]) & tilemap_location_calc_mask) >> 3;
+  uint16 y0 = ((link_y_coord + kDetectTiles_tab5[direction]) & tilemap_location_calc_mask);
+  uint16 y1 = ((link_y_coord + kDetectTiles_tab6[direction]) & tilemap_location_calc_mask);
+  TileDetection_Execute(x, y0, 1);
+  TileDetection_Execute(x, y1, 2);
+}
+
+void Player_TileDetectNearby() {  // 87cf12
+  TileDetect_ResetState();
+  tiledetect_pit_tile = 0;
+
+  uint16 x0 = ((link_x_coord + kDetectTiles_tab1[0]) & tilemap_location_calc_mask) >> 3;
+  uint16 x1 = ((link_x_coord + kDetectTiles_tab3[0]) & tilemap_location_calc_mask) >> 3;
+
+  uint16 y0 = ((link_y_coord + kDetectTiles_tab1[2]) & tilemap_location_calc_mask);
+  uint16 y1 = ((link_y_coord + kDetectTiles_tab3[2]) & tilemap_location_calc_mask);
+
+  scratch_1 = y0;
+
+  TileDetection_Execute(x0, y0, 8);
+  TileDetection_Execute(x0, y1, 2);
+  TileDetection_Execute(x1, y0, 4);
+  TileDetection_Execute(x1, y1, 1);
+}
+
+void Hookshot_CheckTileCollision(int k) {  // 87d576
+  uint8 bak0 = BYTE(dungeon_room_index);
+  uint8 bak1 = link_is_on_lower_level;
+
+  if (ancilla_arr1[k]) {
+    if (!BYTE(kind_of_in_room_staircase))
+      BYTE(dungeon_room_index) += 0x10;
+    link_is_on_lower_level ^= 1;
+  }
+
+  uint16 x = Ancilla_GetX(k), y = Ancilla_GetY(k);
+  int dir = ancilla_dir[k];
+
+  tiledetect_pit_tile = 0;
+  TileDetect_ResetState();
+  if (dung_hdr_collision == 2) {
+    link_is_on_lower_level = 1;
+    Hookshot_CheckSingleLayerTileCollision(x + BG1HOFS_copy2 - BG2HOFS_copy2, y + BG1VOFS_copy2 - BG2VOFS_copy2, dir);
+    link_is_on_lower_level = 0;
+  }
+  Hookshot_CheckSingleLayerTileCollision(x, y, dir);
+
+  link_is_on_lower_level = bak1;
+  BYTE(dungeon_room_index) = bak0;
+}
+
+void Hookshot_CheckSingleLayerTileCollision(uint16 x, uint16 y, int dir) {  // 87d607
+  static const uint8 kHookShot_CheckColl_X[8] = { 0, 15, 0, 15, 0, 0, 8, 8 };
+  static const uint8 kHookShot_CheckColl_Y[8] = { 0, 0, 7, 7, 0, 15, 0, 15 };
+  uint16 y0 = (y + kHookShot_CheckColl_Y[dir * 2 + 0]) & tilemap_location_calc_mask;
+  uint16 y1 = (y + kHookShot_CheckColl_Y[dir * 2 + 1]) & tilemap_location_calc_mask;
+  uint16 x0 = ((x + kHookShot_CheckColl_X[dir * 2 + 0]) & tilemap_location_calc_mask) >> 3;
+  uint16 x1 = ((x + kHookShot_CheckColl_X[dir * 2 + 1]) & tilemap_location_calc_mask) >> 3;
+  TileDetection_Execute(x0, y0, 1);
+  TileDetection_Execute(x1, y1, 2);
+}
+
+void HandleNudgingInADoor(int8 speed) {  // 87d667
+  uint8 y;
+
+  if (link_last_direction_moved_towards & 2) {
+    y = (uint8)link_y_coord < 0x80 ? 1 : 0;
+  } else {
+    y = (uint8)link_x_coord < 0x80 ? 3 : 2;
+  }
+  tiledetect_pit_tile = 0;
+  TileDetect_ResetState();
+
+  static const int8 kDetectTiles_7_Y[] = { 8, 23, 16, 16 };
+  static const int8 kDetectTiles_7_X[] = { 8, 8, 0, 15 };
+
+  uint16 x0 = ((link_x_coord + kDetectTiles_7_X[y]) & tilemap_location_calc_mask) >> 3;
+  uint16 y0 = ((link_y_coord + kDetectTiles_7_Y[y]) & tilemap_location_calc_mask);
+
+  TileDetection_Execute(x0, y0, 1);
+
+  if (((R14 | detection_of_ledge_tiles_horiz_uphoriz) & 3) == 0) {
+    if (((tiledetect_vertical_ledge | detection_of_unknown_tile_types) & 0x33) == 0)
+      return;
+  }
+
+  if (link_last_direction_moved_towards & 2)
+    link_y_coord -= speed;
+  else
+    link_x_coord -= speed;
+}
+
+void TileCheckForMirrorBonk() {  // 87d6f4
+  tiledetect_pit_tile = 0;
+  TileDetect_ResetState();
+
+  uint16 x0 = ((link_x_coord + 2) & tilemap_location_calc_mask) >> 3;
+  uint16 x1 = ((link_x_coord + 13) & tilemap_location_calc_mask) >> 3;
+
+  uint16 y0 = ((link_y_coord + 10) & tilemap_location_calc_mask);
+  uint16 y1 = ((link_y_coord + 21) & tilemap_location_calc_mask);
+
+  scratch_1 = y0;
+
+  TileDetection_Execute(x0, y0, 8);
+  TileDetection_Execute(x0, y1, 2);
+  TileDetection_Execute(x1, y0, 4);
+  TileDetection_Execute(x1, y1, 1);
+
+}
+
+// Used when holding sword in doorway
+void TileDetect_SwordSwingDeepInDoor(uint8 dw) {  // 87d73e
+  tiledetect_pit_tile = 0;
+  TileDetect_ResetState();
+
+  static const int8 kDoorwayDetectX[] = { 8, 8, -1, 16 };
+  static const int8 kDoorwayDetectY[] = { -1, 24, 16, 16 };
+  int o = (dw - 1) * 2;
+  uint16 x0 = ((link_x_coord + kDoorwayDetectX[o + 0]) & tilemap_location_calc_mask) >> 3;
+  uint16 x1 = ((link_x_coord + kDoorwayDetectX[o + 1]) & tilemap_location_calc_mask) >> 3;
+
+  uint16 y0 = ((link_y_coord + kDoorwayDetectY[o + 0]) & tilemap_location_calc_mask);
+  uint16 y1 = ((link_y_coord + kDoorwayDetectY[o + 1]) & tilemap_location_calc_mask);
+
+  TileDetection_Execute(x0, y0, 1);
+  TileDetection_Execute(x1, y1, 2);
+}
+
+void TileDetect_ResetState() {  // 87d798
+  R12 = 0;
+  R14 = 0;
+  tiledetect_diagonal_tile = 0;
+  tiledetect_stair_tile = 0;
+  tiledetect_pit_tile = 0;
+  tiledetect_inroom_staircase = 0;
+  tiledetect_var2 = 0;
+  tiledetect_var1 = 0;
+  tiledetect_moving_floor_tiles = 0;
+  tiledetect_deepwater = 0;
+  tiledetect_normal_tiles = 0;
+  tiledetect_icy_floor = 0;
+  tiledetect_water_staircase = 0;
+  tiledetect_thick_grass = 0;
+  tiledetect_shallow_water = 0;
+  tiledetect_destruction_aftermath = 0;
+  tiledetect_read_something = 0;
+  tiledetect_vertical_ledge = 0;
+  detection_of_ledge_tiles_horiz_uphoriz = 0;
+  tiledetect_ledges_down_leftright = 0;
+  detection_of_unknown_tile_types = 0;
+  tiledetect_chest = 0;
+  tiledetect_key_lock_gravestones = 0;
+  bitfield_spike_cactus_tiles = 0;
+  tiledetect_spike_floor_and_tile_triggers = 0;
+  bitmask_for_dashable_tiles = 0;
+  tiledetect_misc_tiles = 0;
+  tiledetect_var4 = 0;
+}
+
+void TileDetection_Execute(uint16 x, uint16 y, uint16 bits) {  // 87d9d8
+  uint8 tile;
+  uint16 offs = 0;
+  if (player_is_indoors) {
+    force_move_any_direction = force_move_any_direction & 0xff;
+    offs = (y & ~7) * 8 + (x & 63) + (link_is_on_lower_level ? 0x1000 : 0);
+    tile = dung_bg2_attr_table[offs];
+    if (cheatWalkThroughWalls)
+      tile = 0;
+    link_tile_below = tile;
+  } else {
+    tile = Overworld_GetTileAttributeAtLocation(x, y);
+  }
+  TileDetect_ExecuteInner(tile, offs, bits, player_is_indoors);
+}
+
+void TileDetect_ExecuteInner(uint8 tile, uint16 offs, uint16 bits, bool is_indoors) {  // 87dc2e
+  static const uint8 word_87DC55[] = { 4, 0, 6, 2 };
+  if (cheatWalkThroughWalls)
+    tile = 0;
+
+  switch (tile) {
+  case 0x00: case 0x05: case 0x06: case 0x07: case 0x14: case 0x15: case 0x16: case 0x17: case 0x21: case 0x23: case 0x24: case 0x25: case 0x38: case 0x39: case 0x3a: case 0x3b: case 0x3c: case 0x41: case 0x45: case 0x47: case 0x49: case 0x5e: case 0x5f: case 0x61: case 0x62: case 0x64: case 0x65: case 0x66: case 0xa6: case 0xa7: case 0xbe: case 0xbf: case 0xd0: case 0xd1: case 0xd2: case 0xd3: case 0xd4: case 0xd5: case 0xd6: case 0xd7: case 0xd8: case 0xd9: case 0xda: case 0xdb: case 0xdc: case 0xdd: case 0xde: case 0xdf: case 0xe0: case 0xe1: case 0xe2: case 0xe3: case 0xe4: case 0xe5: case 0xe6: case 0xe7: case 0xe8: case 0xe9: case 0xea: case 0xeb: case 0xec: case 0xed: case 0xee: case 0xef:  // TileBehavior_NothingOW
+    if (!is_indoors)
+      tiledetect_normal_tiles |= bits;
+    break;
+  case 0x01: case 0x02: case 0x03:  // TileBehavior_StandardCollision
+  case 0x26: case 0x43:
+    R14 |= bits;
+    break;
+  case 0x6c: case 0x6d: case 0x6e: case 0x6f:
+    if (is_indoors)
+      R14 |= bits;
+    else
+      tiledetect_normal_tiles |= bits;
+    break;
+  case 0x04:
+    if (is_indoors) {
+      R14 |= bits;
+    } else {
+      tiledetect_thick_grass |= bits;
+    }
+    break;
+  case 0x0b:
+    if (is_indoors) {
+      R14 |= bits;
+    } else {
+      index_of_interacting_tile = tile;
+      tiledetect_deepwater |= bits << 4;
+    }
+    break;
+  case 0x08:  // TileBehavior_DeepWater
+    tiledetect_deepwater |= bits;
+    break;
+  case 0x09:  // TileBehavior_ShallowWater
+    tiledetect_shallow_water |= bits;
+    break;
+  case 0x0a:  // TileBehavior_ShortWaterLadder
+    tiledetect_normal_tiles |= bits;
+    break;
+  case 0x0c:  // TileBehavior_OverlayMask_0C
+    tiledetect_moving_floor_tiles |= bits;
+    break;
+  case 0x0d:  // TileBehavior_SpikeFloor
+    if (!flag_block_link_menu && !(dung_savegame_state_bits & 0x8000))
+      tiledetect_spike_floor_and_tile_triggers |= bits << 4;
+    break;
+  case 0x0e:  // TileBehavior_GanonIce
+    tiledetect_icy_floor |= bits;
+    break;
+  case 0x0f:  // TileBehavior_PalaceIce
+    tiledetect_icy_floor |= bits << 4;
+    break;
+  case 0x10: case 0x11: case 0x12: case 0x13:  // TileBehavior_Slope
+    R12 |= bits;
+    tiledetect_diag_state = word_87DC55[tile & 3];
+    break;
+  case 0x18: case 0x19: case 0x1a: case 0x1b:  // TileBehavior_SlopeOuter
+    tiledetect_diagonal_tile |= bits;
+    R12 |= bits;
+    tiledetect_diag_state = word_87DC55[tile & 3];
+    break;
+  case 0x1c:  // TileBehavior_OverlayMask_1C
+    tiledetect_water_staircase |= bits;
+    break;
+  case 0x1d:  // TileBehavior_NorthSingleLayerStairs
+    index_of_interacting_tile = tile;
+    tiledetect_inroom_staircase |= bits;
+    tiledetect_stair_tile |= bits;
+    break;
+  case 0x1e: case 0x1f:  // TileBehavior_NorthSwapLayerStairs
+    index_of_interacting_tile = tile;
+    tiledetect_inroom_staircase |= bits;
+    tiledetect_stair_tile |= bits;
+    break;
+  case 0x20: case 0xb0: case 0xb1: case 0xb2: case 0xb3: case 0xb4: case 0xb5: case 0xb6: case 0xb7: case 0xb8: case 0xb9: case 0xba: case 0xbb: case 0xbc: case 0xbd:  // TileBehavior_Pit
+    if (!player_on_somaria_platform)
+      tiledetect_pit_tile |= bits;
+    break;
+  case 0x22: case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37:  // TileHandlerIndoor_22
+    tiledetect_stair_tile |= bits;
+    break;
+  case 0x27:  // TileBehavior_Hookshottables
+    R14 |= bits;
+    tiledetect_misc_tiles |= bits;
+    break;
+  case 0x28:  // TileBehavior_Ledge_North
+    index_of_interacting_tile = tile;
+    tiledetect_vertical_ledge |= bits;
+    break;
+  case 0x29:  // TileBehavior_Ledge_South
+    index_of_interacting_tile = tile;
+    tiledetect_vertical_ledge |= bits << 4;
+    break;
+  case 0x2a: case 0x2b:  // TileBehavior_Ledge_EastWest
+    index_of_interacting_tile = tile;
+    detection_of_ledge_tiles_horiz_uphoriz |= bits;
+    break;
+  case 0x2c: case 0x2e:  // TileBehavior_Ledge_NorthDiagonal
+    index_of_interacting_tile = tile;
+    detection_of_ledge_tiles_horiz_uphoriz |= bits << 4;
+    break;
+  case 0x2d: case 0x2f:  // TileBehavior_Ledge_SouthDiagonal
+    index_of_interacting_tile = tile;
+    tiledetect_ledges_down_leftright |= bits;
+    break;
+  case 0x3d: case 0x3e: case 0x3f:  // TileHandlerIndoor_3E
+    index_of_interacting_tile = tile;
+    tiledetect_inroom_staircase |= bits << 4;
+    tiledetect_stair_tile |= bits;
+    break;
+  case 0x40:  // TileBehavior_ThickGrass
+    tiledetect_thick_grass |= bits;
+    break;
+  case 0x44:  // TileBehavior_Spike
+    if (!flag_block_link_menu && !(dung_savegame_state_bits & 0x8000))
+      bitfield_spike_cactus_tiles |= bits;
+    else
+      R14 |= bits;
+    break;
+  case 0x46:  // TileBehavior_HylianPlaque
+    tiledetect_spike_floor_and_tile_triggers |= bits;
+    R14 |= bits;
+    break;
+  case 0x48: case 0x4a:  // TileBehavior_DiggableGround
+    tiledetect_destruction_aftermath |= bits;
+    tiledetect_normal_tiles |= bits;
+    break;
+  case 0x4b:  // TileBehavior_Warp
+    tiledetect_thick_grass |= bits << 4;
+    break;
+  case 0x50: case 0x51: case 0x52: case 0x53: case 0x54: case 0x55: case 0x56: { // TileBehavior_Liftable
+    static const uint8 kTile50data[] = { 0x54, 0x52, 0x50, 0x51, 0x53, 0x55, 0x56 };
+    for (int i = 6; i >= 0; i--) {
+      if (kTile50data[i] == tile) {
+        if (tile == 0x50 || tile == 0x51)
+          bitmask_for_dashable_tiles |= bits << 4;
+        tiledetect_read_something |= bits;
+        interacting_with_liftable_tile_x2 = i * 2;
+        R14 |= bits;
+        tiledetect_misc_tiles |= bits;
+        break;
+      }
+    }
+    break;
+  }
+  case 0x57:  // TileBehavior_BonkRocks
+    R14 |= bits;
+    bitmask_for_dashable_tiles |= bits << 4;
+    break;
+  case 0x58: case 0x59: case 0x5a: case 0x5b: case 0x5c: case 0x5d:  // TileBehavior_Chest
+    tiledetect_misc_tiles |= bits;
+    index_of_interacting_tile = tile;
+    if (dung_chest_locations[tile - 0x58] >= 0x8000) {
+      R14 |= bits;
+      tiledetect_key_lock_gravestones |= bits << 4;
+      if (bits & 2)
+        tiledetect_tile_type = tile;
+    } else {
+      tiledetect_chest |= bits;  // small key lock
+      R14 |= bits;
+    }
+    break;
+  case 0x60:  // TileBehavior_RupeeTile
+    if (is_indoors) {
+      if (dung_bg2_attr_table[offs + 64] == 0x60) {
+        tiledetect_misc_tiles |= bits << 8;
+      } else {
+        tiledetect_misc_tiles |= bits << 12;
+      }
+    } else {
+      tiledetect_normal_tiles |= bits;
+    }
+    break;
+  case 0x63:  // TileBehavior_MinigameChest
+    tiledetect_misc_tiles |= bits;
+    index_of_interacting_tile = tile;
+    tiledetect_chest |= bits;  // small key lock
+    R14 |= bits;
+    break;
+  case 0x67:  // TileBehavior_CrystalPeg_Up
+    R14 |= bits;
+    tiledetect_misc_tiles |= bits;
+    bitfield_spike_cactus_tiles |= bits << 4;
+    break;
+  case 0x68:  // TileBehavior_Conveyor_Upwards
+    tiledetect_var4 |= bits;
+    break;
+  case 0x69:  // TileBehavior_Conveyor_Downwards
+    tiledetect_var4 |= bits << 4;
+    break;
+  case 0x6a:  // TileBehavior_Conveyor_Leftwards
+    tiledetect_var4 |= bits << 8;
+    break;
+  case 0x6b:  // TileBehavior_Conveyor_Rightwards
+    tiledetect_var4 |= bits << 12;
+    break;
+  case 0x70: case 0x71: case 0x72: case 0x73: case 0x74: case 0x75: case 0x76: case 0x77: case 0x78: case 0x79: case 0x7a: case 0x7b: case 0x7c: case 0x7d: case 0x7e: case 0x7f:  // TileBehavior_ManipulablyReplaced
+    if (bits & 2)
+      tiledetect_var2 |= 1 << (tile & 0xf);
+    R14 |= bits;
+    tiledetect_misc_tiles |= bits;
+    break;
+  case 0x80: case 0x81: case 0x84: case 0x85: case 0x86: case 0x87: case 0x88: case 0x89: case 0x8a: case 0x8b: case 0x8c: case 0x8d:  // TileHandlerIndoor_80
+    R14 |= bits << 4;
+    tiledetect_var1 = 2 * (tile & 1);
+    break;
+  case 0x82: case 0x83:  // TileHandlerIndoor_82
+    R14 |= (bits << 4) | (bits << 8);
+    tiledetect_var1 = 2 * (tile & 1);
+    break;
+  case 0x8e: case 0x8f:  // TileBehavior_Entrance
+    R14 |= bits << 4;
+    bitmask_for_dashable_tiles |= bits;
+    tiledetect_var1 = 0;
+    break;
+  case 0x90: case 0x91: case 0x92: case 0x93: case 0x94: case 0x95: case 0x96: case 0x97:  // TileBehavior_LayerToggleShutterDoor
+    room_transitioning_flags = 1;
+    R14 |= (bits << 4) | (bits << 8);
+    tiledetect_var1 = 2 * (tile & 1);
+    break;
+  case 0x98: case 0x99: case 0x9a: case 0x9b: case 0x9c: case 0x9d: case 0x9e: case 0x9f: case 0xa8: case 0xa9: case 0xaa: case 0xab: case 0xac: case 0xad: case 0xae: case 0xaf:  // TileBehavior_LayerAndDungeonToggleShutterDoor
+    room_transitioning_flags = 3;
+    R14 |= (bits << 4) | (bits << 8);
+    tiledetect_var1 = 2 * (tile & 1);
+    break;
+  case 0xa0: case 0xa1: case 0xa4: case 0xa5:  // TileBehavior_DungeonToggleManualDoor
+    room_transitioning_flags = 2;
+    R14 |= bits << 4;
+    tiledetect_var1 = 2 * (tile & 1);
+    break;
+  case 0xa2: case 0xa3:  // TileBehavior_DungeonToggleShutterDoor
+    room_transitioning_flags = 2;
+    R14 |= (bits << 4) | (bits << 8);
+    tiledetect_var1 = 2 * (tile & 1);
+    break;
+  case 0xc0: case 0xc1: case 0xc2: case 0xc3: case 0xc4: case 0xc5: case 0xc6: case 0xc7: case 0xc8: case 0xc9: case 0xca: case 0xcb: case 0xcc: case 0xcd: case 0xce: case 0xcf:  // TileBehavior_LightableTorch
+    R14 |= bits;
+    tiledetect_misc_tiles |= bits;
+    break;
+  case 0xf0: case 0xf1: case 0xf2: case 0xf3: case 0xf4: case 0xf5: case 0xf6: case 0xf7: case 0xf8: case 0xf9: case 0xfa: case 0xfb: case 0xfc: case 0xfd: case 0xfe: case 0xff:  // TileBehavior_FlaggableDoor
+    R14 |= bits;
+    tiledetect_misc_tiles |= bits << 4;
+    break;
+
+  case 0x42:  // TileBehavior_GraveStone
+    if (!is_indoors) {
+      tiledetect_key_lock_gravestones |= bits;
+      R14 |= bits;
+    }
+    break;
+  case 0x4c: case 0x4d:  // TileBehavior_UnusedCornerType
+    if (!is_indoors) {
+      index_of_interacting_tile = tile;
+      detection_of_unknown_tile_types |= bits;
+    }
+    break;
+  case 0x4e: case 0x4f:  // TileBehavior_EasternRuinsCorner
+    if (!is_indoors) {
+      index_of_interacting_tile = tile;
+      detection_of_unknown_tile_types |= bits << 4;
+    }
+    break;
+  default:
+    assert(0);
+  }
+}
+
--- /dev/null
+++ b/src/tile_detect.h
@@ -1,0 +1,18 @@
+#pragma once
+#include "types.h"
+
+
+uint8 Overworld_GetTileAttributeAtLocation(uint16 x, uint16 y);
+void TileDetect_Movement_Y(uint16 direction);
+void TileDetect_Movement_X(uint16 direction);
+void TileDetect_Movement_VerticalSlopes(uint16_t direction);
+void TileDetect_Movement_HorizontalSlopes(uint16_t direction);
+void Player_TileDetectNearby();
+void Hookshot_CheckTileCollision(int k);
+void Hookshot_CheckSingleLayerTileCollision(uint16 x, uint16 y, int dir);
+void HandleNudgingInADoor(int8 speed);
+void TileCheckForMirrorBonk();
+void TileDetect_SwordSwingDeepInDoor(uint8 dw);
+void TileDetect_ResetState();
+void TileDetection_Execute(uint16 x, uint16 y, uint16 bits);
+void TileDetect_ExecuteInner(uint8 tile, uint16 offs, uint16 bits, bool is_indoors);
--- /dev/null
+++ b/src/types.h
@@ -1,0 +1,103 @@
+#ifndef ZELDA3_TYPES_H_
+#define ZELDA3_TYPES_H_
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdbool.h>
+
+// Build time config options
+enum {
+  kEnableLargeScreen = 1,
+  // How much extra spacing to add on the sides
+  kPpuExtraLeftRight = kEnableLargeScreen ? 96 : 0,
+};
+
+typedef uint8_t uint8;
+typedef int8_t int8;
+typedef uint16_t uint16;
+typedef int16_t int16;
+typedef uint32_t uint32;
+typedef int32_t int32;
+typedef uint64_t uint64;
+typedef int64_t int64;
+typedef unsigned int uint;
+
+#define arraysize(x) sizeof(x)/sizeof(x[0])
+#define sign8(x) ((x) & 0x80)
+#define sign16(x) ((x) & 0x8000)
+#define load24(x) ((*(uint32*)&(x))&0xffffff)
+
+#ifdef _MSC_VER
+#define countof _countof
+#define NORETURN __declspec(noreturn)
+#define FORCEINLINE __forceinline
+#define NOINLINE __declspec(noinline)
+#else
+#define countof(a) (sizeof(a)/sizeof(*(a)))
+#define NORETURN
+#define FORCEINLINE inline
+#define NOINLINE
+#endif
+
+#ifdef _DEBUG
+#define kDebugFlag 1
+#else
+#define kDebugFlag 0
+#endif
+
+static FORCEINLINE uint16 abs16(uint16 t) { return sign16(t) ? -t : t; }
+static FORCEINLINE uint8 abs8(uint8 t) { return sign8(t) ? -t : t; }
+static FORCEINLINE int IntMin(int a, int b) { return a < b ? a : b; }
+static FORCEINLINE int IntMax(int a, int b) { return a > b ? a : b; }
+static FORCEINLINE uint UintMin(uint a, uint b) { return a < b ? a : b; }
+static FORCEINLINE uint UintMax(uint a, uint b) { return a > b ? a : b; }
+
+// windows.h defines this too
+#ifdef HIBYTE
+#undef HIBYTE
+#endif
+
+#define BYTE(x) (*(uint8*)&(x))
+#define HIBYTE(x) (((uint8*)&(x))[1])
+#define WORD(x) (*(uint16*)&(x))
+#define DWORD(x) (*(uint32*)&(x))
+#define XY(x, y) ((y)*64+(x))
+
+#ifndef swap16
+static inline uint16 swap16(uint16 v) { return (v << 8) | (v >> 8); }
+#endif
+
+typedef struct Point16U {
+  uint16 x, y;
+} Point16U;
+
+typedef struct PointU8 {
+  uint8 x, y;
+} PointU8;
+
+typedef struct Pair16U {
+  uint16 a, b;
+} Pair16U;
+
+typedef struct PairU8 {
+  uint8 a, b;
+} PairU8;
+
+typedef struct ProjectSpeedRet {
+  uint8 x, y;
+  uint8 xdiff, ydiff;
+} ProjectSpeedRet;
+
+typedef struct OamEnt {
+  uint8 x, y, charnum, flags;
+} OamEnt;
+
+typedef struct MemBlk {
+  const uint8 *ptr;
+  size_t size;
+} MemBlk;
+MemBlk FindIndexInMemblk(MemBlk data, size_t i);
+
+void NORETURN Die(const char *error);
+
+#endif  // ZELDA3_TYPES_H_
--- /dev/null
+++ b/src/util.c
@@ -1,0 +1,195 @@
+#include "util.h"
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+
+char *NextDelim(char **s, int sep) {
+  char *r = *s;
+  if (r) {
+    while (r[0] == ' ' || r[0] == '\t')
+      r++;
+    char *t = strchr(r, sep);
+    *s = t ? (*t++ = 0, t) : NULL;
+  }
+  return r;
+}
+
+static inline int ToLower(int a) {
+  return a + (a >= 'A' && a <= 'Z') * 32;
+}
+
+bool StringEqualsNoCase(const char *a, const char *b) {
+  for (;;) {
+    int aa = ToLower(*a++), bb = ToLower(*b++);
+    if (aa != bb)
+      return false;
+    if (aa == 0)
+      return true;
+  }
+}
+
+const char *StringStartsWithNoCase(const char *a, const char *b) {
+  for (;; a++, b++) {
+    int aa = ToLower(*a), bb = ToLower(*b);
+    if (bb == 0)
+      return a;
+    if (aa != bb)
+      return NULL;
+  }
+}
+
+uint8 *ReadWholeFile(const char *name, size_t *length) {
+  FILE *f = fopen(name, "rb");
+  if (f == NULL)
+    return NULL;
+  fseek(f, 0, SEEK_END);
+  size_t size = ftell(f);
+  rewind(f);
+  uint8 *buffer = (uint8 *)malloc(size + 1);
+  if (!buffer) Die("malloc failed");
+  // Always zero terminate so this function can be used also for strings.
+  buffer[size] = 0;
+  if (fread(buffer, 1, size, f) != size)
+    Die("fread failed");
+  fclose(f);
+  if (length) *length = size;
+  return buffer;
+}
+
+char *NextLineStripComments(char **s) {
+  char *p = *s;
+  if (p == NULL)
+    return NULL;
+  // find end of line
+  char *eol = strchr(p, '\n');
+  *s = eol ? eol + 1 : NULL;
+  eol = eol ? eol : p + strlen(p);
+  // strip comments
+  char *comment = memchr(p, '#', eol - p);
+  eol = comment ? comment : eol;
+  // strip trailing whitespace
+  while (eol > p && (eol[-1] == '\r' || eol[-1] == ' ' || eol[-1] == '\t'))
+    eol--;
+  *eol = 0;
+  // strip leading whitespace
+  while (p[0] == ' ' || p[0] == '\t')
+    p++;
+  return p;
+}
+
+// Return the next possibly quoted string, space separated, or the empty string
+char *NextPossiblyQuotedString(char **s) {
+  char *r = *s, *t;
+  while (*r == ' ' || *r == '\t')
+    r++;
+  if (*r == '"') {
+    for (t = ++r; *t && *t != '"'; t++);
+  } else {
+    for (t = r; *t && *t != ' ' && *t != '\t'; t++);
+  }
+  if (*t) *t++ = 0;
+  while (*t == ' ' || *t == '\t')
+    t++;
+  *s = t;
+  return r;
+}
+
+char *ReplaceFilenameWithNewPath(const char *old_path, const char *new_path) {
+  size_t olen = strlen(old_path);
+  size_t nlen = strlen(new_path) + 1;
+  while (olen && old_path[olen - 1] != '/' && old_path[olen - 1] != '\\')
+    olen--;
+  char *result = malloc(olen + nlen);
+  memcpy(result, old_path, olen);
+  memcpy(result + olen, new_path, nlen);
+  return result;
+}
+
+char *SplitKeyValue(char *p) {
+  char *equals = strchr(p, '=');
+  if (equals == NULL)
+    return NULL;
+  char *kr = equals;
+  while (kr > p && (kr[-1] == ' ' || kr[-1] == '\t'))
+    kr--;
+  *kr = 0;
+  char *v = equals + 1;
+  while (v[0] == ' ' || v[0] == '\t')
+    v++;
+  return v;
+}
+
+const char *SkipPrefix(const char *big, const char *little) {
+  for (; *little; big++, little++) {
+    if (*little != *big)
+      return NULL;
+  }
+  return big;
+}
+
+void StrSet(char **rv, const char *s) {
+  char *news = strdup(s);
+  char *old = *rv;
+  *rv = news;
+  free(old);
+}
+
+char *StrFmt(const char *fmt, ...) {
+  char buf[4096];
+  va_list va;
+  va_start(va, fmt);
+  int n = vsnprintf(buf, sizeof(buf), fmt, va);
+  if (n < 0 || n >= sizeof(buf)) Die("vsnprintf failed");
+  va_end(va);
+  return strdup(buf);
+}
+
+void ByteArray_Resize(ByteArray *arr, size_t new_size) {
+  arr->size = new_size;
+  if (new_size > arr->capacity) {
+    size_t minsize = arr->capacity + (arr->capacity >> 1) + 8;
+    arr->capacity = new_size < minsize ? minsize : new_size;
+    void *data = realloc(arr->data, arr->capacity);
+    if (!data) Die("memory allocation failed");
+    arr->data = data;
+  }
+}
+
+void ByteArray_Destroy(ByteArray *arr) {
+  void *data = arr->data;
+  arr->data = NULL;
+  free(data);
+}
+
+void ByteArray_AppendData(ByteArray *arr, const uint8 *data, size_t data_size) {
+  ByteArray_Resize(arr, arr->size + data_size);
+  memcpy(arr->data + arr->size - data_size, data, data_size);
+}
+
+void ByteArray_AppendByte(ByteArray *arr, uint8 v) {
+  ByteArray_Resize(arr, arr->size + 1);
+  arr->data[arr->size - 1] = v;
+}
+
+// Automatically selects between 16 or 32 bit indexes. Can hold up to 8192 elements in 16-bit mode.
+MemBlk FindIndexInMemblk(MemBlk data, size_t i) {
+  if (data.size < 2)
+    return (MemBlk) { 0, 0 };
+  size_t end = data.size - 2, left_off, right_off;
+  size_t mx = *(uint16 *)(data.ptr + end);
+  if (mx < 8192) {
+    if (i > mx || mx * 2 > end)
+      return (MemBlk) { 0, 0 };
+    left_off = ((i == 0) ? mx * 2 : mx * 2 + *(uint16 *)(data.ptr + i * 2 - 2));
+    right_off = (i == mx) ? end : mx * 2 + *(uint16 *)(data.ptr + i * 2);
+  } else {
+    mx -= 8192;
+    if (i > mx || mx * 4 > end)
+      return (MemBlk) { 0, 0 };
+    left_off = ((i == 0) ? mx * 4 : mx * 4 + *(uint32 *)(data.ptr + i * 4 - 4));
+    right_off = (i == mx) ? end : mx * 4 + *(uint32 *)(data.ptr + i * 4);
+  }
+  if (left_off > right_off || right_off > end)
+    return (MemBlk) { 0, 0 };
+  return (MemBlk) { data.ptr + left_off, right_off - left_off };
+}
--- /dev/null
+++ b/src/util.h
@@ -1,0 +1,39 @@
+#ifndef ZELDA3_UTIL_H_
+#define ZELDA3_UTIL_H_
+
+#include "types.h"
+
+typedef struct SDL_Window SDL_Window;
+
+struct RendererFuncs {
+  bool (*Initialize)(SDL_Window *window);
+  void (*Destroy)();
+  void (*BeginDraw)(int width, int height, uint8 **pixels, int *pitch);
+  void (*EndDraw)();
+};
+
+
+typedef struct ByteArray {
+  uint8 *data;
+  size_t size, capacity;
+} ByteArray;
+
+void ByteArray_Resize(ByteArray *arr, size_t new_size);
+void ByteArray_Destroy(ByteArray *arr);
+void ByteArray_AppendData(ByteArray *arr, const uint8 *data, size_t data_size);
+void ByteArray_AppendByte(ByteArray *arr, uint8 v);
+
+uint8 *ReadWholeFile(const char *name, size_t *length);
+char *NextDelim(char **s, int sep);
+char *NextLineStripComments(char **s);
+char *NextPossiblyQuotedString(char **s);
+char *SplitKeyValue(char *p);
+bool StringEqualsNoCase(const char *a, const char *b);
+const char *StringStartsWithNoCase(const char *a, const char *b);
+bool ParseBool(const char *value, bool *result);
+const char *SkipPrefix(const char *big, const char *little);
+void StrSet(char **rv, const char *s);
+char *StrFmt(const char *fmt, ...);
+char *ReplaceFilenameWithNewPath(const char *old_path, const char *new_path);
+
+#endif  // ZELDA3_UTIL_H_
\ No newline at end of file
--- /dev/null
+++ b/src/variables.h
@@ -1,0 +1,1530 @@
+#ifndef ZELDA3_VARIABLES_H_
+#define ZELDA3_VARIABLES_H_
+#define main_module_index (*(uint8*)(g_ram+0x10))
+#define submodule_index (*(uint8*)(g_ram+0x11))
+#define nmi_boolean (*(uint8*)(g_ram+0x12))
+#define INIDISP_copy (*(uint8*)(g_ram+0x13))
+#define nmi_load_bg_from_vram (*(uint8*)(g_ram+0x14))
+#define flag_update_cgram_in_nmi (*(uint8*)(g_ram+0x15))
+#define flag_update_hud_in_nmi (*(uint8*)(g_ram+0x16))
+#define nmi_subroutine_index (*(uint8*)(g_ram+0x17))
+#define nmi_copy_packets_flag (*(uint8*)(g_ram+0x18))
+#define nmi_update_tilemap_dst (*(uint8*)(g_ram+0x19))
+#define frame_counter (*(uint8*)(g_ram+0x1A))
+#define player_is_indoors (*(uint8*)(g_ram+0x1B))
+#define TM_copy (*(uint8*)(g_ram+0x1C))
+#define TS_copy (*(uint8*)(g_ram+0x1D))
+#define TMW_copy (*(uint8*)(g_ram+0x1E))
+#define TSW_copy (*(uint8*)(g_ram+0x1F))
+#define link_y_coord (*(uint16*)(g_ram+0x20))
+#define link_x_coord (*(uint16*)(g_ram+0x22))
+#define link_z_coord (*(uint16*)(g_ram+0x24))
+#define link_direction_last (*(uint8*)(g_ram+0x26))
+#define link_actual_vel_y (*(uint8*)(g_ram+0x27))
+#define link_actual_vel_x (*(uint8*)(g_ram+0x28))
+#define link_actual_vel_z (*(uint8*)(g_ram+0x29))
+#define link_subpixel_y (*(uint8*)(g_ram+0x2A))
+#define link_subpixel_x (*(uint8*)(g_ram+0x2B))
+#define link_subpixel_z (*(uint8*)(g_ram+0x2C))
+#define link_counter_var1 (*(uint8*)(g_ram+0x2D))
+#define link_animation_steps (*(uint8*)(g_ram+0x2E))
+#define link_direction_facing (*(uint8*)(g_ram+0x2F))
+#define link_y_vel (*(uint8*)(g_ram+0x30))
+#define link_x_vel (*(uint8*)(g_ram+0x31))
+#define link_y_coord_original (*(uint16*)(g_ram+0x32))
+#define byte_7E0034 (*(uint8*)(g_ram+0x34))
+#define byte_7E0035 (*(uint8*)(g_ram+0x35))
+#define tiledetect_diagonal_tile (*(uint16*)(g_ram+0x38))
+#define button_mask_b_y (*(uint8*)(g_ram+0x3A))
+#define bitfield_for_a_button (*(uint8*)(g_ram+0x3B))
+#define button_b_frames (*(uint8*)(g_ram+0x3C))
+#define link_delay_timer_spin_attack (*(uint8*)(g_ram+0x3D))
+#define link_y_coord_safe_return_lo (*(uint8*)(g_ram+0x3E))
+#define link_x_coord_safe_return_lo (*(uint8*)(g_ram+0x3F))
+#define link_y_coord_safe_return_hi (*(uint8*)(g_ram+0x40))
+#define link_x_coord_safe_return_hi (*(uint8*)(g_ram+0x41))
+#define link_direction_mask_a (*(uint8*)(g_ram+0x42))
+#define link_direction_mask_b (*(uint8*)(g_ram+0x43))
+#define player_oam_y_offset (*(uint8*)(g_ram+0x44))
+#define player_oam_x_offset (*(uint8*)(g_ram+0x45))
+#define link_incapacitated_timer (*(uint8*)(g_ram+0x46))
+#define set_when_damaging_enemies (*(uint8*)(g_ram+0x47))
+#define bitmask_of_dragstate (*(uint8*)(g_ram+0x48))
+#define force_move_any_direction (*(uint16*)(g_ram+0x49))
+#define link_visibility_status (*(uint8*)(g_ram+0x4B))
+#define cape_decrement_counter (*(uint8*)(g_ram+0x4C))
+#define link_auxiliary_state (*(uint8*)(g_ram+0x4D))
+#define byte_7E004E (*(uint8*)(g_ram+0x4E))
+#define index_of_dashing_sfx (*(uint8*)(g_ram+0x4F))
+#define link_cant_change_direction (*(uint8*)(g_ram+0x50))
+#define tiledetect_which_y_pos ((uint16*)(g_ram+0x51))
+#define link_cape_mode (*(uint8*)(g_ram+0x55))
+#define link_is_bunny (*(uint8*)(g_ram+0x56))
+#define link_speed_modifier (*(uint8*)(g_ram+0x57))
+#define tiledetect_stair_tile (*(uint8*)(g_ram+0x58))
+#define tiledetect_pit_tile (*(uint8*)(g_ram+0x59))
+#define link_this_controls_sprite_oam (*(uint8*)(g_ram+0x5A))
+#define player_near_pit_state (*(uint8*)(g_ram+0x5B))
+#define byte_7E005C (*(uint8*)(g_ram+0x5C))
+#define link_player_handler_state (*(uint8*)(g_ram+0x5D))
+#define link_speed_setting (*(uint8*)(g_ram+0x5E))
+#define tiledetect_var2 (*(uint16*)(g_ram+0x5F))
+#define gravestone_push_timeout (*(uint8*)(g_ram+0x61))
+#define tiledetect_var1 (*(uint16*)(g_ram+0x62))
+#define oam_priority_value (*(uint16*)(g_ram+0x64))
+#define link_last_direction_moved_towards (*(uint8*)(g_ram+0x66))
+#define link_direction (*(uint8*)(g_ram+0x67))
+#define link_y_page_movement_delta (*(uint8*)(g_ram+0x68))
+#define link_x_page_movement_delta (*(uint8*)(g_ram+0x69))
+#define link_num_orthogonal_directions (*(uint8*)(g_ram+0x6A))
+#define link_moving_against_diag_tile (*(uint8*)(g_ram+0x6B))
+#define is_standing_in_doorway (*(uint8*)(g_ram+0x6C))
+#define moving_against_diag_deadlocked (*(uint8*)(g_ram+0x6D))
+#define tiledetect_diag_state (*(uint16*)(g_ram+0x6E))
+#define byte_7E0071 (*(uint8*)(g_ram+0x71))
+#define scratch_b (*(uint8*)(g_ram+0x72))
+#define scratch_a (*(uint8*)(g_ram+0x73))
+#define scratch_c (*(uint8*)(g_ram+0x74))
+#define scratch_d (*(uint8*)(g_ram+0x75))
+#define index_of_interacting_tile (*(uint16*)(g_ram+0x76))
+#define allow_scroll_z (*(uint8*)(g_ram+0x78))
+#define link_spin_attack_step_counter (*(uint8*)(g_ram+0x79))
+#define last_light_vs_dark_world (*(uint8*)(g_ram+0x7B))
+#define word_7E007E (*(uint16*)(g_ram+0x7E))
+#define map16_load_src_off (*(uint16*)(g_ram+0x84))
+#define map16_load_dst_off (*(uint16*)(g_ram+0x86))
+#define map16_load_var2 (*(uint16*)(g_ram+0x88))
+#define overworld_screen_index (*(uint16*)(g_ram+0x8A))
+#define overlay_index (*(uint16*)(g_ram+0x8C))
+#define oam_cur_ptr (*(uint16*)(g_ram+0x90))
+#define oam_ext_cur_ptr (*(uint16*)(g_ram+0x92))
+#define BGMODE_copy (*(uint8*)(g_ram+0x94))
+#define MOSAIC_copy (*(uint8*)(g_ram+0x95))
+#define W12SEL_copy (*(uint8*)(g_ram+0x96))
+#define W34SEL_copy (*(uint8*)(g_ram+0x97))
+#define WOBJSEL_copy (*(uint8*)(g_ram+0x98))
+#define CGWSEL_copy (*(uint8*)(g_ram+0x99))
+#define CGADSUB_copy (*(uint8*)(g_ram+0x9A))
+#define HDMAEN_copy (*(uint8*)(g_ram+0x9B))
+#define COLDATA_copy0 (*(uint8*)(g_ram+0x9C))
+#define COLDATA_copy1 (*(uint8*)(g_ram+0x9D))
+#define COLDATA_copy2 (*(uint8*)(g_ram+0x9E))
+#define dungeon_room_index (*(uint16*)(g_ram+0xA0))
+#define dungeon_room_index_prev (*(uint16*)(g_ram+0xA2))
+#define dung_cur_floor (*(uint8*)(g_ram+0xA4))
+#define quadrant_fullsize_x (*(uint8*)(g_ram+0xA6))
+#define quadrant_fullsize_y (*(uint8*)(g_ram+0xA7))
+#define composite_of_layout_and_quadrant (*(uint8*)(g_ram+0xA8))
+#define link_quadrant_x (*(uint8*)(g_ram+0xA9))
+#define link_quadrant_y (*(uint8*)(g_ram+0xAA))
+#define dung_hdr_collision_2 (*(uint8*)(g_ram+0xAD))
+#define dung_hdr_tag ((uint8*)(g_ram+0xAE))
+#define subsubmodule_index (*(uint8*)(g_ram+0xB0))
+#define subsubmodule_index_PADDING (*(uint8*)(g_ram+0xB1))
+#define dung_draw_width_indicator (*(uint16*)(g_ram+0xB2))
+#define dung_draw_height_indicator (*(uint16*)(g_ram+0xB4))
+#define dung_load_ptr (*(uint16*)(g_ram+0xB7))
+#define dung_load_ptr_bank (*(uint8*)(g_ram+0xB9))
+#define dung_load_ptr_offs (*(uint16*)(g_ram+0xBA))
+#define hud_tmp1 (*(uint16*)(g_ram+0xBD))
+
+#define some_menu_ctr (*(uint8*)(g_ram+0xc8))
+#define dung_line_ptrs_row3 (*(uint16*)(g_ram+0xDA))
+#define dung_line_ptrs_row4 (*(uint16*)(g_ram+0xDD))
+#define BG1HOFS_copy2 (*(uint16*)(g_ram+0xE0))
+#define BG2HOFS_copy2 (*(uint16*)(g_ram+0xE2))
+#define BG3HOFS_copy2 (*(uint16*)(g_ram+0xE4))
+#define BG1VOFS_copy2 (*(uint16*)(g_ram+0xE6))
+#define BG2VOFS_copy2 (*(uint16*)(g_ram+0xE8))
+#define BG3VOFS_copy2 (*(uint16*)(g_ram+0xEA))
+#define tilemap_location_calc_mask (*(uint16*)(g_ram+0xEC))
+#define link_is_on_lower_level (*(uint8*)(g_ram+0xEE))
+#define room_transitioning_flags (*(uint8*)(g_ram+0xEF))
+#define joypad1H_last (*(uint8*)(g_ram+0xF0))
+#define joypad1L_last (*(uint8*)(g_ram+0xF2))
+#define filtered_joypad_H (*(uint8*)(g_ram+0xF4))
+#define filtered_joypad_L (*(uint8*)(g_ram+0xF6))
+#define joypad1H_last2 (*(uint8*)(g_ram+0xF8))
+#define byte_7E00F9 (*(uint8*)(g_ram+0xF9))
+#define joypad1L_last2 (*(uint8*)(g_ram+0xFA))
+#define dung_unk2 (*(uint16*)(g_ram+0xFC))
+#define virq_trigger (*(uint8*)(g_ram+0xFF))
+#define link_dma_graphics_index (*(uint16*)(g_ram+0x100))
+#define link_dma_var1 (*(uint16*)(g_ram+0x102))
+#define link_dma_var2 (*(uint16*)(g_ram+0x104))
+#define link_dma_var3 (*(uint8*)(g_ram+0x107))
+#define link_dma_var4 (*(uint8*)(g_ram+0x108))
+#define link_dma_var5 (*(uint8*)(g_ram+0x109))
+#define death_var5 (*(uint8*)(g_ram+0x10A))
+#define saved_module_for_menu (*(uint8*)(g_ram+0x10C))
+#define which_entrance (*(uint8*)(g_ram+0x10E))
+#define byte_7E010F (*(uint8*)(g_ram+0x10F))
+#define dung_index_x3 (*(uint16*)(g_ram+0x110))
+#define flag_custom_spell_anim_active (*(uint8*)(g_ram+0x112))
+#define link_tile_below (*(uint8*)(g_ram+0x114))
+#define link_tile_below_PADDING (*(uint8*)(g_ram+0x115))
+#define nmi_load_target_addr (*(uint16*)(g_ram+0x116))
+#define nmi_update_tilemap_src (*(uint16*)(g_ram+0x118))
+#define bg1_x_offset (*(uint16*)(g_ram+0x11A))
+#define bg1_y_offset (*(uint16*)(g_ram+0x11C))
+#define BG2HOFS_copy (*(uint16*)(g_ram+0x11E))
+#define BG1HOFS_copy (*(uint16*)(g_ram+0x120))
+#define BG2VOFS_copy (*(uint16*)(g_ram+0x122))
+#define BG1VOFS_copy (*(uint16*)(g_ram+0x124))
+#define transition_counter (*(uint8*)(g_ram+0x126))
+#define irq_flag (*(uint8*)(g_ram+0x128))
+#define is_nmi_thread_active (*(uint8*)(g_ram+0x12A))
+#define music_control (*(uint8*)(g_ram+0x12C))
+#define sound_effect_ambient (*(uint8*)(g_ram+0x12D))
+#define sound_effect_1 (*(uint8*)(g_ram+0x12E))
+#define sound_effect_2 (*(uint8*)(g_ram+0x12F))
+#define music_unk1 (*(uint8*)(g_ram+0x130))
+#define sound_effect_ambient_last (*(uint8*)(g_ram+0x131))
+#define queued_music_control (*(uint8*)(g_ram+0x132))
+#define last_music_control (*(uint8*)(g_ram+0x133))
+#define animated_tile_vram_addr (*(uint16*)(g_ram+0x134))
+#define flag_which_music_type (*(uint8*)(g_ram+0x136))
+#define stk_return_addr (*(uint16*)(g_ram+0x1FE))
+#define overworld_map_state (*(uint8*)(g_ram+0x200))
+#define hud_cur_item (*(uint8*)(g_ram+0x202))
+
+#define hud_var1 (*(uint8*)(g_ram+0x204))
+#define bottle_menu_expand_row (*(uint8*)(g_ram+0x205))
+#define byte_7E0206 (*(uint8*)(g_ram+0x206))
+#define timer_for_flashing_circle (*(uint8*)(g_ram+0x207))
+#define animate_heart_refill_countdown (*(uint8*)(g_ram+0x208))
+#define animate_heart_refill_countdown_subpos (*(uint8*)(g_ram+0x209))
+#define is_doing_heart_animation (*(uint8*)(g_ram+0x20A))
+#define link_debug_value_1 (*(uint8*)(g_ram+0x20B))
+#define dungmap_init_state (*(uint8*)(g_ram+0x20D))
+#define dungmap_cur_floor (*(uint16*)(g_ram+0x20E))
+#define dungmap_var2 (*(uint8*)(g_ram+0x210))
+#define dungmap_idx (*(uint16*)(g_ram+0x211))
+#define dungmap_var4 (*(uint16*)(g_ram+0x213))
+#define dungmap_var3 (*(uint16*)(g_ram+0x215))
+#define dungmap_var5 (*(uint16*)(g_ram+0x217))
+#define word_7E0219 (*(uint16*)(g_ram+0x219))
+#define word_7E021D (*(uint16*)(g_ram+0x21D))
+#define word_7E021F (*(uint16*)(g_ram+0x21F))
+#define word_7E0221 (*(uint16*)(g_ram+0x221))
+#define byte_7E0223 (*(uint8*)(g_ram+0x223))
+#define ancilla_objprio ((uint8*)(g_ram+0x280))
+#define ancilla_U ((uint8*)(g_ram+0x28A))
+#define ancilla_z_vel ((uint8*)(g_ram+0x294))
+#define ancilla_z ((uint8*)(g_ram+0x29E))
+#define ancilla_z_subpixel ((uint8*)(g_ram+0x2A8))
+#define tiledetect_inroom_staircase (*(uint16*)(g_ram+0x2C0))
+#define byte_7E02C2 (*(uint8*)(g_ram+0x2C2))
+#define pushedblocks_some_index (*(uint8*)(g_ram+0x2C3))
+#define pushedblocks_maybe_timeout (*(uint8*)(g_ram+0x2C4))
+#define byte_7E02C5 (*(uint8*)(g_ram+0x2C5))
+#define link_recoilmode_timer (*(uint8*)(g_ram+0x2C6))
+#define link_actual_vel_z_copy (*(uint8*)(g_ram+0x2C7))
+#define byte_7E02C9 (*(uint8*)(g_ram+0x2C9))
+#define fallhole_var2 (*(uint8*)(g_ram+0x2CA))
+#define swimming_countdown (*(uint8*)(g_ram+0x2CB))
+#define byte_7E02CC (*(uint8*)(g_ram+0x2CC))
+#define word_7E02CD (*(uint16*)(g_ram+0x2CD))
+#define tagalong_var2 (*(uint8*)(g_ram+0x2CF))
+#define tagalong_var3 (*(uint8*)(g_ram+0x2D0))
+#define tagalong_var7 (*(uint8*)(g_ram+0x2D1))
+#define timer_tagalong_reacquire (*(uint8*)(g_ram+0x2D2))
+#define tagalong_var1 (*(uint8*)(g_ram+0x2D3))
+#define byte_7E02D4 (*(uint8*)(g_ram+0x2D4))
+#define tagalong_var4 (*(uint8*)(g_ram+0x2D6))
+#define byte_7E02D7 (*(uint8*)(g_ram+0x2D7))
+#define link_receiveitem_index (*(uint8*)(g_ram+0x2D8))
+#define link_receiveitem_var1 (*(uint8*)(g_ram+0x2D9))
+#define link_pose_for_item (*(uint8*)(g_ram+0x2DA))
+#define link_triggered_by_whirlpool_sprite (*(uint8*)(g_ram+0x2DB))
+#define link_x_coord_copy (*(uint16*)(g_ram+0x2DC))
+#define link_y_coord_copy (*(uint16*)(g_ram+0x2DE))
+#define link_is_bunny_mirror (*(uint8*)(g_ram+0x2E0))
+#define link_is_transforming (*(uint8*)(g_ram+0x2E1))
+#define link_bunny_transform_timer (*(uint8*)(g_ram+0x2E2))
+#define link_sword_delay_timer (*(uint8*)(g_ram+0x2E3))
+#define flag_is_link_immobilized (*(uint8*)(g_ram+0x2E4))
+#define tiledetect_chest (*(uint16*)(g_ram+0x2E5))
+#define tiledetect_key_lock_gravestones (*(uint8*)(g_ram+0x2E7))
+#define bitfield_spike_cactus_tiles (*(uint8*)(g_ram+0x2E8))
+#define item_receipt_method (*(uint8*)(g_ram+0x2E9))
+#define tiledetect_tile_type (*(uint16*)(g_ram+0x2EA))
+#define flag_is_ancilla_to_pick_up (*(uint8*)(g_ram+0x2EC))
+#define byte_7E02ED (*(uint8*)(g_ram+0x2ED))
+#define tiledetect_spike_floor_and_tile_triggers (*(uint8*)(g_ram+0x2EE))
+#define bitmask_for_dashable_tiles (*(uint8*)(g_ram+0x2EF))
+#define byte_7E02F0 (*(uint8*)(g_ram+0x2F0))
+#define link_dash_ctr (*(uint8*)(g_ram+0x2F1))
+#define tagalong_event_flags (*(uint8*)(g_ram+0x2F2))
+#define byte_7E02F3 (*(uint8*)(g_ram+0x2F3))
+#define flag_is_sprite_to_pick_up_cached (*(uint8*)(g_ram+0x2F4))
+#define player_on_somaria_platform (*(uint8*)(g_ram+0x2F5))
+#define tiledetect_misc_tiles (*(uint16*)(g_ram+0x2F6))
+#define link_want_make_noise_when_dashed (*(uint8*)(g_ram+0x2F8))
+#define tagalong_var5 (*(uint8*)(g_ram+0x2F9))
+#define link_is_near_moveable_statue (*(uint8*)(g_ram+0x2FA))
+#define player_handler_timer (*(uint8*)(g_ram+0x300))
+#define link_item_in_hand (*(uint8*)(g_ram+0x301))
+#define fallhole_var1 (*(uint8*)(g_ram+0x302))
+#define current_item_y (*(uint8*)(g_ram+0x303))
+#define current_item_active (*(uint8*)(g_ram+0x304))
+#define debug_var2 (*(uint8*)(g_ram+0x305))
+#define unused_2 (*(uint8*)(g_ram+0x306))
+#define eq_selected_rod (*(uint8*)(g_ram+0x307))
+#define link_state_bits (*(uint8*)(g_ram+0x308))
+#define link_picking_throw_state (*(uint8*)(g_ram+0x309))
+#define some_animation_timer_steps (*(uint8*)(g_ram+0x30A))
+#define some_animation_timer (*(uint8*)(g_ram+0x30B))
+#define link_var30d (*(uint8*)(g_ram+0x30D))
+#define link_var30e (*(uint8*)(g_ram+0x30E))
+#define dung_floor_y_vel (*(uint16*)(g_ram+0x310))
+#define dung_floor_x_vel (*(uint16*)(g_ram+0x312))
+#define flag_is_sprite_to_pick_up (*(uint8*)(g_ram+0x314))
+#define tile_coll_flag (*(uint8*)(g_ram+0x315))
+#define byte_7E0316 (*(uint8*)(g_ram+0x316))
+#define byte_7E0317 (*(uint8*)(g_ram+0x317))
+#define related_to_moving_floor_y (*(uint16*)(g_ram+0x318))
+#define related_to_moving_floor_x (*(uint16*)(g_ram+0x31A))
+#define state_for_spin_attack (*(uint8*)(g_ram+0x31C))
+#define step_counter_for_spin_attack (*(uint8*)(g_ram+0x31D))
+#define link_spin_offsets (*(uint8*)(g_ram+0x31E))
+#define countdown_for_blink (*(uint8*)(g_ram+0x31F))
+#define tiledetect_moving_floor_tiles (*(uint16*)(g_ram+0x320))
+#define byte_7E0322 (*(uint8*)(g_ram+0x322))
+#define link_direction_facing_mirror (*(uint8*)(g_ram+0x323))
+#define byte_7E0324 (*(uint8*)(g_ram+0x324))
+#define byte_7E0325 (*(uint8*)(g_ram+0x325))
+#define swimcoll_var3 ((uint16*)(g_ram+0x326))
+#define link_maybe_swim_faster (*(uint8*)(g_ram+0x32A))
+#define swimcoll_var5 ((uint16*)(g_ram+0x32B))
+#define swimcoll_var1 ((uint16*)(g_ram+0x32F))
+#define byte_7E0333 (*(uint8*)(g_ram+0x333))
+#define swimcoll_var9 ((uint16*)(g_ram+0x334))
+#define swimcoll_var11 ((uint16*)(g_ram+0x338))
+#define swimcoll_var7 ((uint16*)(g_ram+0x33C))
+#define link_some_direction_bits (*(uint8*)(g_ram+0x340))
+#define tiledetect_deepwater (*(uint16*)(g_ram+0x341))
+#define tiledetect_normal_tiles (*(uint16*)(g_ram+0x343))
+#define link_is_in_deep_water (*(uint8*)(g_ram+0x345))
+#define link_palette_bits_of_oam (*(uint16*)(g_ram+0x346))
+#define tiledetect_icy_floor (*(uint16*)(g_ram+0x348))
+#define link_flag_moving (*(uint8*)(g_ram+0x34A))
+#define eq_debug_variable (*(uint8*)(g_ram+0x34B))
+#define tiledetect_water_staircase (*(uint16*)(g_ram+0x34C))
+#define byte_7E034E (*(uint8*)(g_ram+0x34E))
+#define link_swim_hard_stroke (*(uint8*)(g_ram+0x34F))
+#define link_debug_value_2 (*(uint8*)(g_ram+0x350))
+#define draw_water_ripples_or_grass (*(uint8*)(g_ram+0x351))
+#define sort_sprites_offset_into_oam_buffer (*(uint16*)(g_ram+0x352))
+#define value_computed_for_player_oam (*(uint8*)(g_ram+0x354))
+#define secondary_water_grass_timer (*(uint8*)(g_ram+0x355))
+#define primary_water_grass_timer (*(uint8*)(g_ram+0x356))
+#define tiledetect_thick_grass (*(uint16*)(g_ram+0x357))
+#define tiledetect_shallow_water (*(uint16*)(g_ram+0x359))
+#define tiledetect_destruction_aftermath (*(uint16*)(g_ram+0x35B))
+#define oam_priority_value_2 (*(uint16*)(g_ram+0x35D))
+#define flag_for_boomerang_in_place (*(uint8*)(g_ram+0x35F))
+#define link_electrocute_on_touch (*(uint8*)(g_ram+0x360))
+#define link_actual_vel_z_mirror (*(uint8*)(g_ram+0x362))
+#define link_actual_vel_z_copy_mirror (*(uint8*)(g_ram+0x363))
+#define link_z_coord_mirror (*(uint16*)(g_ram+0x364))
+#define tiledetect_read_something (*(uint16*)(g_ram+0x366))
+#define interacting_with_liftable_tile_x1 (*(uint8*)(g_ram+0x368))
+#define interacting_with_liftable_tile_x1b (*(uint8*)(g_ram+0x369))
+#define interacting_with_liftable_tile_x2 (*(uint8*)(g_ram+0x36A))
+#define player_unk1 (*(uint8*)(g_ram+0x36B))
+#define tile_action_index (*(uint8*)(g_ram+0x36C))
+#define tiledetect_vertical_ledge (*(uint8*)(g_ram+0x36D))
+#define detection_of_ledge_tiles_horiz_uphoriz (*(uint8*)(g_ram+0x36E))
+#define tiledetect_ledges_down_leftright (*(uint8*)(g_ram+0x36F))
+#define detection_of_unknown_tile_types (*(uint8*)(g_ram+0x370))
+#define link_timer_push_get_tired (*(uint8*)(g_ram+0x371))
+#define link_is_running (*(uint8*)(g_ram+0x372))
+#define link_give_damage (*(uint8*)(g_ram+0x373))
+#define link_countdown_for_dash (*(uint8*)(g_ram+0x374))
+#define link_timer_jump_ledge (*(uint8*)(g_ram+0x375))
+#define link_grabbing_wall (*(uint8*)(g_ram+0x376))
+#define link_unk_master_sword (*(uint8*)(g_ram+0x377))
+#define countdown_timer_for_staircases (*(uint8*)(g_ram+0x378))
+#define byte_7E0379 (*(uint8*)(g_ram+0x379))
+#define link_position_mode (*(uint8*)(g_ram+0x37A))
+#define link_disable_sprite_damage (*(uint8*)(g_ram+0x37B))
+#define player_sleep_in_bed_state (*(uint8*)(g_ram+0x37C))
+#define link_pose_during_opening (*(uint8*)(g_ram+0x37D))
+#define related_to_hookshot (*(uint8*)(g_ram+0x37E))
+#define cheatWalkThroughWalls (*(uint8*)(g_ram+0x37F))
+#define ancilla_K ((uint8*)(g_ram+0x380))
+#define ancilla_L ((uint8*)(g_ram+0x385))
+#define ancilla_A ((uint8*)(g_ram+0x38A))
+#define ancilla_B ((uint8*)(g_ram+0x38F))
+#define ancilla_G ((uint8*)(g_ram+0x394))
+#define boomerang_temp_y (*(uint16*)(g_ram+0x399))
+#define boomerang_temp_x (*(uint16*)(g_ram+0x39B))
+#define hookshot_effect_index (*(uint8*)(g_ram+0x39D))
+#define ancilla_arr3 ((uint8*)(g_ram+0x39F))
+#define ancilla_arr1 ((uint8*)(g_ram+0x3A4))
+#define ancilla_S ((uint8*)(g_ram+0x3A9))
+#define ancilla_aux_timer ((uint8*)(g_ram+0x3B1))
+
+// relocated those so they have 5 entries each
+#define door_debris_x ((uint16*)(g_ram+0x728))
+#define door_debris_y ((uint16*)(g_ram+0x732))
+#define door_debris_direction ((uint8*)(g_ram+0x73c))
+#define ancilla_arr26 ((uint8*)(g_ram+0x741))
+#define ancilla_arr25 ((uint8*)(g_ram+0x746))
+#define ancilla_arr22 ((uint8*)(g_ram+0x74b))
+
+#define ancilla_alloc_rotate (*(uint8*)(g_ram+0x3C4))
+#define ancilla_H ((uint8*)(g_ram+0x3C5))
+#define ancilla_floor2 ((uint8*)(g_ram+0x3CA))
+
+// extended the size of this array by merging it with the adjacent one
+#define ancilla_arr23 ((uint8*)(g_ram+0x3CF))
+#define ancilla_T ((uint8*)(g_ram+0x3D5))
+#define ancilla_arr24 ((uint8*)(g_ram+0x3DB))
+#define ancilla_tile_attr ((uint8*)(g_ram+0x3E4))
+#define link_something_with_hookshot (*(uint8*)(g_ram+0x3E9))
+#define ancilla_R ((uint8*)(g_ram+0x3EA))
+#define link_force_hold_sword_up (*(uint8*)(g_ram+0x3EF))
+#define flute_countdown (*(uint8*)(g_ram+0x3F0))
+#define tiledetect_var4 (*(uint16*)(g_ram+0x3F1))
+#define link_on_conveyor_belt (*(uint8*)(g_ram+0x3F3))
+#define dung_unk6 (*(uint8*)(g_ram+0x3F4))
+#define link_timer_tempbunny (*(uint16*)(g_ram+0x3F5))
+#define link_need_for_poof_for_transform (*(uint8*)(g_ram+0x3F7))
+#define link_need_for_pullforrupees_sprite (*(uint8*)(g_ram+0x3F8))
+#define hookshot_var1 (*(uint8*)(g_ram+0x3F9))
+#define bit9_of_xcoord (*(uint16*)(g_ram+0x3FA))
+#define is_archer_or_shovel_game (*(uint8*)(g_ram+0x3FC))
+#define byte_7E03FD (*(uint8*)(g_ram+0x3FD))
+#define dung_door_opened (*(uint16*)(g_ram+0x400))
+#define dung_savegame_state_bits (*(uint16*)(g_ram+0x402))
+#define word_7E0405 (*(uint16*)(g_ram+0x405))
+#define dung_quadrants_visited (*(uint16*)(g_ram+0x408))
+#define overworld_area_index (*(uint16*)(g_ram+0x40A))
+#define cur_palace_index_x2 (*(uint16*)(g_ram+0x40C))
+#define dung_layout_and_starting_quadrant (*(uint16*)(g_ram+0x40E))
+#define overworld_screen_trans_dir_bits (*(uint16*)(g_ram+0x410))
+#define incremental_counter_for_vram (*(uint8*)(g_ram+0x412))
+#define dung_hdr_bg2_properties (*(uint8*)(g_ram+0x414))
+#define dung_hdr_bg2_properties_PADDING (*(uint8*)(g_ram+0x415))
+#define overworld_screen_trans_dir_bits2 (*(uint16*)(g_ram+0x416))
+#define overworld_screen_transition (*(uint8*)(g_ram+0x418))
+#define overworld_screen_transition_ALWAYSZERO (*(uint8*)(g_ram+0x419))
+#define dung_floor_move_flags (*(uint16*)(g_ram+0x41A))
+#define dung_some_subpixel ((uint8*)(g_ram+0x41C))
+#define moving_wall_var2 (*(uint8*)(g_ram+0x41E))
+#define word_7E0420 (*(uint16*)(g_ram+0x420))
+#define dung_floor_x_offs (*(uint16*)(g_ram+0x422))
+#define dung_floor_y_offs (*(uint16*)(g_ram+0x424))
+#define dung_hdr_collision_2_mirror (*(uint8*)(g_ram+0x428))
+#define dung_hdr_collision_2_mirror_PADDING (*(uint8*)(g_ram+0x429))
+#define moving_wall_var1 (*(uint16*)(g_ram+0x42A))
+#define dung_misc_objs_index (*(uint16*)(g_ram+0x42C))
+#define dung_index_of_torches (*(uint16*)(g_ram+0x42E))
+#define dung_door_switch_triggered (*(uint8*)(g_ram+0x430))
+#define dung_num_star_shaped_switches (*(uint16*)(g_ram+0x432))
+#define invisible_door_dir_and_index_x2 (*(uint16*)(g_ram+0x436))
+#define dung_num_inter_room_upnorth_stairs (*(uint16*)(g_ram+0x438))
+#define dung_num_inter_room_southdown_stairs (*(uint16*)(g_ram+0x43A))
+#define dung_num_inroom_upnorth_stairs (*(uint16*)(g_ram+0x43C))
+#define dung_num_inroom_southdown_stairs (*(uint16*)(g_ram+0x43E))
+#define dung_num_interpseudo_upnorth_stairs (*(uint16*)(g_ram+0x440))
+#define dung_num_inroom_upnorth_stairs_water (*(uint16*)(g_ram+0x442))
+#define dung_num_activated_water_ladders (*(uint16*)(g_ram+0x444))
+#define dung_num_water_ladders (*(uint16*)(g_ram+0x446))
+#define dung_some_stairs_unk4 (*(uint16*)(g_ram+0x448))
+#define kind_of_in_room_staircase (*(uint16*)(g_ram+0x44A))
+#define dung_num_toggle_floor (*(uint16*)(g_ram+0x44E))
+#define dung_num_toggle_palace (*(uint16*)(g_ram+0x450))
+#define dung_blastwall_flag_x (*(uint8*)(g_ram+0x452))
+#define dung_blastwall_flag_y (*(uint8*)(g_ram+0x453))
+#define dung_unk_blast_walls_2 (*(uint16*)(g_ram+0x454))
+#define dung_unk_blast_walls_3 (*(uint16*)(g_ram+0x456))
+#define hdr_dungeon_dark_with_lantern (*(uint8*)(g_ram+0x458))
+#define hdr_dungeon_dark_with_lantern_PADDING (*(uint8*)(g_ram+0x459))
+#define dung_num_lit_torches (*(uint8*)(g_ram+0x45A))
+#define dung_num_lit_torches_PADDING (*(uint8*)(g_ram+0x45B))
+#define dung_cur_quadrant_upload (*(uint8*)(g_ram+0x45C))
+#define dung_cur_quadrant_upload_PADDING (*(uint8*)(g_ram+0x45D))
+#define word_7E045E (*(uint16*)(g_ram+0x45E))
+#define dung_cur_door_idx (*(uint16*)(g_ram+0x460))
+#define which_staircase_index (*(uint8*)(g_ram+0x462))
+#define which_staircase_index_PADDING (*(uint8*)(g_ram+0x463))
+#define staircase_var1 (*(uint8*)(g_ram+0x464))
+#define related_to_trapdoors_somehow (*(uint16*)(g_ram+0x466))
+#define dung_flag_trapdoors_down (*(uint16*)(g_ram+0x468))
+#define dung_floor_2_filler_tiles (*(uint16*)(g_ram+0x46A))
+#define dung_hdr_collision (*(uint8*)(g_ram+0x46C))
+#define watergate_var1 (*(uint8*)(g_ram+0x470))
+#define watergate_var1_PADDING (*(uint8*)(g_ram+0x471))
+#define watergate_pos (*(uint16*)(g_ram+0x472))
+#define push_block_direction (*(uint8*)(g_ram+0x474))
+#define link_is_on_lower_level_mirror (*(uint8*)(g_ram+0x476))
+#define dung_index_of_torches_start (*(uint16*)(g_ram+0x478))
+#define about_to_jump_off_ledge (*(uint8*)(g_ram+0x47A))
+#define word_7E047C (*(uint16*)(g_ram+0x47C))
+#define dung_num_wall_upnorth_spiral_stairs (*(uint16*)(g_ram+0x47E))
+#define dung_num_wall_downnorth_spiral_stairs (*(uint16*)(g_ram+0x480))
+#define dung_num_wall_upnorth_spiral_stairs_2 (*(uint16*)(g_ram+0x482))
+#define dung_num_wall_downnorth_spiral_stairs_2 (*(uint16*)(g_ram+0x484))
+#define word_7E0486 (*(uint16*)(g_ram+0x486))
+#define word_7E0488 (*(uint16*)(g_ram+0x488))
+#define cur_staircase_plane (*(uint8*)(g_ram+0x48A))
+#define word_7E048C (*(uint16*)(g_ram+0x48C))
+#define dungeon_room_index2 (*(uint16*)(g_ram+0x48E))
+#define dung_floor_1_filler_tiles (*(uint16*)(g_ram+0x490))
+#define byte_7E0492 (*(uint8*)(g_ram+0x492))
+#define move_overlay_ctr (*(uint8*)(g_ram+0x494))
+#define dung_num_chests_x2 (*(uint16*)(g_ram+0x496))
+#define dung_num_bigkey_locks_x2 (*(uint16*)(g_ram+0x498))
+#define dung_num_stairs_1 (*(uint16*)(g_ram+0x49A))
+#define dung_num_stairs_2 (*(uint16*)(g_ram+0x49C))
+#define dung_num_stairs_wet (*(uint16*)(g_ram+0x49E))
+#define hud_floor_changed_timer (*(uint8*)(g_ram+0x4A0))
+#define dung_num_inter_room_upnorth_straight_stairs (*(uint16*)(g_ram+0x4A2))
+#define dung_num_inter_room_upsouth_straight_stairs (*(uint16*)(g_ram+0x4A4))
+#define dung_num_inter_room_downnorth_straight_stairs (*(uint16*)(g_ram+0x4A6))
+#define dung_num_inter_room_downsouth_straight_stairs (*(uint16*)(g_ram+0x4A8))
+#define death_var4 (*(uint8*)(g_ram+0x4AA))
+#define num_memorized_tiles (*(uint16*)(g_ram+0x4AC))
+#define dung_num_inroom_upsouth_stairs_water (*(uint16*)(g_ram+0x4AE))
+#define dung_unk5 (*(uint16*)(g_ram+0x4B0))
+#define word_7E04B2 (*(uint16*)(g_ram+0x4B2))
+#define super_bomb_indicator_unk2 (*(uint8*)(g_ram+0x4B4))
+#define super_bomb_indicator_unk1 (*(uint8*)(g_ram+0x4B5))
+#define word_7E04B6 (*(uint16*)(g_ram+0x4B6))
+#define big_key_door_message_triggered (*(uint16*)(g_ram+0x4B8))
+#define dung_overlay_to_load (*(uint8*)(g_ram+0x4BA))
+#define byte_7E04BC (*(uint8*)(g_ram+0x4BC))
+#define byte_7E04BE (*(uint8*)(g_ram+0x4BE))
+#define byte_7E04BF (*(uint8*)(g_ram+0x4BF))
+#define byte_7E04C0 (*(uint8*)(g_ram+0x4C0))
+#define byte_7E04C1 (*(uint8*)(g_ram+0x4C1))
+#define byte_7E04C2 (*(uint8*)(g_ram+0x4C2))
+#define minigame_credits (*(uint8*)(g_ram+0x4C4))
+#define byte_7E04C5 (*(uint8*)(g_ram+0x4C5))
+#define trigger_special_entrance (*(uint8*)(g_ram+0x4C6))
+#define flag_skip_call_tag_routines (*(uint8*)(g_ram+0x4C7))
+#define word_7E04C8 (*(uint16*)(g_ram+0x4C8))
+#define link_lowlife_countdown_timer_beep (*(uint8*)(g_ram+0x4CA))
+#define dung_torch_timers ((uint8*)(g_ram+0x4F0))
+#define dung_replacement_tile_state ((uint16*)(g_ram+0x500))
+#define dung_object_pos_in_objdata ((uint16*)(g_ram+0x520))
+#define dung_object_tilemap_pos ((uint16*)(g_ram+0x540))
+#define replacement_tilemap_UL ((uint16*)(g_ram+0x560))
+#define replacement_tilemap_LL ((uint16*)(g_ram+0x580))
+#define replacement_tilemap_UR ((uint16*)(g_ram+0x5A0))
+#define replacement_tilemap_LR ((uint16*)(g_ram+0x5C0))
+#define pushedblocks_x_hi ((uint16*)(g_ram+0x5E0))
+#define pushedblocks_x_lo ((uint16*)(g_ram+0x5E4))
+#define pushedblocks_target ((uint16*)(g_ram+0x5E8))
+#define pushedblocks_y_hi ((uint16*)(g_ram+0x5EC))
+#define pushedblocks_y_lo ((uint16*)(g_ram+0x5F0))
+#define pushedblocks_subpixel ((uint16*)(g_ram+0x5F4))
+#define pushedblock_facing ((uint16*)(g_ram+0x5F8))
+#define index_of_changable_dungeon_objs ((uint8*)(g_ram+0x5FC))
+#define up_down_scroll_target (*(uint16*)(g_ram+0x610))
+#define up_down_scroll_target_end (*(uint16*)(g_ram+0x612))
+#define left_right_scroll_target (*(uint16*)(g_ram+0x614))
+#define left_right_scroll_target_end (*(uint16*)(g_ram+0x616))
+#define camera_y_coord_scroll_low (*(uint16*)(g_ram+0x618))
+#define camera_y_coord_scroll_hi (*(uint16*)(g_ram+0x61A))
+#define camera_x_coord_scroll_low (*(uint16*)(g_ram+0x61C))
+#define camera_x_coord_scroll_hi (*(uint16*)(g_ram+0x61E))
+#define BG1HOFS_subpixel (*(uint16*)(g_ram+0x620))
+#define BG1VOFS_subpixel (*(uint16*)(g_ram+0x622))
+#define overworld_unk1 (*(uint16*)(g_ram+0x624))
+#define overworld_unk1_neg (*(uint16*)(g_ram+0x626))
+#define overworld_unk3 (*(uint16*)(g_ram+0x628))
+#define overworld_unk3_neg (*(uint16*)(g_ram+0x62A))
+#define dung_loade_bgoffs_h_copy (*(uint16*)(g_ram+0x62C))
+#define dung_loade_bgoffs_v_copy (*(uint16*)(g_ram+0x62E))
+#define byte_7E0630 (*(uint8*)(g_ram+0x630))
+#define byte_7E0631 (*(uint8*)(g_ram+0x631))
+#define byte_7E0635 (*(uint8*)(g_ram+0x635))
+#define overworld_map_flags (*(uint8*)(g_ram+0x636))
+#define timer_for_mode7_zoom (*(uint8*)(g_ram+0x637))
+#define M7X_copy (*(uint16*)(g_ram+0x638))
+#define M7Y_copy (*(uint16*)(g_ram+0x63A))
+#define dung_hdr_hole_teleporter_plane (*(uint8*)(g_ram+0x63C))
+#define dung_hdr_staircase_plane ((uint8*)(g_ram+0x63D))
+#define dung_flag_movable_block_was_pushed (*(uint8*)(g_ram+0x641))
+#define dung_flag_statechange_waterpuzzle (*(uint8*)(g_ram+0x642))
+#define dung_flag_somaria_block_switch (*(uint8*)(g_ram+0x646))
+#define mosaic_inc_or_dec (*(uint8*)(g_ram+0x647))
+#define spotlight_var3 (*(uint16*)(g_ram+0x670))
+#define spotlight_y_lower (*(uint16*)(g_ram+0x674))
+#define spotlight_y_upper (*(uint16*)(g_ram+0x676))
+#define word_7E0678 (*(uint16*)(g_ram+0x678))
+#define spotlight_var4 (*(uint16*)(g_ram+0x67A))
+#define spotlight_var1 (*(uint16*)(g_ram+0x67C))
+#define spotlight_var2 (*(uint16*)(g_ram+0x67E))
+#define water_hdma_var0 (*(uint16*)(g_ram+0x680))
+#define water_hdma_var1 (*(uint16*)(g_ram+0x682))
+#define water_hdma_var2 (*(uint16*)(g_ram+0x684))
+#define water_hdma_var3 (*(uint16*)(g_ram+0x686))
+#define water_hdma_var4 (*(uint16*)(g_ram+0x688))
+#define water_hdma_var5 (*(uint16*)(g_ram+0x68A))
+#define dung_door_opened_incl_adjacent (*(uint16*)(g_ram+0x68C))
+#define dung_cur_door_pos (*(uint16*)(g_ram+0x68E))
+#define door_animation_step_indicator (*(uint16*)(g_ram+0x690))
+#define door_open_closed_counter (*(uint16*)(g_ram+0x692))
+#define dung_which_key_x2 (*(uint16*)(g_ram+0x694))
+#define ow_entrance_value (*(uint16*)(g_ram+0x696))
+#define big_rock_starting_address (*(uint16*)(g_ram+0x698))
+#define ow_countdown_transition (*(uint8*)(g_ram+0x69A))
+#define byte_7E069C (*(uint8*)(g_ram+0x69C))
+#define byte_7E069E ((uint8*)(g_ram+0x69E))
+#define dung_toggle_floor_pos ((uint16*)(g_ram+0x6C0))
+#define dung_toggle_palace_pos ((uint16*)(g_ram+0x6D0))
+#define dung_chest_locations ((uint16*)(g_ram+0x6E0))
+#define dung_stairs_table_2 ((uint16*)(g_ram+0x6EC))
+#define current_area_of_player (*(uint16*)(g_ram+0x700))
+#define overworld_offset_base_y (*(uint16*)(g_ram+0x708))
+#define overworld_offset_mask_y (*(uint16*)(g_ram+0x70A))
+#define overworld_offset_base_x (*(uint16*)(g_ram+0x70C))
+#define overworld_offset_mask_x (*(uint16*)(g_ram+0x70E))
+#define nmi_disable_core_updates (*(uint8*)(g_ram+0x710))
+#define overworld_area_is_big (*(uint16*)(g_ram+0x712))
+#define overworld_area_is_big_backup (*(uint8*)(g_ram+0x714))
+#define overworld_right_bottom_bound_for_scroll (*(uint16*)(g_ram+0x716))
+#define vwf_flag_next_line (*(uint16*)(g_ram+0x720))
+#define vwf_curline (*(uint16*)(g_ram+0x722))
+#define vwf_var1 (*(uint16*)(g_ram+0x724))
+#define vwf_line_ptr (*(uint16*)(g_ram+0x726))
+#define extended_oam ((uint8*)(g_ram+0xA00))
+#define bytewise_extended_oam ((uint8*)(g_ram+0xA20))
+#define byte_7E0AA0 (*(uint8*)(g_ram+0xAA0))
+#define main_tile_theme_index (*(uint8*)(g_ram+0xAA1))
+#define aux_tile_theme_index (*(uint8*)(g_ram+0xAA2))
+#define sprite_graphics_index (*(uint8*)(g_ram+0xAA3))
+#define misc_sprites_graphics_index (*(uint8*)(g_ram+0xAA4))
+#define unused_config_gfx (*(uint16*)(g_ram+0xAA6))
+#define overworld_palette_aux_or_main (*(uint16*)(g_ram+0xAA8))
+#define load_chr_halfslot_even_odd (*(uint8*)(g_ram+0xAAA))
+#define palette_sp0l (*(uint8*)(g_ram+0xAAC))
+#define palette_sp5l (*(uint8*)(g_ram+0xAAD))
+#define palette_sp6l (*(uint8*)(g_ram+0xAAE))
+#define byte_7E0AB0 (*(uint8*)(g_ram+0xAB0))
+#define palette_sp6r_indoors (*(uint8*)(g_ram+0xAB1))
+#define hud_palette (*(uint8*)(g_ram+0xAB2))
+#define overworld_palette_mode (*(uint8*)(g_ram+0xAB3))
+#define overworld_palette_aux1_bp2to4_hi (*(uint8*)(g_ram+0xAB4))
+#define overworld_palette_aux2_bp5to7_hi (*(uint8*)(g_ram+0xAB5))
+#define palette_main_indoors (*(uint8*)(g_ram+0xAB6))
+#define byte_7E0AB7 (*(uint8*)(g_ram+0xAB7))
+#define overworld_palette_aux3_bp7_lo (*(uint8*)(g_ram+0xAB8))
+#define palette_swap_flag (*(uint8*)(g_ram+0xABD))
+#define flag_overworld_area_did_change (*(uint8*)(g_ram+0xABF))
+#define dma_source_addr_6 (*(uint16*)(g_ram+0xAC0))
+#define dma_source_addr_11 (*(uint16*)(g_ram+0xAC2))
+#define dma_source_addr_7 (*(uint16*)(g_ram+0xAC4))
+#define dma_source_addr_12 (*(uint16*)(g_ram+0xAC6))
+#define dma_source_addr_8 (*(uint16*)(g_ram+0xAC8))
+#define dma_source_addr_13 (*(uint16*)(g_ram+0xACA))
+#define dma_source_addr_3 (*(uint16*)(g_ram+0xACC))
+#define dma_source_addr_0 (*(uint16*)(g_ram+0xACE))
+#define dma_source_addr_4 (*(uint16*)(g_ram+0xAD0))
+#define dma_source_addr_1 (*(uint16*)(g_ram+0xAD2))
+#define dma_source_addr_5 (*(uint16*)(g_ram+0xAD4))
+#define dma_source_addr_2 (*(uint16*)(g_ram+0xAD6))
+#define dma_source_addr_10 (*(uint16*)(g_ram+0xAD8))
+#define dma_source_addr_15 (*(uint16*)(g_ram+0xADA))
+#define animated_tile_data_src (*(uint16*)(g_ram+0xADC))
+#define dma_source_addr_9 (*(uint16*)(g_ram+0xAE0))
+#define dma_source_addr_14 (*(uint16*)(g_ram+0xAE2))
+#define dma_var6 (*(uint16*)(g_ram+0xAE8))
+#define dma_var7 (*(uint16*)(g_ram+0xAEA))
+#define dma_source_addr_16 (*(uint16*)(g_ram+0xAEC))
+#define dma_source_addr_18 (*(uint16*)(g_ram+0xAEE))
+#define dma_source_addr_17 (*(uint16*)(g_ram+0xAF0))
+#define dma_source_addr_19 (*(uint16*)(g_ram+0xAF2))
+#define flag_travel_bird (*(uint16*)(g_ram+0xAF4))
+#define dma_source_addr_20 (*(uint16*)(g_ram+0xAF6))
+#define dma_source_addr_21 (*(uint16*)(g_ram+0xAF8))
+#define overlord_type ((uint8*)(g_ram+0xB00))
+#define overlord_x_lo ((uint8*)(g_ram+0xB08))
+#define overlord_x_hi ((uint8*)(g_ram+0xB10))
+#define overlord_y_lo ((uint8*)(g_ram+0xB18))
+#define overlord_y_hi ((uint8*)(g_ram+0xB20))
+#define overlord_gen1 ((uint8*)(g_ram+0xB28))
+#define overlord_gen2 ((uint8*)(g_ram+0xB30))
+#define overlord_gen3 ((uint8*)(g_ram+0xB38))
+#define overlord_floor ((uint8*)(g_ram+0xB40))
+#define overlord_offset_sprite_pos ((uint16*)(g_ram+0xB48))
+#define sprite_stunned ((uint8*)(g_ram+0xB58))
+#define repulsespark_floor_status (*(uint8*)(g_ram+0xB68))
+#define byte_7E0B69 (*(uint8*)(g_ram+0xB69))
+#define sprite_limit_instance (*(uint8*)(g_ram+0xB6A))
+#define sprite_flags ((uint8*)(g_ram+0xB6B))
+#define link_prevent_from_moving (*(uint8*)(g_ram+0xB7B))
+#define drag_player_x (*(uint16*)(g_ram+0xB7C))
+#define drag_player_y (*(uint16*)(g_ram+0xB7E))
+#define dungeon_room_history ((uint16*)(g_ram+0xB80))
+#define byte_7E0B88 (*(uint8*)(g_ram+0xB88))
+#define sprite_obj_prio ((uint8*)(g_ram+0xB89))
+#define archery_game_arrows_left (*(uint8*)(g_ram+0xB99))
+#define archery_game_out_of_arrows (*(uint8*)(g_ram+0xB9A))
+#define byte_7E0B9B (*(uint8*)(g_ram+0xB9B))
+#define dung_secrets_unk1 (*(uint16*)(g_ram+0xB9C))
+#define byte_7E0B9E (*(uint8*)(g_ram+0xB9E))
+#define sprite_ignore_projectile ((uint8*)(g_ram+0xBA0))
+#define sprite_unk2 ((uint8*)(g_ram+0xBB0))
+#define sprite_N ((uint8*)(g_ram+0xBC0))
+#define sprite_flags5 ((uint8*)(g_ram+0xBE0))
+#define ancilla_arr4 ((uint8*)(g_ram+0xBF0))
+#define ancilla_y_lo ((uint8*)(g_ram+0xBFA))
+#define ancilla_x_lo ((uint8*)(g_ram+0xC04))
+#define ancilla_y_hi ((uint8*)(g_ram+0xC0E))
+#define ancilla_x_hi ((uint8*)(g_ram+0xC18))
+#define ancilla_y_vel ((uint8*)(g_ram+0xC22))
+#define ancilla_x_vel ((uint8*)(g_ram+0xC2C))
+#define ancilla_y_subpixel ((uint8*)(g_ram+0xC36))
+#define ancilla_x_subpixel ((uint8*)(g_ram+0xC40))
+#define ancilla_type ((uint8*)(g_ram+0xC4A))
+#define ancilla_step ((uint8*)(g_ram+0xC54))
+#define ancilla_item_to_link ((uint8*)(g_ram+0xC5E))
+#define ancilla_timer ((uint8*)(g_ram+0xC68))
+#define ancilla_dir ((uint8*)(g_ram+0xC72))
+#define ancilla_floor ((uint8*)(g_ram+0xC7C))
+#define ancilla_oam_idx ((uint8*)(g_ram+0xC86))
+#define ancilla_numspr ((uint8*)(g_ram+0xC90))
+#define sprite_room ((uint8*)(g_ram+0xC9A))
+#define sprite_defl_bits ((uint8*)(g_ram+0xCAA))
+#define sprite_die_action ((uint8*)(g_ram+0xCBA))
+#define overlord_spawned_in_area ((uint8*)(g_ram+0xCCA))
+#define sprite_bump_damage ((uint8*)(g_ram+0xCD2))
+#define sprite_give_damage ((uint8*)(g_ram+0xCE2))
+#define damage_type_determiner (*(uint8*)(g_ram+0xCF2))
+#define damage_type_determiner_PADDING (*(uint8*)(g_ram+0xCF3))
+#define activate_bomb_trap_overlord (*(uint8*)(g_ram+0xCF4))
+#define dungmap_var6 (*(uint16*)(g_ram+0xCF5))
+#define overworld_secret_subst_ctr (*(uint8*)(g_ram+0xCF7))
+#define byte_7E0CF8 (*(uint8*)(g_ram+0xCF8))
+#define item_drop_luck (*(uint8*)(g_ram+0xCF9))
+#define luck_kill_counter (*(uint8*)(g_ram+0xCFA))
+#define num_sprites_killed (*(uint8*)(g_ram+0xCFB))
+#define number_of_times_hurt_by_sprites (*(uint8*)(g_ram+0xCFC))
+#define rupee_sfx_sound_delay (*(uint8*)(g_ram+0xCFD))
+#define word_7E0CFE (*(uint16*)(g_ram+0xCFE))
+#define sprite_y_lo ((uint8*)(g_ram+0xD00))
+#define sprite_x_lo ((uint8*)(g_ram+0xD10))
+#define sprite_y_hi ((uint8*)(g_ram+0xD20))
+#define sprite_x_hi ((uint8*)(g_ram+0xD30))
+#define sprite_y_vel ((uint8*)(g_ram+0xD40))
+#define sprite_x_vel ((uint8*)(g_ram+0xD50))
+#define sprite_y_subpixel ((uint8*)(g_ram+0xD60))
+#define sprite_x_subpixel ((uint8*)(g_ram+0xD70))
+#define sprite_ai_state ((uint8*)(g_ram+0xD80))
+#define sprite_A ((uint8*)(g_ram+0xD90))
+#define sprite_B ((uint8*)(g_ram+0xDA0))
+#define sprite_C ((uint8*)(g_ram+0xDB0))
+#define sprite_graphics ((uint8*)(g_ram+0xDC0))
+#define sprite_state ((uint8*)(g_ram+0xDD0))
+#define sprite_D ((uint8*)(g_ram+0xDE0))
+#define sprite_delay_main ((uint8*)(g_ram+0xDF0))
+#define sprite_delay_aux1 ((uint8*)(g_ram+0xE00))
+#define sprite_delay_aux2 ((uint8*)(g_ram+0xE10))
+#define sprite_type ((uint8*)(g_ram+0xE20))
+#define sprite_subtype ((uint8*)(g_ram+0xE30))
+#define sprite_flags2 ((uint8*)(g_ram+0xE40))
+#define sprite_health ((uint8*)(g_ram+0xE50))
+#define sprite_flags3 ((uint8*)(g_ram+0xE60))
+#define sprite_wallcoll ((uint8*)(g_ram+0xE70))
+#define sprite_subtype2 ((uint8*)(g_ram+0xE80))
+#define sprite_E ((uint8*)(g_ram+0xE90))
+#define sprite_F ((uint8*)(g_ram+0xEA0))
+#define sprite_head_dir ((uint8*)(g_ram+0xEB0))
+#define sprite_anim_clock ((uint8*)(g_ram+0xEC0))
+#define sprite_G ((uint8*)(g_ram+0xED0))
+#define sprite_delay_aux3 ((uint8*)(g_ram+0xEE0))
+#define sprite_hit_timer ((uint8*)(g_ram+0xEF0))
+#define sprite_pause ((uint8*)(g_ram+0xF00))
+#define sprite_delay_aux4 ((uint8*)(g_ram+0xF10))
+#define sprite_floor ((uint8*)(g_ram+0xF20))
+#define sprite_y_recoil ((uint8*)(g_ram+0xF30))
+#define sprite_x_recoil ((uint8*)(g_ram+0xF40))
+#define sprite_oam_flags ((uint8*)(g_ram+0xF50))
+#define sprite_flags4 ((uint8*)(g_ram+0xF60))
+#define sprite_z ((uint8*)(g_ram+0xF70))
+#define sprite_z_vel ((uint8*)(g_ram+0xF80))
+#define sprite_z_subpos ((uint8*)(g_ram+0xF90))
+#define cur_object_index (*(uint8*)(g_ram+0xFA0))
+#define byte_7E0FA1 (*(uint8*)(g_ram+0xFA1))
+#define sprite_tiletype (*(uint8*)(g_ram+0xFA5))
+#define dungmap_var7 (*(uint16*)(g_ram+0xFA8))
+#define dungmap_var8 (*(uint16*)(g_ram+0xFAA))
+#define repulsespark_timer (*(uint8*)(g_ram+0xFAC))
+#define repulsespark_x_lo (*(uint8*)(g_ram+0xFAD))
+#define repulsespark_y_lo (*(uint8*)(g_ram+0xFAE))
+#define repulsespark_anim_delay (*(uint8*)(g_ram+0xFAF))
+#define byte_7E0FB0 (*(uint8*)(g_ram+0xFB0))
+#define byte_7E0FB1 (*(uint8*)(g_ram+0xFB1))
+#define byte_7E0FB2 (*(uint8*)(g_ram+0xFB2))
+#define sort_sprites_setting (*(uint8*)(g_ram+0xFB3))
+#define garnish_active (*(uint8*)(g_ram+0xFB4))
+#define tmp_counter (*(uint8*)(g_ram+0xFB5))
+#define byte_7E0FB6 (*(uint8*)(g_ram+0xFB6))
+#define spr_ranged_based_toggler (*(uint8*)(g_ram+0xFB7))
+#define sprcoll_x_size (*(uint16*)(g_ram+0xFB8))
+#define sprcoll_y_size (*(uint16*)(g_ram+0xFBA))
+#define sprcoll_x_base (*(uint16*)(g_ram+0xFBC))
+#define sprcoll_y_base (*(uint16*)(g_ram+0xFBE))
+#define flag_unk1 (*(uint8*)(g_ram+0xFC1))
+#define link_x_coord_prev (*(uint16*)(g_ram+0xFC2))
+#define link_y_coord_prev (*(uint16*)(g_ram+0xFC4))
+#define byte_7E0FC6 (*(uint8*)(g_ram+0xFC6))
+#define prizes_arr1 ((uint8*)(g_ram+0xFC7))
+#define debug_game_frozen (*(uint8*)(g_ram+0xFD7))
+#define cur_sprite_x (*(uint16*)(g_ram+0xFD8))
+#define cur_sprite_y (*(uint16*)(g_ram+0xFDA))
+#define sprite_alert_flag (*(uint8*)(g_ram+0xFDC))
+#define byte_7E0FDD (*(uint8*)(g_ram+0xFDD))
+#define byte_7E0FDE (*(uint8*)(g_ram+0xFDE))
+#define oam_region_base ((uint16*)(g_ram+0xFE0))
+#define oam_alloc_arr1 ((uint16*)(g_ram+0xFEC))
+#define byte_7E0FF8 (*(uint8*)(g_ram+0xFF8))
+#define intro_times_pal_flash (*(uint8*)(g_ram+0xFF9))
+#define alt_sprites_flag (*(uint8*)(g_ram+0xFFA))
+#define byte_7E0FFB (*(uint8*)(g_ram+0xFFB))
+#define flag_block_link_menu (*(uint8*)(g_ram+0xFFC))
+#define byte_7E0FFD (*(uint8*)(g_ram+0xFFD))
+#define byte_7E0FFE (*(uint8*)(g_ram+0xFFE))
+#define is_in_dark_world (*(uint8*)(g_ram+0xFFF))
+#define word_7E1800 (*(uint16*)(g_ram+0x1800))
+#define word_7E1806 (*(uint16*)(g_ram+0x1806))
+#define word_7E197E (*(uint16*)(g_ram+0x197E))
+#define door_type_and_slot ((uint16*)(g_ram+0x1980))
+#define dung_door_tilemap_address ((uint16*)(g_ram+0x19A0))
+#define dung_door_direction ((uint16*)(g_ram+0x19C0))
+#define dung_exit_door_count (*(uint16*)(g_ram+0x19E0))
+#define dung_exit_door_addresses ((uint16*)(g_ram+0x19E2))
+#define tagalong_y_lo ((uint8*)(g_ram+0x1A00))
+#define tagalong_y_hi ((uint8*)(g_ram+0x1A14))
+#define tagalong_x_lo ((uint8*)(g_ram+0x1A28))
+#define tagalong_x_hi ((uint8*)(g_ram+0x1A3C))
+#define tagalong_z ((uint8*)(g_ram+0x1A50))
+#define tagalong_layerbits ((uint8*)(g_ram+0x1A64))
+#define bird_travel_x_lo ((uint8*)(g_ram+0x1AB0))
+#define bird_travel_x_hi ((uint8*)(g_ram+0x1AC0))
+#define bird_travel_y_lo ((uint8*)(g_ram+0x1AD0))
+#define bird_travel_y_hi ((uint8*)(g_ram+0x1AE0))
+#define birdtravel_var1 ((uint8*)(g_ram+0x1AF0))
+#define text_msgbox_topleft_copy (*(uint16*)(g_ram+0x1CD0))
+#define text_msgbox_topleft (*(uint16*)(g_ram+0x1CD2))
+#define text_render_state (*(uint8*)(g_ram+0x1CD4))
+#define vwf_line_speed_cur (*(uint8*)(g_ram+0x1CD5))
+#define vwf_line_speed (*(uint8*)(g_ram+0x1CD6))
+#define text_incremental_state (*(uint8*)(g_ram+0x1CD7))
+#define messaging_module (*(uint8*)(g_ram+0x1CD8))
+#define dialogue_msg_read_pos (*(uint16*)(g_ram+0x1CD9))
+#define dialogue_text_color (*(uint8*)(g_ram+0x1CDC))
+#define dialogue_msg_src_offs (*(uint16*)(g_ram+0x1CDD))
+#define byte_7E1CDF (*(uint8*)(g_ram+0x1CDF))
+#define text_wait_countdown (*(uint16*)(g_ram+0x1CE0))
+#define text_tilemap_cur (*(uint16*)(g_ram+0x1CE2))
+#define text_next_position (*(uint8*)(g_ram+0x1CE6))
+#define choice_in_multiselect_box (*(uint8*)(g_ram+0x1CE8))
+#define text_wait_countdown2 (*(uint8*)(g_ram+0x1CE9))
+
+// This seems never nonzero
+#define dialogue_scroll_speed (*(uint8*)(g_ram+0x1CEA))
+#define dialogue_message_index (*(uint16*)(g_ram+0x1CF0))
+#define dialogue_number ((uint8*)(g_ram+0x1CF2))
+#define choice_in_multiselect_box_bak (*(uint8*)(g_ram+0x1CF4))
+#define alt_sprite_state ((uint8*)(g_ram+0x1D00))
+#define alt_sprite_type ((uint8*)(g_ram+0x1D10))
+#define alt_sprite_x_lo ((uint8*)(g_ram+0x1D20))
+#define alt_sprite_x_hi ((uint8*)(g_ram+0x1D30))
+#define alt_sprite_y_lo ((uint8*)(g_ram+0x1D40))
+#define alt_sprite_y_hi ((uint8*)(g_ram+0x1D50))
+#define alt_sprite_graphics ((uint8*)(g_ram+0x1D60))
+#define alt_sprite_A ((uint8*)(g_ram+0x1D70))
+#define alt_sprite_head_dir ((uint8*)(g_ram+0x1D80))
+#define alt_sprite_oam_flags ((uint8*)(g_ram+0x1D90))
+#define alt_sprite_obj_prio ((uint8*)(g_ram+0x1DA0))
+#define alt_sprite_D ((uint8*)(g_ram+0x1DB0))
+#define alt_sprite_flags2 ((uint8*)(g_ram+0x1DC0))
+#define alt_sprite_floor ((uint8*)(g_ram+0x1DD0))
+#define alt_sprite_spawned_flag ((uint8*)(g_ram+0x1DE0))
+#define alt_sprite_flags3 ((uint8*)(g_ram+0x1DF0))
+#define intro_step_index (*(uint8*)(g_ram+0x1E00))
+#define intro_step_timer (*(uint8*)(g_ram+0x1E01))
+#define intro_want_double_ret (*(uint8*)(g_ram+0x1E02))
+#define intro_sprite_alloc (*(uint16*)(g_ram+0x1E08))
+#define intro_frame_ctr (*(uint8*)(g_ram+0x1E0A))
+#define triforce_ctr (*(uint16*)(g_ram+0x1E0C))
+#define intro_sprite_isinited ((uint8*)(g_ram+0x1E10))
+#define intro_sprite_subtype ((uint8*)(g_ram+0x1E18))
+#define intro_sprite_state ((uint8*)(g_ram+0x1E20))
+#define intro_x_subpixel ((uint8*)(g_ram+0x1E28))
+#define intro_x_lo ((uint8*)(g_ram+0x1E30))
+#define intro_x_hi ((uint8*)(g_ram+0x1E38))
+#define intro_y_subpixel ((uint8*)(g_ram+0x1E40))
+#define intro_y_lo ((uint8*)(g_ram+0x1E48))
+#define intro_y_hi ((uint8*)(g_ram+0x1E50))
+#define intro_x_vel ((uint8*)(g_ram+0x1E58))
+#define intro_y_vel ((uint8*)(g_ram+0x1E60))
+#define intro_did_run_step (*(uint8*)(g_ram+0x1F00))
+#define poly_config_color_mode (*(uint8*)(g_ram+0x1F01))
+#define poly_config1 (*(uint8*)(g_ram+0x1F02))
+#define poly_which_model (*(uint8*)(g_ram+0x1F03))
+#define poly_a (*(uint8*)(g_ram+0x1F04))
+#define poly_b (*(uint8*)(g_ram+0x1F05))
+#define poly_base_x (*(uint8*)(g_ram+0x1F06))
+#define poly_base_y (*(uint8*)(g_ram+0x1F07))
+#define poly_var1 (*(uint16*)(g_ram+0x1F08))
+#define thread_other_stack (*(uint16*)(g_ram+0x1F0A))
+#define nmi_flag_update_polyhedral (*(uint8*)(g_ram+0x1F0C))
+#define poly_config_num_vertex (*(uint8*)(g_ram+0x1F3F))
+#define poly_config_num_polys (*(uint8*)(g_ram+0x1F40))
+#define poly_fromlut_ptr2 (*(uint16*)(g_ram+0x1F41))
+#define poly_fromlut_ptr4 (*(uint16*)(g_ram+0x1F43))
+#define poly_fromlut_z (*(uint8*)(g_ram+0x1F45))
+#define poly_fromlut_y (*(uint8*)(g_ram+0x1F46))
+#define poly_fromlut_x (*(uint8*)(g_ram+0x1F47))
+#define poly_f0 (*(uint16*)(g_ram+0x1F48))
+#define poly_f1 (*(uint16*)(g_ram+0x1F4A))
+#define poly_f2 (*(uint16*)(g_ram+0x1F4C))
+#define poly_num_vertex_in_poly (*(uint8*)(g_ram+0x1F4E))
+#define poly_raster_color_config (*(uint8*)(g_ram+0x1F4F))
+#define poly_sin_a (*(uint16*)(g_ram+0x1F50))
+#define poly_cos_a (*(uint16*)(g_ram+0x1F52))
+#define poly_sin_b (*(uint16*)(g_ram+0x1F54))
+#define poly_cos_b (*(uint16*)(g_ram+0x1F56))
+#define poly_e0 (*(uint16*)(g_ram+0x1F58))
+#define poly_e2 (*(uint16*)(g_ram+0x1F5A))
+#define poly_e3 (*(uint16*)(g_ram+0x1F5C))
+#define poly_e1 (*(uint16*)(g_ram+0x1F5E))
+#define poly_arr_x ((uint8*)(g_ram+0x1F60))
+#define poly_arr_y ((uint8*)(g_ram+0x1F88))
+#define poly_tmp0 (*(uint16*)(g_ram+0x1FB0))
+#define poly_tmp1 (*(uint16*)(g_ram+0x1FB2))
+#define poly_raster_color0 (*(uint16*)(g_ram+0x1FB5))
+#define poly_raster_color1 (*(uint16*)(g_ram+0x1FB7))
+#define poly_raster_dst_ptr (*(uint16*)(g_ram+0x1FB9))
+#define poly_tmp2 (*(uint8*)(g_ram+0x1FBC))
+#define poly_arr_xy_coords_minus1 (*(uint8*)(g_ram+0x1FBF))
+#define poly_xy_coords ((uint8*)(g_ram+0x1FC0))
+#define poly_total_num_steps (*(uint8*)(g_ram+0x1FE0))
+#define poly_x0_cur (*(uint8*)(g_ram+0x1FE1))
+#define poly_y0_cur (*(uint8*)(g_ram+0x1FE2))
+#define poly_x0_target (*(uint8*)(g_ram+0x1FE3))
+#define poly_y0_trig (*(uint8*)(g_ram+0x1FE4))
+#define poly_x0_frac (*(uint16*)(g_ram+0x1FE5))
+#define poly_x0_step (*(uint16*)(g_ram+0x1FE7))
+#define poly_cur_vertex_idx0 (*(uint8*)(g_ram+0x1FE9))
+#define poly_x1_cur (*(uint8*)(g_ram+0x1FEA))
+#define poly_y1_cur (*(uint8*)(g_ram+0x1FEB))
+#define poly_x1_target (*(uint8*)(g_ram+0x1FEC))
+#define poly_y1_trig (*(uint8*)(g_ram+0x1FED))
+#define poly_x1_frac (*(uint16*)(g_ram+0x1FEE))
+#define poly_x1_step (*(uint16*)(g_ram+0x1FF0))
+#define poly_cur_vertex_idx1 (*(uint8*)(g_ram+0x1FF2))
+#define poly_raster_numfull (*(uint16*)(g_ram+0x1FFA))
+#define dung_bg2 ((uint16*)(g_ram+0x2000))
+#define dung_bg1 ((uint16*)(g_ram+0x4000))
+#define word_7E6000 (*(uint16*)(g_ram+0x6000))
+#define word_7E8000 (*(uint16*)(g_ram+0x8000))
+#define dung_hdr_travel_destinations ((uint8*)(g_ram+0xC000))
+#define dung_want_lights_out (*(uint8*)(g_ram+0xC005))
+#define dung_want_lights_out_copy (*(uint8*)(g_ram+0xC006))
+#define palette_filter_countdown (*(uint16*)(g_ram+0xC007))
+#define darkening_or_lightening_screen (*(uint16*)(g_ram+0xC009))
+#define mosaic_target_level (*(uint8*)(g_ram+0xC00B))
+#define mosaic_target_level_PADDING (*(uint8*)(g_ram+0xC00C))
+#define bg_tile_animation_countdown (*(uint16*)(g_ram+0xC00D))
+#define word_7EC00F (*(uint16*)(g_ram+0xC00F))
+#define mosaic_level (*(uint8*)(g_ram+0xC011))
+#define word_7EC013 (*(uint16*)(g_ram+0xC013))
+#define word_7EC015 (*(uint16*)(g_ram+0xC015))
+#define overworld_fixed_color_plusminus (*(uint8*)(g_ram+0xC017))
+#define agahnim_pal_setting ((uint16*)(g_ram+0xC019))
+#define overworld_area_index_spexit (*(uint16*)(g_ram+0xC100))
+#define TM_copy_spexit (*(uint8*)(g_ram+0xC102))
+#define BG2VOFS_copy2_spexit (*(uint16*)(g_ram+0xC104))
+#define BG2HOFS_copy2_spexit (*(uint16*)(g_ram+0xC106))
+#define link_y_coord_spexit (*(uint16*)(g_ram+0xC108))
+#define link_x_coord_spexit (*(uint16*)(g_ram+0xC10A))
+#define overworld_screen_index_spexit (*(uint16*)(g_ram+0xC10C))
+#define map16_load_src_off_spexit (*(uint16*)(g_ram+0xC10E))
+#define camera_y_coord_scroll_low_spexit (*(uint16*)(g_ram+0xC110))
+#define camera_x_coord_scroll_low_spexit (*(uint16*)(g_ram+0xC112))
+#define room_scroll_vars0_ystart_spexit (*(uint16*)(g_ram+0xC114))
+#define room_scroll_vars0_yend_spexit (*(uint16*)(g_ram+0xC116))
+#define room_scroll_vars0_xstart_spexit (*(uint16*)(g_ram+0xC118))
+#define room_scroll_vars0_xend_spexit (*(uint16*)(g_ram+0xC11A))
+#define up_down_scroll_target_spexit (*(uint16*)(g_ram+0xC11C))
+#define up_down_scroll_target_end_spexit (*(uint16*)(g_ram+0xC11E))
+#define left_right_scroll_target_spexit (*(uint16*)(g_ram+0xC120))
+#define left_right_scroll_target_end_spexit (*(uint16*)(g_ram+0xC122))
+#define byte_7EC124 (*(uint8*)(g_ram+0xC124))
+#define main_tile_theme_index_spexit (*(uint8*)(g_ram+0xC125))
+#define aux_tile_theme_index_spexit (*(uint8*)(g_ram+0xC126))
+#define sprite_graphics_index_spexit (*(uint8*)(g_ram+0xC127))
+#define overworld_unk1_spexit (*(uint16*)(g_ram+0xC12A))
+#define overworld_unk1_neg_spexit (*(uint16*)(g_ram+0xC12C))
+#define overworld_unk3_spexit (*(uint16*)(g_ram+0xC12E))
+#define overworld_unk3_neg_spexit (*(uint16*)(g_ram+0xC130))
+#define overworld_area_index_exit (*(uint16*)(g_ram+0xC140))
+#define TM_copy_exit (*(uint16*)(g_ram+0xC142))
+#define BG2VOFS_copy2_exit (*(uint16*)(g_ram+0xC144))
+#define BG2HOFS_copy2_exit (*(uint16*)(g_ram+0xC146))
+#define link_y_coord_exit (*(uint16*)(g_ram+0xC148))
+#define link_x_coord_exit (*(uint16*)(g_ram+0xC14A))
+#define overworld_screen_index_exit (*(uint16*)(g_ram+0xC14C))
+#define map16_load_src_off_exit (*(uint16*)(g_ram+0xC14E))
+#define camera_y_coord_scroll_low_exit (*(uint16*)(g_ram+0xC150))
+#define camera_x_coord_scroll_low_exit (*(uint16*)(g_ram+0xC152))
+#define up_down_scroll_target_exit (*(uint16*)(g_ram+0xC15C))
+#define up_down_scroll_target_end_exit (*(uint16*)(g_ram+0xC15E))
+#define left_right_scroll_target_exit (*(uint16*)(g_ram+0xC160))
+#define left_right_scroll_target_end_exit (*(uint16*)(g_ram+0xC162))
+#define byte_7EC164 (*(uint8*)(g_ram+0xC164))
+#define main_tile_theme_index_exit (*(uint8*)(g_ram+0xC165))
+#define aux_tile_theme_index_exit (*(uint8*)(g_ram+0xC166))
+#define sprite_graphics_index_exit (*(uint8*)(g_ram+0xC167))
+#define overworld_unk1_exit (*(uint16*)(g_ram+0xC16A))
+#define overworld_unk1_neg_exit (*(uint16*)(g_ram+0xC16C))
+#define overworld_unk3_exit (*(uint16*)(g_ram+0xC16E))
+#define overworld_unk3_neg_exit (*(uint16*)(g_ram+0xC170))
+#define orange_blue_barrier_state (*(uint16*)(g_ram+0xC172))
+#define word_7EC174 (*(uint16*)(g_ram+0xC174))
+#define word_7EC176 (*(uint16*)(g_ram+0xC176))
+#define BG2HOFS_copy2_cached (*(uint16*)(g_ram+0xC180))
+#define BG2VOFS_copy2_cached (*(uint16*)(g_ram+0xC182))
+#define link_y_coord_cached (*(uint16*)(g_ram+0xC184))
+#define link_x_coord_cached (*(uint16*)(g_ram+0xC186))
+#define room_scroll_vars_y_vofs1_cached (*(uint16*)(g_ram+0xC188))
+#define room_scroll_vars_y_vofs2_cached (*(uint16*)(g_ram+0xC18A))
+#define room_scroll_vars_x_vofs1_cached (*(uint16*)(g_ram+0xC18C))
+#define room_scroll_vars_x_vofs2_cached (*(uint16*)(g_ram+0xC18E))
+#define up_down_scroll_target_cached (*(uint16*)(g_ram+0xC190))
+#define up_down_scroll_target_end_cached (*(uint16*)(g_ram+0xC192))
+#define left_right_scroll_target_cached (*(uint16*)(g_ram+0xC194))
+#define left_right_scroll_target_end_cached (*(uint16*)(g_ram+0xC196))
+#define camera_y_coord_scroll_low_cached (*(uint16*)(g_ram+0xC198))
+#define camera_x_coord_scroll_low_cached (*(uint16*)(g_ram+0xC19A))
+#define quadrant_fullsize_x_cached (*(uint8*)(g_ram+0xC19C))
+#define quadrant_fullsize_y_cached (*(uint8*)(g_ram+0xC19D))
+#define link_quadrant_x_cached (*(uint8*)(g_ram+0xC19E))
+#define link_quadrant_y_cached (*(uint8*)(g_ram+0xC19F))
+#define link_direction_facing_cached (*(uint8*)(g_ram+0xC1A6))
+#define link_is_on_lower_level_cached (*(uint8*)(g_ram+0xC1A7))
+#define link_is_on_lower_level_mirror_cached (*(uint8*)(g_ram+0xC1A8))
+#define is_standing_in_doorway_cahed (*(uint8*)(g_ram+0xC1A9))
+#define dung_cur_floor_cached (*(uint8*)(g_ram+0xC1AA))
+#define mapbak_BG1HOFS_copy2 (*(uint16*)(g_ram+0xC200))
+#define mapbak_BG2HOFS_copy2 (*(uint16*)(g_ram+0xC202))
+#define mapbak_BG1VOFS_copy2 (*(uint16*)(g_ram+0xC204))
+#define mapbak_BG2VOFS_copy2 (*(uint16*)(g_ram+0xC206))
+#define dung_bg2_properties_backup (*(uint8*)(g_ram+0xC208))
+#define overworld_pal_unk1 (*(uint8*)(g_ram+0xC20A))
+#define overworld_pal_unk2 (*(uint8*)(g_ram+0xC20B))
+#define overworld_pal_unk3 (*(uint8*)(g_ram+0xC20C))
+#define mapbak_main_tile_theme_index (*(uint8*)(g_ram+0xC20E))
+#define mapbak_sprite_graphics_index (*(uint8*)(g_ram+0xC20F))
+#define mapbak_aux_tile_theme_index (*(uint8*)(g_ram+0xC210))
+#define mapbak_TM (*(uint8*)(g_ram+0xC211))
+#define mapbak_TS (*(uint8*)(g_ram+0xC212))
+#define overworld_screen_index_prev (*(uint16*)(g_ram+0xC213))
+#define map16_load_src_off_prev (*(uint16*)(g_ram+0xC215))
+#define map16_load_var2_prev (*(uint16*)(g_ram+0xC217))
+#define map16_load_dst_off_prev (*(uint16*)(g_ram+0xC219))
+#define overworld_screen_transition_prev (*(uint8*)(g_ram+0xC21B))
+#define overworld_screen_trans_dir_bits_prev (*(uint16*)(g_ram+0xC21D))
+#define overworld_screen_trans_dir_bits2_prev (*(uint16*)(g_ram+0xC21F))
+#define mapbak_bg1_x_offset (*(uint16*)(g_ram+0xC221))
+#define mapbak_bg1_y_offset (*(uint16*)(g_ram+0xC223))
+#define mapbak_CGWSEL (*(uint16*)(g_ram+0xC225))
+#define music_unk1_death (*(uint8*)(g_ram+0xC227))
+#define sound_effect_ambient_last_death (*(uint8*)(g_ram+0xC228))
+#define mapbak_HDMAEN (*(uint8*)(g_ram+0xC229))
+#define byte_7EC22F (*(uint8*)(g_ram+0xC22F))
+#define vwf_arr ((uint8*)(g_ram+0xC230))
+#define aux_bg_subset_0 (*(uint8*)(g_ram+0xC2F8))
+#define aux_bg_subset_1 (*(uint8*)(g_ram+0xC2F9))
+#define aux_bg_subset_2 (*(uint8*)(g_ram+0xC2FA))
+#define aux_bg_subset_3 (*(uint8*)(g_ram+0xC2FB))
+#define sprite_gfx_subset_0 (*(uint8*)(g_ram+0xC2FC))
+#define sprite_gfx_subset_1 (*(uint8*)(g_ram+0xC2FD))
+#define sprite_gfx_subset_2 (*(uint8*)(g_ram+0xC2FE))
+#define sprite_gfx_subset_3 (*(uint8*)(g_ram+0xC2FF))
+#define aux_palette_buffer ((uint16*)(g_ram+0xC300))
+#define main_palette_buffer ((uint16*)(g_ram+0xC500))
+#define hud_tile_indices_buffer ((uint16*)(g_ram+0xC700))
+#define moving_wall_arr1 ((uint16*)(g_ram+0xC880))
+#define word_7EE000 (*(uint16*)(g_ram+0xE000))
+#define polyhedral_buffer ((uint8*)(g_ram+0xE800))
+#define save_dung_info ((uint16*)(g_ram+0xF000))
+#define save_ow_event_info ((uint8*)(g_ram+0xF280))
+#define savegame_has_master_sword_flags (*(uint16*)(g_ram+0xF300))
+#define byte_7EF33F (*(uint8*)(g_ram+0xF33F))
+#define link_item_bow (*(uint8*)(g_ram+0xF340))
+#define link_item_boomerang (*(uint8*)(g_ram+0xF341))
+#define link_item_hookshot (*(uint8*)(g_ram+0xF342))
+#define link_item_bombs (*(uint8*)(g_ram+0xF343))
+#define link_item_mushroom (*(uint8*)(g_ram+0xF344))
+#define link_item_fire_rod (*(uint8*)(g_ram+0xF345))
+#define link_item_ice_rod (*(uint8*)(g_ram+0xF346))
+#define link_item_bombos_medallion (*(uint8*)(g_ram+0xF347))
+#define link_item_ether_medallion (*(uint8*)(g_ram+0xF348))
+#define link_item_quake_medallion (*(uint8*)(g_ram+0xF349))
+#define link_item_torch (*(uint8*)(g_ram+0xF34A))
+#define link_item_hammer (*(uint8*)(g_ram+0xF34B))
+#define link_item_flute (*(uint8*)(g_ram+0xF34C))
+#define link_item_bug_net (*(uint8*)(g_ram+0xF34D))
+#define link_item_book_of_mudora (*(uint8*)(g_ram+0xF34E))
+#define link_item_bottle_index (*(uint8*)(g_ram+0xF34F))
+#define link_item_cane_somaria (*(uint8*)(g_ram+0xF350))
+#define link_item_cane_byrna (*(uint8*)(g_ram+0xF351))
+#define link_item_cape (*(uint8*)(g_ram+0xF352))
+#define link_item_mirror (*(uint8*)(g_ram+0xF353))
+#define link_item_gloves (*(uint8*)(g_ram+0xF354))
+#define link_item_boots (*(uint8*)(g_ram+0xF355))
+#define link_item_flippers (*(uint8*)(g_ram+0xF356))
+#define link_item_moon_pearl (*(uint8*)(g_ram+0xF357))
+#define link_sword_type (*(uint8*)(g_ram+0xF359))
+#define link_shield_type (*(uint8*)(g_ram+0xF35A))
+#define link_armor (*(uint8*)(g_ram+0xF35B))
+#define link_bottle_info ((uint8*)(g_ram+0xF35C))
+#define link_rupees_goal (*(uint16*)(g_ram+0xF360))
+#define link_rupees_actual (*(uint16*)(g_ram+0xF362))
+#define link_compass (*(uint16*)(g_ram+0xF364))
+#define link_bigkey (*(uint16*)(g_ram+0xF366))
+#define link_dungeon_map (*(uint16*)(g_ram+0xF368))
+#define link_rupees_in_pond (*(uint8*)(g_ram+0xF36A))
+#define link_heart_pieces (*(uint8*)(g_ram+0xF36B))
+#define link_health_capacity (*(uint8*)(g_ram+0xF36C))
+#define link_health_current (*(uint8*)(g_ram+0xF36D))
+#define link_magic_power (*(uint8*)(g_ram+0xF36E))
+#define link_num_keys (*(uint8*)(g_ram+0xF36F))
+#define link_bomb_upgrades (*(uint8*)(g_ram+0xF370))
+#define link_arrow_upgrades (*(uint8*)(g_ram+0xF371))
+#define link_hearts_filler (*(uint8*)(g_ram+0xF372))
+#define link_magic_filler (*(uint8*)(g_ram+0xF373))
+#define link_which_pendants (*(uint8*)(g_ram+0xF374))
+#define link_bomb_filler (*(uint8*)(g_ram+0xF375))
+#define link_arrow_filler (*(uint8*)(g_ram+0xF376))
+#define link_num_arrows (*(uint8*)(g_ram+0xF377))
+#define link_ability_flags (*(uint8*)(g_ram+0xF379))
+#define link_has_crystals (*(uint8*)(g_ram+0xF37A))
+#define link_magic_consumption (*(uint8*)(g_ram+0xF37B))
+#define link_keys_earned_per_dungeon ((uint8*)(g_ram+0xF37C))
+#define sram_progress_indicator (*(uint8*)(g_ram+0xF3C5))
+#define sram_progress_flags (*(uint8*)(g_ram+0xF3C6))
+#define savegame_map_icons_indicator (*(uint8*)(g_ram+0xF3C7))
+#define which_starting_point (*(uint8*)(g_ram+0xF3C8))
+#define sram_progress_indicator_3 (*(uint8*)(g_ram+0xF3C9))
+#define savegame_is_darkworld (*(uint8*)(g_ram+0xF3CA))
+#define follower_indicator (*(uint8*)(g_ram+0xF3CC))
+#define saved_tagalong_y (*(uint16*)(g_ram+0xF3CD))
+#define saved_tagalong_x (*(uint16*)(g_ram+0xF3CF))
+#define saved_tagalong_indoors (*(uint8*)(g_ram+0xF3D1))
+#define saved_tagalong_floor (*(uint8*)(g_ram+0xF3D2))
+#define follower_dropped (*(uint8*)(g_ram+0xF3D3))
+#define deaths_per_palace ((uint16*)(g_ram+0xF3E7))
+#define death_save_counter (*(uint16*)(g_ram+0xF403))
+#define death_var2 (*(uint16*)(g_ram+0xF405))
+#define word_7EF4FE (*(uint16*)(g_ram+0xF4FE))
+#define pots_revealed_in_room ((uint16*)(g_ram+0xF580))
+#define memorized_tile_addr ((uint16*)(g_ram+0xF800))
+#define memorized_tile_value ((uint16*)(g_ram+0xFA00))
+#define word_7EFA40 ((uint16*)(g_ram+0xFA40))
+#define dung_torch_data ((uint16*)(g_ram+0xFB40))
+#define overworld_sprite_gfx ((uint8*)(g_ram+0xFCC0))
+#define overworld_sprite_palettes ((uint8*)(g_ram+0xFD40))
+#define attributes_for_tile ((uint8*)(g_ram+0xFE00))
+#define skullwoodsfire_var0 ((uint8*)(g_ram+0x10000))
+#define skullwoodsfire_var5 ((uint8*)(g_ram+0x10008))
+#define skullwoodsfire_var4 (*(uint8*)(g_ram+0x10010))
+#define blastwall_var4 (*(uint8*)(g_ram+0x10011))
+#define skullwoodsfire_var9 (*(uint16*)(g_ram+0x10018))
+#define skullwoodsfire_var11 (*(uint16*)(g_ram+0x1001A))
+#define blastwall_var7 (*(uint8*)(g_ram+0x1001C))
+#define skullwoodsfire_y_arr ((uint16*)(g_ram+0x10020))
+#define skullwoodsfire_var10 (*(uint16*)(g_ram+0x10026))
+#define skullwoodsfire_x_arr ((uint16*)(g_ram+0x10030))
+#define skullwoodsfire_var12 (*(uint16*)(g_ram+0x10036))
+#define blastwall_var12 ((uint8*)(g_ram+0x10040))
+#define word_7F1000 (*(uint16*)(g_ram+0x11000))
+#define word_7F1010 (*(uint16*)(g_ram+0x11010))
+#define byte_7F11FA (*(uint8*)(g_ram+0x111FA))
+#define byte_7F11FB (*(uint8*)(g_ram+0x111FB))
+#define byte_7F11FC (*(uint8*)(g_ram+0x111FC))
+#define byte_7F11FD (*(uint8*)(g_ram+0x111FD))
+#define byte_7F11FE (*(uint8*)(g_ram+0x111FE))
+#define byte_7F11FF (*(uint8*)(g_ram+0x111FF))
+#define messaging_text_buffer ((uint8*)(g_ram+0x11200))
+#define word_7F1FC0 (*(uint16*)(g_ram+0x11FC0))
+#define dung_bg2_attr_table ((uint8*)(g_ram+0x12000))
+#define dung_bg1_attr_table ((uint8*)(g_ram+0x13000))
+#define word_7F4000 (*(uint16*)(g_ram+0x14000))
+#define word_7F4002 (*(uint16*)(g_ram+0x14002))
+#define word_7F4004 (*(uint16*)(g_ram+0x14004))
+#define word_7F4006 (*(uint16*)(g_ram+0x14006))
+#define map16_decode_0 ((uint8*)(g_ram+0x14400))
+#define map16_decode_1 ((uint8*)(g_ram+0x14410))
+#define map16_decode_2 ((uint8*)(g_ram+0x14420))
+#define map16_decode_3 ((uint8*)(g_ram+0x14430))
+#define map16_decode_last (*(uint16*)(g_ram+0x14440))
+#define map16_decode_tmp (*(uint16*)(g_ram+0x14442))
+#define breaktowerseal_var3 ((uint8*)(g_ram+0x15800))
+#define breaktowerseal_var4 (*(uint8*)(g_ram+0x15808))
+#define breaktowerseal_x (*(uint16*)(g_ram+0x1580E))
+#define breaktowerseal_y (*(uint16*)(g_ram+0x15810))
+#define breaktowerseal_var5 (*(uint8*)(g_ram+0x15812))
+#define breaktowerseal_base_sparkle_y_lo ((uint8*)(g_ram+0x15817))
+#define breaktowerseal_base_sparkle_y_hi ((uint8*)(g_ram+0x1581F))
+#define breaktowerseal_base_sparkle_x_lo ((uint8*)(g_ram+0x15827))
+#define breaktowerseal_base_sparkle_x_hi ((uint8*)(g_ram+0x1582F))
+#define breaktowerseal_sparkle_var1 ((uint8*)(g_ram+0x15837))
+#define breaktowerseal_sparkle_y_lo ((uint8*)(g_ram+0x1584F))
+#define breaktowerseal_sparkle_y_hi ((uint8*)(g_ram+0x15867))
+#define breaktowerseal_sparkle_x_lo ((uint8*)(g_ram+0x1587F))
+#define breaktowerseal_sparkle_x_hi ((uint8*)(g_ram+0x15897))
+#define breaktowerseal_sparkle_var2 ((uint8*)(g_ram+0x158AF))
+#define overworld_music ((uint8*)(g_ram+0x15B00))
+#define freeRam ((uint8*)(g_ram+0x15BA0))
+#define enemy_damage_data ((uint8*)(g_ram+0x16000))
+#define hdma_table_unused ((uint16*)(g_ram+0x17000))
+#define kTextDialoguePointers ((uint8*)(g_ram+0x171C0))
+#define word_7F8000 (*(uint16*)(g_ram+0x18000))
+#define word_7F9B52 (*(uint16*)(g_ram+0x19B52))
+#define word_7F9B54 (*(uint16*)(g_ram+0x19B54))
+#define word_7F9B56 (*(uint16*)(g_ram+0x19B56))
+#define word_7F9B58 (*(uint16*)(g_ram+0x19B58))
+#define word_7FA000 (*(uint16*)(g_ram+0x1A000))
+#define word_7FC000 (*(uint16*)(g_ram+0x1C000))
+#define mapbak_palette ((uint16*)(g_ram+0x1DD80))
+#define sprite_where_in_room ((uint16*)(g_ram+0x1DF80))
+#define overworld_sprite_was_loaded ((uint8*)(g_ram+0x1EF80))
+#define garnish_type ((uint8*)(g_ram+0x1F800))
+#define garnish_y_lo ((uint8*)(g_ram+0x1F81E))
+#define garnish_x_lo ((uint8*)(g_ram+0x1F83C))
+#define garnish_y_hi ((uint8*)(g_ram+0x1F85A))
+#define garnish_x_hi ((uint8*)(g_ram+0x1F878))
+#define garnish_y_vel ((uint8*)(g_ram+0x1F896))
+#define garnish_x_vel ((uint8*)(g_ram+0x1F8B4))
+#define garnish_y_subpixel ((uint8*)(g_ram+0x1F8D2))
+#define garnish_x_subpixel ((uint8*)(g_ram+0x1F8F0))
+#define garnish_countdown ((uint8*)(g_ram+0x1F90E))
+#define garnish_sprite ((uint8*)(g_ram+0x1F92C))
+#define garnish_anim_5 ((uint8*)(g_ram+0x1F94A))
+#define garnish_floor ((uint8*)(g_ram+0x1F968))
+#define sprite_I ((uint8*)(g_ram+0x1F9C2))
+#define garnish_oam_flags ((uint8*)(g_ram+0x1F9FE))
+#define sprite_unk3 ((uint8*)(g_ram+0x1FA1C))
+#define sprite_unk4 ((uint8*)(g_ram+0x1FA2C))
+#define sprite_unk5 ((uint8*)(g_ram+0x1FA3C))
+#define sprite_unk1 ((uint8*)(g_ram+0x1FA4C))
+#define swamola_x_lo ((uint8*)(g_ram+0x1FA5C))
+#define alt_sprite_C ((uint8*)(g_ram+0x1FA6C))
+#define alt_sprite_E ((uint8*)(g_ram+0x1FA7C))
+#define alt_sprite_subtype2 ((uint8*)(g_ram+0x1FA8C))
+#define alt_sprite_height_above_shadow ((uint8*)(g_ram+0x1FA9C))
+#define alt_sprite_delay_main ((uint8*)(g_ram+0x1FAAC))
+#define byte_7FFABC ((uint8*)(g_ram+0x1FABC))
+#define alt_sprite_I ((uint8*)(g_ram+0x1FACC))
+#define alt_sprite_maybe_ignore_projectile ((uint8*)(g_ram+0x1FADC))
+#define swamola_x_hi ((uint8*)(g_ram+0x1FB1C))
+#define swamola_y_lo ((uint8*)(g_ram+0x1FBDC))
+#define moldorm_x_lo ((uint8*)(g_ram+0x1FC00))
+#define moldorm_x_hi_ ((uint8*)(g_ram+0x1FC80))
+#define swamola_y_hi ((uint8*)(g_ram+0x1FC9C))
+#define moldorm_y_lo ((uint8*)(g_ram+0x1FD00))
+#define word_7FFD02 (*(uint16*)(g_ram+0x1FD02))
+#define swamola_target_x_lo ((uint8*)(g_ram+0x1FD5C))
+#define swamola_target_x_hi ((uint8*)(g_ram+0x1FD62))
+#define swamola_target_y_lo ((uint8*)(g_ram+0x1FD68))
+#define swamola_target_y_hi ((uint8*)(g_ram+0x1FD6E))
+#define beamos_x_lo ((uint8*)(g_ram+0x1FD80))
+#define beamos_x_hi ((uint8*)(g_ram+0x1FE00))
+#define beamos_y_lo ((uint8*)(g_ram+0x1FE80))
+#define beamos_y_hi ((uint8*)(g_ram+0x1FF00))
+
+#define attract_var12 (*(uint16*)(g_ram+0x20))
+#define attract_state (*(uint8*)(g_ram+0x22))
+#define attract_sequence (*(uint8*)(g_ram+0x23))
+#define attract_var10 (*(uint8*)(g_ram+0x25))
+#define attract_next_legend_gfx (*(uint8*)(g_ram+0x26))
+#define attract_legend_flag (*(uint8*)(g_ram+0x27))
+#define attract_x_base (*(uint8*)(g_ram+0x28))
+#define attract_y_base (*(uint8*)(g_ram+0x29))
+#define attract_oam_idx (*(uint8*)(g_ram+0x2A))
+#define attract_var9 (*(uint8*)(g_ram+0x2B))
+#define attract_var13 (*(uint8*)(g_ram+0x2C))
+#define attract_var7 (*(uint16*)(g_ram+0x2D))
+#define attract_vram_dst (*(uint16*)(g_ram+0x30))
+#define attract_var1 (*(uint8*)(g_ram+0x32))
+#define attract_var3 (*(uint8*)(g_ram+0x33))
+#define attract_var4 (*(uint8*)(g_ram+0x34))
+#define attract_x_base_hi (*(uint8*)(g_ram+0x40))
+#define attract_var17 (*(uint8*)(g_ram+0x50))
+#define attract_var21 (*(uint8*)(g_ram+0x51))
+#define attract_var15 (*(uint8*)(g_ram+0x52))
+#define attract_var22 (*(uint8*)(g_ram+0x5D))
+#define attract_var18 (*(uint8*)(g_ram+0x5F))
+#define attract_var5 (*(uint8*)(g_ram+0x60))
+#define attract_var11 (*(uint8*)(g_ram+0x61))
+#define attract_var19 (*(uint8*)(g_ram+0x62))
+#define attract_var20 (*(uint8*)(g_ram+0x63))
+#define selectfile_arr1 ((uint16*)(g_ram+0xBF))
+#define selectfile_arr2 ((uint8*)(g_ram+0xCA))
+#define selectfile_var6 (*(uint8*)(g_ram+0xCC))
+#define attract_room_index (*(uint8*)(g_ram+0x10E))
+#define attract_legend_ctr (*(uint16*)(g_ram+0x200))
+#define selectfile_var8 (*(uint16*)(g_ram+0x630))
+#define selectfile_var3 (*(uint8*)(g_ram+0xB10))
+#define selectfile_var7 (*(uint8*)(g_ram+0xB11))
+#define selectfile_var4 (*(uint8*)(g_ram+0xB12))
+#define selectfile_var9 (*(uint8*)(g_ram+0xB13))
+#define selectfile_var11 (*(uint8*)(g_ram+0xB14))
+#define selectfile_var5 (*(uint8*)(g_ram+0xB15))
+#define selectfile_var10 (*(uint8*)(g_ram+0xB16))
+#define selectfile_var2 (*(uint8*)(g_ram+0xB9D))
+
+#define blastwall_var5 ((uint8*)(g_ram+0x10000))
+#define blastwall_var6 ((uint8*)(g_ram+0x10008))
+#define blastwall_var1 (*(uint8*)(g_ram+0x10010))
+#define blastwall_var4 (*(uint8*)(g_ram+0x10011))
+#define blastwall_var8 (*(uint16*)(g_ram+0x10018))
+#define blastwall_var9 (*(uint16*)(g_ram+0x1001A))
+#define blastwall_var7 (*(uint8*)(g_ram+0x1001C))
+#define blastwall_var10 ((uint16*)(g_ram+0x10020))
+#define blastwall_var11 ((uint16*)(g_ram+0x10030))
+#define blastwall_var12 ((uint8*)(g_ram+0x10040))
+
+#define breaktowerseal_var3 ((uint8*)(g_ram+0x15800))
+#define breaktowerseal_var4 (*(uint8*)(g_ram+0x15808))
+#define breaktowerseal_x (*(uint16*)(g_ram+0x1580E))
+#define breaktowerseal_y (*(uint16*)(g_ram+0x15810))
+#define breaktowerseal_var5 (*(uint8*)(g_ram+0x15812))
+#define breaktowerseal_base_sparkle_y_lo ((uint8*)(g_ram+0x15817))
+#define breaktowerseal_base_sparkle_y_hi ((uint8*)(g_ram+0x1581F))
+#define breaktowerseal_base_sparkle_x_lo ((uint8*)(g_ram+0x15827))
+#define breaktowerseal_base_sparkle_x_hi ((uint8*)(g_ram+0x1582F))
+#define breaktowerseal_sparkle_var1 ((uint8*)(g_ram+0x15837))
+#define breaktowerseal_sparkle_y_lo ((uint8*)(g_ram+0x1584F))
+#define breaktowerseal_sparkle_y_hi ((uint8*)(g_ram+0x15867))
+#define breaktowerseal_sparkle_x_lo ((uint8*)(g_ram+0x1587F))
+#define breaktowerseal_sparkle_x_hi ((uint8*)(g_ram+0x15897))
+#define breaktowerseal_sparkle_var2 ((uint8*)(g_ram+0x158AF))
+
+#define happiness_pond_y_vel ((uint8*)(g_ram+0x15800))
+#define happiness_pond_x_vel ((uint8*)(g_ram+0x1580C))
+#define happiness_pond_z_vel ((uint8*)(g_ram+0x15818))
+#define happiness_pond_y_lo ((uint8*)(g_ram+0x15824))
+#define happiness_pond_y_hi ((uint8*)(g_ram+0x15830))
+#define happiness_pond_x_lo ((uint8*)(g_ram+0x1583C))
+#define happiness_pond_x_hi ((uint8*)(g_ram+0x15848))
+#define happiness_pond_z ((uint8*)(g_ram+0x15854))
+#define happiness_pond_timer ((uint8*)(g_ram+0x15860))
+#define happiness_pond_arr1 ((uint8*)(g_ram+0x1586C))
+#define happiness_pond_item_to_link ((uint8*)(g_ram+0x1587A))
+#define happiness_pond_y_subpixel ((uint8*)(g_ram+0x15886))
+#define happiness_pond_x_subpixel ((uint8*)(g_ram+0x15892))
+#define happiness_pond_z_subpixel ((uint8*)(g_ram+0x1589E))
+#define happiness_pond_step ((uint8*)(g_ram+0x158AA))
+
+#define skullwoodsfire_var0 ((uint8*)(g_ram+0x10000))
+#define skullwoodsfire_var5 ((uint8*)(g_ram+0x10008))
+#define skullwoodsfire_var4 (*(uint8*)(g_ram+0x10010))
+#define skullwoodsfire_var9 (*(uint16*)(g_ram+0x10018))
+#define skullwoodsfire_var11 (*(uint16*)(g_ram+0x1001A))
+#define skullwoodsfire_y_arr ((uint16*)(g_ram+0x10020))
+#define skullwoodsfire_var10 (*(uint16*)(g_ram+0x10026))
+#define skullwoodsfire_x_arr ((uint16*)(g_ram+0x10030))
+#define skullwoodsfire_var12 (*(uint16*)(g_ram+0x10036))
+
+#define weathervane_arr3 ((uint8*)(g_ram+0x15800))
+#define weathervane_arr4 ((uint8*)(g_ram+0x1580C))
+#define weathervane_arr5 ((uint8*)(g_ram+0x15818))
+#define weathervane_arr6 ((uint8*)(g_ram+0x15824))
+#define weathervane_arr7 ((uint8*)(g_ram+0x15830))
+#define weathervane_arr8 ((uint8*)(g_ram+0x1583C))
+#define weathervane_arr9 ((uint8*)(g_ram+0x15848))
+#define weathervane_arr10 ((uint8*)(g_ram+0x15854))
+#define weathervane_arr11 ((uint8*)(g_ram+0x15860))
+#define weathervane_arr12 ((uint8*)(g_ram+0x1586C))
+#define weathervane_var13 (*(uint8*)(g_ram+0x15878))
+#define weathervane_var14 (*(uint8*)(g_ram+0x15879))
+#define weathervane_var2 (*(uint16*)(g_ram+0x158B6))
+#define weathervane_var1 (*(uint8*)(g_ram+0x158B8))
+
+
+#define scratch_0 (*(uint16*)(g_ram+0x72))
+#define scratch_1 (*(uint16*)(g_ram+0x74))
+#define srm_var1 (*(uint16*)(g_zenv.sram+0x1ffe))
+#define messaging_buf ((uint16*)(g_ram+0x10000))
+#define quake_arr1 ((uint8*)(g_ram+0x15800))
+#define quake_arr2 ((uint8*)(g_ram+0x15805))
+#define quake_var5 (*(uint8*)(g_ram+0x1580A))
+#define quake_var1 (*(uint16*)(g_ram+0x1580B))
+#define quake_var2 (*(uint16*)(g_ram+0x1580D))
+#define quake_var4 (*(uint8*)(g_ram+0x1580F))
+#define ether_y3 (*(uint16*)(g_ram+0x15810))
+#define ether_var1 (*(uint8*)(g_ram+0x15812))
+#define ether_y (*(uint16*)(g_ram+0x15813))
+#define ether_x (*(uint16*)(g_ram+0x15815))
+#define quake_var3 (*(uint16*)(g_ram+0x1581E))
+#define bombos_arr7 ((uint8*)(g_ram+0x15820))
+#define bombos_y_lo ((uint8*)(g_ram+0x15824))
+#define bombos_y_hi ((uint8*)(g_ram+0x15864))
+#define bombos_x_lo ((uint8*)(g_ram+0x158A4))
+#define bombos_x_hi ((uint8*)(g_ram+0x158E4))
+#define bombos_y_coord2 ((uint16*)(g_ram+0x15924))
+#define bombos_x_coord2 ((uint16*)(g_ram+0x1592C))
+#define bombos_var4 (*(uint8*)(g_ram+0x15934))
+#define bombos_arr3 ((uint8*)(g_ram+0x15935))
+#define bombos_arr4 ((uint8*)(g_ram+0x15945))
+#define bombos_y_coord ((uint16*)(g_ram+0x15955))
+#define bombos_x_coord ((uint16*)(g_ram+0x159D5))
+#define bombos_var3 (*(uint8*)(g_ram+0x15A55))
+#define bombos_var2 (*(uint8*)(g_ram+0x15A56))
+#define bombos_var1 (*(uint8*)(g_ram+0x15A57))
+
+#define happiness_pond_y_vel ((uint8*)(g_ram+0x15800))
+#define happiness_pond_x_vel ((uint8*)(g_ram+0x1580C))
+#define happiness_pond_z_vel ((uint8*)(g_ram+0x15818))
+#define happiness_pond_y_lo ((uint8*)(g_ram+0x15824))
+#define happiness_pond_y_hi ((uint8*)(g_ram+0x15830))
+#define happiness_pond_x_lo ((uint8*)(g_ram+0x1583C))
+#define happiness_pond_x_hi ((uint8*)(g_ram+0x15848))
+#define happiness_pond_z ((uint8*)(g_ram+0x15854))
+#define happiness_pond_timer ((uint8*)(g_ram+0x15860))
+#define happiness_pond_arr1 ((uint8*)(g_ram+0x1586C))
+#define happiness_pond_item_to_link ((uint8*)(g_ram+0x1587A))
+#define happiness_pond_y_subpixel ((uint8*)(g_ram+0x15886))
+#define happiness_pond_x_subpixel ((uint8*)(g_ram+0x15892))
+#define happiness_pond_z_subpixel ((uint8*)(g_ram+0x1589E))
+#define happiness_pond_step ((uint8*)(g_ram+0x158AA))
+
+
+#define turn_on_off_water_ctr (*(uint8*)(g_ram+0x424))
+#define sprite_N_word ((uint16*)(g_ram+0xBC0))
+#define sprite_where_in_overworld ((uint8*)(g_ram+0x1DF80))
+#define alt_sprite_B ((uint8*)(g_ram+0x1FA5C))
+#define uvram_screen (*(UploadVram_32x32*)&g_ram[0x1000])
+#define vram_upload_offset (*(uint16*)(g_ram+0x1000))
+#define vram_upload_data ((uint16*)(g_ram+0x1002))
+#define vram_upload_tile_buf ((uint16*)(g_ram+0x1100))
+#define overworld_entrance_sequence_counter (*(uint8*)(g_ram+0xc8))
+
+#ifndef overworld_tileattr
+#define overworld_tileattr ((uint16*)(g_ram+0x2000))
+#endif
+#define dung_line_ptrs_row0 (*(uint16*)(g_ram+0xbf))
+#define star_shaped_switches_tile ((uint16*)(g_ram+0x6A0))
+#define dung_inter_starcases ((uint16*)(g_ram+0x6B0))
+#define dung_stairs_table_1 ((uint16*)(g_ram+0x6B8))
+#define selectfile_var8 (*(uint16*)(g_ram+0x630))
+
+#define R10 (*(uint16*)(g_ram+10))
+#define R12 (*(uint16*)(g_ram+12))
+#define R14 (*(uint16*)(g_ram+14))
+#define R16 (*(uint16*)(g_ram+0xc8))
+#define R18 (*(uint16*)(g_ram+0xca))
+#define R20 (*(uint16*)(g_ram+0xcc))
+
+// Relocated the hdma table so it can fit 240 rows
+#define hdma_table_dynamic_orig_pos ((uint16*)(g_ram+0x1B00))
+#define hdma_table_dynamic ((uint16*)(g_ram+0x1DBA0))
+
+// Allocate 64 bytes that we can use for msu resume.
+#define msu_resume_info ((uint8*)(g_ram+0x1DB60))
+
+#define msu_resume_info_alt ((uint8*)(g_ram+0x1DB20))
+
+
+typedef struct MovableBlockData {
+  uint16 room;
+  uint16 tilemap;
+} MovableBlockData;
+
+typedef struct OamEntSigned {
+  int8 x, y;
+  uint8 charnum, flags;
+} OamEntSigned;
+
+
+
+#define movable_block_datas ((MovableBlockData*)(g_ram+0xf940))
+#define oam_buf ((OamEnt*)(g_ram+0x800))
+
+
+typedef struct RoomBounds {
+  union {
+    struct { uint16 a0, b0, a1, b1; };
+    uint16 v[4];
+  };
+} RoomBounds;
+#define room_bounds_y (*(RoomBounds*)(g_ram+0x600))
+#define room_bounds_x (*(RoomBounds*)(g_ram+0x608))
+
+
+typedef struct OwScrollVars {
+  uint16 ystart, yend, xstart, xend;
+} OwScrollVars;
+
+
+#define ow_scroll_vars0 (*(OwScrollVars*)(g_ram+0x600))
+#define ow_scroll_vars1 (*(OwScrollVars*)(g_ram+0x608))
+
+#define ow_scroll_vars0_exit (*(OwScrollVars*)(g_ram+0xC154))
+
+extern const uint8 kLayoutQuadrantFlags[];
+extern const uint8 kVariousPacks[16];
+extern const uint8 kMaxBombsForLevel[];
+extern const uint8 kMaxArrowsForLevel[];
+extern const uint8 kReceiveItem_Tab1[76];
+extern const uint8 kHealthAfterDeath[21];
+extern const uint8 kReceiveItemGfx[76];
+extern const uint16 kOverworld_OffsetBaseY[64];
+extern const uint16 kOverworld_OffsetBaseX[64];
+
+// forwards
+
+
+typedef struct MirrorHdmaVars {
+  uint16 var0;
+  uint16 var1[2];
+  uint16 var3[2];
+  uint16 var5;
+  uint16 var6;
+  uint16 var7;
+  uint16 var8;
+  uint16 var9;
+  uint16 var10;
+  uint16 var11;
+  uint16 pad;
+  uint8 ctr2, ctr;
+} MirrorHdmaVars;
+#define mirror_vars (*(MirrorHdmaVars*)(g_ram+0x6A0))
+
+
+typedef struct UploadVram_Row {
+  uint16 col[32];
+} UploadVram_Row;
+
+typedef struct UploadVram_32x32 {
+  UploadVram_Row row[32];
+} UploadVram_32x32;
+
+typedef struct UploadVram_3 {
+  uint8 pad[256];
+  uint16 data[4];
+} UploadVram_3;
+
+#define uvram (*(UploadVram_3*)(&g_ram[0x1000]))
+
+extern uint8 g_ram[131072];
+extern const uint16 kUpperBitmasks[];
+extern const uint8 kLitTorchesColorPlus[];
+extern const uint8 kDungeonCrystalPendantBit[];
+extern const int8 kGetBestActionToPerformOnTile_x[];
+extern const int8 kGetBestActionToPerformOnTile_y[];
+
+
+#endif  // ZELDA3_VARIABLES_H_
\ No newline at end of file
--- /dev/null
+++ b/src/zelda_cpu_infra.c
@@ -1,0 +1,585 @@
+// This file handles running zelda through the emulated cpu.
+// It defines the runtime environment for the emulated side-by-side state.
+// It should be possible to build and run the game without this file
+#include "zelda_cpu_infra.h"
+#include "zelda_rtl.h"
+#include "variables.h"
+#include "spc_player.h"
+#include "snes/snes.h"
+#include "snes/snes_regs.h"
+#include "snes/cpu.h"
+#include "snes/cart.h"
+#include "snes/tracing.h"
+
+Snes *g_snes;
+Cpu *g_cpu;
+uint8 g_emulated_ram[0x20000];
+
+static void PatchRom(uint8 *rom);
+
+uint8 *GetPtr(uint32 addr) {
+  Cart *cart = g_snes->cart;
+  return &cart->rom[(((addr >> 16) << 15) | (addr & 0x7fff)) & (cart->romSize - 1)];
+}
+
+uint8 *GetCartRamPtr(uint32 addr) {
+  Cart *cart = g_snes->cart;
+  return &cart->ram[addr];
+}
+
+typedef struct Snapshot {
+  uint16 a, x, y, sp, dp, pc;
+  uint8 k, db, flags;
+  uint8 ram[0x20000];
+  uint16 vram[0x8000];
+  uint16 sram[0x2000];
+} Snapshot;
+
+static Snapshot g_snapshot_mine, g_snapshot_theirs, g_snapshot_before;
+
+static void MakeSnapshot(Snapshot *s) {
+  Cpu *c = g_cpu;
+  s->a = c->a, s->x = c->x, s->y = c->y;
+  s->sp = c->sp, s->dp = c->dp, s->db = c->db;
+  s->pc = c->pc, s->k = c->k;
+  s->flags = cpu_getFlags(c);
+  memcpy(s->ram, g_snes->ram, 0x20000);
+  memcpy(s->sram, g_snes->cart->ram, g_snes->cart->ramSize);
+  memcpy(s->vram, g_snes->ppu->vram, sizeof(uint16) * 0x8000);
+  memcpy(s->ram + 0x1DBA0, s->ram + 0x1B00, 224 * 2);  // hdma_table (partial)
+}
+
+static void MakeMySnapshot(Snapshot *s) {
+  memcpy(s->ram, g_zenv.ram, 0x20000);
+  memcpy(s->sram, g_zenv.sram, 0x2000);
+  memcpy(s->vram, g_zenv.ppu->vram, sizeof(uint16) * 0x8000);
+  memcpy(s->ram + 0x1B00, s->ram + 0x1DBA0, 224 * 2);  // hdma_table (partial)
+}
+
+static void RestoreMySnapshot(Snapshot *s) {
+  memcpy(g_zenv.ram, s->ram, 0x20000);
+  memcpy(g_zenv.sram, s->sram, 0x2000);
+  memcpy(g_zenv.ppu->vram, s->vram, sizeof(uint16) * 0x8000);
+}
+
+static void RestoreSnapshot(Snapshot *s) {
+  Cpu *c = g_cpu;
+
+  c->a = s->a, c->x = s->x, c->y = s->y;
+  c->sp = s->sp, c->dp = s->dp, c->db = s->db;
+  c->pc = s->pc, c->k = s->k;
+  cpu_setFlags(c, s->flags);
+  memcpy(g_snes->ram, s->ram, 0x20000);
+  memcpy(g_snes->cart->ram, s->sram, g_snes->cart->ramSize);
+  memcpy(g_snes->ppu->vram, s->vram, sizeof(uint16) * 0x8000);
+}
+
+static bool g_fail;
+
+// b is mine, a is theirs
+static void VerifySnapshotsEq(Snapshot *b, Snapshot *a, Snapshot *prev) {
+  memcpy(b->ram, a->ram, 16);
+  b->ram[0xfa1] = a->ram[0xfa1];
+  b->ram[0x72] = a->ram[0x72];
+  b->ram[0x73] = a->ram[0x73];
+  b->ram[0x74] = a->ram[0x74];
+  b->ram[0x75] = a->ram[0x75];
+  b->ram[0xb7] = a->ram[0xb7];
+  b->ram[0xb8] = a->ram[0xb8];
+  b->ram[0xb9] = a->ram[0xb9];
+  b->ram[0xba] = a->ram[0xba];
+  b->ram[0xbb] = a->ram[0xbb];
+  b->ram[0xbd] = a->ram[0xbd];
+  b->ram[0xbe] = a->ram[0xbe];
+  b->ram[0xc8] = a->ram[0xc8];
+  b->ram[0xc9] = a->ram[0xc9];
+  b->ram[0xca] = a->ram[0xca];
+  b->ram[0xcb] = a->ram[0xcb];
+  b->ram[0xcc] = a->ram[0xcc];
+  b->ram[0xcd] = a->ram[0xcd];
+  b->ram[0xa0] = a->ram[0xa0];
+  b->ram[0x128] = a->ram[0x128];  // irq_flag
+  b->ram[0x463] = a->ram[0x463];  // which_staircase_index_padding
+
+  // c code is authoritative
+  WORD(a->ram[0x1f0a]) = WORD(b->ram[0x1f0a]);
+
+  memcpy(&b->ram[0x1f0d], &a->ram[0x1f0d], 0x3f - 0xd);
+  memcpy(b->ram + 0x138, a->ram + 0x138, 256 - 0x38); // copy the stack over
+
+  memcpy(a->ram + 0x1cc0, b->ram + 0x1cc0, 2);  // some leftover stuff in hdma table
+  memcpy(a->ram + 0x1dd60, b->ram + 0x1dd60, 16 * 2);  // some leftover stuff in hdma table
+
+  memcpy(a->ram + 0x1db20, b->ram + 0x1db20, 64 * 2);  // msu
+  a->ram[0x654] = b->ram[0x654];  // msu_volume
+
+  memcpy(a->ram + 0x1CDD, b->ram + 0x1CDD, 2);  // dialogue_msg_src_offs
+  
+  if (memcmp(b->ram, a->ram, 0x20000)) {
+    fprintf(stderr, "@%d: Memory compare failed (mine != theirs, prev):\n", frame_counter);
+    int j = 0;
+    for (size_t i = 0; i < 0x20000; i++) {
+      if (a->ram[i] != b->ram[i]) {
+        if (++j < 128) {
+          if ((i&1) == 0 && a->ram[i + 1] != b->ram[i + 1]) {
+            fprintf(stderr, "0x%.6X: %.4X != %.4X (%.4X)\n", (int)i, 
+              WORD(b->ram[i]), WORD(a->ram[i]), WORD(prev->ram[i]));
+            i++, j++;
+          } else {
+            fprintf(stderr, "0x%.6X: %.2X != %.2X (%.2X)\n", (int)i, b->ram[i], a->ram[i], prev->ram[i]);
+          }
+        }
+      }
+    }
+    if (j)
+      g_fail = true;
+    fprintf(stderr, "  total of %d failed bytes\n", (int)j);
+  }
+
+  if (memcmp(b->sram, a->sram, 0x2000)) {
+    fprintf(stderr, "@%d: SRAM compare failed (mine != theirs, prev):\n", frame_counter);
+    int j = 0;
+    for (size_t i = 0; i < 0x2000; i++) {
+      if (a->sram[i] != b->sram[i]) {
+        if (++j < 128) {
+          if ((i&1) == 0 && a->sram[i + 1] != b->sram[i + 1]) {
+            fprintf(stderr, "0x%.6X: %.4X != %.4X (%.4X)\n", (int)i, 
+              WORD(b->sram[i]), WORD(a->sram[i]), WORD(prev->sram[i]));
+            i++, j++;
+          } else {
+            fprintf(stderr, "0x%.6X: %.2X != %.2X (%.2X)\n", (int)i, b->sram[i], a->sram[i], prev->sram[i]);
+          }
+        }
+      }
+    }
+    if (j)
+      g_fail = true;
+    fprintf(stderr, "  total of %d failed bytes\n", (int)j);
+  }
+
+  if (memcmp(b->vram, a->vram, sizeof(uint16) * 0x8000)) {
+    fprintf(stderr, "@%d: VRAM compare failed (mine != theirs, prev):\n", frame_counter);
+    for (size_t i = 0, j = 0; i < 0x8000; i++) {
+      if (a->vram[i] != b->vram[i]) {
+        fprintf(stderr, "0x%.6X: %.4X != %.4X (%.4X)\n", (int)i, b->vram[i], a->vram[i], prev->vram[i]);
+        g_fail = true;
+        if (++j >= 16)
+          break;
+      }
+    }
+  }
+}
+
+uint8_t *RomByte(Cart *cart, uint32_t addr) {
+  return &cart->rom[(((addr >> 16) << 15) | (addr & 0x7fff)) & (cart->romSize - 1)];
+}
+
+bool g_calling_asm_from_c;
+
+void HookedFunctionRts(int is_long) {
+  if (g_calling_asm_from_c) {
+    g_calling_asm_from_c = false;
+    return;
+  }
+  assert(0);
+}
+
+void RunEmulatedFunc(uint32 pc, uint16 a, uint16 x, uint16 y, bool mf, bool xf, int b, int whatflags) {
+  g_snes->debug_cycles = 1;
+  RunEmulatedFuncSilent(pc, a, x, y, mf, xf, b, whatflags | 2);
+  g_snes->debug_cycles = 0;
+}
+
+void RunEmulatedFuncSilent(uint32 pc, uint16 a, uint16 x, uint16 y, bool mf, bool xf, int b, int whatflags) {
+  uint16 org_sp = g_cpu->sp;
+  uint16 org_pc = g_cpu->pc;
+  uint8 org_b = g_cpu->db;
+  uint8 org_dp = g_cpu->dp;
+  if (b != -1)
+    g_cpu->db = b >= 0 ? b : pc >> 16;
+  if (b == -3)
+    g_cpu->dp = 0x1f00;
+
+  static uint8 *rambak;
+  if (rambak == 0) rambak = (uint8 *)malloc(0x20000);
+  memcpy(rambak, g_emulated_ram, 0x20000);
+  memcpy(g_emulated_ram, g_ram, 0x20000);
+
+  if (whatflags & 2)
+    g_emulated_ram[0x1ffff] = 0x67;
+
+  g_cpu->a = a;
+  g_cpu->x = x;
+  g_cpu->y = y;
+  g_cpu->spBreakpoint = g_cpu->sp;
+  g_cpu->k = (pc >> 16);
+  g_cpu->pc = (pc & 0xffff);
+  g_cpu->mf = mf;
+  g_cpu->xf = xf;
+  g_calling_asm_from_c = true;
+  while (g_calling_asm_from_c) {
+    if (g_snes->debug_cycles) {
+      char line[80];
+      getProcessorStateCpu(g_snes, line);
+      puts(line);
+    }
+    cpu_runOpcode(g_cpu);
+    while (g_snes->dma->dmaBusy)
+      dma_doDma(g_snes->dma);
+
+    if (whatflags & 1) {
+/*      if (apu_debugging == 2 && g_snes->apu->cpuCyclesLeft == 0) {
+        char line[80];
+        getProcessorStateSpc(g_snes->apu, line);
+        puts(line);
+      }*/
+//      apu_cycle(g_snes->apu);
+    }
+  }
+  g_cpu->dp = org_dp;
+  g_cpu->sp = org_sp;
+  g_cpu->db = org_b;
+  g_cpu->pc = org_pc;
+
+  memcpy(g_ram, g_emulated_ram, 0x20000);
+  memcpy(g_emulated_ram, rambak, 0x20000);
+}
+
+void RunOrigAsmCodeOneLoop(Snes *snes) {
+  Cpu *cpu = snes->cpu;
+  cpu->a = cpu->x = cpu->y = 0;
+  cpu->e = false;
+  cpu->irqWanted = cpu->nmiWanted = cpu->waiting = cpu->stopped = 0;
+  cpu_setFlags(cpu, 0x30);
+
+  // Run until the wait loop in Interrupt_Reset,
+  // Or the polyhedral main function.
+  for(int loops = 0;;loops++) {
+    snes_printCpuLine(snes);
+    cpu_runOpcode(snes->cpu);
+    while (snes->dma->dmaBusy)
+      dma_doDma(snes->dma);
+
+    uint32_t pc = snes->cpu->k << 16 | snes->cpu->pc;
+    if (pc == 0x8034 || pc == 0x9f81d && loops >= 10 || pc == 0x8225 || pc == 0x82D2)
+      break;
+  }
+}
+
+static void RunEmulatedSnesFrame(Snes *snes, int run_what) {
+  // First call runs until init
+  if (snes->cpu->pc == 0x8000 && snes->cpu->k == 0) {
+    RunOrigAsmCodeOneLoop(snes);
+    g_emulated_ram[0x12] = 1;
+    // Fixup uninitialized variable
+    *(uint16*)(g_emulated_ram+0xAE0) = 0xb280;
+    *(uint16*)(g_emulated_ram+0xAE2) = 0xb280 + 0x60;
+  }
+
+  // Run poly code
+  if (run_what & 2) {
+    Cpu *cpu = snes->cpu;
+    cpu->sp = 0x1f3e;
+    cpu->pc = 0xf81d;
+    cpu->db = cpu->k = 9;
+    cpu->dp = 0x1f00;
+    RunOrigAsmCodeOneLoop(snes);
+  }
+    
+  // Run main code
+  if (run_what & 1) {
+    Cpu *cpu = g_snes->cpu;
+    cpu->sp = 0x1ff;
+    cpu->pc = 0x8034;
+    cpu->k = cpu->dp = cpu->db = 0;
+    RunOrigAsmCodeOneLoop(snes);
+  }
+
+  snes_doAutoJoypad(snes);
+
+  // animated_tile_vram_addr uninited
+  if (snes->ram[0xadd] == 0)
+    *(uint16_t*)&snes->ram[0xadc] = 0xa680;
+
+  // In one code path flag_update_hud_in_nmi uses an undefined value
+  snes_write(snes, DMAP0, 0x01);
+  snes_write(snes, BBAD0, 0x18);
+
+  // Run NMI handler
+  Cpu *cpu = g_snes->cpu;
+  cpu->sp = 0x1ff;
+  cpu->pc = 0x80D9;
+  cpu->k = cpu->dp = cpu->db = 0;
+  RunOrigAsmCodeOneLoop(snes);
+}
+
+
+// Copy state into the emulator, we can skip dsp/apu because 
+// we're not emulating that.
+static void EmuSynchronizeWholeState() {
+  *g_snes->ppu = *g_zenv.ppu;
+  memcpy(g_snes->ram, g_zenv.ram, 0x20000);
+  memcpy(g_snes->cart->ram, g_zenv.sram, 0x2000);
+  memcpy(g_snes->dma->channel, g_zenv.dma->channel, sizeof(Dma) - offsetof(Dma, channel));
+
+  // todo: this is hacky
+  if (animated_tile_data_src == 0)
+    cpu_reset(g_snes->cpu);
+}
+
+void EmuRunFrameWithCompare(uint16 input_state, int run_what) {
+  MakeSnapshot(&g_snapshot_before);
+  MakeMySnapshot(&g_snapshot_mine);
+  MakeSnapshot(&g_snapshot_theirs);
+
+  // Compare both snapshots before we run the frame, to see they match
+  VerifySnapshotsEq(&g_snapshot_mine, &g_snapshot_theirs, &g_snapshot_before);
+  if (g_fail) {
+    printf("early fail\n");
+    assert(0);
+    //return turbo;
+  }
+
+  // Run orig version then snapshot
+again_theirs:
+  g_snes->input1->currentState = input_state;
+  RunEmulatedSnesFrame(g_snes, run_what);
+  MakeSnapshot(&g_snapshot_theirs);
+
+  // Run my version and snapshot
+again_mine:
+  ZeldaRunFrameInternal(input_state, run_what);
+
+  MakeMySnapshot(&g_snapshot_mine);
+
+  // Compare both snapshots
+  VerifySnapshotsEq(&g_snapshot_mine, &g_snapshot_theirs, &g_snapshot_before);
+
+  if (g_fail) {
+    g_fail = false;
+    if (1) {
+      RestoreMySnapshot(&g_snapshot_before);
+      //SaveLoadSlot(kSaveLoad_Save, 0);
+      if (0)
+        goto again_mine;
+      RestoreSnapshot(&g_snapshot_before);
+      goto again_theirs;
+    }
+    if (1) {
+      MakeSnapshot(&g_snapshot_theirs);
+      RestoreMySnapshot(&g_snapshot_theirs);
+    }
+  }
+}
+
+
+static void PatchRomBP(uint8_t *rom, uint32_t addr) {
+  rom[(addr >> 16) << 15 | (addr & 0x7fff)] = 0;
+}
+
+static void PatchRomByte(uint8_t *rom, uint32_t addr, uint8 old_value, uint8 value) {
+  assert(rom[(addr >> 16) << 15 | (addr & 0x7fff)] == old_value);
+  rom[(addr >> 16) << 15 | (addr & 0x7fff)] = value;
+}
+
+static void PatchRomWord(uint8_t *rom, uint32_t addr, uint16 old_value, uint16 value) {
+  assert(WORD(rom[(addr >> 16) << 15 | (addr & 0x7fff)]) == old_value);
+  WORD(rom[(addr >> 16) << 15 | (addr & 0x7fff)]) = value;
+}
+
+static void PatchRomArray(uint8_t *rom, uint32_t addr, const uint8 *values, int n) {
+  for (int i = 0; i < n; i++) {
+    rom[(addr >> 16) << 15 | (addr & 0x7fff)] = values[i];
+    addr += 1;
+  }
+}
+
+
+
+static void PatchRom(uint8_t *rom) {
+  //  fix a bug with unitialized memory
+  {
+    uint8_t *p = rom + 0x36434;
+    memmove(p, p + 2, 7);
+    p[7] = 0xb0;
+    p[8] = 0x40 - 7;
+  }
+
+  // BufferAndBuildMap16Stripes_Y can read bad memory if int is negative
+  if (1) {
+    uint8_t *p = rom + 0x10000 - 0x8000;
+    int thunk = 0xFF6E;
+    uint8_t *tp = p + thunk;
+
+    *tp++ = 0xc0; *tp++ = 0x00; *tp++ = 0x20;
+    *tp++ = 0x90; *tp++ = 0x03;
+    *tp++ = 0xa9; *tp++ = 0x00; *tp++ = 0x00;
+    *tp++ = 0x9d; *tp++ = 0x00; *tp++ = 0x05;
+    *tp++ = 0x60;
+
+    p[0xf4a7] = 0x20; p[0xf4a8] = thunk; p[0xf4a9] = thunk >> 8;
+    p[0xf4b5] = 0x20; p[0xf4b6] = thunk; p[0xf4b7] = thunk >> 8;
+
+    p[0xf3dd] = 0x20; p[0xf3de] = thunk; p[0xf3df] = thunk >> 8;
+    p[0xf3ef] = 0x20; p[0xf3f0] = thunk; p[0xf3f1] = thunk >> 8;
+  }
+
+  // Better random numbers
+  if (1) {
+    // 8D:FFC1                      new_random_gen:
+    int new_routine = 0xffc1;
+    uint8_t *p = rom + 0x60000, *tp = p + new_routine;
+
+    *tp++ = 0xad; *tp++ = 0xa1; *tp++ = 0x0f;  // mov.b   A, byte_7E0FA1
+    *tp++ = 0x18; *tp++ = 0x65; *tp++ = 0x1a;  // add.b   A, frame_counter
+    *tp++ = 0x4a;                              // lsr     A
+    *tp++ = 0xb0; *tp++ = 0x02;                // jnb     loc_8DFFCC
+    *tp++ = 0x49; *tp++ = 0xb8;                // eor.b   A, #0xB8
+    *tp++ = 0x8d; *tp++ = 0xa1; *tp++ = 0x0f;  // byte_7E0FA1, A
+    *tp++ = 0x18;                              // clc
+    *tp++ = 0x6b;                              // retf
+
+    p[0xBA71] = 0x4c; p[0xBA72] = new_routine; p[0xBA73] = new_routine >> 8;
+  }
+
+  {
+
+  }
+
+  // Fix so SmashRockPile_fromLift / Overworld_DoMapUpdate32x32_B preserves R2/R0 destroyed
+  {
+    /*
+    .9B:BFA2 A5 00                 mov.w   A, R0
+    .9B:BFA4 48                    push    A
+    .9B:BFA5 A5 02                 mov.w   A, R2
+    .9B:BFA7 48                    push    A
+    .9B:C0F1 22 5C AD 02           callf   Overworld_DoMapUpdate32x32_B
+    .9B:C048 68                    pop     A
+    .9B:C049 85 00                 mov.w   R0, A
+    .9B:C04B 68                    pop     A
+    .9B:C04C 85 02                 mov.w   R2, A
+    */
+    uint8_t *tp = rom + 0x6ffd8;
+    *tp++ = 0xa5; *tp++ = 0x00; *tp++ = 0x48;
+    *tp++ = 0xa5; *tp++ = 0x02; *tp++ = 0x48;
+    *tp++ = 0x22; *tp++ = 0x5c; *tp++ = 0xad; *tp++ = 0x02;
+    *tp++ = 0xc2; *tp++ = 0x30;
+    *tp++ = 0x68; *tp++ = 0x85; *tp++ = 0x02;
+    *tp++ = 0x68; *tp++ = 0x85; *tp++ = 0x00;
+    *tp++ = 0x6b;
+
+    int target = 0xDFFD8;  // DoorAnim_DoWork2_Preserving
+
+    rom[0xdc0f2] = target;
+    rom[0xdc0f3] = target >> 8;
+    rom[0xdc0f4] = target >> 16;
+  }
+
+  rom[0x2dec7] = 0;  // Fix Uncle_Embark reading bad ram
+
+  rom[0x4be5e] = 0;  // Overlord05_FallingStalfos doesn't initialize the sprite_D memory location
+
+  rom[0xD79A4] = 0;  // 0x1AF9A4: // Lanmola_SpawnShrapnel uses undefined carry value
+
+  rom[0xF0A46] = 0;  // 0x1E8A46 Helmasaur Carry Junk
+  rom[0xF0A52] = 0;  // 0x1E8A52 Helmasaur Carry Junk
+
+  rom[0xef9b9] = 0xb9; // TalkingTree_SpitBomb
+
+  rom[0xdf107] = 0xa2;
+  rom[0xdf108] = 0x03;
+  rom[0xdf109] = 0x6b;  // Palette_AgahnimClone destoys X
+
+
+  rom[0x4a966] = 0;  // Follower_AnimateMovement_preserved
+
+  PatchRomBP(rom, 0x1de0e5);
+  PatchRomBP(rom, 0x6d0b6);
+  PatchRomBP(rom, 0x6d0c6);
+
+  PatchRomBP(rom, 0x1d8f29); // adc instead of add
+  PatchRomBP(rom, 0x1DDBD3); // adc instead of add
+  PatchRomBP(rom, 0x1DF856); // adc instead of add
+  PatchRomBP(rom, 0x1E88DA); // adc instead of add
+
+  PatchRomBP(rom, 0x06ED0B);
+
+  PatchRomBP(rom, 0x1dc812); // adc instead of add
+
+  PatchRomBP(rom, 0x9b46c); // adc instead of add
+  PatchRomBP(rom, 0x9b478); // adc instead of add
+
+  PatchRomBP(rom, 0x9B468);  // sbc
+  PatchRomBP(rom, 0x9B46A);
+  PatchRomBP(rom, 0x9B474);
+  PatchRomBP(rom, 0x9B476);
+  PatchRomBP(rom, 0x9B60C);
+
+  PatchRomBP(rom, 0x8f708); // don't init scratch_c
+
+  PatchRomBP(rom, 0x1DCDEB); // y is destroyed earlier, restore it..
+
+  PatchRomBP(rom, 0x7B269);  // Link_APress_LiftCarryThrow oob
+
+  // Smithy_Frog doesn't save X
+  memmove(rom + 0x332b8, rom + 0x332b7, 4); rom[0x332b7] = 0xfa;
+
+  // This needs to be here because the ancilla code reads
+  // from the apu and we don't want to make the core code
+  // dependent on the apu timings, so relocated this value
+  // to 0x648.
+  rom[0x443fe] = 0x48; rom[0x443ff] = 0x6;
+  rom[0x44607] = 0x48; rom[0x44608] = 0x6;
+
+  // AncillaAdd_AddAncilla_Bank09 destroys R14
+  rom[0x49d0c] = 0xda; rom[0x49d0d] = 0xfa; 
+  rom[0x49d0f] = 0xda; rom[0x49d10] = 0xfa; 
+
+  // Prevent LoadSongBank from executing in the rom because it hangs
+  rom[0x888] = 0x60;
+
+  // CleanUpAndPrepDesertPrayerHDMA clearing too much
+  PatchRomWord(rom, 0x2C7E5 + 1, 0x1df, 0x1cf);
+
+  // Merge ancilla_arr23 with boomerang_arr1 because they're only 3 bytes long,
+  // and boomerang might get allocated in slot 4.
+  PatchRomByte(rom, 0x9816C, 0xd2, 0xCF);
+  PatchRomByte(rom, 0xffdeb, 0xd2, 0xCF);
+  PatchRomByte(rom, 0xffdee, 0xd2, 0xCF);
+  PatchRomByte(rom, 0xffdf7, 0xd2, 0xCF);
+  PatchRomByte(rom, 0xffdfa, 0xd2, 0xCF);
+
+  // Relocate the door debris variables so they become 5 entries each (they were 2 before).
+  static const int kDoorDebrisX_Uses[] = {0x1CFC6, 0x1d29d, 0x89794, 0x897a3, 0x8a0a1, 0x8edca, 0x99aa6};
+  for (int i = 0; i < countof(kDoorDebrisX_Uses); i++) PatchRomWord(rom, kDoorDebrisX_Uses[i] + 1, 0x3b6, 0x728);
+  static const int kDoorDebrisX1_Uses[] = { 0x89797, 0x897A6 };
+  for (int i = 0; i < countof(kDoorDebrisX1_Uses); i++) PatchRomWord(rom, kDoorDebrisX1_Uses[i] + 1, 0x3b7, 0x729);
+  static const int kDoorDebrisY_Uses[] = { 0x1CFD7, 0x1D2AE, 0x8A099, 0x8EDC5, 0x99AA1 };
+  for (int i = 0; i < countof(kDoorDebrisY_Uses); i++) PatchRomWord(rom, kDoorDebrisY_Uses[i] + 1, 0x3ba, 0x732);
+  static const int kDoorDebrisDir_Uses[] = { 0x1CFB2, 0x1D2BA, 0x8A0B7 };
+  for (int i = 0; i < countof(kDoorDebrisDir_Uses); i++) PatchRomWord(rom, kDoorDebrisDir_Uses[i] + 1, 0x3be, 0x73c);
+  static const int ancilla_arr26_Uses[] = { 0x89fb9, 0x89fc0, 0x98157, 0x99c49 };
+  for (int i = 0; i < countof(ancilla_arr26_Uses); i++) PatchRomWord(rom, ancilla_arr26_Uses[i] + 1, 0x3c0, 0x741);
+  static const int ancilla_arr25_Uses[] = { 0x89fc3, 0x89fc6, 0x8a0ae, 0x8ab7c, 0x8aba7, 0x8abb6, 0x8ae92, 0x8bae2, 0x8baff, 0x8f429, 0x98148, 0x98e0a, 0x98ebc, 0x9920a, 0x9931e, 0x9987f, 0x99c44 };
+  for (int i = 0; i < countof(ancilla_arr25_Uses); i++) PatchRomWord(rom, ancilla_arr25_Uses[i] + 1, 0x3c2, 0x746);
+  static const int ancilla_arr22_Uses[] = { 0x9816e, 0xffde0, 0xffde7 };
+  for (int i = 0; i < countof(ancilla_arr22_Uses); i++) PatchRomWord(rom, ancilla_arr22_Uses[i] + 1, 0x3e1, 0x74b);
+
+  PatchRomWord(rom, 0xddfac + 1, 0xfa85, 0xfa70); // call Hud_Rebuild instead of Hud_UpdateOnly
+
+  // Make sure it's not calling Decomp_spr on tilesheets less than 12
+  PatchRomWord(rom, 0xe589, 0xe772, 0xe852);  // call New addr
+  static const uint8 kFixSoItWontDecodeSheetLessThan12[] = { 0xc0, 0x0c, 0xb0, 0x02, 0xa0, 0x0c, 0x4c, 0x72, 0xe7 };
+  PatchRomArray(rom, 0xe852, kFixSoItWontDecodeSheetLessThan12, sizeof(kFixSoItWontDecodeSheetLessThan12));
+}
+
+
+
+bool EmuInitialize(uint8 *data, size_t size) {
+  PatchRom(data);
+  g_snes = snes_init(g_emulated_ram);
+  g_cpu = g_snes->cpu;
+
+  ZeldaSetupEmuCallbacks(g_emulated_ram, &EmuRunFrameWithCompare, &EmuSynchronizeWholeState);
+  return snes_loadRom(g_snes, data, (int)size);
+}
--- /dev/null
+++ b/src/zelda_cpu_infra.h
@@ -1,0 +1,14 @@
+#ifndef ZELDA3_ZELDA_CPU_INFRA_H_
+#define ZELDA3_ZELDA_CPU_INFRA_H_
+#include "types.h"
+
+extern uint8 g_emulated_ram[0x20000];
+
+uint8 *GetPtr(uint32 addr);
+
+void RunEmulatedFuncSilent(uint32 pc, uint16 a, uint16 x, uint16 y, bool mf, bool xf, int b, int whatflags);
+void RunEmulatedFunc(uint32 pc, uint16 a, uint16 x, uint16 y, bool mf, bool xf, int b, int whatflags);
+
+bool EmuInitialize(uint8 *data, size_t size);
+
+#endif  // ZELDA3_ZELDA_CPU_INFRA_H_
--- /dev/null
+++ b/src/zelda_rtl.c
@@ -1,0 +1,890 @@
+#include "zelda_rtl.h"
+#include "variables.h"
+#include "misc.h"
+#include "nmi.h"
+#include "poly.h"
+#include "attract.h"
+#include "snes/ppu.h"
+#include "snes/snes_regs.h"
+#include "snes/dma.h"
+#include "spc_player.h"
+#include "util.h"
+#include "audio.h"
+#include "assets.h"
+ZeldaEnv g_zenv;
+uint8 g_ram[131072];
+
+uint32 g_wanted_zelda_features;
+
+static void Startup_InitializeMemory();
+
+typedef struct SimpleHdma {
+  const uint8 *table;
+  const uint8 *indir_ptr;
+  uint8 rep_count;
+  uint8 mode;
+  uint8 ppu_addr;
+  uint8 indir_bank;
+} SimpleHdma;
+static void SimpleHdma_Init(SimpleHdma *c, DmaChannel *dc);
+static void SimpleHdma_DoLine(SimpleHdma *c);
+
+static const uint8 bAdrOffsets[8][4] = {
+  {0, 0, 0, 0},
+  {0, 1, 0, 1},
+  {0, 0, 0, 0},
+  {0, 0, 1, 1},
+  {0, 1, 2, 3},
+  {0, 1, 0, 1},
+  {0, 0, 0, 0},
+  {0, 0, 1, 1}
+};
+static const uint8 transferLength[8] = {
+  1, 2, 2, 4, 4, 4, 2, 4
+};
+const uint16 kUpperBitmasks[] = { 0x8000, 0x4000, 0x2000, 0x1000, 0x800, 0x400, 0x200, 0x100, 0x80, 0x40, 0x20, 0x10, 8, 4, 2, 1 };
+const uint8 kLitTorchesColorPlus[] = {31, 8, 4, 0};
+const uint8 kDungeonCrystalPendantBit[13] = {0, 0, 4, 2, 0, 16, 2, 1, 64, 4, 1, 32, 8};
+const int8 kGetBestActionToPerformOnTile_x[4] = { 7, 7, -3, 16 };
+const int8 kGetBestActionToPerformOnTile_y[4] = { 6, 24, 12, 12 };
+#define AT_WORD(x) (uint8)(x), (x)>>8
+// direct
+static const uint8 kAttractDmaTable0[13] = {0x20, AT_WORD(0x00ff), 0x50, AT_WORD(0xe018), 0x50, AT_WORD(0xe018), 1, AT_WORD(0x00ff), 0};
+static const uint8 kAttractDmaTable1[10] = {0x48, AT_WORD(0x00ff), 0x30, AT_WORD(0xd830), 1, AT_WORD(0x00ff), 0};
+static const uint8 kHdmaTableForEnding[19] = {
+  0x52, AT_WORD(0x600), 8, AT_WORD(0xe2), 8, AT_WORD(0x602), 5, AT_WORD(0x604), 0x10, AT_WORD(0x606), 0x81, AT_WORD(0xe2), 0,
+};
+static const uint8 kSpotlightIndirectHdma[7] = {0xf8, AT_WORD(0x1b00), 0xf8, AT_WORD(0x1bf0), 0};
+static const uint8 kMapModeHdma0[7] = {0xf0, AT_WORD(0xdd27), 0xf0, AT_WORD(0xde07), 0};
+static const uint8 kMapModeHdma1[7] = {0xf0, AT_WORD(0xdee7), 0xf0, AT_WORD(0xdfc7), 0};
+static const uint8 kAttractIndirectHdmaTab[7] = {0xf0, AT_WORD(0x1b00), 0xf0, AT_WORD(0x1be0), 0};
+static const uint8 kHdmaTableForPrayingScene[7] = {0xf8, AT_WORD(0x1b00), 0xf8, AT_WORD(0x1bf0), 0};
+
+void zelda_ppu_write(uint32_t adr, uint8_t val) {
+  assert(adr >= INIDISP && adr <= STAT78);
+  ppu_write(g_zenv.ppu, (uint8)adr, val);
+}
+
+void zelda_ppu_write_word(uint32_t adr, uint16_t val) {
+  zelda_ppu_write(adr, val);
+  zelda_ppu_write(adr + 1, val >> 8);
+}
+
+static const uint8 *SimpleHdma_GetPtr(uint32 p) {
+  switch (p) {
+
+  case 0xCFA87: return kAttractDmaTable0;
+  case 0xCFA94: return kAttractDmaTable1;
+  case 0xebd53: return kHdmaTableForEnding;
+  case 0x0F2FB: return kSpotlightIndirectHdma;
+  case 0xabdcf: return kMapModeHdma0;             // mode7
+  case 0xabdd6: return kMapModeHdma1;             // mode7
+  case 0xABDDD: return kAttractIndirectHdmaTab;   // mode7
+  case 0x2c80c: return kHdmaTableForPrayingScene;
+
+  case 0x1b00: return (uint8 *)hdma_table_dynamic;
+  case 0x1be0: return (uint8 *)hdma_table_dynamic + 0xe0;
+  case 0x1bf0: return (uint8 *)hdma_table_dynamic + 0xf0;
+  case 0xadd27: return (uint8*)kMapMode_Zooms1;
+  case 0xade07: return (uint8*)kMapMode_Zooms1 + 0xe0;
+  case 0xadee7: return (uint8*)kMapMode_Zooms2;
+  case 0xadfc7: return (uint8*)kMapMode_Zooms2 + 0xe0;
+  case 0x600: return &g_ram[0x600];
+  case 0x602: return &g_ram[0x602];
+  case 0x604: return &g_ram[0x604];
+  case 0x606: return &g_ram[0x606];
+  case 0xe2: return &g_ram[0xe2];
+  default:
+    assert(0);
+    return NULL;
+  }
+}
+
+static void SimpleHdma_Init(SimpleHdma *c, DmaChannel *dc) {
+  if (!dc->hdmaActive) {
+    c->table = 0;
+    return;
+  }
+  c->table = SimpleHdma_GetPtr(dc->aAdr | dc->aBank << 16);
+  c->rep_count = 0;
+  c->mode = dc->mode | dc->indirect << 6;
+  c->ppu_addr = dc->bAdr;
+  c->indir_bank = dc->indBank;
+}
+
+static void SimpleHdma_DoLine(SimpleHdma *c) {
+  if (c->table == NULL)
+    return;
+  bool do_transfer = false;
+  if ((c->rep_count & 0x7f) == 0) {
+    c->rep_count = *c->table++;
+    if (c->rep_count == 0) {
+      c->table = NULL;
+      return;
+    }
+    if(c->mode & 0x40) {
+      c->indir_ptr = SimpleHdma_GetPtr(c->indir_bank << 16 | c->table[0] | c->table[1] * 256);
+      c->table += 2;
+    }
+    do_transfer = true;
+  }
+  if(do_transfer || c->rep_count & 0x80) {
+    for(int j = 0, j_end = transferLength[c->mode & 7]; j < j_end; j++) {
+      uint8 v = c->mode & 0x40 ? *c->indir_ptr++ : *c->table++;
+      zelda_ppu_write(0x2100 + c->ppu_addr + bAdrOffsets[c->mode & 7][j], v);
+    }
+  }
+  c->rep_count--;
+}
+
+static void ConfigurePpuSideSpace() {
+  // Let PPU impl know about the maximum allowed extra space on the sides and bottom
+  int extra_right = 0, extra_left = 0, extra_bottom = 0;
+//  printf("main %d, sub %d  (%d, %d, %d)\n", main_module_index, submodule_index, BG2HOFS_copy2, room_bounds_x.v[2 | (quadrant_fullsize_x >> 1)], quadrant_fullsize_x >> 1);
+  int mod = main_module_index;
+  if (mod == 14)
+    mod = saved_module_for_menu;
+  if (mod == 9) {
+    if (main_module_index == 14 && submodule_index == 7 && overworld_map_state >= 4) {
+      // World map
+      extra_left = kPpuExtraLeftRight, extra_right = kPpuExtraLeftRight;
+      extra_bottom = 16;
+    } else {
+      // outdoors
+      extra_left = BG2HOFS_copy2 - ow_scroll_vars0.xstart;
+      extra_right = ow_scroll_vars0.xend - BG2HOFS_copy2;
+      extra_bottom = ow_scroll_vars0.yend - BG2VOFS_copy2;
+    }
+  } else if (mod == 7) {
+    // indoors, except when the light cone is in use
+    if (!(hdr_dungeon_dark_with_lantern && TS_copy != 0)) {
+      int qm = quadrant_fullsize_x >> 1;
+      extra_left = IntMax(BG2HOFS_copy2 - room_bounds_x.v[qm], 0);
+      extra_right = IntMax(room_bounds_x.v[qm + 2] - BG2HOFS_copy2, 0);
+    }
+
+    int qy = quadrant_fullsize_y >> 1;
+    extra_bottom = IntMax(room_bounds_y.v[qy + 2] - BG2VOFS_copy2, 0);
+  } else if (mod == 20 || mod == 0 || mod == 1) {
+    extra_left = kPpuExtraLeftRight, extra_right = kPpuExtraLeftRight;
+    extra_bottom = 16;
+  }
+  PpuSetExtraSideSpace(g_zenv.ppu, extra_left, extra_right, extra_bottom);
+}
+
+void ZeldaDrawPpuFrame(uint8 *pixel_buffer, size_t pitch, uint32 render_flags) {
+  SimpleHdma hdma_chans[2];
+
+  PpuBeginDrawing(g_zenv.ppu, pixel_buffer, pitch, render_flags);
+
+  dma_startDma(g_zenv.dma, HDMAEN_copy, true);
+
+  SimpleHdma_Init(&hdma_chans[0], &g_zenv.dma->channel[6]);
+  SimpleHdma_Init(&hdma_chans[1], &g_zenv.dma->channel[7]);
+
+  // Cheat: Let the PPU impl know about the hdma perspective correction so it can avoid guessing.
+  if ((render_flags & kPpuRenderFlags_4x4Mode7) && g_zenv.ppu->mode == 7) {
+    if (hdma_chans[0].table == kMapModeHdma0)
+      PpuSetMode7PerspectiveCorrection(g_zenv.ppu, kMapMode_Zooms1[0], kMapMode_Zooms1[223]);
+    else if (hdma_chans[0].table == kMapModeHdma1)
+      PpuSetMode7PerspectiveCorrection(g_zenv.ppu, kMapMode_Zooms2[0], kMapMode_Zooms2[223]);
+    else if (hdma_chans[0].table == kAttractIndirectHdmaTab)
+      PpuSetMode7PerspectiveCorrection(g_zenv.ppu, hdma_table_dynamic[0], hdma_table_dynamic[223]);
+    else
+      PpuSetMode7PerspectiveCorrection(g_zenv.ppu, 0, 0);
+  }
+
+  if (g_zenv.ppu->extraLeftRight != 0 || render_flags & kPpuRenderFlags_Height240)
+    ConfigurePpuSideSpace();
+
+  int height = render_flags & kPpuRenderFlags_Height240 ? 240 : 224;
+
+  for (int i = 0; i <= height; i++) {
+    if (i == 128 && irq_flag) {
+      zelda_ppu_write(BG3HOFS, selectfile_var8);
+      zelda_ppu_write(BG3HOFS, selectfile_var8 >> 8);
+      zelda_ppu_write(BG3VOFS, 0);
+      zelda_ppu_write(BG3VOFS, 0);
+      if (irq_flag & 0x80) {
+        irq_flag = 0;
+        zelda_snes_dummy_write(NMITIMEN, 0x81);
+      }
+    }
+    ppu_runLine(g_zenv.ppu, i);
+    SimpleHdma_DoLine(&hdma_chans[0]);
+    SimpleHdma_DoLine(&hdma_chans[1]);
+  }
+}
+
+void HdmaSetup(uint32 addr6, uint32 addr7, uint8 transfer_unit, uint8 reg6, uint8 reg7, uint8 indirect_bank) {
+  Dma *dma = g_zenv.dma;
+  if (addr6) {
+    dma_write(dma, DMAP6, transfer_unit);
+    dma_write(dma, BBAD6, reg6);
+    dma_write(dma, A1T6L, addr6);
+    dma_write(dma, A1T6H, addr6 >> 8);
+    dma_write(dma, A1B6, addr6 >> 16);
+    dma_write(dma, DAS60, indirect_bank);
+  }
+  dma_write(dma, DMAP7, transfer_unit);
+  dma_write(dma, BBAD7, reg7);
+  dma_write(dma, A1T7L, addr7);
+  dma_write(dma, A1T7H, addr7 >> 8);
+  dma_write(dma, A1B7, addr7 >> 16);
+  dma_write(dma, DAS70, indirect_bank);
+}
+
+static void ZeldaInitializationCode() {
+  zelda_snes_dummy_write(NMITIMEN, 0);
+  zelda_snes_dummy_write(HDMAEN, 0);
+  zelda_snes_dummy_write(MDMAEN, 0);
+
+  Sound_LoadIntroSongBank();
+
+  Startup_InitializeMemory();
+
+  animated_tile_data_src = 0xa680;
+  dma_source_addr_9 = 0xb280;
+  dma_source_addr_14 = 0xb280 + 0x60;
+  zelda_snes_dummy_write(NMITIMEN, 0x81);
+}
+
+static void ClearOamBuffer() {  // 80841e
+  for (int i = 0; i < 128; i++)
+    oam_buf[i].y = 0xf0;
+}
+
+static void ZeldaRunGameLoop() {
+  frame_counter++;
+  ClearOamBuffer();
+  Module_MainRouting();
+  NMI_PrepareSprites();
+  nmi_boolean = 0;
+}
+
+void ZeldaInitialize() {
+  g_zenv.dma = dma_init(NULL);
+  g_zenv.ppu = ppu_init(NULL);
+  g_zenv.ram = g_ram;
+  g_zenv.sram = (uint8*)calloc(8192, 1);
+  g_zenv.vram = g_zenv.ppu->vram;
+  g_zenv.player = SpcPlayer_Create();
+  SpcPlayer_Initialize(g_zenv.player);
+  dma_reset(g_zenv.dma);
+  ppu_reset(g_zenv.ppu);
+}
+
+static void ZeldaRunPolyLoop() {
+  if (intro_did_run_step && !nmi_flag_update_polyhedral) {
+    Poly_RunFrame();
+    intro_did_run_step = 0;
+    nmi_flag_update_polyhedral = 0xff;
+  }
+}
+
+void ZeldaRunFrameInternal(uint16 input, int run_what) {
+  if (animated_tile_data_src == 0)
+    ZeldaInitializationCode();
+
+  if (run_what & 2)
+    ZeldaRunPolyLoop();
+  if (run_what & 1)
+    ZeldaRunGameLoop();
+  Interrupt_NMI(input);
+}
+
+
+static int IncrementCrystalCountdown(uint8 *a, int v) {
+  int t = *a + v;
+  *a = t;
+  return t >> 8;
+}
+
+int frame_ctr_dbg;
+static uint8 *g_emu_memory_ptr;
+static ZeldaRunFrameFunc *g_emu_runframe;
+static ZeldaSyncAllFunc *g_emu_syncall;
+
+void ZeldaSetupEmuCallbacks(uint8 *emu_ram, ZeldaRunFrameFunc *func, ZeldaSyncAllFunc *sync_all) {
+  g_emu_memory_ptr = emu_ram;
+  g_emu_runframe = func;
+  g_emu_syncall = sync_all;
+}
+
+static void EmuSynchronizeWholeState() {
+  if (g_emu_syncall)
+    g_emu_syncall();
+}
+
+// |ptr| must be a pointer into g_ram, will synchronize the RAM memory with the
+// emulator.
+static void EmuSyncMemoryRegion(void *ptr, size_t n) {
+  uint8 *data = (uint8 *)ptr;
+  assert(data >= g_ram && data < g_ram + 0x20000);
+  if (g_emu_memory_ptr)
+    memcpy(g_emu_memory_ptr + (data - g_ram), data, n);
+}
+
+static void Startup_InitializeMemory() {  // 8087c0
+  memset(g_ram + 0x0, 0, 0x2000);
+  main_palette_buffer[0] = 0;
+  srm_var1 = 0;
+  uint8 *sram = g_zenv.sram;
+  if (WORD(sram[0x3e5]) != 0x55aa)
+    WORD(sram[0x3e5]) = 0;
+  if (WORD(sram[0x8e5]) != 0x55aa)
+    WORD(sram[0x8e5]) = 0;
+  if (WORD(sram[0xde5]) != 0x55aa)
+    WORD(sram[0xde5]) = 0;
+  INIDISP_copy = 0x80;
+  flag_update_cgram_in_nmi++;
+}
+
+void ByteArray_AppendVl(ByteArray *arr, uint32 v) {
+  for (; v >= 255; v -= 255)
+    ByteArray_AppendByte(arr, 255);
+  ByteArray_AppendByte(arr, v);
+}
+
+void saveFunc(void *ctx_in, void *data, size_t data_size) {
+  ByteArray_AppendData((ByteArray *)ctx_in, data, data_size);
+}
+
+typedef struct LoadFuncState {
+  uint8 *p, *pend;
+} LoadFuncState;
+
+void loadFunc(void *ctx, void *data, size_t data_size) {
+  LoadFuncState *st = (LoadFuncState *)ctx;
+  assert(st->pend - st->p >= data_size);
+  memcpy(data, st->p, data_size);
+  st->p += data_size;
+}
+
+static void InternalSaveLoad(SaveLoadFunc *func, void *ctx) {
+  uint8 junk[58] = { 0 };
+  func(ctx, junk, 27);
+  func(ctx, g_zenv.player->ram, 0x10000);  // apu ram
+  func(ctx, junk, 40); // junk
+  dsp_saveload(g_zenv.player->dsp, func, ctx); // 3024 bytes of dsp
+  func(ctx, junk, 15); // spc junk
+  dma_saveload(g_zenv.dma, func, ctx); // 192 bytes of dma state
+  ppu_saveload(g_zenv.ppu, func, ctx); // 66619 + 512 + 174
+  func(ctx, g_zenv.sram, 0x2000);  // 8192 bytes of sram
+  func(ctx, junk, 58); // snes junk
+  func(ctx, g_zenv.ram, 0x20000);  // 0x20000 bytes of ram
+  func(ctx, junk, 4); // snes junk
+}
+
+void ZeldaReset(bool preserve_sram) {
+  frame_ctr_dbg = 0;
+  dma_reset(g_zenv.dma);
+  ppu_reset(g_zenv.ppu);
+  memset(g_zenv.ram, 0, 0x20000);
+  if (!preserve_sram)
+    memset(g_zenv.sram, 0, 0x2000);
+  ZeldaApuLock();
+  ZeldaRestoreMusicAfterLoad_Locked(true);
+  ZeldaApuUnlock();
+  EmuSynchronizeWholeState();
+
+}
+
+static void LoadSnesState(SaveLoadFunc *func, void *ctx) {
+  // Do the actual loading
+  ZeldaApuLock();
+  InternalSaveLoad(func, ctx);
+  memcpy(g_zenv.ram + 0x1DBA0, g_zenv.ram + 0x1b00, 224 * 2); // hdma table was moved
+
+  ZeldaRestoreMusicAfterLoad_Locked(false);
+  ZeldaApuUnlock();
+  EmuSynchronizeWholeState();
+}
+
+static void SaveSnesState(SaveLoadFunc *func, void *ctx) {
+  memcpy(g_zenv.ram + 0x1b00, g_zenv.ram + 0x1DBA0, 224 * 2); // hdma table was moved
+  ZeldaApuLock();
+  ZeldaSaveMusicStateToRam_Locked();
+  InternalSaveLoad(func, ctx);
+  ZeldaApuUnlock();
+}
+
+typedef struct StateRecorder {
+  uint16 last_inputs;
+  uint32 frames_since_last;
+  uint32 total_frames;
+
+  // For replay
+  uint32 replay_pos, replay_pos_last_complete;
+  uint32 replay_frame_counter;
+  uint32 replay_next_cmd_at;
+  uint8 replay_cmd;
+  bool replay_mode;
+
+  ByteArray log;
+  ByteArray base_snapshot;
+} StateRecorder;
+
+static StateRecorder state_recorder;
+
+void StateRecorder_Init(StateRecorder *sr) {
+  memset(sr, 0, sizeof(*sr));
+}
+
+void StateRecorder_RecordCmd(StateRecorder *sr, uint8 cmd) {
+  int frames = sr->frames_since_last;
+  sr->frames_since_last = 0;
+  int x = (cmd < 0xc0) ? 0xf : 0x1;
+  ByteArray_AppendByte(&sr->log, cmd | (frames < x ? frames : x));
+  if (frames >= x)
+    ByteArray_AppendVl(&sr->log, frames - x);
+}
+
+void StateRecorder_Record(StateRecorder *sr, uint16 inputs) {
+  uint16 diff = inputs ^ sr->last_inputs;
+  if (diff != 0) {
+    sr->last_inputs = inputs;
+    //    printf("0x%.4x %d: ", diff, sr->frames_since_last);
+    //    size_t lb = sr->log.size;
+    for (int i = 0; i < 12; i++) {
+      if ((diff >> i) & 1)
+        StateRecorder_RecordCmd(sr, i << 4);
+    }
+    //    while (lb < sr->log.size)
+    //      printf("%.2x ", sr->log.data[lb++]);
+    //    printf("\n");
+  }
+  sr->frames_since_last++;
+  sr->total_frames++;
+}
+
+void StateRecorder_RecordPatchByte(StateRecorder *sr, uint32 addr, const uint8 *value, int num) {
+  assert(addr < 0x20000);
+
+  //  printf("%d: PatchByte(0x%x, 0x%x. %d): ", sr->frames_since_last, addr, *value, num);
+  //  size_t lb = sr->log.size;
+  int lq = (num - 1) <= 3 ? (num - 1) : 3;
+  StateRecorder_RecordCmd(sr, 0xc0 | (addr & 0x10000 ? 2 : 0) | lq << 2);
+  if (lq == 3)
+    ByteArray_AppendVl(&sr->log, num - 1 - 3);
+  ByteArray_AppendByte(&sr->log, addr >> 8);
+  ByteArray_AppendByte(&sr->log, addr);
+  for (int i = 0; i < num; i++)
+    ByteArray_AppendByte(&sr->log, value[i]);
+  //  while (lb < sr->log.size)
+  //    printf("%.2x ", sr->log.data[lb++]);
+  //  printf("\n");
+}
+
+void ReadFromFile(FILE *f, void *data, size_t n) {
+  if (fread(data, 1, n, f) != n)
+    Die("fread failed\n");
+}
+
+void StateRecorder_Load(StateRecorder *sr, FILE *f, bool replay_mode) {
+  // todo: fix robustness on invalid data.
+  uint32 hdr[8] = { 0 };
+  ReadFromFile(f, hdr, sizeof(hdr));
+
+  assert(hdr[0] == 1);
+
+  sr->total_frames = hdr[1];
+  ByteArray_Resize(&sr->log, hdr[2]);
+  ReadFromFile(f, sr->log.data, sr->log.size);
+  sr->last_inputs = hdr[3];
+  sr->frames_since_last = hdr[4];
+
+  ByteArray_Resize(&sr->base_snapshot, (hdr[5] & 1) ? hdr[6] : 0);
+  ReadFromFile(f, sr->base_snapshot.data, sr->base_snapshot.size);
+
+  sr->replay_next_cmd_at = 0;
+
+  sr->replay_mode = replay_mode;
+  if (replay_mode) {
+    sr->frames_since_last = 0;
+    sr->last_inputs = 0;
+    sr->replay_pos = sr->replay_pos_last_complete = 0;
+    sr->replay_frame_counter = 0;
+    // Load snapshot from |base_snapshot_|, or reset if empty.
+
+    if (sr->base_snapshot.size) {
+      LoadFuncState state = { sr->base_snapshot.data, sr->base_snapshot.data + sr->base_snapshot.size };
+      LoadSnesState(&loadFunc, &state);
+      assert(state.p == state.pend);
+    } else {
+      ZeldaReset(false);
+    }
+  } else {
+    // Resume replay from the saved position?
+    sr->replay_pos = sr->replay_pos_last_complete = hdr[5] >> 1;
+    sr->replay_frame_counter = hdr[7];
+    sr->replay_mode = (sr->replay_frame_counter != 0);
+
+    ByteArray arr = { 0 };
+    ByteArray_Resize(&arr, hdr[6]);
+    ReadFromFile(f, arr.data, arr.size);
+    LoadFuncState state = { arr.data, arr.data + arr.size };
+    LoadSnesState(&loadFunc, &state);
+    ByteArray_Destroy(&arr);
+    assert(state.p == state.pend);
+  }
+}
+
+void StateRecorder_Save(StateRecorder *sr, FILE *f) {
+  uint32 hdr[8] = { 0 };
+  ByteArray arr = { 0 };
+  SaveSnesState(&saveFunc, &arr);
+  assert(sr->base_snapshot.size == 0 || sr->base_snapshot.size == arr.size);
+
+  hdr[0] = 1;
+  hdr[1] = sr->total_frames;
+  hdr[2] = (uint32)sr->log.size;
+  hdr[3] = sr->last_inputs;
+  hdr[4] = sr->frames_since_last;
+  hdr[5] = sr->base_snapshot.size ? 1 : 0;
+  hdr[6] = (uint32)arr.size;
+  // If saving while in replay mode, also need to persist
+  // sr->replay_pos_last_complete and sr->replay_frame_counter
+  // so the replaying can be resumed.
+  if (sr->replay_mode) {
+    hdr[5] |= sr->replay_pos_last_complete << 1;
+    hdr[7] = sr->replay_frame_counter;
+  }
+  fwrite(hdr, 1, sizeof(hdr), f);
+  fwrite(sr->log.data, 1, hdr[2], f);
+  fwrite(sr->base_snapshot.data, 1, sr->base_snapshot.size, f);
+  fwrite(arr.data, 1, arr.size, f);
+
+  ByteArray_Destroy(&arr);
+}
+
+void StateRecorder_ClearKeyLog(StateRecorder *sr) {
+  printf("Clearing key log!\n");
+  sr->base_snapshot.size = 0;
+  SaveSnesState(&saveFunc, &sr->base_snapshot);
+  ByteArray old_log = sr->log;
+  int old_frames_since_last = sr->frames_since_last;
+  memset(&sr->log, 0, sizeof(sr->log));
+  // If there are currently any active inputs, record them initially at timestamp 0.
+  sr->frames_since_last = 0;
+  if (sr->last_inputs) {
+    for (int i = 0; i < 12; i++) {
+      if ((sr->last_inputs >> i) & 1)
+        StateRecorder_RecordCmd(sr, i << 4);
+    }
+  }
+  if (sr->replay_mode) {
+    // When clearing the key log while in replay mode, we want to keep
+    // replaying but discarding all key history up until this point.
+    if (sr->replay_next_cmd_at != 0xffffffff) {
+      sr->replay_next_cmd_at -= old_frames_since_last;
+      sr->frames_since_last = sr->replay_next_cmd_at;
+      sr->replay_pos_last_complete = (uint32)sr->log.size;
+      StateRecorder_RecordCmd(sr, sr->replay_cmd);
+      int old_replay_pos = sr->replay_pos;
+      sr->replay_pos = (uint32)sr->log.size;
+      ByteArray_AppendData(&sr->log, old_log.data + old_replay_pos, old_log.size - old_replay_pos);
+    }
+    sr->total_frames -= sr->replay_frame_counter;
+    sr->replay_frame_counter = 0;
+  } else {
+    sr->total_frames = 0;
+  }
+  ByteArray_Destroy(&old_log);
+  sr->frames_since_last = 0;
+}
+
+uint16 StateRecorder_ReadNextReplayState(StateRecorder *sr) {
+  assert(sr->replay_mode);
+  while (sr->frames_since_last >= sr->replay_next_cmd_at) {
+    int replay_pos = sr->replay_pos;
+    if (replay_pos != sr->replay_pos_last_complete) {
+      // Apply next command
+      sr->frames_since_last = 0;
+      if (sr->replay_cmd < 0xc0) {
+        sr->last_inputs ^= 1 << (sr->replay_cmd >> 4);
+      } else if (sr->replay_cmd < 0xd0) {
+        int nb = 1 + ((sr->replay_cmd >> 2) & 3);
+        uint8 t;
+        if (nb == 4) do {
+          nb += t = sr->log.data[replay_pos++];
+        } while (t == 255);
+        uint32 addr = ((sr->replay_cmd >> 1) & 1) << 16;
+        addr |= sr->log.data[replay_pos++] << 8;
+        addr |= sr->log.data[replay_pos++];
+        do {
+          g_ram[addr & 0x1ffff] = sr->log.data[replay_pos++];
+          EmuSyncMemoryRegion(&g_ram[addr & 0x1ffff], 1);
+        } while (addr++, --nb);
+      } else {
+        assert(0);
+      }
+    }
+    sr->replay_pos_last_complete = replay_pos;
+    if (replay_pos >= sr->log.size) {
+      sr->replay_pos = replay_pos;
+      sr->replay_next_cmd_at = 0xffffffff;
+      break;
+    }
+    // Read the next one
+    uint8 cmd = sr->log.data[replay_pos++], t;
+    int mask = (cmd < 0xc0) ? 0xf : 0x1;
+    int frames = cmd & mask;
+    if (frames == mask) do {
+      frames += t = sr->log.data[replay_pos++];
+    } while (t == 255);
+    sr->replay_next_cmd_at = frames;
+    sr->replay_cmd = cmd;
+    sr->replay_pos = replay_pos;
+  }
+  sr->frames_since_last++;
+  // Turn off replay mode after we reached the final frame position
+  if (++sr->replay_frame_counter >= sr->total_frames) {
+    sr->replay_mode = false;
+  }
+  return sr->last_inputs;
+}
+
+void StateRecorder_StopReplay(StateRecorder *sr) {
+  if (!sr->replay_mode)
+    return;
+  sr->replay_mode = false;
+  sr->total_frames = sr->replay_frame_counter;
+  sr->log.size = sr->replay_pos_last_complete;
+}
+
+#ifdef _DEBUG
+// This can be used to read inputs from a text file for easier debugging
+int InputStateReadFromFile() {
+  static FILE *f;
+  static uint32 next_ts, next_keys, cur_keys;
+  char buf[64];
+  char keys[64];
+
+  while (state_recorder.total_frames == next_ts) {
+    cur_keys = next_keys;
+    if (!f)
+      f = fopen("boss_bug.txt", "r");
+    if (fgets(buf, sizeof(buf), f)) {
+      if (sscanf(buf, "%d: %s", &next_ts, keys) == 1) keys[0] = 0;
+      int i = 0;
+      for (const char *s = keys; *s; s++) {
+        static const char kKeys[] = "AXsSUDLRBY";
+        const char *t = strchr(kKeys, *s);
+        assert(t);
+        i |= 1 << (t - kKeys);
+      }
+      next_keys = i;
+    } else {
+      next_ts = 0xffffffff;
+    }
+  }
+
+  return cur_keys;
+}
+#endif
+
+bool ZeldaRunFrame(int inputs) {
+
+  // Avoid up/down and left/right from being pressed at the same time
+  if ((inputs & 0x30) == 0x30) inputs ^= 0x30;
+  if ((inputs & 0xc0) == 0xc0) inputs ^= 0xc0;
+
+  frame_ctr_dbg++;
+
+  bool is_replay = state_recorder.replay_mode;
+
+  // Either copy state or apply state
+  if (is_replay) {
+    inputs = StateRecorder_ReadNextReplayState(&state_recorder);
+  } else {
+    //    input_state = InputStateReadFromFile();
+    StateRecorder_Record(&state_recorder, inputs);
+
+    // This is whether APUI00 is true or false, this is used by the ancilla code.
+    uint8 apui00 = ZeldaIsMusicPlaying();
+    if (apui00 != g_ram[kRam_APUI00]) {
+      g_ram[kRam_APUI00] = apui00;
+      EmuSyncMemoryRegion(&g_ram[kRam_APUI00], 1);
+      StateRecorder_RecordPatchByte(&state_recorder, 0x648, &apui00, 1);
+    }
+
+    if (animated_tile_data_src != 0) {
+      // Whenever we're no longer replaying, we'll remember what bugs were fixed,
+      // but only if game is initialized.
+      if (g_ram[kRam_BugsFixed] < kBugFix_Latest) {
+        g_ram[kRam_BugsFixed] = kBugFix_Latest;
+        EmuSyncMemoryRegion(&g_ram[kRam_BugsFixed], 1);
+        StateRecorder_RecordPatchByte(&state_recorder, kRam_BugsFixed, &g_ram[kRam_BugsFixed], 1);
+      }
+
+      if (enhanced_features0 != g_wanted_zelda_features) {
+        enhanced_features0 = g_wanted_zelda_features;
+        EmuSyncMemoryRegion(&enhanced_features0, sizeof(enhanced_features0));
+        StateRecorder_RecordPatchByte(&state_recorder, kRam_Features0, (uint8 *)&enhanced_features0, 4);
+      }
+    }
+  }
+
+  int run_what;
+  if (g_ram[kRam_BugsFixed] < kBugFix_PolyRenderer) {
+    // A previous version of this code alternated the game loop with
+    // the poly renderer.
+    run_what = (is_nmi_thread_active && thread_other_stack != 0x1f31) ? 2 : 1;
+  } else {
+    // The snes seems to let poly rendering run for a little
+    // while each fram until it eventually completes a frame.
+    // Simulate this by rendering the poly every n:th frame.
+    run_what = (is_nmi_thread_active && IncrementCrystalCountdown(&g_ram[kRam_CrystalRotateCounter], virq_trigger)) ? 3 : 1;
+    EmuSyncMemoryRegion(&g_ram[kRam_CrystalRotateCounter], 1);
+  }
+
+  if (g_emu_runframe == NULL || enhanced_features0 != 0 || g_zenv.dialogue_flags) {
+    // can't compare against real impl when running with extra features.
+    ZeldaRunFrameInternal(inputs, run_what);
+  } else {
+    g_emu_runframe(inputs, run_what);
+  }
+
+  ZeldaPushApuState();
+
+  return is_replay;
+}
+
+void ZeldaSetLanguage(const char *language) {
+  static const uint8 kDefaultConf[3] = { 0, 0, 0 };
+  MemBlk found = { kDefaultConf, 3 };
+  if (language) {
+    size_t n = strlen(language);
+    for (int i = 0; ; i++) {
+      MemBlk mb = kDialogueMap(i);
+      if (mb.ptr == 0) {
+        fprintf(stderr, "Unable to find language '%s'\n", language);
+        break;
+      }
+      MemBlk name = FindIndexInMemblk(mb, 0);
+      if (name.size == n && !memcmp(name.ptr, language, n)) {
+        found = FindIndexInMemblk(mb, 1);
+        break;
+      }
+    }
+  }
+  g_zenv.dialogue_blk = kDialogue(found.ptr[0]);
+  g_zenv.dialogue_font_blk = kDialogueFont(found.ptr[1]);
+  g_zenv.dialogue_flags = found.ptr[2];
+}
+
+
+static const char *const kReferenceSaves[] = {
+  "Chapter 1 - Zelda's Rescue.sav",
+  "Chapter 2 - After Eastern Palace.sav",
+  "Chapter 3 - After Desert Palace.sav",
+  "Chapter 4 - After Tower of Hera.sav",
+  "Chapter 5 - After Hyrule Castle Tower.sav",
+  "Chapter 6 - After Dark Palace.sav",
+  "Chapter 7 - After Swamp Palace.sav",
+  "Chapter 8 - After Skull Woods.sav",
+  "Chapter 9 - After Gargoyle's Domain.sav",
+  "Chapter 10 - After Ice Palace.sav",
+  "Chapter 11 - After Misery Mire.sav",
+  "Chapter 12 - After Turtle Rock.sav",
+  "Chapter 13 - After Ganon's Tower.sav",
+};
+
+void SaveLoadSlot(int cmd, int which) {
+  char name[128];
+  if (which & 256) {
+    if (cmd == kSaveLoad_Save)
+      return;
+    sprintf(name, "saves/ref/%s", kReferenceSaves[which - 256]);
+  } else {
+    sprintf(name, "saves/save%d.sav", which);
+  }
+  FILE *f = fopen(name, cmd != kSaveLoad_Save ? "rb" : "wb");
+  if (f) {
+    printf("*** %s slot %d\n",
+      cmd == kSaveLoad_Save ? "Saving" : cmd == kSaveLoad_Load ? "Loading" : "Replaying", which);
+
+    if (cmd != kSaveLoad_Save)
+      StateRecorder_Load(&state_recorder, f, cmd == kSaveLoad_Replay);
+    else
+      StateRecorder_Save(&state_recorder, f);
+
+    fclose(f);
+  }
+}
+
+typedef struct StateRecoderMultiPatch {
+  uint32 count;
+  uint32 addr;
+  uint8 vals[256];
+} StateRecoderMultiPatch;
+
+
+void StateRecoderMultiPatch_Init(StateRecoderMultiPatch *mp) {
+  mp->count = mp->addr = 0;
+}
+
+void StateRecoderMultiPatch_Commit(StateRecoderMultiPatch *mp) {
+  if (mp->count)
+    StateRecorder_RecordPatchByte(&state_recorder, mp->addr, mp->vals, mp->count);
+}
+
+void StateRecoderMultiPatch_Patch(StateRecoderMultiPatch *mp, uint32 addr, uint8 value) {
+  if (mp->count >= 256 || addr != mp->addr + mp->count) {
+    StateRecoderMultiPatch_Commit(mp);
+    mp->addr = addr;
+    mp->count = 0;
+  }
+  mp->vals[mp->count++] = value;
+  g_ram[addr] = value;
+  EmuSyncMemoryRegion(&g_ram[addr], 1);
+}
+
+void PatchCommand(char c) {
+  StateRecoderMultiPatch mp;
+
+  StateRecoderMultiPatch_Init(&mp);
+  if (c == 'w') {
+    StateRecoderMultiPatch_Patch(&mp, 0xf372, 80);  // health filler
+    StateRecoderMultiPatch_Patch(&mp, 0xf373, 80);  // magic filler
+    //    b.Patch(0x1FE01, 25);
+  } else if (c == 'W') {
+    StateRecoderMultiPatch_Patch(&mp, 0xf375, 10);  // link_bomb_filler
+    StateRecoderMultiPatch_Patch(&mp, 0xf376, 10);  // link_arrow_filler
+    uint16 rupees = link_rupees_goal + 100;
+    StateRecoderMultiPatch_Patch(&mp, 0xf360, rupees);  // link_rupees_goal
+    StateRecoderMultiPatch_Patch(&mp, 0xf361, rupees >> 8);  // link_rupees_goal
+  } else if (c == 'k') {
+    StateRecorder_ClearKeyLog(&state_recorder);
+  } else if (c == 'o') {
+    StateRecoderMultiPatch_Patch(&mp, 0xf36f, 1);
+  } else if (c == 'l') {
+    StateRecorder_StopReplay(&state_recorder);
+  } else if (c == 'E') {
+    StateRecoderMultiPatch_Patch(&mp, 0x37f, g_ram[0x37f] ^ 1);
+  }
+  StateRecoderMultiPatch_Commit(&mp);
+}
+
+
+void ZeldaReadSram() {
+  FILE *f = fopen("saves/sram.dat", "rb");
+  if (f) {
+    if (fread(g_zenv.sram, 1, 8192, f) != 8192)
+      fprintf(stderr, "Error reading saves/sram.dat\n");
+    fclose(f);
+    EmuSynchronizeWholeState();
+  }
+}
+
+void ZeldaWriteSram() {
+  rename("saves/sram.dat", "saves/sram.bak");
+  FILE *f = fopen("saves/sram.dat", "wb");
+  if (f) {
+    fwrite(g_zenv.sram, 1, 8192, f);
+    fclose(f);
+  } else {
+    fprintf(stderr, "Unable to write saves/sram.dat\n");
+  }
+}
\ No newline at end of file
--- /dev/null
+++ b/src/zelda_rtl.h
@@ -1,0 +1,97 @@
+// This file defines various things related to the runtime environment
+// of the code
+#ifndef ZELDA3_ZELDA_RTL_H_
+#define ZELDA3_ZELDA_RTL_H_
+
+#include <stdio.h>
+#include <string.h>
+#include <stdbool.h>
+#include <assert.h>
+
+#include "types.h"
+#include "features.h"
+
+struct Snes;
+struct Dsp;
+
+typedef struct ZeldaEnv {
+  uint8 *ram;
+  uint8 *sram;
+  uint16 *vram;
+  struct Ppu *ppu;
+  struct SpcPlayer *player;
+  struct Dma *dma;
+  
+  MemBlk dialogue_blk;
+  MemBlk dialogue_font_blk;
+  uint8 dialogue_flags;
+} ZeldaEnv;
+extern ZeldaEnv g_zenv;
+extern int frame_ctr_dbg;
+
+typedef void PlayerHandlerFunc();
+typedef void HandlerFuncK(int k);
+
+static inline void zelda_snes_dummy_write(uint32 adr, uint8 val) {}
+
+void zelda_apu_write(uint32_t adr, uint8_t val);
+uint8_t zelda_read_apui00();
+uint8_t zelda_apu_read(uint32_t adr);
+void zelda_ppu_write(uint32_t adr, uint8_t val);
+void zelda_ppu_write_word(uint32_t adr, uint16_t val);
+
+
+// 512x480 32-bit pixels. Returns true if we instead draw 1024x960
+void HdmaSetup(uint32 addr6, uint32 addr7, uint8 transfer_unit, uint8 reg6, uint8 reg7, uint8 indirect_bank);
+
+void ZeldaInitialize();
+void ZeldaReset(bool preserve_sram);
+void ZeldaDrawPpuFrame(uint8 *pixel_buffer, size_t pitch, uint32 render_flags);
+void ZeldaRunFrameInternal(uint16 input, int run_what);
+bool ZeldaRunFrame(int input_state);
+void LoadSongBank(const uint8 *p);
+void ZeldaApuLock();
+void ZeldaApuUnlock();
+bool ZeldaIsPlayingMusicTrack(uint8 track);
+uint8 ZeldaGetEntranceMusicTrack(int track);
+void ZeldaSetLanguage(const char *language);
+void PatchCommand(char cmd);
+
+// Things for state management
+
+enum {
+  kSaveLoad_Save = 0,
+  kSaveLoad_Load = 1,
+  kSaveLoad_Replay = 2,
+};
+
+void SaveLoadSlot(int cmd, int which);
+void ZeldaWriteSram();
+void ZeldaReadSram();
+
+typedef void ZeldaRunFrameFunc(uint16 input, int run_what);
+typedef void ZeldaSyncAllFunc();
+
+void ZeldaSetupEmuCallbacks(uint8 *emu_ram, ZeldaRunFrameFunc *func, ZeldaSyncAllFunc *sync_all);
+
+// Button definitions, zelda splits them in separate 8-bit high/low
+enum {
+  kJoypadL_A = 0x80,
+  kJoypadL_X = 0x40,
+  kJoypadL_L = 0x20,
+  kJoypadL_R = 0x10,
+
+  kJoypadH_B = 0x80,
+  kJoypadH_Y = 0x40,
+  kJoypadH_Select = 0x20,
+  kJoypadH_Start = 0x10,
+
+  kJoypadH_Up = 0x8,
+  kJoypadH_Down = 0x4,
+  kJoypadH_Left = 0x2,
+  kJoypadH_Right = 0x1,
+
+  kJoypadH_AnyDir = 0xf,
+};
+
+#endif  // ZELDA3_ZELDA_RTL_H_
--- a/tables/.gitignore
+++ /dev/null
@@ -1,14 +1,0 @@
-zelda3.sfc
-dialogue*.txt
-generated_*.h
-linksprite.png
-map32_to_map16.txt
-music_info.yaml
-sfx.txt
-/sound
-sound_ending.txt
-sound_indoor.txt
-sound_intro.txt
-/hud_icons.png
-/font*.png
-
--- a/tables/compile_music.py
+++ /dev/null
@@ -1,453 +1,0 @@
-import array
-import sys
-import yaml
-import re
-import util
-
-class Song:
-  name = 'Song'
-  def __str__(self):
-    s = '[Song_0x%x idx=%d]\n' % (self.ea, self.index)
-    s += "".join(x.name + '\n' for x in self.phrases)
-    return s
-
-class Phrase:
-  name = 'Phrase'
-  def __str__(self):
-    s = '[%s]' % (self.name)
-    return s
-
-class PhraseLoop:
-  name = 'PhraseLoop'
-  def __init__(self, loops, jmp):
-    self.loops = loops
-    self.jmp = jmp
-    self.name = 'PhraseLoop %d %d' % (self.loops, self.jmp)
-  def __str__(self):
-    return self.name
-
-class Pattern:
-  name = 'Pattern'
-
-class SfxPattern:
-  name = 'SfxPattern'
-
-class SongList:
-  name = 'SongList'
-
-class SfxList:
-  name = 'SfxList'
-
-types_for_name = {}
-
-def get_type_for_name(nam, tp, is_create):
-  if nam == 'None':
-    assert not is_create
-    return None
-  a = types_for_name.get(nam)
-  if a != None:
-    if is_create:
-      if a.defined:
-        raise Exception('%s already defined' % nam)
-      a.defined = True
-    assert type(a) == tp, (nam, type(a), tp)
-    return a
-  a = tp()
-  a.name = nam
-  a.defined = is_create
-  types_for_name[nam] = a
-  a.ea = None
-  if '_0x' in nam:
-    a.ea = int(nam[nam.index('_0x') + 3:], 16)
-  return a
-
-def process_song(caption, args, lines):
-  song = get_type_for_name(caption, Song, True)
-  song.phrases = []
-  for line in lines:
-    line_cmd, *line_args = line.split(' ')
-    if line_cmd == 'PhraseLoop':
-      song.phrases.append(PhraseLoop(int(line_args[0]), int(line_args[1])))
-    else:
-      song.phrases.append(get_type_for_name(line_cmd, Phrase, False))
-  return song
-
-def process_song_list(caption, args, lines):
-  song_list = get_type_for_name(caption, SongList, True)
-  song_list.songs = [get_type_for_name(line, Song, False) for line in lines]
-  return song_list
-
-def process_phrase(caption, args, lines):
-  phrase = get_type_for_name(caption, Phrase, True)
-  assert len(lines)==8
-  phrase.patterns = [get_type_for_name(lines[i], Pattern, False) for i in range(8)]
-  return phrase
-  
-kEffectByteLength = [1, 1, 2, 3, 0, 1, 2, 1, 2, 1, 1, 3, 0, 1, 2, 3, 1, 3, 3, 0, 1, 3, 0, 3, 3, 3, 1]
-kEffectNames = ['Instrument', 'Pan', 'PanFade', 'Vibrato', 'VibratoOff',
-                'SongVolume', 'SongVolumeFade', 'Tempo', 'TempoFade',
-                'Transpose', 'ChannelTranpose', 'Tremolo', 'TremoloOff',
-                'Volume', 'VolumeFade', 'Call', 'VibratoFade',
-                'PitchEnvelopeTo', 'PitchEnvelopeFrom', 'PitchEnvelopeOff',
-                'FineTune', 'EchoEnable', 'EchoOff', 'EchoSetup', 'EchoVolumeFade',
-                'PitchSlide', 'PercussionDefine']
-kEffectNamesDict = {a:i for i, a in enumerate(kEffectNames)}
-kKeys  = ['C-', 'C#', 'D-', 'D#', 'E-', 'F-', 'F#', 'G-', 'G#', 'A-', 'A#', 'B-']
-kKeysDict = {a+str(j+1):i+j*12 for i, a in enumerate(kKeys) for j in range(6)}
-kKeysDict['-+-'] = 72
-kKeysDict['---'] = 73
-
-def process_pattern(caption, args, lines):
-  pattern = get_type_for_name(caption, Pattern, True)
-  pattern.lines = []
-  pattern.fallthrough = False
-  for line in lines:
-    assert not pattern.fallthrough
-    line_cmd, *line_args = line.split()
-    if line_cmd == 'Call':
-      assert len(line_args) == 2
-      pattern.lines.append(('Call', (get_type_for_name(line_args[0], Pattern, False),int(line_args[1]) ), None, None))
-    elif line_cmd == 'Fallthrough':
-      pattern.fallthrough = True
-    elif line_cmd in kEffectNamesDict:
-      line_args = [int(a) for a in line_args]
-      pattern.lines.append((line_cmd, line_args, None, None))
-    elif line_cmd in kKeysDict:
-      assert len(line_args) == 2, line_args
-      note_length = None if line_args[0] == '--' else int(line_args[0])
-      volstuff = None if line_args[1] == '--' else int(line_args[1], 16)
-      pattern.lines.append((line_cmd, line_args, note_length, volstuff))
-    else:
-      assert 0, repr(line_cmd)
-  return pattern
-
-def process_sfx_pattern(caption, args, lines):
-  pattern = get_type_for_name(caption, SfxPattern, True)
-  pattern.lines = lines
-  return pattern
-
-def write_sfx_pattern(serializer, o):
-#  print('# Creating %s (%x)' % ( o.name, serializer.addr))
-  for i,line in enumerate(o.lines):
-#    print(line)
-    line_cmd, *line_args = re.split(r' +', line)
-    if line_cmd == 'SetInstrument':
-      assert len(line_args) == 1
-      serializer.write([0xe0, int(line_args[0])])
-    elif line_cmd == 'Restart':
-      serializer.write([0xff])
-      assert i == len(o.lines) - 1
-      return
-    elif line_cmd == 'Fallthrough':
-      assert i == len(o.lines) - 1
-      return
-    elif line_cmd in kKeysDict or line_cmd == '.':
-      if line_args[0] != '--':
-        serializer.write((int(line_args[0]),))
-        if line_args[1] != '---':
-          serializer.write((int(line_args[1]),))
-          if line_args[2] != '---':
-            serializer.write((int(line_args[2]),))
-      if len(line_args) >= 4:
-        assert line_args[3] == 'PitchSlide'
-        if line_cmd == '.':
-          serializer.write([0xf1, int(line_args[4]), int(line_args[5]), int(line_args[6])])
-        else:
-          serializer.write([0xf9, kKeysDict[line_cmd] | 0x80, int(line_args[4]), int(line_args[5]), int(line_args[6])])
-      else:
-        serializer.write([kKeysDict[line_cmd] | 0x80])
-    else:
-      assert 0, repr(line_cmd)
-  serializer.write([0])
-
-def process_sfx_list(caption, args, lines):
-  sfx_list = get_type_for_name(caption, SfxList, True)
-  sfx_list.patterns = []
-  sfx_list.next = []
-  sfx_list.echo = []
-  for line in lines:
-    r = line.split(',')
-    sfx_list.patterns.append(get_type_for_name(r[0], SfxPattern, False))
-    sfx_list.next.append(int(r[1]))
-    if len(r) >= 3:
-      sfx_list.echo.append(int(r[2]))
-  assert len(sfx_list.echo) in (0, len(lines))
-  return sfx_list
-
-def write_sfx_list(serializer, o):
-  for line in o.patterns:
-    serializer.write_reloc_entry(line)
-  for next in o.next:
-    serializer.write([next])
-  for i in o.echo:
-    serializer.write([i])
-
-kGapStartAddrs = (0x2b00, 0x2880, 0xd000)
-
-class Serializer:
-  def __init__(self):
-    self.memory = [None] * 65536
-    self.relocs = []
-    self.addr = None
-
-  def write(self, data):
-    for d in data:
-      assert self.memory[self.addr] == None, '0x%x' % self.addr
-      self.memory[self.addr] = d
-      self.addr += 1
-
-  def write_at(self, a, data):
-    for d in data:
-      self.memory[a] = d
-      a += 1
-
-  def write_word(self, a, v):
-    self.memory[a] = v & 0xff
-    self.memory[a + 1] = v >> 8 & 0xff
-      
-
-  def write_reloc_entry(self, r):
-    self.write([0, 0])
-    if r:
-      self.relocs.append((self.addr - 2, r))
-    
-
-  def write_song(self, song):
-    for phrase in song.phrases:
-      if isinstance(phrase, PhraseLoop):
-        i = self.addr + phrase.jmp * 2
-        self.write([phrase.loops, 0])
-        self.write([i & 0xff, i >> 8])
-      else:
-        self.write_reloc_entry(phrase)
-    self.write([0, 0])
-
-  def write_phrase(self, phrase):
-    for i in range(8):
-      self.write_reloc_entry(phrase.patterns[i])
-
-  def write_song_list(self, song_list):
-    for song in song_list.songs:
-      self.write_reloc_entry(song)
-      
-  def write_pattern(self, patt):
-    for cmd, args, note_length, volstuff in patt.lines:
-      #print(cmd, args, note_length, volstuff)
-      if note_length != None: self.write((note_length, ))
-      if volstuff != None: self.write((volstuff, ))
-      if cmd in kKeysDict:
-        self.write((0x80 | kKeysDict[cmd], ))
-      elif cmd == 'Call':
-        self.write([0xef, 0, 0, int(args[1])])
-        self.relocs.append((self.addr - 3, args[0]))
-      elif cmd in kEffectNamesDict:
-        i = kEffectNamesDict[cmd]
-        assert len(args) == kEffectByteLength[i]
-        self.write([0xe0 + i])
-        self.write(args)
-    if not patt.fallthrough:
-      self.write((0, ))
-
-  def write_obj(self, what):
- #   print(what.name, self.addr, what.ea)
- #   print('Writing %s at 0x%x. Curr pos 0x%x' % (what.name, what.ea, 0 if self.addr == None else self.addr))
-    if what.ea != None:
-      
-      if self.addr == None or what.ea in kGapStartAddrs:# or True:#what.ea >= self.addr:
-        self.addr = what.ea
-      elif what.ea != self.addr:
-        print('%s: 0x%x != 0x%x' % (what.name, what.ea, self.addr))
-        assert(0)
-   
-    what.write_addr = self.addr
-    assert self.addr != None
-    if isinstance(what, Phrase):
-      self.write_phrase(what)
-    elif isinstance(what, Pattern):
-      self.write_pattern(what)
-    elif isinstance(what, Song):
-      self.write_song(what)
-    elif isinstance(what, SongList):
-      self.write_song_list(what)
-    elif isinstance(what, SfxPattern):
-      write_sfx_pattern(self, what)
-    elif isinstance(what, SfxList):
-      write_sfx_list(self, what)
-    else:
-      print(type(what))
-      assert(0)
-
-  def write_zeros(self, a, b):
-    while a < b:
-      self.memory[a] = 0
-      a += 1
-
-  def process_relocs(self):
-    for p, r in self.relocs:
-      self.memory[p + 0] = r.write_addr & 0xff
-      self.memory[p + 1] = r.write_addr >> 8
-
-def process_file(file):
-  sorted_ents = []
-  def add_collect(heading, collect):
-    caption, *args = heading.strip('[]').split(' ', 1)
-    if caption.startswith('Song_'):
-      r = process_song(caption, args, collect)
-    elif caption.startswith('Phrase_'):
-      r = process_phrase(caption, args, collect)
-    elif caption.startswith('Pattern_'):
-      r = process_pattern(caption, args, collect)
-    elif caption.startswith('SongList_'):
-      r = process_song_list(caption, args, collect)
-    elif caption.startswith('Sfx_'):
-      r = process_sfx_pattern(caption, args, collect)
-    elif caption.startswith('SfxPort'):
-      r = process_sfx_list(caption, args, collect)
-    else:
-      assert 0
-    sorted_ents.append(r)
-  collect = None
-  heading = None
-  for line in file:
-    line = line.strip()
-    if line == '' or line.startswith('#'): continue
-    if line.startswith('['):
-      if heading != None:
-        add_collect(heading, collect)
-      heading = line
-      collect = []
-      #
-      #print(caption, args)
-    else:
-      collect.append(line.strip('\n'))
-  if heading != None:
-    add_collect(heading, collect)
-  return sorted_ents
-
-def serialize_song(serializer, song, sorted_ents):
-  if song == 'intro':
-#    serializer.write_zeros(0x2a8b, 0x2b00)
-#    serializer.write_zeros(0x3188, 0x4000)
- #   serializer.write_zeros(0xbaa0, 0xd000)
- #   serializer.write_zeros(0xfdae, 0x10000)
- #   serializer.write_zeros(0x2850, 0x2880)
-    serializer.addr = 0x4000
-    sample_to_addr = {}
-    music_info = yaml.safe_load(open('music_info.yaml', 'r'))
-    for i, info in enumerate(music_info['samples']):
-      if info['file'] not in sample_to_addr:
-        sample_to_addr[info['file']] = serializer.addr
-        serializer.write(open('%s.brr' % info['file'], 'rb').read())
-      addr = sample_to_addr[info['file']]
-      serializer.write_word(0x3c00 + i * 4, addr)
-      serializer.write_word(0x3c00 + i * 4 + 2, addr + info['repeat'] // 16 * 9 if 'repeat' in info else serializer.addr)
-    for i in range(6):
-      serializer.write_word(0x3c64 + i * 2, 0xffff)
-    
-    for i, info in enumerate(music_info['instruments']):
-      ea = 0x3d00 + i * 6
-      serializer.memory[ea + 0] = info['sample']
-      serializer.memory[ea + 1] = 0x80 | info['decay'] << 4 | info['attack']
-      serializer.memory[ea + 2] = info['sustain_level'] << 5 | info['sustain_rate']
-      serializer.memory[ea + 3] = info['vxgain']
-      serializer.memory[ea + 4] = info['pitch_base'] >> 8
-      serializer.memory[ea + 5] = info['pitch_base'] & 0xff
-
-    serializer.write_at(0x3D96, music_info['note_gate_off'])
-    serializer.write_at(0x3D9e, music_info['note_volume'])
-
-    for i, info in enumerate(music_info['sfx_instruments']):
-      ea = 0x3e00 + i * 9
-      serializer.memory[ea + 0] = info['voll']
-      serializer.memory[ea + 1] = info['volr']
-      serializer.write_word(ea + 2, info['pitch'])
-      serializer.memory[ea + 4] = info['sample']
-      serializer.memory[ea + 5] = 0x80 | info['decay'] << 4 | info['attack']
-      serializer.memory[ea + 6] = info['sustain_level'] << 5 | info['sustain_rate']
-      serializer.memory[ea + 7] = info['vxgain']
-      serializer.memory[ea + 8] = info['pitch_base']
-
-  serializer.addr = None
-  for e in sorted_ents:
-    serializer.write_obj(e)
-
-  if song == 'indoor':
-    t = types_for_name['Song_0x2880']
-    t.defined = True
-    t.write_addr = 0x2880
-
-
-  for e in types_for_name.values():
-    if not e.defined:
-      raise Exception('Symbol %s not defined' % e.name)
-
-  serializer.process_relocs()
-
-def compare_with_orig(serializer, song):
-  ranges=[]
-  ok = True
-  spc = open('sound/%s.spc' % song, 'rb').read()
-  for i in range(65536):
-    if serializer.memory[i] != None:
-      if serializer.memory[i]!= spc[i]:
-        print('0x%x: 0x%x != 0x%x' % (i, serializer.memory[i], spc[i]))
-        ok = False
-    else:
-#      serializer.memory[i] = spc[i]
-      if len(ranges) and ranges[-1][1] == i:
-        ranges[-1][1] = i + 1
-      else:
-        ranges.append([i, i + 1])
-  if __name__ == "__main__":
-    for a, b in ranges:
-      print('// undefined %x-%x' % (a, b))
-  return ok
-
-def produce_loadable_seq(serializer):
-  r = []
-  # count non zeros
-  start, i = 0, 0
-  while start < 0x10000:    
-    while i < 0x10000 and serializer.memory[i] != None:
-      i += 1
-    j = i
-    while i < 0x10000 and serializer.memory[i] == None:
-      i += 1
-    
-    if j == start:
-      start = i
-      continue
-    r.extend([(j - start) & 0xff, (j - start) >> 8, start & 0xff, start >> 8])
-    r.extend(serializer.memory[start:j])
-#    print('copy 0x%x - 0x%x (%d)' % (start, j, j - start))
-    start = i
-  r.extend([0, 0])
-  return r
-
-def print_song(song):
-  global types_for_name
-  types_for_name = {}
-
-  serializer = Serializer()
-
-  sorted_ents = process_file(open('sound_%s.txt' % song, 'r'))
-  if song == 'intro':
-    sorted_ents.extend(process_file(open('sfx.txt' , 'r')))
-
-  serialize_song(serializer, song, sorted(sorted_ents, key = lambda x: x.ea))
-
-  r = produce_loadable_seq(serializer)
-
-  result = 'kSoundBank_%s' % song, r
-
-  if not compare_with_orig(serializer, song):
-    raise Exception('compare failed')
-
-  return result
-
-if __name__ == "__main__":
-  if len(sys.argv) == 1:
-    for song in ['intro', 'indoor', 'ending']:
-      print_song(song, sys.stdout)  
-  else:
-    print_song(sys.argv[1], sys.stdout)
--- a/tables/compile_resources.py
+++ /dev/null
@@ -1,827 +1,0 @@
-import sys
-import text_compression
-import util
-from PIL import Image
-import yaml
-import tables
-import compile_music
-import array, hashlib, struct
-from util import cache
-import sprite_sheets
-import argparse
-import os
-
-def flatten(xss):
-    return [x for xs in xss for x in xs]
-  
-def invert_dict(xs):
-  return {s:i for i,s in xs.items()}
-
-assets = {}
-
-def add_asset_uint8(name, data):
-  assert name not in assets
-  assets[name] = ('uint8', bytes(array.array('B', data)))
-
-def add_asset_uint16(name, data):
-  assert name not in assets
-  assets[name] = ('uint16', bytes(array.array('H', data)))
-
-def add_asset_int8(name, data):
-  assert name not in assets
-  assets[name] = ('int8', bytes(array.array('b', data)))
-
-def add_asset_int16(name, data):
-  assert name not in assets
-  assets[name] = ('int16', bytes(array.array('h', data)))
-
-def add_asset_packed(name, data):
-  assert name not in assets
-  assets[name] = ('packed', pack_arrays(data))
-
-def print_map32_to_map16():
-  tab = {}
-  for line in open('map32_to_map16.txt'):
-    line = line.strip()
-    x, xs = line.split(':', 1)
-    tab[int(x)] = [int(t) for t in xs.split(',')]
-
-  def pack(*a):
-    res=[0] * 6
-    res[0] = a[0] & 0xff
-    res[1] = a[1] & 0xff
-    res[2] = a[2] & 0xff
-    res[3] = a[3] & 0xff
-    res[4] = (a[0] >> 8) << 4 | (a[1] >> 8)
-    res[5] = (a[2] >> 8) << 4 | (a[3] >> 8)
-    return res    
-
-  res = [[],[],[],[]]
-  for i in range(0, len(tab), 4):
-    for j in range(4):
-      res[j].extend(pack(tab[i][j], tab[i+1][j], tab[i+2][j], tab[i+3][j]))
-
-  add_asset_uint8('kMap32ToMap16_0', res[0])
-  add_asset_uint8('kMap32ToMap16_1', res[1])
-  add_asset_uint8('kMap32ToMap16_2', res[2])
-  add_asset_uint8('kMap32ToMap16_3', res[3])
-
-def compress_dialogue(fname, lang):
-  lines = []
-  for line in open(fname, encoding='utf8').read().splitlines():
-    a, b = line.split(': ', 1)
-    lines.append(b)
-  return text_compression.compress_strings(lines, lang)
-
-def compress_store(r):
-  rr = []
-  j, jend = 0, len(r)
-  while j < jend:
-    n = min(jend - j, 1024)
-    rr.append(0xe0 | (n - 1) >> 8)
-    rr.append((n - 1) & 0xff)
-    rr.extend(r[j:j+n])
-    j += n
-  rr.append(0xff)
-  return rr
-  
-# Pack arrays and determine automatically the index size
-def pack_arrays(arr):
-  if len(arr) == 0:
-    return b''
-  all_offs, offs = [], 0
-  for i in range(len(arr) - 1):
-    offs += len(arr[i])
-    all_offs.append(offs)
-  if offs < 65536 and len(arr) <= 8192:
-    return b''.join([struct.pack('H', i) for i in all_offs] + arr + [struct.pack('H', len(arr) - 1)])
-  else:
-    return b''.join([struct.pack('I', i) for i in all_offs] + arr + [struct.pack('H', 8192 + len(arr) - 1)])
-
-def print_images(args):
-  sprsheet = sprite_sheets.load_sprite_sheets() if args.sprites_from_png else None
-
-  all = []
-  for i in range(108):
-    if sprsheet != None and i < 103:
-      all.append(sprsheet.encode_sheet_in_snes_format(i))
-    elif i < 12:
-      all.append(bytes(ROM.get_bytes(tables.kCompSpritePtrs[i], 0x600)))   
-    else:
-      decomp, comp_len = util.decomp(tables.kCompSpritePtrs[i], ROM.get_byte, False, True)
-      all.append(bytes(ROM.get_bytes(tables.kCompSpritePtrs[i], comp_len)))
-  add_asset_packed('kSprGfx', all)
-
-  all = []
-  for i in range(len(tables.kCompBgPtrs)):
-    decomp, comp_len = util.decomp(tables.kCompBgPtrs[i], ROM.get_byte, False, True)
-    all.append(bytes(ROM.get_bytes(tables.kCompBgPtrs[i], comp_len)))
-  add_asset_packed('kBgGfx', all)
-
-def print_dialogue(args):
-  from text_compression import dialogue_filename, kLanguages
-
-  languages = ['us']
-  if args.languages:
-    for a in args.languages.split(','):
-      if a in languages or a not in kLanguages:
-        raise Exception(f'Language {a} is not valid')
-      name = dialogue_filename(a)
-      if not os.path.exists(name):
-        raise Exception(f'{name} not found. You need to extract it with --extract-dialogue using the ROM of that language.')
-      languages.append(a)
-
-  all_langs, all_fonts, mappings = [], [], []
-  for i, lang in enumerate(languages):
-    dict_packed = pack_arrays(text_compression.encode_dictionary(lang))
-    dialogue_packed = pack_arrays(compress_dialogue(dialogue_filename(lang), lang))
-    all_langs.append(pack_arrays([dict_packed, dialogue_packed]))
-    font_data, font_width = sprite_sheets.encode_font_from_png(lang)
-    all_fonts.append(pack_arrays([font_data, font_width]))
-    flags = text_compression.uses_new_format(lang)
-    if i != 0: flags |= 2 # no us rom match?
-    mappings.append(pack_arrays([lang.encode('utf8'), bytearray([i, i, flags])]))
-  add_asset_packed('kDialogue', all_langs)
-  add_asset_packed('kDialogueFont', all_fonts)
-  add_asset_packed('kDialogueMap', mappings)
-
-def print_misc(args):
-  add_asset_uint8('kOverworldMapGfx', ROM.get_bytes(0x18c000, 0x4000))
-  add_asset_uint8('kLightOverworldTilemap', ROM.get_bytes(0xac727, 4096))
-  add_asset_uint8('kDarkOverworldTilemap', ROM.get_bytes(0xaD727, 1024))
-
-  add_asset_uint16('kPredefinedTileData', ROM.get_words(0x9B52, 6438))
-
-  add_asset_uint16('kMap16ToMap8', ROM.get_words(0x8f8000, 3752 * 4))
-
-  add_asset_uint8('kGeneratedWishPondItem', ROM.get_bytes(0x888450, 256))
-  add_asset_uint8('kGeneratedBombosArr', ROM.get_bytes(0x8890FC, 256))
-
-  add_asset_uint8('kGeneratedEndSequence15', ROM.get_bytes(0x8ead25, 256))
-  add_asset_uint8('kEnding_Credits_Text', ROM.get_bytes(0x8EB178, 1989))
-  add_asset_uint16('kEnding_Credits_Offs', ROM.get_words(0x8EB93d, 394))
-  add_asset_uint16('kEnding_MapData', ROM.get_words(0x8EB038, 160))
-  add_asset_uint16('kEnding0_Offs', ROM.get_words(0x8EC2E1, 17))
-  add_asset_uint8('kEnding0_Data', ROM.get_bytes(0x8EBF4C, 917))
-
-  add_asset_uint16('kPalette_DungBgMain', ROM.get_words(0x9BD734, 1800))
-  add_asset_uint16('kPalette_MainSpr', ROM.get_words(0x9BD218, 120))
-
-  add_asset_uint16('kPalette_ArmorAndGloves', sprite_sheets.override_armor_palette or ROM.get_words(0x9BD308, 75))
-  add_asset_uint16('kPalette_Sword', ROM.get_words(0x9BD630, 12))
-  add_asset_uint16('kPalette_Shield', ROM.get_words(0x9BD648, 12))
-
-  add_asset_uint16('kPalette_SpriteAux3', ROM.get_words(0x9BD39E, 84))
-  add_asset_uint16('kPalette_MiscSprite_Indoors', ROM.get_words(0x9BD446, 77))
-  add_asset_uint16('kPalette_SpriteAux1', ROM.get_words(0x9BD4E0, 168))
-
-  add_asset_uint16('kPalette_OverworldBgMain', ROM.get_words(0x9BE6C8, 210))
-  add_asset_uint16('kPalette_OverworldBgAux12', ROM.get_words(0x9BE86C, 420))
-  add_asset_uint16('kPalette_OverworldBgAux3', ROM.get_words(0x9BE604, 98))
-  add_asset_uint16('kPalette_PalaceMapBg', ROM.get_words(0x9BE544, 96))
-  add_asset_uint16('kPalette_PalaceMapSpr', ROM.get_words(0x9BD70A, 21))
-  add_asset_uint16('kHudPalData', ROM.get_words(0x9BD660, 64))
-
-  add_asset_uint16('kOverworldMapPaletteData', ROM.get_words(0x8ADB27, 256))
-
-@cache
-def load_overworld_yaml(room):
-  return yaml.safe_load(open('overworld/overworld-%d.yaml' % room, 'r'))
-    
-def print_overworld():
-  r = []
-  for i in range(160):
-    addr = ROM.get_24(0x82F94D + i * 3)
-    decomp, comp_len = util.decomp(addr, ROM.get_byte, True, True)
-    r.append(bytes(ROM.get_bytes(addr, comp_len)))
-  add_asset_packed('kOverworld_Hibytes_Comp', r)
-
-  r = []
-  for i in range(160):
-    addr = ROM.get_24(0x82FB2D + i * 3)
-    decomp, comp_len = util.decomp(addr, ROM.get_byte, True, True)
-    r.append(bytes(ROM.get_bytes(addr, comp_len)))
-  add_asset_packed('kOverworld_Lobytes_Comp', r)
-
-def is_area_head(i):
-  return i >= 128 or ROM.get_byte(0x82A5EC + (i & 63)) == (i & 63)
-
-class OutArrays:
-  def __init__(self):
-    self.arrs = []
-  def add(self, type, name, size, initializer = None, items_per_line = 16):
-    t = [initializer] * size
-    self.arrs.append((type, name, t, items_per_line))
-    setattr(self, name, t)
-  def write(self):
-    for type, name, arr, items_per_line in self.arrs:
-      for i, j in enumerate(arr):
-        assert isinstance(j, int), (name, i, j, arr)
-      if type == 'uint8':
-        add_asset_uint8(name, arr)
-      elif type == 'uint16':
-        add_asset_uint16(name, arr)
-      elif type == 'int8':
-        add_asset_int8(name, arr)
-      elif type == 'int16':
-        add_asset_int16(name, arr)
-      else:
-        assert 0, type
-    
-def print_overworld_tables():
-  A = OutArrays()
-  
-  A.add('uint8', 'kOverworldMapIsSmall', 192, initializer = 0, items_per_line = 8)
-  A.add('uint8', 'kOverworldAuxTileThemeIndexes', 128, items_per_line = 8)
-  A.add('uint8', 'kOverworldBgPalettes', 136, items_per_line = 8)
-  A.add('uint16', 'kOverworld_SignText', 128, items_per_line = 8)
-  A.add('uint8', 'kOwMusicSets', 256, items_per_line = 8)
-  A.add('uint8', 'kOwMusicSets2', 96, items_per_line = 8)
-  
-  def get_music_byte(h, tag):
-    return tables.kMusicNamesRev[h['music'][tag]] | tables.kAmbientSoundNameRev[h['ambient'][tag]] << 4
-
-  def get_loadoffs(c, d):
-    x, y = c[0] >> 4, c[1] >> 4
-    x += d[0]
-    y += d[1]
-    return (y&0x3f) << 7 | (x&0x3f) << 1
-
-  def awrite(arr, area, key, value):
-    arr[key] = value
-    if area < 128 and not A.kOverworldMapIsSmall[area]:
-      arr[key + 1], arr[key + 8], arr[key + 9] = value, value, value
-      
-  loaded_areas = [(i, load_overworld_yaml(i)) for i in range(160) if is_area_head(i)]
-
-  for i,y in loaded_areas:
-    h = y['Header']
-    A.kOverworldMapIsSmall[i] = {'small':1, 'big':0}[h['size']]
-    if i < len(A.kOverworldAuxTileThemeIndexes): awrite(A.kOverworldAuxTileThemeIndexes, i, i, h['gfx'])
-    if i < len(A.kOverworldBgPalettes): awrite(A.kOverworldBgPalettes, i, i, h['palette'])
-    if i < len(A.kOverworld_SignText): awrite(A.kOverworld_SignText, i, i, h['sign_text'])
-    if i < 64:
-      awrite(A.kOwMusicSets, i, i, get_music_byte(h, 'beginning'))
-      awrite(A.kOwMusicSets, i, i + 64, get_music_byte(h, 'zelda'))
-      awrite(A.kOwMusicSets, i, i + 128, get_music_byte(h, 'sword'))
-      awrite(A.kOwMusicSets, i, i + 192, get_music_byte(h, 'agahnim'))
-    elif i < 64 + 96:
-      awrite(A.kOwMusicSets2, i, i - 64, get_music_byte(h, 'agahnim'))
-
-  for a in ['kBirdTravel_ScreenIndex', 'kBirdTravel_Map16LoadSrcOff', 'kBirdTravel_ScrollX',
-            'kBirdTravel_ScrollY', 'kBirdTravel_LinkXCoord', 'kBirdTravel_LinkYCoord',
-            'kBirdTravel_CameraXScroll', 'kBirdTravel_CameraYScroll']:
-    A.add('uint16', a, 17)
-  A.add('int8', 'kBirdTravel_Unk1', 17)
-  A.add('int8', 'kBirdTravel_Unk3', 17)
-  A.add('uint16', 'kWhirlpoolAreas', 8)
-
-  next_whirlpool_id = 0
-  for i, y in loaded_areas:
-    for t in y['Travel']:
-      if 'bird_travel_id' in t:
-        j = t['bird_travel_id']
-      else:
-        A.kWhirlpoolAreas[next_whirlpool_id] = t['whirlpool_src_area']
-        j = next_whirlpool_id + 9
-        next_whirlpool_id += 1
-      base_x, base_y = (i & 7) << 9, (i & 56) << 6
-      A.kBirdTravel_ScreenIndex[j] = i
-      A.kBirdTravel_Map16LoadSrcOff[j] = get_loadoffs(t['scroll_xy'], t['load_xy'])
-      A.kBirdTravel_ScrollX[j] = t['scroll_xy'][0] + base_x
-      A.kBirdTravel_ScrollY[j] = t['scroll_xy'][1] + base_y
-      A.kBirdTravel_LinkXCoord[j] = t['xy'][0] + base_x 
-      A.kBirdTravel_LinkYCoord[j] = t['xy'][1] + base_y
-      A.kBirdTravel_CameraXScroll[j] = t['camera_xy'][0] + base_x 
-      A.kBirdTravel_CameraYScroll[j] = t['camera_xy'][1] + base_y
-      A.kBirdTravel_Unk1[j] = t['unk'][0]
-      A.kBirdTravel_Unk3[j] = t['unk'][1]
-
-  A.add('uint16', 'kOverworld_Entrance_Area', 129)
-  A.add('uint16', 'kOverworld_Entrance_Pos', 129)
-  A.add('uint8', 'kOverworld_Entrance_Id', 129)
-
-  for i, y in loaded_areas:
-    for e in y['Entrances']:
-      j = e['index']
-      assert A.kOverworld_Entrance_Id[j] == None
-      A.kOverworld_Entrance_Area[j] = i
-      A.kOverworld_Entrance_Id[j] = e['entrance_id']
-      A.kOverworld_Entrance_Pos[j] = e['x'] << 1 | e['y'] << 7
-
-  A.add('uint16', 'kFallHole_Area', 19)
-  A.add('uint16', 'kFallHole_Pos', 19)
-  A.add('uint8', 'kFallHole_Entrances', 19)
-      
-  holes = []
-  for i, y in loaded_areas:
-    if 'Holes' not in y: continue
-    for e in y['Holes']:
-      x, y, j = e['x'], e['y'], e['entrance_id']
-      holes.append((j, x << 1 | ((y - 8) & 0x3f) << 7, i))
-  for i, (entrance, pos, area) in enumerate(sorted(holes)):
-    A.kFallHole_Area[i] = area
-    A.kFallHole_Pos[i] = pos
-    A.kFallHole_Entrances[i] = entrance
-
-  A.add('uint8', 'kExitData_ScreenIndex', 79)
-  for a in ['kExitDataRooms', 'kExitData_Map16LoadSrcOff', 'kExitData_ScrollX',
-            'kExitData_ScrollY', 'kExitData_XCoord', 'kExitData_YCoord',
-            'kExitData_CameraXScroll', 'kExitData_CameraYScroll']:
-    A.add('uint16', a, 79)
-  A.add('uint16', 'kExitData_NormalDoor', 79, initializer = 0)
-  A.add('uint16', 'kExitData_FancyDoor', 79, initializer = 0)
-  A.add('int8', 'kExitData_Unk1', 79)
-  A.add('int8', 'kExitData_Unk3', 79)
-
-  A.add('uint16', 'kSpExit_Top', 16, initializer = 0)
-  A.add('uint16', 'kSpExit_Bottom', 16, initializer = 0)
-  A.add('uint16', 'kSpExit_Left', 16, initializer = 0)
-  A.add('uint16', 'kSpExit_Right', 16, initializer = 0)
-  A.add('int16', 'kSpExit_Tab4', 16, initializer = 0)
-  A.add('int16', 'kSpExit_Tab5', 16, initializer = 0)
-  A.add('int16', 'kSpExit_Tab6', 16, initializer = 0)
-  A.add('int16', 'kSpExit_Tab7', 16, initializer = 0)
-  A.add('uint16', 'kSpExit_LeftEdgeOfMap', 16, initializer = 0)
-  A.add('uint8', 'kSpExit_Dir', 16, initializer = 0)
-  A.add('uint8', 'kSpExit_SprGfx', 16, initializer = 0)
-  A.add('uint8', 'kSpExit_AuxGfx', 16, initializer = 0)
-  A.add('uint8', 'kSpExit_PalBg', 16, initializer = 0)
-  A.add('uint8', 'kSpExit_PalSpr', 16, initializer = 0)
-  
-  for i, y in loaded_areas:
-    for e in y['Exits']:
-      j = e['index']
-      base_x, base_y = (i & 7) << 9, (i & 56) << 6
-      assert A.kExitData_ScreenIndex[j] == None
-      A.kExitData_ScreenIndex[j] = i
-      room = e['room']
-      A.kExitDataRooms[j] = e['room']
-      A.kExitData_Map16LoadSrcOff[j] = get_loadoffs(e['scroll_xy'], e['load_xy'])
-      A.kExitData_ScrollX[j] = e['scroll_xy'][0] + base_x
-      A.kExitData_ScrollY[j] = e['scroll_xy'][1] + base_y
-      A.kExitData_XCoord[j] = e['xy'][0] + base_x
-      A.kExitData_YCoord[j] = e['xy'][1] + base_y
-      A.kExitData_CameraXScroll[j] = e['camera_xy'][0] + base_x 
-      A.kExitData_CameraYScroll[j] = e['camera_xy'][1] + base_y
-      A.kExitData_Unk1[j] = e['unk'][0]
-      A.kExitData_Unk3[j] = e['unk'][1]
-      door = e.get('door')
-      if door != None:
-        if door[0] in ('bombable', 'wooden'):
-          A.kExitData_NormalDoor[j] = door[1] << 1 | door[2] << 7 | (0x8000 if door[0] == 'bombable' else 0)
-        elif door[0] in ('palace', 'sanctuary'):
-          A.kExitData_FancyDoor[j] = door[1] << 1 | door[2] << 7 | (0x8000 if door[0] == 'palace' else 0)
-        else:
-          assert e[0] == 'none'
-      se = e.get('special_exit')
-      if se:
-        j = room - 0x180
-        A.kSpExit_Dir[j] = se['dir'] * 2
-        A.kSpExit_SprGfx[j] = se['spr_gfx']
-        A.kSpExit_AuxGfx[j] = se['aux_gfx']
-        A.kSpExit_PalBg[j] = se['pal_bg']
-        A.kSpExit_PalSpr[j] = se['pal_spr']
-        A.kSpExit_Top[j] = se['top']
-        A.kSpExit_Bottom[j] = se['bottom']
-        A.kSpExit_Left[j] = se['left']
-        A.kSpExit_Right[j] = se['right']
-        A.kSpExit_LeftEdgeOfMap[j] = se['left_edge_of_map']
-        A.kSpExit_Tab4[j] = se['unk4']
-        A.kSpExit_Tab5[j] = se['unk5']
-        A.kSpExit_Tab6[j] = se['unk6']
-        A.kSpExit_Tab7[j] = se['unk7']
-
-
-  A.add('uint16', 'kOverworldSecrets_Offs', 128, initializer = None)
-  A.add('uint8', 'kOverworldSecrets', 0)
-  for i, y in loaded_areas:
-    if len(y['Items']):
-      assert i < 128
-      j = len(A.kOverworldSecrets)
-      awrite(A.kOverworldSecrets_Offs, i, i, j)
-      for e in y['Items']:
-        pos = e[0] << 1 | e[1] << 7
-        item = tables.kSecretNamesRev[e[2]]
-        A.kOverworldSecrets.extend([pos & 0xff, pos >> 8, item])
-      A.kOverworldSecrets.extend([0xff, 0xff])
-  for i in range(128):
-    if A.kOverworldSecrets_Offs[i] == None:
-      A.kOverworldSecrets_Offs[i] = len(A.kOverworldSecrets) - 2
-
-  A.add('uint16', 'kOverworldSpriteOffs', 144 * 3, initializer = 0)
-  A.add('uint8', 'kOverworldSprites', 0)
-  A.add('uint8', 'kOverworldSpriteGfx', 256)
-  A.add('uint8', 'kOverworldSpritePalettes', 256)
-  A.kOverworldSprites.append(0xff)
-  def do_sprite_range(start, end, stagename, sprite_stage_idxs, infostage):
-    for i, y in loaded_areas:
-      if i < start or i >= end: continue
-      info = y[stagename]['info']
-      if i < 128:
-        awrite(A.kOverworldSpriteGfx, i, (i & 63) + infostage * 64, info['gfx'])
-        awrite(A.kOverworldSpritePalettes, i, (i & 63) + infostage * 64, info['palette'])
-      if len(y[stagename]['sprites']):
-        for stage in sprite_stage_idxs:
-          A.kOverworldSpriteOffs[stage * 144 + i] = len(A.kOverworldSprites)
-        for e in y[stagename]['sprites']:
-          A.kOverworldSprites.extend([e[1], e[0], tables.kSpriteNamesRev[e[2]]])
-        A.kOverworldSprites.append(0xff)
-  do_sprite_range(0, 64, 'Sprites.Beginning', [0], 0)
-  do_sprite_range(0, 64, 'Sprites.FirstPart', [1], 1)
-  do_sprite_range(0, 64, 'Sprites.SecondPart', [2], 2)
-  do_sprite_range(64, 144, 'Sprites', [1, 2], 3)
-
-  A.write()
-  add_asset_uint8('kMap8DataToTileAttr', ROM.get_bytes(0x8E9459, 512))
-  add_asset_uint8('kSomeTileAttr', ROM.get_bytes(0x9bf110, 3824))
-
-
-def print_dungeon_map():
-  r, r2 = [], []
-  for i in range(14):
-    kSizes = [75, 125, 50, 75, 175, 75, 50, 75, 50, 200, 150, 75, 100, 200]
-    addr = 0xa0000 + ROM.get_word(0x8AF605 + i * 2)
-    b = ROM.get_bytes(addr, kSizes[i])
-    nonzero_bytes = len(b) - b.count(0xf)
-    r.append(bytes(b))
-    addr = 0xa0000 + ROM.get_word(0x8AFBE4 + i * 2)
-    b = ROM.get_bytes(addr, nonzero_bytes)
-    r2.append(bytes(b))
-    
-  add_asset_packed('kDungMap_FloorLayout', r)
-  add_asset_packed('kDungMap_Tiles', r2)
-
-
-@cache
-def load_dungeon_yaml(room):
-  return yaml.safe_load(open('dungeon/dungeon-%d.yaml' % room, 'r'))
-  
-def print_dungeon_sprites():
-  offsets=[0 for i in range(320)]
-  data = [0, 0xff]
-  for i in range(320):
-    y = load_dungeon_yaml(i)
-    sortmode = y['Header']['sort_sprites']
-    if len(y['Sprites']) == 0 and sortmode == 0:
-      continue
-    offsets[i] = len(data)
-    data.append(sortmode)
-    for s in y['Sprites']:
-      xx, yy, f, name = s[:4]
-      f = {'upper' : 0, 'lower' : 1}[f]
-      assert xx >= 0 and xx <= 0x1f
-      assert yy >= 0 and yy <= 0x1f
-
-      # parse out subcode
-      ss = 0
-      if len(name) > 2 and name[2] == '.':
-        j = name.index('-')
-        ss = int(name[3:j])
-        name = name[0:2] + name[j:]
-
-      name = tables.kSpriteName2Idx[name]
-      if name >= 0x100:
-        data.extend((f << 7 | 0 << 5 | yy, xx | 7 << 5, name & 0xff))
-      else:
-        data.extend((f << 7 | (ss >> 3) << 5 | yy, xx | (ss & 7) << 5, name))
-      if len(s) == 5:
-        kDropTypesToCode = {'drop_key' : [0xfe, 0, 0xe4], 'drop_big_key' : [0xfd, 0, 0xe4]}
-        data.extend(kDropTypesToCode[s[-1]])
-        
-    data.append(0xff)
-  add_asset_uint8('kDungeonSprites', data)
-  add_asset_uint16('kDungeonSpriteOffs', offsets)
-
-def print_dungeon_secrets():
-  result = [None] * 640
-  for i in range(320):
-    y = load_dungeon_yaml(i)
-    def fixone(s):
-      x, y, data = s[0], s[1], tables.kSecretNamesRev[s[2]]
-      pos = (x + y * 64) * 2
-      return [pos & 0xff, pos >> 8, data]
-    if len(y['Secrets']):
-      result[i*2+0] = len(result) & 0xff
-      result[i*2+1] = len(result) >> 8
-      for a in y['Secrets']:
-        result.extend(fixone(a))
-        
-      result.extend([0xff, 0xff])
-  for i in range(320):
-    if result[i*2+0] == None:
-      l = (len(result) - 2)
-      result[i*2+0] = l & 0xff
-      result[i*2+1] = l >> 8
-  add_asset_uint8('kDungeonSecrets', result)
-
-def append_scan_bytes(big, little):
-  for n in range(len(little), -1, -1):
-    if n == 0 or big[-n:] == little[:n]:
-      offset = len(big) - n
-      big.extend(little[n:])
-      return offset
-  
-def print_dungeon_rooms():
-  def print_layer(objs, doors):
-    door_offset = None
-    for o in objs:
-      if o['n'] in tables.kType0Names_rev:
-        index = tables.kType0Names_rev[o['n']] # 0 - 0xf7
-        w = int(o['s'][0])
-        h = int(o['s'][2])
-        assert w >= 0 and w <= 3 and h >= 0 and h <= 3
-        p0 = o['x'] * 4 + w
-        p1 = o['y'] * 4 + h
-        p2 = index
-      elif o['n'] in tables.kType1Names_rev:
-        index = tables.kType1Names_rev[o['n']]
-        p0 = o['x'] * 4 + (index >> 0 & 3)
-        p1 = o['y'] * 4 + (index >> 2 & 3)
-        p2 = (index >> 4) + 0xf8
-      elif o['n'] in tables.kType2Names_rev:
-        index = tables.kType2Names_rev[o['n']]
-        x, y = o['x'], o['y']
-        #111111xx xxxxyyyy yyiiiiii
-        p0 = 0xfc + (x >> 4 & 3)
-        p1 = (x << 4 & 0xf0) | (y >> 2 & 0x0f)
-        p2 = index | (y << 6 & 0xc0)
-      else:
-        raise Exception('item %s not found' % o['n'])
-      data.extend((p0, p1, p2))
-    if doors != None:
-      data.extend([0xf0, 0xff])
-      door_offset = len(data)
-      for d in doors:
-        data.extend((d['dir'] | d['pos'] << 4, d['type']))
-    data.extend([0xff, 0xff])
-    return door_offset
-
-  def get_room_header(y):
-    h = y['Header']
-    p7 = h['hole0_dest'][1] | h['stair0_dest'][1] << 2 | h['stair1_dest'][1] << 4 | h['stair2_dest'][1] << 6
-    p8 = h['stair3_dest'][1]
-    return [tables.kBg2_rev[h['bg2']] << 5 | tables.kCollisionNames_rev[h['collision']] << 2 | h['lights_out'],
-            h['palette'],
-            h['blockset'],
-            h['enemyblk'],
-            tables.kEffectNames_rev[h['effect']],
-            tables.kTagNames_rev[h['tag0']],
-            tables.kTagNames_rev[h['tag1']],
-            p7,
-            p8,
-            h['hole0_dest'][0],
-            h['stair0_dest'][0],
-            h['stair1_dest'][0],
-            h['stair2_dest'][0],
-            h['stair3_dest'][0]]
-
-  data = []
-  offsets = [0]*320
-  door_offsets = [0]*320
-  room_headers = []
-  header_offsets = [0] * 320
-  chests = []
-  entrances = [None] * 133
-  starting_points = [None] * 7
-  sign_texts = [0] * 320
-  pits_hurt_player = []
-  
-  for i in range(320):
-    y = load_dungeon_yaml(i)
-    h = y['Header']
-    if h['pits_hurt_player']: pits_hurt_player.append(i)
-    offsets[i]=len(data)
-    data.append(h['floor1'] + h['floor2'] * 16)
-    data.append(h['layout'] * 4 + h['start_quadrant'])
-    print_layer(y['Layer1'], y.get('Layer1.doors'))
-    print_layer(y['Layer2'], y.get('Layer2.doors'))
-    door_offsets[i] = print_layer(y['Layer3'], y.get('Layer3.doors') or [])
-    header_offsets[i] = append_scan_bytes(room_headers, get_room_header(y))
-    sign_texts[i] = h['tele_msg']
-    for a in y['Chests']:
-      if isinstance(a, int):
-        chests.extend([i & 0xff, i >> 8, a])
-      else:
-        assert a.endswith('!')
-        chests.extend([i & 0xff, (i >> 8) | 0x80, int(a[:-1])])
-    for e in y['Entrances']:
-      a = e['entrance_index']
-      e['room'] = i
-      assert entrances[a] == None
-      entrances[a] = e
-    if 'StartingPoints' in y:
-      for e in y['StartingPoints']:
-        a = e['starting_point_index']
-        e['room'] = i
-        assert starting_points[a] == None
-        starting_points[a] = e
-  for i in range(133):
-    if entrances[i] == None:
-      raise Exception('Entrance %d not defined' % i)
-  for i in range(7):
-    if starting_points[i] == None:
-      raise Exception('Starting point %d not defined' % i)
-
-  def print_entrance_info(entrances, prefix):
-    def get_rc(a):
-      rep, room, quads, xy = a.get('repair_scroll_bounds'), a['room'], a['quadrants'], a['player_xy']
-      if rep == None: rep = (0, 0, 0, 0, 0, 0, 0, 0)
-      base_x = (room & 0xf) * 2
-      base_y = (room >> 4) * 2
-      ym = (xy[1] & 0x100) >> 8
-      xm = (xy[0] & 0x100) >> 8
-      qqq = xm if room >= 242 and quads[0] == 'single_x' else 0
-      l = [base_y + ym, base_y, base_y + ym, base_y + 1,
-           base_x + xm, base_x + qqq, base_x + xm, base_x + qqq + 1]
-      return [a+b for a,b in zip(l, rep)]
-    def get_palace(a):
-      i = tables.kPalaceNames.index(a)
-      return -1 if i == 0 else (i - 1) * 2
-    def get_quadrant1(a):
-      return ['single_x', 'double_x'].index(a[0]) * 0x20 + ['single_y', 'double_y'].index(a[1]) * 0x2
-    def get_quadrant2(a):
-      kScrollNames = { 'upper_left' : 0, 'lower_left' : 2, 'upper_right' : 16, 'lower_right' : 18 }
-      return kScrollNames[a[2]]
-    def get_exit_door(a):
-      if a[0] == 'none': return 0
-      if a[0] == 'none_0xffff': return 65535
-      return ['wooden', 'bombable'].index(a[0]) << 15 | a[1] << 1 | a[2] << 7
-            
-    add_asset_uint16(prefix+'rooms', [a['room'] for a in entrances])
-    add_asset_uint8(prefix+'relativeCoords', flatten([get_rc(a) for a in entrances]))
-    def get_base_x(a): return ((a['room'] & 0x00f) << 9)
-    def get_base_y(a): return ((a['room'] & 0x1f0) << 5)
-    add_asset_uint16(prefix+'scrollX', [a['scroll_xy'][0] + get_base_x(a) for a in entrances])
-    add_asset_uint16(prefix+'scrollY', [a['scroll_xy'][1] + get_base_y(a) for a in entrances])
-    add_asset_uint16(prefix+'playerX', [a['player_xy'][0] + get_base_x(a) for a in entrances])
-    add_asset_uint16(prefix+'playerY', [a['player_xy'][1] + get_base_y(a) for a in entrances])
-    add_asset_uint16(prefix+'cameraX', [a['camera_xy'][0] for a in entrances])
-    add_asset_uint16(prefix+'cameraY', [a['camera_xy'][1] for a in entrances])
-    add_asset_uint8(prefix+'blockset', [a['blockset'] for a in entrances])
-    add_asset_int8(prefix+'floor', [a['floor'] for a in entrances])
-    add_asset_int8(prefix+'palace', [get_palace(a['palace']) for a in entrances])
-    add_asset_uint8(prefix+'doorwayOrientation', [a['doorway_orientation'] for a in entrances])
-    add_asset_uint8(prefix+'startingBg', [a['plane'] + a['ladder_level'] * 16 for a in entrances])
-    add_asset_uint8(prefix+'quadrant1', [get_quadrant1(a['quadrants']) for a in entrances])
-    add_asset_uint8(prefix+'quadrant2', [get_quadrant2(a['quadrants']) for a in entrances])
-    add_asset_uint16(prefix+'doorSettings', [get_exit_door(a['house_exit_door']) for a in entrances])
-    if prefix == 'kStartingPoint_':
-      add_asset_uint8(prefix+'entrance', [a['associated_entrance_index'] for a in entrances])
-    m = invert_dict(tables.kMusicNames)
-    add_asset_uint8(prefix+'musicTrack', [m[a['music']] for a in entrances])
-    
-
-  add_asset_uint8('kDungeonRoom', data)
-  add_asset_uint16('kDungeonRoomOffs', offsets)
-  add_asset_uint16('kDungeonRoomDoorOffs', door_offsets)
-  add_asset_uint8('kDungeonRoomHeaders', room_headers)
-  add_asset_uint16('kDungeonRoomHeadersOffs', header_offsets)
-  add_asset_uint8('kDungeonRoomChests', chests)
-  add_asset_uint16('kDungeonRoomTeleMsg', sign_texts)
-  add_asset_uint16('kDungeonPitsHurtPlayer', pits_hurt_player)
-  
-  print_entrance_info(entrances, 'kEntranceData_')
-  print_entrance_info(starting_points, 'kStartingPoint_')
-
-  data = []
-  offsets = [0] * 8
-  default_yaml = yaml.safe_load(open('dungeon/default_rooms.yaml', 'r'))
-  for i in range(len(offsets)):
-    offsets[i] = len(data)
-    print_layer(default_yaml['Default%d' % i], None)
-  add_asset_uint8('kDungeonRoomDefault', data)
-  add_asset_uint16('kDungeonRoomDefaultOffs', offsets)
-
-  data = []
-  offsets = [0] * 19
-  overlay_yaml = yaml.safe_load(open('dungeon/overlay_rooms.yaml', 'r'))
-  for i in range(len(offsets)):
-    offsets[i] = len(data)
-    print_layer(overlay_yaml['Overlay%d' % i], None)
-  add_asset_uint8('kDungeonRoomOverlay', data)
-  add_asset_uint16('kDungeonRoomOverlayOffs', offsets)
-
-  print_dungeon_secrets()
-
-  add_asset_uint16('kDungAttrsForTile_Offs', ROM.get_words(0x8e9000, 21))
-  add_asset_uint8('kDungAttrsForTile', ROM.get_bytes(0x8e902a, 1024))
-
-  add_asset_uint16('kMovableBlockDataInit', ROM.get_words(0x84f1de, 198))
-  add_asset_uint16('kTorchDataInit', ROM.get_words(0x84F36A, 144))
-  add_asset_uint16('kTorchDataJunk', ROM.get_words(0x84F48a, 48))
- 
-def print_enemy_damage_data():
-  decomp, comp_len = util.decomp(0x83e800, ROM.get_byte, True, True)
-  add_asset_uint8('kEnemyDamageData', decomp)
-
-def print_tilemaps():
-  kSrcs = [0xcdd6d, 0xce7bf, 0xce2a8, 0xce63c, 0xce456, 0xeda9c]
-  def decode_one(p):
-    p_org = p
-    while not (ROM.get_byte(p) & 0x80):
-      is_memset = ROM.get_byte(p+2) & 0x40
-      len = ((ROM.get_byte(p+2)*256+ROM.get_byte(p+3))&0x3fff) + 1
-      p += 4
-      p += 2 if is_memset else len
-    return p - p_org + 1
-  for i,s in enumerate(kSrcs):
-    l = decode_one(s)
-    add_asset_uint8('kBgTilemap_%d' % i, ROM.get_bytes(s, l))
-
-def print_link_graphics():
-  image = Image.open('linksprite.png')
-  data = image.tobytes()
-  def encode_4bit_sprite(data, offset, pitch):
-    b = [0] * 32
-    for y in range(8):
-      for x in range(8):
-        v = data[offset + y * pitch + x]
-        b[y*2+0] |= (v & 1) << (7-x)
-        b[y*2+1] |= (v >> 1 & 1) << (7-x)
-        b[y*2+16] |= (v >> 2 & 1) << (7-x)
-        b[y*2+17] |= (v >> 3 & 1) << (7-x)
-    return bytes(b)
-  b = b''
-  for y in range(56):
-    for x in range(16):
-      b += encode_4bit_sprite(data, y * 128 * 8 + x * 8, 128)
-  add_asset_uint8('kLinkGraphics', b)
-
-def print_sound_banks():
-  for song in ['intro', 'indoor', 'ending']:
-    name, data = compile_music.print_song(song)
-    add_asset_uint8(name, data)
-
-def print_all(args):
-  print_sound_banks()
-  print_dungeon_rooms()
-  print_enemy_damage_data()
-  print_link_graphics()
-  print_dungeon_sprites()
-  print_map32_to_map16()
-  print_images(args)
-  print_misc(args)
-  print_dialogue(args)
-  print_dungeon_map()
-  print_tilemaps()
-  print_overworld()
-  print_overworld_tables()
-
-def write_assets_to_file(print_header = False):
-  key_sig = b''
-  all_data = []
-  if print_header:
-    print('''#pragma once
-#include "types.h"
-
-enum {
-  kNumberOfAssets = %d
-};
-extern const uint8 *g_asset_ptrs[kNumberOfAssets];
-extern uint32 g_asset_sizes[kNumberOfAssets];
-extern MemBlk FindInAssetArray(int asset, int idx);
-''' % len(assets))
-
-  for i, (k, (tp, data)) in enumerate(assets.items()):
-    if print_header:
-      if tp == 'packed':
-        print('#define %s(idx) FindInAssetArray(%d, idx)' % (k, i))
-      else:
-        print('#define %s ((%s*)g_asset_ptrs[%d])' % (k, tp, i))
-        print('#define %s_SIZE (g_asset_sizes[%d])' % (k, i))
-    key_sig += k.encode('utf8') + b'\0'
-    all_data.append(data)
-
-  assets_sig = b'Zelda3_v0     \n\0' + hashlib.sha256(key_sig).digest()
-
-  if print_header:
-    print('#define kAssets_Sig %s' % ", ".join((str(a) for a in assets_sig)))
-
-  hdr = assets_sig + b'\x00' * 32 + struct.pack('II', len(all_data), len(key_sig))
-
-  encoded_sizes = array.array('I', [len(i) for i in all_data])
-
-  file_data = hdr + encoded_sizes + key_sig
-
-  for v in all_data:
-    while len(file_data) & 3:
-      file_data += b'\0'
-    file_data += v
-
-  open('zelda3_assets.dat', 'wb').write(file_data)
-
-def main(args):
-  print_all(args)
-  write_assets_to_file(args.print_assets_header)
-
-if __name__ == "__main__":
-  ROM = util.load_rom(sys.argv[1] if len(sys.argv) >= 2 else None)
-  class DefaultArgs:
-    sprites_from_png = False
-    languages = None
-    print_assets_header = False
-  main(DefaultArgs())
-else:
-  ROM = util.ROM
-
--- a/tables/decode_music.py
+++ /dev/null
@@ -1,471 +1,0 @@
-import hashlib
-import array
-import heapq, sys
-import yaml
-import time
-import util, brr_tools
-
-
-def load_sound_bank(rom, ea, mem_in = None):
-  memory = list(mem_in) if mem_in else [None]*65536
-  j =0 
-  while True:
-    numbytes = rom.get_word(ea)
-    target = rom.get_word(ea+2)
-    if numbytes==0:
-#      print('Entry point = 0x%x' % target)
-      return memory, target
-    print('# Copy %d bytes to 0x%x' % (numbytes, target))
-    ea += 4
-    for i in range(numbytes):
-      memory[target+i] = rom.get_byte(ea)
-      ea += 1
-      if (ea & 0xffff) < 0x8000:
-        ea += 0x8000
-    j += 1
-    if j > 256:
-      break
-
-def get_byte(ea):
-  return memory[ea]
-
-def get_word(ea):
-  return get_byte(ea) | get_byte(ea + 1) * 256
-
-
-# lightworld
-# Copy 11694 bytes to 0xd000
-# Copy 1672 bytes to 0x2b00
-
-
-# indoor
-# Copy 11455 bytes to 0xd000
-# Copy 1292 bytes to 0x2b00
-
-def to_str(s):
-  if isinstance(s, str):
-    return s
-  if isinstance(s, int):
-    return str(s)
-  return s.name
-
-
-class Song:
-  name = 'Song'
-  def __str__(self):
-    s = '# Song index %d\n' % self.index
-    s += '[Song_0x%x]\n' % (self.ea)
-    s += "".join(x.name + '\n' for x in self.phrases)
-    return s
-
-class SongList:
-  name = 'SongList'
-  def __str__(self):
-    s = '[SongList_0x%x]\n' % (self.ea)
-    s += "".join(('None' if x == None else x.name) + '\n' for x in self.songs)
-    return s
-
-class Phrase:
-  name = 'Phrase'
-  def __str__(self):
-    s = '[Phrase_0x%x]\n' % (self.ea)
-    s += "".join(('None' if x == None else x.name) + '\n' for x in self.patterns)
-    return s
-
-class Pattern:
-  name = 'Pattern'
-  def __str__(self):
-    r = '[Pattern_0x%x]\n' % (self.ea)
-    last_len = None
-    for a in self.lines:
-      s = ''
-      if len(a) == 4:
-        s += a[0] + " " + " ".join(map(to_str, a[1]))
-      else:
-        s += '%s' % (a[0])
-
-        if a[-2] != None:
-          s += ' %2d' % a[-2]
-          last_len = a[-2]
-        else:
-          s += ' --'# % last_len
-
-        if a[-1] != None:
-          s += ' %2x' % a[-1]
-        else:
-          s += ' --'
-
-      r += s + '\n'
-    return r
-  
-class PhraseLoop:
-  name = 'PhraseLoop'
-  def __init__(self, loops, jmp):
-    self.loops = loops
-    self.jmp = jmp
-    self.name = 'PhraseLoop %d %d' % (self.loops, self.jmp)
-  def __str__(self):
-    return self.name
-
-types_for_ea = {}
-pqueue_by_ea = []
-
-def reset_queues():
-  global types_for_ea, pqueue_by_ea
-  types_for_ea = {}
-  pqueue_by_ea = []
-
-def get_type_for_ea(ea, tp):
-  if ea == 0:
-    return None
-  assert(ea >= 256), ea
-  a = types_for_ea.get(ea)
-  if a != None:
-    assert type(a)==tp, (type(a), tp, '0x%x' % ea)
-    return a
-  a = tp()
-  a.ea = ea
-  a.name = '%s_0x%x' % (a.name, ea)
-  types_for_ea[ea] = a
-  if get_byte(ea) != None:
-    heapq.heappush(pqueue_by_ea, (ea, a))
-    a.is_imported = False
-  else:
-    a.is_imported = True
-  return a
-
-kEffectByteLength = [1, 1, 2, 3, 0, 1, 2, 1, 2, 1, 1, 3, 0, 1, 2, 3, 1, 3, 3, 0, 1, 3, 0, 3, 3, 3, 1]
-kEffectNames = ['Instrument', 'Pan', 'PanFade', 'Vibrato', 'VibratoOff',
-                'SongVolume', 'SongVolumeFade', 'Tempo', 'TempoFade',
-                'Transpose', 'ChannelTranpose', 'Tremolo', 'TremoloOff',
-                'Volume', 'VolumeFade', 'Call', 'VibratoFade',
-                'PitchEnvelopeTo', 'PitchEnvelopeFrom', 'PitchEnvelopeOff',
-                'FineTune', 'EchoEnable', 'EchoOff', 'EchoSetup', 'EchoVolumeFade',
-                'PitchSlide', 'PercussionDefine']
-assert(len(kEffectNames) == 27)
-
-def note_to_str(note):
-  kKeys  = ['C-', 'C#', 'D-', 'D#', 'E-', 'F-', 'F#', 'G-', 'G#', 'A-', 'A#', 'B-']
-  if note >= 72:
-    if note == 72:
-      return '-+-' # don't write kof
-    elif note == 73:
-      return '---' # want kof
-    else:
-      assert 0
-  octave = note / 12
-  key = note % 12
-  return '%s%d' % (kKeys[key], octave + 1)
-
-def get_pattern(ea):
-  if ea == 0:
-    return None
-  pattern = get_type_for_ea(ea, Pattern)
-  return pattern
-
-def get_song(ea, index):
-  song = get_type_for_ea(ea, Song)
-  if song:
-    song.index = index
-  return song
-
-def get_phrase(ea):
-  phrase = get_type_for_ea(ea, Phrase)
-  return phrase
-
-def decode_pattern(pattern, next_ea):
-  ea = pattern.ea
-  pattern.lines = []
-  start_ea = ea
-  while True:
-#    print('0x%x 0x%x' % (ea, start_ea))
-#    assert ea != 0x28f0
-    if ea != start_ea and ea == next_ea:
-      pattern.lines.append(('Fallthrough', (), None, None))
-      return
-    note_length, volstuff = None, None
-    cmd = get_byte(ea); ea += 1
-    if cmd == 0:
-      break
-    if not (cmd & 0x80):
-      note_length = cmd
-      cmd = get_byte(ea); ea += 1
-      if not (cmd & 0x80):
-        volstuff = cmd
-        cmd = get_byte(ea); ea += 1
-    if cmd == 0xef:
-      addr = get_word(ea)
-      loops = get_byte(ea + 2)
-      ea += 3
-      pattern.lines.append((kEffectNames[cmd-0xe0], (get_pattern(addr), loops), note_length, volstuff))
-    elif cmd >= 0xe0:
-      assert note_length == None and volstuff == None, (note_length, volstuff)
-      x = kEffectByteLength[cmd - 0xe0]
-      args = [get_byte(ea+i) for i in range(x)]
-      ea += x
-      pattern.lines.append((kEffectNames[cmd-0xe0], args, note_length, volstuff))
-    else:
-      assert(cmd & 0x80)
-      pattern.lines.append((note_to_str(cmd & 0x7f), note_length, volstuff))
-
-  return pattern
-
-def decode_phrase(phrase):
-  phrase.patterns = [get_pattern(get_word(phrase.ea + i * 2)) for i in range(8)]
-
-def decode_song(song):
-  ea = song.ea
-  song.phrases = []
-  ea_org = ea
-  eas_in_phrase = []
-  while True:
-    eas_in_phrase.append(ea)
-    phrase = get_word(ea)
-    if phrase == 0:
-      break
-    if phrase < 0x100:
-      assert phrase != 0x80 and phrase != 0x81
-      tgt = get_word(ea + 2)
-      assert tgt in eas_in_phrase
-      song.phrases.append(PhraseLoop(phrase, (tgt - ea) // 2))
-      ea += 4                                     
-    else:
-      song.phrases.append(get_phrase(phrase))
-      ea += 2
-  return song
-
-def decode_any(what, next_ea):
-  if isinstance(what, Song):
-    decode_song(what)
-  elif isinstance(what, SongList):
-    pass # no need
-  elif isinstance(what, Phrase):
-    decode_phrase(what)
-  elif isinstance(what, Pattern):
-    decode_pattern(what, next_ea)
-  else:
-    assert 0
-
-def get_song_list(ea, num):
-  song_list = get_type_for_ea(ea, SongList)
-  song_list.songs  = [get_song(get_word(ea + i * 2), i) for i in range(num)]    
-
-def load_song(ROM, song):
-  global memory, SONGS_IN_BANK
-  reset_queues()
-  if song == 'intro':
-    memory, entry_point = load_sound_bank(ROM, 0x998000) # intro
-    SONGS_IN_BANK = (get_word(0xd000) - 0xd000) // 2
-  elif song == 'lightworld':
-    memory, entry_point = load_sound_bank(ROM, 0x9a9ef5) # lw
-    SONGS_IN_BANK = (get_word(0xd000) - 0xd000) // 2
-  elif song == 'indoor':
-    memory, entry_point = load_sound_bank(ROM, 0x9b8000) # indoor
-    SONGS_IN_BANK = (0xd046 - 0xd000) // 2
-  elif song == 'ending':
-    memory, entry_point = load_sound_bank(ROM, 0x9ad380) # ending
-    SONGS_IN_BANK = (0xd046 - 0xd000) // 2
-
-
-def print_song(song, f):
-  get_song_list(0xd000, SONGS_IN_BANK)
-  if song in ('intro', 'lightworld'):
-    get_phrase(0xD878)
-    get_phrase(0xD8A8)
-    get_phrase(0xD8B8)
-    get_phrase(0xDf11)
-    get_phrase(0xe37c)
-  if song == 'indoor':
-    get_phrase(0xDc5e)
-    get_phrase(0xDc6e)
-    get_pattern(0xe905)
-    get_phrase(0xe94a)
-  if song == 'ending':
-    get_phrase(0x2a10)    
-  while len(pqueue_by_ea):
-    _, item = heapq.heappop(pqueue_by_ea)
-    decode_any(item, pqueue_by_ea[0][0] if len(pqueue_by_ea) else None)
-  for a, b in sorted(types_for_ea.items()):
-    if not b.is_imported:
-      print(b, file = f)
-
-
-def dump_brr_audio():
-  def decode_brr(snd):
-    start, loop_start = get_word(0x3c00 + snd * 4), get_word(0x3c00 + snd * 4 + 2)
-    r = brr_tools.decode_brr(lambda x: get_byte(start+x))
-    return r, [get_byte(start+x) for x in range(len(r)//16 * 9)], get_byte(start)&0x2 != 0
-  for audio_idx in range(25):
-    sound_data, brr_data, brr_repeat = decode_brr(audio_idx)
-    open('sound/sound%d.pcm.brr' % audio_idx, 'wb').write(bytes(brr_data))
-    open('sound/sound%d.pcm' % audio_idx, 'wb').write(sound_data)
-
-def dump_music_info():
-  music_info = {}
-  kDupSamples = {10 : 9, 20 : 19}
-  music_info['samples'] = []
-  for audio_idx in range(25):
-    start, rep = get_word(0x3c00 + audio_idx * 4), get_word(0x3c00 + audio_idx * 4 + 2)
-    sample_info = {
-      'file' : 'sound/sound%d.pcm' % kDupSamples.get(audio_idx, audio_idx)
-    }
-    if get_byte(start) & 2:
-      sample_info['repeat'] = (rep - start) // 9 * 16
-    music_info['samples'].append(sample_info)
-
-  def add_sustain_decay_etc(ea, info):
-    adsr1, adsr2, gain = get_byte(ea), get_byte(ea + 1), get_byte(ea + 2)
-    info['decay'] = (adsr1 >> 4) & 7
-    info['attack'] = adsr1 & 0xf
-    info['sustain_level'] = adsr2 >> 5
-    info['sustain_rate'] = adsr2 & 0x1f
-    info['vxgain'] = gain  
-
-  music_info['instruments'] = []
-  for i in range(25):
-    ea = 0x3d00 + i * 6
-    adsr1, adsr2 = get_byte(ea + 1), get_byte(ea + 2)
-    info = {
-      'sample' : get_byte(ea),
-    }
-    add_sustain_decay_etc(ea + 1, info)
-    info['pitch_base'] = get_byte(ea + 4) << 8 | get_byte(ea + 5)
-    music_info['instruments'].append(info)
-
-  music_info['note_gate_off'] = [get_byte(i) for i in range(0x3D96, 0x3D96 + 8)]
-  music_info['note_volume'] = [get_byte(i) for i in range(0x3D9E, 0x3D9E + 16)]
-
-  music_info['sfx_instruments'] = []
-
-  for i in range(25):
-    ea = 0x3e00 + i * 9
-    info = {
-      'voll' : get_byte(ea),
-      'volr' : get_byte(ea + 1),
-      'pitch' : get_word(ea + 2),
-      'sample' : get_byte(ea + 4)
-    }
-    add_sustain_decay_etc(ea + 5, info)
-    info['pitch_base'] = get_byte(ea + 8)
-    music_info['sfx_instruments'].append(info)  
-
-  s = yaml.dump(music_info, default_flow_style=None, sort_keys=False)
-  open('music_info.yaml', 'w').write(s)
-
-def decode_sfx(ea, next_addr):
-  r = []
-  while True:
-    if ea == next_addr:
-      r.append(('Fallthrough', ))
-      return r
-    b = get_byte(ea); ea += 1
-    if b == 0:
-      return r
-    note_length = None
-    volume_left, volume_right = None, None
-    if not (b & 0x80):
-      note_length = b
-      b = get_byte(ea); ea += 1
-      if not (b & 0x80):
-        volume_left, volume_right = b, None
-        b = get_byte(ea); ea += 1
-        if not b & 0x80:
-          volume_right = b
-          b = get_byte(ea); ea += 1
-    if b == 0xe0:
-      assert note_length == None and volume_left == None and volume_right == None, ea
-      b = get_byte(ea); ea += 1
-      r.append(('SetInstrument %d' % b, ))
-    elif b == 0xf9:
-      #assert note_length == None and volume_left == None and volume_right == None, ea
-      b = get_byte(ea); ea += 1
-      b0, b1, b2 = get_byte(ea), get_byte(ea+1), get_byte(ea+2); ea += 3
-      r.append(('PitchSlide %d %d %d' % (b0, b1, b2), note_to_str(b & 0x7f), note_length, volume_left, volume_right))
-    elif b == 0xf1:
-      #assert note_length == None and volume_left == None and volume_right == None, ea
-      b0, b1, b2 = get_byte(ea), get_byte(ea+1), get_byte(ea+2); ea += 3
-      r.append(('PitchSlide %d %d %d' % (b0, b1, b2), None, note_length, volume_left, volume_right))
-    elif b == 0xff:
-      assert note_length == None and volume_left == None and volume_right == None, ea
-      r.append(('Restart',))
-      return r
-    else:
-      r.append((None, note_to_str(b & 0x7f), note_length, volume_left, volume_right))
-
-def print_all_sfx(f):
-  items = set()
-  def add_sfx_top(base, num, name):
-    print('[%s_0x%x]' % (name, base), file = f)
-    next_ea = base + num * 2
-    echo_ea = next_ea + num
-    for i in range(num):
-      r = []
-      ea = get_word(base + i * 2)
-      if ea == 0:
-        t = 'None'
-      else:
-        items.add(ea)
-        t = 'Sfx_0x%x' % ea
-      if name == 'SfxPort1':
-        print('%s,%d' % (t, get_byte(next_ea + i)), file = f)
-      else:
-        print('%s,%d,%d' % (t, get_byte(next_ea + i), get_byte(echo_ea + i)), file = f)
-    print(file = f)
-  add_sfx_top(0x17c0, 32, 'SfxPort1')
-  add_sfx_top(0x1820, 63, 'SfxPort2')
-  add_sfx_top(0x191c, 63, 'SfxPort3')
-  items.add(0x1a5b)
-  items.add(0x1d1c)
-  items.add(0x1ee2)
-  items.add(0x1f13)
-  items.add(0x1f1c)
-  items.add(0x252d)
-  items.add(0x2533)
-  items.add(0x26a2)
-  items.add(0x277e)
-  items.add(0x279d)
-  items.add(0x27c9)
-  items.add(0x27f6)
-  items.add(0x2807)
-  items.add(0x2818)
-  items.add(0x2829)
-  items.add(0x2831)
-  items.add(0x284a)
-  items = sorted(list(items))
-  for i in range(len(items)):
-    print('[Sfx_0x%x]' % items[i], file = f)
-    next_addr = items[i + 1] if i + 1 < len(items) else 0
-    rs = decode_sfx(items[i], next_addr)
-    for r in rs:
-      if len(r) == 5:
-        aa = '.  ' if r[1] == None else r[1]
-        bb = '--' if r[2] == None else '%2d' % r[2]
-        cc = '---' if r[3] == None else '%3d' % r[3]
-        dd = '---' if r[4] == None else '%3d' % r[4]
-        r0 = '' if r[0] == None else ' ' + r[0]
-        print('%s %s %s %s%s' % (aa, bb, cc, dd, r0), file = f)
-      else:
-        print(r[0], file = f)
-    print(file = f)
-
-def extract_sound_data(rom):
-  load_song(rom, 'intro')
-  print_song('intro', open('sound_intro.txt', 'w'))
-
-  dump_brr_audio()
-  dump_music_info()
-  print_all_sfx(open('sfx.txt', 'w'))
-
-  load_song(rom, 'indoor')
-  print_song('indoor', open('sound_indoor.txt', 'w'))
-
-  load_song(rom, 'ending')
-  print_song('ending', open('sound_ending.txt', 'w'))
-
-if __name__ == "__main__":
-  ROM = util.LoadedRom(sys.argv[1])
-  song = sys.argv[2]
-
-  load_song(ROM, song)
-  print_song(song, sys.stdout)
-
--- a/tables/extract_music.py
+++ /dev/null
@@ -1,470 +1,0 @@
-import hashlib
-import array
-import heapq, sys
-import yaml
-import time
-import util
-
-
-def load_sound_bank(rom, ea, mem_in = None):
-  memory = list(mem_in) if mem_in else [None]*65536
-  j =0 
-  while True:
-    numbytes = rom.get_word(ea)
-    target = rom.get_word(ea+2)
-    if numbytes==0:
-#      print('Entry point = 0x%x' % target)
-      return memory, target
-#    print('# Copy %d bytes to 0x%x' % (numbytes, target))
-    ea += 4
-    for i in range(numbytes):
-      memory[target+i] = rom.get_byte(ea)
-      ea += 1
-      if (ea & 0xffff) < 0x8000:
-        ea += 0x8000
-    j += 1
-    if j > 256:
-      break
-
-def get_byte(ea):
-  return memory[ea]
-
-def get_word(ea):
-  return get_byte(ea) | get_byte(ea + 1) * 256
-
-
-# lightworld
-# Copy 11694 bytes to 0xd000
-# Copy 1672 bytes to 0x2b00
-
-
-# indoor
-# Copy 11455 bytes to 0xd000
-# Copy 1292 bytes to 0x2b00
-
-def to_str(s):
-  if isinstance(s, str):
-    return s
-  if isinstance(s, int):
-    return str(s)
-  return s.name
-
-
-class Song:
-  name = 'Song'
-  def __str__(self):
-    s = '# Song index %d\n' % self.index
-    s += '[Song_0x%x]\n' % (self.ea)
-    s += "".join(x.name + '\n' for x in self.phrases)
-    return s
-
-class SongList:
-  name = 'SongList'
-  def __str__(self):
-    s = '[SongList_0x%x]\n' % (self.ea)
-    s += "".join(('None' if x == None else x.name) + '\n' for x in self.songs)
-    return s
-
-class Phrase:
-  name = 'Phrase'
-  def __str__(self):
-    s = '[Phrase_0x%x]\n' % (self.ea)
-    s += "".join(('None' if x == None else x.name) + '\n' for x in self.patterns)
-    return s
-
-class Pattern:
-  name = 'Pattern'
-  def __str__(self):
-    r = '[Pattern_0x%x]\n' % (self.ea)
-    last_len = None
-    for a in self.lines:
-      s = ''
-      if len(a) == 4:
-        s += a[0] + " " + " ".join(map(to_str, a[1]))
-      else:
-        s += '%s' % (a[0])
-
-        if a[-2] != None:
-          s += ' %2d' % a[-2]
-          last_len = a[-2]
-        else:
-          s += ' --'# % last_len
-
-        if a[-1] != None:
-          s += ' %2x' % a[-1]
-        else:
-          s += ' --'
-
-      r += s + '\n'
-    return r
-  
-class PhraseLoop:
-  name = 'PhraseLoop'
-  def __init__(self, loops, jmp):
-    self.loops = loops
-    self.jmp = jmp
-    self.name = 'PhraseLoop %d %d' % (self.loops, self.jmp)
-  def __str__(self):
-    return self.name
-
-types_for_ea = {}
-pqueue_by_ea = []
-
-def reset_queues():
-  global types_for_ea, pqueue_by_ea
-  types_for_ea = {}
-  pqueue_by_ea = []
-
-def get_type_for_ea(ea, tp):
-  if ea == 0:
-    return None
-  assert(ea >= 256), ea
-  a = types_for_ea.get(ea)
-  if a != None:
-    assert type(a)==tp, (type(a), tp, '0x%x' % ea)
-    return a
-  a = tp()
-  a.ea = ea
-  a.name = '%s_0x%x' % (a.name, ea)
-  types_for_ea[ea] = a
-  if get_byte(ea) != None:
-    heapq.heappush(pqueue_by_ea, (ea, a))
-    a.is_imported = False
-  else:
-    a.is_imported = True
-  return a
-
-kEffectByteLength = [1, 1, 2, 3, 0, 1, 2, 1, 2, 1, 1, 3, 0, 1, 2, 3, 1, 3, 3, 0, 1, 3, 0, 3, 3, 3, 1]
-kEffectNames = ['Instrument', 'Pan', 'PanFade', 'Vibrato', 'VibratoOff',
-                'SongVolume', 'SongVolumeFade', 'Tempo', 'TempoFade',
-                'Transpose', 'ChannelTranpose', 'Tremolo', 'TremoloOff',
-                'Volume', 'VolumeFade', 'Call', 'VibratoFade',
-                'PitchEnvelopeTo', 'PitchEnvelopeFrom', 'PitchEnvelopeOff',
-                'FineTune', 'EchoEnable', 'EchoOff', 'EchoSetup', 'EchoVolumeFade',
-                'PitchSlide', 'PercussionDefine']
-assert(len(kEffectNames) == 27)
-
-def note_to_str(note):
-  kKeys  = ['C-', 'C#', 'D-', 'D#', 'E-', 'F-', 'F#', 'G-', 'G#', 'A-', 'A#', 'B-']
-  if note >= 72:
-    if note == 72:
-      return '-+-' # don't write kof
-    elif note == 73:
-      return '---' # want kof
-    else:
-      assert 0
-  octave = note / 12
-  key = note % 12
-  return '%s%d' % (kKeys[key], octave + 1)
-
-def get_pattern(ea):
-  if ea == 0:
-    return None
-  pattern = get_type_for_ea(ea, Pattern)
-  return pattern
-
-def get_song(ea, index):
-  song = get_type_for_ea(ea, Song)
-  if song:
-    song.index = index
-  return song
-
-def get_phrase(ea):
-  phrase = get_type_for_ea(ea, Phrase)
-  return phrase
-
-def decode_pattern(pattern, next_ea):
-  ea = pattern.ea
-  pattern.lines = []
-  start_ea = ea
-  while True:
-#    print('0x%x 0x%x' % (ea, start_ea))
-#    assert ea != 0x28f0
-    if ea != start_ea and ea == next_ea:
-      pattern.lines.append(('Fallthrough', (), None, None))
-      return
-    note_length, volstuff = None, None
-    cmd = get_byte(ea); ea += 1
-    if cmd == 0:
-      break
-    if not (cmd & 0x80):
-      note_length = cmd
-      cmd = get_byte(ea); ea += 1
-      if not (cmd & 0x80):
-        volstuff = cmd
-        cmd = get_byte(ea); ea += 1
-    if cmd == 0xef:
-      addr = get_word(ea)
-      loops = get_byte(ea + 2)
-      ea += 3
-      pattern.lines.append((kEffectNames[cmd-0xe0], (get_pattern(addr), loops), note_length, volstuff))
-    elif cmd >= 0xe0:
-      assert note_length == None and volstuff == None, (note_length, volstuff)
-      x = kEffectByteLength[cmd - 0xe0]
-      args = [get_byte(ea+i) for i in range(x)]
-      ea += x
-      pattern.lines.append((kEffectNames[cmd-0xe0], args, note_length, volstuff))
-    else:
-      assert(cmd & 0x80)
-      pattern.lines.append((note_to_str(cmd & 0x7f), note_length, volstuff))
-
-  return pattern
-
-def decode_phrase(phrase):
-  phrase.patterns = [get_pattern(get_word(phrase.ea + i * 2)) for i in range(8)]
-
-def decode_song(song):
-  ea = song.ea
-  song.phrases = []
-  ea_org = ea
-  eas_in_phrase = []
-  while True:
-    eas_in_phrase.append(ea)
-    phrase = get_word(ea)
-    if phrase == 0:
-      break
-    if phrase < 0x100:
-      assert phrase != 0x80 and phrase != 0x81
-      tgt = get_word(ea + 2)
-      assert tgt in eas_in_phrase
-      song.phrases.append(PhraseLoop(phrase, (tgt - ea) // 2))
-      ea += 4                                     
-    else:
-      song.phrases.append(get_phrase(phrase))
-      ea += 2
-  return song
-
-def decode_any(what, next_ea):
-  if isinstance(what, Song):
-    decode_song(what)
-  elif isinstance(what, SongList):
-    pass # no need
-  elif isinstance(what, Phrase):
-    decode_phrase(what)
-  elif isinstance(what, Pattern):
-    decode_pattern(what, next_ea)
-  else:
-    assert 0
-
-def get_song_list(ea, num):
-  song_list = get_type_for_ea(ea, SongList)
-  song_list.songs  = [get_song(get_word(ea + i * 2), i) for i in range(num)]    
-
-def load_song(ROM, song):
-  global memory, SONGS_IN_BANK
-  reset_queues()
-  if song == 'intro':
-    memory, entry_point = load_sound_bank(ROM, 0x998000) # intro
-    SONGS_IN_BANK = (get_word(0xd000) - 0xd000) // 2
-  elif song == 'lightworld':
-    memory, entry_point = load_sound_bank(ROM, 0x9a9ef5) # lw
-    SONGS_IN_BANK = (get_word(0xd000) - 0xd000) // 2
-  elif song == 'indoor':
-    memory, entry_point = load_sound_bank(ROM, 0x9b8000) # indoor
-    SONGS_IN_BANK = (0xd046 - 0xd000) // 2
-  elif song == 'ending':
-    memory, entry_point = load_sound_bank(ROM, 0x9ad380) # ending
-    SONGS_IN_BANK = (0xd046 - 0xd000) // 2
-
-
-def print_song(song, f):
-  get_song_list(0xd000, SONGS_IN_BANK)
-  if song in ('intro', 'lightworld'):
-    get_phrase(0xD878)
-    get_phrase(0xD8A8)
-    get_phrase(0xD8B8)
-    get_phrase(0xDf11)
-    get_phrase(0xe37c)
-  if song == 'indoor':
-    get_phrase(0xDc5e)
-    get_phrase(0xDc6e)
-    get_pattern(0xe905)
-    get_phrase(0xe94a)
-  if song == 'ending':
-    get_phrase(0x2a10)    
-  while len(pqueue_by_ea):
-    _, item = heapq.heappop(pqueue_by_ea)
-    decode_any(item, pqueue_by_ea[0][0] if len(pqueue_by_ea) else None)
-  for a, b in sorted(types_for_ea.items()):
-    if not b.is_imported:
-      print(b, file = f)
-
-
-def dump_brr_audio():
-  def decode_brr(snd):
-    start, loop_start = get_word(0x3c00 + snd * 4), get_word(0x3c00 + snd * 4 + 2)
-    r = util.decode_brr(lambda x: get_byte(start+x))
-    return r, [get_byte(start+x) for x in range(len(r)//16 * 9)], get_byte(start)&0x2 != 0
-  for audio_idx in range(25):
-    sound_data, brr_data, brr_repeat = decode_brr(audio_idx)
-    open('sound/sound%d.pcm.brr' % audio_idx, 'wb').write(bytes(brr_data))
-    open('sound/sound%d.pcm' % audio_idx, 'wb').write(sound_data)
-
-def dump_music_info():
-  music_info = {}
-  kDupSamples = {10 : 9, 20 : 19}
-  music_info['samples'] = []
-  for audio_idx in range(25):
-    start, rep = get_word(0x3c00 + audio_idx * 4), get_word(0x3c00 + audio_idx * 4 + 2)
-    sample_info = {
-      'file' : 'sound/sound%d.pcm' % kDupSamples.get(audio_idx, audio_idx)
-    }
-    if get_byte(start) & 2:
-      sample_info['repeat'] = (rep - start) // 9 * 16
-    music_info['samples'].append(sample_info)
-
-  def add_sustain_decay_etc(ea, info):
-    adsr1, adsr2, gain = get_byte(ea), get_byte(ea + 1), get_byte(ea + 2)
-    info['decay'] = (adsr1 >> 4) & 7
-    info['attack'] = adsr1 & 0xf
-    info['sustain_level'] = adsr2 >> 5
-    info['sustain_rate'] = adsr2 & 0x1f
-    info['vxgain'] = gain  
-
-  music_info['instruments'] = []
-  for i in range(25):
-    ea = 0x3d00 + i * 6
-    adsr1, adsr2 = get_byte(ea + 1), get_byte(ea + 2)
-    info = {
-      'sample' : get_byte(ea),
-    }
-    add_sustain_decay_etc(ea + 1, info)
-    info['pitch_base'] = get_byte(ea + 4) << 8 | get_byte(ea + 5)
-    music_info['instruments'].append(info)
-
-  music_info['note_gate_off'] = [get_byte(i) for i in range(0x3D96, 0x3D96 + 8)]
-  music_info['note_volume'] = [get_byte(i) for i in range(0x3D9E, 0x3D9E + 16)]
-
-  music_info['sfx_instruments'] = []
-
-  for i in range(25):
-    ea = 0x3e00 + i * 9
-    info = {
-      'voll' : get_byte(ea),
-      'volr' : get_byte(ea + 1),
-      'pitch' : get_word(ea + 2),
-      'sample' : get_byte(ea + 4)
-    }
-    add_sustain_decay_etc(ea + 5, info)
-    info['pitch_base'] = get_byte(ea + 8)
-    music_info['sfx_instruments'].append(info)  
-
-  s = yaml.dump(music_info, default_flow_style=None, sort_keys=False)
-  open('music_info.yaml', 'w').write(s)
-
-def decode_sfx(ea, next_addr):
-  r = []
-  while True:
-    if ea == next_addr:
-      r.append(('Fallthrough', ))
-      return r
-    b = get_byte(ea); ea += 1
-    if b == 0:
-      return r
-    note_length = None
-    volume_left, volume_right = None, None
-    if not (b & 0x80):
-      note_length = b
-      b = get_byte(ea); ea += 1
-      if not (b & 0x80):
-        volume_left, volume_right = b, None
-        b = get_byte(ea); ea += 1
-        if not b & 0x80:
-          volume_right = b
-          b = get_byte(ea); ea += 1
-    if b == 0xe0:
-      assert note_length == None and volume_left == None and volume_right == None, ea
-      b = get_byte(ea); ea += 1
-      r.append(('SetInstrument %d' % b, ))
-    elif b == 0xf9:
-      #assert note_length == None and volume_left == None and volume_right == None, ea
-      b = get_byte(ea); ea += 1
-      b0, b1, b2 = get_byte(ea), get_byte(ea+1), get_byte(ea+2); ea += 3
-      r.append(('PitchSlide %d %d %d' % (b0, b1, b2), note_to_str(b & 0x7f), note_length, volume_left, volume_right))
-    elif b == 0xf1:
-      #assert note_length == None and volume_left == None and volume_right == None, ea
-      b0, b1, b2 = get_byte(ea), get_byte(ea+1), get_byte(ea+2); ea += 3
-      r.append(('PitchSlide %d %d %d' % (b0, b1, b2), None, note_length, volume_left, volume_right))
-    elif b == 0xff:
-      assert note_length == None and volume_left == None and volume_right == None, ea
-      r.append(('Restart',))
-      return r
-    else:
-      r.append((None, note_to_str(b & 0x7f), note_length, volume_left, volume_right))
-
-def print_all_sfx(f):
-  items = set()
-  def add_sfx_top(base, num, name):
-    print('[%s_0x%x]' % (name, base), file = f)
-    next_ea = base + num * 2
-    echo_ea = next_ea + num
-    for i in range(num):
-      r = []
-      ea = get_word(base + i * 2)
-      if ea == 0:
-        t = 'None'
-      else:
-        items.add(ea)
-        t = 'Sfx_0x%x' % ea
-      if name == 'SfxPort1':
-        print('%s,%d' % (t, get_byte(next_ea + i)), file = f)
-      else:
-        print('%s,%d,%d' % (t, get_byte(next_ea + i), get_byte(echo_ea + i)), file = f)
-    print(file = f)
-  add_sfx_top(0x17c0, 32, 'SfxPort1')
-  add_sfx_top(0x1820, 63, 'SfxPort2')
-  add_sfx_top(0x191c, 63, 'SfxPort3')
-  items.add(0x1a5b)
-  items.add(0x1d1c)
-  items.add(0x1ee2)
-  items.add(0x1f13)
-  items.add(0x1f1c)
-  items.add(0x252d)
-  items.add(0x2533)
-  items.add(0x26a2)
-  items.add(0x277e)
-  items.add(0x279d)
-  items.add(0x27c9)
-  items.add(0x27f6)
-  items.add(0x2807)
-  items.add(0x2818)
-  items.add(0x2829)
-  items.add(0x2831)
-  items.add(0x284a)
-  items = sorted(list(items))
-  for i in range(len(items)):
-    print('[Sfx_0x%x]' % items[i], file = f)
-    next_addr = items[i + 1] if i + 1 < len(items) else 0
-    rs = decode_sfx(items[i], next_addr)
-    for r in rs:
-      if len(r) == 5:
-        aa = '.  ' if r[1] == None else r[1]
-        bb = '--' if r[2] == None else '%2d' % r[2]
-        cc = '---' if r[3] == None else '%3d' % r[3]
-        dd = '---' if r[4] == None else '%3d' % r[4]
-        r0 = '' if r[0] == None else ' ' + r[0]
-        print('%s %s %s %s%s' % (aa, bb, cc, dd, r0), file = f)
-      else:
-        print(r[0], file = f)
-    print(file = f)
-
-def extract_sound_data(rom):
-  for song in ['intro', 'indoor', 'ending']:
-    load_song(rom, song)
-    open('sound/%s.spc' % song, 'wb').write(bytes((0 if a == None else a) for a in memory))
-    print_song(song, open('sound_%s.txt' % song, 'w'))
-    if song == 'intro':
-      dump_brr_audio()
-      dump_music_info()
-      print_all_sfx(open('sfx.txt', 'w'))
-
-if __name__ == "__main__":
-  if len(sys.argv) < 3:
-    print('extract_music.py [rom-filename] [intro|lightworld|indoor|ending]')
-    sys.exit(0)
-  ROM = util.LoadedRom(None if sys.argv[1] == '' else sys.argv[1])
-  song = sys.argv[2]
-
-  load_song(ROM, song)
-  print_song(song, sys.stdout)
-
--- a/tables/extract_resources.py
+++ /dev/null
@@ -1,541 +1,0 @@
-from ast import literal_eval as make_tuple
-import sys
-import text_compression
-import util
-from util import get_bytes, get_words, get_byte, get_word, get_int8, get_int16, cache
-import tables
-import yaml
-import extract_music
-import os
-import sprite_sheets
-
-def print_map32_to_map16(f):
-  for i in range(2218):
-    def getit(ea):
-      ov = [get_byte(ea + j) for j in range(6)]
-      res=[0]*4
-      res[0] = ov[0] | (ov[4] >> 4) << 8
-      res[1] = ov[1] | (ov[4] & 0xf) << 8
-      res[2] = ov[2] | (ov[5] >> 4) << 8
-      res[3] = ov[3] | (ov[5] & 0xf) << 8
-      return res
-    t0 = getit(0x838000 + i * 6)
-    t1 = getit(0x83b400 + i * 6)
-    t2 = getit(0x848000 + i * 6)
-    t3 = getit(0x84b400 + i * 6)
-    for j in range(4):
-      print('%5d: %4d, %4d, %4d, %4d' % (i * 4 + j, t0[j], t1[j], t2[j], t3[j]), file = f)
-
-@cache
-def get_exit_datas():
-  r = {}
-  for i in range(79):
-    room = get_word(0x82dd8a + i * 2)
-    screen_index = get_byte(0x82DE28 + i)
-    load_offs = get_word(0x82DE77 + i * 2)
-    scroll_y = get_word(0x82DF15 + i * 2)
-    scroll_x = get_word(0x82DFB3 + i * 2)
-    pos_y = get_word(0x82E051 + i * 2)
-    pos_x = get_word(0x82E0EF + i * 2)
-    camera_y = get_word(0x82E18D + i * 2)
-    camera_x = get_word(0x82E22B + i * 2)
-    unk1 = get_int8(0x82E2C9 + i)
-    unk3 = get_int8(0x82E318 + i)
-    ndoor = get_word(0x82E367 + i * 2)
-    fdoor = get_word(0x82E405 + i * 2)
-    base_x = (screen_index & 7) << 9
-    base_y = (screen_index & 56) << 6
-    y = {
-      'index' : i,
-      'room' : room,
-      'xy' : [pos_x - base_x, pos_y - base_y],
-      'scroll_xy' : [scroll_x - base_x, scroll_y - base_y],
-      'camera_xy' : [camera_x - base_x, camera_y - base_y],
-    }
-    y['load_xy'] = [((load_offs >> 1) - (y['scroll_xy'][0] >> 4)) & 0x3f, (load_offs >> 7) - (y['scroll_xy'][1] >> 4) & 0x3f]
-    y['unk'] = [unk1, unk3]
-    def get_special_exit_info(room_index):
-      return {
-        'dir' : get_byte(0x82E801  + room_index - 0x180) >> 1,
-        'spr_gfx' : get_byte(0x82E811  + room_index - 0x180),
-        'aux_gfx' : get_byte(0x82E821  + room_index - 0x180),
-        'pal_bg' : get_byte(0x82E831  + room_index - 0x180),
-        'pal_spr' : get_byte(0x82E841  + room_index - 0x180),
-        'top' : get_word(0x82e6e1 + (room_index - 0x180) * 2),
-        'bottom' : get_word(0x82e701 + (room_index - 0x180) * 2),
-        'left' : get_word(0x82e721 + (room_index - 0x180) * 2),
-        'right' : get_word(0x82e741 + (room_index - 0x180) * 2),
-        'left_edge_of_map' : get_word(0x82E7E1 + (room_index - 0x180) * 2),
-        'unk4' : get_int16(0x82e761 + (room_index - 0x180) * 2),
-        'unk6' : get_int16(0x82e781 + (room_index - 0x180) * 2),
-        'unk5' : get_int16(0x82e7a1 + (room_index - 0x180) * 2),
-        'unk7' : get_int16(0x82e7c1 + (room_index - 0x180) * 2),
-      }
-
-    if room >= 0x180 and room < 0x190:
-      y['special_exit'] = get_special_exit_info(room)
-
-    if ndoor != 0:
-      assert fdoor == 0
-      y['door'] = ['bombable' if ndoor & 0x8000 else 'wooden', (ndoor & 0x7e) >> 1, (ndoor & 0x3f80) >> 7]
-    if fdoor != 0:
-      y['door'] = ['palace' if fdoor & 0x8000 else 'sanctuary', (fdoor & 0x7e) >> 1, (fdoor & 0x3f80) >> 7]
-    r.setdefault(screen_index, []).append(y)
-  return r
-
-def get_loadoffs(c, d):
-  x, y = c[0] >> 4, c[1] >> 4
-  x += d[0]
-  y += d[1]
-  return (y&0x3f) << 7 | (x&0x3f) << 1
-
-@cache
-def get_ow_travel_infos():
-  r = {}
-  for i in range(17):
-    screen_index = get_word(0x82EAE5 + i * 2)
-    load_offs = get_word(0x82EB07 + i * 2)
-    scroll_y = get_word(0x82EB29 + i * 2)
-    scroll_x = get_word(0x82EB4B + i * 2)
-    pos_y = get_word(0x82EB6D + i * 2)
-    pos_x = get_word(0x82EB8F + i * 2)
-    camera_y = get_word(0x82EBB1 + i * 2)
-    camera_x = get_word(0x82EBD3 + i * 2)
-    unk1 = get_int8(0x82EBF5 + i * 2)
-    unk3 = get_int8(0x82EC17 + i * 2)
-    base_x = (screen_index & 7) << 9
-    base_y = (screen_index & 56) << 6
-    y = {}
-    if i < 9:
-      y['bird_travel_id'] = i
-    else:
-      y['whirlpool_src_area'] = get_word(0x82ECF8 + (i - 9) * 2)
-    y['xy'] = [pos_x - base_x, pos_y - base_y]
-    y['scroll_xy'] = [scroll_x - base_x, scroll_y - base_y]
-    y['camera_xy'] = [camera_x - base_x, camera_y - base_y]
-    y['load_xy'] = [((load_offs >> 1) - (y['scroll_xy'][0] >> 4)) & 0x3f, (load_offs >> 7) - (y['scroll_xy'][1] >> 4) & 0x3f]
-
-    t0 = get_loadoffs(y['scroll_xy'], y['load_xy'])
-    assert t0 == load_offs, (t0 & 0x7f, load_offs & 0x7f)
-    
-    y['unk'] = [unk1, unk3]
-    r.setdefault(screen_index, []).append(y)
-  return r
-
-@cache
-def get_ow_entrance_info():
-  r = {}
-  for i in range(129):
-    area = get_word(0x9BB96F + i * 2)
-    pos = get_word(0x9BBA71 + i * 2)
-    entrance_id = get_byte(0x9BBB73 + i)
-    r.setdefault(area, []).append({'index' : i, 'x' : (pos >> 1) & 0x3f, 'y' : (pos >> 7) & 0x3f, 'entrance_id' : entrance_id})
-  return r
-
-@cache
-def get_hole_infos():
-  r = {}
-  for i in range(19):
-    pos = get_word(0x9BB800 + i * 2) + 0x400
-    area = get_word(0x9BB826 + i * 2)
-    entrance_id = get_byte(0x9BB84C + i)
-    r.setdefault(area, []).append({'x' : (pos >> 1) & 0x3f, 'y' : (pos >> 7) & 0x3f, 'entrance_id' : entrance_id})
-  return r
-
-def print_overworld_area(overworld_area):
-  is_small = get_bytes(0x82F88D, 192)
-  y = {}
-
-  def get_music(ambient):
-    def fn(x):
-      if ambient:
-        return tables.kAmbientSoundName[x >> 4]
-      else:
-        return tables.kMusicNames[x & 0xf]
-    if overworld_area < 64:
-      return {
-        'beginning' : fn(get_byte(0x82C303 + overworld_area)),
-        'zelda' : fn(get_byte(0x82C303 + overworld_area + 64)),
-        'sword' : fn(get_byte(0x82C303 + overworld_area + 128)),
-        'agahnim' : fn(get_byte(0x82C303 + overworld_area + 192)),
-      }
-    else:
-      assert overworld_area < 64 + 96
-      return {'agahnim' : fn(get_byte(0x82C403 + overworld_area - 64)) }
-
-  def get_items():
-    if overworld_area >= 128: return []
-    ea = 0x9b0000 | get_word(0x9BC2F9 + overworld_area * 2)
-    xs = []
-    while get_word(ea) != 0xffff:
-      pos = get_word(ea)
-      assert pos%2==0
-      x, y = pos//2%64, pos//2//64 
-      xs.append([x, y, tables.kSecretNames[get_byte(ea+2)]])
-      ea += 3
-    return xs
-
-  header = {
-    'name' : tables.kAreaNames[overworld_area],
-    'size' : 'small' if is_small[overworld_area] else 'big',
-    'gfx' : get_byte(0x80FC9C + overworld_area) if overworld_area < 128 else -1,
-    'palette' : get_byte(0x80FD1C + overworld_area) if overworld_area < 136 else -1,
-    'sign_text' : get_word(0x87F51D + overworld_area * 2) if overworld_area < 128 else -1,
-    'music' : get_music(False),
-    'ambient' : get_music(True),
-  }
-      
-  y['Header'] = header
-  y['Travel'] = get_ow_travel_infos().get(overworld_area, [])
-  y['Entrances'] = get_ow_entrance_info().get(overworld_area, [])
-  hole_infos = get_hole_infos()
-  if overworld_area in hole_infos:
-    y['Holes'] = hole_infos[overworld_area]
-  y['Exits'] = get_exit_datas().get(overworld_area, [])
-  y['Items'] = get_items()
-  
-  def decode_sprites(base_addr):
-    r = []
-    ea = 0x890000 + get_word(base_addr + overworld_area * 2)
-    while get_byte(ea) != 0xff:
-      y, x, w = get_byte(ea), get_byte(ea+1), get_byte(ea+2)
-      r.append([x, y, tables.kSpriteNames[w]])
-      ea += 3
-    return r
-
-  def get_info(stage):
-    if overworld_area >= 128: return {}
-    if overworld_area >= 64: stage = 3
-    return {
-      'gfx' : get_byte(0x80FA41 + (overworld_area & 63) + stage * 64),
-      'palette' : get_byte(0x80FB41 + (overworld_area & 63) + stage * 64),
-    }
-  if overworld_area < 64:
-    y['Sprites.Beginning'] = {
-      'info' : get_info(0),
-      'sprites' : decode_sprites(0x89C881)
-    }
-    y['Sprites.FirstPart'] = {
-      'info' : get_info(1),
-      'sprites' : decode_sprites(0x89C901)
-    }
-    y['Sprites.SecondPart'] = {
-      'info' : get_info(2),
-      'sprites' : decode_sprites(0x89CA21)
-    }
-  elif overworld_area < 144:
-    y['Sprites'] = {
-      'info' : get_info(2),
-      'sprites' : decode_sprites(0x89CA21)
-    }
-    
-  s = yaml.dump(y, default_flow_style=None, sort_keys=False)
-  open('overworld/overworld-%d.yaml' % overworld_area, 'w').write(s)
-
-def print_all_overworld_areas():
-  area_heads = get_bytes(0x82A5EC, 64)
-  
-  for i in range(160):
-    if i >= 128 or area_heads[i&63] == (i&63):
-      print_overworld_area(i)
-
-def print_dialogue():
-  text_compression.print_strings(util.ROM, file = open(text_compression.dialogue_filename(util.ROM.language), 'w', encoding='utf8'))
-
-def decode_room_objects(p):
-  objs = []
-  j = 0
-  while True:
-    p0, p1, p2 = get_byte(p), get_byte(p+1), get_byte(p+2)
-    A = p0 | p1 << 8
-    if A == 0xffff:
-      return p + 2, objs, None
-    if A == 0xfff0:
-      p += 2
-      break
-    if (A & 0xfc) != 0xfc:
-      index = p2
-      Dst = (p1 >> 2) << 7
-      Dst |= (p0 & 0xfc) >> 1
-      X = (Dst >> 1) & 0x3f
-      Y = (Dst >> 7) & 0x3f
-      W = p0 & 3
-      H = p1 & 3
-      if index < 0xf8:
-        objs.append({'x' : X, 'y' : Y, 's' : '%d*%d' % (W, H), 'n': tables.kType0Names[index]})
-      else:
-        index2 = (index & 7) << 4 | H << 2 | W
-        objs.append({'x' : X, 'y' : Y, 'n': tables.kType1Names[index2]})
-    else:
-      # subtype 2: 111111xx xxxxyyyy yyiiiiii
-      X = ((p0 << 4 | p1 >> 4) & 0x3f)
-      Y = (p1 << 2 | p2 >> 6) & 0x3f
-      index = p2 & 0x3f
-      objs.append({'x' : X, 'y' : Y, 'n' : tables.kType2Names[index]})
-    p += 3
-    j += 1
-
-  doors = []
-  while True:
-    A = get_byte(p) | get_byte(p+1) << 8
-    if A == 0xffff:
-      return p + 2, objs, doors
-    doors.append({'type':get_byte(p + 1), 'pos' : get_byte(p) >> 4, 'dir' : A & 3})
-    p += 2
-
-@cache
-def get_chest_info():
-  ea = 0x81e96e
-  all = {}
-  for i in range(504//3):
-    room = get_word(ea + i * 3)
-    data = get_byte(ea + i * 3 + 2)
-    all.setdefault(room & 0x7fff, []).append((data, (room & 0x8000) != 0))
-  return all
-
-def _get_entrance_info_one(i, set):
-  def get_exit_door(i):
-    x = get_word((0x82D724, 0x82DC32)[set] + i * 2)
-    if x == 0:
-      return ['none']
-    if x == 0xffff:
-      return ['none_0xffff']
-    return ['bombable' if x & 0x8000 else 'wooden', (x & 0x7e) >> 1, (x & 0x3f80) >> 7]
-  kQuadrantNames = { 0 : 'upper_left', 2 : 'lower_left', 16 : 'upper_right', 18 : 'lower_right' }
-  room = get_word((0x82C813, 0x82DB6E )[set] + i * 2)
-  def get_se(se_base_addr, xy, quds):
-    base_x = (room & 0xf) * 2
-    base_y = (room >> 4) * 2  
-    ym = (xy[1] & 0x100) >> 8
-    xm = (xy[0] & 0x100) >> 8
-    #if room == 259: ym = 1 # possibly related to none_0xffff
-    hu = get_byte(se_base_addr + i * 8 + 0) - base_y - ym
-    fu = get_byte(se_base_addr + i * 8 + 1) - base_y
-    hd = get_byte(se_base_addr + i * 8 + 2) - base_y - ym
-    fd = get_byte(se_base_addr + i * 8 + 3) - base_y - 1
-    #assert fu == 0 and fd == 0 and hd == 0 and fd == 0, (room, fu, fd, hd, fd)
-    qqq = xm if room >= 242 and quds[0] == 'single_x' else 0
-    hl = get_byte(se_base_addr + i * 8 + 4) - base_x - xm
-    fl = get_byte(se_base_addr + i * 8 + 5) - base_x - qqq
-    hr = get_byte(se_base_addr + i * 8 + 6) - base_x - xm
-    fr = get_byte(se_base_addr + i * 8 + 7) - base_x - 1 - qqq
-    return [hu, fu, hd, fd, hl, fl, hr, fr]#
-
-  player_x = get_word((0x82D063, 0x82DBDE)[set] + i * 2) - ((room & 0x00f) << 9)
-  player_y = get_word((0x82CF59, 0x82DBD0)[set] + i * 2) - ((room & 0x1f0) << 5)
-
-  y = {
-    ('entrance_index' if set == 0 else 'starting_point_index'): i,
-    'name' : tables.kEntranceNames[i] if set == 0 else 'Starting Location %d' % i,
-    'scroll_xy' : [
-      get_word((0x82CD45, 0x82DBB4)[set] + i * 2) - ((room & 0x00f) << 9),
-      get_word((0x82CE4F, 0x82DBC2)[set] + i * 2) - ((room & 0x1f0) << 5),
-    ],
-    'player_xy' : [ player_x, player_y ],
-    'camera_xy' : [
-      get_word((0x82D277, 0x82DBFA)[set] + i * 2),
-      get_word((0x82D16D, 0x82DBEC)[set] + i * 2),
-    ],
-    'blockset' : get_byte((0x82D381, 0x82DC08)[set] + i),
-    'music' : tables.kMusicNames[get_byte((0x82D82E, 0x82DC4E)[set] + i)],
-    'palace' : tables.kPalaceNames[(get_int8((0x82D48B, 0x82DC16)[set] + i) + 2) >> 1],
-    'doorway_orientation' : get_int8(0x82D510 + i) if set == 0 else 0,
-    'plane' : get_byte((0x82D595, 0x82DC1D)[set] + i) & 0xf,
-    'ladder_level' : get_byte((0x82D595, 0x82DC1D)[set] + i) >> 4,
-    'quadrants' : [
-      'double_x' if (get_byte((0x82D61a, 0x82DC24)[set] + i) & 0x20) != 0 else 'single_x',
-      'double_y' if (get_byte((0x82D61a, 0x82DC24)[set] + i) & 0x2) else 'single_y',
-      kQuadrantNames[get_byte((0x82D69F, 0x82DC2B)[set] + i)]
-      ],
-    'floor' : get_int8((0x82D406, 0x82DC0F)[set] + i),
-  }
-
-  se = get_se((0x82C91D, 0x82DB7C)[set], y['player_xy'], y['quadrants'])
-  if se != [0, 0, 0, 0, 0, 0, 0, 0]:
-    y['repair_scroll_bounds'] = se
-  y['house_exit_door'] = get_exit_door(i)
-
-#  quadrant_byte = (2 if player_y & 0x100 else 0) + (16 if player_x & 0x100 else 0)
-#  if get_byte((0x82D69F, 0x82DC2B)[set] + i) != quadrant_byte:
-#    print('Room %d has incorrect quadrant byte' % room, y['quadrants'])
-  if set:
-    y['associated_entrance_index'] = get_word(0x82DC40 + i * 2)
-  return room, y 
-
-@cache
-def get_entrance_info(set):
-  r = {}
-  for i in range(133 if set == 0 else 7):
-    room, y = _get_entrance_info_one(i, set)
-    r.setdefault(room, []).append(y)
-  return r
-
-@cache 
-def pits_hurt_player():
-  return set(get_word(0x80990C + i * 2) for i in range(57))
-
-def print_room(room_index):
-  p = 0x1f8000 + room_index * 3
-  room_addr = get_byte(p) | get_byte(p+1) << 8 | get_byte(p+2) << 16
-  p = 0x40000 | get_word(0x4f502 + room_index * 2)
-  if p == 0x4FFEF:
-    p = 0x82EDC5 # just some place with zeros
-  floor, layout = get_byte(room_addr), get_byte(room_addr + 1)
-
-  flags = get_byte(p + 0)
-  p7, p8 = get_byte(p + 7), get_byte(p + 8)
-
-  ea = 0x890000 + get_word(0x89D62E + room_index * 2)
-  sort_sprites_setting = get_byte(ea)
-
-  header = {
-    'floor1': floor & 0xf,
-    'floor2' : floor >> 4,
-    'layout': layout >> 2,
-    'start_quadrant' : layout & 3,
-    'bg2' : tables.kBg2[flags >> 5],
-    'collision' : tables.kCollisionNames[flags >> 2 & 7],
-    'lights_out' : flags & 1,
-    'palette' : get_byte(p + 1),
-    'blockset' : get_byte(p + 2),
-    'enemyblk' : get_byte(p + 3),
-    'effect' : tables.kEffectNames[get_byte(p + 4)],
-    'tag0' : tables.kTagNames[get_byte(p + 5)],
-    'tag1' : tables.kTagNames[get_byte(p + 6)],
-    'hole0_dest' : [get_byte(p+9), p7 & 3],
-    'stair0_dest' : [get_byte(p+10), p7 >> 2 & 3],
-    'stair1_dest' : [get_byte(p+11), p7 >> 4 & 3],
-    'stair2_dest' : [get_byte(p+12), p7 >> 6 & 3],
-    'stair3_dest' : [get_byte(p+13),p8 & 3],
-    'tele_msg' : get_word(0x87F61D+room_index*2),
-    'sort_sprites' : sort_sprites_setting,
-    'pits_hurt_player' : room_index in pits_hurt_player()
-  }
-
-  def get_sprites():
-    ea = 0x890000 + get_word(0x89D62E + room_index * 2)
-    ea += 1
-    r = []
-    while get_byte(ea) != 0xff:
-      y, x, type = get_byte(ea), get_byte(ea+1), get_byte(ea+2)
-      if type == 0xe4:
-        if y == 0xfe or y == 0xfd:
-          r[-1].append('drop_key' if y == 0xfe else 'drop_big_key')
-          ea += 3
-          continue
-      elif x >= 0xe0:
-        floor = y >> 7
-        r.append([x & 0x1f, y & 0x1f, 'lower' if floor else 'upper', tables.kSpriteNames[type + 0x100]])
-        ea += 3
-        continue
-      subtype = (x >> 5) | ((y >> 5) & 3) << 3
-      floor = y >> 7
-      name = tables.kSpriteNames[type]
-      if subtype != 0:
-        i = name.index('-')
-        name = name[:i] + ('.%d' % subtype) + name[i:]
-      r.append([x & 0x1f, y & 0x1f, 'lower' if floor else 'upper', name])
-      ea += 3
-    return r
-
-  def get_secrets():
-    ea = 0x810000 | get_word(0x81db69 + room_index * 2)
-    xs = []
-    while get_word(ea) != 0xffff:
-      pos = get_word(ea)
-      assert pos%2==0
-      x, y = pos//2%64, pos//2//64 
-      xs.append([x, y, tables.kSecretNames[get_byte(ea+2)]])
-      ea += 3
-    return xs
-
-  def get_chests():
-    r = []
-    for data, big in get_chest_info().get(room_index, []):
-      if big:
-        r.append('%d!' % data)
-      else:
-        r.append(data)
-    return r
-      
-  sprites = get_sprites()
-  secrets = get_secrets()
-
-  data = {'Header' : header, 'Sprites' : sprites, 'Secrets' : secrets, 'Chests' : get_chests()}
-  data['Entrances'] = get_entrance_info(0).get(room_index, [])
-  if room_index in get_entrance_info(1):
-    data['StartingPoints'] = get_entrance_info(1)[room_index]
-
-  p = room_addr + 2
-  p, objs, doors = decode_room_objects(p)
-  data['Layer1'] = objs
-  if doors: data['Layer1.doors'] = doors
-
-  p, objs, doors = decode_room_objects(p)
-  data['Layer2'] = objs
-  if doors: data['Layer2.doors'] = doors
-
-  p, objs, doors = decode_room_objects(p)
-  data['Layer3'] = objs
-  if doors: data['Layer3.doors'] = doors
-  
-  return yaml.dump(data, default_flow_style=None, sort_keys=False)
-
-def print_all_dungeon_rooms():
-  for i in range(320):
-    s = print_room(i)
-    open( 'dungeon/dungeon-%d.yaml' % i, 'w').write(s)
-
-def print_default_rooms():
-  def print_default_room(idx):
-    p = 0x84EF2F + idx * 3
-    room_addr = get_byte(p) | get_byte(p+1) << 8 | get_byte(p+2) << 16
-    p, objs, doors = decode_room_objects(room_addr)
-    assert doors == None
-    return objs
-  default_rooms = {}
-  for i in range(8):
-    default_rooms['Default%d' % i] = print_default_room(i)
-  s = yaml.dump(default_rooms, default_flow_style=None, sort_keys=False)
-  open('dungeon/default_rooms.yaml', 'w').write(s)
-
-def print_overlay_rooms():
-  def print_overlay_room(idx):
-    p = 0x84ECC0 + idx * 3
-    room_addr = get_byte(p) | get_byte(p+1) << 8 | get_byte(p+2) << 16
-    p, objs, doors = decode_room_objects(room_addr)
-    assert doors == None
-    return objs
-  default_rooms = {}
-  for i in range(19):
-    default_rooms['Overlay%d' % i] = print_overlay_room(i)
-  s = yaml.dump(default_rooms, default_flow_style=None, sort_keys=False)
-  open('dungeon/overlay_rooms.yaml', 'w').write(s)
-
-def make_directories():
-  os.makedirs('img', exist_ok=True)
-  os.makedirs('overworld', exist_ok=True)
-  os.makedirs('dungeon', exist_ok=True)
-  os.makedirs('sound', exist_ok=True)
-
-def print_all_text_stuff():
-  print_all_overworld_areas()
-  print_all_dungeon_rooms()
-  print_overlay_rooms()
-  print_default_rooms()
-  print_dialogue()
-  print_map32_to_map16(open('map32_to_map16.txt', 'w'))
-
-def main():
-  make_directories()
-  print_all_text_stuff()
-  extract_music.extract_sound_data(util.ROM)
-  sprite_sheets.decode_link_sprites()
-  sprite_sheets.decode_sprite_sheets()
-  sprite_sheets.decode_hud_icons()
-  sprite_sheets.decode_font()
- 
-if __name__ == "__main__":
-  util.load_rom(sys.argv[1] if len(sys.argv) >= 2 else None)
-  main()
-
binary files a/tables/palette_usage.bin /dev/null differ
--- a/tables/restool.py
+++ /dev/null
@@ -1,48 +1,0 @@
-import argparse
-import util
-import sys
-
-parser = argparse.ArgumentParser(description='Resource tool used to build zelda3_assets.dat', allow_abbrev=False)
-parser.add_argument('-r', '--rom', nargs='?', metavar='ROM')
-parser.add_argument('--extract-from-rom', '-e', action='store_true', help='Extract/overwrite things from the ROM')
-
-optional = parser.add_argument_group('Language settings')
-optional.add_argument('--extract-dialogue', action='store_true', help = 'Extract dialogue from a translated ROM')
-optional.add_argument('--languages', action='store', metavar='L1,L2', help = 'Comma separated list of additional languages to build (de,fr,fr-c,en,es,pl,pt,redux,nl,sv).')
-
-optional = parser.add_argument_group('Debug things')
-optional.add_argument('--no-build', action='store_true', help="Don't actually build zelda3_assets.dat")
-optional.add_argument('--print-strings', action='store_true', help="Print all dialogue strings")
-optional.add_argument('--print-assets-header', action='store_true')
-
-optional = parser.add_argument_group('Image handling')
-optional.add_argument('--sprites-from-png', action='store_true', help="When compiling, load sprites from png instead of from ROM")
-
-args = parser.parse_args()
-
-if args.extract_dialogue:
-  ROM = util.load_rom(args.rom, True)
-  import extract_resources, sprite_sheets
-  sprite_sheets.decode_font()
-  extract_resources.print_dialogue()
-  sys.exit(0)
-
-ROM = util.load_rom(args.rom)
-
-want_compile = True
-
-if args.extract_from_rom:
-  import extract_resources
-  extract_resources.main()
-
-if args.print_strings:
-  import text_compression
-  text_compression.print_strings(ROM)
-  want_compile = False
-
-if want_compile and not args.no_build:
-  import compile_resources
-  compile_resources.main(args)
-
-
-
--- a/tables/sprite_sheet_info.py
+++ /dev/null
@@ -1,1547 +1,0 @@
-class Entry:
-  def __init__(self, name, dungeon_or_ow, tileset_and_pal, ss_idx, matrix, pal_base):
-    self.name = name.replace(' - ', ': ')
-    self.dungeon_or_ow = dungeon_or_ow
-    self.tileset, self.palset_idx = tileset_and_pal
-    self.ss_idx = ss_idx
-    self.matrix = matrix
-    self.pal_base = pal_base
-
-entries = []
-def add(name, lw = None, dw = None, sheet = None, ow = None, dung = None, ss_1 = None, ss_2 = None, ss_3 = None, ss_4 = None, palette = None):
-  def doit(tileset_and_pal, dungeon_or_ow, suffix = ''):
-    all_chars = sorted(set("".join([ss.lower() for ss in (ss_1, ss_2, ss_3, ss_4) if ss != None])))
-    for ch in all_chars:
-      if ch == '\n' or ch == '.' or ch == 'o': continue
-      for ss_idx, ss in enumerate((ss_1, ss_2, ss_3, ss_4)):
-        if ss == None: continue
-        ss = ss.lower().replace('o', 'x')
-        matrix = ss.splitlines()[1:]
-        assert len(matrix) == 4 and all(len(m) == 16 for m in matrix), name
-        matrix2 = [[('x' if x == ch else '.') for x in m] for m in matrix]
-        if any('x' in m for m in matrix2):
-          entries.append(Entry(name + suffix, dungeon_or_ow, tileset_and_pal, ss_idx, matrix2, palette if ch == 'x' else int(ch)))
-
-  if lw and dw:
-    doit(lw, 0, ' - LW')
-    doit(dw, 1, ' - DW')
-  elif lw:
-    doit(lw, 0)
-  elif dw:
-    doit(dw, 1)
-  elif ow:
-    doit(ow, 0)
-  elif dung:
-    doit(dung, 2)
-  elif sheet:
-    doit(sheet, 3)
-
-
-add("00 - Raven", lw=(4, 3), dw=(23, 13), ss_4 = """
-....XXXXXX......
-....XXXXXX......
-................
-................""")
-
-add("01 - Vulture", ow=(8, 4), ss_3 = """
-XXXXXXXX........
-XXXXXXXX........
-................
-................""")
-
-add("04 - PullSwitch", dung=(6, 29), ss_4 = """
-..............XX
-..............XX
-..............XX
-..............XX""")
-
-add("07 - PullSwitch2", dung=(4, 0), ss_3 = """
-................
-................
-..XXXX..........
-..XXXX..........""")
-
-add("08 - Octorok", lw=(11, 3), dw=(22, 10), ss_3 = """
-XXXXXX..........
-XXXXXX..........
-XXXX.....XXX....
-XXXX....XXXXX...""")
-
-add("09 - Moldorm", dung=(12, 6), ss_3 = """
-5555555555666666
-5555555555666666
-5555555566666666
-5555555566666666""")
-
-add("0b - Chicken", lw=(6, 1), dw=(21, 16), ss_4 = """
-................
-................
-..........XXXX..
-..........XXXX..""")
-
-add("0d - Buzzblob", ow=(7, 6), ss_4 = """
-..........XXXXXX
-..........XXXXXX
-XXXXXX..........
-XXXX............""")
-
-add("0e - SnapDragon", ow=(19, 14), ss_1 = """
-................
-................
-........XXXX....
-........XXXXXXXX""", ss_3 = """
-............XXXX
-............XXXX
-..........XXXXXX
-..........XXXXXX""")
-
-add("0f - Octoballon", ow=(4, 3), ss_3 = """
-......XX....XX..
-......XX....XX..
-............XX..
-.............X..""")
-
-add("11 - Hinox", dw=(19, 14), ss_1 = """
-33333333....3333
-33333333....3333
-333333......3333
-333333..........""")
-
-add("12 - Moblin", ow=(19, 14), ss_3 = """
-XXXXXXXXXXXX....
-XXXXXXXXXXXX....
-XXXXXXXXXX......
-XXXXXXXXXX......""")
-
-add("13 - MiniHelmasaur", dung=(12, 26), ss_2 = """
-..............XX
-............X.XX
-....XXXXXXXXXXXX
-....XXXXXXXXXXXX""")
-
-add("15 - Antifairy", dung=(8, 10), ss_4 = """
-................
-................
-.1.1............
-................""")
-
-# Aginah is (16, 7)
-add("16 - Elder", dung=(16, 28), ss_3 = """
-................
-................
-XXXXXX..........
-XXXXXX..........""")
-
-add("17 - Hoarder", ow=(4, 3), ss_4 = """
-................
-................
-......XXXX......
-......XXXX......""")
-
-
-add("18 - MiniMoldorm", dung=(19, 13), ss_2 = """
-.............X..
-.............X..
-XXXX............
-XXXX............""")
-
-add("19 - Poe", lw=(3, 2), dw=(21, 16), ss_4 = """
-................
-................
-......XX........
-......XX........""")
-
-add("1a - Smithy", dung=(5, 30), ss_2 = """
-XXXXXX..........
-XXXXXX..........
-XXXXXX..........
-XXXXXX..........""")
-
-add("1a - Smithy", ow=(29, 0), ss_4 = """
-........XX......
-........XX......
-................
-................""")
-
-add("1c - Statue", dung=(17, 10), ss_4 = """
-XXX.............
-XX..............
-................
-................""")
-
-add("1e - CrystalSwitch", dung=(8, 15), ss_4 = """
-................
-................
-....11..........
-....11..........""")
-
-add("1f - SickKid", dung=(13, 21), ss_1 = """
-..........6666XX
-..........6666XX
-.......X......XX
-.......X......XX""")
-
-
-add("20 - Sluggula", dung=(29, 17), ss_3 = """
-XXXXXX..........
-XXXXXX..........
-xx........xxxxxx
-xx........xxxxxx""")
-
-
-add("21 - PushSwitch", dung=(17, 10), ss_4 = """
-..........xxxx..
-..........xxxx..
-..........xx....
-..........xx....""")
-
-add("22 - Ropa", ow=(19, 14), ss_1 = """
-........xxxx....
-........xxxx....
-......xx........
-......xx........""")
-
-# also used for blue bari
-add("23 - RedBari", dung=(8, 15), ss_1 = """
-................
-................
-xxxx..xx........
-xxxx..xx........""")
-
-add("25 - TalkingTree (S27)", dw=(19, 16), ss_4 = """
-................
-................
-........xx......
-........xx......""")
-
-add("25 - TalkingTree (S21)", dw=(21, 16), ss_1 = """
-................
-................
-........xx......
-........xx......""")
-
-add("26 - HardhatBeetle", dung=(19, 13), ss_2 = """
-xxxxxxxxxxxxx...
-xxxxxxxxxxxx....
-................
-................""")
-add("27 - Deadrock", ow=(16, 9), ss_4 = """
-..xxxxxx........
-..xxxxxx........
-..xxxx..........
-..xxxx..........""")
-add("28 - DarkWorldHintNpc", dung=(5, 7), ss_2 = """
-..........55....
-..........55....
-..............55
-..............55""")
-add("28 - DarkWorldHintNpc", dung=(5, 7), ss_1 = """
-................
-................
-....55..........
-....55..........""")
-add("28 - DarkWorldHintNpc", dung=(5, 7), ss_1 = """
-....44..........
-....44..........
-................
-................""")
-add("28 - DarkWorldHintNpc", dung=(7, 7), ss_1 = """
-..............55
-..............55
-..............55
-..............55""")
-add("28 - DarkWorldHintNpc", dung=(5, 28), ss_2 = """
-................
-................
-..........5555..
-..........5555..""")
-
-
-add("29 - Human/Woman", dung=(15, 35), ss_1 = """
-............xxxx
-............xxxx
-................
-................""", ss_4 = """
-..........xxxxxx
-..........xxxxxx
-................
-................""")
-
-add("29 - Human/Thief", dung=(40, 7), ss_1 = """
-xxxxxxxx..xx..xx
-xxxxxxxx..xx..xx
-xxxxxx......xx..
-xxxxxx......xx..""", palette = 7)
-
-
-add("29 - Human/Elder", dung=(15, 35), ss_3 = """
-....xxxxxx......
-....xxxxxx......
-..xx............
-..xx............""")
-
-add("2a - SweepingLady", ow=(6, 1), ss_3 = """
-..........xxxxxx
-..........xxxxxx
-................
-................""")
-
-add("2b - Hobo", ow=(12, 8), ss_3 = """
-........xxxx....
-........xxxx....
-......xxxxxxx...
-......xxxxxxx...""")
-
-add("2c - LumberJacks", ow=(26, 6), ss_1 = """
-..............xx
-..............xx
-................
-................""", ss_3 = """
-................
-................
-....xxxxxx......
-....xxxxxx....44""")
-
-add("2e - FluteKid - LW", lw=(15, 1), ss_3= """
-................
-................
-........xxxx...x
-........xxxx..xx""")
-
-
-add("2e - FluteKid - DW", dw=(17,11), ss_4 = """
-........xxxx00..
-........xxxx00..
-......xxxx..00..
-......xxxx..00..""", palette = 3)
-
-
-add("2f - MazeGameLady", ow=(6, 1), ss_4 = """
-xxxx............
-xxxx............
-xxxxxxxxxx......
-xxxxxxxxxx......""")
-
-add("30 - MazeGameGuy", ow=(6, 1), ss_1="""
-xxxx............
-xxxx............
-xx..............
-xx..............""")
-
-add("31 - FortuneTeller", dung=(5, 30), ss_1 = """
-..........xxxx..
-..........xxxx..
-..........x.x...
-................""", ss_2 = """
-................
-................
-......xxxx......
-......xxxx......""")
-
-add("32 - QuarrelBros", dung=(15,2), ss_1 = """
-....XX..XXXX....
-....XX..XXXX....
-................
-................""")
-
-add("34 - YoungSnitchLady", ow=(6,1), ss_1 = """
-................
-................
-....xxxxxx......
-....xxxxxx......""", ss_4 = """
-..xx............
-..xx............
-....xxxxxx......
-....xxxxxx......""")
-
-add("35 - InnKeeper", dung=(15,5), ss_4 = """
-....xxxxxxxxxxxx
-....xxxxxxxxxxxx
-..............xx
-..............xx""")
-
-add("36 - Witch", ow=(13, 6), ss_3 = """
-xxxxxx11........
-xxxxxx11........
-..............xx
-..............xx""")
-
-add("39 - Locksmith", ow=(10, 0), ss_4 = """
-................
-................
-..........xxxx..
-..........xxxx..""")
-
-add("3a - MagicBat", dung=(9, 32), ss_4 = """
-................
-................
-..........xxxx..
-..........xxxx.x""")
-
-add("3b - TreeTop", ow=(26, 6), ss_1 = """
-xxxxxxxxxx......
-xxxxxxxxxx......
-xxxxxxxxxxxx....
-xxxxxxxxxxxx....""", palette = 0)
-
-add("3c - TroughBoy", ow=(6, 1), ss_3 = """
-4444............
-4444............
-55........55....
-55........55....""")
-
-add("3d - OldSnitchLady", ow=(6, 1), ss_4 = """
-xxxx............
-xxxx............
-xxxxxxxxxx......
-xxxxxxxxxx......""")
-
-# rock crab is included in two sheets
-add("3e - RockCrab", ow=(10, 0), ss_4 = """
-................
-................
-......xxxx......
-......xxxx......""", palette = 0)
-
-add("3e - RockCrab (S16)", ow=(33, 0), ss_4 = """
-................
-................
-......xxxx......
-......xxxx......""", palette = 0)
-
-
-add("3f - PalaceGuard", ow=(2, 1), ss_1 = """
-xx..............
-xx..............
-......xxxxx.....
-......xxxxx.....""", palette = 4)
-
-add("3f - PalaceGuard", ow=(2, 1), ss_2 = """
-xxxxxxxx......xx
-xxxxxxxx......xx
-....xx..........
-....xx..........""")
-
-
-add("40 - ElectricBarrier", ow=(2, 1), ss_4 = """
-..........xxxx..
-..........xxxx..
-......xxxx......
-......xxxx......""")
-
-
-add("41 - Soldier", dung=(3, 0), ss_2 = """
-xxxxxxxxxxxxxxxx
-xxxxxxxxxxxxxxxx
-xxxxxxxxxxxxxxxx
-xxxxxxxxxxxxxxxx""")
-
-add("41 - Soldier (DW)", dung=(36, 37), ss_2 = """
-xxxxxxxxxxxxxxxx
-xxxxxxxxxxxxxxxx
-xxxxxxxxxxxxxxxx
-xxxxxxxxxxxxxxxx""", ss_3 = """
-................
-................
-......xxxxxxxxx.
-......xxxxxxxxx.
-""")
-
-add("44 - Warrior", dung=(33, 38), ss_1 = """
-xxxxxx..........
-xxxxxx..........
-................
-................""")
-
-add("47 - GrassArcher", ow=(4, 3), ss_1 = """
-..xxxxxxxxxxxxxx
-..xxxxxxxxxxxxxx
-11xxxx..........
-11xxxx..........""")
-
-add("4a - RedBombKnight", ow=(1, 3), ss_1 = """
-xxxxxxxxxxxxxxx.
-xxxxxxxxxxxxxxx.
-..xx........xxxx
-..xx........xxx.""")
-
-add("4b - GreenKnifeGuard", ow=(2, 1), ss_3 = """
-xxxxxxxxxxxxxxxx
-xxxxxxxxxxxxxxxx
-xx....xxxxxxxxxx
-xx....xxxxxxxxxx""")
-
-add("4c - Geldman", ow=(8, 4), ss_3 = """
-................
-................
-xxxxxxxx........
-xxxxxxxxx.......""")
-
-add("4d - Toppo", ow=(4, 3), ss_4 = """
-xxxx............
-xxxx............
-................
-................""")
-
-add("4e - Popo", dung=(8, 11), ss_2 = """
-xxxx............
-xxxx............
-................
-................""")
-
-add("51 - ArmosStatue", ow=(5, 7), ss_4 = """
-xx..............
-xx..............
-xx..............
-xx..............""", palette = 5)
-
-add("52 - ZoraKing", ow=(14, 8), ss_3 = """
-........2222....
-........2222....
-........2.......
-................""", ss_4 = """
-xxxx2222........
-xxxx2222........
-xxxx2222..xx....
-xxxx2222..xx....""")
-
-add("53 - ArmosKnight", dung=(9, 11), ss_4 = """
-xxxxxxxxxx......
-xxxxxxxxxx......
-xxxxxx..........
-xxxxxx..........""")
-
-add("54 - Lanmolas", dung=(11, 4), ss_4 = """
-xxxxxxxxxxxxxxxx
-xxxxxxxxxxxxxxxx
-xxxxxxxxxxxxxxxx
-xxxxxxxxxxxxxxxx""")
-
-add("55 - FireBallZora", lw=(4, 3), dw=(22, 10), ss_3 = """
-........2222....
-........2222....
-....xxxx2.......
-....xxxx........""")
-
-add("56 - WalkingZora", ow=(14, 8), ss_4 = """
-........xxxxxxxx
-........xxxxxxxx
-........xx..xxxx
-........xx..xxxx""")
-
-add("57 - HyliaObstacle", ow=(8, 4), ss_3 = """
-..............xx
-..............xx
-..............xx
-..............xx""")
-
-add("58 - Crab", ow=(4, 3), ss_3 = """
-..............xx
-..............xx
-..............xx
-..............xx""")
-
-add("59 - LostWoodsBird", ow=(12, 1), ss_4 = """
-................
-................
-...xxxx.........
-...xxxx.........""")
-
-add("5a - LostWoodsSquirrel", ow=(12, 1), ss_4 = """
-.....xx.........
-.....xx.........
-.xx.............
-.xx.............""")
-
-add("5b - Spark", dung=(17, 10), ss_1 = """
-................
-................
-........xx......
-........xx......""", palette = 2)
-
-add("5d - Roller", dung=(30, 24), ss_3 = """
-........xxx.....
-........xxx.....
-................
-................""")
-
-add("5f - Roller", dung=(30, 24), ss_3 = """
-..............xx
-..............xx
-..............xx
-................""")
-  
-add("61 - Beamos", dung=(10, 9), ss_2 = """
-........xx555...
-........xx551...
-........xx......
-........xx......""")
-
-add("62 - MasterSword", ow=(12, 1), ss_3 = """
-xxxxxxxx........
-xxxxxxxx........
-xxxxxx..........
-xxxxxx..........""", ss_4 = """
-...xx...........
-...xx...........
-x......xx.......
-x......xx.......""")
-
-add("63 - DebirandoPit", dung=(10, 9), ss_1 = """
-..xxxx..........
-..xxxx..........
-..xx....xxxx....
-..xx....xxxx....""")
-
-add("64 - Debirando", dung=(10, 9), ss_1 = """
-xx..............
-xx..............
-xx..............
-xx..............""", palette = 3)
-
-add("65 - ArcherGame", dung=(5, 30), ss_1 = """
-..xxxxxxxx......
-..xxxxxxxx......
-..xxxxxxxx.x....
-xxxxxxxxxxxx....""", palette = 4)
-
-add("66 - Cannon", dung=(10, 9), ss_1 = """
-..........xxxxxx
-..........xxxxxx
-....44........xx
-....44........xx""")
-
-add("6a - MorningStar", dung=(4, 1), ss_1 = """
-xxxxxxxxxxxxxxx.
-xxxxxxxxxxxxxxx.
-..xx......xxxxxx
-..xx......xxxxxx""", ss_2 = """
-......xxxxxxx.xO
-......xxxxxxx.xO
-xxxxxxxxxxx.....
-xxxxxxxxxxx.....""")
-
-add("6b - CannonTrooper", dung=(4, 1), ss_1 = """
-xxxxxxxxxxxxxxxx
-xxxxxxxxxxxxxxxx
-xxxxxxxxxxxxxxxx
-xxxxxxxxxxxxxxx.""")
-
-add("6d - Rat", dung=(1, 1), ss_3 = """
-......xxxxxxxxxx
-......xxxxxxxxxx
-..xx............
-..xx............""")
-
-add("6d - Rat (DW)", dung=(33, 35), ss_3 = """
-......xxxxxxxxxx
-......xxxxxxxxxx
-xxxx............
-xxxx............""")
-
-
-
-add("6e - Rope", dung=(1, 1), ss_3 = """
-................
-................
-....xxxxxxxx....
-....xxxxxxxx....""")
-
-add("6e - Rope (DW)", dung=(33, 35), ss_3 = """
-................
-................
-....xxxxxxxx....
-....xxxxxxxx....""")
-
-add("6f - Keese", dung=(1, 1), ss_3 = """
-xxxxxx..........
-xxxxxx..........
-................
-................""")
-
-add("6f - Keese (DW)", dung=(33, 35), ss_3 = """
-xxxxxx..........
-xxxxxx..........
-................
-................""")
-
-add("70 - KingHelmasaurFireball", dung=(21, 16), ss_3 = """
-................
-................
-............xx..
-............xx..""", ss_4 = """
-..........xxxx..
-..........xxxx.x
-................
-................""")
-
-add("71 - Leever", dung=(10, 9), ss_1 = """
-......xxxx......
-......xxxx......
-......xxx.......
-......xxx.......""")
-
-add("72 - FairyPond", dung=(7, 7), ss_4 = """
-........xxxxxxxx
-........xxxxxxxx
-................
-................""")
-
-add("72 - FairyPond", dung=(7, 34), ss_4 = """
-................
-................
-.........xxxxxxx
-.........xxxxxxx""")
-
-add("73 - UncleAndPriest", dung=(6, 29), ss_1 = """
-OOOOOOxxxxxxxxxx
-OOOOOOxxxxxxxxxx
-xxxxxxxxxxxx0000
-xxxxxxxxxxxx0000""", palette = 4)
-
-add("73 - UncleAndPriest", dung=(13, 21), ss_1 = """
-xxxxxxxxxx......
-xxxxxxxxxx......
-xxxxxxx.xxxxxx..
-xxxxxxx.xxxxxx..""", palette = 4)
-
-
-
-add("74 - RunningMan", ow=(6, 1), ss_1 = """
-................
-................
-..........xxxxxx
-..........xxxxxx""", ss_4 = """
-..........xxxxxx
-..........xxxxxx
-..............xx
-..............xx""")
-
-add("75 - BottleVendor", ow=(6, 1), ss_3 = """
-........xx......
-........xx......
-..xx........xx..
-..xx........xx..""")
-
-add("78 - MrsSahasrahla", dung=(5, 2), ss_1 = """
-................
-................
-........xx......
-........xx......""", ss_3 = """
-..............xx
-..............xx
-................
-................""")
-
-add("7a - Agahnim", dung=(24, 27), ss_1 = """
-............xxxx
-............xxxx
-............xxxx
-............xxxx""", ss_2 = """
-xxxxxxxxxxxxxxxx
-xxxxxxxxxxxxxxxx
-xxxxxxxxxxxxxxxx
-xxxxxxxxxxxxxxxx""", ss_3 = """
-xxxxxxxxxxxxxxxx
-xxxxxxxxxxxxxxxx
-xxxxxxxxxxxxxxxx
-xxxxxxxxxxxxxxxx""", ss_4 = """
-xxxxxx..xxxx...x
-xxxxxx..xxxx..xx
-xxxxxxxxxxxxxxxx
-xxxxxxxxxxxxxxxx""", palette = 6)
-
-add("7b - AgahnimBalls", dung=(24, 27), ss_4 = """
-......xx....xxx.
-......xx....xx..
-................
-................""", palette = 2)
-
-add("7c - StalfosHead", dung=(8, 11), ss_1 = """
-xxxxxx..........
-xxxxxx..........
-................
-................""")
-
-add("7d - BigSpikeBlock", dung=(12, 16), ss_4 = """
-....xx..........
-....xx..........
-................
-................""")
-
-add("7e - FireBlade", dung=(17, 10), ss_1 = """
-................
-................
-........xx......
-........xx......""")
-
-add("81 - WaterBug", dung=(17, 10), ss_3 = """
-xxxxxx..........
-xxxxxx..........
-................
-................""")
-
-add("83 - GreenEyegore", dung=(10, 9), ss_3 = """
-..........xxxxxx
-..........xxxxxx
-xxxxxxxxxxxxxxxx
-xxxxxxxxxxxxxx..""")
-
-add("83 - GreenEyegore", dung=(8, 39), ss_2 = """
-....xxxx......xx
-....xxxx......xx
-..xxxxxx..xxxxxx
-..xxxxxx..xxxxxx""")
-
-add("85 - YellowStalfos", dung=(25, 15), ss_1 = """
-xxxxxxxxxxxxxxxx
-xxxxxxxxxxxxxxxx
-....xx....xxxxxx
-....xx....xxxxxx""")
-
-add("86 - Kodongo", dung=(25, 6), ss_3 = """
-............xx..
-............xx..
-xxxxxxxxxxxxxx..
-xxxxxxxxxxxxxx..""")
-
-add("88 - Mothula", dung=(26, 14), ss_3 = """
-xxxxxxxxxx.xxxxx
-xxxxxxxxxx.xxxxx
-xxxxxxxxxx..xxxx
-xxxxxxxxxx..xxxx""")
-
-add("89 - MothulaRing", dung=(26, 14), ss_3 = """
-..........x.....
-..........x.....
-..........xx....
-..........xx....""")
-
-add("8a - SpikeBlock", dung=(8, 15), ss_4 = """
-................
-................
-......xx........
-......xx........""")
-
-add("8b - Gibdo", dung=(19, 13), ss_3 = """
-xxxxxxxxxxxxxxxx
-xxxxxxxxxxxxxxxx
-xxxxxx..........
-xxxxxx..........""")
-
-add("8c - Arrghus", dung=(20, 8), ss_3 = """
-xxxxxxxxxx......
-xxxxxxxxxx......
-xxxxxxxxxx......
-xxxxxxxxxx......""")
-
-add("8e - TerrorPin", dung=(25, 15), ss_3 = """
-..........xx..xx
-..........xx..xx
-..............xx
-..............xx""")
-
-add("8f - Blob", dung=(17, 8), ss_2 = """
-xxxxxx..........
-xxxxxx..........
-x...............
-x...............""")
-
-add("90 - WallMaster", dung=(19, 13), ss_3 = """
-................
-................
-......xxxxxxxxxx
-......xxxxxxxxxx""")
-
-add("91 - StalfosKnight", dung=(28, 19), ss_2 = """
-......xxxxxxxx..
-......xxxxxxxx..
-.xxxxxxxxxx.....
-.xxxxxxxxxx.....""")
-
-add("92 - HelmasaurKing", dung=(21, 16), ss_3 = """
-xxxxxxxxxxxxxxxx
-xxxxxxxxxxxxxxxx
-xxxxxxxxxxxxxx66
-xxxxxxxxxxxxxx66""", ss_4 = """
-6666666666xxxxxx
-6666666666xxxxxx
-6666xxOOOOOOOOOO
-6666xxOOOOOOOOOO""", palette = 5)
-
-add("93 - Bumper", dung=(12, 26), ss_4 = """
-................
-................
-............xx..
-............xx..""")
-
-add("94 - Pirogusu", dung=(17, 10), ss_3 = """
-.......x....xxxx
-.......x....xxxx
-..........xxxxxx
-..........xxxxxx""")
-
-add("95 - LaserEye", dung=(29, 17), ss_4 = """
-......xxxx......
-..2...xxxx......
-................
-...2............""")
-
-add("99 - Pengator", dung=(28, 19), ss_3 = """
-xxxxxxxxxxxxxxxx
-xxxxxxxxxxxxxxxx
-xxxxxx..........
-xxxxxx..........""")
-
-add("9a - Kyameron", dung=(17, 10), ss_3 = """
-......x.xxxx....
-......x.xxxx....
-xxxxxxxxxx......
-xxxxxxxxxx......""")
-
-add("9b - Wizzrobe", dung=(29, 17), ss_3 = """
-......xxxxxxxxxx
-......xxxxxxxxxx
-....xx..........
-..xxxx..........""")
-
-add("9b - Wizzrobe (DW)", dung=(36, 37), ss_3 = """
-......xxxxxxxxxx
-......xxxxxxxxxx
-....xx..........
-..xxxx..........""")
-
-
-
-add("9c - Babasu", dung=(17, 10), ss_2 = """
-..............xx
-..............xx
-...........xxxxx
-...........xxxxx""", palette=1)
-
-add("9e - HauntedGroveOstrich", ow=(15, 1), ss_3 = """
-xxxxxx..........
-xxxxxx..........
-xxxxxx..........
-xxxxxx..........""")
-
-add("9f - HauntedGroveRabbit", ow=(15, 1), ss_3 = """
-........xxxxxx..
-........xxxxxx..
-......xx........
-......xx........""")
-
-add("A0 - HauntedGroveBird", ow=(15, 1), ss_3 = """
-......xx......xx
-......xx......xx
-............xxx.
-............xx..""")
-
-add("A1 - Freezor", dung=(28, 19), ss_3 = """
-................
-................
-......xxxxxxxxxx
-......xxxxxxxxxx""")
-
-add("A2 - Kholdstare", dung=(22, 20), ss_3 = """
-xxxxxxxx....xx..
-xxxxxxxx....xx..
-xxxxxxxxxxxxxxxx
-xxxxxxxxxxxxxxxx""")
-
-add("A4 - FallingIce", dung=(22, 20), ss_3 = """
-........xxxx..xx
-........xxxx..xx
-................
-................""")
-
-add("A5 - Zazak", dung=(27, 23), ss_3 = """
-xxxxxxxxxx......
-xxxxxxxxxx......
-xxxxxxxxxx......
-xxxxxxxxxx......""")
-
-add("A8 - GreenZirro", ow=(19, 14), ss_4 = """
-xxxxxxxx........
-xxxxxxxx........
-xxxxxxxx........
-xxxxxxxx.......7""")
-
-add("AA - Pikit", ow=(19, 14), ss_4 = """
-........xxxxxxxx
-........xxxxxxxx
-..........xxxxx.
-..........xxxxx.""")
-
-add("AD - OldMan", dung=(1, 7), ss_3 = """
-................
-................
-............xxxx
-............xxxx""")
-
-
-add("B4 - PurpleChest", ow=(21, 16), ss_1 = """
-................
-................
-..............xx
-..............xx""", ss_4 = """
-................
-................
-..............xx
-..............xx""")
-
-add("B5 - BombShop", dung=(5, 31), ss_2 = """
-........xx..xxxx
-........xx..xx44
-................
-................""", palette = 1)
-
-add("B6 - Kiki", ow=(23, 13), ss_4 = """
-..........xxx.xx
-..........xxxxxx
-............xxxx
-............xxxx""")
-
-add("B9 - BullyAndPinkBall", dw=(20, 12), ss_4 = """
-....xx..........
-....xx..........
-xxxx............
-xxxx............""", palette = 6)
-
-add("B9 - BullyAndPinkBall", dw=(20, 12), ss_4 = """
-xxxx............
-xxxx............
-................
-................""")
-
-add("BB - Shopkeeper", dung=(5, 7), ss_1 = """
-xxxx............
-xxxx............
-xxxx............
-xxxx............""", palette = 5)
-
-add("BB - Shopkeeper", dung=(5, 7), ss_4 = """
-11..22......4422
-11..22......4422
-........22......
-........22......""")
-
-add("BB - Shopkeeper", dung=(15, 31), ss_2 = """
-......xx........
-......xx........
-................
-................""", palette = 6)
-
-add("BB - Shopkeeper", dung=(40, 5), ss_1 = """
-xxxxxxxx..xx..xx
-xxxxxxxx..xx..xx
-xxxxxx......xx..
-xxxxxx......xx..""", palette = 6)
-
-add("BB - Shopkeeper", dung=(15, 5), ss_1 = """
-xxxx............
-xxxx............
-xx..............
-xx..............""", palette = 6)
-
-add("BB - Shopkeeper", dung=(42, 32), ss_1 = """
-xxxxxxxx..xx..xx
-xxxxxxxx..xx..xx
-xxxxxx..........
-xxxxxx..........""", palette = 6)
-
-add("BC - Drunkard", dung=(15, 5), ss_1 = """
-......xx........
-......xx........
-..xx............
-..xx............""", ss_3 = """
-................
-................
-..............xx
-................""", palette = 4)
-
-add("BD - Viterous", dung=(22, 18), ss_4 = """
-xxxxxxxxxxxx....
-xxxxxxxxxxxx....
-xxxxxxxxxxxx....
-xxxxxxxxxxxx....""")
-
-add("BF - ViterousLightning", dung=(22, 18), ss_4 = """
-............xxxx
-............xxxx
-............xxxx
-............xxxx""")
-
-add("C0 - Catfish", ow=(22, 10), ss_3 = """
-......xxxxxxxxx.
-......xxxxxxxxx.
-........x...xxx.
-.............xx.""")
-
-add("C1 - CutsceneAgahnim", dung=(18, 12), ss_1 = """
-xxxxxx..........
-xxxxxx..........
-xxxxxxxx........
-xxxxxxx.........""", ss_3 = """
-xxxx............
-xxxx............
-xxxx............
-xxxx............""", ss_4 = """
-..............2.
-...............x
-............xxxx
-............xxxx""", palette = 5)
-
-add("C3 - Gibo", dung=(27, 23), ss_3 = """
-..........xxxxxx
-..........xxxxxx
-..........xxxxxx
-..........xxxxxx""")
-
-add("C7 - Pokey", dung=(30, 24), ss_3 = """
-xxxx............
-xxxx............
-xxxx............
-xxxx............""")
-
-add("C8 - BigFairy", dung=(7, 7), ss_3 = """
-..........xxxxxx
-..........xxxxxx
-..........xxxxxx
-..........xxxxxx""")
-
-add("C9 - Tektite", dw=(5, 7), ss_4 = """
-........xxxx....
-........xxxx....
-..........xx....
-..........xx....""", palette = 4)
-
-add("CA - ChainChomp", dung=(30, 24), ss_3 = """
-......xx...xxx..
-......xx....xx..
-......xxxxxx....
-......xxxxxx....""")
-
-add("CB - Trinexx", dung=(23, 25), ss_1 = """
-xxxx55xx55xxxxXX
-xxxx55xx55xxxxXX
-xxxx55xxxxxxxxXX
-xxxx55xxxxxxxxXX""", ss_4 = """
-xxxxxxXXXXXXXXXX
-xxxxxxXXXXXXXXXX
-xxxxxxxxxxXXXXxx
-xxxxxxxxxxXXXXxx""")
-
-add("CE - Blind", dung=(32, 23), ss_3 = """
-xxxxxxxxxxxxxx66
-xxxxxxxxxxxxxx66
-666666xxxxxx6666
-666666xxxxxx6666""", palette = 5)
-
-add("CF - Swamola", ow=(22, 15), ss_4 = """
-xxxx............
-xxxx............
-xxxxxxxxxxxx....
-xxxxxxxxxxxx....""")
-
-add("D0 - Lynel", ow=(20, 12), ss_4 = """
-......xxxxxxxxxx
-......xxxxxxxxxx
-....xxxxxxxxxxxx
-....xxxxxxxxxxxx""")
-
-add("D5 - DigGameGuy", ow=(27, 18), ss_2 = """
-xxxxxxx.........
-xxxxxxx.........
-................
-................""", palette = 5)
-
-add("D6 - Ganon", dung=(34, 33), ss_2 = """
-....xx..........
-....xx..........
-xxxxxx..........
-xxxxxx..........""", palette = 4)
-
-add("D6 - Ganon", dung=(34, 33), ss_1 = """
-xx5555xxxxxxxx55
-xx5555xxxxxxxx55
-xx5555xxxxxxxxxx
-xx5555xxxxxxxxxx""", ss_2 = """
-xxxx..xxxxxxxx55
-xxxx..xxxxxxxx55
-......xxxxxxxx55
-......xxxxxxxx55""", ss_3 = """
-xxxx55xxxxxxxxxx
-xxxx55xxxxxxxxxx
-xxxx55xxxxxxxxxx
-xxxx55xxxxxxxxxx""", ss_4 = """
-xxxxxx5555xxxx55
-xxxxxx5555xxxx55
-xxxxxx5555xxxx55
-xxxxxx5555xxxx55""", palette = 6)
-
-add("E7 - Mushroom", ow=(7, 5), ss_4 = """
-................
-................
-..............xx
-..............xx""", palette = 3)
-
-add("E8 - FakeSword", ow=(7, 5), ss_4 = """
-................
-................
-................
-....xx..........""")
-
-add("E9 - PotionShop", dung=(5, 5), ss_4 = """
-................
-................
-......xx........
-......xx........""", palette = 2)
-
-add("ED - SomariaPlatform", dung=(30, 24), ss_3 = """
-................
-................
-............XX..
-............XX..""")
-
-add("EE - MovableMantle", dung=(3, 0), ss_1 = """
-............xxxx
-............xxxx
-............xxxx
-............xxxx""")
-
-add("F2 - MedallionTablet", ow=(8, 4), ss_3 = """
-..........xxxx..
-..........xxxx..
-..........xxxx..
-..........xxxx..""")
-
-add("F4 - FallingRocks", ow=(5, 7), ss_4 = """
-............xxxx
-............xxxx
-............xxxx
-............xxxx""")
-
-add("XX - Unknown Sheet 00", sheet=(0, 1), ss_1 = """
-xxxxxxxxxxxxxxxx
-xxxxxxxxxxxxxxxx
-xxxxxxxxxxxxxxxx
-xxxxxxxxxxxxxxxx""", palette = 4)
-
-add("XX - Unknown Sheet 01", sheet=(1, 1), ss_1 = """
-xxxxxxxxxxxxxxxx
-xxxxxxxxxxxxxxxx
-xxxxxxxxxxxxxxxx
-xxxxxxxxxxxxxxxx""", palette = 4)
-
-add("XX - Unknown Sheet 02", sheet=(2, 1), ss_1 = """
-xxxxxxxxxxxxxxxx
-xxxxxxxxxxxxxxxx
-xxxxxxxxxxxxxxxx
-xxxxxxxxxxxxxxxx""", palette = 4)
-
-add("XX - Unknown Sheet 03", sheet=(3, 1), ss_1 = """
-xxxxxxxxxxxxxxxx
-xxxxxxxxxxxxxxxx
-xxxxxxxxxxxxxxxx
-xxxxxxxxxxxxxxxx""", palette = 4)
-
-add("XX - Unknown Sheet 04", sheet=(4, 1), ss_1 = """
-xxxxxxxxxxxxxxxx
-xxxxxxxxxxxxxxxx
-xxxxxxxxxxxxxxxx
-xxxxxxxxxxxxxxxx""", palette = 4)
-
-add("XX - Unknown Sheet 05", sheet=(5, 1), ss_1 = """
-xxxxxxxxxxxxxxxx
-xxxxxxxxxxxxxxxx
-xxxxxxxxxxxxxxxx
-xxxxxxxxxxxxxxxx""", palette = 4)
-
-add("XX - Unknown Sheet 06", sheet=(6, 1), ss_1 = """
-xxxxxxxxxxxxxxxx
-xxxxxxxxxxxxxxxx
-xxxxxxxxxxxxxxxx
-xxxxxxxxxxxxxxxx""", palette = 4)
-
-add("XX - Unknown Sheet 07", sheet=(7, 1), ss_1 = """
-xxxxxxxxxxxxxxxx
-xxxxxxxxxxxxxxxx
-xxxxxxxxxxxxxxxx
-xxxxxxxxxxxxxxxx""", palette = 4)
-
-add("XX - Unknown Sheet 08", sheet=(8, 1), ss_1 = """
-xxxxxxxxxxxxxxxx
-xxxxxxxxxxxxxxxx
-xxxxxxxxxxxxxxxx
-xxxxxxxxxxxxxxxx""", palette = 4)
-
-add("XX - Unknown Sheet 09", sheet=(9, 1), ss_1 = """
-xxxxxxxxxxxxxxxx
-xxxxxxxxxxxxxxxx
-xxxxxxxxxxxxxxxx
-xxxxxxxxxxxxxxxx""", palette = 4)
-
-add("XX - Unknown Sheet 10", sheet=(10, 1), ss_1 = """
-xxxxxxxxxxxxxxxx
-xxxxxxxxxxxxxxxx
-xxxxxxxxxxxxxxxx
-xxxxxxxxxxxxxxxx""", palette = 4)
-
-add("XX - Unknown Sheet 11", sheet=(11, 1), ss_1 = """
-xxxxxxxxxxxxxxxx
-xxxxxxxxxxxxxxxx
-xxxxxxxxxxxxxxxx
-xxxxxxxxxxxxxxxx""", palette = 4)
-
-add("XX - Unknown Sheet 14", ow=(37, 1), ss_1 = """
-........xx..xx..
-........xx..xx..
-........xxxx..xx
-........xxxx..xx""", palette = 4)
-
-
-add("XX - Unknown Sheet 15", ow=(26, 1), ss_1 = """
-..........xxxx..
-..........xxxx..
-............xxxx
-............xxxx""", palette = 4)
-
-
-add("XX - Unknown Sheet 21", ow=(21, 1), ss_1 = """
-............xx..
-............xx..
-................
-................""", palette = 4)
-
-add("XX - Unknown Sheet 27", ow=(25, 1), ss_4 = """
-................
-................
-...............x
-................""", palette = 4)
-
-add("XX - Unknown Sheet 37", ow=(93, 1), ss_3 = """
-................
-................
-..xx..xxxx......
-......xxxx......""", palette = 4)
-
-
-add("XX - Unknown Sheet 39", ow=(94, 1), ss_3 = """
-....xx..........
-....xx.....x....
-....xx..........
-....xx........xx""", palette = 4)
-
-add("XX - Unknown Sheet 41", dung=(36, 1), ss_3 = """
-xxxxxx..........
-xxxxxx..........
-xxxx...........x
-xx.............x""", palette = 4)
-
-
-add("XX - Unknown Sheet 42", ow=(107, 1), ss_3 = """
-.......xxx......
-.......xxx......
-................
-................""", palette = 4)
-
-add("XX - Unknown Sheet 43", dung=(16, 1), ss_4 = """
-xxxxxxxxxxxxxxxx
-xxxxxxxxxxxxxxxx
-xxxxxxxxxxxxxxxx
-xxxxxxxxxxxxxxxx""", palette = 4)
-
-add("XX - Unknown Sheet 44", ow=(72, 1), ss_2 = """
-.............x..
-.............x..
-xx..............
-xx..............""", palette = 4)
-
-add("XX - Unknown Sheet 45", ow=(45, 1), ss_1 = """
-xxxxxxxxxxxxxxxx
-xxxxxxxxxxxxxxxx
-xxxxxxxxxxxxxxxx
-xxxxxxxxxxxxxxxx""", palette = 4)
-
-add("XX - Unknown Sheet 46", ow=(73, 1), ss_3 = """
-xxxxxxxxxx......
-xxxxxxxxxx......
-................
-..............xx""", palette = 4)
-
-add("XX - Intro Sheet 50", sheet=(50, 1), ss_1 = """
-xxxxxxxxxxxxxxxx
-xxxxxxxxxxxxxxxx
-xxxxxxxxxxxxxxxx
-xxxxxxxxxxxxxxxx""", palette = 4)
-
-add("XX - Ending Sheet 52", sheet=(52, 1), ss_2 = """
-xxxxxxxxxxxxxxxx
-xxxxxxxxxxxxxxxx
-xxxxxxxxxxxxxxxx
-xxxxxxxxxxxxxxxx""", palette = 4)
-
-add("XX - Ending Sheet 53", sheet=(53, 1), ss_1 = """
-xxxxxxxxxxxxxxxx
-xxxxxxxxxxxxxxxx
-xxxxxxxxxxxxxxxx
-xxxxxxxxxxxxxxxx""", palette = 4)
-
-add("XX - Unknown Sheet 54", ow=(40, 1), ss_4 = """
-xxx....x........
-xxx....x........
-................
-................""", palette = 4)
-
-add("XX - Unknown Sheet 55", ow=(12, 1), ss_3 = """
-............xxxx
-............xxxx
-.............xxx
-.............xxx""", palette = 4)
-
-add("XX - Unknown Sheet 72", ow=(2, 1), ss_1 = """
-................
-................
-...........xxxxx
-...........xxxxx""", palette = 4)
-
-add("XX - Unknown Sheet 75", ow=(27, 1), ss_1 = """
-................
-................
-.............x..
-............xx..""", palette = 4)
-
-
-add("XX - Unknown Sheet 76", ow=(13, 1), ss_3 = """
-..............xx
-..............xx
-..........xx....
-..........xx....""", palette = 4)
-
-add("XX - Unknown Sheet 82", dung=(19, 1), ss_4 = """
-xxxx......xxxx..
-xx.x......xxxx..
-x.x.....xxxx....
-xxx.....xxxx....""", palette = 4)
-
-add("XX - Unknown Sheet 83", dung=(38, 1), ss_4 = """
-...xxxxxxx....xx
-..xxxxxxxx....xx
-xxxxxxxxxx..xxxx
-xxxxxxxxxx..xxxx""", palette = 4)
-
-add("XX - Unknown Sheet 84", sheet=(84, 1), ss_3 = """
-xxxxxxxxxxxxxxxx
-xxxxxxxxxxxxxxxx
-xxxxxxxxxxxxxxxx
-xxxxxxxxxxxxxxxx""", palette = 4)
-
-add("XX - Unknown Sheet 85", dung=(63, 1), ss_1 = """
-......xxxxxx....
-......xxxxxx....
-........xxxx....
-.......xxxxx....""", palette = 4)
-
-add("XX - Map Sheet 86", sheet=(86, 1), ss_2 = """
-xxxxxxxxxxxxxxxx
-xxxxxxxxxxxxxxxx
-xxxxxxxxxxxxxxxx
-xxxxxxxxxxxxxxxx""", palette = 4)
-
-add("XX - Map Sheet 87", sheet=(87, 1), ss_3 = """
-xxxxxxxxxxxxxxxx
-xxxxxxxxxxxxxxxx
-xxxxxxxxxxxxxxxx
-xxxxxxxxxxxxxxxx""", palette = 4)
-
-add("XX - Unknown Sheet 88", sheet=(88, 1), ss_3 = """
-xxxxxxxxxxxxxxxx
-xxxxxxxxxxxxxxxx
-xxxxxxxxxxxxxxxx
-xxxxxxxxxxxxxxxx""", palette = 4)
-
-add("XX - Tagalong S89", sheet=(89, 1), ss_4 = """
-xxxxxxxxxxxxxxxx
-xxxxxxxxxxxxxxxx
-xxxxxxxxxxxxxxxx
-xxxxxxxxxxxxxxxx""", palette = 4)
-
-add("XX - Unknown Sheet 90", dung=(5, 1), ss_4 = """
-..xx..xxxxxx....
-..xx..xxxxxx....
-xxxxxx....xxxxxx
-xxxxxx....xxxxxx""", palette = 4)
-
-add("XX - Unknown Sheet 91", sheet=(91, 1), ss_3 = """
-xxxxxxxxxxxxxxxx
-xxxxxxxxxxxxxxxx
-xxxxxxxxxxxxxxxx
-xxxxxxxxxxxxxxxx""", palette = 4)
-
-add("XX - Unknown Sheet 92", sheet=(92, 1), ss_3 = """
-xxxxxxxxxxxxxxxx
-xxxxxxxxxxxxxxxx
-xxxxxxxxxxxxxxxx
-xxxxxxxxxxxxxxxx""", palette = 4)
-
-add("XX - Unknown Sheet 93", ow=(43, 1), ss_3 = """
-xxxxxxxxxxxx....
-xxxxxxxxxxxx....
-xxxxxxxxxxxx....
-xxxxxxxxxxxx....""", palette = 4)
-
-add("XX - Unknown Sheet 94", sheet=(94, 1), ss_3 = """
-xxxxxxxxxxxxxxxx
-xxxxxxxxxxxxxxxx
-xxxxxxxxxxxxxxxx
-xxxxxxxxxxxxxxxx""", palette = 4)
-
-add("XX - Unknown Sheet 95", sheet=(95, 1), ss_3 = """
-xxxxxxxxxxxxxxxx
-xxxxxxxxxxxxxxxx
-xxxxxxxxxxxxxxxx
-xxxxxxxxxxxxxxxx""", palette = 4)
-
-add("XX - Unknown Sheet 96", sheet=(96, 1), ss_3 = """
-xxxxxxxxxxxxxxxx
-xxxxxxxxxxxxxxxx
-xxxxxxxxxxxxxxxx
-xxxxxxxxxxxxxxxx""", palette = 4)
-
-add("XX - Map Sheet 97", sheet=(97, 1), ss_1 = """
-xxxxxxxxxxxxxxxx
-xxxxxxxxxxxxxxxx
-xxxxxxxxxxxxxxxx
-xxxxxxxxxxxxxxxx""", palette = 4)
-
-add("XX - Map Sheet 98", sheet=(98, 1), ss_2 = """
-xxxxxxxxxxxxxxxx
-xxxxxxxxxxxxxxxx
-xxxxxxxxxxxxxxxx
-xxxxxxxxxxxxxxxx""", palette = 4)
-
-add("XX - Map Sheet 99", sheet=(99, 1), ss_3 = """
-xxxxxxxxxxxxxxxx
-xxxxxxxxxxxxxxxx
-xxxxxxxxxxxxxxxx
-xxxxxxxxxxxxxxxx""", palette = 4)
-
-add("XX - Tagalong S100", sheet=(100, 1), ss_1 = """
-xxxxxxxxxxxxxxxx
-xxxxxxxxxxxxxxxx
-xxxxxxxxxxxxxxxx
-xxxxxxxxxxxxxxxx""", palette = 4)
-
-add("XX - Tagalong S101", sheet=(101, 1), ss_1 = """
-xxxxxxxxxxxxxxxx
-xxxxxxxxxxxxxxxx
-xxxxxxxxxxxxxxxx
-xxxxxxxxxxxxxxxx""", palette = 4)
-
-
-add("XX - Tagalong S102", sheet=(102, 1), ss_1 = """
-xxxxxxxxxxxxxxxx
-xxxxxxxxxxxxxxxx
-xxxxxxxxxxxxxxxx
-xxxxxxxxxxxxxxxx""", palette = 4)
--- a/tables/sprite_sheets.py
+++ /dev/null
@@ -1,640 +1,0 @@
-from PIL import Image
-import sprite_sheet_info
-import util
-from util import get_bytes, get_words, get_byte, cache
-import array
-import tables
-import sys
-
-override_armor_palette = None
-#override_armor_palette = [0x7fff, 0x237e, 0x11b7, 0x369e, 0x14a5,  0x1ff, 0x1078, 0x599d, 0x3647, 0x3b68, 0xa4a, 0x12ef, 0x2a5c, 0x1571, 0x7a18,
-#                          0x7fff, 0x237e, 0x11b7, 0x369e, 0x14a5,  0x1ff, 0x1078, 0x599d, 0x6980, 0x7691, 0x26b8, 0x437f, 0x2a5c, 0x1199, 0x7a18,
-#                          0x7fff, 0x237e, 0x11b7, 0x369e, 0x14a5,  0x1ff, 0x1078, 0x599d, 0x1057, 0x457e, 0x6df3, 0xfeb9, 0x2a5c, 0x2227, 0x7a18,
-#                          0x7fff, 0x237e, 0x11b7, 0x369e, 0x14a5,  0x1ff, 0x1078, 0x3d97, 0x3647, 0x3b68, 0xa4a, 0x12ef, 0x567e, 0x1571, 0x7a18,
-#                          0,      0x0EFA, 0x7DD1, 0,      0x7F1A,  0x7F1A,0,      0x716E, 0x7DD1, 0x40A7, 0x7DD1, 0x40A7, 0x48E9, 0x50CF, 0x7FFF]
-
-
-def save_as_png(dimensions, data, fname, palette = None):
-  img = Image.new('L' if palette == None else 'P', dimensions)
-  img.putdata(data)
-  if palette != None:
-    img.putpalette(palette)
-  img.save(fname)
-
-def save_as_24bpp_png(dimensions, data, fname):
-  img = Image.new("RGB", dimensions)
-  img.putdata(data)
-  img.save(fname)
-
-@cache
-def decode_2bit_tileset(tileset, height = 32, base = 0):
-  data = util.decomp(tables.kCompSpritePtrs[tileset], get_byte, False)
-  assert len(data) == 0x400 * height // 32
-  dst = bytearray(128*height)
-  def decode_2bit(offs, toffs, base):
-    for y in range(8):
-      d0, d1 = data[offs + y * 2], data[offs + y * 2 + 1]
-      for x in range(8):
-        t = ((d0 >> x) & 1) * 1 + ((d1 >> x) & 1) * 2
-        dst[toffs + y * 128 + (7 - x)] = t + base
-  for i in range(16*height//8):
-    x = i % 16
-    y = i // 16
-    decode_2bit(i * 16, x * 8 + y * 8 * 128, base[i] if isinstance(base, tuple) else base)
-  return dst
-
-def is_high_3bit_tileset(tileset):
-  # is 0x5c, 0x5e, 0x5f included or not?
-  return tileset in (0x52, 0x53, 0x5a, 0x5b, 0x5c, 0x5e, 0x5f)
-
-def get_unpacked_snes_tileset(tileset):
-  if tileset < 12:
-    return get_bytes(tables.kCompSpritePtrs[tileset], 0x600)
-  else:
-    return util.decomp(tables.kCompSpritePtrs[tileset], get_byte, False)
-
-@cache
-def decode_3bit_tileset(tileset):
-  data = get_unpacked_snes_tileset(tileset)
-  assert len(data) == 0x600
-  base = 8 if is_high_3bit_tileset(tileset) else 0
-  height = 32
-  dst = bytearray(128*height)
-  def decode_3bit(offs, toffs):
-    for y in range(8):
-      d0, d1, d2 = data[offs + y * 2], data[offs + y * 2 + 1], data[offs + y + 16]
-      for x in range(8):
-        t = ((d0 >> x) & 1) * 1 + ((d1 >> x) & 1) * 2 + ((d2 >> x) & 1) * 4
-        dst[toffs + y * 128 + (7 - x)] = base + t
-  for i in range(16*height//8):
-    x, y = i % 16, i // 16
-    decode_3bit(i * 24, x * 8 + y * 8 * 128)
-  return dst
-
-def decode_4bit_tileset_link():
-  height = 448
-  data = get_bytes(0x108000, 0x800 * height // 32) # only link sprites for now
-  dst = bytearray(128*height)
-  def decode_4bit(offs, toffs):
-    for y in range(8):
-      d0, d1, d2, d3 = data[offs + y * 2 + 0], data[offs + y * 2 + 1], data[offs + y * 2 + 16], data[offs + y * 2 + 17]
-      for x in range(8):
-        t = ((d0 >> x) & 1) * 1 + ((d1 >> x) & 1) * 2 + ((d2 >> x) & 1) * 4 + ((d3 >> x) & 1) * 8
-        dst[toffs + y * 128 + (7 - x)] = t
-  for i in range(16*height//8):
-    x, y = i % 16, i // 16
-    decode_4bit(i * 32, x * 8 + y * 8 * 128)
-  return dst
-
-def convert_snes_palette(v):
-  rr=bytearray()
-  for x in v:
-    r, g, b = x & 0x1f, x >> 5 & 0x1f, x >> 10 & 0x1f
-    rr.extend((r << 3 | r >> 2, g << 3 | g >> 2, b << 3 | b >> 2))
-  return rr
-
-def convert_int24_palette_to_bytes(v):
-  rr=bytearray()
-  for x in v:
-    rr.extend((x & 0xff, x >> 8 & 0xff, x >> 16 & 0xff))
-  return rr
-
-def convert_snes_palette_to_int(v):
-  rr=[]
-  for x in v:
-    r, g, b = x & 0x1f, x >> 5 & 0x1f, x >> 10 & 0x1f
-    rr.append((r << 3 | r >> 2) | (g << 3 | g >> 2) << 8 | (b << 3 | b >> 2) << 16)
-  return rr
-
-def decode_link_sprites():
-  kLinkPalette = [0, 0x7fff, 0x237e, 0x11b7, 0x369e, 0x14a5,  0x1ff, 0x1078, 0x599d, 0x3647, 0x3b68,  0xa4a, 0x12ef, 0x2a5c, 0x1571, 0x7a18]
-  save_as_png((128, 448), decode_4bit_tileset_link(), 'linksprite.png', convert_snes_palette(kLinkPalette))
-
-def get_hud_snes_palette():
-  hud_palette  = get_words(0x9BD660, 64)
-  palette = [(31 << 10 | 31) for i in range(256)]
-  for i in range(16):
-    for j in range(1, 4):
-      palette[i * 16 + j] = hud_palette[i * 4 + j]
-  return palette
-
-def decode_hud_icons():
-  class PaletteUsage:
-    def __init__(self):
-      self.data = open('palette_usage.bin', 'rb').read()
-    def get(self, icon):
-      usage = self.data[icon]
-      for j in range(8):
-        if usage & (1 << j):
-          return j 
-      return 0
-  pu = PaletteUsage()
-  dst = bytearray()
-  for slot, image_set in enumerate([106, 107, 105]):
-    tbase = tuple([pu.get(slot * 128 + i) * 16 for i in range(128)])
-    dst += decode_2bit_tileset(image_set, height = 64, base = tbase)
-
-  save_as_png((128, 64 * 3), dst, 'hud_icons.png', convert_snes_palette(get_hud_snes_palette()[:128]))
-
-def get_pt_remapper():
-  b = util.ROM.get_bytes(0x8EFC09, 121 * 3)
-  d = {}
-  for i in range(121):
-    ch = (i & 0xf) | (i << 1) & 0xe0
-    d[ch] = b[i*3+0]
-    d[ch|0x10] = b[i*3+1]
-  return d
-
-kFontTypes = {
-  'us'   : (0x8e8000, 256, 'font.png', (0x8ECADF, 99)),
-  'de'   : (0xCC6E8, 256, 'font_de.png', (0x8CDECF, 112)),
-  'fr'   : (0xCC6E8, 256, 'font_fr.png', (0x8CDEAF, 112)),
-  'fr-c' : (0xCD078, 256, 'font_fr_c.png', (0x8CE83F, 112)),
-  'en'   : (0x8E8000, 256, 'font_en.png', (0x8ECAFF, 102)),
-  'es'   : (0x8e8000, 256, 'font_es.png', (0x8ECADF, 99)),
-  'pl'   : (0x8e8000, 256, 'font_pl.png', (0x8ECADF, 99)),
-  'pt'   : (0x8e8000, 256, 'font_pt.png', (0x8ECADF, 121)),
-  'redux': (0x8e8000, 256, 'font_redux.png', (0x8ECADF, 99)),
-  'nl': (0x8e8000, 256, 'font_nl.png', (0x8ECADF, 99)),
-  'sv': (0x8e8000, 256, 'font_sv.png', (0x8ECADF, 99)),
-}
-
-def decode_font():
-  lang = util.ROM.language
-  def decomp_one_spr_2bit(data, offs, target, toffs, pitch, palette_base):
-    for y in range(8):
-      d0, d1 = data[offs + y * 2], data[offs + y * 2 + 1]
-      for x in range(8):
-        t = ((d0 >> x) & 1) * 1 + ((d1 >> x) & 1) * 2
-        target[toffs + y * pitch + (7 - x)] = t + palette_base
-  ft = kFontTypes[lang]
-  if lang == 'pt':
-    W = util.ROM.get_bytes(0x8EFC09, 121 * 3)
-    W = [W[i*3+2] for i in range(121)]
-    remapper = get_pt_remapper()
-  else:
-    W = get_bytes(*ft[3])
-    remapper = {}
-  w = 128 + 15
-  hi = ft[1] // 32
-  h = hi * 17
-  data = get_bytes(ft[0], ft[1] * 16)
-  dst = bytearray(w * h)
-  
-  for i in range(ft[1]):
-    x, y = i % 16, i // 16
-    pal_base = 6 * 16
-    base_offs = x * 9 + (y * 8 + (y >> 1)) * w
-    decomp_one_spr_2bit(data, remapper.get(i, i) * 16, dst, base_offs + w, w, pal_base)
-    if (y & 1) == 0:
-      j = (y >> 1) * 16 + x
-      if j < len(W):
-        dst[base_offs + W[j] - 1] = 255
-  pal = convert_snes_palette(get_hud_snes_palette()[:128])
-  pal.extend([0] * 384)
-  pal[0], pal[1], pal[2] = 192, 192, 192
-  pal[255*3+0], pal[255*3+1], pal[255*3+2] = 128, 128, 128
-  save_as_png((w, h), dst, ft[2], pal)
-  if lang != 'pt':
-    assert (data, W) == encode_font_from_png(lang)
-
-def encode_font_from_png(lang):
-  font_data = Image.open(kFontTypes[lang][2]).tobytes()
-  def encode_one_spr_2bit(data, offs, target, toffs, pitch):
-    for y in range(8):
-      d0, d1 = 0, 0
-      for x in range(8):
-        pixel = data[offs + y * pitch + 7 - x]
-        d0 |= (pixel & 1) << x
-        d1 |= ((pixel >> 1) & 1) << x
-      target[toffs + y * 2 + 0], target[toffs + y * 2 + 1] = d0, d1
-  w = 128 + 15
-  dst = bytearray(256 * 16)
-  def get_width(base_offs):
-    for i in range(8):
-      if font_data[base_offs + i] == 255:
-        break
-    return i + 1
-  W = bytearray()
-  for i in range(256):
-    x, y = i % 16, i // 16
-    base_offs = x * 9 + (y * 8 + (y >> 1)) * w
-    if (y & 1) == 0:
-      W.append(get_width(base_offs))
-    encode_one_spr_2bit(font_data, base_offs + w, dst, i * 16, w)
-  chars_per_lang = kFontTypes[lang][3][1]
-  return dst, W[:chars_per_lang]
-
-# Returns the dungeon palette for the specified palette index
-# 0 = lightworld, 1 = darkworld, 2 = dungeon
-@cache
-def get_palette_subidx(palset_idx, dungeon_or_ow, which_palette):
-  spmain = 1 if (dungeon_or_ow == 1) else 0
-  if dungeon_or_ow == 2:
-    main, sp0l, sp5l, sp6l = tables.kDungPalinfos[palset_idx]
-    sp0r = (main // 2) + 11
-    sp6r = 10
-  else:
-    sp5l, sp6l = tables.kOwSprPalInfo[palset_idx * 2 : palset_idx * 2 + 2]
-    sp0l = 3 if dungeon_or_ow == 1 else 1
-    sp0r = 9 if dungeon_or_ow == 1 else 7
-    sp6r = 8 if dungeon_or_ow == 1 else 6
-  pal_defs = (sp0l, sp0r, 
-    spmain, None, spmain, None, spmain, None, None, None,
-    sp5l, None,
-    sp6l, sp6r,
-    None, None)
-  return pal_defs[which_palette]
-
-@cache
-def get_palette_subset(pal_idx, j):
-  if j == None: j = 0
-  pal = [0] * 7
-  if pal_idx == 0: # 0
-    kPalette_SpriteAux3 = get_words(0x9BD39E, 84)
-    return kPalette_SpriteAux3[j * 7 : j * 7 + 7]
-  if pal_idx == 1: # 0R
-    if j < 11:
-      kPalette_MiscSprite = get_words(0x9BD446, 77)
-      return kPalette_MiscSprite[j * 7 : j * 7 + 7]
-    else:
-      kPalette_DungBgMain = get_words(0x9BD734, 1800)
-      return kPalette_DungBgMain[(j - 11) * 90 : (j - 11) * 90 + 7]
-  if pal_idx in (2, 3, 4, 5, 6, 7, 8, 9):
-    o = j * 60 + ((pal_idx - 2) >> 1) * 15 + (pal_idx & 1) * 8
-    kPalette_MainSpr = get_words(0x9BD218, 120)
-    return kPalette_MainSpr[o : o + 7]
-  if pal_idx in (10, 12):
-    kPalette_SpriteAux1 = get_words(0x9BD4E0, 168)
-    return kPalette_SpriteAux1[j * 7 : j * 7 + 7]
-  assert pal_idx != 11
-  if pal_idx == 13:
-    kPalette_MiscSprite = get_words(0x9BD446, 77)
-    return kPalette_MiscSprite[j * 7 : j * 7 + 7]
-  elif pal_idx == 14:
-    kPalette_ArmorAndGloves = get_words(0x9BD308, 75)
-    return kPalette_ArmorAndGloves[1:8]
-  elif pal_idx == 15:
-    kPalette_ArmorAndGloves = get_words(0x9BD308, 75)
-    return kPalette_ArmorAndGloves[9:16]
-
-@cache
-def get_full_palette(pal_idx, pal_subidx):
-  rv = []
-  if pal_idx & 1:
-    rv.extend([0x00fe00] * 9)
-  else:
-    rv.extend([0x00fe00] * 1)
-  rv.extend(convert_snes_palette_to_int(get_palette_subset(pal_idx, pal_subidx)))
-  rv += [0xe000e0] * (256 - len(rv))
-  # change the transparent to teal #008080
-  for i in range(0, 128, 8):
-    rv[i] = 0x808000
-  rv[251] = 0xe0c0c0 # blueish text
-  rv[252] = 0xc0c0c0 # palette text
-  rv[253] = 0xf0f0f0 # unallocated
-  rv[254] = 0x404040 # lines
-  rv[255] = 0xe0e0e0 # bg
-  return rv
-
-@cache
-def get_font_3x5():
-  return Image.open('../other/3x5_font.png').tobytes()
-
-def draw_letter3x5(dst, dst_pitch, dx, dy, ch, color):
-  font = get_font_3x5()
-  dst_offs = dy * dst_pitch + dx
-  src_offs = (ord(ch) & 31) * 4 + (ord(ch) // 32) * 6 * 128
-  for y in range(6):
-    for x in range(3):
-      if font[src_offs + y * 128 + x] == 0:
-        dst[dst_offs + y * dst_pitch + x] = color
-
-def draw_string3x5(dst, dst_pitch, dx, dy, s, color):
-  for ch in s:
-    draw_letter3x5(dst, dst_pitch, dx, dy, ch, color)
-    dx += 4
-
-def convert_to_24bpp(data, palette):
-  out = [0] * len(data)
-  for i in range(len(data)):
-    out[i] = palette[data[i]]
-  return out
-
-def concat_byte_arrays(ar):
-  r = bytearray()
-  for a in ar:
-    r += a
-  return r
-
-def fixup_sprite_set_entry(e, e_prev):
-  sprite_index = int(e.name[:2], 16) if e.name[0] != 'X' else 10000
-
-  if e.dungeon_or_ow != 3:
-    e.tileset = tables.kSpriteTilesets[e.tileset + (64 if e.dungeon_or_ow == 2 else 0)][e.ss_idx]
-  e.high_palette = is_high_3bit_tileset(e.tileset)
-  e.skip_header = False
-  if e.pal_base == None:
-    if sprite_index < len(tables.kSpriteInit_Flags3):
-      e.pal_base = (tables.kSpriteInit_Flags3[sprite_index] >> 1) & 7
-    else:
-      e.pal_base = 4 # just default to some palette
-
-  e.pal_idx = e.pal_base * 2 + e.high_palette
-  e.pal_subidx = get_palette_subidx(e.palset_idx, e.dungeon_or_ow, e.pal_idx)
-
-  if e_prev != None and e_prev.name == e.name and e_prev.pal_idx == e.pal_idx and e_prev.pal_subidx == e.pal_subidx:
-    e.skip_header = True
-
-  # the (pal_idx, pal_subidx) tuple identifies the palette
-  e.encoded_id = e.pal_base | e.tileset << 3 | e.skip_header << 10 | (e.pal_subidx or 0) << 11 
-  e.encoded_id = e.encoded_id << 8 | ((e.encoded_id + 41) % 255)
-
-
-BIGW = 148
-def save_sprite_set_entry(finaldst, e, master_tilesheets = None):
-  empty_253 = [253] * 8
-  def fill_with_empty(dst, dst_offs):
-    for y in range(8):
-      o = dst_offs + y * BIGW
-      dst[o : o + 8] = empty_253
-
-  def copy_8x8(dst, dst_offs, src, src_offs, base):
-    for y in range(8):
-      for x in range(8):
-        dst[dst_offs + y * BIGW + x] = src[src_offs + y * 128 + x] + base
-
-  def hline(dst, x1, x2, y, color):
-    for x in range(x1, x2 + 1):
-      dst[y * BIGW + x] = color
-
-  def vline(dst, x, y1, y2, color):
-    for y in range(y1, y2 + 1):
-      dst[y * BIGW + x] = color
-  
-  def fillrect(dst, x1, x2, y1, y2, color):
-    for y in range(y1, y2 + 1):
-      hline(dst, x1, x2, y, color)
-
-  def encode_id(dst, x, y, v):
-    while v:
-      if v & 1:
-        dst[y * BIGW + x] = 253
-      x -= 1
-      v >>= 1
-
-  palette = get_full_palette(e.pal_idx, e.pal_subidx)
-
-  if not e.skip_header:
-    pal_subidx = e.pal_subidx
-    if e.high_palette:
-      pal_name = '%sR' % e.pal_base
-    else:
-      pal_name = '%s' % e.pal_base
-      if e.pal_base in (1, 2, 3):
-        assert e.pal_subidx in (0, 1)
-        pal_subidx = 'LW' if pal_subidx == 0 else 'DW'
-    if pal_subidx != None:
-      pal_name = '%s-%s' % (pal_name, pal_subidx)
-
-    header = bytearray([255] * BIGW * 9)
-    draw_string3x5(header, BIGW, 1, 3, e.name[:22], 254)
-
-    for i in range(7):
-      xx = BIGW - 37 + i * 5 - 9
-      fillrect(header, xx, xx + 4, 3, 7, i + (9 if e.high_palette else 1))
-
-    draw_string3x5(header, BIGW, BIGW - 9, 3, '%2s' % e.tileset, 252)
-    draw_string3x5(header, BIGW, BIGW - 45 - 1 - len(pal_name) * 4, 3, pal_name, 252)
-    finaldst.extend(convert_to_24bpp(header, palette))
-
-  bigdst = bytearray([255] * BIGW * 36)
-  hline(bigdst, 1, 137, 0, 254)
-  hline(bigdst, 1, 137, 34, 254)
-  vline(bigdst, 1, 0, 34, 254)
-  vline(bigdst, 137, 0, 34, 254)
-
-  encode_id(bigdst, 137, 35, e.encoded_id << 9 | 0x55)
-
-  src = decode_3bit_tileset(e.tileset) # returns 128x64
-
-  for i in range(16*4):
-    x, y = i % 16, i // 16
-    dst_offs = (y * 8 + 1 + (y >> 1)) * BIGW + x * 8 + 2 + (x >> 1)
-    if x & 8: dst_offs
-    m = e.matrix[y][x]
-    if m == '.':
-      fill_with_empty(bigdst, dst_offs)
-    else:
-      copy_8x8(bigdst, dst_offs, src, x * 8 + y * 8 * 128, 0)
-      if master_tilesheets:
-        master_tilesheets.insert(e.tileset, src, x, y, palette, 0)
-
-  # display vram addresses
-  draw_string3x5(bigdst, BIGW, BIGW - 9, 4, '%Xx' % (e.ss_idx * 0x4), 251)
-  draw_string3x5(bigdst, BIGW, BIGW - 9, 4 + 17, '%Xx' % (e.ss_idx * 0x4 + 2), 251)
-
-  # collapse unused matrix sections
-  if all(m=='.' for m in e.matrix[0]) and all(m=='.' for m in e.matrix[1]):
-    del bigdst[1*BIGW:17*BIGW]
-  elif all(m=='.' for m in e.matrix[2]) and all(m=='.' for m in e.matrix[3]):
-    del bigdst[18*BIGW:34*BIGW]
-
-  if e.skip_header:
-    draw_string3x5(bigdst, BIGW, BIGW - 9, len(bigdst)//BIGW - 6, '%.2d' % e.tileset, 252)
-  
-  finaldst.extend(convert_to_24bpp(bigdst, palette))
-
-def fixup_entries():
-  e_prev = None
-  for e in sprite_sheet_info.entries:
-    fixup_sprite_set_entry(e, e_prev)
-    e_prev = e
-
-class MasterTilesheets:
-  def __init__(self):
-    self.sheets = {}
-
-  def insert(self, tileset, src, xp, yp, palette, pal_base):
-    sheet = self.sheets.get(tileset)
-    if sheet == None:
-      sheet = (array.array('I', [0x00f000] * 128 * 32), None)
-      self.sheets[tileset] = sheet
-    sheet24 = sheet[0]
-    for y in range(yp * 8, yp * 8 + 8):
-      for x in range(xp * 8, xp * 8 + 8):
-        o = y * 128 + x
-        sheet24[o] = palette[pal_base + src[o]]
-
-  def add_verify_8x8(self, tileset, pal_lut, img_data, pitch, dst_pos, src_pos):
-    # add to the master sheet
-    sheet = self.sheets.get(tileset)
-    if sheet == None:
-      sheet = (array.array('I', [0x00f000] * 128 * 32), bytearray([248] * 128 * 32))
-      self.sheets[tileset] = sheet
-    sheet24, sheet8 = sheet[0], sheet[1]
-    for y in range(8):
-      for x in range(8):
-        pixel = img_data[src_pos + y * pitch + x]
-        o = dst_pos + y * 128 + x 
-        sheet24[o] = pixel
-        pixel8 = pal_lut.get(pixel)
-        if pixel8 == None:
-          raise Exception('Pixel #%.6x not found' % pixel)
-        if sheet8[o] != 248 and pixel8 != sheet8[o]:
-          raise Exception('Pixel has more than one value')
-        sheet8[o] = pixel8
-
-  def save_to_all_sheets(self, save_also_8bit = False):
-    rv = array.array('I')
-    if save_also_8bit:
-      rv8 = bytearray()
-
-    def extend_with_string_line(text):
-      header = array.array('I', [0xf0f0f0] * 128 * 8)
-      draw_string3x5(header, 128, 1, 2, text, 0x404040)
-      rv.extend(header)
-      if save_also_8bit:
-        header8 = bytearray([255] * 128 * 8)
-        draw_string3x5(header8, 128, 1, 2, text, 254)
-        rv8.extend(header8)
-    extend_with_string_line('AUTO GENERATED DO NOT EDIT')
-    kk = 0
-    for k in sorted(self.sheets.keys()):
-      extend_with_string_line('Sheet %d' % k)
-      rv.extend(self.sheets[k][0])
-      if save_also_8bit:
-        rv8.extend(self.sheets[k][1])
-      if k != kk:
-        print('Missing %d' % kk)
-      kk = k + 1
-    if save_also_8bit:
-      palette8 = get_full_palette(4, 0)
-      for i, v in enumerate(convert_snes_palette_to_int(get_palette_subset(5, 0))):
-        palette8[i + 9] = v
-      palette8[248] = 0x00f000
-      save_as_png((128, len(rv)//128), rv8, 'sprites/all_sheets_8bit.png', palette = convert_int24_palette_to_bytes(palette8))
-      self.verify_identical_to_snes()
-    save_as_24bpp_png((128, len(rv)//128), rv, 'sprites/all_sheets.png')
-
-  def verify_identical_to_snes(self):
-    for tileset in range(103):
-      a = self.encode_sheet_in_snes_format(tileset)
-      b = get_unpacked_snes_tileset(tileset)
-      if a != b:
-        print('Sheet %d mismatch' % tileset)
-        break
-
-  # convert a tileset to the 8bit snes format, 24 bytes per tile
-  def encode_sheet_in_snes_format(self, tileset):
-    sheet8 = self.sheets[tileset][1]
-    result = bytearray(24 * 16 * 4)
-    def encode_into(dst_pos, src_pos):
-      for y in range(8):
-        for x in range(8):
-          b = sheet8[src_pos + 128 * y + 7 - x]
-          result[dst_pos+2*y] |= (b & 1) << x
-          result[dst_pos+2*y+1] |= ((b & 2) >> 1) << x
-          result[dst_pos+y+16] |= ((b & 4) >> 2) << x
-    for y in range(4):
-      for x in range(16):
-        encode_into((y * 16 + x) * 24, y * 8 * 128 + x * 8)
-    return result
-
-def decode_sprite_sheets():
-  master_tilesheets = MasterTilesheets()
-
-  fixup_entries()
-  for char in "0123456789ABCDEFX":
-    dst = []
-    for e in sprite_sheet_info.entries:
-      if e.name[0].upper() == char:
-        save_sprite_set_entry(dst, e, master_tilesheets)
-    if len(dst):
-      save_as_24bpp_png((BIGW, len(dst) // BIGW), dst, 'sprites/sprites_%s.png' % char)
-  master_tilesheets.save_to_all_sheets()
-
-def load_sprite_sheets():
-  master_tilesheets = MasterTilesheets()
-  for char in "0123456789ABCDEFX":
-    img = Image.open('sprites/sprites_%s.png' % char)
-    img_size = img.size
-    img_data = array.array('I', (a[0] | a[1] << 8 | a[2] << 16 for a in img.getdata()))
-    pitch = img.size[0]
-
-    def find_next_tag(start_pos):
-      for i in range(start_pos, len(img_data) - pitch * 2, pitch if start_pos != 0 else 1):
-        if img_data[i+0] == 0x404040 and img_data[i+pitch] == 0x404040 and \
-          img_data[i+pitch * 2 + 0] == 0xf0f0f0 and img_data[i+pitch * 2 - 1] == 0xe0e0e0 and \
-          img_data[i+pitch * 2 - 2] == 0xf0f0f0 and img_data[i+pitch * 2 - 3] == 0xe0e0e0 and \
-          img_data[i+pitch * 2 - 4] == 0xf0f0f0 and img_data[i+pitch * 2 - 5] == 0xe0e0e0 and \
-          img_data[i+pitch * 2 - 6] == 0xf0f0f0 and img_data[i+pitch * 2 - 7] == 0xe0e0e0:
-          return i + pitch * 2
-      else:
-        return None
-
-    def decode_tag(pos):
-      r = 0
-      for i in range(64):
-        v = img_data[pos - 63 + i]
-        assert v in (0xe0e0e0, 0xf0f0f0)
-        r = r * 2 + (v == 0xf0f0f0)
-      if (r & 0x1ff) != 0x55:
-        raise Exception('Invalid tag')
-      r >>= 9
-      if (((r >> 8) + 41) % 255) != (r & 0xff):
-        raise Exception('Invalid checksum')
-      r >>= 8
-      return r & 7, (r >> 3) & 127, (r >> 10) & 1, (r >> 11) & 31
-
-    def determine_image_rects(tag_pos):
-      h = 1
-      while (img_data[tag_pos - pitch * (h + 1)] == 0x404040):
-        h += 1
-      if h == 19:
-        if img_data[tag_pos - pitch * 2 - 1] == 0xe0e0e0:
-          image_rects = ((0, tag_pos - 135 - pitch * 18), )
-        elif img_data[tag_pos - pitch * 18 - 1] == 0xe0e0e0:
-          image_rects = ((1, tag_pos - 135 - pitch * 17), )
-        else:
-          raise Exception('cant uncompact')
-      elif h == 35:
-        image_rects = ((0, tag_pos - 135 - pitch * 34), (1, tag_pos - 135 - pitch * 17))
-      else:
-        raise Exception('height not found')
-      return image_rects, h
-
-    def get_pal_lut(tag_pos, is_high):
-      # read palette colors from the image pixels
-      pal_lut = {img_data[tag_pos + 5 * i] : i + (9 if is_high else 1) for i in range(7)}
-      pal_lut[0x808000] = 0 # transparent color
-      return pal_lut
-
-    def is_empty(pos):
-      return all(img_data[pos+y*pitch+x] == 0xf0f0f0 for x in range(8) for y in range(8))
-
-    pal_lut = None
-    tag_pos = 0
-    while True:
-      tag_pos = find_next_tag(tag_pos)
-      if tag_pos == None:
-        break
-      pal_base, tileset, headerless, pal_subidx = decode_tag(tag_pos)
-      image_rects, box_height = determine_image_rects(tag_pos)
-      if not headerless:
-        pal_lut = get_pal_lut(tag_pos - pitch * (box_height + 3) - 34, is_high_3bit_tileset(tileset))
-      for idx, sheet_pos in image_rects:
-        for y in range(2):
-          for x in range(16):
-            src_pos = sheet_pos + (y * 8 + (y >> 1)) * pitch + (x * 8 + (x >> 1))
-            dst_pos = (y + idx * 2) * 8 * 128 + x * 8
-            if not is_empty(src_pos):
-              master_tilesheets.add_verify_8x8(tileset, pal_lut, img_data, pitch, dst_pos, src_pos)
-  return master_tilesheets
-
-#if __name__ == "__main__":
-#  ROM = util.load_rom(sys.argv[1] if len(sys.argv) >= 2 else None, True)
-#  decode_font()
-  
-
-
--- a/tables/sprites/.gitignore
+++ /dev/null
@@ -1,1 +1,0 @@
-/*.png
--- a/tables/tables.py
+++ /dev/null
@@ -1,1132 +1,0 @@
-def invert_dict(xs):
-  return {s:i for i,s in xs.items()}
-
-type0_names="""Ceiling [L-R]
-[N]Wall Horz: [L-R]
-[S]Wall Horz: [L-R]
-[N]Wall Horz: (LOW) [L-R]
-[S]Wall Horz: (LOW) [L-R]
-[N]Wall Column [L-R]
-[S]Wall Column [L-R]
-[N]Wall Pit [L-R]
-[S]Wall Pit [L-R]
-/ Wall Wood Bot (HIGH) [NW]
-\ Wall Wood Bot (HIGH) [SW]
-\ Wall Wood Bot (HIGH) [NE]
-/ Wall Wood Bot (HIGH) [SE]
-/ Wall Tile Bot (HIGH) [NW]
-\ Wall Tile Bot (HIGH) [SW]
-\ Wall Tile Bot (HIGH) [NE]
-/ Wall Tile Bot (HIGH) [SE]
-/ Wall Tile2 Bot (HIGH) [NW]
-\ Wall Tile2 Bot (HIGH) [SW]
-\ Wall Tile2 Bot (HIGH) [NE]
-/ Wall Tile2 Bot (HIGH) [SE]
-/ Wall Tile Top (LOW)[NW]
-\ Wall Tile Top (LOW)[SW]
-\ Wall Tile Top (LOW)[NE]
-/ Wall Tile Top (LOW)[SE]
-/ Wall Tile Bot (LOW)[NW]
-\ Wall Tile Bot (LOW)[SW]
-\ Wall Tile Bot (LOW)[NE]
-/ Wall Tile Bot (LOW)[SE]
-/ Wall Tile2 Bot (LOW)[NW]
-\ Wall Tile2 Bot (LOW)[SW]
-\ Wall Tile2 Bot (LOW)[NE]
-/ Wall Tile2 Bot (LOW)[SE]
-Mini Stairs [L-R]
-Horz: Rail Thin [L-R]
-Pit [N]Edge [L-R]
-Pit [N]Edge [L-R]
-Pit [N]Edge [L-R]
-Pit [N]Edge [L-R]
-Pit [N]Edge [L-R]
-Pit [S]Edge [L-R]
-Pit [S]Edge [L-R]
-Pit [N]Edge [L-R]
-Pit [SE]Corner [L-R]
-Pit [SW]Corner [L-R]
-Pit [NE]Corner [L-R]
-Pit [NW]Corner [L-R]
-Rail Wall [L-R]
-Rail Wall [L-R]
-Unused -empty
-Unused -empty
-Red Carpet Floor [L-R]
-Red Carpet Floor Trim [L-R]
-Unused -empty
-[N]Curtain [L-R]
-[W]Curtain [L-R]-unused-
-Statue [L-R]
-Column [L-R]
-[N]Wall Decor: [L-R]
-[S]Wall Decor: [L-R]
-Double Chair [L-R]
-Stand Torch [L-R]
-[N]Wall Column [L-R]
-Water Edge [L-R]
-Water Edge [L-R]
-Water Edge [L-R]
-Water Edge [L-R]
-Water Edge [L-R]
-Water Edge [L-R]
-Water Edge [L-R]
-Water Edge [L-R]
-Unused Waterfall [L-R]
-Unused Waterfall [L-R]
-N/A
-N/A
-[S]Wall Column [L-R]
-Bar [L-R]
-Shelf [L-R]
-Shelf [L-R]
-Shelf [L-R]
-Cane Ride [L-R]
-[N]Canon Hole [L-R]
-[S]Canon Hole [L-R]
-Cane Ride [L-R]
-Unused [L-R]
-[N]Wall Torches [L-R]
-[S]Wall Torches [L-R]
-Unused
-Unused
-Unused
-Unused
-[N]Canon Hole [L-R]
-[S]Canon Hole [L-R]
-Large Horz: Rail [L-R]
-Block [L-R]
-Long Horz: Rail [L-R]
-Ceiling [U-D]
-[W]Wall Vert: [U-D]
-[E]Wall Vert: [U-D]
-[W]Wall Vert: (LOW) [U-D]
-[E]Wall Vert: (LOW) [U-D]
-[W]Wall Column [U-D]
-[E]Wall Column [U-D]
-[W]Wall Pit [U-D]
-[E]Wall Pit [U-D]
-Vert: Rail Thin [U-D]
-[W]Pit Edge [U-D]
-[E]Pit Edge [U-D]
-[W]Rail Wall [U-D]
-[E]Rail Wall [U-D]
-Unused
-Unused
-Red Floor/Wire Floor [U-D]
-Red Carpet Floor Trim [U-D]
-Unused
-[W]Curtain [U-D]
-[E]Curtain [U-D]
-Column [U-D]
-[W]Wall Decor: [U-D]
-[E]Wall Decor: [U-D]
-[W]Wall Top Column [U-D]
-Water Edge [U-D]
-Water Edge [U-D]
-[E]Wall Top Column [U-D]
-Cane Ride [U-D]
-Pipe Ride [U-D]
-Unused
-[W]Wall Torches [U-D]
-[E]Wall Torches [U-D]
-[W]Wall Decor: [U-D]
-[E]Wall Decor: [U-D]
-[W]Wall Decor:?? [U-D]
-[E]Wall Decor:?? [U-D]
-[W]Wall Canon Hole [U-D]
-[E]Wall Canon Hole [U-D]
-Floor Torch [U-D]
-Large Vert: Rail [U-D]
-Block Vert: [U-D]
-Long Vert: Rail [U-D]
-[W]Vert: Jump Edge [U-D]
-[E]Vert: Jump Edge [U-D]
-[W]Edge [U-D]
-[E]Edge [U-D]
-N/A
-[W]Wall Vert: [U-D]
-[E]Wall Horz: [U-D]
-Blue Peg Block [U-D]
-Orange Peg Block [U-D]
-Invisible Floor [U-D]
-Fake Pot [U-D]
-Hammer Peg Block [U-D]
-Unused
-Unused
-Unused
-Unused
-Unused
-Unused
-Unused
-Unused
-Unused
-/ Ceiling [NW]
-\ Ceiling [SW]
-\ Ceiling [NE]
-/ Ceiling [SE]
-Hole [4-way]
-/ Ceiling [Trans][NW]
-\ Ceiling [Trans][SW]
-\ Ceiling [Trans][NE]
-/ Ceiling [Trans][SE]
-/ Ceiling [BG2 X-RAY][SE]
-\ Ceiling [BG2 X-RAY][NE]
-\ Ceiling [BG2 X-RAY][SW]
-/ Ceiling [BG2 X-RAY][NW]
-N/A
-N/A
-N/A
-[S]Horz: Jump Edge [L-R]
-[S]Horz: Jump Edge [L-R]
-Floor? [L-R]
-N/A
-N/A
-N/A
-[N]Wall Decor: 1/2 [L-R]
-[S]Wall Decor: 1/2 [L-R]
-Blue Switch Block [L-R]
-Red Switch Block [L-R]
-Invisible Floor [L-R]
-N/A
-fake pots [L-R]
-Hammer Pegs [L-R]
-Unused
-Unused
-Ceiling Large [4-way]
-Chest Pedastal [4-way]
-Falling Edge Mask [4-way]
-Falling Edge Mask [4-way]
-Doorless Room Transition
-Floor3 [4-way]
-BG2 X-RAY Overlay [4-way]
-Floor4 [4-way]
-Water Floor [4-way]
-Water Floor2 [4-way]
-Floor5 [4-way]
-Unused
-Unused
-Moving Wall Right [4-way]
-Moving Wall Left [4-way]
-Unused
-Unused
-Water Floor3 [4-way]
-Floor6 [4-way]
-Unused
-Unused
-Unused
-N/A
-overlay tile? [4-way]
-Lava Background? [4-way]
-Swimming Overlay [4-way]
-Lava Background 2 [4-way]
-Floor2 [4-way]
-Chest Platform? [4-way]
-Table / Rock [4-way]
-Spike Block [4-way]
-Spike Floor [4-way]
-Floor7 [4-way]
-Floor9 [4-way]
-Rupee Floor [4-way]
-Moving Floor Up [4-way]
-Moving Floor Down [4-way]
-Moving Floor Left [4-way]
-Moving Floor Right [4-way]
-Moving Floor/Water [4-way]
-Weird Floor? [4-way]
-Unused
-Unused
-Unused
-Unused
-Unused
-Unused
-Unused
-Unused
-Unused
-Unused
-Unused
-Unused
-Unused
-Unused
-Unused
-Water Face
-Waterfall Face
-Waterfall Face Longer
-Cane Ride Spawn [?]Block
-Cane Ride Node [4-way]
-Cane Ride Node [S-E]
-Cane Ride Node [N-E]
-Cane Ride Node [S-E]-2
-Cane Ride Node [N-E]-2
-Cane Ride Node [W-S-E]
-Cane Ride Node [W-N-E]
-Cane Ride Node [N-E-S]
-Cane Ride Node [N-W-S]
-Prison Cell
-Cane Ride Spawn [?]Block
-?
-?
-?
-Rupee Floor
-Telepathic Tile
-Down Warp Door
-Kholdstare Shell - BG2
-Single Hammer Peg
-Cell
-Cell Lock
-Chest
-Open Chest
-Stair
-Stair [S](Layer)
-Stair Wet [S](Layer)
-Staircase going Up(Up)
-Staircase Going Down (Up)
-Staircase Going Up (Down)
-Staircase Going Down (Down)
-Pit Wall Corner
-Pit Wall Corner
-Pit Wall Corner
-Pit Wall Corner
-Staircase Going Up (Lower)
-Staircase Going Up (Lower)
-Staircase Going Down (Lower)
-Staircase Going Down (Lower)
-Dark Room BG2 Mask
-Staircase Going Down (Lower)
-Large Pick Up Block
-Agahnim Altar
-Agahnim Room
-Pot
-??
-Big Chest
-Big Chest Open
-Stairs Submerged [S](layer)
-???
-???
-???
-???
-???
-???
-Pipe Ride Mouth [S]
-Pipe Ride Mouth [N]
-Pipe Ride Mouth [E]
-Pipe Ride Mouth [W]
-Pipe Ride Corner [S-E]
-Pipe Ride Corner [N-E]
-Pipe Ride Corner [S-W]
-Pipe Ride Corner [N-W]
-Pipe Ride Tunnel [N]
-Pipe Ride Tunnel [S]
-Pipe Ride Tunnel [W]
-Pipe Ride Tunnel [E]
-Pipe Ride Over Mask [U-D]
-Bomb Floor
-Fake Bomb Floor
-Fake Bomb Floor
-Warp Tile
-???
-???
-???
-???
-Inactive Warp
-Floor Switch
-Skull Pot
-Single Blue Peg
-Single Red Peg
-
-???
-Bar Corner [NW]
-Bar Corner [SW]
-Bar Corner [NE]
-Bar Corner [SE]
-Plate on Table
-Water Troof
-Bookshelf
-Forge
-???
-Bottles on Bar
-???
-Left Warp Door
-Right Warp Door
-Fake Floor Switch
-Fireball Shooter
-Medusa Head
-Hole
-Top Crack Wall
-Bottom Crack Wall
-Left Crack Wall
-Right Crack Wall
-Throne/Decor: Object
-???
-???
-???
-???
-Window Light
-Floor Light Blind BG2
-Boss Goo/Shell BG2
-Bg2 Full Mask
-Boss Entrance
-Minigame Chest
-???
-???
-???
-???
-???
-Vitreous Boss?
-???
-???
-???
-???
-""".splitlines()
-
-type2_names="""Wall Outer Corner (HIGH) [NW]
-Wall Outer Corner (HIGH) [SW]
-Wall Outer Corner (HIGH) [NE]
-Wall Outer Corner (HIGH) [SE]
-Wall Inner Corner (HIGH) [NW]
-Wall Inner Corner (HIGH) [SW]
-Wall Inner Corner (HIGH) [NE]
-Wall Inner Corner (HIGH) [SE]
-Wall Outer Corner (LOW) [NW]
-Wall Outer Corner (LOW) [SW]
-Wall Outer Corner (LOW) [NE]
-Wall Outer Corner (LOW) [SE]
-Wall Inner Corner (LOW) [NW]
-Wall Inner Corner (LOW) [SW]
-Wall Inner Corner (LOW) [NE]
-Wall Inner Corner (LOW) [SE]
-Wall S-Bend (LOW) [N1]
-Wall S-Bend (LOW) [S1]
-Wall S-Bend (LOW) [N2]
-Wall S-Bend (LOW) [S2]
-Wall S-Bend (LOW) [W1]
-Wall S-Bend (LOW) [W2]
-Wall S-Bend (LOW) [E1]
-Wall S-Bend (LOW) [E2]
-Wall Pit Corner (Lower) [NW]
-Wall Pit Corner (Lower) [SW]
-Wall Pit Corner (Lower) [NE]
-Wall Pit Corner (Lower) [SE]
-Fairy Pot
-Statue
-Star Tile Off
-Star Tile On
-Torch Lit
-Barrel
-Weird Bed
-Table
-Decoration
-???
-???
-Chair
-Bed
-Decoration
-Wall Painting
-???
-???
-Floor Stairs Up (room)
-Floor Stairs Down (room)
-Floor Stairs Down2 (room)
-Stairs [N](unused)
-Stairs [N](layer)
-Stairs [N](layer)
-Stairs Submerged [N](layer)
-Block
-Water Ladder
-Water Ladder
-Water Gate Large
-Door Staircase Up R
-Door Staircase Down L
-Door Staircase Up R (Lower)
-Door Staircase Down L (Lower)
-Sanctuary Wall
-???
-Church Pew
-???
-Ceiling [L-R]""".splitlines()
-
-kType0Names = ['%.2X-%s' % (i, type0_names[i]) for i in range(0xf8)]
-kType1Names = ['%.3X-%s' % (0xf80 + i, type0_names[i+0xf8]) for i in range(0x80)]
-kType2Names = ['%X-%s' % (i + 0x100, x) for i,x in enumerate(type2_names)]
-
-def invert_list(x):
-	return {s:i for i,s in enumerate(x)}
-
-kType0Names_rev = invert_list(kType0Names)
-kType1Names_rev = invert_list(kType1Names)
-kType2Names_rev = invert_list(kType2Names)
-
-kTagNames = [        "None","NW Kill enemy to open","NE Kill enemy to open","SW Kill enemy to open","SE Kill enemy to open","W Kill enemy to open","E Kill enemy to open","N Kill enemy to open","S Kill enemy to open","Clear quadrant to open","Clear room to open",
-        "NW Move block to open","NE Move block to open","SW Move block to open","SE Move block to open","W Move block to open","E Move block to open","N Move block to open",
-        "S Move block to open","Move block to open","Pull lever to open","Clear level to open door","Switch opens door(Hold)","Switch opens door(Toggle)",
-        "Turn off water","Turn on water","Water gate","Water twin","Secret wall (Right)","Secret wall (Left)","Crash","Crash",
-        "Use switch to bomb wall","Holes(0)","Open chest for holes(0)","Holes(1)","Holes(2)","Kill enemy to clear level","SE Kill enemy to move block","Trigger activated chest",
-        "Use lever to bomb wall","NW Kill enemy for chest","NE Kill enemy for chest","SW Kill enemies for chest","SE Kill enemy for chest","W Kill enemy for chest","E Kill enemy for chest","N Kill enemy for chest",
-        "S Kill enemy for chest","Clear quadrant for chest","Clear room for chest","Light torches to open","Holes(3)","Holes(4)","Holes(5)","Holes(6)",
-        "Agahnim's room","Holes(7)","Holes(8)","Open chest for holes(8)","Move block to get chest","Kill to open Ganon's door","Light torches to get chest","Kill boss again",
-]
-
-kTagNames_rev = invert_list(kTagNames)
-
-kEffectNames = ["None","01","Moving floor","Moving water","04","Red flashes","Light torch to see floor","Ganon room"]
-kEffectNames_rev = invert_list(kEffectNames)
-
-kCollisionNames = ["One", "Both", "Both w/scroll", "Moving floor", "Moving water"]
-kCollisionNames_rev = invert_list(kCollisionNames)
-
-kBg2 = ["None", "Parallaxing", "Dark", "On top", "Translucent", "Parallaxing2", "Normal", "Addition", "Dark room"]
-kBg2_rev = invert_list(kBg2)
-
-kMusicNames = {
-    255: "Same",
-    0: "None",
-    1:"Title",
-    2:"World_map",
-    3:"Beginning",
-    4:"Rabbit",
-    5:"Forest",
-    6:"Intro",
-    7:"Town",
-    8:"Warp",
-    9:"Dark_world",
-    10:"Master_swd",
-    11:"File_select",
-    12:"Soldier",
-    13:"Mountain",
-    14:"Shop",
-    15:"Fanfare",
-    16:"Castle",
-    17:"Palace",
-    18:"Cave",
-    19:"Clear",
-    20:"Church",
-    21:"Boss",
-    22:"Dungeon",
-    23:"Psychic",
-    24:"Secret_way",
-    25:"Rescue",
-    26:"Crystal",
-    27:"Fountain",
-    28:"Pyramid",
-    29:"Kill_Agah",
-    30:"Ganon_room",
-    31:"Last_boss",
-    32:"Triforce",
-    33:"Ending",
-    34:"Staff",
-    240:"Stop",
-    241:"Fade_out",
-    242:"Lower_vol",
-    243:"Normal_vol"
-}
-
-kMusicNamesRev = invert_dict(kMusicNames)
-
-kAmbientSoundName = {
-    0: "None",
-    1: "Heavy rain",
-    3: "Light rain",
-    5: "Stop",
-    7: "Earthquake",
-    9: "Wind",
-    11: "Flute",
-    13: "Chime 1",
-    15: "Chime 2"
-}
-
-kAmbientSoundNameRev = invert_dict(kAmbientSoundName)
-
-kPalaceNames = (
-    "None",
-    "Church",
-    
-    "Castle",
-    "East",
-    "Desert",
-    "Agahnim",
-    
-    "Water",
-    "Dark",
-    "Mud",
-    "Wood",
-    
-    "Ice",
-    "Tower",
-    "Town",
-    "Mountain",
-    "Agahnim2"
-)
-
-kAreaNames = """LW 000 : Lost Woods NW
-LW 001 : Lost Woods NE
-LW 002 : Lumberjack Estate
-LW 003 : Tower of Hera NW
-LW 004 : Tower of Hera NE
-LW 005 : Death Mountain Bridge NW
-LW 006 : Death Mountain Bridge NE
-LW 007 : Turtle Rock
-LW 008 : Lost Woods SW
-LW 009 : Lost Woods SE
-LW 010 : Death Mountain Gateway
-LW 011 : Tower of Hera SW
-LW 012 : Tower of Hera SE
-LW 013 : Mountain Bridge NW
-LW 014 : Mountain Bridge NE
-LW 015 : Zora Falls Outskirts
-LW 016 : Lost Woods Outskirts
-LW 017 : Kakariko Psychics Unlimited
-LW 018 : Nothern Pond
-LW 019 : Sanctuary Grounds
-LW 020 : Graveyard
-LW 021 : South Bend
-LW 022 : Coven of Commerce
-LW 023 : Zora Ridge
-LW 024 : Kakariko NW
-LW 025 : Kakariko NE
-LW 026 : West Woods
-LW 027 : Hyrule Castle NW
-LW 028 : Hyrule Castle NE
-LW 029 : Castle East Bridge
-LW 030 : Eastern Ruins NW
-LW 031 : Eastern Ruins NE
-LW 032 : Kakariko SW
-LW 033 : Kakariko SE
-LW 034 : Smithy Estate
-LW 035 : Hyrule Castle SW
-LW 036 : Hyrule Castle SE
-LW 037 : Moundlands
-LW 038 : Eastern Ruins SW
-LW 039 : Eastern Ruins SE
-LW 040 : Kakariko Maze
-LW 041 : Kakariko South Annex
-LW 042 : Haunted Grove
-LW 043 : Uncle's Estate West
-LW 044 : Uncle's Estate East
-LW 045 : Eastern Ruins Bridge
-LW 046 : Eastern Ruins Ridge
-LW 047 : Eastern Cul-de-sac
-LW 048 : Desert of Mystery NW
-LW 049 : Desert of Mystery NE
-LW 050 : Haunted Terrace
-LW 051 : Hyrule Wetlands NW
-LW 052 : Hyrule Wetlands NE
-LW 053 : Lake Hylia NW
-LW 054 : Lake Hylia NE
-LW 055 : Frosty Caves
-LW 056 : Desert of Mystery SW
-LW 057 : Desert of Mystery SE
-LW 058 : Via of Mystery
-LW 059 : Watergate Grounds
-LW 060 : Hyrule Wetlands Terrace
-LW 061 : Lake Hylia SW
-LW 062 : Lake Hylia SE
-LW 063 : Octorock Nesting Grounds
-DW 064 : Skull Woods NW
-DW 065 : Skull Woods NE
-DW 066 : Eastern Skull Clearing
-DW 067 : Ganon's Tower NW
-DW 068 : Ganon's Tower NE
-DW 069 : Death Mountain Bridge NW
-DW 070 : Death Mountain Bridge NE
-DW 071 : Turtle Rock
-DW 072 : Skull Woods SW
-DW 073 : Skull Woods SE
-DW 074 : Bungie Cave Fun Zone
-DW 075 : Ganon's Tower SW
-DW 076 : Ganon's Tower SE
-DW 077 : Death Mountain Bridge SW
-DW 078 : Death Mountain Bridge SE
-DW 079 : Falls of Ill Omen
-DW 080 : Skull Woods Outskirts
-DW 081 : Village of Outcasts Psychics Unlimited
-DW 082 : Northern Pond (Evil Edition)
-DW 083 : Unctuary Grounds
-DW 084 : Garden of Very Bad Things
-DW 085 : South Bend
-DW 086 : Riverside Commerce
-DW 087 : Ridge of Ill Omen
-DW 088 : Village of Outcasts NW
-DW 089 : Village of Outcasts NE
-DW 090 : West Woods
-DW 091 : Pyramid of Power NW
-DW 092 : Pyramid of Power NE
-DW 093 : Pyramid East Non-bridge
-DW 094 : Maze of Darkness NW
-DW 095 : Maze of Darkness NE
-DW 096 : Village of Outcasts SW
-DW 097 : Village of Outcasts SW
-DW 098 : Gossip Shop
-DW 099 : Pyramid of Power SW
-DW 100 : Pyramid of Power SE
-DW 101 : Moundlands
-DW 102 : Maze of Darkness SW
-DW 103 : Maze of Darkness SE  
-DW 104 : Digging Game Field
-DW 105 : Archery Shop Grounds
-DW 106 : Depressing Grove
-DW 107 : Bomb Shop Grounds West
-DW 108 : Bomp Shop Grounds
-DW 109 : Hammer Time Bridge
-DW 110 : Terrace of Darkness
-DW 111 : Cul-de-sac of Darkness
-DW 112 : Swamp of Evil NW
-DW 113 : Swamp of Evil NE
-DW 114 : Depressing Terrace
-DW 115 : Wilted Wetlands NW
-DW 116 : Wilted Wetlands NE
-DW 117 : Lake Dielia NW
-DW 118 : Lake Dielia NE
-DW 119 : Info Hub
-DW 120 : Swamp of Evil SW
-DW 121 : Swamp of Evil SE
-DW 122 : Via To Nowhere
-DW 123 : Swamp Palace Grounds
-DW 124 : Wilted Terrace
-DW 125 : Lake Dielia SW
-DW 126 : Lake Dielia SE
-DW 127 : A Terrible Vacation Spot
-SP 128 : Master Grove / Under Hyrule Bridge
-SP 129 : Zora Falls NW <AVAILABLE>
-SP 130 : Zora Falls NE <NO SPRITES>
-NA 131 : Unused N/A
-NA 132 : Unused N/A
-NA 133 : Unused N/A
-NA 134 : Unused N/A
-NA 135 : Unused N/A
-SP 136 : Triforce Room / Curtain Overlay
-SP 137 : Zora Falls SW <NO SPRITES>
-SP 138 : Zora Falls SE <NO SPRITES>
-NA 139 : Unused N/A
-NA 140 : Unused N/A
-NA 141 : Unused N/A
-NA 142 : Unused N/A
-NA 143 : Unused N/A
-NA 144 : Unused N/A
-NA 145 : Unused N/A
-NA 146 : Unused N/A
-SP 147 : Triforce Rm / Overlay (2?) N/A
-SP 148 : Master Gr. / Under Bdg (2?) N/A
-SP 149 : Birds' Eye Woods Underlay
-SP 150 : Death Mountain Panorama
-SP 151 : Lost Woods Mist Overlay
-NA 152 : Unused N/A
-NA 153 : Unused N/A
-NA 154 : Unused N/A
-NA 155 : Unused N/A
-SP 156 : Lava Flow Underlay
-SP 157 : Lost Woods Mist Overlay (2?) N/A
-SP 158 : Lost Woods Tree Cover Overlay
-SP 159 : Rain Overlay
-NA 160 : non-existant N/A""".splitlines()
-
-kEntranceNames = """[Room #260] -- Link's House Intro
-[Room #260] -- Link's House Post-intro
-[Room #018] -- Sanctuary
-[Room #096] -- Hyrule Castle West
-[Room #097] -- Hyrule Castle Central
-[Room #098] -- Hyrule Castle East
-[Room #240] -- Death Mountain Express (Lower)
-[Room #241] -- Death Mountain Express (Upper)
-[Room #201] -- Eastern Palace
-[Room #132] -- Desert Palace Central
-[Room #133] -- Desert Palace East
-[Room #131] -- Desert Palace West
-[Room #099] -- Desert Palace Boss Lair
-[Room #242] -- Kakariko Elder's House West
-[Room #243] -- Kakariko Elder's House East
-[Room #244] -- Kakariko Angry Bros West
-[Room #245] -- Kakariko Angry Bros East
-[Room #227] -- Mad Batter Lair
-[Room #226] -- Under Lumberjacks' Weird Tree
-[Room #248] -- Death Mountain Maze 0000
-[Room #232] -- Death Mountain Maze 0001
-[Room #035] -- Turtle Rock Mountainface 1
-[Room #251] -- Death Mountain Cape Heart Piece Cave (Lower)
-[Room #235] -- Death Mountain Cape Heart Piece Cave (Upper)
-[Room #213] -- Turtle Rock Mountainface 2
-[Room #036] -- Turtle Rock Mountainface 3
-[Room #253] -- Death Mountain Maze 0002
-[Room #237] -- Death Mountain Maze 0003
-[Room #254] -- Death Mountain Maze 0004
-[Room #238] -- Death Mountain Maze 0005
-[Room #255] -- Death Mountain Maze 0006
-[Room #239] -- Death Mountain Maze 0007
-[Room #223] -- Death Mountain Maze 0008
-[Room #249] -- Spectacle Rock Maze 1
-[Room #250] -- Spectacle Rock Maze 2
-[Room #234] -- Spectacle Rock Maze 3
-[Room #224] -- Hyrule Castle Tower
-[Room #040] -- Swamp Palace
-[Room #074] -- Palace of Darkness
-[Room #152] -- Misery Mire
-[Room #086] -- Skull Woods 1
-[Room #087] -- Skull Woods 2
-[Room #088] -- Skull Woods Big Chest
-[Room #089] -- Skull Woods Boss Lair
-[Room #225] -- Lost Woods Thieves' Lair
-[Room #014] -- Ice Palace
-[Room #230] -- Death Mountain Escape West
-[Room #231] -- Death Mountain Escape East
-[Room #228] -- Death Mountain Elder's Cave (Lower)
-[Room #229] -- Death Mountain Elder's Cave (Upper)
-[Room #085] -- Hyrule Castle Secret Cellar
-[Room #119] -- Tower of Hera
-[Room #219] -- Thieves's Town
-[Room #214] -- Turtle Rock Main
-[Room #016] -- Ganon's Pyramid Sanctum (Lower)
-[Room #012] -- Ganon's Tower
-[Room #008] -- Fairy Cave 1
-[Room #047] -- Kakariko Western Well
-[Room #060] -- Death Mountain Maze 0009
-[Room #044] -- Death Mountain Maze 0010
-[Room #256] -- Treasure Shell Game 1
-[Room #286] -- Storyteller Cave 1
-[Room #257] -- Snitch House 1
-[Room #257] -- Snitch House 2
-[Room #258] -- SickBoy House
-[Room #279] -- Byrna Gauntlet
-[Room #259] -- Kakariko Pub South
-[Room #259] -- Kakariko Pub North
-[Room #259] -- Kakariko Inn
-[Room #261] -- Sahasrahlah's Disco Infernum
-[Room #287] -- Kakariko's Lame Shop
-[Room #262] -- Village of Outcasts Chest Game
-[Room #262] -- Village of Outcasts Orphanage
-[Room #263] -- Kakariko Library
-[Room #263] -- Kakariko Storage Shed
-[Room #264] -- Kakariko Sweeper Lady's House
-[Room #265] -- Potion Shop
-[Room #266] -- Aginah's Desert Cottage
-[Room #267] -- Watergate
-[Room #268] -- Death Mountain Maze 0011
-[Room #268] -- Fairy Cave 2
-[Room #283] -- Refill Cave 0001
-[Room #283] -- Refill Cave 0002
-[Room #284] -- The Bomb "Shop"
-[Room #284] -- Village of Outcasts Retirement Center
-[Room #286] -- Fairy Cave 3
-[Room #288] -- Good Bee Cave
-[Room #272] -- General Store 1
-[Room #274] -- General Store 2
-[Room #273] -- Archery Game
-[Room #274] -- Storyteller Cave 2
-[Room #275] -- Hall of the Invisibility Cape
-[Room #276] -- Pond of Wishing
-[Room #277] -- Pond of Happiness
-[Room #277] -- Fairy Cave 4
-[Room #269] -- Swamp of Evil Heart Piece Hall
-[Room #271] -- General Store 3
-[Room #281] -- Blind's Old Hideout
-[Room #276] -- Storyteller Cave 3
-[Room #278] -- Warped Pond of Wishing
-[Room #289] -- Chez Smithies
-[Room #290] -- Fortune Teller 1
-[Room #290] -- Fortune Teller 2
-[Room #280] -- Chest Shell Game 2
-[Room #282] -- Storyteller Cave 4
-[Room #270] -- Storyteller Cave 5
-[Room #270] -- Storyteller Cave 6
-[Room #287] -- Village House 1
-[Room #291] -- Thief Hideout 1
-[Room #292] -- Thief Hideout 2
-[Room #292] -- Heart Piece Cave 1
-[Room #293] -- Thief Hideout 3
-[Room #293] -- Refill Cave 3
-[Room #294] -- Fairy Cave 5
-[Room #294] -- Heart Piece Cave 2
-[Room #128] -- Hyrule Castle Prison
-[Room #081] -- Hyrule Castle Throne Room
-[Room #048] -- Hyrule Tower Agahnim's Sanctum
-[Room #088] -- Skull Woods 3 (Drop In)
-[Room #103] -- Skull Woods 4 (Drop In)
-[Room #104] -- Skull Woods 5 (Drop In)
-[Room #086] -- Skull Woods 6 (Drop In)
-[Room #225] -- Lost Woods Thieves' Hideout (Drop In)
-[Room #000] -- Ganon's Pyramid Sanctum (Upper)
-[Room #024] -- Fairy Cave 6 (Drop In)
-[Room #085] -- Hyrule Castle Secret Cellar (Drop In)
-[Room #227] -- Mad Batter Lair (Drop In)
-[Room #226] -- Under Lumberjacks' Weird Tree (Drop In)
-[Room #047] -- Kakariko Western Well (Drop In)
-[Room #017] -- Hyrule Sewers Goodies Room (Drop In)
-[Room #003] -- Chris Houlihan Room (Drop In)
-[Room #295] -- Heart Piece Cave 3 (Drop In)
-[Room #288] -- Ice Rod Cave""".splitlines()
-
-kEntranceNames = [a[a.find(' -- ') + 4:] for a in kEntranceNames]
-
-kEntranceNames_rev = {s:i for i,s in enumerate(kEntranceNames)}
-
-kSpriteNames=['00:Raven', '01:Vulture', '02', '03:BigCanon', '04:PullSwitch', '05:DnSwitch', '06:TrapSwitch', '07:FloorMove', '08:Octorok', '09:Mouldrum', '0A:4WayOctorok', '0B:Chicken', '0C:HoveringRock', '0D:Cucumber', '0E:SnapDragon', '0F:OctoBlimp', '10', '11:Hinox', '12:PigSpearMan', '13:MiniHelmasaur', '14:GargoyleGrate', '15:Bubble', '16:Mutant', '17:BushCrab', '18:Moldorm', '19:Poe/Ghini', '1A:BlackSmith(Frog', '1B:AnArrow', '1C:Statue', '1D:UselessSprite', '1E:PegSwitch', '1F:SickBoy', '20:BombSlug', '21:PushSwitch', '22:HoppingBulbPlan', '23:RedMiri', '24:BlueMiri', '25:LiveTree', '26:BlueOrb', '27:Squirrel', '28:PersonRm270', '29:Thief', '2A:DustGirl', '2B:TentMan', '2C:Lumberjacks', '2D', '2E:FluteBoy', '2F:Person', '30:Person', '31:FortuneTeller', '32:AngryBrother', '33:PullForRupees', '34:ScaredGirl2', '35:HedgeMan', '36:Witch', '37:Waterfall', '38:ArrowTarget', '39:GuyByTheSign', '3A:Person11_227', '3B:DashItem', '3C:FarmBoy', '3D:ScaredGirl1', '3E:RockCrab', '3F:PalaceGuard', '40:ElectricBarrier', '41:BlueSoldier', '42:GreenSoldier', '43:RedSpearSoldier', '44:Warrior', '45:HogSpearMan', '46:BlueArcher', '47:GreenGrassArche', '48:RedSpearKnight', '49:RedGrassSpearSo', '4A:RedBombKnight', '4B:Knight', '4C:Geldman', '4D:Bunny', '4E:Tentacle2', '4F:Tentacle', '50:GlassSquirrel', '51:Armos', '52:ZoraKing', '53:ArmosKnight', '54:Lanmolas', '55:FireBallZora', '56:WalkingZora', '57:HyliaObstacle', '58:Crab', '59:Animal', '5A:Animal', '5B:WallBubble(L-R)', '5C:WallBubble(R-L)', '5D:Roller_1', '5E:Roller_2', '5F:Roller_3', '60:Roller_4', '61:Beamos', '62:MasterSwd', '63:SandCrab1', '64:SandCrab2', '65:ArcherGame', '66:Cannon(Right)', '67:Cannon(Left)', '68:Cannon(Down)', '69:Cannon(Up)', '6A:MorningStar', '6B:CannonSoldier', '6C:Teleport', '6D:Rat', '6E:Rope', '6F:Keese', '70', '71:Leever', '72:Pond', '73:Priest/Uncle', '74:Runner', '75:BottleMan', '76:Zelda', '77:WierdBuble', '78:OldWoman', '79:Bee', '7A:Agahnim', '7B:OneShotMagicBal', '7C:StalfosHead', '7D:BigSpikeBlock', '7E:FireBlade', '7F:FireBlade2', '80:Lanmola', '81:WaterBug', '82:4Bubbles', '83:GreenRocklops', '84:RedRocklops', '85:BigSpikeBlock', '86:Triceritops', '87:FireKeese', '88:Mothula', '89', '8A:SpikeBlock', '8B:Gibdo', '8C:Arrghus', '8D:ArrghusFuzz', '8E:Shell', '8F:Blob', '90:WallMaster', '91:StalfosKnight', '92:Helmasaur', '93:RedOrb', '94', '95:EyeLaser(Right)', '96:EyeLaser(Left)', '97:EyeLaser(Down)', '98:EyeLaser(Up)', '99:Penguin', '9A:Splash', '9B:Wizzrobe', '9C', '9D:VRat', '9E:Ostrich', '9F:Rabbit', 'A0:Uglybird', 'A1:IceMan', 'A2:KholdStare', 'A3', 'A4', 'A5:GreenLizard', 'A6:RedLizard', 'A7:Stalfos', 'A8:GreenAirBomber', 'A9:BlueAirBomber', 'AA:LikeLike', 'AB', 'AC:Apples', 'AD:OldMan', 'AE:DownPipe', 'AF:UpPipe', 'B0:RightPipe', 'B1:LeftPipe', 'B2:Good-Bee', 'B3:Inscription', 'B4:BlueChest', 'B5:BombShop', 'B6:Kiki', 'B7:BlindMan', 'B8', 'B9:Bully&Whimp(DW)', 'BA:Whirlpool', 'BB:ShopMan', 'BC:OldMan2', 'BD:Viterous', 'BE:', 'BF:Lighting', 'C0:Item', 'C1:AgahTalk', 'C2:RockChip', 'C3:Half-Bubble', 'C4:Bully', 'C5:Shooter', 'C6:4WayShooter', 'C7:FuzzyStack', 'C8:BigFairy', 'C9:Tektite', 'CA:Chomp', 'CB:TriNexx1', 'CC:TriNexx2', 'CD:TriNexx3', 'CE:Blind', 'CF:SwampSnake', 'D0:Lynel', 'D1:Transform/Smoke', 'D2:Fish', 'D3:AliveRock', 'D4:GroundBomb', 'D5:DiggingGameGuy', 'D6:Ganon', 'D7', 'D8:Heart', 'D9:Rupee-G', 'DA:Rupee-B', 'DB:InTreeRocks', 'DC:Bomb', 'DD:4_bombs', 'DE:8_bombs', 'DF:Magic', 'E0:BigMagic', 'E1:Arrow', 'E2:10-Arrows', 'E3:Fairy', 'E4:Key', 'E5:Big_Key', 'E6', 'E7:Mushroom', 'E8:FakeSword', 'E9:ShopMan2', 'EA:WitchAssistant', 'EB:HeartPie', 'EC:PickedObj', 'ED', 'EE:Mantle', 'EF', 'F0', 'F1', 'F2:MedallianTablet', 'F3:PersonsDoor', 'F4:FallingRocks', 'F5', 'F6', 'F7', 'F8', 'F9', 'FA', 'FB', 'FC', 'FD', 'FE', 'FF', '100:CannonRoom', '101:01', '102:CannonRoom', '103:CannonBalls', '104:RopeDrp(Snake)', '105:StalfosDrop', '106:BombDrop', '107:MovingFloor', '108:Transformer', '109:WallMaster', '10A:FloorDrop(Sqr)', '10B:FloorDrop(Vert)', '10C:0C', '10D:0D', '10E:0E', '10F:0F', '110:RightEvil', '111:LeftEvil', '112:DownEvil
\ No newline at end of file
-kSpriteNames = [a.replace(':', '-') for a in kSpriteNames]
-
-kSpriteName2Idx = {a:i for i,a in enumerate(kSpriteNames)}
-kSpriteNamesRev = {v : i for i, v in enumerate(kSpriteNames)}
-
-
-
-kSpriteDropToNameIdx = [
-  0xd9, 0x3e, 0x79, 0xd9, 0xdc, 0xd8, 0xda, 0xe4, 0xe1, 0xdc, 0xd8, 0xdf, 0xe0, 0xb, 0x42, 0xd3, 
-  0x41, 0xd4, 0xd9, 0xe3, 0xd8,    0, ]
-
-def get_secret_names():
-  r = {}
-  for i in range(1, 23):
-    r[i] = '%.2X-%s' % (i, kSpriteNames[kSpriteDropToNameIdx[i - 1]][3:])
-  kSpecialSecret = {0 : "Nothing", 4 : "Random", 0x80 : "Hole", 0x82 : "Warp", 0x84 : "Staircase", 0x86 : 'Bombable', 0x88 : 'Switch' }
-  for k,v in kSpecialSecret.items():
-    r[k] = '%.2X-%s' % (k, v)
-  return r
-
-kSecretNames = get_secret_names()
-kSecretNamesRev = invert_dict(kSecretNames)
-
-kCompSpritePtrs = [
-  0x10f000,0x10f600,0x10fc00,0x118200,0x118800,0x118e00,0x119400,0x119a00,
-  0x11a000,0x11a600,0x11ac00,0x11b200,0x14fffc,0x1585d4,0x158ab6,0x158fbe,
-  0x1593f8,0x1599a6,0x159f32,0x15a3d7,0x15a8f1,0x15aec6,0x15b418,0x15b947,
-  0x15bed0,0x15c449,0x15c975,0x15ce7c,0x15d394,0x15d8ac,0x15ddc0,0x15e34c,
-  0x15e8e8,0x15ee31,0x15f3a6,0x15f92d,0x15feba,0x1682ff,0x1688e0,0x168e41,
-  0x1692df,0x169883,0x169cd0,0x16a26e,0x16a275,0x16a787,0x16aa06,0x16ae9d,
-  0x16b3ff,0x16b87e,0x16be6b,0x16c13d,0x16c619,0x16cbbb,0x16d0f1,0x16d641,
-  0x16d95a,0x16dd99,0x16e278,0x16e760,0x16ed25,0x16f20f,0x16f6b7,0x16fa5f,
-  0x16fd29,0x1781cd,0x17868d,0x178b62,0x178fd5,0x179527,0x17994b,0x179ea7,
-  0x17a30e,0x17a805,0x17acf8,0x17b2a2,0x17b7f9,0x17bc93,0x17c237,0x17c78e,
-  0x17cd55,0x17d2bc,0x17d82f,0x17dcec,0x17e1cc,0x17e36b,0x17e842,0x17eb38,
-  0x17ed58,0x17f06c,0x17f4fd,0x17fa39,0x17ff86,0x18845c,0x1889a1,0x188d64,
-  0x18919d,0x189610,0x189857,0x189b24,0x189dd2,0x18a03f,0x18a4ed,0x18a7ba,
-  0x18aedf,0x18af0d,0x18b520,0x18b953,
-]
-
-kCompBgPtrs = [
-  0x11b800,0x11bce2,0x11c15f,0x11c675,0x11cb84,0x11cf4c,0x11d2ce,0x11d726,
-  0x11d9cf,0x11dec4,0x11e393,0x11e893,0x11ed7d,0x11f283,0x11f746,0x11fc21,
-  0x11fff2,0x128498,0x128a0e,0x128f30,0x129326,0x129804,0x129d5b,0x12a272,
-  0x12a6fe,0x12aa77,0x12ad83,0x12b167,0x12b51d,0x12b840,0x12bd54,0x12c1c9,
-  0x12c73d,0x12cc86,0x12d198,0x12d6b1,0x12db6a,0x12e0ea,0x12e6bd,0x12eb51,
-  0x12f135,0x12f6c5,0x12fc71,0x138129,0x138693,0x138bad,0x139117,0x139609,
-  0x139b21,0x13a074,0x13a619,0x13ab2b,0x13b00c,0x13b4f5,0x13b9eb,0x13bebf,
-  0x13c3ce,0x13c817,0x13cb68,0x13cfb5,0x13d460,0x13d8c2,0x13dd7a,0x13e266,
-  0x13e7af,0x13ece5,0x13f245,0x13f6f0,0x13fc30,0x1480e9,0x14863b,0x148a7c,
-  0x148f2a,0x149346,0x1497ed,0x149cc2,0x14a173,0x14a61d,0x14ab5d,0x14b083,
-  0x14b4bd,0x14b94e,0x14be0e,0x14c291,0x14c7ba,0x14cce4,0x14d1db,0x14d6bd,
-  0x14db77,0x14ded1,0x14e2ac,0x14e754,0x14ebae,0x14ef4e,0x14f309,0x14f6f4,
-  0x14fa55,0x14ff8c,0x14ff93,0x14ff9a,0x14ffa1,0x14ffa8,0x14ffaf,0x14ffb6,
-  0x14ffbd,0x14ffc4,0x14ffcb,0x14ffd2,0x14ffd9,0x14ffe0,0x14ffe7,0x14ffee,
-  0x14fff5,0x18b520,0x18b953,
-]
-
-kSpriteTilesets = [
-  ( 0, 73,   0,  0),
-  (70, 73,  12, 29),
-  (72, 73,  19, 29),
-  (70, 73,  19, 14),
-  (72, 73,  12, 17),
-  (72, 73,  12, 16),
-  (79, 73,  74, 80),
-  (14, 73,  74, 17),
-  (70, 73,  18,  0),
-  ( 0, 73,   0, 80),
-  ( 0, 73,   0, 17),
-  (72, 73,  12,  0),
-  ( 0,  0,  55, 54),
-  (72, 73,  76, 17),
-  (93, 44,  12, 68),
-  ( 0,  0,  78,  0),
-  (15,  0,  18, 16),
-  ( 0,  0,   0, 76),
-  ( 0, 13,  23,  0),
-  (22, 13,  23, 27),
-  (22, 13,  23, 20),
-  (21, 13,  23, 21),
-  (22, 13,  24, 25),
-  (22, 13,  23, 25),
-  (22, 13,   0,  0),
-  (22, 13,  24, 27),
-  (15, 73,  74, 17),
-  (75, 42,  92, 21),
-  (22, 73,  23, 29),
-  ( 0,  0,   0, 21),
-  (22, 13,  23, 16),
-  (22, 73,  18,  0),
-  (22, 73,  12, 17),
-  ( 0,  0,  18, 16),
-  (22, 13,   0, 17),
-  (22, 73,  12,  0),
-  (22, 13,  76, 17),
-  (14, 13,  74, 17),
-  (22, 26,  23, 27),
-  (79, 52,  74, 80),
-  (53, 77, 101, 54),
-  (74, 52,  78,  0),
-  (14, 52,  74, 17),
-  (81, 52,  93, 89),
-  (75, 73,  76, 17),
-  (45,  0,   0,  0),
-  (93,  0,  18, 89),
-  ( 0,  0,   0,  0),
-  ( 0,  0,   0,  0),
-  ( 0,  0,   0,  0),
-  ( 0,  0,   0,  0),
-  ( 0,  0,   0,  0),
-  ( 0,  0,   0,  0),
-  ( 0,  0,   0,  0),
-  ( 0,  0,   0,  0),
-  ( 0,  0,   0,  0),
-  ( 0,  0,   0,  0),
-  ( 0,  0,   0,  0),
-  ( 0,  0,   0,  0),
-  ( 0,  0,   0,  0),
-  ( 0,  0,   0,  0),
-  ( 0,  0,   0,  0),
-  ( 0,  0,   0,  0),
-  ( 0,  0,   0,  0),
-  (71, 73,  43, 45),
-  (70, 73,  28, 82),
-  ( 0, 73,  28, 82),
-  (93, 73,   0, 82),
-  (70, 73,  19, 82),
-  (75, 77,  74, 90),
-  (71, 73,  28, 82),
-  (75, 77,  57, 54),
-  (31, 44,  46, 82),
-  (31, 44,  46, 29),
-  (47, 44,  46, 82),
-  (47, 44,  46, 49),
-  (31, 30,  48, 82),
-  (81, 73,  19,  0),
-  (79, 73,  19, 80),
-  (79, 77,  74, 80),
-  (75, 73,  76, 43),
-  (31, 32,  34, 83),
-  (85, 61,  66, 67),
-  (31, 30,  35, 82),
-  (31, 30,  57, 58),
-  (31, 30,  58, 62),
-  (31, 30,  60, 61),
-  (64, 30,  39, 63),
-  (85, 26,  66, 67),
-  (31, 30,  42, 82),
-  (31, 30,  56, 82),
-  (31, 32,  40, 82),
-  (31, 32,  38, 82),
-  (31, 44,  37, 82),
-  (31, 32,  39, 82),
-  (31, 30,  41, 82),
-  (31, 44,  59, 82),
-  (70, 73,  36, 82),
-  (33, 65,  69, 51),
-  (31, 44,  40, 49),
-  (31, 13,  41, 82),
-  (31, 30,  39, 82),
-  (31, 32,  39, 83),
-  (72, 73,  19, 82),
-  (14, 30,  74, 80),
-  (31, 32,  38, 83),
-  (21,  0,   0,  0),
-  (31,  0,  42, 82),
-  ( 0,  0,   0,  0),
-  ( 0,  0,   0,  0),
-  ( 0,  0,   0,  0),
-  ( 0,  0,   0,  0),
-  ( 0,  0,   0,  0),
-  ( 0,  0,   0,  0),
-  ( 0,  0,   0,  0),
-  ( 0,  0,   0,  0),
-  ( 0,  0,   0,  0),
-  ( 0,  0,   0,  0),
-  ( 0,  0,   0,  0),
-  ( 0,  0,   0,  0),
-  ( 0,  0,   0,  0),
-  ( 0,  0,   0,  0),
-  ( 0,  0,   0,  0),
-  ( 0,  0,   0,  0),
-  ( 0,  0,   0,  0),
-  (50,  0,   0,  8),
-  (93, 73,   0, 82),
-  (85, 73,  66, 67),
-  (97, 98,  99, 80),
-  (97, 98,  99, 80),
-  (97, 98,  99, 80),
-  (97, 98,  99, 80),
-  (97, 98,  99, 80),
-  (97, 98,  99, 80),
-  (97, 86,  87, 80),
-  (97, 98,  99, 80),
-  (97, 98,  99, 80),
-  (97, 86,  87, 80),
-  (97, 86,  99, 80),
-  (97, 86,  87, 80),
-  (97, 86,  51, 80),
-  (97, 86,  87, 80),
-  (97, 98,  99, 80),
-  (97, 98,  99, 80),
-]
-
-kDungPalinfos = [
-  ( 0,  0,  3,  1),
-  ( 2,  0,  3,  1),
-  ( 4,  0, 10,  1),
-  ( 6,  0,  1,  7),
-  (10,  2,  2,  7),
-  ( 4,  4,  3, 10),
-  (12,  5,  8, 20),
-  (14,  0,  3, 10),
-  ( 2,  0, 15, 20),
-  (10,  2,  0,  7),
-  ( 2,  0, 15, 12),
-  ( 6,  0,  6,  7),
-  ( 0,  0, 14, 18),
-  (18,  5,  5, 11),
-  (18,  0,  2, 12),
-  (16,  5, 10,  7),
-  (16,  0, 16, 12),
-  (22,  7,  2,  7),
-  (22,  0,  7, 15),
-  ( 8,  0,  4, 12),
-  ( 8,  0,  4,  9),
-  ( 4,  0,  3,  1),
-  (20,  0,  4,  4),
-  (20,  0, 20, 12),
-  (24,  5,  7, 11),
-  (24,  6, 16, 12),
-  (26,  5,  8, 20),
-  (26,  2,  0,  7),
-  ( 6,  0,  3, 10),
-  (28,  0,  3,  1),
-  (30,  0, 11, 17),
-  ( 4,  0, 11, 17),
-  (14,  0,  0,  2),
-  (32,  8, 19, 13),
-  (10,  0,  3, 10),
-  (20,  0,  4,  4),
-  (26,  2,  2,  7),
-  (26, 10,  0,  0),
-  ( 0,  0,  3,  2),
-  (14,  0,  3,  7),
-  (26,  5,  5, 11),
-]
-
-kOwSprPalInfo = [
-  -1, -1, 3, 10, 3, 6, 3, 1, 0, 2, 3, 14, 3, 2, 19, 1, 11, 12, 17, 1, 7, 5, 17, 0,
-  9, 11, 15, 5, 3, 5, 3, 7, 15, 2, 10, 2, 5, 1, 12, 14,
-]
-
-kSpriteInit_Flags3 = [
-  0x19,  0xb, 0x1b, 0x4b, 0x41, 0x41, 0x41, 0x4d, 0x1d,    1, 0x1d, 0x19, 0x8d, 0x1b,    9, 0x9d,
-  0x3d,    1,    9, 0x11, 0x40,    1, 0x4d, 0x19,    7, 0x1d, 0x59, 0x80, 0x4d, 0x40,    1, 0x49,
-  0x1b, 0x41,    3, 0x13, 0x15, 0x41, 0x18, 0x1b, 0x41, 0x47,  0xf, 0x49, 0x4b, 0x4d, 0x41, 0x47,
-  0x49, 0x4d, 0x49, 0x40, 0x4d, 0x47, 0x49, 0x41, 0x74, 0x47, 0x5b, 0x58, 0x51, 0x49, 0x1d, 0x5d,
-     3, 0x19, 0x1b, 0x17, 0x19, 0x17, 0x19, 0x1b, 0x17, 0x17, 0x17, 0x1b,  0xd,    9, 0x19, 0x19,
-  0x49, 0x5d, 0x5b, 0x49,  0xd,    3, 0x13, 0x41, 0x1b, 0x5b, 0x5d, 0x43, 0x43, 0x4d, 0x4d, 0x4d,
-  0x4d, 0x4d, 0x49,    1,    0, 0x41, 0x4d, 0x4d, 0x4d, 0x4d, 0x1d,    9, 0xc4,  0xd,  0xd,    9,
-     3,    3, 0x4b, 0x47, 0x47, 0x49, 0x49, 0x41, 0x47, 0x36, 0x8b, 0x49, 0x1d, 0x49, 0x43, 0x43,
-  0x43,  0xb, 0x41,  0xd,    7,  0xb, 0x1d, 0x43,  0xd, 0x43,  0xd, 0x1d, 0x4d, 0x4d, 0x1b, 0x1b,
-   0xa,  0xb,    0,    5,  0xd,    1,    1,    1,    1,  0xb,    5,    1,    1,    1,    7, 0x17,
-  0x19,  0xd,  0xd, 0x80, 0x4d, 0x19, 0x17, 0x19,  0xb,    9,  0xd, 0x4a, 0x12, 0x49, 0xc3, 0xc3,
-  0xc3, 0xc3, 0x76, 0x40, 0x59, 0x41, 0x58, 0x4f, 0x73, 0x5b, 0x44, 0x41, 0x51,  0xa,  0xb,  0xb,
-  0x4b,    0, 0x40, 0x5b,  0xd,    0,    0,  0xd, 0x4b,  0xb, 0x59, 0x41,  0xb,  0xd,    1,  0xd,
-   0xd,    0, 0x50, 0x4c, 0x44, 0x51,    1,    1, 0xf2, 0xf8, 0xf4, 0xf2, 0xd4, 0xd4, 0xd4, 0xf8,
-  0xf8, 0xf4, 0xf4, 0xd8, 0xf8, 0xd8, 0xdf, 0xc8, 0x69, 0xc1, 0xd2, 0xd2, 0xdc, 0xc7, 0xc1, 0xc7,
-  0xc7, 0xc7, 0xc1,
-]
--- a/tables/text_compression.py
+++ /dev/null
@@ -1,551 +1,0 @@
-import util, sys
-
-kTextAlphabet_US = [
-  "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", # 0 - 15
-  "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "a", "b", "c", "d", "e", "f", # 16 - 31
-  "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", # 32 - 47
-  "w", "x", "y", "z", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "!", "?", # 48 - 63
-  "-", ".", ",", 
-  # 64 - 79
-  "[...]", ">", "(", ")",
-  "[Ankh]", "[Waves]", "[Snake]", "[LinkL]", "[LinkR]",
-  "\"", "[Up]", "[Down]", "[Left]",
-  # 80 - 95
-  "[Right]", "'", "[1HeartL]", "[1HeartR]", "[2HeartL]", "[3HeartL]", "[3HeartR]",
-  "[4HeartL]", "[4HeartR]", " ", "<", "[A]", "[B]", "[X]", "[Y]",
-]
-
-kTextAlphabet_DE = [
-  "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", # 0 - 15
-  "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "a", "b", "c", "d", "e", "f", # 16 - 31
-  "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", # 32 - 47
-  "w", "x", "y", "z", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "!", "?", # 48 - 63
-  # 64 - 79
-  "-", ".", ",",  "[...]", ">", "(", ")",
-  "[Ankh]", "[Waves]", "[Snake]", "[LinkL]", "[LinkR]",
-  "\"", "[UpL]", "[UpR]", "[LeftL]",
-  # 80 - 95
-  "[LeftR]", "'", "[1HeartL]", "[1HeartR]", "[2HeartL]", "[3HeartL]", "[3HeartR]",
-  "[4HeartL]", "[4HeartR]", " ", "ö", "[A]", "[B]", "[X]", "[Y]", "ü",
-  # 96-111
-  "ß", ":", "[DownL]", "[DownR]", "[RightL]", "[RightR]",
-  "è", "é", "ê", "à", "ù", "ç", "Ä", "Ö", "Ü", "ä"
-  # 112-
-]
-
-kTextAlphabet_FR = [
-  "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", # 0 - 15
-  "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "a", "b", "c", "d", "e", "f", # 16 - 31
-  "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", # 32 - 47
-  "w", "x", "y", "z", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "!", "?", # 48 - 63
-  # 64 - 79
-  "-", ".", ",",  "[...]", ">", "(", ")",
-  "[Ankh]", "[Waves]", "[Snake]", "[LinkL]", "[LinkR]",
-  "\"", "[UpL]", "[UpR]", "[LeftL]",
-  # 80 - 95
-  "[LeftR]", "'", "[1HeartL]", "[1HeartR]", "[2HeartL]", "[3HeartL]", "[3HeartR]",
-  "[4HeartL]", "[4HeartR]", " ", "ö", "[A]", "[B]", "[X]", "[Y]", "ü",
-  # 96-111
-  "ô", ":", "[DownL]", "[DownR]", "[RightL]", "[RightR]",
-  "è", "é", "ê", "à", "ù", "ç", "â", "û", "î", "ä"
-  # 112-
-]
-
-kText_CommandLengths_US = [1, 1, 1, 1, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 1, 1, 1, 1, 1, ]
-kText_CommandNames_US = [
-  "NextPic", "Choose", "Item", "Name", "Window", "Number",
-  "Position","ScrollSpd", "Selchg", "Unused_Crash", "Choose3",
-  "Choose2", "Scroll", "1", "2", "3", "Color",
-  "Wait", "Sound", "Speed", "Unused_Mark", "Unused_Mark2", "Unused_Clear",
-  "Waitkey"
-]
-
-kTextDictionary_US = [
-'    ', '   ', '  ', "'s ", 'and ', 
-'are ', 'all ', 'ain', 'and', 'at ', 
-'ast', 'an', 'at', 'ble', 'ba', 
-'be', 'bo', 'can ', 'che', 'com', 
-'ck', 'des', 'di', 'do', 'en ', 
-'er ', 'ear', 'ent', 'ed ', 'en', 
-'er', 'ev', 'for', 'fro', 'give ', 
-'get', 'go', 'have', 'has', 'her', 
-'hi', 'ha', 'ight ', 'ing ', 'in', 
-'is', 'it', 'just', 'know', 'ly ', 
-'la', 'lo', 'man', 'ma', 'me', 
-'mu', "n't ", 'non', 'not', 'open', 
-'ound', 'out ', 'of', 'on', 'or', 
-'per', 'ple', 'pow', 'pro', 're ', 
-'re', 'some', 'se', 'sh', 'so', 
-'st', 'ter ', 'thin', 'ter', 'tha', 
-'the', 'thi', 'to', 'tr', 'up', 
-'ver', 'with', 'wa', 'we', 'wh', 
-'wi', 'you', 'Her', 'Tha', 'The', 
-'Thi', 'You', 
-]
-
-
-kText_CommandLengths_EU = [1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2]
-kText_CommandNames_EU = [
-  "Selchg", "Choose3", "Choose2", "Scroll", "1", "2", "3",
-  "Color", "Wait", "Sound", "Speed", "Mark", "Mark2",
-  "Clear", "Waitkey", "EndMessage", "NextPic", "Choose",
-  "Item", "Name", "Window", "Number", "Position", "ScrollSpd",
-]
-
-kTextDictionary_DE = [
-'    ', '   ', '                                          ', '-Knopf', ' ich ', 
-' Sch', ' Ver', ' zu ', ' es ', 'aber', 
-'alle', 'auch', 'ang', 'aus', 'auf', 
-'an', 'bist', 'bin', 'bei', 'der ', 
-'die ', 'das ', 'den ', 'dem ', 'daß', 
-'der', 'die', 'das', 'den', 'da', 
-'etwas', 'ein ', 'ein', 'en ', 'er ', 
-'es ', 'en', 'er', 'es', 'ei', 
-'für', 'fe', 'habe', 'hier', 'hast', 
-'her', 'ich ', 'icht', 'ich', 'ist', 
-'ie ', 'im', 'ie', 'kannst ', 'kannst', 
-'kommen', 'kann ', 'll', 'mich', 'mein', 
-'mit', 'mal', 'mir', 'nicht ', 'nicht', 
-'nen', 'nn', 'och ', 'och', 'or', 
-'schon', 'sich', 'sein', 'sch', 'sie', 
-'st', 'tte', 'te ', 'te', 'und ', 
-'und', 'ung', 'um', 'von', 'ver', 
-'vor', 'wird', 'zu ', 'Amulett', 'Aber', 
-'Deine', 'Dich ', 'Dir ', 'Dir', 'Der', 
-'Die', 'Das', 'Du ', 'Du', 'Da', 
-'Ein', 'Hyrule', 'Hier', 'Ich ', 'Master-Schwert', 
-'Mach', 'Rubine', 'Sch', 'Sie', 'Ver', 
-'Weisen', 'Zelda', 
-]
-
-kTextDictionary_FR = [
-'                                          ', ' de ', ' la ', ' le ', ' ! ', 
-' d', ' p', ' t', ' !', ", c'est moi, Sahasrahla", 
-', ', 'ais ', 'as ', 'an', 'ai', 
-'a ', 'che', 'ce', 'ch', 'dans ', 
-'des ', 'de ', 'de', 'est ', 'ent', 
-'en ', 'er ', 'es ', 'en', 'es', 
-'et', 'eu', 'e,', 'e ', 'ique', 
-'ien', 'is ', 'ie', 'in', 'ir', 
-'is', 'i ', 'les ', 'la ', 'le ', 
-'le', 'll', 'maintenant', 'magique', 'ment', 
-'mon', 'mai', 'me', 'ne ', 'onne', 
-'oir', 'our', 'ouv', 'oi', 'on', 
-'ou', 'or', 'pouvoir', 'pour', 'peux', 
-'pas', 'que ', 'qu', 'rubis', 're ', 
-'ra', 're', 'r ', 'sorcier', 's l', 
-'s d', 'se', 'so', 's ', 'tro', 
-'te ', 'tu ', 'te', 't ', 'un', 
-'ur', 'u ', 'ver', 'Ah ! Ah ! Ah !', "C'est", 
-'Ganon', 'Maintenant', 'Merci', 'Monde', 'Perle de Lune', 
-'Tu as trouvé ', 'Ténèbres', 'Tu peux', 'Tu ',
-]
-
-
-# Uses the original format
-def org_encoder(cmd, param):
-    if cmd not in kText_CommandNames_US:
-      raise Exception(f'Invalid cmd {cmd}')
-    cmd_index = kText_CommandNames_US.index(cmd)
-    if kText_CommandLengths_US[cmd_index] != (1 if param == None else 2):
-      raise Exception(f'Invalid cmd params {cmd} {param}')
-    if param == None:
-      return [cmd_index + 0x67]
-    return [cmd_index + 0x67, int(param)]
-
-kCmdInfo = {
-  "Scroll" : (0x80, ),
-  "Waitkey" : (0x81, ),
-  "1" : (0x82, ),
-  "2" : (0x83, ),
-  "3" : (0x84, ),
-  "Name" : (0x85, ),
-  "Wait" : (0x87, {i:i+0x00 for i in range(16)}),
-  "Color" : (0x87, {i:i+0x10 for i in range(16)}),
-  "Number" : (0x87, {i:i+0x20 for i in range(16)}),
-  "Speed" : (0x87, {i:i+0x30 for i in range(16)}),
-  "Sound" : (0x87, {45 : 0x40, 64 : None}), # pt uses 64 for some reason
-  "Choose" : (0x87, 0x80),
-  "Choose2" : (0x87, 0x81),
-  "Choose3" : (0x87, 0x82),
-  "Selchg" : (0x87, 0x83),
-  "Item" : (0x87, 0x84),
-  "NextPic" : (0x87, 0x85),
-  "Window" : (0x87, {0 : None, 2 : 0x86}),
-  "Position" : (0x87, {0: 0x87, 1: 0x88}),
-  "ScrollSpd" : (0, {0 : None}),
-}
-
-# Uses another format where there's more bytes left for characters
-def new_encoder(cmd, param):
-  if cmd not in kCmdInfo:
-    raise Exception(f'Invalid cmd {cmd}')
-  info = kCmdInfo[cmd]
-  if len(info) <= 1 or isinstance(info[1], int):
-    if param != None:
-      raise Exception(f'Invalid cmd params {cmd} {param}')
-    return info
-  else:
-    if param == None or param not in info[1]:
-      raise Exception(f'Invalid cmd params {cmd} {param}')
-    r = info[1][param]
-    return (info[0], r) if r != None else ()
-
-kEncoders = {'org' : org_encoder, 'new' : new_encoder}
-
-
-class LangUS:
-  alphabet = kTextAlphabet_US
-  dictionary = kTextDictionary_US
-  command_lengths = kText_CommandLengths_US
-  command_names = kText_CommandNames_US
-  rom_addrs = [0x9c8000, 0x8edf40]
-  COMMAND_START = 0x67
-  SWITCH_BANK = 0x80
-  FINISH = 0xff
-  DICT_BASE_ENC, DICT_BASE_DEC = 0x88, 0x88
-  ESCAPE_CHARACTER = None
-  encoder = 'org'
-
-class LangEN(LangUS):
-  alphabet = kTextAlphabet_DE
-  dictionary = kTextDictionary_US
-  rom_addrs = [0x9c8000, 0x8edf60]
-
-class LangES(LangUS):
-  alphabet = [
-    "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", # 0 - 15
-    "Q", "R", "S", "T", "U", "V", "W", "é", "Y", "Z", "a", "b", "c", "d", "e", "f", # 16 - 31
-    "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", # 32 - 47
-    "ó", "x", "y", "z", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "!", "?", # 48 - 63
-    "[Waves]", ".", ",", 
-    # 64 - 79
-    "[...]", ">", "(", ")",
-    "ñ", "ú", "á", "[LinkL]", "[LinkR]", "\"", "[Up]", "[Down]", "[Left]",
-    # 80 - 95
-    "[Right]", "í", "[1HeartL]", "[1HeartR]", "[2HeartL]", "[3HeartL]", "[3HeartR]",
-    "[Ankh]", "[4HeartR]", " ", "[Snake]", "[A]", "[B]", "[X]", "[Y]", "[I]",
-    "¡", "¿", "Ñ"
-  ]
-  # "[Ankh]", "[Waves]", "[Snake]"
-
-  dictionary = [
-    '    ', '   ', '  ', ' en', ' la ', ' el ', ' de ', 'ien', 'tra', ' de', 
-    'te ', 'ar', 'a ', 'ada', 'es', 'as', 'o ', ' con', 'ero', 'ado', 
-    'e ', 'que', 'en', 'al', 'os ', 'ora', 'nte', ' al', 'lo ', 'or', 
-    'os', 'er', 'aci', 'res', ' que ', ' es', 'el', 'los ', 'tar', ' se', 
-    ', ', 'ro', ' de l', ' est', 're', 'on', 'an', 'pued', ' del', 'ás ', 
-    'la', 'ti', 'la ', 'Es', 'to', 'ta', 'para', 'uer', 'ier', ' un ', 
-    ' por', 'oder', 'da', 'in', 'cu', ' ha', 'per', 'ano', ' ve', 'cer', 
-    'lo', ' no ', 'ic', 'ra', 'ab', 'ir', ' una', 'undo', 'es ', 'as ', 
-    'con', 'a, ', 'te', ' m', 'gu', ' tu', 'ando', ' p', 'de', 'le', 
-    'ol', 'o, ', 'ten', 'lle', ' a ', 'aba', 'com', 
-  ]
-  rom_addrs = [0x9c8000, 0x8edf40]
-
-
-class LangNL(LangUS):
-  alphabet = [
-    "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", # 0 - 15
-    "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "a", "b", "c", "d", "e", "f", # 16 - 31
-    "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", # 32 - 47
-    "w", "x", "y", "z", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "!", "?", # 48 - 63
-    "-", ".", ",", "[...]", ">", "(", ")", "[Ankh]",
-    "[Waves]", "[Snake]", "[LinkL]", "[LinkR]", "\"", "[Up]", "[Down]", "[Left]",
-    # 80 - 95
-    "[Right]", "'", "[1HeartL]", "[1HeartR]", "[2HeartL]", "[3HeartL]", "[3HeartR]",
-    "[4HeartL]", "[4HeartR]", " ", "<", "[A]", "[B]", "[X]", "[Y]",
-  ]
-
-  dictionary = [
-    '    ', '   ', '  ', "'s ", 'and ', 'are ', 'all ', 'ain', 'and', 'at ', 
-    'ast', 'an', 'at', 'ble', 'ba', 'be', 'bo', 'can ', 'che', 'com', 
-    'ck', 'des', 'di', 'do', 'en ', 'er ', 'ear', 'ent', 'ed ', 'en', 
-    'er', 'ev', 'for', 'fro', 'give ', 'get', 'go', 'have', 'has', 'her', 
-    'hi', 'ha', 'ight ', 'ing ', 'in', 'is', 'it', 'just', 'know', 'ly ', 
-    'la', 'lo', 'man', 'ma', 'me', 'mu', "n't ", 'non', 'not', 'open', 
-    'ound', 'out ', 'of', 'on', 'or', 'per', 'ple', 'pow', 'pro', 're ', 
-    're', 'some', 'se', 'sh', 'so', 'st', 'ter ', 'thin', 'ter', 'tha', 
-    'the', 'thi', 'to', 'tr', 'up', 'ver', 'with', 'wa', 'we', 'wh', 
-    'wi', 'you', 'Her', 'Tha', 'The', 'Thi', 'You', 
-  ]
-  rom_addrs = [0x9c8000, 0x8edf40]
-
-
-
-class LangSV(LangUS):
-  alphabet = [
-    "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "Ö", "P", # 0 - 15
-    "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "a", "b", "c", "d", "e", "f", # 16 - 31
-    "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", # 32 - 47
-    "w", "x", "y", "z", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "!", "?", # 48 - 63
-    "å", ".", ",", "ä", ">", "(", ")","ö",
-    "Å", "Ä", "[LinkL]", "[LinkR]", "\"", "[Up]", "[Down]", "[Left]",
-    # 80 - 95
-    "[Right]", "'", "[1HeartL]", "[1HeartR]", "[2HeartL]", "[3HeartL]", "[3HeartR]",
-    "[4HeartL]", "[4HeartR]", " ", "<", "[Ankh]", "[Waves]", "[Snake]", "-", "[I]",
-    "[i]", "…", " ",
-  ]
-
-  dictionary = [
-    '    ', '   ', '  ', 'Du ', 'till', 'vill', 'bara', 'det', 'den', 'och', 
-    'en ', 'r ', 'n ', 'ett', 'en', ' d', 'a ', 'Hjäl', 'har', 'ter', 
-    't ', 'var', ' s', 'de', 'kan', 'med', 'som', 'för', 'att', 'ar', 
-    ' h', 'er', 'jag', 'dig', 'öppna', 'mig', 'är', 'inte', 'hit', 'på ', 
-    'an', 'e ', 'rupie', '0kej', ' m', 'et', ', ', 'gång', 'måst', 'ten', 
-    ' f', 'u ', 'men', 'te', 'tt', 'ka', 'vara', 'ken', '0m ', 'från', 
-    'myck', 'någo', 'in', ' k', ' i', 'vil', 'bar', 'ond', 'För', 'Jag', 
-    'ra', 'tack', 'll', 'g ', 'ta', 'om', 'anna', 'alla', 'en,', 'ber', 
-    'hem', 'han', 'st', 'ig', ' t', 'tro', 'kraf', 'ör', ' v', 'ag', 
-    '… ', 'får', 'sin', 'mme', 'mma', 'en ', 'tat',
-  ]
-  rom_addrs = [0x9c8000, 0x8edf40]
-
-
-class LangPL(LangUS):
-  alphabet = [
-    "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", # 0 - 15
-    "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "a", "b", "c", "d", "e", "f", # 16 - 31
-    "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", # 32 - 47
-    "w", "x", "y", "z", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "!", "?", # 48 - 63
-    "-", ".", ",", "ć", "[Right]", "(", ")", "[Ankh]", 
-    "[Waves]", "[Snake]", "[LinkL]", "[LinkR]","\"", "[Up]", "[Down]", "ę",
-
-    "ł", "ń", "[1HeartL]", "[1HeartR]", "[2HeartL]", "[3HeartL]", "[3HeartR]",
-    "ą", "[4HeartR]", " ", "[Left]", "ó", "ś", "ż", "ź", "Ł",
-    "Ś", "Ż", "Ź",
-  ] # 
-  dictionary = ['Trój', '...', 'ść', 'Nie', ' nie', ' się', 'może', ' że', 'and', 'at ', 
-    ' ty', 'an', 'at', 'kus', 'ba', 'be', 'bo', 'chce', 'che', 'ki ', 
-    'za', 'des', 'di', 'do', 'en ', 'er ', 'sz ', 'ent', 'ed ', 'en', 
-    'er', ' w', 'moc', 'zię', 'przez', 'ale', 'go', 'dzie', 'has', 'rze', 
-    'hi', 'ha', 'który', 'aby ', 'in', 'is', 'it', 'twoj', 'Może', 'łeś', 
-    'la', 'lo', 'czn', 'ma', 'me', 'mu', 'szcz', 'ska', 'śli', 'przy', 
-    'znaj', 'iecz', 'of', 'on', 'or', '   ', 'ple', 'pow', 'pro', 're ', 
-    're', 'mnie', 'se', ' z', 'so', 'st', 'któr', ' jak', 'ksz', 'sze', 
-    'coś', ' je', 'to', 'tr', 'up', 'kie', 'praw', 'wa', 'we', 'mi', 
-    'wi', 'szy', 'chc', 'pra', 'cie', ' i ', 'esz',
-  ]
-
-  rom_addrs = [0x9c8000, 0x8edf40]
-
-class LangPT(LangUS):
-  alphabet = [
-    "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", # 0 - 15
-    "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "a", "b", "c", "d", "e", "f", # 16 - 31
-    "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", # 32 - 47
-    "w", "x", "y", "z", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "!", "?", # 48 - 63
-    "-", ".", ",", "[...]", ">", "(", ")", "[Ankh]",
-    "[Waves]", "[Snake]", "[LinkL]", "[LinkR]", "\"", "[Up]", "[Down]", "[Left]",
-    # 80 - 95
-    "[Right]", "'", "[1HeartL]", "[1HeartR]", "[2HeartL]", "[3HeartL]", "[3HeartR]",
-    "[4HeartL]", "[4HeartR]", " ", "<", "[A]", "[B]", "[X]", "[Y]", "[I]",
-
-    "¡", "[!]", "Á", "À", "Â", "Ã", "É", "Ê", "Í", "Ó", "Ô", "Õ", "Ú", "á", "à", "â", 
-    "ã", "é", "ê", "í", "ó", "ô", "õ", "ú", "ç", 
-  ]
-  dictionary = [
-    '     ', '    ', '   ', '                                          ', 'o ', 'a ', 'e ', '..', 'de', 'ar', 
-    's ', 'ra', ' d', 'es', 'ocê ', 'do', ' a', ' p', 'er', ' e', 
-    'que', 'r ', 'os', 'te', ', ', 'as', 'or', 'm ', 'en', ' o', 
-    'nt', 're', ' s', 'co', 'da', 'se', 'st', ' c', ' m', 'em', 
-    'ma', 'ta', ' n', 'ad', 'on', 'al', 'ro', 'an', 'u ', 'nd', 
-    ' um', 'pa', 'ca', 'el', ' f', 'to', 'in', ' t', 'ou', 'ei', 
-    'ss', 'ir', 'no', 'ri', 'tr', 'me', 'la', 'ia', 'le', 've', 
-    'is', 'sa', 'eu', 'pe', 'a.', 'na', 'so', 'mo', 'ga', 'o.', 
-    'á ', 'lo', 'ha', 'pr', 'ua', ' l', '! ', 'ui', 'am', 'ti', 
-    'io', 'gu', 'i ', 'di', 'nh', ' i', 'id', 
-  ]
-  ESCAPE_CHARACTER = 0x62
-  rom_addrs = [0x9c8000, 0x8edf40]
-  encoder = 'new'
-
-  def __init__(self):
-    assert len(self.alphabet) == 121
-
-class LangEU:
-  command_lengths = kText_CommandLengths_EU
-  command_names = kText_CommandNames_EU
-  COMMAND_START = 0x70
-  SWITCH_BANK = 0x88
-  FINISH = 0x8f
-  DICT_BASE_ENC, DICT_BASE_DEC = 0x88, 0x90
-  ESCAPE_CHARACTER = None
-  encoder = 'new'
-
-class LangDE(LangEU):
-  alphabet = kTextAlphabet_DE
-  dictionary = kTextDictionary_DE
-  rom_addrs = [0x9c8000, 0x8CEB00]
-
-class LangFR(LangEU):
-  alphabet = kTextAlphabet_FR
-  dictionary = kTextDictionary_FR
-  rom_addrs = [0x9c8000, 0x8CE800]
-
-class LangFR_C(LangEU):
-  alphabet = kTextAlphabet_FR
-  dictionary = kTextDictionary_FR
-  rom_addrs = [0x9c8000, 0x8CF150]
-
-kLanguages = {
-  'us' : LangUS(),
-  'de' : LangDE(),
-  'fr' : LangFR(),
-  'fr-c' : LangFR_C(),
-  'en' : LangEN(),
-  'es' : LangES(),
-  'pl' : LangPL(),
-  'pt' : LangPT(),
-  'redux' : LangUS(),
-  'nl' : LangNL(),
-  'sv' : LangSV(),
-}
-
-def dialogue_filename(s):
-  if s == 'us': return 'dialogue.txt'
-  return f"dialogue_{s.replace('-', '_')}.txt"
-
-def uses_new_format(lang): 
-  return kLanguages[lang].encoder == 'new'
-
-dict_expansion = []
-
-def decode_strings_generic(get_byte, lang):
-  info = kLanguages[lang]
-  p, rom_idx = info.rom_addrs[0], 1
-  result = []
-  while True:
-    s, srcdata = '', []
-    while True:
-      c = get_byte(p)
-      srcdata.append(c)
-      l = info.command_lengths[c - info.COMMAND_START] if c >= info.COMMAND_START and c < info.SWITCH_BANK else 1
-
-      p += l
-      if c == 0x7f: # EndMessage
-        break
-      if c < info.COMMAND_START:
-        if c == info.ESCAPE_CHARACTER:
-          c = get_byte(p); p += 1
-          srcdata.append(c)
-        s += info.alphabet[c]
-      elif c < info.SWITCH_BANK:
-        if l == 2:
-          srcdata.append(get_byte(p - 1))
-          s += '[%s %.2d]' % (info.command_names[c - info.COMMAND_START], get_byte(p - 1))
-        else:
-          s += '[%s]' % info.command_names[c - info.COMMAND_START]
-      elif c == info.FINISH:
-        return result # done
-      elif c == info.SWITCH_BANK:
-        p = info.rom_addrs[rom_idx]; rom_idx += 1
-        s, srcdata = '', []
-      elif c < info.SWITCH_BANK + 8:
-        if lang != 'pt':
-          assert 0
-      else:
-        s += info.dictionary[c - info.DICT_BASE_DEC]
-        dict_expansion.append(len(info.dictionary[c - info.DICT_BASE_DEC]))
-    result.append((s, srcdata)) 
-    if len(result) >= 397 and lang == 'pt':
-      return result
-#    print(len(result), s)   
-#    if len(result) == 89:
-#      print(s)
-#      sys.exit(0)
-
-
-  
-def print_strings(rom, file = None):
-  texts = decode_strings_generic(rom.get_byte, rom.language)
-  if len(texts) == 396:
-    extra_str = "[Speed 00]0- [Number 00]. 1- [Number 01][2]2- [Number 02]. 3- [Number 03]"
-    texts = texts[:4] + [(extra_str, None)] + texts[4:]
-
-  for i, s in enumerate(texts):
-    print('%s: %s' % (i + 1, s[0]), file = file)
-
-
-def encode_greedy_from_dict(s, i, rev, a2i, info):
-  a = s[i:]
-  if r := rev.get(a[0]):
-    for k, v in r.items():
-      if a.startswith(k):
-        return [v + info.DICT_BASE_ENC], len(k)
-
-  if a[0] == '[':
-    cmd, param = a[1:a.index(']')], None
-    cmdlen = len(cmd)
-    if r := a2i.get(a[:cmdlen+2]):
-      return [r], cmdlen+2
-    if ' ' in cmd:
-      cmd, param = cmd.split(' ', 1)
-      param = int(param)
-    return kEncoders[info.encoder](cmd, param), cmdlen + 2
-  else:
-    return [a2i[a[0]]], 1
-
-  print('substr %s not found' % a)
-  assert 0
-
-def compress_strings(xs, lang = 'us'):
-  info = kLanguages[lang]
-  rev = {}
-  for a,b in enumerate(info.dictionary):
-    rev.setdefault(b[0], {})[b] = a
-  #rev = {b:a for a,b in enumerate(info.dictionary)}
-  a2i = {e:i for i,e in enumerate(info.alphabet)}
-  def compress_string(s):
-    i = 0
-    r = bytearray()
-    while i < len(s):
-      what, num = encode_greedy_from_dict(s, i, rev, a2i, info)
-      r.extend(what)
-      i += num
-    return r
-  return [compress_string(x) for x in xs]
-  
-def verify(get_byte):
-  for i, (decoded, original) in enumerate(decode_strings_generic(get_byte, 'us')):
-    c = compress_strings([decoded])[0]
-    if c != original:
-      print('String %s not match: %s, %s' % (decoded, c, original))
-      break
-    else:
-      pass
-
-def encode_dictionary(lang = 'us'):
-  info = kLanguages[lang]
-  rev = {b:a for a,b in enumerate(info.alphabet)}
-  return [bytearray(rev[c] for c in line) for line in info.dictionary]
-
-if __name__ == "__main__":
-  ROM = util.load_rom(sys.argv[1] if len(sys.argv) >= 2 else None, True)
-
-  decoded = decode_strings_generic(ROM.get_byte, 'de')
-  print('Total bytes: %d' % sum(len(a[1]) for a in decoded))
-
-  print('Dict tokens: %d' % len(dict_expansion))
-  print('Dict save: %d' % (sum(dict_expansion) - len(dict_expansion)))
-
-  print('US size ', len(kTextDictionary_US))
-  print('DE size ', len(kTextDictionary_DE))
-
-  texts = [a[0] for a in decoded]
-
-
-  # Pal seems to have one string too little
-  if len(texts) == 396:
-    extra_str = "[Speed 00]0- [Number 00]. 1- [Number 01][2]2- [Number 02]. 3- [Number 03]"
-    texts = texts[:4] + [extra_str] + texts[4:]
-
-  #for i, s in enumerate(texts):
-  #  print('%s: %s' % (i + 1, s), file = None)
-
-
-  #encode_dictionary()
-  compr = compress_strings(texts, 'de')
-  print(f'Compressed size (excl eof): {sum(len(a) for a in compr)}')
-
-
--- a/tables/util.py
+++ /dev/null
@@ -1,333 +1,0 @@
-import array
-import sys
-import hashlib
-import os
-from functools import lru_cache
-
-def cache(user_function):
-  'Simple lightweight unbounded cache.  Sometimes called "memoize".'
-  return lru_cache(maxsize=None)(user_function)
-
-# Both are common SNES rom extensions. For Zelda3 (NA), they are equivalent files.
-COMMON_ROM_NAMES = ['zelda3.sfc', 'zelda3.smc']
-DEFAULT_ROM_DIRECTORY = os.path.dirname(__file__)
-
-ZELDA3_SHA1_US = '6D4F10A8B10E10DBE624CB23CF03B88BB8252973'
-ZELDA3_SHA1 = {
-   ZELDA3_SHA1_US : ('us', 'Legend of Zelda, The - A Link to the Past (USA)'),
-  '2E62494967FB0AFDF5DA1635607F9641DF7C6559' : ('de', 'Legend of Zelda, The - A Link to the Past (Germany)'),
-  '229364A1B92A05167CD38609B1AA98F7041987CC' : ('fr', 'Legend of Zelda, The - A Link to the Past (France)'),
-  'C1C6C7F76FFF936C534FF11F87A54162FC0AA100' : ('fr-c', 'Legend of Zelda, The - A Link to the Past (Canada)'),
-  '7C073A222569B9B8E8CA5FCB5DFEC3B5E31DA895' : ('en',  'Legend of Zelda, The - A Link to the Past (Europe)'),
-  '461FCBD700D1332009C0E85A7A136E2A8E4B111E' : ('es',  'Spanish - https://www.romhacking.net/translations/2195/'),
-  '3C4D605EEFDA1D76F101965138F238476655B11D' : ('pl',  'Polish - https://www.romhacking.net/translations/5760/'),
-  'D0D09ED41F9C373FE6AFDCCAFBF0DA8C88D3D90D' : ('pt',  'Portuguese - https://www.romhacking.net/translations/6530/'),
-  'B2A07A59E64C498BC1B2F28728F9BF4014C8D582' : ('redux', 'English Redux - https://www.romhacking.net/translations/6657/'),
-  '9325C22EB0A2A1F0017157C8B620BC3A605CEDE1' : ('redux', 'English Redux - https://www.romhacking.net/hacks/2594/'),
-  'FA8ADFDBA2697C9A54D583A1284A22AC764C7637' : ('nl', 'Dutch - https://www.romhacking.net/translations/1124/'),
-  '43CD3438469B2C3FE879EA2F410B3EF3CB3F1CA4' : ('sv', 'Swedish - https://www.romhacking.net/translations/982/'),
-}
-
-def load_rom(filename, support_multilanguage = False):
-  global ROM
-  ROM = LoadedRom(filename, support_multilanguage)
-  return ROM
-
-def get_byte(addr):
-  return ROM.get_byte(addr)
-
-@cache
-def get_bytes(addr, n):
-  return ROM.get_bytes(addr, n)
-
-@cache
-def get_words(addr, n):
-  return ROM.get_words(addr, n)
-
-def get_int8(ea):
-  b = get_byte(ea)
-  if b & 0x80: b -= 256
-  return b
-
-def get_int16(ea):
-  b = get_word(ea)
-  if b & 0x8000: b -= 65536
-  return b
-
-def get_word(addr):
-  return ROM.get_word(addr)
-
-
-class LoadedRom:
-  def __init__(self, path = None, support_multilanguage = False):
-    rom_path = self.__get_rom_path(path)
-    self.ROM = open(rom_path, 'rb').read()
-
-    # Remove the SMC header?
-    if (len(self.ROM) & 0xfffff) == 0x200:
-      self.ROM = self.ROM[0x200:]
-
-    hash = hashlib.sha1(self.ROM).hexdigest().upper()
-    entry = ZELDA3_SHA1.get(hash)
-    self.language = entry[0] if entry != None else None
-
-    # Workaround for swedish rom with broken size
-    if self.language == 'sv' and len(self.ROM) == 0x10083b:
-      self.ROM = self.ROM[0x200:]
-
-    if support_multilanguage:
-      if self.language == None:
-        msg = f"\n\nROM with hash {hash} not supported.\n\nYou need one of the following ROMs to extract the resources:\n"
-        for k, v in ZELDA3_SHA1.items():
-          msg += '%5s: %s: %s\n' % (v[0], k, v[1])
-        raise Exception(msg)
-      print('Identified ROM as: %s - "%s"' % entry)
-    else:
-      if self.language != 'us':
-        raise Exception(f"\n\nROM with hash {hash} not supported.\n\nExpected {ZELDA3_SHA1_US}.\nPlease verify your ROM is \"Legend of Zelda, The - A Link to the Past (USA)\"");
-
-  def get_byte(self, ea):
-    assert (ea & 0x8000)
-    ea = ((ea >> 16) & 0x7f) * 0x8000 + (ea & 0x7fff)
-    return self.ROM[ea]
-
-  def get_word(self, ea):
-    return self.get_byte(ea) + self.get_byte(ea + 1) * 256
-
-  def get_24(self, ea):
-    return self.get_byte(ea) + self.get_byte(ea + 1) * 256 + self.get_byte(ea + 2) * 65536
-
-  def get_bytes(self, addr, n):
-    r = bytearray()
-    for i in range(n):
-      r.append(self.get_byte(addr))
-      addr += 1
-      if (addr & 0x8000) == 0:
-        addr += 0x8000
-    return r
-
-  def get_words(self, addr, n):
-    r = []
-    for i in range(n):
-      r.append(self.get_word(addr))
-      addr += 2
-      if (addr & 0x8000) == 0:
-        addr += 0x8000
-    return r
-
-  def __get_rom_path(self, path = None):
-    # Check default locations when no path is given by user.
-    if path is None:
-      for rom_name in COMMON_ROM_NAMES:
-        rom_path = os.path.join(DEFAULT_ROM_DIRECTORY, rom_name)
-        if os.path.isfile(rom_path):
-          return rom_path
-      raise Exception(f"Could not find any ROMs ({', '.join(COMMON_ROM_NAMES)}) at the default location {DEFAULT_ROM_DIRECTORY}.") 
-
-    rom_path = os.path.join(DEFAULT_ROM_DIRECTORY, path)
-    if os.path.isfile(rom_path):
-      return rom_path
-    raise Exception(f"No ROM found at provided path {rom_path}.")
-
-
-
-def split_list(l, n):
-  return [l[i:i+n] for i in range(0, len(l), n)]
-
-def to_hex(v):
-  return '%#x' % v if v < -9 or v >9 else '%d'%v
-
-
-def print_int_array(name, r, tname, decimal, split_length = 16, file = sys.stdout):
-  rlen = len(r)
-  rr = split_list(r, split_length )
-  if decimal != None:
-    if decimal:
-      rr = [['%d' % s for s in t] for t in rr]
-    else:
-      rr = [[to_hex(s) for s in t] for t in rr]
-
-  def pad_all_columns(rrs):
-    colsiz = [max((0 if j >= len(r) else len(r[j])) for r in rrs) for j in range(len(rrs[0]))]
-    def pad(c, i):
-      return (' ' * (i - len(c))) + c
-    return [[pad(c, colsiz[i]) for (i, c) in enumerate(r)] for r in rrs]
-
-  if len(rr) == 1:
-    print('static const %s %s[%d] = {%s};' % (tname, name, rlen, ", ".join(rr[0])), file = file)
-  else:
-    print('static const %s %s[%d] = {' % (tname, name, rlen), file = file)
-    for t in pad_all_columns(rr):
-      print("  " + "".join([(a + ', ') for a in t]), file = file)
-    print('};', file = file)
-
-
-
-class Reader:
-  def __init__(self, ea, rb):
-    self.ea, self.rb = ea, rb
-  def next(self):
-    r = self.rb(self.ea)
-    self.ea += 1
-    if (self.ea & 0xffff) == 0:
-      self.ea += 0x8000
-    return r
-
-def decomp(ea, rb, offset_is_be = True, return_length = False):
-  result = bytearray()
-  reader = Reader(ea, rb)
-  while True:
-    b = reader.next()
-    if b == 0xff:
-      if return_length:
-        return result, (reader.ea - ea) & 0x7fff
-      else:
-        return result
-    if (b & 0xe0) != 0xe0:
-      lx = b & 0x1f
-      cmd = b & 0xe0
-    else:
-      cmd = (b << 3) & 0xe0
-      lx = ((b & 3) << 8) | reader.next()
-    lx += 1
-    if cmd == 0x00: # 000 - literal
-#      print('literal %d' % lx)
-      while lx:
-        result.append(reader.next())
-        lx -= 1
-    elif cmd & 0x80: # 1xx - copy
-#      print('copy %d' % lx)
-      offs = reader.next() << 8
-      offs |= reader.next()
-      if not offset_is_be: offs = ((offs >> 8) | (offs << 8)) & 0xffff
-      while lx:
-        result.append(result[offs])
-        offs += 1
-        lx -= 1
-    elif (cmd & 0x40) == 0: # 00x - memset
-#      print('memset %d' % lx)
-      b = reader.next()
-      while lx:
-        result.append(b)
-        lx -= 1
-    elif (cmd & 0x20) == 0: # 010 - memset16
-#      print('memsetw %d' % lx)
-      b1, b2 = reader.next(), reader.next()
-      while lx:
-        result.append(b1)
-        if lx==1: break
-        result.append(b2)
-        lx -= 2
-    else: # 011 - incr
-#      print('incr %d' % lx)
-      b = reader.next()
-      while lx:
-        result.append(b)
-        b = (b + 1) & 0xff
-        lx -= 1
-
-
-def decode_brr(get_byte, olds = (0, 0)):
-  ea=0
-  r = []
-  old , older = olds
-  while True:
-    cmd = get_byte(ea)
-    
-    shift = cmd >> 4
-    filter = (cmd >> 2) & 3
-    #print("shift=%d, filter=%d" % (shift, filter))
-    for i in range(16):
-      t = (get_byte(ea+1+i//2) >> (0 if i & 1 else 4)) & 0xf
-      s = (t & 7) - (t & 8)
-      if shift <= 12:
-        s = ((s << shift) >> 1)
-      else:
-        s = (s >> 3) << 12 # -2048 or 0
-
-      if filter == 1:
-        s += old*1+((-old*1) >> 4)
-      elif filter == 2:
-        s += old*2 + ((-old*3) >> 5)  - older + ((older*1) >> 4)
-      elif filter == 3:
-        s += old*2 + ((-old*13) >> 6) - older + ((older*3) >> 4)
-      # saturate to 16 bits
-      if s < -0x8000: s = -0x8000
-      elif s >= 0x7fff: s = 0x7fff
-      # wrap to 15 bits
-      s = (s & 0x3fff) - (s & 0x4000)
-
-      older, old = old, s
-      #print('%d: 0x%x -> %d (shift %d, filter %d)' % (i, t, s*2, shift, filter))
-      r.append(s*2)
-    ea += 9
-    if cmd & 1:
-      break
-  return array.array('h', r)
-
-kBrrFilters = [
-  lambda old, older: 0,
-  lambda old, older: old*1+((-old*1) >> 4),
-  lambda old, older: old*2 + ((-old*3) >> 5)  - older + ((older*1) >> 4),
-  lambda old, older: old*2 + ((-old*13) >> 6) - older + ((older*3) >> 4)
-]
-
-def brr_get_one(old, rs, r):
-  s = (rs << r) >> 1 if r <= 12 else (rs >> 3) << 12
-  s += old
-  s = -0x8000 if s < -0x8000 else 0x7fff if s > 0x7fff else s
-  return (s & 0x3fff) - (s & 0x4000) # wrap to 15 bits
-
-def encode_brr_generic(data, brr_repeat, olds = (0, 0), lossless=True):  
-  assert len(data) % 16 == 0
-  loop_enabled, loop_offset = 1 if brr_repeat != 0 else 0, 0
-  result = []
-  blk_data = [0] * 16
-  best_data = [0] * 9
-  p = 0
-  best_old, best_older = olds
-  while p < len(data):
-#    print(p)
-    best_err = 1 << 60
-    startold, startolder = best_old, best_older
-
-    if all(data[p + i] == 0 for i in range(16)):
-      result.extend((loop_enabled * 2, 0, 0, 0, 0, 0, 0, 0, 0))
-      p += 16
-      continue
-    for filter in range(4):
-      if filter != 0 and (p == 0 or p == loop_offset):
-        continue
-      for r in range(12, 0, -1):
-        blk_err = 0
-        old, older = startold, startolder
-        for i in range(16):
-          s = kBrrFilters[filter](old, older)
-          xs = data[p + i] >> 1 
-          best_e = 1<<60
-          for j in (0, 1, -1, 2, -2, 3, -3, 4, -4, 5, -5, 6, -6, 7, -7, -8):
-            s0 = brr_get_one(s, j, r)
-            e = (xs - s0) * (xs - s0)
-            if e < best_e:
-              best_e, best_j, best_s0 = e, j, s0
-              if e == 0:
-                #print(j)
-                break
-          if best_e != 0 and lossless:
-            break
-          blk_err += best_e
-          blk_data[i] = best_j & 0xf
-          older, old = old, best_s0
-        else:
-          if blk_err < best_err:
-            best_err = blk_err
-            best_old, best_older = old, older
-            best_data[0] = r << 4 | filter << 2 | loop_enabled << 1
-            for i in range(8):
-              best_data[i + 1] = blk_data[i * 2] << 4 | blk_data[i * 2 + 1]
-    result.extend(best_data)
-    if lossless: assert best_err==0
-    p += 16
-#  result[-9] |= 1
-  return result
-
--- a/tagalong.c
+++ /dev/null
@@ -1,756 +1,0 @@
-#include "tagalong.h"
-#include "sprite_main.h"
-#include "sprite.h"
-#include "zelda_rtl.h"
-#include "variables.h"
-#include "snes/snes_regs.h"
-#include "dungeon.h"
-#include "overworld.h"
-#include "ancilla.h"
-#include "player.h"
-#include "misc.h"
-
-static const uint8 kTagalongFlags[4] = {0x20, 0x10, 0x30, 0x20};
-static const uint8 kTagalong_Tab5[15] = {0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
-static const uint8 kTagalong_Tab4[15] = {0, 0, 3, 3, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
-static const uint8 kTagalong_Tab0[3] = {5, 9, 0xa};
-static const uint16 kTagalong_Tab1[3] = {0xdf3, 0x6f9, 0xdf3};
-static const uint16 kTagalong_Msg[3] = {0x20, 0x108, 0x11d};
-static const TagalongMessageInfo kTagalong_IndoorInfos[12] = {
-  {0x1ef0, 0x288, 1, 0x99, 4},
-  {0x1e58, 0x2f0, 2, 0x9a, 4},
-  {0x1ea8, 0x3b8, 4, 0x9b, 4},
-  {0xcf8, 0x25b, 1, 0x21, 1},
-  {0xcf8, 0x39d, 2, 0x21, 1},
-  {0xc78, 0x238, 4, 0x21, 1},
-  {0xa30, 0x2f8, 1, 0x22, 1},
-  {0x178, 0x550, 1, 0x23, 1},
-  {0x168, 0x4f8, 2, 0x2a, 1},
-  {0x1bd8, 0x16fc, 1, 0x124, 6},
-  {0x1520, 0x167c, 1, 0x124, 6},
-  {0x5ac, 0x4fc, 1, 0x29, 1},
-};
-static const TagalongMessageInfo kTagalong_OutdoorInfos[5] = {
-  {0x3c0, 0x730, 1, 0x9d, 4},
-  {0x648, 0xf50, 0, 0xffff, 0xa},
-  {0x6c8, 0xd78, 1, 0xffff, 0xa},
-  {0x688, 0xc78, 2, 0xffff, 0xa},
-  {0xe8, 0x90, 0, 0x28, 0xe},
-};
-static const uint8 kTagalong_IndoorOffsets[8] = {0, 3, 6, 7, 9, 10, 11, 12};
-static const uint8 kTagalong_OutdoorOffsets[4] = {0, 1, 4, 5};
-static const uint16 kTagalong_IndoorRooms[7] = {0xf1, 0x61, 0x51, 2, 0xdb, 0xab, 0x22};
-static const uint16 kTagalong_OutdoorRooms[3] = {3, 0x5e, 0};
-typedef struct TagalongSprXY {
-  int8 y1, x1, y2, x2;
-} TagalongSprXY;
-typedef struct TagalongDmaFlags {
-  uint8 dma6, dma7;
-  uint8 flags;
-} TagalongDmaFlags;
-static const TagalongSprXY kTagalongDraw_SprXY[56] = {
-  {-2, 0, 0, 0},
-  {-2, 0, 0, 0},
-  {-2, 0, 0, 0},
-  {-2, 0, 0, 0},
-  {-1, 0, 1, 0},
-  {-1, 0, 1, 0},
-  {-1, 0, 1, 0},
-  {-1, 0, 1, 0},
-  {0, 0, 0, 0},
-  {0, 0, 0, 0},
-  {0, 0, 0, 0},
-  {0, 0, 0, 0},
-  {1, 0, 0, 0},
-  {1, 0, 0, 0},
-  {1, 0, 0, 0},
-  {1, 0, 0, 0},
-  {0, 0, 0, 0},
-  {0, 0, 0, 0},
-  {0, -3, 0, 0},
-  {0, 3, 0, 0},
-  {1, 0, 0, 0},
-  {1, 0, 0, 0},
-  {1, -3, 1, 0},
-  {1, 3, 1, 0},
-  {0, 0, 0, 0},
-  {0, 0, 0, 0},
-  {0, 0, 0, 0},
-  {0, 0, 0, 0},
-  {0, 0, 1, 0},
-  {0, 0, 1, 0},
-  {0, 0, 1, 0},
-  {0, 0, 1, 0},
-  {-1, 0, 0, 0},
-  {-1, 0, 0, 0},
-  {-1, 0, 0, 0},
-  {-1, 0, 0, 0},
-  {0, 0, 1, 0},
-  {0, 0, 1, 0},
-  {0, 0, 1, 0},
-  {0, 0, 1, 0},
-  {0, 0, 0, 0},
-  {0, 0, 0, 0},
-  {0, 0, 0, 0},
-  {0, 0, 0, 0},
-  {0, 0, 0, 0},
-  {0, 0, 0, 0},
-  {0, 0, 0, 0},
-  {0, 0, 0, 0},
-  {2, 0, 0, 0},
-  {2, 0, 0, 0},
-  {2, -1, 0, 0},
-  {2, 1, 0, 0},
-  {3, 0, 1, 0},
-  {3, 0, 1, 0},
-  {3, -1, 1, 0},
-  {3, 1, 1, 0},
-};
-static const TagalongDmaFlags kTagalongDmaAndFlags[16] = {
-  {0x20, 0xc0, 0x00},
-  {0x00, 0xa0, 0x00},
-  {0x40, 0x60, 0x00},
-  {0x40, 0x60, 0x44},
-  {0x20, 0xc0, 0x04},
-  {0x00, 0xa0, 0x04},
-  {0x40, 0x80, 0x00},
-  {0x40, 0x80, 0x44},
-  {0x20, 0xe0, 0x00},
-  {0x00, 0xe0, 0x00},
-  {0x40, 0xe0, 0x00},
-  {0x40, 0xe0, 0x44},
-  {0x20, 0xe0, 0x04},
-  {0x00, 0xe0, 0x04},
-  {0x40, 0xe0, 0x04},
-  {0x40, 0xe0, 0x40},
-};
-static const uint8 kTagalongDraw_Pals[14] = {0, 4, 4, 4, 4, 0, 7, 4, 4, 3, 4, 4, 4, 4};
-static const uint16 kTagalongDraw_Offs[14] = {0, 0, 0x80, 0x80, 0x80, 0, 0, 0xc0, 0xc0, 0x100, 0x180, 0x180, 0x140, 0x140};
-static const uint8 kTagalongDraw_SprInfo0[24] = {
-  0xd8, 0x24, 0xd8, 0x64, 0xd9, 0x24, 0xd9, 0x64, 0xda, 0x24, 0xda, 0x64, 0xc8, 0x22, 0xc8, 0x62,
-  0xc9, 0x22, 0xc9, 0x62, 0xca, 0x22, 0xca, 0x62,
-};
-static const uint16 kTagalongDraw_SprOffs0[2] = {0x170, 0xc0};
-static const uint16 kTagalongDraw_SprOffs1[2] = {0x1c0, 0x110};
-bool Tagalong_IsFollowing() {
-  uint8 main = main_module_index;
-  uint8 sub = submodule_index;
-  return !flag_is_link_immobilized && sub != 10 && !(main == 9 && sub == 0x23) && !(main == 14 && (sub == 1 || sub == 2));
-}
-
-bool Follower_ValidateMessageFreedom() {  // 87f46f
-  uint8 ps = link_player_handler_state;
-  if (ps != kPlayerState_Ground && ps != kPlayerState_Swimming && ps != kPlayerState_StartDash)
-    return false;
-  uint8 t = button_mask_b_y & 0x80 | link_unk_master_sword | link_item_in_hand |
-            link_position_mode | flag_is_ancilla_to_pick_up | flag_is_sprite_to_pick_up |
-            link_state_bits | link_grabbing_wall;
-  return t == 0;
-}
-
-void Follower_MoveTowardsLink() {  // 88f91a
-  for(;;) {
-    int k = 9;
-    int j = tagalong_var1;
-    ancilla_y_lo[k] = tagalong_y_lo[j];
-    ancilla_y_hi[k] = tagalong_y_hi[j];
-    ancilla_x_lo[k] = tagalong_x_lo[j];
-    ancilla_x_hi[k] = tagalong_x_hi[j];
-
-    ProjectSpeedRet pt = Ancilla_ProjectSpeedTowardsPlayer(k, 24);
-    ancilla_x_vel[k] = pt.x;
-    ancilla_y_vel[k] = pt.y;
-    Ancilla_MoveY(k);
-    Ancilla_MoveX(k);
-
-    uint16 x = Ancilla_GetX(k);
-    uint16 y = Ancilla_GetY(k);
-    if (abs16(x - link_x_coord) < 2 && abs16(y - link_y_coord) < 2)
-      return;
-    k = ++tagalong_var1;
-    if (k == 18)
-      return;
-    tagalong_y_lo[k] = y;
-    tagalong_y_hi[k] = y >> 8;
-    tagalong_x_lo[k] = x;
-    tagalong_x_hi[k] = x >> 8;
-    static const uint8 kTagalongLayerBits[4] = {0x20, 0x10, 0x30, 0x20};
-    tagalong_layerbits[k] = kTagalongLayerBits[link_is_on_lower_level] >> 2 | 1;
-  }
-}
-
-bool Follower_CheckBlindTrigger() {  // 899e90
-  int k = tagalong_var2;
-  uint16 x = tagalong_x_hi[k] << 8 | tagalong_x_lo[k];
-  uint16 y = tagalong_y_hi[k] << 8 | tagalong_y_lo[k];
-  uint16 z = (int8)tagalong_z[k];
-  y += z + 12;
-  x += 8;
-  return abs16(0x1568 - y) < 24 && abs16(0x1980 - x) < 24;
-}
-
-void Follower_Initialize() {  // 899efc
-  tagalong_y_lo[0] = link_y_coord;
-  tagalong_y_hi[0] = link_y_coord >> 8;
-
-  tagalong_x_lo[0] = link_x_coord;
-  tagalong_x_hi[0] = link_x_coord >> 8;
-
-  tagalong_layerbits[0] = kTagalongFlags[link_is_on_lower_level] >> 2 | (link_direction_facing >> 1);
-  timer_tagalong_reacquire = 64;
-  tagalong_var2 = 0;
-  tagalong_var1 = 0;
-  tagalong_var3 = 0;
-  tagalong_var4 = 0;
-  link_speed_setting = 0;
-
-  if (enhanced_features0 & kFeatures0_TurnWhileDashing) {
-    link_player_handler_state = kPlayerState_Ground;
-    link_is_running = false;
-  }
-
-}
-
-void Sprite_BecomeFollower(int k) {  // 899f39
-  tagalong_var5 = 0;
-  int y = Sprite_GetY(k) - 6;
-  tagalong_y_lo[0] = y, tagalong_y_hi[0] = (y >> 8);
-  int x = Sprite_GetX(k) + 1;
-  tagalong_x_lo[0] = x, tagalong_x_hi[0] = (x >> 8);
-  tagalong_layerbits[0] = kTagalongFlags[link_is_on_lower_level] >> 2 | 1;
-  timer_tagalong_reacquire = 64;
-  tagalong_var1 = 0;
-  tagalong_var2 = 0;
-  tagalong_var3 = 0;
-  tagalong_var4 = 0;
-  link_speed_setting = 0;
-  tagalong_var5 = 0;
-  follower_dropped = 0;
-  Follower_MoveTowardsLink();
-}
-
-void Follower_Main() {  // 899fc4
-  if (!follower_indicator)
-    return;
-  if (follower_indicator == 0xe) {
-    Follower_HandleTrigger();
-    return;
-  }
-  int j = FindInByteArray(kTagalong_Tab0, follower_indicator, 3);
-  if (j >= 0 && submodule_index == 0 && !(j == 2 && overworld_screen_index & 0x40) && sign16(--word_7E02CD)) {
-    if (!Follower_ValidateMessageFreedom()) {
-      word_7E02CD = 0;
-    } else {
-      word_7E02CD = kTagalong_Tab1[j];
-      dialogue_message_index = kTagalong_Msg[j];
-      Main_ShowTextMessage();
-    }
-  }
-  if (j != 0)
-    Follower_NoTimedMessage();
-}
-
-void Follower_NoTimedMessage() {  // 89a02b
-  int k;
-
-  if (follower_dropped) {
-    Follower_NotFollowing();
-    return;
-  }
-
-  if (follower_indicator == 12) {
-    if (link_auxiliary_state != 0)
-      goto label_a;
-
-  } else if (follower_indicator == 13) {
-    if (link_auxiliary_state == 2 || player_near_pit_state == 2)
-      goto label_c;
-  } else {
-    goto label_a;
-  }
-
-  if (submodule_index != 0 || link_auxiliary_state == 1 || (link_state_bits & 0x80) || tagalong_var5 || tagalong_var3 ||
-    (int8)tagalong_z[tagalong_var2] > 0 || !(filtered_joypad_L & 0x80))
-    goto label_a;
-
-label_c:
-
-  if (follower_indicator == 13 && !player_is_indoors) {
-    if (link_player_handler_state == kPlayerState_Ether ||
-        link_player_handler_state == kPlayerState_Bombos ||
-        link_player_handler_state == kPlayerState_Quake)
-      goto label_a;
-    super_bomb_indicator_unk2 = 3;
-    super_bomb_indicator_unk1 = 0xbb;
-  }
-
-  follower_dropped = 128;
-  timer_tagalong_reacquire = 64;
-
-  k = tagalong_var2;
-  saved_tagalong_y = tagalong_y_lo[k] | tagalong_y_hi[k] << 8;
-  saved_tagalong_x = tagalong_x_lo[k] | tagalong_x_hi[k] << 8;
-  saved_tagalong_floor = link_is_on_lower_level;
-  saved_tagalong_indoors = player_is_indoors;
-  Follower_NotFollowing();
-  return;
-
-label_a:
-  Follower_CheckGameMode();
-}
-
-void Follower_CheckGameMode() {  // 89a0e1
-  if (Tagalong_IsFollowing() && (link_x_vel | link_y_vel)) {
-    int k = tagalong_var1 + 1;
-    if (k == 20)
-      k = 0;
-    tagalong_var1 = k;
-    uint8 z = link_z_coord;
-    if (z >= 0xf0)
-      z = 0;
-    tagalong_z[k] = z;
-    uint16 y = link_y_coord - z;
-    tagalong_y_lo[k] = y;
-    tagalong_y_hi[k] = y >> 8;
-    uint16 x = link_x_coord;
-    tagalong_x_lo[k] = x;
-    tagalong_x_hi[k] = x >> 8;
-    uint8 layerbits = link_direction_facing >> 1 | kTagalongFlags[link_is_on_lower_level] >> 2;
-    if (link_player_handler_state == kPlayerState_Swimming) {
-      layerbits |= 0x20;
-    } else {
-      if (link_player_handler_state == kPlayerState_Hookshot && related_to_hookshot)
-        layerbits |= 0x10;
-      if (draw_water_ripples_or_grass)
-        layerbits |= (draw_water_ripples_or_grass == 1) ? 0x80 : 0x40;
-    }
-    tagalong_layerbits[k] = layerbits;
-  }
-
-  switch (follower_indicator) {
-  case 2: case 4:
-    Follower_OldMan();
-    return;
-  case 3: case 11:
-    Follower_OldManUnused();
-    return;
-  case 5: case 14:
-    assert(0); // Y is unknown here...
-    return;
-  default:
-    Follower_BasicMover();
-    return;
-  }
-}
-
-void Follower_BasicMover() {  // 89a197
-  int k;
-  if (!Tagalong_IsFollowing()) {
-    Tagalong_Draw();
-    return;
-  }
-
-  Follower_HandleTrigger();
-
-  if (follower_indicator == 10 && link_auxiliary_state && countdown_for_blink) {
-    int k = tagalong_var2 + 1 == 20 ? 0 : tagalong_var2 + 1;
-    Kiki_SpawnHandler_B(k);
-    follower_indicator = 0;
-    return;
-  }
-
-  if (follower_indicator == 6 && dungeon_room_index == 0xac && (save_dung_info[101] & 0x100) && Follower_CheckBlindTrigger()) {
-    int k = tagalong_var2;
-    uint16 x = tagalong_x_lo[k] | tagalong_x_hi[k] << 8;
-    uint16 y = tagalong_y_lo[k] | tagalong_y_hi[k] << 8;
-    follower_indicator = 0;
-    Blind_SpawnFromMaiden(x, y);
-    BYTE(dung_flag_trapdoors_down)++;
-    BYTE(dung_cur_door_pos) = 0;
-    BYTE(door_animation_step_indicator) = 0;
-    submodule_index = 5;
-    music_control = 21;
-    return;
-  }
-
-  if (!tagalong_var3) {
-    if (link_player_handler_state == kPlayerState_Hookshot && related_to_hookshot) {
-      tagalong_var3 = 1;
-      goto label_e;
-    }
-  } else {
-    if (link_player_handler_state == kPlayerState_Hookshot)
-      goto label_e;
-    if (tagalong_var7 != tagalong_var2)
-      goto label_d;
-    tagalong_var3 = 0;
-  }
-
-  k = tagalong_var2;
-  if ((int8)tagalong_z[k] > 0) {
-    if (tagalong_var1 != k)
-      goto label_d;
-    tagalong_z[k] = 0;
-    uint16 y = link_y_coord, x = link_x_coord;
-    tagalong_y_lo[k] = y;
-    tagalong_y_hi[k] = y >> 8;
-    tagalong_x_lo[k] = x;
-    tagalong_x_hi[k] = x >> 8;
-  }
-
-  if (link_x_vel | link_y_vel) {
-    uint8 t;
-label_e:
-    t = tagalong_var1 - 15;
-    if (sign8(t))
-      t += 20;
-    if (t == tagalong_var2) {
-label_d:
-      tagalong_var2 = (tagalong_var2 + 1 == 20) ? 0 : tagalong_var2 + 1;
-    }
-  }
-  Tagalong_Draw();
-}
-
-void Follower_NotFollowing() {  // 89a2b2
-  if (saved_tagalong_indoors != player_is_indoors)
-    return;
-  if (!link_is_running && !Follower_CheckProximityToLink()) {
-    Follower_Initialize();
-    saved_tagalong_indoors = player_is_indoors;
-    if (follower_indicator == 13) {
-      super_bomb_indicator_unk2 = 254;
-      super_bomb_indicator_unk1 = 0;
-    }
-    follower_dropped = 0;
-    Tagalong_Draw();
-  } else {
-    if (follower_indicator == 13 && !player_is_indoors && !super_bomb_indicator_unk2) {
-      // Fixed so we wait a little bit if we can't spawn the ancilla
-      if (AncillaAdd_SuperBombExplosion(0x3a, 0) >= 0) {
-        follower_dropped = 0;
-
-        // A ticking super bomb will cancel and teleport back to you as a follower if you do
-        // any of these at count 0: (1) change screen via walking, mirror, or bird travel
-        // (2) fill all ancillary slots
-        // (3) die with a bottled faerie.
-        // Fixed this by clearing the follower indicator here, instead of in the ancilla
-        // bomb code.
-        if (enhanced_features0 & kFeatures0_MiscBugFixes) {
-          follower_indicator = 0;
-          return;
-        }
-      } else {
-        super_bomb_indicator_unk1 = 1;
-      }
-    }
-    Follower_DoLayers();
-  }
-}
-
-void Follower_OldMan() {  // 89a318
-  uint8 t;
-
-  if (!Tagalong_IsFollowing()) {
-    Tagalong_Draw();
-    return;
-  }
-
-  if (link_speed_setting != 4)
-    link_speed_setting = 12;
-
-  Follower_HandleTrigger();
-
-  if (follower_indicator == 0) {
-    return;
-  } else if (follower_indicator == 4) {
-    if ((int8)tagalong_z[tagalong_var2] > 0 && tagalong_var1 != tagalong_var2) {
-      tagalong_var2 = (tagalong_var2 + 1 >= 20) ? 0 : tagalong_var2 + 1;
-      Tagalong_Draw();
-      return;
-    }
-  } else {
-    // tagalong type 2
-    if ((link_auxiliary_state & 1) && link_player_handler_state == kPlayerState_RecoilOther) {
-      if (tagalong_var1 != tagalong_var2)
-        goto transform;
-      assert(0); // X is undefined here
-    }
-
-    if (link_auxiliary_state & 2) {
-transform:
-      follower_indicator = kTagalong_Tab4[follower_indicator];
-      timer_tagalong_reacquire = 64;
-      int k = tagalong_var2;
-      saved_tagalong_y = tagalong_y_lo[k] | tagalong_y_hi[k] << 8;
-      saved_tagalong_x = tagalong_x_lo[k] | tagalong_x_hi[k] << 8;
-      saved_tagalong_floor = link_is_on_lower_level;
-      Follower_OldManUnused();
-      return;
-    }
-  }
-
-  if (link_x_vel | link_y_vel) {
-    t = tagalong_var1 - 20;
-    if (sign8(t))
-      t += 20;
-    if (t == tagalong_var2) {
-      tagalong_var2 = (tagalong_var2 + 1 >= 20) ? 0 : tagalong_var2 + 1;
-    }
-  } else if ((frame_counter & 3) == 0 && tagalong_var1 != tagalong_var2) {
-    t = tagalong_var1 - 9;
-    if (sign8(t))
-      t += 20;
-    if (t != tagalong_var2) {
-      tagalong_var2 = (tagalong_var2 + 1 >= 20) ? 0 : tagalong_var2 + 1;
-    }
-  }
-  Tagalong_Draw();
-}
-
-void Follower_OldManUnused() {  // 89a41f
-  link_speed_setting = 16;
-  if (!link_is_running && !link_auxiliary_state && link_player_handler_state != kPlayerState_Swimming) {
-    link_speed_setting = 0;
-    if (link_player_handler_state != kPlayerState_Hookshot && !Follower_CheckProximityToLink()) {
-      Follower_Initialize();
-      follower_indicator = kTagalong_Tab5[follower_indicator];
-      return;
-    }
-  }
-  Follower_DoLayers();
-}
-
-void Follower_DoLayers() {  // 89a450
-  oam_priority_value = kTagalongFlags[saved_tagalong_floor] << 8;
-  uint8 a = (follower_indicator == 12 || follower_indicator == 13) ? 2 : 1;
-  Follower_AnimateMovement_preserved(a, saved_tagalong_x, saved_tagalong_y);
-}
-
-bool Follower_CheckProximityToLink() {  // 89a48e
-  if (!sign8(--timer_tagalong_reacquire))
-    return true;
-  timer_tagalong_reacquire = 0;
-  if ((uint16)(saved_tagalong_y - 1) >= link_y_coord ||
-      (uint16)(saved_tagalong_y + 19) < link_y_coord ||
-      (uint16)(saved_tagalong_x - 1) >= link_x_coord ||
-      (uint16)(saved_tagalong_x + 19) < link_x_coord)
-    return true;
-  return false;
-}
-
-void Follower_HandleTrigger() {  // 89a59e
-  if (submodule_index)
-    return;
-
-  const TagalongMessageInfo *tmi, *tmi_end;
-  if (player_is_indoors) {
-    int j = FindInWordArray(kTagalong_IndoorRooms, dungeon_room_index, 7);
-    if (j < 0)
-      return;
-    tmi = kTagalong_IndoorInfos + kTagalong_IndoorOffsets[j];
-    tmi_end = kTagalong_IndoorInfos + kTagalong_IndoorOffsets[j + 1];
-  } else {
-    int j = FindInWordArray(kTagalong_OutdoorRooms, overworld_screen_index, 3);
-    if (j < 0)
-      return;
-    tmi = kTagalong_OutdoorInfos + kTagalong_OutdoorOffsets[j];
-    tmi_end = kTagalong_OutdoorInfos + kTagalong_OutdoorOffsets[j + 1];
-  }
-  int st = (tagalong_var2 + 1 >= 20) ? 0 : tagalong_var2 + 1;
-  do {
-    if (tmi->tagalong == follower_indicator && Follower_CheckForTrigger(tmi)) {
-      if (tmi->bit & tagalong_event_flags)
-        return;
-      tagalong_event_flags |= tmi->bit;
-      dialogue_message_index = tmi->msg;
-      if (tmi->msg == 0xffff) {
-        if (!(tmi->bit & 3))
-          Kiki_RevertToSprite(st);
-        else if (!(save_ow_event_info[BYTE(overworld_screen_index)] & 1))
-          Kiki_SpawnHandler_A(st);
-        return;
-      }
-      if (tmi->msg == 0x9d) {
-        OldMan_RevertToSprite(st);
-      } else if (tmi->msg == 0x28) {
-        follower_indicator = 0;
-      }
-      Main_ShowTextMessage();
-      return;
-    }
-  } while (++tmi != tmi_end);
-}
-
-void Tagalong_Draw() {  // 89a907
-  if (tagalong_var5)
-    return;
-  oam_priority_value =
-    ((tagalong_z[tagalong_var2] && !player_is_indoors) ? 0x20 :
-    (submodule_index == 14) ? kTagalongFlags[link_is_on_lower_level] :
-                              (tagalong_layerbits[tagalong_var2] & 0xc) << 2) << 8;
-  int k = tagalong_var2;
-  if (sign8(k))
-    k = 0;
-  uint16 x = tagalong_x_lo[k] | tagalong_x_hi[k] << 8;
-  uint16 y = tagalong_y_lo[k] | tagalong_y_hi[k] << 8;
-  uint8 a = tagalong_layerbits[k];
-  Follower_AnimateMovement_preserved(a, x, y);
-}
-
-static inline void SetOam_Follower(OamEnt *oam, uint16 x, uint16 y, uint8 charnum, uint8 flags, uint8 big) {
-  oam->x = x;
-  oam->y = (uint16)(x + 0x80) < 0x180 && (big |= x >> 8 & 1, (uint16)(y + 0x10) < 0x100) ? y : 0xf0;
-  oam->charnum = charnum;
-  oam->flags = flags;
-  bytewise_extended_oam[oam - oam_buf] = big;
-}
-
-
-void Follower_AnimateMovement_preserved(uint8 ain, uint16 xin, uint16 yin) {  // 89a959
-
-  uint8 yt = 0, av = 0;
-  uint8 sc = 0;
-
-  if ((ain >> 2 & 8) && (follower_indicator == 6 || follower_indicator == 1)) {
-    yt = 8;
-    if (swimcoll_var7[0] | swimcoll_var7[1])
-      av = (frame_counter >> 1) & 4;
-    else
-      av = (frame_counter >> 2) & 4;
-  } else if (submodule_index == 8 || submodule_index == 14 || submodule_index == 16) {
-    av = link_is_running ? (frame_counter & 4) : ((frame_counter >> 1) & 4);
-  } else if (follower_indicator == 11) {
-    av = (frame_counter >> 1) & 4;
-  } else if ((follower_indicator == 12 || follower_indicator == 13) && follower_dropped || flag_is_link_immobilized ||
-             submodule_index == 10 || main_module_index == 9 && submodule_index == 0x23 ||
-             main_module_index == 14 && (submodule_index == 1 || submodule_index == 2) ||
-             (link_y_vel | link_x_vel) == 0) {
-    av = sc = 4;
-  } else {
-    av = link_is_running ? (frame_counter & 4) : ((frame_counter >> 1) & 4);
-  }
-  uint8 frame = (ain & 3) + av + yt;
-
-  int spr_offs =
-    (link_y_coord == yin && !(ain & 3) || link_y_coord < yin) ?
-      kTagalongDraw_SprOffs0[sort_sprites_setting] >> 2:
-      kTagalongDraw_SprOffs1[sort_sprites_setting] >> 2;
-  oam_ext_cur_ptr = 0xa20 + spr_offs;
-  oam_cur_ptr = 0x800 + spr_offs * 4;
-
-  OamEnt *oam = GetOamCurPtr();
-  uint16 scrolly = yin - BG2VOFS_copy2;
-  uint16 scrollx = xin - BG2HOFS_copy2;
-
-  const uint8 *sk = kTagalongDraw_SprInfo0;
-  if (follower_indicator == 1 || follower_indicator == 6 || !(ain & 0x20)) {
-    if (!(ain & 0xc0))
-      goto skip_first_sprites;
-    if ((ain & 0x80) || (sk += 12, sc == 0))
-      goto incr;
-    byte_7E02D7 = 0;
-  } else {
-incr:
-    if (!(frame_counter & 7) && ++byte_7E02D7 == 3)
-      byte_7E02D7 = 0;
-  }
-  sk += byte_7E02D7 * 4;
-  SetOam_Follower(oam + 0, scrollx, scrolly + 16, sk[0], sk[1], 0);
-  SetOam_Follower(oam + 1, scrollx + 8, scrolly + 16, sk[2], sk[3], 0);
-  oam += 2;
- uint8 pal;
-skip_first_sprites:
-  pal = kTagalongDraw_Pals[follower_indicator];
-  if (pal == 7 && palette_swap_flag)
-    pal = 0;
-
-  if (follower_indicator == 13) {
-    // Display colorful superbomb palette also on frame 0.
-    if (enhanced_features0 & kFeatures0_MiscBugFixes ? (super_bomb_indicator_unk2 <= 1) : (super_bomb_indicator_unk2 == 1))
-     pal = (frame_counter & 7);
-  }
-
-  const TagalongSprXY *sprd = kTagalongDraw_SprXY + frame + (kTagalongDraw_Offs[follower_indicator] >> 3);
-  const TagalongDmaFlags *sprf = kTagalongDmaAndFlags + frame;
-
-  if (follower_indicator != 12 && follower_indicator != 13) {
-    SetOam_Follower(oam, scrollx + sprd->x1, scrolly + sprd->y1, 0x20, 
-                  (sprf->flags & 0xf0) | pal << 1 | (oam_priority_value >> 8), 2);
-    oam++;
-    BYTE(dma_var6) = sprf->dma6;
-  }
-  {
-    SetOam_Follower(oam, scrollx + sprd->x2, scrolly + sprd->y2 + 8, 0x22,
-                  ((sprf->flags & 0xf) << 4) | pal << 1 | (oam_priority_value >> 8), 2);
-    BYTE(dma_var7) = sprf->dma7;
-  }
-}
-
-bool Follower_CheckForTrigger(const TagalongMessageInfo *info) {  // 89ac26
-  uint16 x = link_x_coord + 12 - (info->x + 8);
-  uint16 y = link_y_coord + 12 - (info->y + 8);
-  if (sign16(x))
-    x = -x;
-  if (sign16(y))
-    y = -y;
-  return x < 24 && y < 28;
-}
-
-void Follower_Disable() {  // 89acf3
-  if (follower_indicator == 9 || follower_indicator == 10)
-    follower_indicator = 0;
-}
-
-void Blind_SpawnFromMaiden(uint16 x, uint16 y) {  // 9da03c
-  int k = 0;
-  sprite_state[k] = 9;
-  sprite_type[k] = 206;
-  Sprite_SetX(k, x);
-  Sprite_SetY(k, y - 16);
-  SpritePrep_LoadProperties(k);
-  sprite_delay_aux2[k] = 192;
-  sprite_graphics[k] = 21;
-  sprite_D[k] = 2;
-  sprite_ignore_projectile[k] = 2;
-  dung_savegame_state_bits |= 0x2000;
-  byte_7E0B69 = 0;
-}
-
-void Kiki_RevertToSprite(int k) {  // 9ee66b
-  int j = Kiki_SpawnHandlerMonke(k);
-  sprite_subtype2[j] = 1;
-  follower_indicator = 0;
-}
-
-int Kiki_SpawnHandlerMonke(int k) {  // 9ee67a
-  SpriteSpawnInfo info;
-  int j = Sprite_SpawnDynamically(k, 0xb6, &info);
-  if (j >= 0) {
-    sprite_head_dir[j] = tagalong_layerbits[k] & 3;
-    sprite_D[j] = tagalong_layerbits[k] & 3;
-    int x = tagalong_x_hi[k] << 8 | tagalong_x_lo[k];
-    int y = tagalong_y_hi[k] << 8 | tagalong_y_lo[k];
-    Sprite_SetX(j, x + 2);
-    Sprite_SetY(j, y + 2);
-    sprite_floor[j] = link_is_on_lower_level;
-    sprite_ignore_projectile[j] = 1;
-    sprite_floor[j] = 2;
-    link_speed_setting = 0;
-  }
-  return j;
-}
-
-void Kiki_SpawnHandler_A(int k) {  // 9ee6c7
-  int j = Kiki_SpawnHandlerMonke(k);
-  sprite_subtype2[j] = 2;
-}
-
-void Kiki_SpawnHandler_B(int k) {  // 9ee6d0
-  int j = Kiki_SpawnHandlerMonke(k);
-  sprite_z[j] = 1;
-  sprite_z_vel[j] = 16;
-  sprite_subtype2[j] = 3;
-  follower_indicator = 0;
-}
-
--- a/tagalong.h
+++ /dev/null
@@ -1,32 +1,0 @@
-#pragma once
-#include "types.h"
-
-typedef struct TagalongMessageInfo {
-  uint16 y, x, bit, msg, tagalong;
-} TagalongMessageInfo;
-
-bool Tagalong_IsFollowing();
-bool Follower_ValidateMessageFreedom();
-void Follower_MoveTowardsLink();
-bool Follower_CheckBlindTrigger();
-void Follower_Initialize();
-void Sprite_BecomeFollower(int k);
-void Follower_Main();
-void Follower_NoTimedMessage();
-void Follower_CheckGameMode();
-void Follower_BasicMover();
-void Follower_NotFollowing();
-void Follower_OldMan();
-void Follower_OldManUnused();
-void Follower_DoLayers();
-bool Follower_CheckProximityToLink();
-void Follower_HandleTrigger();
-void Tagalong_Draw();
-void Follower_AnimateMovement_preserved(uint8 ain, uint16 xin, uint16 yin);
-bool Follower_CheckForTrigger(const TagalongMessageInfo *info);
-void Follower_Disable();
-void Blind_SpawnFromMaiden(uint16 x, uint16 y);
-void Kiki_RevertToSprite(int k);
-int Kiki_SpawnHandlerMonke(int k);
-void Kiki_SpawnHandler_A(int k);
-void Kiki_SpawnHandler_B(int k);
--- a/tile_detect.c
+++ /dev/null
@@ -1,527 +1,0 @@
-#include "tile_detect.h"
-#include "zelda_rtl.h"
-#include "ancilla.h"
-#include "variables.h"
-#include "overworld.h"
-
-static const uint8 kDetectTiles_tab0[] = { 8, 24, 0, 15 };
-static const uint8 kDetectTiles_tab1[] = { 0, 0, 8, 8 };
-static const uint8 kDetectTiles_tab2[] = { 8, 8, 16, 16 };
-static const uint8 kDetectTiles_tab3[] = { 15, 15, 23, 23 };
-static const int8 kDetectTiles_tab4[] = { 7, 24, -1, 16 };
-static const uint8 kDetectTiles_tab5[] = { 0, 0, 8, 8 };
-static const uint8 kDetectTiles_tab6[] = { 15, 15, 23, 23 };
-uint8 Overworld_GetTileAttributeAtLocation(uint16 x, uint16 y) {  // 80882e
-  uint16 t;
-
-  t = ((y - overworld_offset_base_y) & overworld_offset_mask_y) * 8;
-  t |= ((x - overworld_offset_base_x) & overworld_offset_mask_x);
-  t = overworld_tileattr[t >> 1] * 4;
-  t |= (y & 8) >> 2;
-  t |= (x & 1);
-  t = GetMap16toMap8Table()[t];
-
-  uint8 rv = GetMap8toTileAttr()[t & 0x1ff];
-  if (rv >= 0x10 && rv < 0x1C) {
-    rv |= (t >> 14) & 1;
-  }
-  return rv;
-}
-
-void TileDetect_Movement_Y(uint16 direction) {  // 87cdcb
-  assert(direction < 4);
-  TileDetect_ResetState();
-  tiledetect_pit_tile = 0;
-
-  tiledetect_which_y_pos[0] = (link_y_coord + kDetectTiles_tab0[direction]);
-  uint16 y = tiledetect_which_y_pos[0] & tilemap_location_calc_mask;
-  uint16 x0 = ((link_x_coord + kDetectTiles_tab1[direction]) & tilemap_location_calc_mask) >> 3;
-  uint16 x1 = ((link_x_coord + kDetectTiles_tab2[direction]) & tilemap_location_calc_mask) >> 3;
-  uint16 x2 = ((link_x_coord + kDetectTiles_tab3[direction]) & tilemap_location_calc_mask) >> 3;
-  scratch_1 = x2;
-  TileDetection_Execute(x0, y, 1);
-  TileDetection_Execute(x1, y, 2);
-  TileDetection_Execute(x2, y, 4);
-}
-
-void TileDetect_Movement_X(uint16 direction) {  // 87ce2a
-  assert(direction < 4);
-  TileDetect_ResetState();
-  tiledetect_pit_tile = 0;
-
-  uint16 x = ((link_x_coord + kDetectTiles_tab0[direction]) & tilemap_location_calc_mask) >> 3;
-  uint16 y0 = ((link_y_coord + kDetectTiles_tab1[direction]) & tilemap_location_calc_mask);
-  tiledetect_which_y_pos[0] = link_y_coord + kDetectTiles_tab2[direction];
-  uint16 y1 = tiledetect_which_y_pos[0] & tilemap_location_calc_mask;
-  tiledetect_which_y_pos[1] = link_y_coord + kDetectTiles_tab3[direction];
-  uint16 y2 = tiledetect_which_y_pos[1] & tilemap_location_calc_mask;
-  TileDetection_Execute(x, y0, 1);
-  TileDetection_Execute(x, y1, 2);
-  TileDetection_Execute(x, y2, 4);
-}
-
-void TileDetect_Movement_VerticalSlopes(uint16_t direction) {  // 87ce85
-  assert(direction < 4);
-  TileDetect_ResetState();
-  tiledetect_pit_tile = 0;
-
-  uint16 y = (link_y_coord + kDetectTiles_tab4[direction]) & tilemap_location_calc_mask;
-  uint16 x0 = ((link_x_coord + kDetectTiles_tab5[direction]) & tilemap_location_calc_mask) >> 3;
-  uint16 x1 = ((link_x_coord + kDetectTiles_tab6[direction]) & tilemap_location_calc_mask) >> 3;
-  TileDetection_Execute(x0, y, 1);
-  TileDetection_Execute(x1, y, 2);
-}
-
-void TileDetect_Movement_HorizontalSlopes(uint16_t direction) {  // 87cec9
-  assert(direction < 4);
-  TileDetect_ResetState();
-  tiledetect_pit_tile = 0;
-
-  uint16 x = ((link_x_coord + kDetectTiles_tab4[direction]) & tilemap_location_calc_mask) >> 3;
-  uint16 y0 = ((link_y_coord + kDetectTiles_tab5[direction]) & tilemap_location_calc_mask);
-  uint16 y1 = ((link_y_coord + kDetectTiles_tab6[direction]) & tilemap_location_calc_mask);
-  TileDetection_Execute(x, y0, 1);
-  TileDetection_Execute(x, y1, 2);
-}
-
-void Player_TileDetectNearby() {  // 87cf12
-  TileDetect_ResetState();
-  tiledetect_pit_tile = 0;
-
-  uint16 x0 = ((link_x_coord + kDetectTiles_tab1[0]) & tilemap_location_calc_mask) >> 3;
-  uint16 x1 = ((link_x_coord + kDetectTiles_tab3[0]) & tilemap_location_calc_mask) >> 3;
-
-  uint16 y0 = ((link_y_coord + kDetectTiles_tab1[2]) & tilemap_location_calc_mask);
-  uint16 y1 = ((link_y_coord + kDetectTiles_tab3[2]) & tilemap_location_calc_mask);
-
-  scratch_1 = y0;
-
-  TileDetection_Execute(x0, y0, 8);
-  TileDetection_Execute(x0, y1, 2);
-  TileDetection_Execute(x1, y0, 4);
-  TileDetection_Execute(x1, y1, 1);
-}
-
-void Hookshot_CheckTileCollision(int k) {  // 87d576
-  uint8 bak0 = BYTE(dungeon_room_index);
-  uint8 bak1 = link_is_on_lower_level;
-
-  if (ancilla_arr1[k]) {
-    if (!BYTE(kind_of_in_room_staircase))
-      BYTE(dungeon_room_index) += 0x10;
-    link_is_on_lower_level ^= 1;
-  }
-
-  uint16 x = Ancilla_GetX(k), y = Ancilla_GetY(k);
-  int dir = ancilla_dir[k];
-
-  tiledetect_pit_tile = 0;
-  TileDetect_ResetState();
-  if (dung_hdr_collision == 2) {
-    link_is_on_lower_level = 1;
-    Hookshot_CheckSingleLayerTileCollision(x + BG1HOFS_copy2 - BG2HOFS_copy2, y + BG1VOFS_copy2 - BG2VOFS_copy2, dir);
-    link_is_on_lower_level = 0;
-  }
-  Hookshot_CheckSingleLayerTileCollision(x, y, dir);
-
-  link_is_on_lower_level = bak1;
-  BYTE(dungeon_room_index) = bak0;
-}
-
-void Hookshot_CheckSingleLayerTileCollision(uint16 x, uint16 y, int dir) {  // 87d607
-  static const uint8 kHookShot_CheckColl_X[8] = { 0, 15, 0, 15, 0, 0, 8, 8 };
-  static const uint8 kHookShot_CheckColl_Y[8] = { 0, 0, 7, 7, 0, 15, 0, 15 };
-  uint16 y0 = (y + kHookShot_CheckColl_Y[dir * 2 + 0]) & tilemap_location_calc_mask;
-  uint16 y1 = (y + kHookShot_CheckColl_Y[dir * 2 + 1]) & tilemap_location_calc_mask;
-  uint16 x0 = ((x + kHookShot_CheckColl_X[dir * 2 + 0]) & tilemap_location_calc_mask) >> 3;
-  uint16 x1 = ((x + kHookShot_CheckColl_X[dir * 2 + 1]) & tilemap_location_calc_mask) >> 3;
-  TileDetection_Execute(x0, y0, 1);
-  TileDetection_Execute(x1, y1, 2);
-}
-
-void HandleNudgingInADoor(int8 speed) {  // 87d667
-  uint8 y;
-
-  if (link_last_direction_moved_towards & 2) {
-    y = (uint8)link_y_coord < 0x80 ? 1 : 0;
-  } else {
-    y = (uint8)link_x_coord < 0x80 ? 3 : 2;
-  }
-  tiledetect_pit_tile = 0;
-  TileDetect_ResetState();
-
-  static const int8 kDetectTiles_7_Y[] = { 8, 23, 16, 16 };
-  static const int8 kDetectTiles_7_X[] = { 8, 8, 0, 15 };
-
-  uint16 x0 = ((link_x_coord + kDetectTiles_7_X[y]) & tilemap_location_calc_mask) >> 3;
-  uint16 y0 = ((link_y_coord + kDetectTiles_7_Y[y]) & tilemap_location_calc_mask);
-
-  TileDetection_Execute(x0, y0, 1);
-
-  if (((R14 | detection_of_ledge_tiles_horiz_uphoriz) & 3) == 0) {
-    if (((tiledetect_vertical_ledge | detection_of_unknown_tile_types) & 0x33) == 0)
-      return;
-  }
-
-  if (link_last_direction_moved_towards & 2)
-    link_y_coord -= speed;
-  else
-    link_x_coord -= speed;
-}
-
-void TileCheckForMirrorBonk() {  // 87d6f4
-  tiledetect_pit_tile = 0;
-  TileDetect_ResetState();
-
-  uint16 x0 = ((link_x_coord + 2) & tilemap_location_calc_mask) >> 3;
-  uint16 x1 = ((link_x_coord + 13) & tilemap_location_calc_mask) >> 3;
-
-  uint16 y0 = ((link_y_coord + 10) & tilemap_location_calc_mask);
-  uint16 y1 = ((link_y_coord + 21) & tilemap_location_calc_mask);
-
-  scratch_1 = y0;
-
-  TileDetection_Execute(x0, y0, 8);
-  TileDetection_Execute(x0, y1, 2);
-  TileDetection_Execute(x1, y0, 4);
-  TileDetection_Execute(x1, y1, 1);
-
-}
-
-// Used when holding sword in doorway
-void TileDetect_SwordSwingDeepInDoor(uint8 dw) {  // 87d73e
-  tiledetect_pit_tile = 0;
-  TileDetect_ResetState();
-
-  static const int8 kDoorwayDetectX[] = { 8, 8, -1, 16 };
-  static const int8 kDoorwayDetectY[] = { -1, 24, 16, 16 };
-  int o = (dw - 1) * 2;
-  uint16 x0 = ((link_x_coord + kDoorwayDetectX[o + 0]) & tilemap_location_calc_mask) >> 3;
-  uint16 x1 = ((link_x_coord + kDoorwayDetectX[o + 1]) & tilemap_location_calc_mask) >> 3;
-
-  uint16 y0 = ((link_y_coord + kDoorwayDetectY[o + 0]) & tilemap_location_calc_mask);
-  uint16 y1 = ((link_y_coord + kDoorwayDetectY[o + 1]) & tilemap_location_calc_mask);
-
-  TileDetection_Execute(x0, y0, 1);
-  TileDetection_Execute(x1, y1, 2);
-}
-
-void TileDetect_ResetState() {  // 87d798
-  R12 = 0;
-  R14 = 0;
-  tiledetect_diagonal_tile = 0;
-  tiledetect_stair_tile = 0;
-  tiledetect_pit_tile = 0;
-  tiledetect_inroom_staircase = 0;
-  tiledetect_var2 = 0;
-  tiledetect_var1 = 0;
-  tiledetect_moving_floor_tiles = 0;
-  tiledetect_deepwater = 0;
-  tiledetect_normal_tiles = 0;
-  tiledetect_icy_floor = 0;
-  tiledetect_water_staircase = 0;
-  tiledetect_thick_grass = 0;
-  tiledetect_shallow_water = 0;
-  tiledetect_destruction_aftermath = 0;
-  tiledetect_read_something = 0;
-  tiledetect_vertical_ledge = 0;
-  detection_of_ledge_tiles_horiz_uphoriz = 0;
-  tiledetect_ledges_down_leftright = 0;
-  detection_of_unknown_tile_types = 0;
-  tiledetect_chest = 0;
-  tiledetect_key_lock_gravestones = 0;
-  bitfield_spike_cactus_tiles = 0;
-  tiledetect_spike_floor_and_tile_triggers = 0;
-  bitmask_for_dashable_tiles = 0;
-  tiledetect_misc_tiles = 0;
-  tiledetect_var4 = 0;
-}
-
-void TileDetection_Execute(uint16 x, uint16 y, uint16 bits) {  // 87d9d8
-  uint8 tile;
-  uint16 offs = 0;
-  if (player_is_indoors) {
-    force_move_any_direction = force_move_any_direction & 0xff;
-    offs = (y & ~7) * 8 + (x & 63) + (link_is_on_lower_level ? 0x1000 : 0);
-    tile = dung_bg2_attr_table[offs];
-    if (cheatWalkThroughWalls)
-      tile = 0;
-    link_tile_below = tile;
-  } else {
-    tile = Overworld_GetTileAttributeAtLocation(x, y);
-  }
-  TileDetect_ExecuteInner(tile, offs, bits, player_is_indoors);
-}
-
-void TileDetect_ExecuteInner(uint8 tile, uint16 offs, uint16 bits, bool is_indoors) {  // 87dc2e
-  static const uint8 word_87DC55[] = { 4, 0, 6, 2 };
-  if (cheatWalkThroughWalls)
-    tile = 0;
-
-  switch (tile) {
-  case 0x00: case 0x05: case 0x06: case 0x07: case 0x14: case 0x15: case 0x16: case 0x17: case 0x21: case 0x23: case 0x24: case 0x25: case 0x38: case 0x39: case 0x3a: case 0x3b: case 0x3c: case 0x41: case 0x45: case 0x47: case 0x49: case 0x5e: case 0x5f: case 0x61: case 0x62: case 0x64: case 0x65: case 0x66: case 0xa6: case 0xa7: case 0xbe: case 0xbf: case 0xd0: case 0xd1: case 0xd2: case 0xd3: case 0xd4: case 0xd5: case 0xd6: case 0xd7: case 0xd8: case 0xd9: case 0xda: case 0xdb: case 0xdc: case 0xdd: case 0xde: case 0xdf: case 0xe0: case 0xe1: case 0xe2: case 0xe3: case 0xe4: case 0xe5: case 0xe6: case 0xe7: case 0xe8: case 0xe9: case 0xea: case 0xeb: case 0xec: case 0xed: case 0xee: case 0xef:  // TileBehavior_NothingOW
-    if (!is_indoors)
-      tiledetect_normal_tiles |= bits;
-    break;
-  case 0x01: case 0x02: case 0x03:  // TileBehavior_StandardCollision
-  case 0x26: case 0x43:
-    R14 |= bits;
-    break;
-  case 0x6c: case 0x6d: case 0x6e: case 0x6f:
-    if (is_indoors)
-      R14 |= bits;
-    else
-      tiledetect_normal_tiles |= bits;
-    break;
-  case 0x04:
-    if (is_indoors) {
-      R14 |= bits;
-    } else {
-      tiledetect_thick_grass |= bits;
-    }
-    break;
-  case 0x0b:
-    if (is_indoors) {
-      R14 |= bits;
-    } else {
-      index_of_interacting_tile = tile;
-      tiledetect_deepwater |= bits << 4;
-    }
-    break;
-  case 0x08:  // TileBehavior_DeepWater
-    tiledetect_deepwater |= bits;
-    break;
-  case 0x09:  // TileBehavior_ShallowWater
-    tiledetect_shallow_water |= bits;
-    break;
-  case 0x0a:  // TileBehavior_ShortWaterLadder
-    tiledetect_normal_tiles |= bits;
-    break;
-  case 0x0c:  // TileBehavior_OverlayMask_0C
-    tiledetect_moving_floor_tiles |= bits;
-    break;
-  case 0x0d:  // TileBehavior_SpikeFloor
-    if (!flag_block_link_menu && !(dung_savegame_state_bits & 0x8000))
-      tiledetect_spike_floor_and_tile_triggers |= bits << 4;
-    break;
-  case 0x0e:  // TileBehavior_GanonIce
-    tiledetect_icy_floor |= bits;
-    break;
-  case 0x0f:  // TileBehavior_PalaceIce
-    tiledetect_icy_floor |= bits << 4;
-    break;
-  case 0x10: case 0x11: case 0x12: case 0x13:  // TileBehavior_Slope
-    R12 |= bits;
-    tiledetect_diag_state = word_87DC55[tile & 3];
-    break;
-  case 0x18: case 0x19: case 0x1a: case 0x1b:  // TileBehavior_SlopeOuter
-    tiledetect_diagonal_tile |= bits;
-    R12 |= bits;
-    tiledetect_diag_state = word_87DC55[tile & 3];
-    break;
-  case 0x1c:  // TileBehavior_OverlayMask_1C
-    tiledetect_water_staircase |= bits;
-    break;
-  case 0x1d:  // TileBehavior_NorthSingleLayerStairs
-    index_of_interacting_tile = tile;
-    tiledetect_inroom_staircase |= bits;
-    tiledetect_stair_tile |= bits;
-    break;
-  case 0x1e: case 0x1f:  // TileBehavior_NorthSwapLayerStairs
-    index_of_interacting_tile = tile;
-    tiledetect_inroom_staircase |= bits;
-    tiledetect_stair_tile |= bits;
-    break;
-  case 0x20: case 0xb0: case 0xb1: case 0xb2: case 0xb3: case 0xb4: case 0xb5: case 0xb6: case 0xb7: case 0xb8: case 0xb9: case 0xba: case 0xbb: case 0xbc: case 0xbd:  // TileBehavior_Pit
-    if (!player_on_somaria_platform)
-      tiledetect_pit_tile |= bits;
-    break;
-  case 0x22: case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37:  // TileHandlerIndoor_22
-    tiledetect_stair_tile |= bits;
-    break;
-  case 0x27:  // TileBehavior_Hookshottables
-    R14 |= bits;
-    tiledetect_misc_tiles |= bits;
-    break;
-  case 0x28:  // TileBehavior_Ledge_North
-    index_of_interacting_tile = tile;
-    tiledetect_vertical_ledge |= bits;
-    break;
-  case 0x29:  // TileBehavior_Ledge_South
-    index_of_interacting_tile = tile;
-    tiledetect_vertical_ledge |= bits << 4;
-    break;
-  case 0x2a: case 0x2b:  // TileBehavior_Ledge_EastWest
-    index_of_interacting_tile = tile;
-    detection_of_ledge_tiles_horiz_uphoriz |= bits;
-    break;
-  case 0x2c: case 0x2e:  // TileBehavior_Ledge_NorthDiagonal
-    index_of_interacting_tile = tile;
-    detection_of_ledge_tiles_horiz_uphoriz |= bits << 4;
-    break;
-  case 0x2d: case 0x2f:  // TileBehavior_Ledge_SouthDiagonal
-    index_of_interacting_tile = tile;
-    tiledetect_ledges_down_leftright |= bits;
-    break;
-  case 0x3d: case 0x3e: case 0x3f:  // TileHandlerIndoor_3E
-    index_of_interacting_tile = tile;
-    tiledetect_inroom_staircase |= bits << 4;
-    tiledetect_stair_tile |= bits;
-    break;
-  case 0x40:  // TileBehavior_ThickGrass
-    tiledetect_thick_grass |= bits;
-    break;
-  case 0x44:  // TileBehavior_Spike
-    if (!flag_block_link_menu && !(dung_savegame_state_bits & 0x8000))
-      bitfield_spike_cactus_tiles |= bits;
-    else
-      R14 |= bits;
-    break;
-  case 0x46:  // TileBehavior_HylianPlaque
-    tiledetect_spike_floor_and_tile_triggers |= bits;
-    R14 |= bits;
-    break;
-  case 0x48: case 0x4a:  // TileBehavior_DiggableGround
-    tiledetect_destruction_aftermath |= bits;
-    tiledetect_normal_tiles |= bits;
-    break;
-  case 0x4b:  // TileBehavior_Warp
-    tiledetect_thick_grass |= bits << 4;
-    break;
-  case 0x50: case 0x51: case 0x52: case 0x53: case 0x54: case 0x55: case 0x56: { // TileBehavior_Liftable
-    static const uint8 kTile50data[] = { 0x54, 0x52, 0x50, 0x51, 0x53, 0x55, 0x56 };
-    for (int i = 6; i >= 0; i--) {
-      if (kTile50data[i] == tile) {
-        if (tile == 0x50 || tile == 0x51)
-          bitmask_for_dashable_tiles |= bits << 4;
-        tiledetect_read_something |= bits;
-        interacting_with_liftable_tile_x2 = i * 2;
-        R14 |= bits;
-        tiledetect_misc_tiles |= bits;
-        break;
-      }
-    }
-    break;
-  }
-  case 0x57:  // TileBehavior_BonkRocks
-    R14 |= bits;
-    bitmask_for_dashable_tiles |= bits << 4;
-    break;
-  case 0x58: case 0x59: case 0x5a: case 0x5b: case 0x5c: case 0x5d:  // TileBehavior_Chest
-    tiledetect_misc_tiles |= bits;
-    index_of_interacting_tile = tile;
-    if (dung_chest_locations[tile - 0x58] >= 0x8000) {
-      R14 |= bits;
-      tiledetect_key_lock_gravestones |= bits << 4;
-      if (bits & 2)
-        tiledetect_tile_type = tile;
-    } else {
-      tiledetect_chest |= bits;  // small key lock
-      R14 |= bits;
-    }
-    break;
-  case 0x60:  // TileBehavior_RupeeTile
-    if (is_indoors) {
-      if (dung_bg2_attr_table[offs + 64] == 0x60) {
-        tiledetect_misc_tiles |= bits << 8;
-      } else {
-        tiledetect_misc_tiles |= bits << 12;
-      }
-    } else {
-      tiledetect_normal_tiles |= bits;
-    }
-    break;
-  case 0x63:  // TileBehavior_MinigameChest
-    tiledetect_misc_tiles |= bits;
-    index_of_interacting_tile = tile;
-    tiledetect_chest |= bits;  // small key lock
-    R14 |= bits;
-    break;
-  case 0x67:  // TileBehavior_CrystalPeg_Up
-    R14 |= bits;
-    tiledetect_misc_tiles |= bits;
-    bitfield_spike_cactus_tiles |= bits << 4;
-    break;
-  case 0x68:  // TileBehavior_Conveyor_Upwards
-    tiledetect_var4 |= bits;
-    break;
-  case 0x69:  // TileBehavior_Conveyor_Downwards
-    tiledetect_var4 |= bits << 4;
-    break;
-  case 0x6a:  // TileBehavior_Conveyor_Leftwards
-    tiledetect_var4 |= bits << 8;
-    break;
-  case 0x6b:  // TileBehavior_Conveyor_Rightwards
-    tiledetect_var4 |= bits << 12;
-    break;
-  case 0x70: case 0x71: case 0x72: case 0x73: case 0x74: case 0x75: case 0x76: case 0x77: case 0x78: case 0x79: case 0x7a: case 0x7b: case 0x7c: case 0x7d: case 0x7e: case 0x7f:  // TileBehavior_ManipulablyReplaced
-    if (bits & 2)
-      tiledetect_var2 |= 1 << (tile & 0xf);
-    R14 |= bits;
-    tiledetect_misc_tiles |= bits;
-    break;
-  case 0x80: case 0x81: case 0x84: case 0x85: case 0x86: case 0x87: case 0x88: case 0x89: case 0x8a: case 0x8b: case 0x8c: case 0x8d:  // TileHandlerIndoor_80
-    R14 |= bits << 4;
-    tiledetect_var1 = 2 * (tile & 1);
-    break;
-  case 0x82: case 0x83:  // TileHandlerIndoor_82
-    R14 |= (bits << 4) | (bits << 8);
-    tiledetect_var1 = 2 * (tile & 1);
-    break;
-  case 0x8e: case 0x8f:  // TileBehavior_Entrance
-    R14 |= bits << 4;
-    bitmask_for_dashable_tiles |= bits;
-    tiledetect_var1 = 0;
-    break;
-  case 0x90: case 0x91: case 0x92: case 0x93: case 0x94: case 0x95: case 0x96: case 0x97:  // TileBehavior_LayerToggleShutterDoor
-    room_transitioning_flags = 1;
-    R14 |= (bits << 4) | (bits << 8);
-    tiledetect_var1 = 2 * (tile & 1);
-    break;
-  case 0x98: case 0x99: case 0x9a: case 0x9b: case 0x9c: case 0x9d: case 0x9e: case 0x9f: case 0xa8: case 0xa9: case 0xaa: case 0xab: case 0xac: case 0xad: case 0xae: case 0xaf:  // TileBehavior_LayerAndDungeonToggleShutterDoor
-    room_transitioning_flags = 3;
-    R14 |= (bits << 4) | (bits << 8);
-    tiledetect_var1 = 2 * (tile & 1);
-    break;
-  case 0xa0: case 0xa1: case 0xa4: case 0xa5:  // TileBehavior_DungeonToggleManualDoor
-    room_transitioning_flags = 2;
-    R14 |= bits << 4;
-    tiledetect_var1 = 2 * (tile & 1);
-    break;
-  case 0xa2: case 0xa3:  // TileBehavior_DungeonToggleShutterDoor
-    room_transitioning_flags = 2;
-    R14 |= (bits << 4) | (bits << 8);
-    tiledetect_var1 = 2 * (tile & 1);
-    break;
-  case 0xc0: case 0xc1: case 0xc2: case 0xc3: case 0xc4: case 0xc5: case 0xc6: case 0xc7: case 0xc8: case 0xc9: case 0xca: case 0xcb: case 0xcc: case 0xcd: case 0xce: case 0xcf:  // TileBehavior_LightableTorch
-    R14 |= bits;
-    tiledetect_misc_tiles |= bits;
-    break;
-  case 0xf0: case 0xf1: case 0xf2: case 0xf3: case 0xf4: case 0xf5: case 0xf6: case 0xf7: case 0xf8: case 0xf9: case 0xfa: case 0xfb: case 0xfc: case 0xfd: case 0xfe: case 0xff:  // TileBehavior_FlaggableDoor
-    R14 |= bits;
-    tiledetect_misc_tiles |= bits << 4;
-    break;
-
-  case 0x42:  // TileBehavior_GraveStone
-    if (!is_indoors) {
-      tiledetect_key_lock_gravestones |= bits;
-      R14 |= bits;
-    }
-    break;
-  case 0x4c: case 0x4d:  // TileBehavior_UnusedCornerType
-    if (!is_indoors) {
-      index_of_interacting_tile = tile;
-      detection_of_unknown_tile_types |= bits;
-    }
-    break;
-  case 0x4e: case 0x4f:  // TileBehavior_EasternRuinsCorner
-    if (!is_indoors) {
-      index_of_interacting_tile = tile;
-      detection_of_unknown_tile_types |= bits << 4;
-    }
-    break;
-  default:
-    assert(0);
-  }
-}
-
--- a/tile_detect.h
+++ /dev/null
@@ -1,18 +1,0 @@
-#pragma once
-#include "types.h"
-
-
-uint8 Overworld_GetTileAttributeAtLocation(uint16 x, uint16 y);
-void TileDetect_Movement_Y(uint16 direction);
-void TileDetect_Movement_X(uint16 direction);
-void TileDetect_Movement_VerticalSlopes(uint16_t direction);
-void TileDetect_Movement_HorizontalSlopes(uint16_t direction);
-void Player_TileDetectNearby();
-void Hookshot_CheckTileCollision(int k);
-void Hookshot_CheckSingleLayerTileCollision(uint16 x, uint16 y, int dir);
-void HandleNudgingInADoor(int8 speed);
-void TileCheckForMirrorBonk();
-void TileDetect_SwordSwingDeepInDoor(uint8 dw);
-void TileDetect_ResetState();
-void TileDetection_Execute(uint16 x, uint16 y, uint16 bits);
-void TileDetect_ExecuteInner(uint8 tile, uint16 offs, uint16 bits, bool is_indoors);
--- a/types.h
+++ /dev/null
@@ -1,103 +1,0 @@
-#ifndef ZELDA3_TYPES_H_
-#define ZELDA3_TYPES_H_
-
-#include <stdint.h>
-#include <stdlib.h>
-#include <stdbool.h>
-
-// Build time config options
-enum {
-  kEnableLargeScreen = 1,
-  // How much extra spacing to add on the sides
-  kPpuExtraLeftRight = kEnableLargeScreen ? 96 : 0,
-};
-
-typedef uint8_t uint8;
-typedef int8_t int8;
-typedef uint16_t uint16;
-typedef int16_t int16;
-typedef uint32_t uint32;
-typedef int32_t int32;
-typedef uint64_t uint64;
-typedef int64_t int64;
-typedef unsigned int uint;
-
-#define arraysize(x) sizeof(x)/sizeof(x[0])
-#define sign8(x) ((x) & 0x80)
-#define sign16(x) ((x) & 0x8000)
-#define load24(x) ((*(uint32*)&(x))&0xffffff)
-
-#ifdef _MSC_VER
-#define countof _countof
-#define NORETURN __declspec(noreturn)
-#define FORCEINLINE __forceinline
-#define NOINLINE __declspec(noinline)
-#else
-#define countof(a) (sizeof(a)/sizeof(*(a)))
-#define NORETURN
-#define FORCEINLINE inline
-#define NOINLINE
-#endif
-
-#ifdef _DEBUG
-#define kDebugFlag 1
-#else
-#define kDebugFlag 0
-#endif
-
-static FORCEINLINE uint16 abs16(uint16 t) { return sign16(t) ? -t : t; }
-static FORCEINLINE uint8 abs8(uint8 t) { return sign8(t) ? -t : t; }
-static FORCEINLINE int IntMin(int a, int b) { return a < b ? a : b; }
-static FORCEINLINE int IntMax(int a, int b) { return a > b ? a : b; }
-static FORCEINLINE uint UintMin(uint a, uint b) { return a < b ? a : b; }
-static FORCEINLINE uint UintMax(uint a, uint b) { return a > b ? a : b; }
-
-// windows.h defines this too
-#ifdef HIBYTE
-#undef HIBYTE
-#endif
-
-#define BYTE(x) (*(uint8*)&(x))
-#define HIBYTE(x) (((uint8*)&(x))[1])
-#define WORD(x) (*(uint16*)&(x))
-#define DWORD(x) (*(uint32*)&(x))
-#define XY(x, y) ((y)*64+(x))
-
-#ifndef swap16
-static inline uint16 swap16(uint16 v) { return (v << 8) | (v >> 8); }
-#endif
-
-typedef struct Point16U {
-  uint16 x, y;
-} Point16U;
-
-typedef struct PointU8 {
-  uint8 x, y;
-} PointU8;
-
-typedef struct Pair16U {
-  uint16 a, b;
-} Pair16U;
-
-typedef struct PairU8 {
-  uint8 a, b;
-} PairU8;
-
-typedef struct ProjectSpeedRet {
-  uint8 x, y;
-  uint8 xdiff, ydiff;
-} ProjectSpeedRet;
-
-typedef struct OamEnt {
-  uint8 x, y, charnum, flags;
-} OamEnt;
-
-typedef struct MemBlk {
-  const uint8 *ptr;
-  size_t size;
-} MemBlk;
-MemBlk FindIndexInMemblk(MemBlk data, size_t i);
-
-void NORETURN Die(const char *error);
-
-#endif  // ZELDA3_TYPES_H_
--- a/util.c
+++ /dev/null
@@ -1,195 +1,0 @@
-#include "util.h"
-#include <stdio.h>
-#include <string.h>
-#include <stdarg.h>
-
-char *NextDelim(char **s, int sep) {
-  char *r = *s;
-  if (r) {
-    while (r[0] == ' ' || r[0] == '\t')
-      r++;
-    char *t = strchr(r, sep);
-    *s = t ? (*t++ = 0, t) : NULL;
-  }
-  return r;
-}
-
-static inline int ToLower(int a) {
-  return a + (a >= 'A' && a <= 'Z') * 32;
-}
-
-bool StringEqualsNoCase(const char *a, const char *b) {
-  for (;;) {
-    int aa = ToLower(*a++), bb = ToLower(*b++);
-    if (aa != bb)
-      return false;
-    if (aa == 0)
-      return true;
-  }
-}
-
-const char *StringStartsWithNoCase(const char *a, const char *b) {
-  for (;; a++, b++) {
-    int aa = ToLower(*a), bb = ToLower(*b);
-    if (bb == 0)
-      return a;
-    if (aa != bb)
-      return NULL;
-  }
-}
-
-uint8 *ReadWholeFile(const char *name, size_t *length) {
-  FILE *f = fopen(name, "rb");
-  if (f == NULL)
-    return NULL;
-  fseek(f, 0, SEEK_END);
-  size_t size = ftell(f);
-  rewind(f);
-  uint8 *buffer = (uint8 *)malloc(size + 1);
-  if (!buffer) Die("malloc failed");
-  // Always zero terminate so this function can be used also for strings.
-  buffer[size] = 0;
-  if (fread(buffer, 1, size, f) != size)
-    Die("fread failed");
-  fclose(f);
-  if (length) *length = size;
-  return buffer;
-}
-
-char *NextLineStripComments(char **s) {
-  char *p = *s;
-  if (p == NULL)
-    return NULL;
-  // find end of line
-  char *eol = strchr(p, '\n');
-  *s = eol ? eol + 1 : NULL;
-  eol = eol ? eol : p + strlen(p);
-  // strip comments
-  char *comment = memchr(p, '#', eol - p);
-  eol = comment ? comment : eol;
-  // strip trailing whitespace
-  while (eol > p && (eol[-1] == '\r' || eol[-1] == ' ' || eol[-1] == '\t'))
-    eol--;
-  *eol = 0;
-  // strip leading whitespace
-  while (p[0] == ' ' || p[0] == '\t')
-    p++;
-  return p;
-}
-
-// Return the next possibly quoted string, space separated, or the empty string
-char *NextPossiblyQuotedString(char **s) {
-  char *r = *s, *t;
-  while (*r == ' ' || *r == '\t')
-    r++;
-  if (*r == '"') {
-    for (t = ++r; *t && *t != '"'; t++);
-  } else {
-    for (t = r; *t && *t != ' ' && *t != '\t'; t++);
-  }
-  if (*t) *t++ = 0;
-  while (*t == ' ' || *t == '\t')
-    t++;
-  *s = t;
-  return r;
-}
-
-char *ReplaceFilenameWithNewPath(const char *old_path, const char *new_path) {
-  size_t olen = strlen(old_path);
-  size_t nlen = strlen(new_path) + 1;
-  while (olen && old_path[olen - 1] != '/' && old_path[olen - 1] != '\\')
-    olen--;
-  char *result = malloc(olen + nlen);
-  memcpy(result, old_path, olen);
-  memcpy(result + olen, new_path, nlen);
-  return result;
-}
-
-char *SplitKeyValue(char *p) {
-  char *equals = strchr(p, '=');
-  if (equals == NULL)
-    return NULL;
-  char *kr = equals;
-  while (kr > p && (kr[-1] == ' ' || kr[-1] == '\t'))
-    kr--;
-  *kr = 0;
-  char *v = equals + 1;
-  while (v[0] == ' ' || v[0] == '\t')
-    v++;
-  return v;
-}
-
-const char *SkipPrefix(const char *big, const char *little) {
-  for (; *little; big++, little++) {
-    if (*little != *big)
-      return NULL;
-  }
-  return big;
-}
-
-void StrSet(char **rv, const char *s) {
-  char *news = strdup(s);
-  char *old = *rv;
-  *rv = news;
-  free(old);
-}
-
-char *StrFmt(const char *fmt, ...) {
-  char buf[4096];
-  va_list va;
-  va_start(va, fmt);
-  int n = vsnprintf(buf, sizeof(buf), fmt, va);
-  if (n < 0 || n >= sizeof(buf)) Die("vsnprintf failed");
-  va_end(va);
-  return strdup(buf);
-}
-
-void ByteArray_Resize(ByteArray *arr, size_t new_size) {
-  arr->size = new_size;
-  if (new_size > arr->capacity) {
-    size_t minsize = arr->capacity + (arr->capacity >> 1) + 8;
-    arr->capacity = new_size < minsize ? minsize : new_size;
-    void *data = realloc(arr->data, arr->capacity);
-    if (!data) Die("memory allocation failed");
-    arr->data = data;
-  }
-}
-
-void ByteArray_Destroy(ByteArray *arr) {
-  void *data = arr->data;
-  arr->data = NULL;
-  free(data);
-}
-
-void ByteArray_AppendData(ByteArray *arr, const uint8 *data, size_t data_size) {
-  ByteArray_Resize(arr, arr->size + data_size);
-  memcpy(arr->data + arr->size - data_size, data, data_size);
-}
-
-void ByteArray_AppendByte(ByteArray *arr, uint8 v) {
-  ByteArray_Resize(arr, arr->size + 1);
-  arr->data[arr->size - 1] = v;
-}
-
-// Automatically selects between 16 or 32 bit indexes. Can hold up to 8192 elements in 16-bit mode.
-MemBlk FindIndexInMemblk(MemBlk data, size_t i) {
-  if (data.size < 2)
-    return (MemBlk) { 0, 0 };
-  size_t end = data.size - 2, left_off, right_off;
-  size_t mx = *(uint16 *)(data.ptr + end);
-  if (mx < 8192) {
-    if (i > mx || mx * 2 > end)
-      return (MemBlk) { 0, 0 };
-    left_off = ((i == 0) ? mx * 2 : mx * 2 + *(uint16 *)(data.ptr + i * 2 - 2));
-    right_off = (i == mx) ? end : mx * 2 + *(uint16 *)(data.ptr + i * 2);
-  } else {
-    mx -= 8192;
-    if (i > mx || mx * 4 > end)
-      return (MemBlk) { 0, 0 };
-    left_off = ((i == 0) ? mx * 4 : mx * 4 + *(uint32 *)(data.ptr + i * 4 - 4));
-    right_off = (i == mx) ? end : mx * 4 + *(uint32 *)(data.ptr + i * 4);
-  }
-  if (left_off > right_off || right_off > end)
-    return (MemBlk) { 0, 0 };
-  return (MemBlk) { data.ptr + left_off, right_off - left_off };
-}
--- a/util.h
+++ /dev/null
@@ -1,39 +1,0 @@
-#ifndef ZELDA3_UTIL_H_
-#define ZELDA3_UTIL_H_
-
-#include "types.h"
-
-typedef struct SDL_Window SDL_Window;
-
-struct RendererFuncs {
-  bool (*Initialize)(SDL_Window *window);
-  void (*Destroy)();
-  void (*BeginDraw)(int width, int height, uint8 **pixels, int *pitch);
-  void (*EndDraw)();
-};
-
-
-typedef struct ByteArray {
-  uint8 *data;
-  size_t size, capacity;
-} ByteArray;
-
-void ByteArray_Resize(ByteArray *arr, size_t new_size);
-void ByteArray_Destroy(ByteArray *arr);
-void ByteArray_AppendData(ByteArray *arr, const uint8 *data, size_t data_size);
-void ByteArray_AppendByte(ByteArray *arr, uint8 v);
-
-uint8 *ReadWholeFile(const char *name, size_t *length);
-char *NextDelim(char **s, int sep);
-char *NextLineStripComments(char **s);
-char *NextPossiblyQuotedString(char **s);
-char *SplitKeyValue(char *p);
-bool StringEqualsNoCase(const char *a, const char *b);
-const char *StringStartsWithNoCase(const char *a, const char *b);
-bool ParseBool(const char *value, bool *result);
-const char *SkipPrefix(const char *big, const char *little);
-void StrSet(char **rv, const char *s);
-char *StrFmt(const char *fmt, ...);
-char *ReplaceFilenameWithNewPath(const char *old_path, const char *new_path);
-
-#endif  // ZELDA3_UTIL_H_
\ No newline at end of file
--- a/variables.h
+++ /dev/null
@@ -1,1530 +1,0 @@
-#ifndef ZELDA3_VARIABLES_H_
-#define ZELDA3_VARIABLES_H_
-#define main_module_index (*(uint8*)(g_ram+0x10))
-#define submodule_index (*(uint8*)(g_ram+0x11))
-#define nmi_boolean (*(uint8*)(g_ram+0x12))
-#define INIDISP_copy (*(uint8*)(g_ram+0x13))
-#define nmi_load_bg_from_vram (*(uint8*)(g_ram+0x14))
-#define flag_update_cgram_in_nmi (*(uint8*)(g_ram+0x15))
-#define flag_update_hud_in_nmi (*(uint8*)(g_ram+0x16))
-#define nmi_subroutine_index (*(uint8*)(g_ram+0x17))
-#define nmi_copy_packets_flag (*(uint8*)(g_ram+0x18))
-#define nmi_update_tilemap_dst (*(uint8*)(g_ram+0x19))
-#define frame_counter (*(uint8*)(g_ram+0x1A))
-#define player_is_indoors (*(uint8*)(g_ram+0x1B))
-#define TM_copy (*(uint8*)(g_ram+0x1C))
-#define TS_copy (*(uint8*)(g_ram+0x1D))
-#define TMW_copy (*(uint8*)(g_ram+0x1E))
-#define TSW_copy (*(uint8*)(g_ram+0x1F))
-#define link_y_coord (*(uint16*)(g_ram+0x20))
-#define link_x_coord (*(uint16*)(g_ram+0x22))
-#define link_z_coord (*(uint16*)(g_ram+0x24))
-#define link_direction_last (*(uint8*)(g_ram+0x26))
-#define link_actual_vel_y (*(uint8*)(g_ram+0x27))
-#define link_actual_vel_x (*(uint8*)(g_ram+0x28))
-#define link_actual_vel_z (*(uint8*)(g_ram+0x29))
-#define link_subpixel_y (*(uint8*)(g_ram+0x2A))
-#define link_subpixel_x (*(uint8*)(g_ram+0x2B))
-#define link_subpixel_z (*(uint8*)(g_ram+0x2C))
-#define link_counter_var1 (*(uint8*)(g_ram+0x2D))
-#define link_animation_steps (*(uint8*)(g_ram+0x2E))
-#define link_direction_facing (*(uint8*)(g_ram+0x2F))
-#define link_y_vel (*(uint8*)(g_ram+0x30))
-#define link_x_vel (*(uint8*)(g_ram+0x31))
-#define link_y_coord_original (*(uint16*)(g_ram+0x32))
-#define byte_7E0034 (*(uint8*)(g_ram+0x34))
-#define byte_7E0035 (*(uint8*)(g_ram+0x35))
-#define tiledetect_diagonal_tile (*(uint16*)(g_ram+0x38))
-#define button_mask_b_y (*(uint8*)(g_ram+0x3A))
-#define bitfield_for_a_button (*(uint8*)(g_ram+0x3B))
-#define button_b_frames (*(uint8*)(g_ram+0x3C))
-#define link_delay_timer_spin_attack (*(uint8*)(g_ram+0x3D))
-#define link_y_coord_safe_return_lo (*(uint8*)(g_ram+0x3E))
-#define link_x_coord_safe_return_lo (*(uint8*)(g_ram+0x3F))
-#define link_y_coord_safe_return_hi (*(uint8*)(g_ram+0x40))
-#define link_x_coord_safe_return_hi (*(uint8*)(g_ram+0x41))
-#define link_direction_mask_a (*(uint8*)(g_ram+0x42))
-#define link_direction_mask_b (*(uint8*)(g_ram+0x43))
-#define player_oam_y_offset (*(uint8*)(g_ram+0x44))
-#define player_oam_x_offset (*(uint8*)(g_ram+0x45))
-#define link_incapacitated_timer (*(uint8*)(g_ram+0x46))
-#define set_when_damaging_enemies (*(uint8*)(g_ram+0x47))
-#define bitmask_of_dragstate (*(uint8*)(g_ram+0x48))
-#define force_move_any_direction (*(uint16*)(g_ram+0x49))
-#define link_visibility_status (*(uint8*)(g_ram+0x4B))
-#define cape_decrement_counter (*(uint8*)(g_ram+0x4C))
-#define link_auxiliary_state (*(uint8*)(g_ram+0x4D))
-#define byte_7E004E (*(uint8*)(g_ram+0x4E))
-#define index_of_dashing_sfx (*(uint8*)(g_ram+0x4F))
-#define link_cant_change_direction (*(uint8*)(g_ram+0x50))
-#define tiledetect_which_y_pos ((uint16*)(g_ram+0x51))
-#define link_cape_mode (*(uint8*)(g_ram+0x55))
-#define link_is_bunny (*(uint8*)(g_ram+0x56))
-#define link_speed_modifier (*(uint8*)(g_ram+0x57))
-#define tiledetect_stair_tile (*(uint8*)(g_ram+0x58))
-#define tiledetect_pit_tile (*(uint8*)(g_ram+0x59))
-#define link_this_controls_sprite_oam (*(uint8*)(g_ram+0x5A))
-#define player_near_pit_state (*(uint8*)(g_ram+0x5B))
-#define byte_7E005C (*(uint8*)(g_ram+0x5C))
-#define link_player_handler_state (*(uint8*)(g_ram+0x5D))
-#define link_speed_setting (*(uint8*)(g_ram+0x5E))
-#define tiledetect_var2 (*(uint16*)(g_ram+0x5F))
-#define gravestone_push_timeout (*(uint8*)(g_ram+0x61))
-#define tiledetect_var1 (*(uint16*)(g_ram+0x62))
-#define oam_priority_value (*(uint16*)(g_ram+0x64))
-#define link_last_direction_moved_towards (*(uint8*)(g_ram+0x66))
-#define link_direction (*(uint8*)(g_ram+0x67))
-#define link_y_page_movement_delta (*(uint8*)(g_ram+0x68))
-#define link_x_page_movement_delta (*(uint8*)(g_ram+0x69))
-#define link_num_orthogonal_directions (*(uint8*)(g_ram+0x6A))
-#define link_moving_against_diag_tile (*(uint8*)(g_ram+0x6B))
-#define is_standing_in_doorway (*(uint8*)(g_ram+0x6C))
-#define moving_against_diag_deadlocked (*(uint8*)(g_ram+0x6D))
-#define tiledetect_diag_state (*(uint16*)(g_ram+0x6E))
-#define byte_7E0071 (*(uint8*)(g_ram+0x71))
-#define scratch_b (*(uint8*)(g_ram+0x72))
-#define scratch_a (*(uint8*)(g_ram+0x73))
-#define scratch_c (*(uint8*)(g_ram+0x74))
-#define scratch_d (*(uint8*)(g_ram+0x75))
-#define index_of_interacting_tile (*(uint16*)(g_ram+0x76))
-#define allow_scroll_z (*(uint8*)(g_ram+0x78))
-#define link_spin_attack_step_counter (*(uint8*)(g_ram+0x79))
-#define last_light_vs_dark_world (*(uint8*)(g_ram+0x7B))
-#define word_7E007E (*(uint16*)(g_ram+0x7E))
-#define map16_load_src_off (*(uint16*)(g_ram+0x84))
-#define map16_load_dst_off (*(uint16*)(g_ram+0x86))
-#define map16_load_var2 (*(uint16*)(g_ram+0x88))
-#define overworld_screen_index (*(uint16*)(g_ram+0x8A))
-#define overlay_index (*(uint16*)(g_ram+0x8C))
-#define oam_cur_ptr (*(uint16*)(g_ram+0x90))
-#define oam_ext_cur_ptr (*(uint16*)(g_ram+0x92))
-#define BGMODE_copy (*(uint8*)(g_ram+0x94))
-#define MOSAIC_copy (*(uint8*)(g_ram+0x95))
-#define W12SEL_copy (*(uint8*)(g_ram+0x96))
-#define W34SEL_copy (*(uint8*)(g_ram+0x97))
-#define WOBJSEL_copy (*(uint8*)(g_ram+0x98))
-#define CGWSEL_copy (*(uint8*)(g_ram+0x99))
-#define CGADSUB_copy (*(uint8*)(g_ram+0x9A))
-#define HDMAEN_copy (*(uint8*)(g_ram+0x9B))
-#define COLDATA_copy0 (*(uint8*)(g_ram+0x9C))
-#define COLDATA_copy1 (*(uint8*)(g_ram+0x9D))
-#define COLDATA_copy2 (*(uint8*)(g_ram+0x9E))
-#define dungeon_room_index (*(uint16*)(g_ram+0xA0))
-#define dungeon_room_index_prev (*(uint16*)(g_ram+0xA2))
-#define dung_cur_floor (*(uint8*)(g_ram+0xA4))
-#define quadrant_fullsize_x (*(uint8*)(g_ram+0xA6))
-#define quadrant_fullsize_y (*(uint8*)(g_ram+0xA7))
-#define composite_of_layout_and_quadrant (*(uint8*)(g_ram+0xA8))
-#define link_quadrant_x (*(uint8*)(g_ram+0xA9))
-#define link_quadrant_y (*(uint8*)(g_ram+0xAA))
-#define dung_hdr_collision_2 (*(uint8*)(g_ram+0xAD))
-#define dung_hdr_tag ((uint8*)(g_ram+0xAE))
-#define subsubmodule_index (*(uint8*)(g_ram+0xB0))
-#define subsubmodule_index_PADDING (*(uint8*)(g_ram+0xB1))
-#define dung_draw_width_indicator (*(uint16*)(g_ram+0xB2))
-#define dung_draw_height_indicator (*(uint16*)(g_ram+0xB4))
-#define dung_load_ptr (*(uint16*)(g_ram+0xB7))
-#define dung_load_ptr_bank (*(uint8*)(g_ram+0xB9))
-#define dung_load_ptr_offs (*(uint16*)(g_ram+0xBA))
-#define hud_tmp1 (*(uint16*)(g_ram+0xBD))
-
-#define some_menu_ctr (*(uint8*)(g_ram+0xc8))
-#define dung_line_ptrs_row3 (*(uint16*)(g_ram+0xDA))
-#define dung_line_ptrs_row4 (*(uint16*)(g_ram+0xDD))
-#define BG1HOFS_copy2 (*(uint16*)(g_ram+0xE0))
-#define BG2HOFS_copy2 (*(uint16*)(g_ram+0xE2))
-#define BG3HOFS_copy2 (*(uint16*)(g_ram+0xE4))
-#define BG1VOFS_copy2 (*(uint16*)(g_ram+0xE6))
-#define BG2VOFS_copy2 (*(uint16*)(g_ram+0xE8))
-#define BG3VOFS_copy2 (*(uint16*)(g_ram+0xEA))
-#define tilemap_location_calc_mask (*(uint16*)(g_ram+0xEC))
-#define link_is_on_lower_level (*(uint8*)(g_ram+0xEE))
-#define room_transitioning_flags (*(uint8*)(g_ram+0xEF))
-#define joypad1H_last (*(uint8*)(g_ram+0xF0))
-#define joypad1L_last (*(uint8*)(g_ram+0xF2))
-#define filtered_joypad_H (*(uint8*)(g_ram+0xF4))
-#define filtered_joypad_L (*(uint8*)(g_ram+0xF6))
-#define joypad1H_last2 (*(uint8*)(g_ram+0xF8))
-#define byte_7E00F9 (*(uint8*)(g_ram+0xF9))
-#define joypad1L_last2 (*(uint8*)(g_ram+0xFA))
-#define dung_unk2 (*(uint16*)(g_ram+0xFC))
-#define virq_trigger (*(uint8*)(g_ram+0xFF))
-#define link_dma_graphics_index (*(uint16*)(g_ram+0x100))
-#define link_dma_var1 (*(uint16*)(g_ram+0x102))
-#define link_dma_var2 (*(uint16*)(g_ram+0x104))
-#define link_dma_var3 (*(uint8*)(g_ram+0x107))
-#define link_dma_var4 (*(uint8*)(g_ram+0x108))
-#define link_dma_var5 (*(uint8*)(g_ram+0x109))
-#define death_var5 (*(uint8*)(g_ram+0x10A))
-#define saved_module_for_menu (*(uint8*)(g_ram+0x10C))
-#define which_entrance (*(uint8*)(g_ram+0x10E))
-#define byte_7E010F (*(uint8*)(g_ram+0x10F))
-#define dung_index_x3 (*(uint16*)(g_ram+0x110))
-#define flag_custom_spell_anim_active (*(uint8*)(g_ram+0x112))
-#define link_tile_below (*(uint8*)(g_ram+0x114))
-#define link_tile_below_PADDING (*(uint8*)(g_ram+0x115))
-#define nmi_load_target_addr (*(uint16*)(g_ram+0x116))
-#define nmi_update_tilemap_src (*(uint16*)(g_ram+0x118))
-#define bg1_x_offset (*(uint16*)(g_ram+0x11A))
-#define bg1_y_offset (*(uint16*)(g_ram+0x11C))
-#define BG2HOFS_copy (*(uint16*)(g_ram+0x11E))
-#define BG1HOFS_copy (*(uint16*)(g_ram+0x120))
-#define BG2VOFS_copy (*(uint16*)(g_ram+0x122))
-#define BG1VOFS_copy (*(uint16*)(g_ram+0x124))
-#define transition_counter (*(uint8*)(g_ram+0x126))
-#define irq_flag (*(uint8*)(g_ram+0x128))
-#define is_nmi_thread_active (*(uint8*)(g_ram+0x12A))
-#define music_control (*(uint8*)(g_ram+0x12C))
-#define sound_effect_ambient (*(uint8*)(g_ram+0x12D))
-#define sound_effect_1 (*(uint8*)(g_ram+0x12E))
-#define sound_effect_2 (*(uint8*)(g_ram+0x12F))
-#define music_unk1 (*(uint8*)(g_ram+0x130))
-#define sound_effect_ambient_last (*(uint8*)(g_ram+0x131))
-#define queued_music_control (*(uint8*)(g_ram+0x132))
-#define last_music_control (*(uint8*)(g_ram+0x133))
-#define animated_tile_vram_addr (*(uint16*)(g_ram+0x134))
-#define flag_which_music_type (*(uint8*)(g_ram+0x136))
-#define stk_return_addr (*(uint16*)(g_ram+0x1FE))
-#define overworld_map_state (*(uint8*)(g_ram+0x200))
-#define hud_cur_item (*(uint8*)(g_ram+0x202))
-
-#define hud_var1 (*(uint8*)(g_ram+0x204))
-#define bottle_menu_expand_row (*(uint8*)(g_ram+0x205))
-#define byte_7E0206 (*(uint8*)(g_ram+0x206))
-#define timer_for_flashing_circle (*(uint8*)(g_ram+0x207))
-#define animate_heart_refill_countdown (*(uint8*)(g_ram+0x208))
-#define animate_heart_refill_countdown_subpos (*(uint8*)(g_ram+0x209))
-#define is_doing_heart_animation (*(uint8*)(g_ram+0x20A))
-#define link_debug_value_1 (*(uint8*)(g_ram+0x20B))
-#define dungmap_init_state (*(uint8*)(g_ram+0x20D))
-#define dungmap_cur_floor (*(uint16*)(g_ram+0x20E))
-#define dungmap_var2 (*(uint8*)(g_ram+0x210))
-#define dungmap_idx (*(uint16*)(g_ram+0x211))
-#define dungmap_var4 (*(uint16*)(g_ram+0x213))
-#define dungmap_var3 (*(uint16*)(g_ram+0x215))
-#define dungmap_var5 (*(uint16*)(g_ram+0x217))
-#define word_7E0219 (*(uint16*)(g_ram+0x219))
-#define word_7E021D (*(uint16*)(g_ram+0x21D))
-#define word_7E021F (*(uint16*)(g_ram+0x21F))
-#define word_7E0221 (*(uint16*)(g_ram+0x221))
-#define byte_7E0223 (*(uint8*)(g_ram+0x223))
-#define ancilla_objprio ((uint8*)(g_ram+0x280))
-#define ancilla_U ((uint8*)(g_ram+0x28A))
-#define ancilla_z_vel ((uint8*)(g_ram+0x294))
-#define ancilla_z ((uint8*)(g_ram+0x29E))
-#define ancilla_z_subpixel ((uint8*)(g_ram+0x2A8))
-#define tiledetect_inroom_staircase (*(uint16*)(g_ram+0x2C0))
-#define byte_7E02C2 (*(uint8*)(g_ram+0x2C2))
-#define pushedblocks_some_index (*(uint8*)(g_ram+0x2C3))
-#define pushedblocks_maybe_timeout (*(uint8*)(g_ram+0x2C4))
-#define byte_7E02C5 (*(uint8*)(g_ram+0x2C5))
-#define link_recoilmode_timer (*(uint8*)(g_ram+0x2C6))
-#define link_actual_vel_z_copy (*(uint8*)(g_ram+0x2C7))
-#define byte_7E02C9 (*(uint8*)(g_ram+0x2C9))
-#define fallhole_var2 (*(uint8*)(g_ram+0x2CA))
-#define swimming_countdown (*(uint8*)(g_ram+0x2CB))
-#define byte_7E02CC (*(uint8*)(g_ram+0x2CC))
-#define word_7E02CD (*(uint16*)(g_ram+0x2CD))
-#define tagalong_var2 (*(uint8*)(g_ram+0x2CF))
-#define tagalong_var3 (*(uint8*)(g_ram+0x2D0))
-#define tagalong_var7 (*(uint8*)(g_ram+0x2D1))
-#define timer_tagalong_reacquire (*(uint8*)(g_ram+0x2D2))
-#define tagalong_var1 (*(uint8*)(g_ram+0x2D3))
-#define byte_7E02D4 (*(uint8*)(g_ram+0x2D4))
-#define tagalong_var4 (*(uint8*)(g_ram+0x2D6))
-#define byte_7E02D7 (*(uint8*)(g_ram+0x2D7))
-#define link_receiveitem_index (*(uint8*)(g_ram+0x2D8))
-#define link_receiveitem_var1 (*(uint8*)(g_ram+0x2D9))
-#define link_pose_for_item (*(uint8*)(g_ram+0x2DA))
-#define link_triggered_by_whirlpool_sprite (*(uint8*)(g_ram+0x2DB))
-#define link_x_coord_copy (*(uint16*)(g_ram+0x2DC))
-#define link_y_coord_copy (*(uint16*)(g_ram+0x2DE))
-#define link_is_bunny_mirror (*(uint8*)(g_ram+0x2E0))
-#define link_is_transforming (*(uint8*)(g_ram+0x2E1))
-#define link_bunny_transform_timer (*(uint8*)(g_ram+0x2E2))
-#define link_sword_delay_timer (*(uint8*)(g_ram+0x2E3))
-#define flag_is_link_immobilized (*(uint8*)(g_ram+0x2E4))
-#define tiledetect_chest (*(uint16*)(g_ram+0x2E5))
-#define tiledetect_key_lock_gravestones (*(uint8*)(g_ram+0x2E7))
-#define bitfield_spike_cactus_tiles (*(uint8*)(g_ram+0x2E8))
-#define item_receipt_method (*(uint8*)(g_ram+0x2E9))
-#define tiledetect_tile_type (*(uint16*)(g_ram+0x2EA))
-#define flag_is_ancilla_to_pick_up (*(uint8*)(g_ram+0x2EC))
-#define byte_7E02ED (*(uint8*)(g_ram+0x2ED))
-#define tiledetect_spike_floor_and_tile_triggers (*(uint8*)(g_ram+0x2EE))
-#define bitmask_for_dashable_tiles (*(uint8*)(g_ram+0x2EF))
-#define byte_7E02F0 (*(uint8*)(g_ram+0x2F0))
-#define link_dash_ctr (*(uint8*)(g_ram+0x2F1))
-#define tagalong_event_flags (*(uint8*)(g_ram+0x2F2))
-#define byte_7E02F3 (*(uint8*)(g_ram+0x2F3))
-#define flag_is_sprite_to_pick_up_cached (*(uint8*)(g_ram+0x2F4))
-#define player_on_somaria_platform (*(uint8*)(g_ram+0x2F5))
-#define tiledetect_misc_tiles (*(uint16*)(g_ram+0x2F6))
-#define link_want_make_noise_when_dashed (*(uint8*)(g_ram+0x2F8))
-#define tagalong_var5 (*(uint8*)(g_ram+0x2F9))
-#define link_is_near_moveable_statue (*(uint8*)(g_ram+0x2FA))
-#define player_handler_timer (*(uint8*)(g_ram+0x300))
-#define link_item_in_hand (*(uint8*)(g_ram+0x301))
-#define fallhole_var1 (*(uint8*)(g_ram+0x302))
-#define current_item_y (*(uint8*)(g_ram+0x303))
-#define current_item_active (*(uint8*)(g_ram+0x304))
-#define debug_var2 (*(uint8*)(g_ram+0x305))
-#define unused_2 (*(uint8*)(g_ram+0x306))
-#define eq_selected_rod (*(uint8*)(g_ram+0x307))
-#define link_state_bits (*(uint8*)(g_ram+0x308))
-#define link_picking_throw_state (*(uint8*)(g_ram+0x309))
-#define some_animation_timer_steps (*(uint8*)(g_ram+0x30A))
-#define some_animation_timer (*(uint8*)(g_ram+0x30B))
-#define link_var30d (*(uint8*)(g_ram+0x30D))
-#define link_var30e (*(uint8*)(g_ram+0x30E))
-#define dung_floor_y_vel (*(uint16*)(g_ram+0x310))
-#define dung_floor_x_vel (*(uint16*)(g_ram+0x312))
-#define flag_is_sprite_to_pick_up (*(uint8*)(g_ram+0x314))
-#define tile_coll_flag (*(uint8*)(g_ram+0x315))
-#define byte_7E0316 (*(uint8*)(g_ram+0x316))
-#define byte_7E0317 (*(uint8*)(g_ram+0x317))
-#define related_to_moving_floor_y (*(uint16*)(g_ram+0x318))
-#define related_to_moving_floor_x (*(uint16*)(g_ram+0x31A))
-#define state_for_spin_attack (*(uint8*)(g_ram+0x31C))
-#define step_counter_for_spin_attack (*(uint8*)(g_ram+0x31D))
-#define link_spin_offsets (*(uint8*)(g_ram+0x31E))
-#define countdown_for_blink (*(uint8*)(g_ram+0x31F))
-#define tiledetect_moving_floor_tiles (*(uint16*)(g_ram+0x320))
-#define byte_7E0322 (*(uint8*)(g_ram+0x322))
-#define link_direction_facing_mirror (*(uint8*)(g_ram+0x323))
-#define byte_7E0324 (*(uint8*)(g_ram+0x324))
-#define byte_7E0325 (*(uint8*)(g_ram+0x325))
-#define swimcoll_var3 ((uint16*)(g_ram+0x326))
-#define link_maybe_swim_faster (*(uint8*)(g_ram+0x32A))
-#define swimcoll_var5 ((uint16*)(g_ram+0x32B))
-#define swimcoll_var1 ((uint16*)(g_ram+0x32F))
-#define byte_7E0333 (*(uint8*)(g_ram+0x333))
-#define swimcoll_var9 ((uint16*)(g_ram+0x334))
-#define swimcoll_var11 ((uint16*)(g_ram+0x338))
-#define swimcoll_var7 ((uint16*)(g_ram+0x33C))
-#define link_some_direction_bits (*(uint8*)(g_ram+0x340))
-#define tiledetect_deepwater (*(uint16*)(g_ram+0x341))
-#define tiledetect_normal_tiles (*(uint16*)(g_ram+0x343))
-#define link_is_in_deep_water (*(uint8*)(g_ram+0x345))
-#define link_palette_bits_of_oam (*(uint16*)(g_ram+0x346))
-#define tiledetect_icy_floor (*(uint16*)(g_ram+0x348))
-#define link_flag_moving (*(uint8*)(g_ram+0x34A))
-#define eq_debug_variable (*(uint8*)(g_ram+0x34B))
-#define tiledetect_water_staircase (*(uint16*)(g_ram+0x34C))
-#define byte_7E034E (*(uint8*)(g_ram+0x34E))
-#define link_swim_hard_stroke (*(uint8*)(g_ram+0x34F))
-#define link_debug_value_2 (*(uint8*)(g_ram+0x350))
-#define draw_water_ripples_or_grass (*(uint8*)(g_ram+0x351))
-#define sort_sprites_offset_into_oam_buffer (*(uint16*)(g_ram+0x352))
-#define value_computed_for_player_oam (*(uint8*)(g_ram+0x354))
-#define secondary_water_grass_timer (*(uint8*)(g_ram+0x355))
-#define primary_water_grass_timer (*(uint8*)(g_ram+0x356))
-#define tiledetect_thick_grass (*(uint16*)(g_ram+0x357))
-#define tiledetect_shallow_water (*(uint16*)(g_ram+0x359))
-#define tiledetect_destruction_aftermath (*(uint16*)(g_ram+0x35B))
-#define oam_priority_value_2 (*(uint16*)(g_ram+0x35D))
-#define flag_for_boomerang_in_place (*(uint8*)(g_ram+0x35F))
-#define link_electrocute_on_touch (*(uint8*)(g_ram+0x360))
-#define link_actual_vel_z_mirror (*(uint8*)(g_ram+0x362))
-#define link_actual_vel_z_copy_mirror (*(uint8*)(g_ram+0x363))
-#define link_z_coord_mirror (*(uint16*)(g_ram+0x364))
-#define tiledetect_read_something (*(uint16*)(g_ram+0x366))
-#define interacting_with_liftable_tile_x1 (*(uint8*)(g_ram+0x368))
-#define interacting_with_liftable_tile_x1b (*(uint8*)(g_ram+0x369))
-#define interacting_with_liftable_tile_x2 (*(uint8*)(g_ram+0x36A))
-#define player_unk1 (*(uint8*)(g_ram+0x36B))
-#define tile_action_index (*(uint8*)(g_ram+0x36C))
-#define tiledetect_vertical_ledge (*(uint8*)(g_ram+0x36D))
-#define detection_of_ledge_tiles_horiz_uphoriz (*(uint8*)(g_ram+0x36E))
-#define tiledetect_ledges_down_leftright (*(uint8*)(g_ram+0x36F))
-#define detection_of_unknown_tile_types (*(uint8*)(g_ram+0x370))
-#define link_timer_push_get_tired (*(uint8*)(g_ram+0x371))
-#define link_is_running (*(uint8*)(g_ram+0x372))
-#define link_give_damage (*(uint8*)(g_ram+0x373))
-#define link_countdown_for_dash (*(uint8*)(g_ram+0x374))
-#define link_timer_jump_ledge (*(uint8*)(g_ram+0x375))
-#define link_grabbing_wall (*(uint8*)(g_ram+0x376))
-#define link_unk_master_sword (*(uint8*)(g_ram+0x377))
-#define countdown_timer_for_staircases (*(uint8*)(g_ram+0x378))
-#define byte_7E0379 (*(uint8*)(g_ram+0x379))
-#define link_position_mode (*(uint8*)(g_ram+0x37A))
-#define link_disable_sprite_damage (*(uint8*)(g_ram+0x37B))
-#define player_sleep_in_bed_state (*(uint8*)(g_ram+0x37C))
-#define link_pose_during_opening (*(uint8*)(g_ram+0x37D))
-#define related_to_hookshot (*(uint8*)(g_ram+0x37E))
-#define cheatWalkThroughWalls (*(uint8*)(g_ram+0x37F))
-#define ancilla_K ((uint8*)(g_ram+0x380))
-#define ancilla_L ((uint8*)(g_ram+0x385))
-#define ancilla_A ((uint8*)(g_ram+0x38A))
-#define ancilla_B ((uint8*)(g_ram+0x38F))
-#define ancilla_G ((uint8*)(g_ram+0x394))
-#define boomerang_temp_y (*(uint16*)(g_ram+0x399))
-#define boomerang_temp_x (*(uint16*)(g_ram+0x39B))
-#define hookshot_effect_index (*(uint8*)(g_ram+0x39D))
-#define ancilla_arr3 ((uint8*)(g_ram+0x39F))
-#define ancilla_arr1 ((uint8*)(g_ram+0x3A4))
-#define ancilla_S ((uint8*)(g_ram+0x3A9))
-#define ancilla_aux_timer ((uint8*)(g_ram+0x3B1))
-
-// relocated those so they have 5 entries each
-#define door_debris_x ((uint16*)(g_ram+0x728))
-#define door_debris_y ((uint16*)(g_ram+0x732))
-#define door_debris_direction ((uint8*)(g_ram+0x73c))
-#define ancilla_arr26 ((uint8*)(g_ram+0x741))
-#define ancilla_arr25 ((uint8*)(g_ram+0x746))
-#define ancilla_arr22 ((uint8*)(g_ram+0x74b))
-
-#define ancilla_alloc_rotate (*(uint8*)(g_ram+0x3C4))
-#define ancilla_H ((uint8*)(g_ram+0x3C5))
-#define ancilla_floor2 ((uint8*)(g_ram+0x3CA))
-
-// extended the size of this array by merging it with the adjacent one
-#define ancilla_arr23 ((uint8*)(g_ram+0x3CF))
-#define ancilla_T ((uint8*)(g_ram+0x3D5))
-#define ancilla_arr24 ((uint8*)(g_ram+0x3DB))
-#define ancilla_tile_attr ((uint8*)(g_ram+0x3E4))
-#define link_something_with_hookshot (*(uint8*)(g_ram+0x3E9))
-#define ancilla_R ((uint8*)(g_ram+0x3EA))
-#define link_force_hold_sword_up (*(uint8*)(g_ram+0x3EF))
-#define flute_countdown (*(uint8*)(g_ram+0x3F0))
-#define tiledetect_var4 (*(uint16*)(g_ram+0x3F1))
-#define link_on_conveyor_belt (*(uint8*)(g_ram+0x3F3))
-#define dung_unk6 (*(uint8*)(g_ram+0x3F4))
-#define link_timer_tempbunny (*(uint16*)(g_ram+0x3F5))
-#define link_need_for_poof_for_transform (*(uint8*)(g_ram+0x3F7))
-#define link_need_for_pullforrupees_sprite (*(uint8*)(g_ram+0x3F8))
-#define hookshot_var1 (*(uint8*)(g_ram+0x3F9))
-#define bit9_of_xcoord (*(uint16*)(g_ram+0x3FA))
-#define is_archer_or_shovel_game (*(uint8*)(g_ram+0x3FC))
-#define byte_7E03FD (*(uint8*)(g_ram+0x3FD))
-#define dung_door_opened (*(uint16*)(g_ram+0x400))
-#define dung_savegame_state_bits (*(uint16*)(g_ram+0x402))
-#define word_7E0405 (*(uint16*)(g_ram+0x405))
-#define dung_quadrants_visited (*(uint16*)(g_ram+0x408))
-#define overworld_area_index (*(uint16*)(g_ram+0x40A))
-#define cur_palace_index_x2 (*(uint16*)(g_ram+0x40C))
-#define dung_layout_and_starting_quadrant (*(uint16*)(g_ram+0x40E))
-#define overworld_screen_trans_dir_bits (*(uint16*)(g_ram+0x410))
-#define incremental_counter_for_vram (*(uint8*)(g_ram+0x412))
-#define dung_hdr_bg2_properties (*(uint8*)(g_ram+0x414))
-#define dung_hdr_bg2_properties_PADDING (*(uint8*)(g_ram+0x415))
-#define overworld_screen_trans_dir_bits2 (*(uint16*)(g_ram+0x416))
-#define overworld_screen_transition (*(uint8*)(g_ram+0x418))
-#define overworld_screen_transition_ALWAYSZERO (*(uint8*)(g_ram+0x419))
-#define dung_floor_move_flags (*(uint16*)(g_ram+0x41A))
-#define dung_some_subpixel ((uint8*)(g_ram+0x41C))
-#define moving_wall_var2 (*(uint8*)(g_ram+0x41E))
-#define word_7E0420 (*(uint16*)(g_ram+0x420))
-#define dung_floor_x_offs (*(uint16*)(g_ram+0x422))
-#define dung_floor_y_offs (*(uint16*)(g_ram+0x424))
-#define dung_hdr_collision_2_mirror (*(uint8*)(g_ram+0x428))
-#define dung_hdr_collision_2_mirror_PADDING (*(uint8*)(g_ram+0x429))
-#define moving_wall_var1 (*(uint16*)(g_ram+0x42A))
-#define dung_misc_objs_index (*(uint16*)(g_ram+0x42C))
-#define dung_index_of_torches (*(uint16*)(g_ram+0x42E))
-#define dung_door_switch_triggered (*(uint8*)(g_ram+0x430))
-#define dung_num_star_shaped_switches (*(uint16*)(g_ram+0x432))
-#define invisible_door_dir_and_index_x2 (*(uint16*)(g_ram+0x436))
-#define dung_num_inter_room_upnorth_stairs (*(uint16*)(g_ram+0x438))
-#define dung_num_inter_room_southdown_stairs (*(uint16*)(g_ram+0x43A))
-#define dung_num_inroom_upnorth_stairs (*(uint16*)(g_ram+0x43C))
-#define dung_num_inroom_southdown_stairs (*(uint16*)(g_ram+0x43E))
-#define dung_num_interpseudo_upnorth_stairs (*(uint16*)(g_ram+0x440))
-#define dung_num_inroom_upnorth_stairs_water (*(uint16*)(g_ram+0x442))
-#define dung_num_activated_water_ladders (*(uint16*)(g_ram+0x444))
-#define dung_num_water_ladders (*(uint16*)(g_ram+0x446))
-#define dung_some_stairs_unk4 (*(uint16*)(g_ram+0x448))
-#define kind_of_in_room_staircase (*(uint16*)(g_ram+0x44A))
-#define dung_num_toggle_floor (*(uint16*)(g_ram+0x44E))
-#define dung_num_toggle_palace (*(uint16*)(g_ram+0x450))
-#define dung_blastwall_flag_x (*(uint8*)(g_ram+0x452))
-#define dung_blastwall_flag_y (*(uint8*)(g_ram+0x453))
-#define dung_unk_blast_walls_2 (*(uint16*)(g_ram+0x454))
-#define dung_unk_blast_walls_3 (*(uint16*)(g_ram+0x456))
-#define hdr_dungeon_dark_with_lantern (*(uint8*)(g_ram+0x458))
-#define hdr_dungeon_dark_with_lantern_PADDING (*(uint8*)(g_ram+0x459))
-#define dung_num_lit_torches (*(uint8*)(g_ram+0x45A))
-#define dung_num_lit_torches_PADDING (*(uint8*)(g_ram+0x45B))
-#define dung_cur_quadrant_upload (*(uint8*)(g_ram+0x45C))
-#define dung_cur_quadrant_upload_PADDING (*(uint8*)(g_ram+0x45D))
-#define word_7E045E (*(uint16*)(g_ram+0x45E))
-#define dung_cur_door_idx (*(uint16*)(g_ram+0x460))
-#define which_staircase_index (*(uint8*)(g_ram+0x462))
-#define which_staircase_index_PADDING (*(uint8*)(g_ram+0x463))
-#define staircase_var1 (*(uint8*)(g_ram+0x464))
-#define related_to_trapdoors_somehow (*(uint16*)(g_ram+0x466))
-#define dung_flag_trapdoors_down (*(uint16*)(g_ram+0x468))
-#define dung_floor_2_filler_tiles (*(uint16*)(g_ram+0x46A))
-#define dung_hdr_collision (*(uint8*)(g_ram+0x46C))
-#define watergate_var1 (*(uint8*)(g_ram+0x470))
-#define watergate_var1_PADDING (*(uint8*)(g_ram+0x471))
-#define watergate_pos (*(uint16*)(g_ram+0x472))
-#define push_block_direction (*(uint8*)(g_ram+0x474))
-#define link_is_on_lower_level_mirror (*(uint8*)(g_ram+0x476))
-#define dung_index_of_torches_start (*(uint16*)(g_ram+0x478))
-#define about_to_jump_off_ledge (*(uint8*)(g_ram+0x47A))
-#define word_7E047C (*(uint16*)(g_ram+0x47C))
-#define dung_num_wall_upnorth_spiral_stairs (*(uint16*)(g_ram+0x47E))
-#define dung_num_wall_downnorth_spiral_stairs (*(uint16*)(g_ram+0x480))
-#define dung_num_wall_upnorth_spiral_stairs_2 (*(uint16*)(g_ram+0x482))
-#define dung_num_wall_downnorth_spiral_stairs_2 (*(uint16*)(g_ram+0x484))
-#define word_7E0486 (*(uint16*)(g_ram+0x486))
-#define word_7E0488 (*(uint16*)(g_ram+0x488))
-#define cur_staircase_plane (*(uint8*)(g_ram+0x48A))
-#define word_7E048C (*(uint16*)(g_ram+0x48C))
-#define dungeon_room_index2 (*(uint16*)(g_ram+0x48E))
-#define dung_floor_1_filler_tiles (*(uint16*)(g_ram+0x490))
-#define byte_7E0492 (*(uint8*)(g_ram+0x492))
-#define move_overlay_ctr (*(uint8*)(g_ram+0x494))
-#define dung_num_chests_x2 (*(uint16*)(g_ram+0x496))
-#define dung_num_bigkey_locks_x2 (*(uint16*)(g_ram+0x498))
-#define dung_num_stairs_1 (*(uint16*)(g_ram+0x49A))
-#define dung_num_stairs_2 (*(uint16*)(g_ram+0x49C))
-#define dung_num_stairs_wet (*(uint16*)(g_ram+0x49E))
-#define hud_floor_changed_timer (*(uint8*)(g_ram+0x4A0))
-#define dung_num_inter_room_upnorth_straight_stairs (*(uint16*)(g_ram+0x4A2))
-#define dung_num_inter_room_upsouth_straight_stairs (*(uint16*)(g_ram+0x4A4))
-#define dung_num_inter_room_downnorth_straight_stairs (*(uint16*)(g_ram+0x4A6))
-#define dung_num_inter_room_downsouth_straight_stairs (*(uint16*)(g_ram+0x4A8))
-#define death_var4 (*(uint8*)(g_ram+0x4AA))
-#define num_memorized_tiles (*(uint16*)(g_ram+0x4AC))
-#define dung_num_inroom_upsouth_stairs_water (*(uint16*)(g_ram+0x4AE))
-#define dung_unk5 (*(uint16*)(g_ram+0x4B0))
-#define word_7E04B2 (*(uint16*)(g_ram+0x4B2))
-#define super_bomb_indicator_unk2 (*(uint8*)(g_ram+0x4B4))
-#define super_bomb_indicator_unk1 (*(uint8*)(g_ram+0x4B5))
-#define word_7E04B6 (*(uint16*)(g_ram+0x4B6))
-#define big_key_door_message_triggered (*(uint16*)(g_ram+0x4B8))
-#define dung_overlay_to_load (*(uint8*)(g_ram+0x4BA))
-#define byte_7E04BC (*(uint8*)(g_ram+0x4BC))
-#define byte_7E04BE (*(uint8*)(g_ram+0x4BE))
-#define byte_7E04BF (*(uint8*)(g_ram+0x4BF))
-#define byte_7E04C0 (*(uint8*)(g_ram+0x4C0))
-#define byte_7E04C1 (*(uint8*)(g_ram+0x4C1))
-#define byte_7E04C2 (*(uint8*)(g_ram+0x4C2))
-#define minigame_credits (*(uint8*)(g_ram+0x4C4))
-#define byte_7E04C5 (*(uint8*)(g_ram+0x4C5))
-#define trigger_special_entrance (*(uint8*)(g_ram+0x4C6))
-#define flag_skip_call_tag_routines (*(uint8*)(g_ram+0x4C7))
-#define word_7E04C8 (*(uint16*)(g_ram+0x4C8))
-#define link_lowlife_countdown_timer_beep (*(uint8*)(g_ram+0x4CA))
-#define dung_torch_timers ((uint8*)(g_ram+0x4F0))
-#define dung_replacement_tile_state ((uint16*)(g_ram+0x500))
-#define dung_object_pos_in_objdata ((uint16*)(g_ram+0x520))
-#define dung_object_tilemap_pos ((uint16*)(g_ram+0x540))
-#define replacement_tilemap_UL ((uint16*)(g_ram+0x560))
-#define replacement_tilemap_LL ((uint16*)(g_ram+0x580))
-#define replacement_tilemap_UR ((uint16*)(g_ram+0x5A0))
-#define replacement_tilemap_LR ((uint16*)(g_ram+0x5C0))
-#define pushedblocks_x_hi ((uint16*)(g_ram+0x5E0))
-#define pushedblocks_x_lo ((uint16*)(g_ram+0x5E4))
-#define pushedblocks_target ((uint16*)(g_ram+0x5E8))
-#define pushedblocks_y_hi ((uint16*)(g_ram+0x5EC))
-#define pushedblocks_y_lo ((uint16*)(g_ram+0x5F0))
-#define pushedblocks_subpixel ((uint16*)(g_ram+0x5F4))
-#define pushedblock_facing ((uint16*)(g_ram+0x5F8))
-#define index_of_changable_dungeon_objs ((uint8*)(g_ram+0x5FC))
-#define up_down_scroll_target (*(uint16*)(g_ram+0x610))
-#define up_down_scroll_target_end (*(uint16*)(g_ram+0x612))
-#define left_right_scroll_target (*(uint16*)(g_ram+0x614))
-#define left_right_scroll_target_end (*(uint16*)(g_ram+0x616))
-#define camera_y_coord_scroll_low (*(uint16*)(g_ram+0x618))
-#define camera_y_coord_scroll_hi (*(uint16*)(g_ram+0x61A))
-#define camera_x_coord_scroll_low (*(uint16*)(g_ram+0x61C))
-#define camera_x_coord_scroll_hi (*(uint16*)(g_ram+0x61E))
-#define BG1HOFS_subpixel (*(uint16*)(g_ram+0x620))
-#define BG1VOFS_subpixel (*(uint16*)(g_ram+0x622))
-#define overworld_unk1 (*(uint16*)(g_ram+0x624))
-#define overworld_unk1_neg (*(uint16*)(g_ram+0x626))
-#define overworld_unk3 (*(uint16*)(g_ram+0x628))
-#define overworld_unk3_neg (*(uint16*)(g_ram+0x62A))
-#define dung_loade_bgoffs_h_copy (*(uint16*)(g_ram+0x62C))
-#define dung_loade_bgoffs_v_copy (*(uint16*)(g_ram+0x62E))
-#define byte_7E0630 (*(uint8*)(g_ram+0x630))
-#define byte_7E0631 (*(uint8*)(g_ram+0x631))
-#define byte_7E0635 (*(uint8*)(g_ram+0x635))
-#define overworld_map_flags (*(uint8*)(g_ram+0x636))
-#define timer_for_mode7_zoom (*(uint8*)(g_ram+0x637))
-#define M7X_copy (*(uint16*)(g_ram+0x638))
-#define M7Y_copy (*(uint16*)(g_ram+0x63A))
-#define dung_hdr_hole_teleporter_plane (*(uint8*)(g_ram+0x63C))
-#define dung_hdr_staircase_plane ((uint8*)(g_ram+0x63D))
-#define dung_flag_movable_block_was_pushed (*(uint8*)(g_ram+0x641))
-#define dung_flag_statechange_waterpuzzle (*(uint8*)(g_ram+0x642))
-#define dung_flag_somaria_block_switch (*(uint8*)(g_ram+0x646))
-#define mosaic_inc_or_dec (*(uint8*)(g_ram+0x647))
-#define spotlight_var3 (*(uint16*)(g_ram+0x670))
-#define spotlight_y_lower (*(uint16*)(g_ram+0x674))
-#define spotlight_y_upper (*(uint16*)(g_ram+0x676))
-#define word_7E0678 (*(uint16*)(g_ram+0x678))
-#define spotlight_var4 (*(uint16*)(g_ram+0x67A))
-#define spotlight_var1 (*(uint16*)(g_ram+0x67C))
-#define spotlight_var2 (*(uint16*)(g_ram+0x67E))
-#define water_hdma_var0 (*(uint16*)(g_ram+0x680))
-#define water_hdma_var1 (*(uint16*)(g_ram+0x682))
-#define water_hdma_var2 (*(uint16*)(g_ram+0x684))
-#define water_hdma_var3 (*(uint16*)(g_ram+0x686))
-#define water_hdma_var4 (*(uint16*)(g_ram+0x688))
-#define water_hdma_var5 (*(uint16*)(g_ram+0x68A))
-#define dung_door_opened_incl_adjacent (*(uint16*)(g_ram+0x68C))
-#define dung_cur_door_pos (*(uint16*)(g_ram+0x68E))
-#define door_animation_step_indicator (*(uint16*)(g_ram+0x690))
-#define door_open_closed_counter (*(uint16*)(g_ram+0x692))
-#define dung_which_key_x2 (*(uint16*)(g_ram+0x694))
-#define ow_entrance_value (*(uint16*)(g_ram+0x696))
-#define big_rock_starting_address (*(uint16*)(g_ram+0x698))
-#define ow_countdown_transition (*(uint8*)(g_ram+0x69A))
-#define byte_7E069C (*(uint8*)(g_ram+0x69C))
-#define byte_7E069E ((uint8*)(g_ram+0x69E))
-#define dung_toggle_floor_pos ((uint16*)(g_ram+0x6C0))
-#define dung_toggle_palace_pos ((uint16*)(g_ram+0x6D0))
-#define dung_chest_locations ((uint16*)(g_ram+0x6E0))
-#define dung_stairs_table_2 ((uint16*)(g_ram+0x6EC))
-#define current_area_of_player (*(uint16*)(g_ram+0x700))
-#define overworld_offset_base_y (*(uint16*)(g_ram+0x708))
-#define overworld_offset_mask_y (*(uint16*)(g_ram+0x70A))
-#define overworld_offset_base_x (*(uint16*)(g_ram+0x70C))
-#define overworld_offset_mask_x (*(uint16*)(g_ram+0x70E))
-#define nmi_disable_core_updates (*(uint8*)(g_ram+0x710))
-#define overworld_area_is_big (*(uint16*)(g_ram+0x712))
-#define overworld_area_is_big_backup (*(uint8*)(g_ram+0x714))
-#define overworld_right_bottom_bound_for_scroll (*(uint16*)(g_ram+0x716))
-#define vwf_flag_next_line (*(uint16*)(g_ram+0x720))
-#define vwf_curline (*(uint16*)(g_ram+0x722))
-#define vwf_var1 (*(uint16*)(g_ram+0x724))
-#define vwf_line_ptr (*(uint16*)(g_ram+0x726))
-#define extended_oam ((uint8*)(g_ram+0xA00))
-#define bytewise_extended_oam ((uint8*)(g_ram+0xA20))
-#define byte_7E0AA0 (*(uint8*)(g_ram+0xAA0))
-#define main_tile_theme_index (*(uint8*)(g_ram+0xAA1))
-#define aux_tile_theme_index (*(uint8*)(g_ram+0xAA2))
-#define sprite_graphics_index (*(uint8*)(g_ram+0xAA3))
-#define misc_sprites_graphics_index (*(uint8*)(g_ram+0xAA4))
-#define unused_config_gfx (*(uint16*)(g_ram+0xAA6))
-#define overworld_palette_aux_or_main (*(uint16*)(g_ram+0xAA8))
-#define load_chr_halfslot_even_odd (*(uint8*)(g_ram+0xAAA))
-#define palette_sp0l (*(uint8*)(g_ram+0xAAC))
-#define palette_sp5l (*(uint8*)(g_ram+0xAAD))
-#define palette_sp6l (*(uint8*)(g_ram+0xAAE))
-#define byte_7E0AB0 (*(uint8*)(g_ram+0xAB0))
-#define palette_sp6r_indoors (*(uint8*)(g_ram+0xAB1))
-#define hud_palette (*(uint8*)(g_ram+0xAB2))
-#define overworld_palette_mode (*(uint8*)(g_ram+0xAB3))
-#define overworld_palette_aux1_bp2to4_hi (*(uint8*)(g_ram+0xAB4))
-#define overworld_palette_aux2_bp5to7_hi (*(uint8*)(g_ram+0xAB5))
-#define palette_main_indoors (*(uint8*)(g_ram+0xAB6))
-#define byte_7E0AB7 (*(uint8*)(g_ram+0xAB7))
-#define overworld_palette_aux3_bp7_lo (*(uint8*)(g_ram+0xAB8))
-#define palette_swap_flag (*(uint8*)(g_ram+0xABD))
-#define flag_overworld_area_did_change (*(uint8*)(g_ram+0xABF))
-#define dma_source_addr_6 (*(uint16*)(g_ram+0xAC0))
-#define dma_source_addr_11 (*(uint16*)(g_ram+0xAC2))
-#define dma_source_addr_7 (*(uint16*)(g_ram+0xAC4))
-#define dma_source_addr_12 (*(uint16*)(g_ram+0xAC6))
-#define dma_source_addr_8 (*(uint16*)(g_ram+0xAC8))
-#define dma_source_addr_13 (*(uint16*)(g_ram+0xACA))
-#define dma_source_addr_3 (*(uint16*)(g_ram+0xACC))
-#define dma_source_addr_0 (*(uint16*)(g_ram+0xACE))
-#define dma_source_addr_4 (*(uint16*)(g_ram+0xAD0))
-#define dma_source_addr_1 (*(uint16*)(g_ram+0xAD2))
-#define dma_source_addr_5 (*(uint16*)(g_ram+0xAD4))
-#define dma_source_addr_2 (*(uint16*)(g_ram+0xAD6))
-#define dma_source_addr_10 (*(uint16*)(g_ram+0xAD8))
-#define dma_source_addr_15 (*(uint16*)(g_ram+0xADA))
-#define animated_tile_data_src (*(uint16*)(g_ram+0xADC))
-#define dma_source_addr_9 (*(uint16*)(g_ram+0xAE0))
-#define dma_source_addr_14 (*(uint16*)(g_ram+0xAE2))
-#define dma_var6 (*(uint16*)(g_ram+0xAE8))
-#define dma_var7 (*(uint16*)(g_ram+0xAEA))
-#define dma_source_addr_16 (*(uint16*)(g_ram+0xAEC))
-#define dma_source_addr_18 (*(uint16*)(g_ram+0xAEE))
-#define dma_source_addr_17 (*(uint16*)(g_ram+0xAF0))
-#define dma_source_addr_19 (*(uint16*)(g_ram+0xAF2))
-#define flag_travel_bird (*(uint16*)(g_ram+0xAF4))
-#define dma_source_addr_20 (*(uint16*)(g_ram+0xAF6))
-#define dma_source_addr_21 (*(uint16*)(g_ram+0xAF8))
-#define overlord_type ((uint8*)(g_ram+0xB00))
-#define overlord_x_lo ((uint8*)(g_ram+0xB08))
-#define overlord_x_hi ((uint8*)(g_ram+0xB10))
-#define overlord_y_lo ((uint8*)(g_ram+0xB18))
-#define overlord_y_hi ((uint8*)(g_ram+0xB20))
-#define overlord_gen1 ((uint8*)(g_ram+0xB28))
-#define overlord_gen2 ((uint8*)(g_ram+0xB30))
-#define overlord_gen3 ((uint8*)(g_ram+0xB38))
-#define overlord_floor ((uint8*)(g_ram+0xB40))
-#define overlord_offset_sprite_pos ((uint16*)(g_ram+0xB48))
-#define sprite_stunned ((uint8*)(g_ram+0xB58))
-#define repulsespark_floor_status (*(uint8*)(g_ram+0xB68))
-#define byte_7E0B69 (*(uint8*)(g_ram+0xB69))
-#define sprite_limit_instance (*(uint8*)(g_ram+0xB6A))
-#define sprite_flags ((uint8*)(g_ram+0xB6B))
-#define link_prevent_from_moving (*(uint8*)(g_ram+0xB7B))
-#define drag_player_x (*(uint16*)(g_ram+0xB7C))
-#define drag_player_y (*(uint16*)(g_ram+0xB7E))
-#define dungeon_room_history ((uint16*)(g_ram+0xB80))
-#define byte_7E0B88 (*(uint8*)(g_ram+0xB88))
-#define sprite_obj_prio ((uint8*)(g_ram+0xB89))
-#define archery_game_arrows_left (*(uint8*)(g_ram+0xB99))
-#define archery_game_out_of_arrows (*(uint8*)(g_ram+0xB9A))
-#define byte_7E0B9B (*(uint8*)(g_ram+0xB9B))
-#define dung_secrets_unk1 (*(uint16*)(g_ram+0xB9C))
-#define byte_7E0B9E (*(uint8*)(g_ram+0xB9E))
-#define sprite_ignore_projectile ((uint8*)(g_ram+0xBA0))
-#define sprite_unk2 ((uint8*)(g_ram+0xBB0))
-#define sprite_N ((uint8*)(g_ram+0xBC0))
-#define sprite_flags5 ((uint8*)(g_ram+0xBE0))
-#define ancilla_arr4 ((uint8*)(g_ram+0xBF0))
-#define ancilla_y_lo ((uint8*)(g_ram+0xBFA))
-#define ancilla_x_lo ((uint8*)(g_ram+0xC04))
-#define ancilla_y_hi ((uint8*)(g_ram+0xC0E))
-#define ancilla_x_hi ((uint8*)(g_ram+0xC18))
-#define ancilla_y_vel ((uint8*)(g_ram+0xC22))
-#define ancilla_x_vel ((uint8*)(g_ram+0xC2C))
-#define ancilla_y_subpixel ((uint8*)(g_ram+0xC36))
-#define ancilla_x_subpixel ((uint8*)(g_ram+0xC40))
-#define ancilla_type ((uint8*)(g_ram+0xC4A))
-#define ancilla_step ((uint8*)(g_ram+0xC54))
-#define ancilla_item_to_link ((uint8*)(g_ram+0xC5E))
-#define ancilla_timer ((uint8*)(g_ram+0xC68))
-#define ancilla_dir ((uint8*)(g_ram+0xC72))
-#define ancilla_floor ((uint8*)(g_ram+0xC7C))
-#define ancilla_oam_idx ((uint8*)(g_ram+0xC86))
-#define ancilla_numspr ((uint8*)(g_ram+0xC90))
-#define sprite_room ((uint8*)(g_ram+0xC9A))
-#define sprite_defl_bits ((uint8*)(g_ram+0xCAA))
-#define sprite_die_action ((uint8*)(g_ram+0xCBA))
-#define overlord_spawned_in_area ((uint8*)(g_ram+0xCCA))
-#define sprite_bump_damage ((uint8*)(g_ram+0xCD2))
-#define sprite_give_damage ((uint8*)(g_ram+0xCE2))
-#define damage_type_determiner (*(uint8*)(g_ram+0xCF2))
-#define damage_type_determiner_PADDING (*(uint8*)(g_ram+0xCF3))
-#define activate_bomb_trap_overlord (*(uint8*)(g_ram+0xCF4))
-#define dungmap_var6 (*(uint16*)(g_ram+0xCF5))
-#define overworld_secret_subst_ctr (*(uint8*)(g_ram+0xCF7))
-#define byte_7E0CF8 (*(uint8*)(g_ram+0xCF8))
-#define item_drop_luck (*(uint8*)(g_ram+0xCF9))
-#define luck_kill_counter (*(uint8*)(g_ram+0xCFA))
-#define num_sprites_killed (*(uint8*)(g_ram+0xCFB))
-#define number_of_times_hurt_by_sprites (*(uint8*)(g_ram+0xCFC))
-#define rupee_sfx_sound_delay (*(uint8*)(g_ram+0xCFD))
-#define word_7E0CFE (*(uint16*)(g_ram+0xCFE))
-#define sprite_y_lo ((uint8*)(g_ram+0xD00))
-#define sprite_x_lo ((uint8*)(g_ram+0xD10))
-#define sprite_y_hi ((uint8*)(g_ram+0xD20))
-#define sprite_x_hi ((uint8*)(g_ram+0xD30))
-#define sprite_y_vel ((uint8*)(g_ram+0xD40))
-#define sprite_x_vel ((uint8*)(g_ram+0xD50))
-#define sprite_y_subpixel ((uint8*)(g_ram+0xD60))
-#define sprite_x_subpixel ((uint8*)(g_ram+0xD70))
-#define sprite_ai_state ((uint8*)(g_ram+0xD80))
-#define sprite_A ((uint8*)(g_ram+0xD90))
-#define sprite_B ((uint8*)(g_ram+0xDA0))
-#define sprite_C ((uint8*)(g_ram+0xDB0))
-#define sprite_graphics ((uint8*)(g_ram+0xDC0))
-#define sprite_state ((uint8*)(g_ram+0xDD0))
-#define sprite_D ((uint8*)(g_ram+0xDE0))
-#define sprite_delay_main ((uint8*)(g_ram+0xDF0))
-#define sprite_delay_aux1 ((uint8*)(g_ram+0xE00))
-#define sprite_delay_aux2 ((uint8*)(g_ram+0xE10))
-#define sprite_type ((uint8*)(g_ram+0xE20))
-#define sprite_subtype ((uint8*)(g_ram+0xE30))
-#define sprite_flags2 ((uint8*)(g_ram+0xE40))
-#define sprite_health ((uint8*)(g_ram+0xE50))
-#define sprite_flags3 ((uint8*)(g_ram+0xE60))
-#define sprite_wallcoll ((uint8*)(g_ram+0xE70))
-#define sprite_subtype2 ((uint8*)(g_ram+0xE80))
-#define sprite_E ((uint8*)(g_ram+0xE90))
-#define sprite_F ((uint8*)(g_ram+0xEA0))
-#define sprite_head_dir ((uint8*)(g_ram+0xEB0))
-#define sprite_anim_clock ((uint8*)(g_ram+0xEC0))
-#define sprite_G ((uint8*)(g_ram+0xED0))
-#define sprite_delay_aux3 ((uint8*)(g_ram+0xEE0))
-#define sprite_hit_timer ((uint8*)(g_ram+0xEF0))
-#define sprite_pause ((uint8*)(g_ram+0xF00))
-#define sprite_delay_aux4 ((uint8*)(g_ram+0xF10))
-#define sprite_floor ((uint8*)(g_ram+0xF20))
-#define sprite_y_recoil ((uint8*)(g_ram+0xF30))
-#define sprite_x_recoil ((uint8*)(g_ram+0xF40))
-#define sprite_oam_flags ((uint8*)(g_ram+0xF50))
-#define sprite_flags4 ((uint8*)(g_ram+0xF60))
-#define sprite_z ((uint8*)(g_ram+0xF70))
-#define sprite_z_vel ((uint8*)(g_ram+0xF80))
-#define sprite_z_subpos ((uint8*)(g_ram+0xF90))
-#define cur_object_index (*(uint8*)(g_ram+0xFA0))
-#define byte_7E0FA1 (*(uint8*)(g_ram+0xFA1))
-#define sprite_tiletype (*(uint8*)(g_ram+0xFA5))
-#define dungmap_var7 (*(uint16*)(g_ram+0xFA8))
-#define dungmap_var8 (*(uint16*)(g_ram+0xFAA))
-#define repulsespark_timer (*(uint8*)(g_ram+0xFAC))
-#define repulsespark_x_lo (*(uint8*)(g_ram+0xFAD))
-#define repulsespark_y_lo (*(uint8*)(g_ram+0xFAE))
-#define repulsespark_anim_delay (*(uint8*)(g_ram+0xFAF))
-#define byte_7E0FB0 (*(uint8*)(g_ram+0xFB0))
-#define byte_7E0FB1 (*(uint8*)(g_ram+0xFB1))
-#define byte_7E0FB2 (*(uint8*)(g_ram+0xFB2))
-#define sort_sprites_setting (*(uint8*)(g_ram+0xFB3))
-#define garnish_active (*(uint8*)(g_ram+0xFB4))
-#define tmp_counter (*(uint8*)(g_ram+0xFB5))
-#define byte_7E0FB6 (*(uint8*)(g_ram+0xFB6))
-#define spr_ranged_based_toggler (*(uint8*)(g_ram+0xFB7))
-#define sprcoll_x_size (*(uint16*)(g_ram+0xFB8))
-#define sprcoll_y_size (*(uint16*)(g_ram+0xFBA))
-#define sprcoll_x_base (*(uint16*)(g_ram+0xFBC))
-#define sprcoll_y_base (*(uint16*)(g_ram+0xFBE))
-#define flag_unk1 (*(uint8*)(g_ram+0xFC1))
-#define link_x_coord_prev (*(uint16*)(g_ram+0xFC2))
-#define link_y_coord_prev (*(uint16*)(g_ram+0xFC4))
-#define byte_7E0FC6 (*(uint8*)(g_ram+0xFC6))
-#define prizes_arr1 ((uint8*)(g_ram+0xFC7))
-#define debug_game_frozen (*(uint8*)(g_ram+0xFD7))
-#define cur_sprite_x (*(uint16*)(g_ram+0xFD8))
-#define cur_sprite_y (*(uint16*)(g_ram+0xFDA))
-#define sprite_alert_flag (*(uint8*)(g_ram+0xFDC))
-#define byte_7E0FDD (*(uint8*)(g_ram+0xFDD))
-#define byte_7E0FDE (*(uint8*)(g_ram+0xFDE))
-#define oam_region_base ((uint16*)(g_ram+0xFE0))
-#define oam_alloc_arr1 ((uint16*)(g_ram+0xFEC))
-#define byte_7E0FF8 (*(uint8*)(g_ram+0xFF8))
-#define intro_times_pal_flash (*(uint8*)(g_ram+0xFF9))
-#define alt_sprites_flag (*(uint8*)(g_ram+0xFFA))
-#define byte_7E0FFB (*(uint8*)(g_ram+0xFFB))
-#define flag_block_link_menu (*(uint8*)(g_ram+0xFFC))
-#define byte_7E0FFD (*(uint8*)(g_ram+0xFFD))
-#define byte_7E0FFE (*(uint8*)(g_ram+0xFFE))
-#define is_in_dark_world (*(uint8*)(g_ram+0xFFF))
-#define word_7E1800 (*(uint16*)(g_ram+0x1800))
-#define word_7E1806 (*(uint16*)(g_ram+0x1806))
-#define word_7E197E (*(uint16*)(g_ram+0x197E))
-#define door_type_and_slot ((uint16*)(g_ram+0x1980))
-#define dung_door_tilemap_address ((uint16*)(g_ram+0x19A0))
-#define dung_door_direction ((uint16*)(g_ram+0x19C0))
-#define dung_exit_door_count (*(uint16*)(g_ram+0x19E0))
-#define dung_exit_door_addresses ((uint16*)(g_ram+0x19E2))
-#define tagalong_y_lo ((uint8*)(g_ram+0x1A00))
-#define tagalong_y_hi ((uint8*)(g_ram+0x1A14))
-#define tagalong_x_lo ((uint8*)(g_ram+0x1A28))
-#define tagalong_x_hi ((uint8*)(g_ram+0x1A3C))
-#define tagalong_z ((uint8*)(g_ram+0x1A50))
-#define tagalong_layerbits ((uint8*)(g_ram+0x1A64))
-#define bird_travel_x_lo ((uint8*)(g_ram+0x1AB0))
-#define bird_travel_x_hi ((uint8*)(g_ram+0x1AC0))
-#define bird_travel_y_lo ((uint8*)(g_ram+0x1AD0))
-#define bird_travel_y_hi ((uint8*)(g_ram+0x1AE0))
-#define birdtravel_var1 ((uint8*)(g_ram+0x1AF0))
-#define text_msgbox_topleft_copy (*(uint16*)(g_ram+0x1CD0))
-#define text_msgbox_topleft (*(uint16*)(g_ram+0x1CD2))
-#define text_render_state (*(uint8*)(g_ram+0x1CD4))
-#define vwf_line_speed_cur (*(uint8*)(g_ram+0x1CD5))
-#define vwf_line_speed (*(uint8*)(g_ram+0x1CD6))
-#define text_incremental_state (*(uint8*)(g_ram+0x1CD7))
-#define messaging_module (*(uint8*)(g_ram+0x1CD8))
-#define dialogue_msg_read_pos (*(uint16*)(g_ram+0x1CD9))
-#define dialogue_text_color (*(uint8*)(g_ram+0x1CDC))
-#define dialogue_msg_src_offs (*(uint16*)(g_ram+0x1CDD))
-#define byte_7E1CDF (*(uint8*)(g_ram+0x1CDF))
-#define text_wait_countdown (*(uint16*)(g_ram+0x1CE0))
-#define text_tilemap_cur (*(uint16*)(g_ram+0x1CE2))
-#define text_next_position (*(uint8*)(g_ram+0x1CE6))
-#define choice_in_multiselect_box (*(uint8*)(g_ram+0x1CE8))
-#define text_wait_countdown2 (*(uint8*)(g_ram+0x1CE9))
-
-// This seems never nonzero
-#define dialogue_scroll_speed (*(uint8*)(g_ram+0x1CEA))
-#define dialogue_message_index (*(uint16*)(g_ram+0x1CF0))
-#define dialogue_number ((uint8*)(g_ram+0x1CF2))
-#define choice_in_multiselect_box_bak (*(uint8*)(g_ram+0x1CF4))
-#define alt_sprite_state ((uint8*)(g_ram+0x1D00))
-#define alt_sprite_type ((uint8*)(g_ram+0x1D10))
-#define alt_sprite_x_lo ((uint8*)(g_ram+0x1D20))
-#define alt_sprite_x_hi ((uint8*)(g_ram+0x1D30))
-#define alt_sprite_y_lo ((uint8*)(g_ram+0x1D40))
-#define alt_sprite_y_hi ((uint8*)(g_ram+0x1D50))
-#define alt_sprite_graphics ((uint8*)(g_ram+0x1D60))
-#define alt_sprite_A ((uint8*)(g_ram+0x1D70))
-#define alt_sprite_head_dir ((uint8*)(g_ram+0x1D80))
-#define alt_sprite_oam_flags ((uint8*)(g_ram+0x1D90))
-#define alt_sprite_obj_prio ((uint8*)(g_ram+0x1DA0))
-#define alt_sprite_D ((uint8*)(g_ram+0x1DB0))
-#define alt_sprite_flags2 ((uint8*)(g_ram+0x1DC0))
-#define alt_sprite_floor ((uint8*)(g_ram+0x1DD0))
-#define alt_sprite_spawned_flag ((uint8*)(g_ram+0x1DE0))
-#define alt_sprite_flags3 ((uint8*)(g_ram+0x1DF0))
-#define intro_step_index (*(uint8*)(g_ram+0x1E00))
-#define intro_step_timer (*(uint8*)(g_ram+0x1E01))
-#define intro_want_double_ret (*(uint8*)(g_ram+0x1E02))
-#define intro_sprite_alloc (*(uint16*)(g_ram+0x1E08))
-#define intro_frame_ctr (*(uint8*)(g_ram+0x1E0A))
-#define triforce_ctr (*(uint16*)(g_ram+0x1E0C))
-#define intro_sprite_isinited ((uint8*)(g_ram+0x1E10))
-#define intro_sprite_subtype ((uint8*)(g_ram+0x1E18))
-#define intro_sprite_state ((uint8*)(g_ram+0x1E20))
-#define intro_x_subpixel ((uint8*)(g_ram+0x1E28))
-#define intro_x_lo ((uint8*)(g_ram+0x1E30))
-#define intro_x_hi ((uint8*)(g_ram+0x1E38))
-#define intro_y_subpixel ((uint8*)(g_ram+0x1E40))
-#define intro_y_lo ((uint8*)(g_ram+0x1E48))
-#define intro_y_hi ((uint8*)(g_ram+0x1E50))
-#define intro_x_vel ((uint8*)(g_ram+0x1E58))
-#define intro_y_vel ((uint8*)(g_ram+0x1E60))
-#define intro_did_run_step (*(uint8*)(g_ram+0x1F00))
-#define poly_config_color_mode (*(uint8*)(g_ram+0x1F01))
-#define poly_config1 (*(uint8*)(g_ram+0x1F02))
-#define poly_which_model (*(uint8*)(g_ram+0x1F03))
-#define poly_a (*(uint8*)(g_ram+0x1F04))
-#define poly_b (*(uint8*)(g_ram+0x1F05))
-#define poly_base_x (*(uint8*)(g_ram+0x1F06))
-#define poly_base_y (*(uint8*)(g_ram+0x1F07))
-#define poly_var1 (*(uint16*)(g_ram+0x1F08))
-#define thread_other_stack (*(uint16*)(g_ram+0x1F0A))
-#define nmi_flag_update_polyhedral (*(uint8*)(g_ram+0x1F0C))
-#define poly_config_num_vertex (*(uint8*)(g_ram+0x1F3F))
-#define poly_config_num_polys (*(uint8*)(g_ram+0x1F40))
-#define poly_fromlut_ptr2 (*(uint16*)(g_ram+0x1F41))
-#define poly_fromlut_ptr4 (*(uint16*)(g_ram+0x1F43))
-#define poly_fromlut_z (*(uint8*)(g_ram+0x1F45))
-#define poly_fromlut_y (*(uint8*)(g_ram+0x1F46))
-#define poly_fromlut_x (*(uint8*)(g_ram+0x1F47))
-#define poly_f0 (*(uint16*)(g_ram+0x1F48))
-#define poly_f1 (*(uint16*)(g_ram+0x1F4A))
-#define poly_f2 (*(uint16*)(g_ram+0x1F4C))
-#define poly_num_vertex_in_poly (*(uint8*)(g_ram+0x1F4E))
-#define poly_raster_color_config (*(uint8*)(g_ram+0x1F4F))
-#define poly_sin_a (*(uint16*)(g_ram+0x1F50))
-#define poly_cos_a (*(uint16*)(g_ram+0x1F52))
-#define poly_sin_b (*(uint16*)(g_ram+0x1F54))
-#define poly_cos_b (*(uint16*)(g_ram+0x1F56))
-#define poly_e0 (*(uint16*)(g_ram+0x1F58))
-#define poly_e2 (*(uint16*)(g_ram+0x1F5A))
-#define poly_e3 (*(uint16*)(g_ram+0x1F5C))
-#define poly_e1 (*(uint16*)(g_ram+0x1F5E))
-#define poly_arr_x ((uint8*)(g_ram+0x1F60))
-#define poly_arr_y ((uint8*)(g_ram+0x1F88))
-#define poly_tmp0 (*(uint16*)(g_ram+0x1FB0))
-#define poly_tmp1 (*(uint16*)(g_ram+0x1FB2))
-#define poly_raster_color0 (*(uint16*)(g_ram+0x1FB5))
-#define poly_raster_color1 (*(uint16*)(g_ram+0x1FB7))
-#define poly_raster_dst_ptr (*(uint16*)(g_ram+0x1FB9))
-#define poly_tmp2 (*(uint8*)(g_ram+0x1FBC))
-#define poly_arr_xy_coords_minus1 (*(uint8*)(g_ram+0x1FBF))
-#define poly_xy_coords ((uint8*)(g_ram+0x1FC0))
-#define poly_total_num_steps (*(uint8*)(g_ram+0x1FE0))
-#define poly_x0_cur (*(uint8*)(g_ram+0x1FE1))
-#define poly_y0_cur (*(uint8*)(g_ram+0x1FE2))
-#define poly_x0_target (*(uint8*)(g_ram+0x1FE3))
-#define poly_y0_trig (*(uint8*)(g_ram+0x1FE4))
-#define poly_x0_frac (*(uint16*)(g_ram+0x1FE5))
-#define poly_x0_step (*(uint16*)(g_ram+0x1FE7))
-#define poly_cur_vertex_idx0 (*(uint8*)(g_ram+0x1FE9))
-#define poly_x1_cur (*(uint8*)(g_ram+0x1FEA))
-#define poly_y1_cur (*(uint8*)(g_ram+0x1FEB))
-#define poly_x1_target (*(uint8*)(g_ram+0x1FEC))
-#define poly_y1_trig (*(uint8*)(g_ram+0x1FED))
-#define poly_x1_frac (*(uint16*)(g_ram+0x1FEE))
-#define poly_x1_step (*(uint16*)(g_ram+0x1FF0))
-#define poly_cur_vertex_idx1 (*(uint8*)(g_ram+0x1FF2))
-#define poly_raster_numfull (*(uint16*)(g_ram+0x1FFA))
-#define dung_bg2 ((uint16*)(g_ram+0x2000))
-#define dung_bg1 ((uint16*)(g_ram+0x4000))
-#define word_7E6000 (*(uint16*)(g_ram+0x6000))
-#define word_7E8000 (*(uint16*)(g_ram+0x8000))
-#define dung_hdr_travel_destinations ((uint8*)(g_ram+0xC000))
-#define dung_want_lights_out (*(uint8*)(g_ram+0xC005))
-#define dung_want_lights_out_copy (*(uint8*)(g_ram+0xC006))
-#define palette_filter_countdown (*(uint16*)(g_ram+0xC007))
-#define darkening_or_lightening_screen (*(uint16*)(g_ram+0xC009))
-#define mosaic_target_level (*(uint8*)(g_ram+0xC00B))
-#define mosaic_target_level_PADDING (*(uint8*)(g_ram+0xC00C))
-#define bg_tile_animation_countdown (*(uint16*)(g_ram+0xC00D))
-#define word_7EC00F (*(uint16*)(g_ram+0xC00F))
-#define mosaic_level (*(uint8*)(g_ram+0xC011))
-#define word_7EC013 (*(uint16*)(g_ram+0xC013))
-#define word_7EC015 (*(uint16*)(g_ram+0xC015))
-#define overworld_fixed_color_plusminus (*(uint8*)(g_ram+0xC017))
-#define agahnim_pal_setting ((uint16*)(g_ram+0xC019))
-#define overworld_area_index_spexit (*(uint16*)(g_ram+0xC100))
-#define TM_copy_spexit (*(uint8*)(g_ram+0xC102))
-#define BG2VOFS_copy2_spexit (*(uint16*)(g_ram+0xC104))
-#define BG2HOFS_copy2_spexit (*(uint16*)(g_ram+0xC106))
-#define link_y_coord_spexit (*(uint16*)(g_ram+0xC108))
-#define link_x_coord_spexit (*(uint16*)(g_ram+0xC10A))
-#define overworld_screen_index_spexit (*(uint16*)(g_ram+0xC10C))
-#define map16_load_src_off_spexit (*(uint16*)(g_ram+0xC10E))
-#define camera_y_coord_scroll_low_spexit (*(uint16*)(g_ram+0xC110))
-#define camera_x_coord_scroll_low_spexit (*(uint16*)(g_ram+0xC112))
-#define room_scroll_vars0_ystart_spexit (*(uint16*)(g_ram+0xC114))
-#define room_scroll_vars0_yend_spexit (*(uint16*)(g_ram+0xC116))
-#define room_scroll_vars0_xstart_spexit (*(uint16*)(g_ram+0xC118))
-#define room_scroll_vars0_xend_spexit (*(uint16*)(g_ram+0xC11A))
-#define up_down_scroll_target_spexit (*(uint16*)(g_ram+0xC11C))
-#define up_down_scroll_target_end_spexit (*(uint16*)(g_ram+0xC11E))
-#define left_right_scroll_target_spexit (*(uint16*)(g_ram+0xC120))
-#define left_right_scroll_target_end_spexit (*(uint16*)(g_ram+0xC122))
-#define byte_7EC124 (*(uint8*)(g_ram+0xC124))
-#define main_tile_theme_index_spexit (*(uint8*)(g_ram+0xC125))
-#define aux_tile_theme_index_spexit (*(uint8*)(g_ram+0xC126))
-#define sprite_graphics_index_spexit (*(uint8*)(g_ram+0xC127))
-#define overworld_unk1_spexit (*(uint16*)(g_ram+0xC12A))
-#define overworld_unk1_neg_spexit (*(uint16*)(g_ram+0xC12C))
-#define overworld_unk3_spexit (*(uint16*)(g_ram+0xC12E))
-#define overworld_unk3_neg_spexit (*(uint16*)(g_ram+0xC130))
-#define overworld_area_index_exit (*(uint16*)(g_ram+0xC140))
-#define TM_copy_exit (*(uint16*)(g_ram+0xC142))
-#define BG2VOFS_copy2_exit (*(uint16*)(g_ram+0xC144))
-#define BG2HOFS_copy2_exit (*(uint16*)(g_ram+0xC146))
-#define link_y_coord_exit (*(uint16*)(g_ram+0xC148))
-#define link_x_coord_exit (*(uint16*)(g_ram+0xC14A))
-#define overworld_screen_index_exit (*(uint16*)(g_ram+0xC14C))
-#define map16_load_src_off_exit (*(uint16*)(g_ram+0xC14E))
-#define camera_y_coord_scroll_low_exit (*(uint16*)(g_ram+0xC150))
-#define camera_x_coord_scroll_low_exit (*(uint16*)(g_ram+0xC152))
-#define up_down_scroll_target_exit (*(uint16*)(g_ram+0xC15C))
-#define up_down_scroll_target_end_exit (*(uint16*)(g_ram+0xC15E))
-#define left_right_scroll_target_exit (*(uint16*)(g_ram+0xC160))
-#define left_right_scroll_target_end_exit (*(uint16*)(g_ram+0xC162))
-#define byte_7EC164 (*(uint8*)(g_ram+0xC164))
-#define main_tile_theme_index_exit (*(uint8*)(g_ram+0xC165))
-#define aux_tile_theme_index_exit (*(uint8*)(g_ram+0xC166))
-#define sprite_graphics_index_exit (*(uint8*)(g_ram+0xC167))
-#define overworld_unk1_exit (*(uint16*)(g_ram+0xC16A))
-#define overworld_unk1_neg_exit (*(uint16*)(g_ram+0xC16C))
-#define overworld_unk3_exit (*(uint16*)(g_ram+0xC16E))
-#define overworld_unk3_neg_exit (*(uint16*)(g_ram+0xC170))
-#define orange_blue_barrier_state (*(uint16*)(g_ram+0xC172))
-#define word_7EC174 (*(uint16*)(g_ram+0xC174))
-#define word_7EC176 (*(uint16*)(g_ram+0xC176))
-#define BG2HOFS_copy2_cached (*(uint16*)(g_ram+0xC180))
-#define BG2VOFS_copy2_cached (*(uint16*)(g_ram+0xC182))
-#define link_y_coord_cached (*(uint16*)(g_ram+0xC184))
-#define link_x_coord_cached (*(uint16*)(g_ram+0xC186))
-#define room_scroll_vars_y_vofs1_cached (*(uint16*)(g_ram+0xC188))
-#define room_scroll_vars_y_vofs2_cached (*(uint16*)(g_ram+0xC18A))
-#define room_scroll_vars_x_vofs1_cached (*(uint16*)(g_ram+0xC18C))
-#define room_scroll_vars_x_vofs2_cached (*(uint16*)(g_ram+0xC18E))
-#define up_down_scroll_target_cached (*(uint16*)(g_ram+0xC190))
-#define up_down_scroll_target_end_cached (*(uint16*)(g_ram+0xC192))
-#define left_right_scroll_target_cached (*(uint16*)(g_ram+0xC194))
-#define left_right_scroll_target_end_cached (*(uint16*)(g_ram+0xC196))
-#define camera_y_coord_scroll_low_cached (*(uint16*)(g_ram+0xC198))
-#define camera_x_coord_scroll_low_cached (*(uint16*)(g_ram+0xC19A))
-#define quadrant_fullsize_x_cached (*(uint8*)(g_ram+0xC19C))
-#define quadrant_fullsize_y_cached (*(uint8*)(g_ram+0xC19D))
-#define link_quadrant_x_cached (*(uint8*)(g_ram+0xC19E))
-#define link_quadrant_y_cached (*(uint8*)(g_ram+0xC19F))
-#define link_direction_facing_cached (*(uint8*)(g_ram+0xC1A6))
-#define link_is_on_lower_level_cached (*(uint8*)(g_ram+0xC1A7))
-#define link_is_on_lower_level_mirror_cached (*(uint8*)(g_ram+0xC1A8))
-#define is_standing_in_doorway_cahed (*(uint8*)(g_ram+0xC1A9))
-#define dung_cur_floor_cached (*(uint8*)(g_ram+0xC1AA))
-#define mapbak_BG1HOFS_copy2 (*(uint16*)(g_ram+0xC200))
-#define mapbak_BG2HOFS_copy2 (*(uint16*)(g_ram+0xC202))
-#define mapbak_BG1VOFS_copy2 (*(uint16*)(g_ram+0xC204))
-#define mapbak_BG2VOFS_copy2 (*(uint16*)(g_ram+0xC206))
-#define dung_bg2_properties_backup (*(uint8*)(g_ram+0xC208))
-#define overworld_pal_unk1 (*(uint8*)(g_ram+0xC20A))
-#define overworld_pal_unk2 (*(uint8*)(g_ram+0xC20B))
-#define overworld_pal_unk3 (*(uint8*)(g_ram+0xC20C))
-#define mapbak_main_tile_theme_index (*(uint8*)(g_ram+0xC20E))
-#define mapbak_sprite_graphics_index (*(uint8*)(g_ram+0xC20F))
-#define mapbak_aux_tile_theme_index (*(uint8*)(g_ram+0xC210))
-#define mapbak_TM (*(uint8*)(g_ram+0xC211))
-#define mapbak_TS (*(uint8*)(g_ram+0xC212))
-#define overworld_screen_index_prev (*(uint16*)(g_ram+0xC213))
-#define map16_load_src_off_prev (*(uint16*)(g_ram+0xC215))
-#define map16_load_var2_prev (*(uint16*)(g_ram+0xC217))
-#define map16_load_dst_off_prev (*(uint16*)(g_ram+0xC219))
-#define overworld_screen_transition_prev (*(uint8*)(g_ram+0xC21B))
-#define overworld_screen_trans_dir_bits_prev (*(uint16*)(g_ram+0xC21D))
-#define overworld_screen_trans_dir_bits2_prev (*(uint16*)(g_ram+0xC21F))
-#define mapbak_bg1_x_offset (*(uint16*)(g_ram+0xC221))
-#define mapbak_bg1_y_offset (*(uint16*)(g_ram+0xC223))
-#define mapbak_CGWSEL (*(uint16*)(g_ram+0xC225))
-#define music_unk1_death (*(uint8*)(g_ram+0xC227))
-#define sound_effect_ambient_last_death (*(uint8*)(g_ram+0xC228))
-#define mapbak_HDMAEN (*(uint8*)(g_ram+0xC229))
-#define byte_7EC22F (*(uint8*)(g_ram+0xC22F))
-#define vwf_arr ((uint8*)(g_ram+0xC230))
-#define aux_bg_subset_0 (*(uint8*)(g_ram+0xC2F8))
-#define aux_bg_subset_1 (*(uint8*)(g_ram+0xC2F9))
-#define aux_bg_subset_2 (*(uint8*)(g_ram+0xC2FA))
-#define aux_bg_subset_3 (*(uint8*)(g_ram+0xC2FB))
-#define sprite_gfx_subset_0 (*(uint8*)(g_ram+0xC2FC))
-#define sprite_gfx_subset_1 (*(uint8*)(g_ram+0xC2FD))
-#define sprite_gfx_subset_2 (*(uint8*)(g_ram+0xC2FE))
-#define sprite_gfx_subset_3 (*(uint8*)(g_ram+0xC2FF))
-#define aux_palette_buffer ((uint16*)(g_ram+0xC300))
-#define main_palette_buffer ((uint16*)(g_ram+0xC500))
-#define hud_tile_indices_buffer ((uint16*)(g_ram+0xC700))
-#define moving_wall_arr1 ((uint16*)(g_ram+0xC880))
-#define word_7EE000 (*(uint16*)(g_ram+0xE000))
-#define polyhedral_buffer ((uint8*)(g_ram+0xE800))
-#define save_dung_info ((uint16*)(g_ram+0xF000))
-#define save_ow_event_info ((uint8*)(g_ram+0xF280))
-#define savegame_has_master_sword_flags (*(uint16*)(g_ram+0xF300))
-#define byte_7EF33F (*(uint8*)(g_ram+0xF33F))
-#define link_item_bow (*(uint8*)(g_ram+0xF340))
-#define link_item_boomerang (*(uint8*)(g_ram+0xF341))
-#define link_item_hookshot (*(uint8*)(g_ram+0xF342))
-#define link_item_bombs (*(uint8*)(g_ram+0xF343))
-#define link_item_mushroom (*(uint8*)(g_ram+0xF344))
-#define link_item_fire_rod (*(uint8*)(g_ram+0xF345))
-#define link_item_ice_rod (*(uint8*)(g_ram+0xF346))
-#define link_item_bombos_medallion (*(uint8*)(g_ram+0xF347))
-#define link_item_ether_medallion (*(uint8*)(g_ram+0xF348))
-#define link_item_quake_medallion (*(uint8*)(g_ram+0xF349))
-#define link_item_torch (*(uint8*)(g_ram+0xF34A))
-#define link_item_hammer (*(uint8*)(g_ram+0xF34B))
-#define link_item_flute (*(uint8*)(g_ram+0xF34C))
-#define link_item_bug_net (*(uint8*)(g_ram+0xF34D))
-#define link_item_book_of_mudora (*(uint8*)(g_ram+0xF34E))
-#define link_item_bottle_index (*(uint8*)(g_ram+0xF34F))
-#define link_item_cane_somaria (*(uint8*)(g_ram+0xF350))
-#define link_item_cane_byrna (*(uint8*)(g_ram+0xF351))
-#define link_item_cape (*(uint8*)(g_ram+0xF352))
-#define link_item_mirror (*(uint8*)(g_ram+0xF353))
-#define link_item_gloves (*(uint8*)(g_ram+0xF354))
-#define link_item_boots (*(uint8*)(g_ram+0xF355))
-#define link_item_flippers (*(uint8*)(g_ram+0xF356))
-#define link_item_moon_pearl (*(uint8*)(g_ram+0xF357))
-#define link_sword_type (*(uint8*)(g_ram+0xF359))
-#define link_shield_type (*(uint8*)(g_ram+0xF35A))
-#define link_armor (*(uint8*)(g_ram+0xF35B))
-#define link_bottle_info ((uint8*)(g_ram+0xF35C))
-#define link_rupees_goal (*(uint16*)(g_ram+0xF360))
-#define link_rupees_actual (*(uint16*)(g_ram+0xF362))
-#define link_compass (*(uint16*)(g_ram+0xF364))
-#define link_bigkey (*(uint16*)(g_ram+0xF366))
-#define link_dungeon_map (*(uint16*)(g_ram+0xF368))
-#define link_rupees_in_pond (*(uint8*)(g_ram+0xF36A))
-#define link_heart_pieces (*(uint8*)(g_ram+0xF36B))
-#define link_health_capacity (*(uint8*)(g_ram+0xF36C))
-#define link_health_current (*(uint8*)(g_ram+0xF36D))
-#define link_magic_power (*(uint8*)(g_ram+0xF36E))
-#define link_num_keys (*(uint8*)(g_ram+0xF36F))
-#define link_bomb_upgrades (*(uint8*)(g_ram+0xF370))
-#define link_arrow_upgrades (*(uint8*)(g_ram+0xF371))
-#define link_hearts_filler (*(uint8*)(g_ram+0xF372))
-#define link_magic_filler (*(uint8*)(g_ram+0xF373))
-#define link_which_pendants (*(uint8*)(g_ram+0xF374))
-#define link_bomb_filler (*(uint8*)(g_ram+0xF375))
-#define link_arrow_filler (*(uint8*)(g_ram+0xF376))
-#define link_num_arrows (*(uint8*)(g_ram+0xF377))
-#define link_ability_flags (*(uint8*)(g_ram+0xF379))
-#define link_has_crystals (*(uint8*)(g_ram+0xF37A))
-#define link_magic_consumption (*(uint8*)(g_ram+0xF37B))
-#define link_keys_earned_per_dungeon ((uint8*)(g_ram+0xF37C))
-#define sram_progress_indicator (*(uint8*)(g_ram+0xF3C5))
-#define sram_progress_flags (*(uint8*)(g_ram+0xF3C6))
-#define savegame_map_icons_indicator (*(uint8*)(g_ram+0xF3C7))
-#define which_starting_point (*(uint8*)(g_ram+0xF3C8))
-#define sram_progress_indicator_3 (*(uint8*)(g_ram+0xF3C9))
-#define savegame_is_darkworld (*(uint8*)(g_ram+0xF3CA))
-#define follower_indicator (*(uint8*)(g_ram+0xF3CC))
-#define saved_tagalong_y (*(uint16*)(g_ram+0xF3CD))
-#define saved_tagalong_x (*(uint16*)(g_ram+0xF3CF))
-#define saved_tagalong_indoors (*(uint8*)(g_ram+0xF3D1))
-#define saved_tagalong_floor (*(uint8*)(g_ram+0xF3D2))
-#define follower_dropped (*(uint8*)(g_ram+0xF3D3))
-#define deaths_per_palace ((uint16*)(g_ram+0xF3E7))
-#define death_save_counter (*(uint16*)(g_ram+0xF403))
-#define death_var2 (*(uint16*)(g_ram+0xF405))
-#define word_7EF4FE (*(uint16*)(g_ram+0xF4FE))
-#define pots_revealed_in_room ((uint16*)(g_ram+0xF580))
-#define memorized_tile_addr ((uint16*)(g_ram+0xF800))
-#define memorized_tile_value ((uint16*)(g_ram+0xFA00))
-#define word_7EFA40 ((uint16*)(g_ram+0xFA40))
-#define dung_torch_data ((uint16*)(g_ram+0xFB40))
-#define overworld_sprite_gfx ((uint8*)(g_ram+0xFCC0))
-#define overworld_sprite_palettes ((uint8*)(g_ram+0xFD40))
-#define attributes_for_tile ((uint8*)(g_ram+0xFE00))
-#define skullwoodsfire_var0 ((uint8*)(g_ram+0x10000))
-#define skullwoodsfire_var5 ((uint8*)(g_ram+0x10008))
-#define skullwoodsfire_var4 (*(uint8*)(g_ram+0x10010))
-#define blastwall_var4 (*(uint8*)(g_ram+0x10011))
-#define skullwoodsfire_var9 (*(uint16*)(g_ram+0x10018))
-#define skullwoodsfire_var11 (*(uint16*)(g_ram+0x1001A))
-#define blastwall_var7 (*(uint8*)(g_ram+0x1001C))
-#define skullwoodsfire_y_arr ((uint16*)(g_ram+0x10020))
-#define skullwoodsfire_var10 (*(uint16*)(g_ram+0x10026))
-#define skullwoodsfire_x_arr ((uint16*)(g_ram+0x10030))
-#define skullwoodsfire_var12 (*(uint16*)(g_ram+0x10036))
-#define blastwall_var12 ((uint8*)(g_ram+0x10040))
-#define word_7F1000 (*(uint16*)(g_ram+0x11000))
-#define word_7F1010 (*(uint16*)(g_ram+0x11010))
-#define byte_7F11FA (*(uint8*)(g_ram+0x111FA))
-#define byte_7F11FB (*(uint8*)(g_ram+0x111FB))
-#define byte_7F11FC (*(uint8*)(g_ram+0x111FC))
-#define byte_7F11FD (*(uint8*)(g_ram+0x111FD))
-#define byte_7F11FE (*(uint8*)(g_ram+0x111FE))
-#define byte_7F11FF (*(uint8*)(g_ram+0x111FF))
-#define messaging_text_buffer ((uint8*)(g_ram+0x11200))
-#define word_7F1FC0 (*(uint16*)(g_ram+0x11FC0))
-#define dung_bg2_attr_table ((uint8*)(g_ram+0x12000))
-#define dung_bg1_attr_table ((uint8*)(g_ram+0x13000))
-#define word_7F4000 (*(uint16*)(g_ram+0x14000))
-#define word_7F4002 (*(uint16*)(g_ram+0x14002))
-#define word_7F4004 (*(uint16*)(g_ram+0x14004))
-#define word_7F4006 (*(uint16*)(g_ram+0x14006))
-#define map16_decode_0 ((uint8*)(g_ram+0x14400))
-#define map16_decode_1 ((uint8*)(g_ram+0x14410))
-#define map16_decode_2 ((uint8*)(g_ram+0x14420))
-#define map16_decode_3 ((uint8*)(g_ram+0x14430))
-#define map16_decode_last (*(uint16*)(g_ram+0x14440))
-#define map16_decode_tmp (*(uint16*)(g_ram+0x14442))
-#define breaktowerseal_var3 ((uint8*)(g_ram+0x15800))
-#define breaktowerseal_var4 (*(uint8*)(g_ram+0x15808))
-#define breaktowerseal_x (*(uint16*)(g_ram+0x1580E))
-#define breaktowerseal_y (*(uint16*)(g_ram+0x15810))
-#define breaktowerseal_var5 (*(uint8*)(g_ram+0x15812))
-#define breaktowerseal_base_sparkle_y_lo ((uint8*)(g_ram+0x15817))
-#define breaktowerseal_base_sparkle_y_hi ((uint8*)(g_ram+0x1581F))
-#define breaktowerseal_base_sparkle_x_lo ((uint8*)(g_ram+0x15827))
-#define breaktowerseal_base_sparkle_x_hi ((uint8*)(g_ram+0x1582F))
-#define breaktowerseal_sparkle_var1 ((uint8*)(g_ram+0x15837))
-#define breaktowerseal_sparkle_y_lo ((uint8*)(g_ram+0x1584F))
-#define breaktowerseal_sparkle_y_hi ((uint8*)(g_ram+0x15867))
-#define breaktowerseal_sparkle_x_lo ((uint8*)(g_ram+0x1587F))
-#define breaktowerseal_sparkle_x_hi ((uint8*)(g_ram+0x15897))
-#define breaktowerseal_sparkle_var2 ((uint8*)(g_ram+0x158AF))
-#define overworld_music ((uint8*)(g_ram+0x15B00))
-#define freeRam ((uint8*)(g_ram+0x15BA0))
-#define enemy_damage_data ((uint8*)(g_ram+0x16000))
-#define hdma_table_unused ((uint16*)(g_ram+0x17000))
-#define kTextDialoguePointers ((uint8*)(g_ram+0x171C0))
-#define word_7F8000 (*(uint16*)(g_ram+0x18000))
-#define word_7F9B52 (*(uint16*)(g_ram+0x19B52))
-#define word_7F9B54 (*(uint16*)(g_ram+0x19B54))
-#define word_7F9B56 (*(uint16*)(g_ram+0x19B56))
-#define word_7F9B58 (*(uint16*)(g_ram+0x19B58))
-#define word_7FA000 (*(uint16*)(g_ram+0x1A000))
-#define word_7FC000 (*(uint16*)(g_ram+0x1C000))
-#define mapbak_palette ((uint16*)(g_ram+0x1DD80))
-#define sprite_where_in_room ((uint16*)(g_ram+0x1DF80))
-#define overworld_sprite_was_loaded ((uint8*)(g_ram+0x1EF80))
-#define garnish_type ((uint8*)(g_ram+0x1F800))
-#define garnish_y_lo ((uint8*)(g_ram+0x1F81E))
-#define garnish_x_lo ((uint8*)(g_ram+0x1F83C))
-#define garnish_y_hi ((uint8*)(g_ram+0x1F85A))
-#define garnish_x_hi ((uint8*)(g_ram+0x1F878))
-#define garnish_y_vel ((uint8*)(g_ram+0x1F896))
-#define garnish_x_vel ((uint8*)(g_ram+0x1F8B4))
-#define garnish_y_subpixel ((uint8*)(g_ram+0x1F8D2))
-#define garnish_x_subpixel ((uint8*)(g_ram+0x1F8F0))
-#define garnish_countdown ((uint8*)(g_ram+0x1F90E))
-#define garnish_sprite ((uint8*)(g_ram+0x1F92C))
-#define garnish_anim_5 ((uint8*)(g_ram+0x1F94A))
-#define garnish_floor ((uint8*)(g_ram+0x1F968))
-#define sprite_I ((uint8*)(g_ram+0x1F9C2))
-#define garnish_oam_flags ((uint8*)(g_ram+0x1F9FE))
-#define sprite_unk3 ((uint8*)(g_ram+0x1FA1C))
-#define sprite_unk4 ((uint8*)(g_ram+0x1FA2C))
-#define sprite_unk5 ((uint8*)(g_ram+0x1FA3C))
-#define sprite_unk1 ((uint8*)(g_ram+0x1FA4C))
-#define swamola_x_lo ((uint8*)(g_ram+0x1FA5C))
-#define alt_sprite_C ((uint8*)(g_ram+0x1FA6C))
-#define alt_sprite_E ((uint8*)(g_ram+0x1FA7C))
-#define alt_sprite_subtype2 ((uint8*)(g_ram+0x1FA8C))
-#define alt_sprite_height_above_shadow ((uint8*)(g_ram+0x1FA9C))
-#define alt_sprite_delay_main ((uint8*)(g_ram+0x1FAAC))
-#define byte_7FFABC ((uint8*)(g_ram+0x1FABC))
-#define alt_sprite_I ((uint8*)(g_ram+0x1FACC))
-#define alt_sprite_maybe_ignore_projectile ((uint8*)(g_ram+0x1FADC))
-#define swamola_x_hi ((uint8*)(g_ram+0x1FB1C))
-#define swamola_y_lo ((uint8*)(g_ram+0x1FBDC))
-#define moldorm_x_lo ((uint8*)(g_ram+0x1FC00))
-#define moldorm_x_hi_ ((uint8*)(g_ram+0x1FC80))
-#define swamola_y_hi ((uint8*)(g_ram+0x1FC9C))
-#define moldorm_y_lo ((uint8*)(g_ram+0x1FD00))
-#define word_7FFD02 (*(uint16*)(g_ram+0x1FD02))
-#define swamola_target_x_lo ((uint8*)(g_ram+0x1FD5C))
-#define swamola_target_x_hi ((uint8*)(g_ram+0x1FD62))
-#define swamola_target_y_lo ((uint8*)(g_ram+0x1FD68))
-#define swamola_target_y_hi ((uint8*)(g_ram+0x1FD6E))
-#define beamos_x_lo ((uint8*)(g_ram+0x1FD80))
-#define beamos_x_hi ((uint8*)(g_ram+0x1FE00))
-#define beamos_y_lo ((uint8*)(g_ram+0x1FE80))
-#define beamos_y_hi ((uint8*)(g_ram+0x1FF00))
-
-#define attract_var12 (*(uint16*)(g_ram+0x20))
-#define attract_state (*(uint8*)(g_ram+0x22))
-#define attract_sequence (*(uint8*)(g_ram+0x23))
-#define attract_var10 (*(uint8*)(g_ram+0x25))
-#define attract_next_legend_gfx (*(uint8*)(g_ram+0x26))
-#define attract_legend_flag (*(uint8*)(g_ram+0x27))
-#define attract_x_base (*(uint8*)(g_ram+0x28))
-#define attract_y_base (*(uint8*)(g_ram+0x29))
-#define attract_oam_idx (*(uint8*)(g_ram+0x2A))
-#define attract_var9 (*(uint8*)(g_ram+0x2B))
-#define attract_var13 (*(uint8*)(g_ram+0x2C))
-#define attract_var7 (*(uint16*)(g_ram+0x2D))
-#define attract_vram_dst (*(uint16*)(g_ram+0x30))
-#define attract_var1 (*(uint8*)(g_ram+0x32))
-#define attract_var3 (*(uint8*)(g_ram+0x33))
-#define attract_var4 (*(uint8*)(g_ram+0x34))
-#define attract_x_base_hi (*(uint8*)(g_ram+0x40))
-#define attract_var17 (*(uint8*)(g_ram+0x50))
-#define attract_var21 (*(uint8*)(g_ram+0x51))
-#define attract_var15 (*(uint8*)(g_ram+0x52))
-#define attract_var22 (*(uint8*)(g_ram+0x5D))
-#define attract_var18 (*(uint8*)(g_ram+0x5F))
-#define attract_var5 (*(uint8*)(g_ram+0x60))
-#define attract_var11 (*(uint8*)(g_ram+0x61))
-#define attract_var19 (*(uint8*)(g_ram+0x62))
-#define attract_var20 (*(uint8*)(g_ram+0x63))
-#define selectfile_arr1 ((uint16*)(g_ram+0xBF))
-#define selectfile_arr2 ((uint8*)(g_ram+0xCA))
-#define selectfile_var6 (*(uint8*)(g_ram+0xCC))
-#define attract_room_index (*(uint8*)(g_ram+0x10E))
-#define attract_legend_ctr (*(uint16*)(g_ram+0x200))
-#define selectfile_var8 (*(uint16*)(g_ram+0x630))
-#define selectfile_var3 (*(uint8*)(g_ram+0xB10))
-#define selectfile_var7 (*(uint8*)(g_ram+0xB11))
-#define selectfile_var4 (*(uint8*)(g_ram+0xB12))
-#define selectfile_var9 (*(uint8*)(g_ram+0xB13))
-#define selectfile_var11 (*(uint8*)(g_ram+0xB14))
-#define selectfile_var5 (*(uint8*)(g_ram+0xB15))
-#define selectfile_var10 (*(uint8*)(g_ram+0xB16))
-#define selectfile_var2 (*(uint8*)(g_ram+0xB9D))
-
-#define blastwall_var5 ((uint8*)(g_ram+0x10000))
-#define blastwall_var6 ((uint8*)(g_ram+0x10008))
-#define blastwall_var1 (*(uint8*)(g_ram+0x10010))
-#define blastwall_var4 (*(uint8*)(g_ram+0x10011))
-#define blastwall_var8 (*(uint16*)(g_ram+0x10018))
-#define blastwall_var9 (*(uint16*)(g_ram+0x1001A))
-#define blastwall_var7 (*(uint8*)(g_ram+0x1001C))
-#define blastwall_var10 ((uint16*)(g_ram+0x10020))
-#define blastwall_var11 ((uint16*)(g_ram+0x10030))
-#define blastwall_var12 ((uint8*)(g_ram+0x10040))
-
-#define breaktowerseal_var3 ((uint8*)(g_ram+0x15800))
-#define breaktowerseal_var4 (*(uint8*)(g_ram+0x15808))
-#define breaktowerseal_x (*(uint16*)(g_ram+0x1580E))
-#define breaktowerseal_y (*(uint16*)(g_ram+0x15810))
-#define breaktowerseal_var5 (*(uint8*)(g_ram+0x15812))
-#define breaktowerseal_base_sparkle_y_lo ((uint8*)(g_ram+0x15817))
-#define breaktowerseal_base_sparkle_y_hi ((uint8*)(g_ram+0x1581F))
-#define breaktowerseal_base_sparkle_x_lo ((uint8*)(g_ram+0x15827))
-#define breaktowerseal_base_sparkle_x_hi ((uint8*)(g_ram+0x1582F))
-#define breaktowerseal_sparkle_var1 ((uint8*)(g_ram+0x15837))
-#define breaktowerseal_sparkle_y_lo ((uint8*)(g_ram+0x1584F))
-#define breaktowerseal_sparkle_y_hi ((uint8*)(g_ram+0x15867))
-#define breaktowerseal_sparkle_x_lo ((uint8*)(g_ram+0x1587F))
-#define breaktowerseal_sparkle_x_hi ((uint8*)(g_ram+0x15897))
-#define breaktowerseal_sparkle_var2 ((uint8*)(g_ram+0x158AF))
-
-#define happiness_pond_y_vel ((uint8*)(g_ram+0x15800))
-#define happiness_pond_x_vel ((uint8*)(g_ram+0x1580C))
-#define happiness_pond_z_vel ((uint8*)(g_ram+0x15818))
-#define happiness_pond_y_lo ((uint8*)(g_ram+0x15824))
-#define happiness_pond_y_hi ((uint8*)(g_ram+0x15830))
-#define happiness_pond_x_lo ((uint8*)(g_ram+0x1583C))
-#define happiness_pond_x_hi ((uint8*)(g_ram+0x15848))
-#define happiness_pond_z ((uint8*)(g_ram+0x15854))
-#define happiness_pond_timer ((uint8*)(g_ram+0x15860))
-#define happiness_pond_arr1 ((uint8*)(g_ram+0x1586C))
-#define happiness_pond_item_to_link ((uint8*)(g_ram+0x1587A))
-#define happiness_pond_y_subpixel ((uint8*)(g_ram+0x15886))
-#define happiness_pond_x_subpixel ((uint8*)(g_ram+0x15892))
-#define happiness_pond_z_subpixel ((uint8*)(g_ram+0x1589E))
-#define happiness_pond_step ((uint8*)(g_ram+0x158AA))
-
-#define skullwoodsfire_var0 ((uint8*)(g_ram+0x10000))
-#define skullwoodsfire_var5 ((uint8*)(g_ram+0x10008))
-#define skullwoodsfire_var4 (*(uint8*)(g_ram+0x10010))
-#define skullwoodsfire_var9 (*(uint16*)(g_ram+0x10018))
-#define skullwoodsfire_var11 (*(uint16*)(g_ram+0x1001A))
-#define skullwoodsfire_y_arr ((uint16*)(g_ram+0x10020))
-#define skullwoodsfire_var10 (*(uint16*)(g_ram+0x10026))
-#define skullwoodsfire_x_arr ((uint16*)(g_ram+0x10030))
-#define skullwoodsfire_var12 (*(uint16*)(g_ram+0x10036))
-
-#define weathervane_arr3 ((uint8*)(g_ram+0x15800))
-#define weathervane_arr4 ((uint8*)(g_ram+0x1580C))
-#define weathervane_arr5 ((uint8*)(g_ram+0x15818))
-#define weathervane_arr6 ((uint8*)(g_ram+0x15824))
-#define weathervane_arr7 ((uint8*)(g_ram+0x15830))
-#define weathervane_arr8 ((uint8*)(g_ram+0x1583C))
-#define weathervane_arr9 ((uint8*)(g_ram+0x15848))
-#define weathervane_arr10 ((uint8*)(g_ram+0x15854))
-#define weathervane_arr11 ((uint8*)(g_ram+0x15860))
-#define weathervane_arr12 ((uint8*)(g_ram+0x1586C))
-#define weathervane_var13 (*(uint8*)(g_ram+0x15878))
-#define weathervane_var14 (*(uint8*)(g_ram+0x15879))
-#define weathervane_var2 (*(uint16*)(g_ram+0x158B6))
-#define weathervane_var1 (*(uint8*)(g_ram+0x158B8))
-
-
-#define scratch_0 (*(uint16*)(g_ram+0x72))
-#define scratch_1 (*(uint16*)(g_ram+0x74))
-#define srm_var1 (*(uint16*)(g_zenv.sram+0x1ffe))
-#define messaging_buf ((uint16*)(g_ram+0x10000))
-#define quake_arr1 ((uint8*)(g_ram+0x15800))
-#define quake_arr2 ((uint8*)(g_ram+0x15805))
-#define quake_var5 (*(uint8*)(g_ram+0x1580A))
-#define quake_var1 (*(uint16*)(g_ram+0x1580B))
-#define quake_var2 (*(uint16*)(g_ram+0x1580D))
-#define quake_var4 (*(uint8*)(g_ram+0x1580F))
-#define ether_y3 (*(uint16*)(g_ram+0x15810))
-#define ether_var1 (*(uint8*)(g_ram+0x15812))
-#define ether_y (*(uint16*)(g_ram+0x15813))
-#define ether_x (*(uint16*)(g_ram+0x15815))
-#define quake_var3 (*(uint16*)(g_ram+0x1581E))
-#define bombos_arr7 ((uint8*)(g_ram+0x15820))
-#define bombos_y_lo ((uint8*)(g_ram+0x15824))
-#define bombos_y_hi ((uint8*)(g_ram+0x15864))
-#define bombos_x_lo ((uint8*)(g_ram+0x158A4))
-#define bombos_x_hi ((uint8*)(g_ram+0x158E4))
-#define bombos_y_coord2 ((uint16*)(g_ram+0x15924))
-#define bombos_x_coord2 ((uint16*)(g_ram+0x1592C))
-#define bombos_var4 (*(uint8*)(g_ram+0x15934))
-#define bombos_arr3 ((uint8*)(g_ram+0x15935))
-#define bombos_arr4 ((uint8*)(g_ram+0x15945))
-#define bombos_y_coord ((uint16*)(g_ram+0x15955))
-#define bombos_x_coord ((uint16*)(g_ram+0x159D5))
-#define bombos_var3 (*(uint8*)(g_ram+0x15A55))
-#define bombos_var2 (*(uint8*)(g_ram+0x15A56))
-#define bombos_var1 (*(uint8*)(g_ram+0x15A57))
-
-#define happiness_pond_y_vel ((uint8*)(g_ram+0x15800))
-#define happiness_pond_x_vel ((uint8*)(g_ram+0x1580C))
-#define happiness_pond_z_vel ((uint8*)(g_ram+0x15818))
-#define happiness_pond_y_lo ((uint8*)(g_ram+0x15824))
-#define happiness_pond_y_hi ((uint8*)(g_ram+0x15830))
-#define happiness_pond_x_lo ((uint8*)(g_ram+0x1583C))
-#define happiness_pond_x_hi ((uint8*)(g_ram+0x15848))
-#define happiness_pond_z ((uint8*)(g_ram+0x15854))
-#define happiness_pond_timer ((uint8*)(g_ram+0x15860))
-#define happiness_pond_arr1 ((uint8*)(g_ram+0x1586C))
-#define happiness_pond_item_to_link ((uint8*)(g_ram+0x1587A))
-#define happiness_pond_y_subpixel ((uint8*)(g_ram+0x15886))
-#define happiness_pond_x_subpixel ((uint8*)(g_ram+0x15892))
-#define happiness_pond_z_subpixel ((uint8*)(g_ram+0x1589E))
-#define happiness_pond_step ((uint8*)(g_ram+0x158AA))
-
-
-#define turn_on_off_water_ctr (*(uint8*)(g_ram+0x424))
-#define sprite_N_word ((uint16*)(g_ram+0xBC0))
-#define sprite_where_in_overworld ((uint8*)(g_ram+0x1DF80))
-#define alt_sprite_B ((uint8*)(g_ram+0x1FA5C))
-#define uvram_screen (*(UploadVram_32x32*)&g_ram[0x1000])
-#define vram_upload_offset (*(uint16*)(g_ram+0x1000))
-#define vram_upload_data ((uint16*)(g_ram+0x1002))
-#define vram_upload_tile_buf ((uint16*)(g_ram+0x1100))
-#define overworld_entrance_sequence_counter (*(uint8*)(g_ram+0xc8))
-
-#ifndef overworld_tileattr
-#define overworld_tileattr ((uint16*)(g_ram+0x2000))
-#endif
-#define dung_line_ptrs_row0 (*(uint16*)(g_ram+0xbf))
-#define star_shaped_switches_tile ((uint16*)(g_ram+0x6A0))
-#define dung_inter_starcases ((uint16*)(g_ram+0x6B0))
-#define dung_stairs_table_1 ((uint16*)(g_ram+0x6B8))
-#define selectfile_var8 (*(uint16*)(g_ram+0x630))
-
-#define R10 (*(uint16*)(g_ram+10))
-#define R12 (*(uint16*)(g_ram+12))
-#define R14 (*(uint16*)(g_ram+14))
-#define R16 (*(uint16*)(g_ram+0xc8))
-#define R18 (*(uint16*)(g_ram+0xca))
-#define R20 (*(uint16*)(g_ram+0xcc))
-
-// Relocated the hdma table so it can fit 240 rows
-#define hdma_table_dynamic_orig_pos ((uint16*)(g_ram+0x1B00))
-#define hdma_table_dynamic ((uint16*)(g_ram+0x1DBA0))
-
-// Allocate 64 bytes that we can use for msu resume.
-#define msu_resume_info ((uint8*)(g_ram+0x1DB60))
-
-#define msu_resume_info_alt ((uint8*)(g_ram+0x1DB20))
-
-
-typedef struct MovableBlockData {
-  uint16 room;
-  uint16 tilemap;
-} MovableBlockData;
-
-typedef struct OamEntSigned {
-  int8 x, y;
-  uint8 charnum, flags;
-} OamEntSigned;
-
-
-
-#define movable_block_datas ((MovableBlockData*)(g_ram+0xf940))
-#define oam_buf ((OamEnt*)(g_ram+0x800))
-
-
-typedef struct RoomBounds {
-  union {
-    struct { uint16 a0, b0, a1, b1; };
-    uint16 v[4];
-  };
-} RoomBounds;
-#define room_bounds_y (*(RoomBounds*)(g_ram+0x600))
-#define room_bounds_x (*(RoomBounds*)(g_ram+0x608))
-
-
-typedef struct OwScrollVars {
-  uint16 ystart, yend, xstart, xend;
-} OwScrollVars;
-
-
-#define ow_scroll_vars0 (*(OwScrollVars*)(g_ram+0x600))
-#define ow_scroll_vars1 (*(OwScrollVars*)(g_ram+0x608))
-
-#define ow_scroll_vars0_exit (*(OwScrollVars*)(g_ram+0xC154))
-
-extern const uint8 kLayoutQuadrantFlags[];
-extern const uint8 kVariousPacks[16];
-extern const uint8 kMaxBombsForLevel[];
-extern const uint8 kMaxArrowsForLevel[];
-extern const uint8 kReceiveItem_Tab1[76];
-extern const uint8 kHealthAfterDeath[21];
-extern const uint8 kReceiveItemGfx[76];
-extern const uint16 kOverworld_OffsetBaseY[64];
-extern const uint16 kOverworld_OffsetBaseX[64];
-
-// forwards
-
-
-typedef struct MirrorHdmaVars {
-  uint16 var0;
-  uint16 var1[2];
-  uint16 var3[2];
-  uint16 var5;
-  uint16 var6;
-  uint16 var7;
-  uint16 var8;
-  uint16 var9;
-  uint16 var10;
-  uint16 var11;
-  uint16 pad;
-  uint8 ctr2, ctr;
-} MirrorHdmaVars;
-#define mirror_vars (*(MirrorHdmaVars*)(g_ram+0x6A0))
-
-
-typedef struct UploadVram_Row {
-  uint16 col[32];
-} UploadVram_Row;
-
-typedef struct UploadVram_32x32 {
-  UploadVram_Row row[32];
-} UploadVram_32x32;
-
-typedef struct UploadVram_3 {
-  uint8 pad[256];
-  uint16 data[4];
-} UploadVram_3;
-
-#define uvram (*(UploadVram_3*)(&g_ram[0x1000]))
-
-extern uint8 g_ram[131072];
-extern const uint16 kUpperBitmasks[];
-extern const uint8 kLitTorchesColorPlus[];
-extern const uint8 kDungeonCrystalPendantBit[];
-extern const int8 kGetBestActionToPerformOnTile_x[];
-extern const int8 kGetBestActionToPerformOnTile_y[];
-
-
-#endif  // ZELDA3_VARIABLES_H_
\ No newline at end of file
--- a/zelda3.vcxproj
+++ b/zelda3.vcxproj
@@ -126,6 +126,7 @@
       <LanguageStandard_C>stdc11</LanguageStandard_C>
       <DisableSpecificWarnings>4244;4018;4996</DisableSpecificWarnings>
       <TreatWarningAsError>true</TreatWarningAsError>
+      <AdditionalIncludeDirectories>$(SolutionDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
     </ClCompile>
     <Link>
       <TargetMachine>MachineX86</TargetMachine>
@@ -132,6 +133,7 @@
       <GenerateDebugInformation>true</GenerateDebugInformation>
       <SubSystem>Console</SubSystem>
       <AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
+      <AdditionalOptions>/PDBALTPATH:%_PDB% %(AdditionalOptions)</AdditionalOptions>
     </Link>
   </ItemDefinitionGroup>
   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
@@ -143,6 +145,7 @@
       <LanguageStandard_C>stdc11</LanguageStandard_C>
       <DisableSpecificWarnings>4244;4018;4996</DisableSpecificWarnings>
       <TreatWarningAsError>true</TreatWarningAsError>
+      <AdditionalIncludeDirectories>$(SolutionDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
     </ClCompile>
     <Link>
       <TargetMachine>MachineX86</TargetMachine>
@@ -151,6 +154,7 @@
       <EnableCOMDATFolding>true</EnableCOMDATFolding>
       <OptimizeReferences>true</OptimizeReferences>
       <AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
+      <AdditionalOptions>/PDBALTPATH:%_PDB% %(AdditionalOptions)</AdditionalOptions>
     </Link>
   </ItemDefinitionGroup>
   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseDeploy|Win32'">
@@ -162,6 +166,7 @@
       <LanguageStandard_C>stdc11</LanguageStandard_C>
       <DisableSpecificWarnings>4244;4018;4996</DisableSpecificWarnings>
       <TreatWarningAsError>true</TreatWarningAsError>
+      <AdditionalIncludeDirectories>$(SolutionDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
     </ClCompile>
     <Link>
       <TargetMachine>MachineX86</TargetMachine>
@@ -171,6 +176,7 @@
       <OptimizeReferences>true</OptimizeReferences>
       <AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
       <ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile>
+      <AdditionalOptions>/PDBALTPATH:%_PDB% %(AdditionalOptions)</AdditionalOptions>
     </Link>
   </ItemDefinitionGroup>
   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
@@ -181,9 +187,11 @@
       <DisableSpecificWarnings>4244;4018;4996</DisableSpecificWarnings>
       <TreatWarningAsError>true</TreatWarningAsError>
       <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions);_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+      <AdditionalIncludeDirectories>$(SolutionDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
     </ClCompile>
     <Link>
       <AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
+      <AdditionalOptions>/PDBALTPATH:%_PDB% %(AdditionalOptions)</AdditionalOptions>
     </Link>
   </ItemDefinitionGroup>
   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
@@ -193,9 +201,11 @@
       <DisableSpecificWarnings>4244;4018;4996</DisableSpecificWarnings>
       <TreatWarningAsError>true</TreatWarningAsError>
       <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+      <AdditionalIncludeDirectories>$(SolutionDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
     </ClCompile>
     <Link>
       <AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
+      <AdditionalOptions>/PDBALTPATH:%_PDB% %(AdditionalOptions)</AdditionalOptions>
     </Link>
   </ItemDefinitionGroup>
   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseDeploy|x64'">
@@ -205,38 +215,36 @@
       <DisableSpecificWarnings>4244;4018;4996</DisableSpecificWarnings>
       <TreatWarningAsError>true</TreatWarningAsError>
       <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+      <AdditionalIncludeDirectories>$(SolutionDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
     </ClCompile>
     <Link>
       <AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
       <ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile>
+      <AdditionalOptions>/PDBALTPATH:%_PDB% %(AdditionalOptions)</AdditionalOptions>
     </Link>
   </ItemDefinitionGroup>
   <ItemGroup>
-    <ClCompile Include="ancilla.c" />
-    <ClCompile Include="attract.c" />
-    <ClCompile Include="config.c" />
-    <ClCompile Include="dungeon.c" />
-    <ClCompile Include="ending.c" />
-    <ClCompile Include="glsl_shader.c" />
-    <ClCompile Include="hud.c" />
-    <ClCompile Include="load_gfx.c" />
-    <ClCompile Include="main.c">
-      <Optimization Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Disabled</Optimization>
-      <Optimization Condition="'$(Configuration)|$(Platform)'=='ReleaseDeploy|x64'">Disabled</Optimization>
-      <InlineFunctionExpansion Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Disabled</InlineFunctionExpansion>
-    </ClCompile>
-    <ClCompile Include="messaging.c" />
-    <ClCompile Include="misc.c" />
-    <ClCompile Include="audio.c" />
-    <ClCompile Include="nmi.c" />
-    <ClCompile Include="overlord.c" />
-    <ClCompile Include="overworld.c" />
-    <ClCompile Include="platform\win32\volume_control.c" />
-    <ClCompile Include="player.c" />
-    <ClCompile Include="player_oam.c" />
-    <ClCompile Include="poly.c" />
-    <ClCompile Include="select_file.c" />
-    <ClCompile Include="opengl.c" />
+    <ClCompile Include="src\ancilla.c" />
+    <ClCompile Include="src\attract.c" />
+    <ClCompile Include="src\config.c" />
+    <ClCompile Include="src\dungeon.c" />
+    <ClCompile Include="src\ending.c" />
+    <ClCompile Include="src\glsl_shader.c" />
+    <ClCompile Include="src\hud.c" />
+    <ClCompile Include="src\load_gfx.c" />
+    <ClCompile Include="src\main.c" />
+    <ClCompile Include="src\messaging.c" />
+    <ClCompile Include="src\misc.c" />
+    <ClCompile Include="src\audio.c" />
+    <ClCompile Include="src\nmi.c" />
+    <ClCompile Include="src\overlord.c" />
+    <ClCompile Include="src\overworld.c" />
+    <ClCompile Include="src\platform\win32\volume_control.c" />
+    <ClCompile Include="src\player.c" />
+    <ClCompile Include="src\player_oam.c" />
+    <ClCompile Include="src\poly.c" />
+    <ClCompile Include="src\select_file.c" />
+    <ClCompile Include="src\opengl.c" />
     <ClCompile Include="snes\apu.c">
       <Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Disabled</Optimization>
       <InlineFunctionExpansion Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Disabled</InlineFunctionExpansion>
@@ -276,13 +284,10 @@
       <InlineFunctionExpansion Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Disabled</InlineFunctionExpansion>
     </ClCompile>
     <ClCompile Include="snes\tracing.c" />
-    <ClCompile Include="spc_player.c" />
-    <ClCompile Include="sprite.c" />
-    <ClCompile Include="sprite_main.c">
-      <Optimization Condition="'$(Configuration)|$(Platform)'=='Release|x64'">MaxSpeed</Optimization>
-      <Optimization Condition="'$(Configuration)|$(Platform)'=='ReleaseDeploy|x64'">MaxSpeed</Optimization>
-    </ClCompile>
-    <ClCompile Include="tagalong.c" />
+    <ClCompile Include="src\spc_player.c" />
+    <ClCompile Include="src\sprite.c" />
+    <ClCompile Include="src\sprite_main.c" />
+    <ClCompile Include="src\tagalong.c" />
     <ClCompile Include="third_party\gl_core\gl_core_3_1.c" />
     <ClCompile Include="third_party\opus-1.3.1-stripped\bands.c">
       <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
@@ -429,34 +434,34 @@
       <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseDeploy|x64'">true</ExcludedFromBuild>
       <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
     </ClCompile>
-    <ClCompile Include="tile_detect.c" />
-    <ClCompile Include="util.c" />
-    <ClCompile Include="zelda_cpu_infra.c" />
-    <ClCompile Include="zelda_rtl.c" />
+    <ClCompile Include="src\tile_detect.c" />
+    <ClCompile Include="src\util.c" />
+    <ClCompile Include="src\zelda_cpu_infra.c" />
+    <ClCompile Include="src\zelda_rtl.c" />
   </ItemGroup>
   <ItemGroup>
-    <ClInclude Include="ancilla.h" />
-    <ClInclude Include="assets.h" />
-    <ClInclude Include="attract.h" />
-    <ClInclude Include="config.h" />
-    <ClInclude Include="dungeon.h" />
-    <ClInclude Include="ending.h" />
-    <ClInclude Include="features.h" />
-    <ClInclude Include="glsl_shader.h" />
-    <ClInclude Include="hud.h" />
-    <ClInclude Include="load_gfx.h" />
-    <ClInclude Include="messaging.h" />
-    <ClInclude Include="misc.h" />
-    <ClInclude Include="audio.h" />
-    <ClInclude Include="nmi.h" />
-    <ClInclude Include="overlord.h" />
-    <ClInclude Include="overworld.h" />
-    <ClInclude Include="platform\win32\volume_control.h" />
-    <ClInclude Include="player.h" />
-    <ClInclude Include="player_oam.h" />
-    <ClInclude Include="poly.h" />
-    <ClInclude Include="platform\win32\resource.h" />
-    <ClInclude Include="select_file.h" />
+    <ClInclude Include="src\ancilla.h" />
+    <ClInclude Include="src\assets.h" />
+    <ClInclude Include="src\attract.h" />
+    <ClInclude Include="src\config.h" />
+    <ClInclude Include="src\dungeon.h" />
+    <ClInclude Include="src\ending.h" />
+    <ClInclude Include="src\features.h" />
+    <ClInclude Include="src\glsl_shader.h" />
+    <ClInclude Include="src\hud.h" />
+    <ClInclude Include="src\load_gfx.h" />
+    <ClInclude Include="src\messaging.h" />
+    <ClInclude Include="src\misc.h" />
+    <ClInclude Include="src\audio.h" />
+    <ClInclude Include="src\nmi.h" />
+    <ClInclude Include="src\overlord.h" />
+    <ClInclude Include="src\overworld.h" />
+    <ClInclude Include="src\platform\win32\volume_control.h" />
+    <ClInclude Include="src\player.h" />
+    <ClInclude Include="src\player_oam.h" />
+    <ClInclude Include="src\poly.h" />
+    <ClInclude Include="src\platform\win32\resource.h" />
+    <ClInclude Include="src\select_file.h" />
     <ClInclude Include="snes\apu.h" />
     <ClInclude Include="snes\cart.h" />
     <ClInclude Include="snes\cpu.h" />
@@ -470,10 +475,10 @@
     <ClInclude Include="snes\snes_regs.h" />
     <ClInclude Include="snes\spc.h" />
     <ClInclude Include="snes\tracing.h" />
-    <ClInclude Include="spc_player.h" />
-    <ClInclude Include="sprite.h" />
-    <ClInclude Include="sprite_main.h" />
-    <ClInclude Include="tagalong.h" />
+    <ClInclude Include="src\spc_player.h" />
+    <ClInclude Include="src\sprite.h" />
+    <ClInclude Include="src\sprite_main.h" />
+    <ClInclude Include="src\tagalong.h" />
     <ClInclude Include="third_party\gl_core\gl_core_3_1.h" />
     <ClInclude Include="third_party\opus-1.3.1-stripped\arch.h">
       <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
@@ -731,22 +736,22 @@
       <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseDeploy|x64'">true</ExcludedFromBuild>
       <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
     </ClInclude>
-    <ClInclude Include="tile_detect.h" />
-    <ClInclude Include="types.h" />
-    <ClInclude Include="util.h" />
-    <ClInclude Include="variables.h" />
-    <ClInclude Include="zelda_cpu_infra.h" />
-    <ClInclude Include="zelda_rtl.h" />
+    <ClInclude Include="src\tile_detect.h" />
+    <ClInclude Include="src\types.h" />
+    <ClInclude Include="src\util.h" />
+    <ClInclude Include="src\variables.h" />
+    <ClInclude Include="src\zelda_cpu_infra.h" />
+    <ClInclude Include="src\zelda_rtl.h" />
   </ItemGroup>
   <ItemGroup>
     <None Include="packages.config" />
   </ItemGroup>
   <ItemGroup>
-    <ResourceCompile Include="platform\win32\zelda3.rc" />
+    <ResourceCompile Include="src\platform\win32\zelda3.rc" />
   </ItemGroup>
   <ItemGroup>
-    <Image Include="platform\win32\triforce.ico" />
-    <Image Include="platform\linux\triforce.png" />
+    <Image Include="src\platform\win32\triforce.ico" />
+    <Image Include="src\platform\linux\triforce.png" />
   </ItemGroup>
   <ItemGroup>
     <Content Include="LICENSE.txt">
--- a/zelda3.vcxproj.filters
+++ b/zelda3.vcxproj.filters
@@ -31,123 +31,6 @@
     </Filter>
   </ItemGroup>
   <ItemGroup>
-    <ClCompile Include="snes\apu.c">
-      <Filter>Snes</Filter>
-    </ClCompile>
-    <ClCompile Include="snes\cart.c">
-      <Filter>Snes</Filter>
-    </ClCompile>
-    <ClCompile Include="snes\cpu.c">
-      <Filter>Snes</Filter>
-    </ClCompile>
-    <ClCompile Include="snes\dma.c">
-      <Filter>Snes</Filter>
-    </ClCompile>
-    <ClCompile Include="snes\dsp.c">
-      <Filter>Snes</Filter>
-    </ClCompile>
-    <ClCompile Include="snes\input.c">
-      <Filter>Snes</Filter>
-    </ClCompile>
-    <ClCompile Include="snes\ppu.c">
-      <Filter>Snes</Filter>
-    </ClCompile>
-    <ClCompile Include="snes\snes.c">
-      <Filter>Snes</Filter>
-    </ClCompile>
-    <ClCompile Include="snes\snes_other.c">
-      <Filter>Snes</Filter>
-    </ClCompile>
-    <ClCompile Include="snes\spc.c">
-      <Filter>Snes</Filter>
-    </ClCompile>
-    <ClCompile Include="zelda_rtl.c">
-      <Filter>Zelda</Filter>
-    </ClCompile>
-    <ClCompile Include="hud.c">
-      <Filter>Zelda</Filter>
-    </ClCompile>
-    <ClCompile Include="dungeon.c">
-      <Filter>Zelda</Filter>
-    </ClCompile>
-    <ClCompile Include="nmi.c">
-      <Filter>Zelda</Filter>
-    </ClCompile>
-    <ClCompile Include="player_oam.c">
-      <Filter>Zelda</Filter>
-    </ClCompile>
-    <ClCompile Include="load_gfx.c">
-      <Filter>Zelda</Filter>
-    </ClCompile>
-    <ClCompile Include="messaging.c">
-      <Filter>Zelda</Filter>
-    </ClCompile>
-    <ClCompile Include="overworld.c">
-      <Filter>Zelda</Filter>
-    </ClCompile>
-    <ClCompile Include="sprite.c">
-      <Filter>Zelda</Filter>
-    </ClCompile>
-    <ClCompile Include="sprite_main.c">
-      <Filter>Zelda</Filter>
-    </ClCompile>
-    <ClCompile Include="tagalong.c">
-      <Filter>Zelda</Filter>
-    </ClCompile>
-    <ClCompile Include="overlord.c">
-      <Filter>Zelda</Filter>
-    </ClCompile>
-    <ClCompile Include="poly.c">
-      <Filter>Zelda</Filter>
-    </ClCompile>
-    <ClCompile Include="ancilla.c">
-      <Filter>Zelda</Filter>
-    </ClCompile>
-    <ClCompile Include="ending.c">
-      <Filter>Zelda</Filter>
-    </ClCompile>
-    <ClCompile Include="attract.c">
-      <Filter>Zelda</Filter>
-    </ClCompile>
-    <ClCompile Include="select_file.c">
-      <Filter>Zelda</Filter>
-    </ClCompile>
-    <ClCompile Include="spc_player.c">
-      <Filter>Zelda</Filter>
-    </ClCompile>
-    <ClCompile Include="player.c">
-      <Filter>Zelda</Filter>
-    </ClCompile>
-    <ClCompile Include="tile_detect.c">
-      <Filter>Zelda</Filter>
-    </ClCompile>
-    <ClCompile Include="misc.c">
-      <Filter>Zelda</Filter>
-    </ClCompile>
-    <ClCompile Include="zelda_cpu_infra.c">
-      <Filter>Zelda</Filter>
-    </ClCompile>
-    <ClCompile Include="config.c">
-      <Filter>Zelda</Filter>
-    </ClCompile>
-    <ClCompile Include="platform\win32\volume_control.c">
-      <Filter>Platform</Filter>
-    </ClCompile>
-    <ClCompile Include="main.c">
-      <Filter>Zelda</Filter>
-    </ClCompile>
-    <ClCompile Include="snes\tracing.c">
-      <Filter>Snes</Filter>
-    </ClCompile>
-    <ClCompile Include="opengl.c">
-      <Filter>Zelda</Filter>
-    </ClCompile>
-    <ClCompile Include="glsl_shader.c">
-      <Filter>Zelda</Filter>
-    </ClCompile>
-    <ClCompile Include="util.c">
-      <Filter>Zelda</Filter>
-    </ClCompile>
     <ClCompile Include="third_party\gl_core\gl_core_3_1.c">
       <Filter>third_party</Filter>
     </ClCompile>
@@ -154,9 +37,6 @@
     <ClCompile Include="third_party\opus-1.3.1-stripped\opus_decoder_amalgam.c">
       <Filter>third_party\Opus</Filter>
     </ClCompile>
-    <ClCompile Include="audio.c">
-      <Filter>Zelda</Filter>
-    </ClCompile>
     <ClCompile Include="third_party\opus-1.3.1-stripped\bands.c">
       <Filter>third_party\Opus</Filter>
     </ClCompile>
@@ -211,8 +91,39 @@
     <ClCompile Include="third_party\opus-1.3.1-stripped\x86\x86cpu.c">
       <Filter>third_party\Opus</Filter>
     </ClCompile>
-  </ItemGroup>
-  <ItemGroup>
+    <ClCompile Include="snes\apu.c">
+      <Filter>Snes</Filter>
+    </ClCompile>
+    <ClCompile Include="snes\cart.c">
+      <Filter>Snes</Filter>
+    </ClCompile>
+    <ClCompile Include="snes\cpu.c">
+      <Filter>Snes</Filter>
+    </ClCompile>
+    <ClCompile Include="snes\dma.c">
+      <Filter>Snes</Filter>
+    </ClCompile>
+    <ClCompile Include="snes\dsp.c">
+      <Filter>Snes</Filter>
+    </ClCompile>
+    <ClCompile Include="snes\input.c">
+      <Filter>Snes</Filter>
+    </ClCompile>
+    <ClCompile Include="snes\ppu.c">
+      <Filter>Snes</Filter>
+    </ClCompile>
+    <ClCompile Include="snes\snes.c">
+      <Filter>Snes</Filter>
+    </ClCompile>
+    <ClCompile Include="snes\snes_other.c">
+      <Filter>Snes</Filter>
+    </ClCompile>
+    <ClCompile Include="snes\spc.c">
+      <Filter>Snes</Filter>
+    </ClCompile>
+    <ClCompile Include="snes\tracing.c">
+      <Filter>Snes</Filter>
+    </ClCompile>
     <ClInclude Include="snes\apu.h">
       <Filter>Snes</Filter>
     </ClInclude>
@@ -243,114 +154,107 @@
     <ClInclude Include="snes\spc.h">
       <Filter>Snes</Filter>
     </ClInclude>
-    <ClInclude Include="zelda_rtl.h">
-      <Filter>Zelda</Filter>
+    <ClInclude Include="snes\dsp_regs.h">
+      <Filter>Snes</Filter>
     </ClInclude>
-    <ClInclude Include="hud.h">
-      <Filter>Zelda</Filter>
+    <ClInclude Include="snes\snes_regs.h">
+      <Filter>Snes</Filter>
     </ClInclude>
-    <ClInclude Include="dungeon.h">
-      <Filter>Zelda</Filter>
+    <ClInclude Include="snes\tracing.h">
+      <Filter>Snes</Filter>
     </ClInclude>
-    <ClInclude Include="nmi.h">
+    <ClCompile Include="src\ancilla.c">
       <Filter>Zelda</Filter>
-    </ClInclude>
-    <ClInclude Include="load_gfx.h">
+    </ClCompile>
+    <ClCompile Include="src\dungeon.c">
       <Filter>Zelda</Filter>
-    </ClInclude>
-    <ClInclude Include="overworld.h">
+    </ClCompile>
+    <ClCompile Include="src\ending.c">
       <Filter>Zelda</Filter>
-    </ClInclude>
-    <ClInclude Include="variables.h">
+    </ClCompile>
+    <ClCompile Include="src\glsl_shader.c">
       <Filter>Zelda</Filter>
-    </ClInclude>
-    <ClInclude Include="sprite.h">
+    </ClCompile>
+    <ClCompile Include="src\hud.c">
       <Filter>Zelda</Filter>
-    </ClInclude>
-    <ClInclude Include="tagalong.h">
+    </ClCompile>
+    <ClCompile Include="src\load_gfx.c">
       <Filter>Zelda</Filter>
-    </ClInclude>
-    <ClInclude Include="overlord.h">
+    </ClCompile>
+    <ClCompile Include="src\main.c">
       <Filter>Zelda</Filter>
-    </ClInclude>
-    <ClInclude Include="poly.h">
+    </ClCompile>
+    <ClCompile Include="src\messaging.c">
       <Filter>Zelda</Filter>
-    </ClInclude>
-    <ClInclude Include="ancilla.h">
+    </ClCompile>
+    <ClCompile Include="src\misc.c">
       <Filter>Zelda</Filter>
-    </ClInclude>
-    <ClInclude Include="ending.h">
+    </ClCompile>
+    <ClCompile Include="src\opengl.c">
       <Filter>Zelda</Filter>
-    </ClInclude>
-    <ClInclude Include="select_file.h">
+    </ClCompile>
+    <ClCompile Include="src\nmi.c">
       <Filter>Zelda</Filter>
-    </ClInclude>
-    <ClInclude Include="tile_detect.h">
+    </ClCompile>
+    <ClCompile Include="src\overworld.c">
       <Filter>Zelda</Filter>
-    </ClInclude>
-    <ClInclude Include="types.h">
+    </ClCompile>
+    <ClCompile Include="src\overlord.c">
       <Filter>Zelda</Filter>
-    </ClInclude>
-    <ClInclude Include="player.h">
+    </ClCompile>
+    <ClCompile Include="src\player.c">
       <Filter>Zelda</Filter>
-    </ClInclude>
-    <ClInclude Include="misc.h">
+    </ClCompile>
+    <ClCompile Include="src\player_oam.c">
       <Filter>Zelda</Filter>
-    </ClInclude>
-    <ClInclude Include="player_oam.h">
+    </ClCompile>
+    <ClCompile Include="src\poly.c">
       <Filter>Zelda</Filter>
-    </ClInclude>
-    <ClInclude Include="messaging.h">
+    </ClCompile>
+    <ClCompile Include="src\select_file.c">
       <Filter>Zelda</Filter>
-    </ClInclude>
-    <ClInclude Include="attract.h">
+    </ClCompile>
+    <ClCompile Include="src\spc_player.c">
       <Filter>Zelda</Filter>
-    </ClInclude>
-    <ClInclude Include="zelda_cpu_infra.h">
+    </ClCompile>
+    <ClCompile Include="src\sprite.c">
       <Filter>Zelda</Filter>
-    </ClInclude>
-    <ClInclude Include="spc_player.h">
+    </ClCompile>
+    <ClCompile Include="src\sprite_main.c">
       <Filter>Zelda</Filter>
-    </ClInclude>
-    <ClInclude Include="sprite_main.h">
+    </ClCompile>
+    <ClCompile Include="src\tagalong.c">
       <Filter>Zelda</Filter>
-    </ClInclude>
-    <ClInclude Include="snes\dsp_regs.h">
-      <Filter>Snes</Filter>
-    </ClInclude>
-    <ClInclude Include="platform\win32\resource.h">
-      <Filter>Resource Files</Filter>
-    </ClInclude>
-    <ClInclude Include="config.h">
+    </ClCompile>
+    <ClCompile Include="src\tile_detect.c">
       <Filter>Zelda</Filter>
-    </ClInclude>
-    <ClInclude Include="snes\snes_regs.h">
-      <Filter>Snes</Filter>
-    </ClInclude>
-    <ClInclude Include="platform\win32\volume_control.h">
-      <Filter>Platform</Filter>
-    </ClInclude>
-    <ClInclude Include="assets.h">
+    </ClCompile>
+    <ClCompile Include="src\util.c">
       <Filter>Zelda</Filter>
-    </ClInclude>
-    <ClInclude Include="features.h">
+    </ClCompile>
+    <ClCompile Include="src\platform\win32\volume_control.c">
       <Filter>Zelda</Filter>
-    </ClInclude>
-    <ClInclude Include="snes\tracing.h">
-      <Filter>Snes</Filter>
-    </ClInclude>
-    <ClInclude Include="glsl_shader.h">
+    </ClCompile>
+    <ClCompile Include="src\zelda_cpu_infra.c">
       <Filter>Zelda</Filter>
-    </ClInclude>
-    <ClInclude Include="util.h">
+    </ClCompile>
+    <ClCompile Include="src\zelda_rtl.c">
       <Filter>Zelda</Filter>
-    </ClInclude>
+    </ClCompile>
+    <ClCompile Include="src\attract.c">
+      <Filter>Zelda</Filter>
+    </ClCompile>
+    <ClCompile Include="src\audio.c">
+      <Filter>Zelda</Filter>
+    </ClCompile>
+    <ClCompile Include="src\config.c">
+      <Filter>Zelda</Filter>
+    </ClCompile>
+  </ItemGroup>
+  <ItemGroup>
     <ClInclude Include="third_party\gl_core\gl_core_3_1.h">
       <Filter>third_party</Filter>
     </ClInclude>
-    <ClInclude Include="audio.h">
-      <Filter>Zelda</Filter>
-    </ClInclude>
     <ClInclude Include="third_party\opus-1.3.1-stripped\_kiss_fft_guts.h">
       <Filter>third_party\Opus</Filter>
     </ClInclude>
@@ -447,24 +351,112 @@
     <ClInclude Include="third_party\opus-1.3.1-stripped\x86\x86cpu.h">
       <Filter>third_party\Opus</Filter>
     </ClInclude>
+    <ClInclude Include="src\ancilla.h">
+      <Filter>Zelda</Filter>
+    </ClInclude>
+    <ClInclude Include="src\assets.h">
+      <Filter>Zelda</Filter>
+    </ClInclude>
+    <ClInclude Include="src\attract.h">
+      <Filter>Zelda</Filter>
+    </ClInclude>
+    <ClInclude Include="src\audio.h">
+      <Filter>Zelda</Filter>
+    </ClInclude>
+    <ClInclude Include="src\config.h">
+      <Filter>Zelda</Filter>
+    </ClInclude>
+    <ClInclude Include="src\dungeon.h">
+      <Filter>Zelda</Filter>
+    </ClInclude>
+    <ClInclude Include="src\ending.h">
+      <Filter>Zelda</Filter>
+    </ClInclude>
+    <ClInclude Include="src\features.h">
+      <Filter>Zelda</Filter>
+    </ClInclude>
+    <ClInclude Include="src\glsl_shader.h">
+      <Filter>Zelda</Filter>
+    </ClInclude>
+    <ClInclude Include="src\hud.h">
+      <Filter>Zelda</Filter>
+    </ClInclude>
+    <ClInclude Include="src\load_gfx.h">
+      <Filter>Zelda</Filter>
+    </ClInclude>
+    <ClInclude Include="src\messaging.h">
+      <Filter>Zelda</Filter>
+    </ClInclude>
+    <ClInclude Include="src\misc.h">
+      <Filter>Zelda</Filter>
+    </ClInclude>
+    <ClInclude Include="src\nmi.h">
+      <Filter>Zelda</Filter>
+    </ClInclude>
+    <ClInclude Include="src\overlord.h">
+      <Filter>Zelda</Filter>
+    </ClInclude>
+    <ClInclude Include="src\overworld.h">
+      <Filter>Zelda</Filter>
+    </ClInclude>
+    <ClInclude Include="src\player.h">
+      <Filter>Zelda</Filter>
+    </ClInclude>
+    <ClInclude Include="src\player_oam.h">
+      <Filter>Zelda</Filter>
+    </ClInclude>
+    <ClInclude Include="src\poly.h">
+      <Filter>Zelda</Filter>
+    </ClInclude>
+    <ClInclude Include="src\platform\win32\resource.h">
+      <Filter>Zelda</Filter>
+    </ClInclude>
+    <ClInclude Include="src\select_file.h">
+      <Filter>Zelda</Filter>
+    </ClInclude>
+    <ClInclude Include="src\spc_player.h">
+      <Filter>Zelda</Filter>
+    </ClInclude>
+    <ClInclude Include="src\sprite.h">
+      <Filter>Zelda</Filter>
+    </ClInclude>
+    <ClInclude Include="src\sprite_main.h">
+      <Filter>Zelda</Filter>
+    </ClInclude>
+    <ClInclude Include="src\tagalong.h">
+      <Filter>Zelda</Filter>
+    </ClInclude>
+    <ClInclude Include="src\tile_detect.h">
+      <Filter>Zelda</Filter>
+    </ClInclude>
+    <ClInclude Include="src\types.h">
+      <Filter>Zelda</Filter>
+    </ClInclude>
+    <ClInclude Include="src\util.h">
+      <Filter>Zelda</Filter>
+    </ClInclude>
+    <ClInclude Include="src\variables.h">
+      <Filter>Zelda</Filter>
+    </ClInclude>
+    <ClInclude Include="src\platform\win32\volume_control.h">
+      <Filter>Zelda</Filter>
+    </ClInclude>
+    <ClInclude Include="src\zelda_cpu_infra.h">
+      <Filter>Zelda</Filter>
+    </ClInclude>
+    <ClInclude Include="src\zelda_rtl.h">
+      <Filter>Zelda</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
-    <None Include="packages.config" />
-  </ItemGroup>
-  <ItemGroup>
-    <Image Include="platform\win32\triforce.ico">
-      <Filter>Resource Files</Filter>
+    <Image Include="src\platform\win32\triforce.ico">
+      <Filter>Zelda</Filter>
     </Image>
-    <Image Include="platform\linux\triforce.png">
-      <Filter>Resource Files</Filter>
+    <Image Include="src\platform\linux\triforce.png">
+      <Filter>Zelda</Filter>
     </Image>
   </ItemGroup>
   <ItemGroup>
-    <ResourceCompile Include="platform\win32\zelda3.rc">
-      <Filter>Resource Files</Filter>
-    </ResourceCompile>
-  </ItemGroup>
-  <ItemGroup>
     <Text Include="LICENSE.txt">
       <Filter>Deploy</Filter>
     </Text>
@@ -481,6 +473,9 @@
     <None Include="tables\zelda3_assets.dat">
       <Filter>Deploy\tables</Filter>
     </None>
+    <None Include="packages.config">
+      <Filter>Zelda</Filter>
+    </None>
   </ItemGroup>
   <ItemGroup>
     <None Include="saves\ref\Chapter 1 - Zelda's Rescue.sav">
@@ -522,5 +517,10 @@
     <None Include="saves\ref\Chapter 13 - After Ganon's Tower.sav">
       <Filter>Deploy\saverefs</Filter>
     </None>
+  </ItemGroup>
+  <ItemGroup>
+    <ResourceCompile Include="src\platform\win32\zelda3.rc">
+      <Filter>Zelda</Filter>
+    </ResourceCompile>
   </ItemGroup>
 </Project>
\ No newline at end of file
--- a/zelda_cpu_infra.c
+++ /dev/null
@@ -1,585 +1,0 @@
-// This file handles running zelda through the emulated cpu.
-// It defines the runtime environment for the emulated side-by-side state.
-// It should be possible to build and run the game without this file
-#include "zelda_cpu_infra.h"
-#include "zelda_rtl.h"
-#include "variables.h"
-#include "spc_player.h"
-#include "snes/snes.h"
-#include "snes/snes_regs.h"
-#include "snes/cpu.h"
-#include "snes/cart.h"
-#include "snes/tracing.h"
-
-Snes *g_snes;
-Cpu *g_cpu;
-uint8 g_emulated_ram[0x20000];
-
-static void PatchRom(uint8 *rom);
-
-uint8 *GetPtr(uint32 addr) {
-  Cart *cart = g_snes->cart;
-  return &cart->rom[(((addr >> 16) << 15) | (addr & 0x7fff)) & (cart->romSize - 1)];
-}
-
-uint8 *GetCartRamPtr(uint32 addr) {
-  Cart *cart = g_snes->cart;
-  return &cart->ram[addr];
-}
-
-typedef struct Snapshot {
-  uint16 a, x, y, sp, dp, pc;
-  uint8 k, db, flags;
-  uint8 ram[0x20000];
-  uint16 vram[0x8000];
-  uint16 sram[0x2000];
-} Snapshot;
-
-static Snapshot g_snapshot_mine, g_snapshot_theirs, g_snapshot_before;
-
-static void MakeSnapshot(Snapshot *s) {
-  Cpu *c = g_cpu;
-  s->a = c->a, s->x = c->x, s->y = c->y;
-  s->sp = c->sp, s->dp = c->dp, s->db = c->db;
-  s->pc = c->pc, s->k = c->k;
-  s->flags = cpu_getFlags(c);
-  memcpy(s->ram, g_snes->ram, 0x20000);
-  memcpy(s->sram, g_snes->cart->ram, g_snes->cart->ramSize);
-  memcpy(s->vram, g_snes->ppu->vram, sizeof(uint16) * 0x8000);
-  memcpy(s->ram + 0x1DBA0, s->ram + 0x1B00, 224 * 2);  // hdma_table (partial)
-}
-
-static void MakeMySnapshot(Snapshot *s) {
-  memcpy(s->ram, g_zenv.ram, 0x20000);
-  memcpy(s->sram, g_zenv.sram, 0x2000);
-  memcpy(s->vram, g_zenv.ppu->vram, sizeof(uint16) * 0x8000);
-  memcpy(s->ram + 0x1B00, s->ram + 0x1DBA0, 224 * 2);  // hdma_table (partial)
-}
-
-static void RestoreMySnapshot(Snapshot *s) {
-  memcpy(g_zenv.ram, s->ram, 0x20000);
-  memcpy(g_zenv.sram, s->sram, 0x2000);
-  memcpy(g_zenv.ppu->vram, s->vram, sizeof(uint16) * 0x8000);
-}
-
-static void RestoreSnapshot(Snapshot *s) {
-  Cpu *c = g_cpu;
-
-  c->a = s->a, c->x = s->x, c->y = s->y;
-  c->sp = s->sp, c->dp = s->dp, c->db = s->db;
-  c->pc = s->pc, c->k = s->k;
-  cpu_setFlags(c, s->flags);
-  memcpy(g_snes->ram, s->ram, 0x20000);
-  memcpy(g_snes->cart->ram, s->sram, g_snes->cart->ramSize);
-  memcpy(g_snes->ppu->vram, s->vram, sizeof(uint16) * 0x8000);
-}
-
-static bool g_fail;
-
-// b is mine, a is theirs
-static void VerifySnapshotsEq(Snapshot *b, Snapshot *a, Snapshot *prev) {
-  memcpy(b->ram, a->ram, 16);
-  b->ram[0xfa1] = a->ram[0xfa1];
-  b->ram[0x72] = a->ram[0x72];
-  b->ram[0x73] = a->ram[0x73];
-  b->ram[0x74] = a->ram[0x74];
-  b->ram[0x75] = a->ram[0x75];
-  b->ram[0xb7] = a->ram[0xb7];
-  b->ram[0xb8] = a->ram[0xb8];
-  b->ram[0xb9] = a->ram[0xb9];
-  b->ram[0xba] = a->ram[0xba];
-  b->ram[0xbb] = a->ram[0xbb];
-  b->ram[0xbd] = a->ram[0xbd];
-  b->ram[0xbe] = a->ram[0xbe];
-  b->ram[0xc8] = a->ram[0xc8];
-  b->ram[0xc9] = a->ram[0xc9];
-  b->ram[0xca] = a->ram[0xca];
-  b->ram[0xcb] = a->ram[0xcb];
-  b->ram[0xcc] = a->ram[0xcc];
-  b->ram[0xcd] = a->ram[0xcd];
-  b->ram[0xa0] = a->ram[0xa0];
-  b->ram[0x128] = a->ram[0x128];  // irq_flag
-  b->ram[0x463] = a->ram[0x463];  // which_staircase_index_padding
-
-  // c code is authoritative
-  WORD(a->ram[0x1f0a]) = WORD(b->ram[0x1f0a]);
-
-  memcpy(&b->ram[0x1f0d], &a->ram[0x1f0d], 0x3f - 0xd);
-  memcpy(b->ram + 0x138, a->ram + 0x138, 256 - 0x38); // copy the stack over
-
-  memcpy(a->ram + 0x1cc0, b->ram + 0x1cc0, 2);  // some leftover stuff in hdma table
-  memcpy(a->ram + 0x1dd60, b->ram + 0x1dd60, 16 * 2);  // some leftover stuff in hdma table
-
-  memcpy(a->ram + 0x1db20, b->ram + 0x1db20, 64 * 2);  // msu
-  a->ram[0x654] = b->ram[0x654];  // msu_volume
-
-  memcpy(a->ram + 0x1CDD, b->ram + 0x1CDD, 2);  // dialogue_msg_src_offs
-  
-  if (memcmp(b->ram, a->ram, 0x20000)) {
-    fprintf(stderr, "@%d: Memory compare failed (mine != theirs, prev):\n", frame_counter);
-    int j = 0;
-    for (size_t i = 0; i < 0x20000; i++) {
-      if (a->ram[i] != b->ram[i]) {
-        if (++j < 128) {
-          if ((i&1) == 0 && a->ram[i + 1] != b->ram[i + 1]) {
-            fprintf(stderr, "0x%.6X: %.4X != %.4X (%.4X)\n", (int)i, 
-              WORD(b->ram[i]), WORD(a->ram[i]), WORD(prev->ram[i]));
-            i++, j++;
-          } else {
-            fprintf(stderr, "0x%.6X: %.2X != %.2X (%.2X)\n", (int)i, b->ram[i], a->ram[i], prev->ram[i]);
-          }
-        }
-      }
-    }
-    if (j)
-      g_fail = true;
-    fprintf(stderr, "  total of %d failed bytes\n", (int)j);
-  }
-
-  if (memcmp(b->sram, a->sram, 0x2000)) {
-    fprintf(stderr, "@%d: SRAM compare failed (mine != theirs, prev):\n", frame_counter);
-    int j = 0;
-    for (size_t i = 0; i < 0x2000; i++) {
-      if (a->sram[i] != b->sram[i]) {
-        if (++j < 128) {
-          if ((i&1) == 0 && a->sram[i + 1] != b->sram[i + 1]) {
-            fprintf(stderr, "0x%.6X: %.4X != %.4X (%.4X)\n", (int)i, 
-              WORD(b->sram[i]), WORD(a->sram[i]), WORD(prev->sram[i]));
-            i++, j++;
-          } else {
-            fprintf(stderr, "0x%.6X: %.2X != %.2X (%.2X)\n", (int)i, b->sram[i], a->sram[i], prev->sram[i]);
-          }
-        }
-      }
-    }
-    if (j)
-      g_fail = true;
-    fprintf(stderr, "  total of %d failed bytes\n", (int)j);
-  }
-
-  if (memcmp(b->vram, a->vram, sizeof(uint16) * 0x8000)) {
-    fprintf(stderr, "@%d: VRAM compare failed (mine != theirs, prev):\n", frame_counter);
-    for (size_t i = 0, j = 0; i < 0x8000; i++) {
-      if (a->vram[i] != b->vram[i]) {
-        fprintf(stderr, "0x%.6X: %.4X != %.4X (%.4X)\n", (int)i, b->vram[i], a->vram[i], prev->vram[i]);
-        g_fail = true;
-        if (++j >= 16)
-          break;
-      }
-    }
-  }
-}
-
-uint8_t *RomByte(Cart *cart, uint32_t addr) {
-  return &cart->rom[(((addr >> 16) << 15) | (addr & 0x7fff)) & (cart->romSize - 1)];
-}
-
-bool g_calling_asm_from_c;
-
-void HookedFunctionRts(int is_long) {
-  if (g_calling_asm_from_c) {
-    g_calling_asm_from_c = false;
-    return;
-  }
-  assert(0);
-}
-
-void RunEmulatedFunc(uint32 pc, uint16 a, uint16 x, uint16 y, bool mf, bool xf, int b, int whatflags) {
-  g_snes->debug_cycles = 1;
-  RunEmulatedFuncSilent(pc, a, x, y, mf, xf, b, whatflags | 2);
-  g_snes->debug_cycles = 0;
-}
-
-void RunEmulatedFuncSilent(uint32 pc, uint16 a, uint16 x, uint16 y, bool mf, bool xf, int b, int whatflags) {
-  uint16 org_sp = g_cpu->sp;
-  uint16 org_pc = g_cpu->pc;
-  uint8 org_b = g_cpu->db;
-  uint8 org_dp = g_cpu->dp;
-  if (b != -1)
-    g_cpu->db = b >= 0 ? b : pc >> 16;
-  if (b == -3)
-    g_cpu->dp = 0x1f00;
-
-  static uint8 *rambak;
-  if (rambak == 0) rambak = (uint8 *)malloc(0x20000);
-  memcpy(rambak, g_emulated_ram, 0x20000);
-  memcpy(g_emulated_ram, g_ram, 0x20000);
-
-  if (whatflags & 2)
-    g_emulated_ram[0x1ffff] = 0x67;
-
-  g_cpu->a = a;
-  g_cpu->x = x;
-  g_cpu->y = y;
-  g_cpu->spBreakpoint = g_cpu->sp;
-  g_cpu->k = (pc >> 16);
-  g_cpu->pc = (pc & 0xffff);
-  g_cpu->mf = mf;
-  g_cpu->xf = xf;
-  g_calling_asm_from_c = true;
-  while (g_calling_asm_from_c) {
-    if (g_snes->debug_cycles) {
-      char line[80];
-      getProcessorStateCpu(g_snes, line);
-      puts(line);
-    }
-    cpu_runOpcode(g_cpu);
-    while (g_snes->dma->dmaBusy)
-      dma_doDma(g_snes->dma);
-
-    if (whatflags & 1) {
-/*      if (apu_debugging == 2 && g_snes->apu->cpuCyclesLeft == 0) {
-        char line[80];
-        getProcessorStateSpc(g_snes->apu, line);
-        puts(line);
-      }*/
-//      apu_cycle(g_snes->apu);
-    }
-  }
-  g_cpu->dp = org_dp;
-  g_cpu->sp = org_sp;
-  g_cpu->db = org_b;
-  g_cpu->pc = org_pc;
-
-  memcpy(g_ram, g_emulated_ram, 0x20000);
-  memcpy(g_emulated_ram, rambak, 0x20000);
-}
-
-void RunOrigAsmCodeOneLoop(Snes *snes) {
-  Cpu *cpu = snes->cpu;
-  cpu->a = cpu->x = cpu->y = 0;
-  cpu->e = false;
-  cpu->irqWanted = cpu->nmiWanted = cpu->waiting = cpu->stopped = 0;
-  cpu_setFlags(cpu, 0x30);
-
-  // Run until the wait loop in Interrupt_Reset,
-  // Or the polyhedral main function.
-  for(int loops = 0;;loops++) {
-    snes_printCpuLine(snes);
-    cpu_runOpcode(snes->cpu);
-    while (snes->dma->dmaBusy)
-      dma_doDma(snes->dma);
-
-    uint32_t pc = snes->cpu->k << 16 | snes->cpu->pc;
-    if (pc == 0x8034 || pc == 0x9f81d && loops >= 10 || pc == 0x8225 || pc == 0x82D2)
-      break;
-  }
-}
-
-static void RunEmulatedSnesFrame(Snes *snes, int run_what) {
-  // First call runs until init
-  if (snes->cpu->pc == 0x8000 && snes->cpu->k == 0) {
-    RunOrigAsmCodeOneLoop(snes);
-    g_emulated_ram[0x12] = 1;
-    // Fixup uninitialized variable
-    *(uint16*)(g_emulated_ram+0xAE0) = 0xb280;
-    *(uint16*)(g_emulated_ram+0xAE2) = 0xb280 + 0x60;
-  }
-
-  // Run poly code
-  if (run_what & 2) {
-    Cpu *cpu = snes->cpu;
-    cpu->sp = 0x1f3e;
-    cpu->pc = 0xf81d;
-    cpu->db = cpu->k = 9;
-    cpu->dp = 0x1f00;
-    RunOrigAsmCodeOneLoop(snes);
-  }
-    
-  // Run main code
-  if (run_what & 1) {
-    Cpu *cpu = g_snes->cpu;
-    cpu->sp = 0x1ff;
-    cpu->pc = 0x8034;
-    cpu->k = cpu->dp = cpu->db = 0;
-    RunOrigAsmCodeOneLoop(snes);
-  }
-
-  snes_doAutoJoypad(snes);
-
-  // animated_tile_vram_addr uninited
-  if (snes->ram[0xadd] == 0)
-    *(uint16_t*)&snes->ram[0xadc] = 0xa680;
-
-  // In one code path flag_update_hud_in_nmi uses an undefined value
-  snes_write(snes, DMAP0, 0x01);
-  snes_write(snes, BBAD0, 0x18);
-
-  // Run NMI handler
-  Cpu *cpu = g_snes->cpu;
-  cpu->sp = 0x1ff;
-  cpu->pc = 0x80D9;
-  cpu->k = cpu->dp = cpu->db = 0;
-  RunOrigAsmCodeOneLoop(snes);
-}
-
-
-// Copy state into the emulator, we can skip dsp/apu because 
-// we're not emulating that.
-static void EmuSynchronizeWholeState() {
-  *g_snes->ppu = *g_zenv.ppu;
-  memcpy(g_snes->ram, g_zenv.ram, 0x20000);
-  memcpy(g_snes->cart->ram, g_zenv.sram, 0x2000);
-  memcpy(g_snes->dma->channel, g_zenv.dma->channel, sizeof(Dma) - offsetof(Dma, channel));
-
-  // todo: this is hacky
-  if (animated_tile_data_src == 0)
-    cpu_reset(g_snes->cpu);
-}
-
-void EmuRunFrameWithCompare(uint16 input_state, int run_what) {
-  MakeSnapshot(&g_snapshot_before);
-  MakeMySnapshot(&g_snapshot_mine);
-  MakeSnapshot(&g_snapshot_theirs);
-
-  // Compare both snapshots before we run the frame, to see they match
-  VerifySnapshotsEq(&g_snapshot_mine, &g_snapshot_theirs, &g_snapshot_before);
-  if (g_fail) {
-    printf("early fail\n");
-    assert(0);
-    //return turbo;
-  }
-
-  // Run orig version then snapshot
-again_theirs:
-  g_snes->input1->currentState = input_state;
-  RunEmulatedSnesFrame(g_snes, run_what);
-  MakeSnapshot(&g_snapshot_theirs);
-
-  // Run my version and snapshot
-again_mine:
-  ZeldaRunFrameInternal(input_state, run_what);
-
-  MakeMySnapshot(&g_snapshot_mine);
-
-  // Compare both snapshots
-  VerifySnapshotsEq(&g_snapshot_mine, &g_snapshot_theirs, &g_snapshot_before);
-
-  if (g_fail) {
-    g_fail = false;
-    if (1) {
-      RestoreMySnapshot(&g_snapshot_before);
-      //SaveLoadSlot(kSaveLoad_Save, 0);
-      if (0)
-        goto again_mine;
-      RestoreSnapshot(&g_snapshot_before);
-      goto again_theirs;
-    }
-    if (1) {
-      MakeSnapshot(&g_snapshot_theirs);
-      RestoreMySnapshot(&g_snapshot_theirs);
-    }
-  }
-}
-
-
-static void PatchRomBP(uint8_t *rom, uint32_t addr) {
-  rom[(addr >> 16) << 15 | (addr & 0x7fff)] = 0;
-}
-
-static void PatchRomByte(uint8_t *rom, uint32_t addr, uint8 old_value, uint8 value) {
-  assert(rom[(addr >> 16) << 15 | (addr & 0x7fff)] == old_value);
-  rom[(addr >> 16) << 15 | (addr & 0x7fff)] = value;
-}
-
-static void PatchRomWord(uint8_t *rom, uint32_t addr, uint16 old_value, uint16 value) {
-  assert(WORD(rom[(addr >> 16) << 15 | (addr & 0x7fff)]) == old_value);
-  WORD(rom[(addr >> 16) << 15 | (addr & 0x7fff)]) = value;
-}
-
-static void PatchRomArray(uint8_t *rom, uint32_t addr, const uint8 *values, int n) {
-  for (int i = 0; i < n; i++) {
-    rom[(addr >> 16) << 15 | (addr & 0x7fff)] = values[i];
-    addr += 1;
-  }
-}
-
-
-
-static void PatchRom(uint8_t *rom) {
-  //  fix a bug with unitialized memory
-  {
-    uint8_t *p = rom + 0x36434;
-    memmove(p, p + 2, 7);
-    p[7] = 0xb0;
-    p[8] = 0x40 - 7;
-  }
-
-  // BufferAndBuildMap16Stripes_Y can read bad memory if int is negative
-  if (1) {
-    uint8_t *p = rom + 0x10000 - 0x8000;
-    int thunk = 0xFF6E;
-    uint8_t *tp = p + thunk;
-
-    *tp++ = 0xc0; *tp++ = 0x00; *tp++ = 0x20;
-    *tp++ = 0x90; *tp++ = 0x03;
-    *tp++ = 0xa9; *tp++ = 0x00; *tp++ = 0x00;
-    *tp++ = 0x9d; *tp++ = 0x00; *tp++ = 0x05;
-    *tp++ = 0x60;
-
-    p[0xf4a7] = 0x20; p[0xf4a8] = thunk; p[0xf4a9] = thunk >> 8;
-    p[0xf4b5] = 0x20; p[0xf4b6] = thunk; p[0xf4b7] = thunk >> 8;
-
-    p[0xf3dd] = 0x20; p[0xf3de] = thunk; p[0xf3df] = thunk >> 8;
-    p[0xf3ef] = 0x20; p[0xf3f0] = thunk; p[0xf3f1] = thunk >> 8;
-  }
-
-  // Better random numbers
-  if (1) {
-    // 8D:FFC1                      new_random_gen:
-    int new_routine = 0xffc1;
-    uint8_t *p = rom + 0x60000, *tp = p + new_routine;
-
-    *tp++ = 0xad; *tp++ = 0xa1; *tp++ = 0x0f;  // mov.b   A, byte_7E0FA1
-    *tp++ = 0x18; *tp++ = 0x65; *tp++ = 0x1a;  // add.b   A, frame_counter
-    *tp++ = 0x4a;                              // lsr     A
-    *tp++ = 0xb0; *tp++ = 0x02;                // jnb     loc_8DFFCC
-    *tp++ = 0x49; *tp++ = 0xb8;                // eor.b   A, #0xB8
-    *tp++ = 0x8d; *tp++ = 0xa1; *tp++ = 0x0f;  // byte_7E0FA1, A
-    *tp++ = 0x18;                              // clc
-    *tp++ = 0x6b;                              // retf
-
-    p[0xBA71] = 0x4c; p[0xBA72] = new_routine; p[0xBA73] = new_routine >> 8;
-  }
-
-  {
-
-  }
-
-  // Fix so SmashRockPile_fromLift / Overworld_DoMapUpdate32x32_B preserves R2/R0 destroyed
-  {
-    /*
-    .9B:BFA2 A5 00                 mov.w   A, R0
-    .9B:BFA4 48                    push    A
-    .9B:BFA5 A5 02                 mov.w   A, R2
-    .9B:BFA7 48                    push    A
-    .9B:C0F1 22 5C AD 02           callf   Overworld_DoMapUpdate32x32_B
-    .9B:C048 68                    pop     A
-    .9B:C049 85 00                 mov.w   R0, A
-    .9B:C04B 68                    pop     A
-    .9B:C04C 85 02                 mov.w   R2, A
-    */
-    uint8_t *tp = rom + 0x6ffd8;
-    *tp++ = 0xa5; *tp++ = 0x00; *tp++ = 0x48;
-    *tp++ = 0xa5; *tp++ = 0x02; *tp++ = 0x48;
-    *tp++ = 0x22; *tp++ = 0x5c; *tp++ = 0xad; *tp++ = 0x02;
-    *tp++ = 0xc2; *tp++ = 0x30;
-    *tp++ = 0x68; *tp++ = 0x85; *tp++ = 0x02;
-    *tp++ = 0x68; *tp++ = 0x85; *tp++ = 0x00;
-    *tp++ = 0x6b;
-
-    int target = 0xDFFD8;  // DoorAnim_DoWork2_Preserving
-
-    rom[0xdc0f2] = target;
-    rom[0xdc0f3] = target >> 8;
-    rom[0xdc0f4] = target >> 16;
-  }
-
-  rom[0x2dec7] = 0;  // Fix Uncle_Embark reading bad ram
-
-  rom[0x4be5e] = 0;  // Overlord05_FallingStalfos doesn't initialize the sprite_D memory location
-
-  rom[0xD79A4] = 0;  // 0x1AF9A4: // Lanmola_SpawnShrapnel uses undefined carry value
-
-  rom[0xF0A46] = 0;  // 0x1E8A46 Helmasaur Carry Junk
-  rom[0xF0A52] = 0;  // 0x1E8A52 Helmasaur Carry Junk
-
-  rom[0xef9b9] = 0xb9; // TalkingTree_SpitBomb
-
-  rom[0xdf107] = 0xa2;
-  rom[0xdf108] = 0x03;
-  rom[0xdf109] = 0x6b;  // Palette_AgahnimClone destoys X
-
-
-  rom[0x4a966] = 0;  // Follower_AnimateMovement_preserved
-
-  PatchRomBP(rom, 0x1de0e5);
-  PatchRomBP(rom, 0x6d0b6);
-  PatchRomBP(rom, 0x6d0c6);
-
-  PatchRomBP(rom, 0x1d8f29); // adc instead of add
-  PatchRomBP(rom, 0x1DDBD3); // adc instead of add
-  PatchRomBP(rom, 0x1DF856); // adc instead of add
-  PatchRomBP(rom, 0x1E88DA); // adc instead of add
-
-  PatchRomBP(rom, 0x06ED0B);
-
-  PatchRomBP(rom, 0x1dc812); // adc instead of add
-
-  PatchRomBP(rom, 0x9b46c); // adc instead of add
-  PatchRomBP(rom, 0x9b478); // adc instead of add
-
-  PatchRomBP(rom, 0x9B468);  // sbc
-  PatchRomBP(rom, 0x9B46A);
-  PatchRomBP(rom, 0x9B474);
-  PatchRomBP(rom, 0x9B476);
-  PatchRomBP(rom, 0x9B60C);
-
-  PatchRomBP(rom, 0x8f708); // don't init scratch_c
-
-  PatchRomBP(rom, 0x1DCDEB); // y is destroyed earlier, restore it..
-
-  PatchRomBP(rom, 0x7B269);  // Link_APress_LiftCarryThrow oob
-
-  // Smithy_Frog doesn't save X
-  memmove(rom + 0x332b8, rom + 0x332b7, 4); rom[0x332b7] = 0xfa;
-
-  // This needs to be here because the ancilla code reads
-  // from the apu and we don't want to make the core code
-  // dependent on the apu timings, so relocated this value
-  // to 0x648.
-  rom[0x443fe] = 0x48; rom[0x443ff] = 0x6;
-  rom[0x44607] = 0x48; rom[0x44608] = 0x6;
-
-  // AncillaAdd_AddAncilla_Bank09 destroys R14
-  rom[0x49d0c] = 0xda; rom[0x49d0d] = 0xfa; 
-  rom[0x49d0f] = 0xda; rom[0x49d10] = 0xfa; 
-
-  // Prevent LoadSongBank from executing in the rom because it hangs
-  rom[0x888] = 0x60;
-
-  // CleanUpAndPrepDesertPrayerHDMA clearing too much
-  PatchRomWord(rom, 0x2C7E5 + 1, 0x1df, 0x1cf);
-
-  // Merge ancilla_arr23 with boomerang_arr1 because they're only 3 bytes long,
-  // and boomerang might get allocated in slot 4.
-  PatchRomByte(rom, 0x9816C, 0xd2, 0xCF);
-  PatchRomByte(rom, 0xffdeb, 0xd2, 0xCF);
-  PatchRomByte(rom, 0xffdee, 0xd2, 0xCF);
-  PatchRomByte(rom, 0xffdf7, 0xd2, 0xCF);
-  PatchRomByte(rom, 0xffdfa, 0xd2, 0xCF);
-
-  // Relocate the door debris variables so they become 5 entries each (they were 2 before).
-  static const int kDoorDebrisX_Uses[] = {0x1CFC6, 0x1d29d, 0x89794, 0x897a3, 0x8a0a1, 0x8edca, 0x99aa6};
-  for (int i = 0; i < countof(kDoorDebrisX_Uses); i++) PatchRomWord(rom, kDoorDebrisX_Uses[i] + 1, 0x3b6, 0x728);
-  static const int kDoorDebrisX1_Uses[] = { 0x89797, 0x897A6 };
-  for (int i = 0; i < countof(kDoorDebrisX1_Uses); i++) PatchRomWord(rom, kDoorDebrisX1_Uses[i] + 1, 0x3b7, 0x729);
-  static const int kDoorDebrisY_Uses[] = { 0x1CFD7, 0x1D2AE, 0x8A099, 0x8EDC5, 0x99AA1 };
-  for (int i = 0; i < countof(kDoorDebrisY_Uses); i++) PatchRomWord(rom, kDoorDebrisY_Uses[i] + 1, 0x3ba, 0x732);
-  static const int kDoorDebrisDir_Uses[] = { 0x1CFB2, 0x1D2BA, 0x8A0B7 };
-  for (int i = 0; i < countof(kDoorDebrisDir_Uses); i++) PatchRomWord(rom, kDoorDebrisDir_Uses[i] + 1, 0x3be, 0x73c);
-  static const int ancilla_arr26_Uses[] = { 0x89fb9, 0x89fc0, 0x98157, 0x99c49 };
-  for (int i = 0; i < countof(ancilla_arr26_Uses); i++) PatchRomWord(rom, ancilla_arr26_Uses[i] + 1, 0x3c0, 0x741);
-  static const int ancilla_arr25_Uses[] = { 0x89fc3, 0x89fc6, 0x8a0ae, 0x8ab7c, 0x8aba7, 0x8abb6, 0x8ae92, 0x8bae2, 0x8baff, 0x8f429, 0x98148, 0x98e0a, 0x98ebc, 0x9920a, 0x9931e, 0x9987f, 0x99c44 };
-  for (int i = 0; i < countof(ancilla_arr25_Uses); i++) PatchRomWord(rom, ancilla_arr25_Uses[i] + 1, 0x3c2, 0x746);
-  static const int ancilla_arr22_Uses[] = { 0x9816e, 0xffde0, 0xffde7 };
-  for (int i = 0; i < countof(ancilla_arr22_Uses); i++) PatchRomWord(rom, ancilla_arr22_Uses[i] + 1, 0x3e1, 0x74b);
-
-  PatchRomWord(rom, 0xddfac + 1, 0xfa85, 0xfa70); // call Hud_Rebuild instead of Hud_UpdateOnly
-
-  // Make sure it's not calling Decomp_spr on tilesheets less than 12
-  PatchRomWord(rom, 0xe589, 0xe772, 0xe852);  // call New addr
-  static const uint8 kFixSoItWontDecodeSheetLessThan12[] = { 0xc0, 0x0c, 0xb0, 0x02, 0xa0, 0x0c, 0x4c, 0x72, 0xe7 };
-  PatchRomArray(rom, 0xe852, kFixSoItWontDecodeSheetLessThan12, sizeof(kFixSoItWontDecodeSheetLessThan12));
-}
-
-
-
-bool EmuInitialize(uint8 *data, size_t size) {
-  PatchRom(data);
-  g_snes = snes_init(g_emulated_ram);
-  g_cpu = g_snes->cpu;
-
-  ZeldaSetupEmuCallbacks(g_emulated_ram, &EmuRunFrameWithCompare, &EmuSynchronizeWholeState);
-  return snes_loadRom(g_snes, data, (int)size);
-}
--- a/zelda_cpu_infra.h
+++ /dev/null
@@ -1,14 +1,0 @@
-#ifndef ZELDA3_ZELDA_CPU_INFRA_H_
-#define ZELDA3_ZELDA_CPU_INFRA_H_
-#include "types.h"
-
-extern uint8 g_emulated_ram[0x20000];
-
-uint8 *GetPtr(uint32 addr);
-
-void RunEmulatedFuncSilent(uint32 pc, uint16 a, uint16 x, uint16 y, bool mf, bool xf, int b, int whatflags);
-void RunEmulatedFunc(uint32 pc, uint16 a, uint16 x, uint16 y, bool mf, bool xf, int b, int whatflags);
-
-bool EmuInitialize(uint8 *data, size_t size);
-
-#endif  // ZELDA3_ZELDA_CPU_INFRA_H_
--- a/zelda_rtl.c
+++ /dev/null
@@ -1,890 +1,0 @@
-#include "zelda_rtl.h"
-#include "variables.h"
-#include "misc.h"
-#include "nmi.h"
-#include "poly.h"
-#include "attract.h"
-#include "snes/ppu.h"
-#include "snes/snes_regs.h"
-#include "snes/dma.h"
-#include "spc_player.h"
-#include "util.h"
-#include "audio.h"
-#include "assets.h"
-ZeldaEnv g_zenv;
-uint8 g_ram[131072];
-
-uint32 g_wanted_zelda_features;
-
-static void Startup_InitializeMemory();
-
-typedef struct SimpleHdma {
-  const uint8 *table;
-  const uint8 *indir_ptr;
-  uint8 rep_count;
-  uint8 mode;
-  uint8 ppu_addr;
-  uint8 indir_bank;
-} SimpleHdma;
-static void SimpleHdma_Init(SimpleHdma *c, DmaChannel *dc);
-static void SimpleHdma_DoLine(SimpleHdma *c);
-
-static const uint8 bAdrOffsets[8][4] = {
-  {0, 0, 0, 0},
-  {0, 1, 0, 1},
-  {0, 0, 0, 0},
-  {0, 0, 1, 1},
-  {0, 1, 2, 3},
-  {0, 1, 0, 1},
-  {0, 0, 0, 0},
-  {0, 0, 1, 1}
-};
-static const uint8 transferLength[8] = {
-  1, 2, 2, 4, 4, 4, 2, 4
-};
-const uint16 kUpperBitmasks[] = { 0x8000, 0x4000, 0x2000, 0x1000, 0x800, 0x400, 0x200, 0x100, 0x80, 0x40, 0x20, 0x10, 8, 4, 2, 1 };
-const uint8 kLitTorchesColorPlus[] = {31, 8, 4, 0};
-const uint8 kDungeonCrystalPendantBit[13] = {0, 0, 4, 2, 0, 16, 2, 1, 64, 4, 1, 32, 8};
-const int8 kGetBestActionToPerformOnTile_x[4] = { 7, 7, -3, 16 };
-const int8 kGetBestActionToPerformOnTile_y[4] = { 6, 24, 12, 12 };
-#define AT_WORD(x) (uint8)(x), (x)>>8
-// direct
-static const uint8 kAttractDmaTable0[13] = {0x20, AT_WORD(0x00ff), 0x50, AT_WORD(0xe018), 0x50, AT_WORD(0xe018), 1, AT_WORD(0x00ff), 0};
-static const uint8 kAttractDmaTable1[10] = {0x48, AT_WORD(0x00ff), 0x30, AT_WORD(0xd830), 1, AT_WORD(0x00ff), 0};
-static const uint8 kHdmaTableForEnding[19] = {
-  0x52, AT_WORD(0x600), 8, AT_WORD(0xe2), 8, AT_WORD(0x602), 5, AT_WORD(0x604), 0x10, AT_WORD(0x606), 0x81, AT_WORD(0xe2), 0,
-};
-static const uint8 kSpotlightIndirectHdma[7] = {0xf8, AT_WORD(0x1b00), 0xf8, AT_WORD(0x1bf0), 0};
-static const uint8 kMapModeHdma0[7] = {0xf0, AT_WORD(0xdd27), 0xf0, AT_WORD(0xde07), 0};
-static const uint8 kMapModeHdma1[7] = {0xf0, AT_WORD(0xdee7), 0xf0, AT_WORD(0xdfc7), 0};
-static const uint8 kAttractIndirectHdmaTab[7] = {0xf0, AT_WORD(0x1b00), 0xf0, AT_WORD(0x1be0), 0};
-static const uint8 kHdmaTableForPrayingScene[7] = {0xf8, AT_WORD(0x1b00), 0xf8, AT_WORD(0x1bf0), 0};
-
-void zelda_ppu_write(uint32_t adr, uint8_t val) {
-  assert(adr >= INIDISP && adr <= STAT78);
-  ppu_write(g_zenv.ppu, (uint8)adr, val);
-}
-
-void zelda_ppu_write_word(uint32_t adr, uint16_t val) {
-  zelda_ppu_write(adr, val);
-  zelda_ppu_write(adr + 1, val >> 8);
-}
-
-static const uint8 *SimpleHdma_GetPtr(uint32 p) {
-  switch (p) {
-
-  case 0xCFA87: return kAttractDmaTable0;
-  case 0xCFA94: return kAttractDmaTable1;
-  case 0xebd53: return kHdmaTableForEnding;
-  case 0x0F2FB: return kSpotlightIndirectHdma;
-  case 0xabdcf: return kMapModeHdma0;             // mode7
-  case 0xabdd6: return kMapModeHdma1;             // mode7
-  case 0xABDDD: return kAttractIndirectHdmaTab;   // mode7
-  case 0x2c80c: return kHdmaTableForPrayingScene;
-
-  case 0x1b00: return (uint8 *)hdma_table_dynamic;
-  case 0x1be0: return (uint8 *)hdma_table_dynamic + 0xe0;
-  case 0x1bf0: return (uint8 *)hdma_table_dynamic + 0xf0;
-  case 0xadd27: return (uint8*)kMapMode_Zooms1;
-  case 0xade07: return (uint8*)kMapMode_Zooms1 + 0xe0;
-  case 0xadee7: return (uint8*)kMapMode_Zooms2;
-  case 0xadfc7: return (uint8*)kMapMode_Zooms2 + 0xe0;
-  case 0x600: return &g_ram[0x600];
-  case 0x602: return &g_ram[0x602];
-  case 0x604: return &g_ram[0x604];
-  case 0x606: return &g_ram[0x606];
-  case 0xe2: return &g_ram[0xe2];
-  default:
-    assert(0);
-    return NULL;
-  }
-}
-
-static void SimpleHdma_Init(SimpleHdma *c, DmaChannel *dc) {
-  if (!dc->hdmaActive) {
-    c->table = 0;
-    return;
-  }
-  c->table = SimpleHdma_GetPtr(dc->aAdr | dc->aBank << 16);
-  c->rep_count = 0;
-  c->mode = dc->mode | dc->indirect << 6;
-  c->ppu_addr = dc->bAdr;
-  c->indir_bank = dc->indBank;
-}
-
-static void SimpleHdma_DoLine(SimpleHdma *c) {
-  if (c->table == NULL)
-    return;
-  bool do_transfer = false;
-  if ((c->rep_count & 0x7f) == 0) {
-    c->rep_count = *c->table++;
-    if (c->rep_count == 0) {
-      c->table = NULL;
-      return;
-    }
-    if(c->mode & 0x40) {
-      c->indir_ptr = SimpleHdma_GetPtr(c->indir_bank << 16 | c->table[0] | c->table[1] * 256);
-      c->table += 2;
-    }
-    do_transfer = true;
-  }
-  if(do_transfer || c->rep_count & 0x80) {
-    for(int j = 0, j_end = transferLength[c->mode & 7]; j < j_end; j++) {
-      uint8 v = c->mode & 0x40 ? *c->indir_ptr++ : *c->table++;
-      zelda_ppu_write(0x2100 + c->ppu_addr + bAdrOffsets[c->mode & 7][j], v);
-    }
-  }
-  c->rep_count--;
-}
-
-static void ConfigurePpuSideSpace() {
-  // Let PPU impl know about the maximum allowed extra space on the sides and bottom
-  int extra_right = 0, extra_left = 0, extra_bottom = 0;
-//  printf("main %d, sub %d  (%d, %d, %d)\n", main_module_index, submodule_index, BG2HOFS_copy2, room_bounds_x.v[2 | (quadrant_fullsize_x >> 1)], quadrant_fullsize_x >> 1);
-  int mod = main_module_index;
-  if (mod == 14)
-    mod = saved_module_for_menu;
-  if (mod == 9) {
-    if (main_module_index == 14 && submodule_index == 7 && overworld_map_state >= 4) {
-      // World map
-      extra_left = kPpuExtraLeftRight, extra_right = kPpuExtraLeftRight;
-      extra_bottom = 16;
-    } else {
-      // outdoors
-      extra_left = BG2HOFS_copy2 - ow_scroll_vars0.xstart;
-      extra_right = ow_scroll_vars0.xend - BG2HOFS_copy2;
-      extra_bottom = ow_scroll_vars0.yend - BG2VOFS_copy2;
-    }
-  } else if (mod == 7) {
-    // indoors, except when the light cone is in use
-    if (!(hdr_dungeon_dark_with_lantern && TS_copy != 0)) {
-      int qm = quadrant_fullsize_x >> 1;
-      extra_left = IntMax(BG2HOFS_copy2 - room_bounds_x.v[qm], 0);
-      extra_right = IntMax(room_bounds_x.v[qm + 2] - BG2HOFS_copy2, 0);
-    }
-
-    int qy = quadrant_fullsize_y >> 1;
-    extra_bottom = IntMax(room_bounds_y.v[qy + 2] - BG2VOFS_copy2, 0);
-  } else if (mod == 20 || mod == 0 || mod == 1) {
-    extra_left = kPpuExtraLeftRight, extra_right = kPpuExtraLeftRight;
-    extra_bottom = 16;
-  }
-  PpuSetExtraSideSpace(g_zenv.ppu, extra_left, extra_right, extra_bottom);
-}
-
-void ZeldaDrawPpuFrame(uint8 *pixel_buffer, size_t pitch, uint32 render_flags) {
-  SimpleHdma hdma_chans[2];
-
-  PpuBeginDrawing(g_zenv.ppu, pixel_buffer, pitch, render_flags);
-
-  dma_startDma(g_zenv.dma, HDMAEN_copy, true);
-
-  SimpleHdma_Init(&hdma_chans[0], &g_zenv.dma->channel[6]);
-  SimpleHdma_Init(&hdma_chans[1], &g_zenv.dma->channel[7]);
-
-  // Cheat: Let the PPU impl know about the hdma perspective correction so it can avoid guessing.
-  if ((render_flags & kPpuRenderFlags_4x4Mode7) && g_zenv.ppu->mode == 7) {
-    if (hdma_chans[0].table == kMapModeHdma0)
-      PpuSetMode7PerspectiveCorrection(g_zenv.ppu, kMapMode_Zooms1[0], kMapMode_Zooms1[223]);
-    else if (hdma_chans[0].table == kMapModeHdma1)
-      PpuSetMode7PerspectiveCorrection(g_zenv.ppu, kMapMode_Zooms2[0], kMapMode_Zooms2[223]);
-    else if (hdma_chans[0].table == kAttractIndirectHdmaTab)
-      PpuSetMode7PerspectiveCorrection(g_zenv.ppu, hdma_table_dynamic[0], hdma_table_dynamic[223]);
-    else
-      PpuSetMode7PerspectiveCorrection(g_zenv.ppu, 0, 0);
-  }
-
-  if (g_zenv.ppu->extraLeftRight != 0 || render_flags & kPpuRenderFlags_Height240)
-    ConfigurePpuSideSpace();
-
-  int height = render_flags & kPpuRenderFlags_Height240 ? 240 : 224;
-
-  for (int i = 0; i <= height; i++) {
-    if (i == 128 && irq_flag) {
-      zelda_ppu_write(BG3HOFS, selectfile_var8);
-      zelda_ppu_write(BG3HOFS, selectfile_var8 >> 8);
-      zelda_ppu_write(BG3VOFS, 0);
-      zelda_ppu_write(BG3VOFS, 0);
-      if (irq_flag & 0x80) {
-        irq_flag = 0;
-        zelda_snes_dummy_write(NMITIMEN, 0x81);
-      }
-    }
-    ppu_runLine(g_zenv.ppu, i);
-    SimpleHdma_DoLine(&hdma_chans[0]);
-    SimpleHdma_DoLine(&hdma_chans[1]);
-  }
-}
-
-void HdmaSetup(uint32 addr6, uint32 addr7, uint8 transfer_unit, uint8 reg6, uint8 reg7, uint8 indirect_bank) {
-  Dma *dma = g_zenv.dma;
-  if (addr6) {
-    dma_write(dma, DMAP6, transfer_unit);
-    dma_write(dma, BBAD6, reg6);
-    dma_write(dma, A1T6L, addr6);
-    dma_write(dma, A1T6H, addr6 >> 8);
-    dma_write(dma, A1B6, addr6 >> 16);
-    dma_write(dma, DAS60, indirect_bank);
-  }
-  dma_write(dma, DMAP7, transfer_unit);
-  dma_write(dma, BBAD7, reg7);
-  dma_write(dma, A1T7L, addr7);
-  dma_write(dma, A1T7H, addr7 >> 8);
-  dma_write(dma, A1B7, addr7 >> 16);
-  dma_write(dma, DAS70, indirect_bank);
-}
-
-static void ZeldaInitializationCode() {
-  zelda_snes_dummy_write(NMITIMEN, 0);
-  zelda_snes_dummy_write(HDMAEN, 0);
-  zelda_snes_dummy_write(MDMAEN, 0);
-
-  Sound_LoadIntroSongBank();
-
-  Startup_InitializeMemory();
-
-  animated_tile_data_src = 0xa680;
-  dma_source_addr_9 = 0xb280;
-  dma_source_addr_14 = 0xb280 + 0x60;
-  zelda_snes_dummy_write(NMITIMEN, 0x81);
-}
-
-static void ClearOamBuffer() {  // 80841e
-  for (int i = 0; i < 128; i++)
-    oam_buf[i].y = 0xf0;
-}
-
-static void ZeldaRunGameLoop() {
-  frame_counter++;
-  ClearOamBuffer();
-  Module_MainRouting();
-  NMI_PrepareSprites();
-  nmi_boolean = 0;
-}
-
-void ZeldaInitialize() {
-  g_zenv.dma = dma_init(NULL);
-  g_zenv.ppu = ppu_init(NULL);
-  g_zenv.ram = g_ram;
-  g_zenv.sram = (uint8*)calloc(8192, 1);
-  g_zenv.vram = g_zenv.ppu->vram;
-  g_zenv.player = SpcPlayer_Create();
-  SpcPlayer_Initialize(g_zenv.player);
-  dma_reset(g_zenv.dma);
-  ppu_reset(g_zenv.ppu);
-}
-
-static void ZeldaRunPolyLoop() {
-  if (intro_did_run_step && !nmi_flag_update_polyhedral) {
-    Poly_RunFrame();
-    intro_did_run_step = 0;
-    nmi_flag_update_polyhedral = 0xff;
-  }
-}
-
-void ZeldaRunFrameInternal(uint16 input, int run_what) {
-  if (animated_tile_data_src == 0)
-    ZeldaInitializationCode();
-
-  if (run_what & 2)
-    ZeldaRunPolyLoop();
-  if (run_what & 1)
-    ZeldaRunGameLoop();
-  Interrupt_NMI(input);
-}
-
-
-static int IncrementCrystalCountdown(uint8 *a, int v) {
-  int t = *a + v;
-  *a = t;
-  return t >> 8;
-}
-
-int frame_ctr_dbg;
-static uint8 *g_emu_memory_ptr;
-static ZeldaRunFrameFunc *g_emu_runframe;
-static ZeldaSyncAllFunc *g_emu_syncall;
-
-void ZeldaSetupEmuCallbacks(uint8 *emu_ram, ZeldaRunFrameFunc *func, ZeldaSyncAllFunc *sync_all) {
-  g_emu_memory_ptr = emu_ram;
-  g_emu_runframe = func;
-  g_emu_syncall = sync_all;
-}
-
-static void EmuSynchronizeWholeState() {
-  if (g_emu_syncall)
-    g_emu_syncall();
-}
-
-// |ptr| must be a pointer into g_ram, will synchronize the RAM memory with the
-// emulator.
-static void EmuSyncMemoryRegion(void *ptr, size_t n) {
-  uint8 *data = (uint8 *)ptr;
-  assert(data >= g_ram && data < g_ram + 0x20000);
-  if (g_emu_memory_ptr)
-    memcpy(g_emu_memory_ptr + (data - g_ram), data, n);
-}
-
-static void Startup_InitializeMemory() {  // 8087c0
-  memset(g_ram + 0x0, 0, 0x2000);
-  main_palette_buffer[0] = 0;
-  srm_var1 = 0;
-  uint8 *sram = g_zenv.sram;
-  if (WORD(sram[0x3e5]) != 0x55aa)
-    WORD(sram[0x3e5]) = 0;
-  if (WORD(sram[0x8e5]) != 0x55aa)
-    WORD(sram[0x8e5]) = 0;
-  if (WORD(sram[0xde5]) != 0x55aa)
-    WORD(sram[0xde5]) = 0;
-  INIDISP_copy = 0x80;
-  flag_update_cgram_in_nmi++;
-}
-
-void ByteArray_AppendVl(ByteArray *arr, uint32 v) {
-  for (; v >= 255; v -= 255)
-    ByteArray_AppendByte(arr, 255);
-  ByteArray_AppendByte(arr, v);
-}
-
-void saveFunc(void *ctx_in, void *data, size_t data_size) {
-  ByteArray_AppendData((ByteArray *)ctx_in, data, data_size);
-}
-
-typedef struct LoadFuncState {
-  uint8 *p, *pend;
-} LoadFuncState;
-
-void loadFunc(void *ctx, void *data, size_t data_size) {
-  LoadFuncState *st = (LoadFuncState *)ctx;
-  assert(st->pend - st->p >= data_size);
-  memcpy(data, st->p, data_size);
-  st->p += data_size;
-}
-
-static void InternalSaveLoad(SaveLoadFunc *func, void *ctx) {
-  uint8 junk[58] = { 0 };
-  func(ctx, junk, 27);
-  func(ctx, g_zenv.player->ram, 0x10000);  // apu ram
-  func(ctx, junk, 40); // junk
-  dsp_saveload(g_zenv.player->dsp, func, ctx); // 3024 bytes of dsp
-  func(ctx, junk, 15); // spc junk
-  dma_saveload(g_zenv.dma, func, ctx); // 192 bytes of dma state
-  ppu_saveload(g_zenv.ppu, func, ctx); // 66619 + 512 + 174
-  func(ctx, g_zenv.sram, 0x2000);  // 8192 bytes of sram
-  func(ctx, junk, 58); // snes junk
-  func(ctx, g_zenv.ram, 0x20000);  // 0x20000 bytes of ram
-  func(ctx, junk, 4); // snes junk
-}
-
-void ZeldaReset(bool preserve_sram) {
-  frame_ctr_dbg = 0;
-  dma_reset(g_zenv.dma);
-  ppu_reset(g_zenv.ppu);
-  memset(g_zenv.ram, 0, 0x20000);
-  if (!preserve_sram)
-    memset(g_zenv.sram, 0, 0x2000);
-  ZeldaApuLock();
-  ZeldaRestoreMusicAfterLoad_Locked(true);
-  ZeldaApuUnlock();
-  EmuSynchronizeWholeState();
-
-}
-
-static void LoadSnesState(SaveLoadFunc *func, void *ctx) {
-  // Do the actual loading
-  ZeldaApuLock();
-  InternalSaveLoad(func, ctx);
-  memcpy(g_zenv.ram + 0x1DBA0, g_zenv.ram + 0x1b00, 224 * 2); // hdma table was moved
-
-  ZeldaRestoreMusicAfterLoad_Locked(false);
-  ZeldaApuUnlock();
-  EmuSynchronizeWholeState();
-}
-
-static void SaveSnesState(SaveLoadFunc *func, void *ctx) {
-  memcpy(g_zenv.ram + 0x1b00, g_zenv.ram + 0x1DBA0, 224 * 2); // hdma table was moved
-  ZeldaApuLock();
-  ZeldaSaveMusicStateToRam_Locked();
-  InternalSaveLoad(func, ctx);
-  ZeldaApuUnlock();
-}
-
-typedef struct StateRecorder {
-  uint16 last_inputs;
-  uint32 frames_since_last;
-  uint32 total_frames;
-
-  // For replay
-  uint32 replay_pos, replay_pos_last_complete;
-  uint32 replay_frame_counter;
-  uint32 replay_next_cmd_at;
-  uint8 replay_cmd;
-  bool replay_mode;
-
-  ByteArray log;
-  ByteArray base_snapshot;
-} StateRecorder;
-
-static StateRecorder state_recorder;
-
-void StateRecorder_Init(StateRecorder *sr) {
-  memset(sr, 0, sizeof(*sr));
-}
-
-void StateRecorder_RecordCmd(StateRecorder *sr, uint8 cmd) {
-  int frames = sr->frames_since_last;
-  sr->frames_since_last = 0;
-  int x = (cmd < 0xc0) ? 0xf : 0x1;
-  ByteArray_AppendByte(&sr->log, cmd | (frames < x ? frames : x));
-  if (frames >= x)
-    ByteArray_AppendVl(&sr->log, frames - x);
-}
-
-void StateRecorder_Record(StateRecorder *sr, uint16 inputs) {
-  uint16 diff = inputs ^ sr->last_inputs;
-  if (diff != 0) {
-    sr->last_inputs = inputs;
-    //    printf("0x%.4x %d: ", diff, sr->frames_since_last);
-    //    size_t lb = sr->log.size;
-    for (int i = 0; i < 12; i++) {
-      if ((diff >> i) & 1)
-        StateRecorder_RecordCmd(sr, i << 4);
-    }
-    //    while (lb < sr->log.size)
-    //      printf("%.2x ", sr->log.data[lb++]);
-    //    printf("\n");
-  }
-  sr->frames_since_last++;
-  sr->total_frames++;
-}
-
-void StateRecorder_RecordPatchByte(StateRecorder *sr, uint32 addr, const uint8 *value, int num) {
-  assert(addr < 0x20000);
-
-  //  printf("%d: PatchByte(0x%x, 0x%x. %d): ", sr->frames_since_last, addr, *value, num);
-  //  size_t lb = sr->log.size;
-  int lq = (num - 1) <= 3 ? (num - 1) : 3;
-  StateRecorder_RecordCmd(sr, 0xc0 | (addr & 0x10000 ? 2 : 0) | lq << 2);
-  if (lq == 3)
-    ByteArray_AppendVl(&sr->log, num - 1 - 3);
-  ByteArray_AppendByte(&sr->log, addr >> 8);
-  ByteArray_AppendByte(&sr->log, addr);
-  for (int i = 0; i < num; i++)
-    ByteArray_AppendByte(&sr->log, value[i]);
-  //  while (lb < sr->log.size)
-  //    printf("%.2x ", sr->log.data[lb++]);
-  //  printf("\n");
-}
-
-void ReadFromFile(FILE *f, void *data, size_t n) {
-  if (fread(data, 1, n, f) != n)
-    Die("fread failed\n");
-}
-
-void StateRecorder_Load(StateRecorder *sr, FILE *f, bool replay_mode) {
-  // todo: fix robustness on invalid data.
-  uint32 hdr[8] = { 0 };
-  ReadFromFile(f, hdr, sizeof(hdr));
-
-  assert(hdr[0] == 1);
-
-  sr->total_frames = hdr[1];
-  ByteArray_Resize(&sr->log, hdr[2]);
-  ReadFromFile(f, sr->log.data, sr->log.size);
-  sr->last_inputs = hdr[3];
-  sr->frames_since_last = hdr[4];
-
-  ByteArray_Resize(&sr->base_snapshot, (hdr[5] & 1) ? hdr[6] : 0);
-  ReadFromFile(f, sr->base_snapshot.data, sr->base_snapshot.size);
-
-  sr->replay_next_cmd_at = 0;
-
-  sr->replay_mode = replay_mode;
-  if (replay_mode) {
-    sr->frames_since_last = 0;
-    sr->last_inputs = 0;
-    sr->replay_pos = sr->replay_pos_last_complete = 0;
-    sr->replay_frame_counter = 0;
-    // Load snapshot from |base_snapshot_|, or reset if empty.
-
-    if (sr->base_snapshot.size) {
-      LoadFuncState state = { sr->base_snapshot.data, sr->base_snapshot.data + sr->base_snapshot.size };
-      LoadSnesState(&loadFunc, &state);
-      assert(state.p == state.pend);
-    } else {
-      ZeldaReset(false);
-    }
-  } else {
-    // Resume replay from the saved position?
-    sr->replay_pos = sr->replay_pos_last_complete = hdr[5] >> 1;
-    sr->replay_frame_counter = hdr[7];
-    sr->replay_mode = (sr->replay_frame_counter != 0);
-
-    ByteArray arr = { 0 };
-    ByteArray_Resize(&arr, hdr[6]);
-    ReadFromFile(f, arr.data, arr.size);
-    LoadFuncState state = { arr.data, arr.data + arr.size };
-    LoadSnesState(&loadFunc, &state);
-    ByteArray_Destroy(&arr);
-    assert(state.p == state.pend);
-  }
-}
-
-void StateRecorder_Save(StateRecorder *sr, FILE *f) {
-  uint32 hdr[8] = { 0 };
-  ByteArray arr = { 0 };
-  SaveSnesState(&saveFunc, &arr);
-  assert(sr->base_snapshot.size == 0 || sr->base_snapshot.size == arr.size);
-
-  hdr[0] = 1;
-  hdr[1] = sr->total_frames;
-  hdr[2] = (uint32)sr->log.size;
-  hdr[3] = sr->last_inputs;
-  hdr[4] = sr->frames_since_last;
-  hdr[5] = sr->base_snapshot.size ? 1 : 0;
-  hdr[6] = (uint32)arr.size;
-  // If saving while in replay mode, also need to persist
-  // sr->replay_pos_last_complete and sr->replay_frame_counter
-  // so the replaying can be resumed.
-  if (sr->replay_mode) {
-    hdr[5] |= sr->replay_pos_last_complete << 1;
-    hdr[7] = sr->replay_frame_counter;
-  }
-  fwrite(hdr, 1, sizeof(hdr), f);
-  fwrite(sr->log.data, 1, hdr[2], f);
-  fwrite(sr->base_snapshot.data, 1, sr->base_snapshot.size, f);
-  fwrite(arr.data, 1, arr.size, f);
-
-  ByteArray_Destroy(&arr);
-}
-
-void StateRecorder_ClearKeyLog(StateRecorder *sr) {
-  printf("Clearing key log!\n");
-  sr->base_snapshot.size = 0;
-  SaveSnesState(&saveFunc, &sr->base_snapshot);
-  ByteArray old_log = sr->log;
-  int old_frames_since_last = sr->frames_since_last;
-  memset(&sr->log, 0, sizeof(sr->log));
-  // If there are currently any active inputs, record them initially at timestamp 0.
-  sr->frames_since_last = 0;
-  if (sr->last_inputs) {
-    for (int i = 0; i < 12; i++) {
-      if ((sr->last_inputs >> i) & 1)
-        StateRecorder_RecordCmd(sr, i << 4);
-    }
-  }
-  if (sr->replay_mode) {
-    // When clearing the key log while in replay mode, we want to keep
-    // replaying but discarding all key history up until this point.
-    if (sr->replay_next_cmd_at != 0xffffffff) {
-      sr->replay_next_cmd_at -= old_frames_since_last;
-      sr->frames_since_last = sr->replay_next_cmd_at;
-      sr->replay_pos_last_complete = (uint32)sr->log.size;
-      StateRecorder_RecordCmd(sr, sr->replay_cmd);
-      int old_replay_pos = sr->replay_pos;
-      sr->replay_pos = (uint32)sr->log.size;
-      ByteArray_AppendData(&sr->log, old_log.data + old_replay_pos, old_log.size - old_replay_pos);
-    }
-    sr->total_frames -= sr->replay_frame_counter;
-    sr->replay_frame_counter = 0;
-  } else {
-    sr->total_frames = 0;
-  }
-  ByteArray_Destroy(&old_log);
-  sr->frames_since_last = 0;
-}
-
-uint16 StateRecorder_ReadNextReplayState(StateRecorder *sr) {
-  assert(sr->replay_mode);
-  while (sr->frames_since_last >= sr->replay_next_cmd_at) {
-    int replay_pos = sr->replay_pos;
-    if (replay_pos != sr->replay_pos_last_complete) {
-      // Apply next command
-      sr->frames_since_last = 0;
-      if (sr->replay_cmd < 0xc0) {
-        sr->last_inputs ^= 1 << (sr->replay_cmd >> 4);
-      } else if (sr->replay_cmd < 0xd0) {
-        int nb = 1 + ((sr->replay_cmd >> 2) & 3);
-        uint8 t;
-        if (nb == 4) do {
-          nb += t = sr->log.data[replay_pos++];
-        } while (t == 255);
-        uint32 addr = ((sr->replay_cmd >> 1) & 1) << 16;
-        addr |= sr->log.data[replay_pos++] << 8;
-        addr |= sr->log.data[replay_pos++];
-        do {
-          g_ram[addr & 0x1ffff] = sr->log.data[replay_pos++];
-          EmuSyncMemoryRegion(&g_ram[addr & 0x1ffff], 1);
-        } while (addr++, --nb);
-      } else {
-        assert(0);
-      }
-    }
-    sr->replay_pos_last_complete = replay_pos;
-    if (replay_pos >= sr->log.size) {
-      sr->replay_pos = replay_pos;
-      sr->replay_next_cmd_at = 0xffffffff;
-      break;
-    }
-    // Read the next one
-    uint8 cmd = sr->log.data[replay_pos++], t;
-    int mask = (cmd < 0xc0) ? 0xf : 0x1;
-    int frames = cmd & mask;
-    if (frames == mask) do {
-      frames += t = sr->log.data[replay_pos++];
-    } while (t == 255);
-    sr->replay_next_cmd_at = frames;
-    sr->replay_cmd = cmd;
-    sr->replay_pos = replay_pos;
-  }
-  sr->frames_since_last++;
-  // Turn off replay mode after we reached the final frame position
-  if (++sr->replay_frame_counter >= sr->total_frames) {
-    sr->replay_mode = false;
-  }
-  return sr->last_inputs;
-}
-
-void StateRecorder_StopReplay(StateRecorder *sr) {
-  if (!sr->replay_mode)
-    return;
-  sr->replay_mode = false;
-  sr->total_frames = sr->replay_frame_counter;
-  sr->log.size = sr->replay_pos_last_complete;
-}
-
-#ifdef _DEBUG
-// This can be used to read inputs from a text file for easier debugging
-int InputStateReadFromFile() {
-  static FILE *f;
-  static uint32 next_ts, next_keys, cur_keys;
-  char buf[64];
-  char keys[64];
-
-  while (state_recorder.total_frames == next_ts) {
-    cur_keys = next_keys;
-    if (!f)
-      f = fopen("boss_bug.txt", "r");
-    if (fgets(buf, sizeof(buf), f)) {
-      if (sscanf(buf, "%d: %s", &next_ts, keys) == 1) keys[0] = 0;
-      int i = 0;
-      for (const char *s = keys; *s; s++) {
-        static const char kKeys[] = "AXsSUDLRBY";
-        const char *t = strchr(kKeys, *s);
-        assert(t);
-        i |= 1 << (t - kKeys);
-      }
-      next_keys = i;
-    } else {
-      next_ts = 0xffffffff;
-    }
-  }
-
-  return cur_keys;
-}
-#endif
-
-bool ZeldaRunFrame(int inputs) {
-
-  // Avoid up/down and left/right from being pressed at the same time
-  if ((inputs & 0x30) == 0x30) inputs ^= 0x30;
-  if ((inputs & 0xc0) == 0xc0) inputs ^= 0xc0;
-
-  frame_ctr_dbg++;
-
-  bool is_replay = state_recorder.replay_mode;
-
-  // Either copy state or apply state
-  if (is_replay) {
-    inputs = StateRecorder_ReadNextReplayState(&state_recorder);
-  } else {
-    //    input_state = InputStateReadFromFile();
-    StateRecorder_Record(&state_recorder, inputs);
-
-    // This is whether APUI00 is true or false, this is used by the ancilla code.
-    uint8 apui00 = ZeldaIsMusicPlaying();
-    if (apui00 != g_ram[kRam_APUI00]) {
-      g_ram[kRam_APUI00] = apui00;
-      EmuSyncMemoryRegion(&g_ram[kRam_APUI00], 1);
-      StateRecorder_RecordPatchByte(&state_recorder, 0x648, &apui00, 1);
-    }
-
-    if (animated_tile_data_src != 0) {
-      // Whenever we're no longer replaying, we'll remember what bugs were fixed,
-      // but only if game is initialized.
-      if (g_ram[kRam_BugsFixed] < kBugFix_Latest) {
-        g_ram[kRam_BugsFixed] = kBugFix_Latest;
-        EmuSyncMemoryRegion(&g_ram[kRam_BugsFixed], 1);
-        StateRecorder_RecordPatchByte(&state_recorder, kRam_BugsFixed, &g_ram[kRam_BugsFixed], 1);
-      }
-
-      if (enhanced_features0 != g_wanted_zelda_features) {
-        enhanced_features0 = g_wanted_zelda_features;
-        EmuSyncMemoryRegion(&enhanced_features0, sizeof(enhanced_features0));
-        StateRecorder_RecordPatchByte(&state_recorder, kRam_Features0, (uint8 *)&enhanced_features0, 4);
-      }
-    }
-  }
-
-  int run_what;
-  if (g_ram[kRam_BugsFixed] < kBugFix_PolyRenderer) {
-    // A previous version of this code alternated the game loop with
-    // the poly renderer.
-    run_what = (is_nmi_thread_active && thread_other_stack != 0x1f31) ? 2 : 1;
-  } else {
-    // The snes seems to let poly rendering run for a little
-    // while each fram until it eventually completes a frame.
-    // Simulate this by rendering the poly every n:th frame.
-    run_what = (is_nmi_thread_active && IncrementCrystalCountdown(&g_ram[kRam_CrystalRotateCounter], virq_trigger)) ? 3 : 1;
-    EmuSyncMemoryRegion(&g_ram[kRam_CrystalRotateCounter], 1);
-  }
-
-  if (g_emu_runframe == NULL || enhanced_features0 != 0 || g_zenv.dialogue_flags) {
-    // can't compare against real impl when running with extra features.
-    ZeldaRunFrameInternal(inputs, run_what);
-  } else {
-    g_emu_runframe(inputs, run_what);
-  }
-
-  ZeldaPushApuState();
-
-  return is_replay;
-}
-
-void ZeldaSetLanguage(const char *language) {
-  static const uint8 kDefaultConf[3] = { 0, 0, 0 };
-  MemBlk found = { kDefaultConf, 3 };
-  if (language) {
-    size_t n = strlen(language);
-    for (int i = 0; ; i++) {
-      MemBlk mb = kDialogueMap(i);
-      if (mb.ptr == 0) {
-        fprintf(stderr, "Unable to find language '%s'\n", language);
-        break;
-      }
-      MemBlk name = FindIndexInMemblk(mb, 0);
-      if (name.size == n && !memcmp(name.ptr, language, n)) {
-        found = FindIndexInMemblk(mb, 1);
-        break;
-      }
-    }
-  }
-  g_zenv.dialogue_blk = kDialogue(found.ptr[0]);
-  g_zenv.dialogue_font_blk = kDialogueFont(found.ptr[1]);
-  g_zenv.dialogue_flags = found.ptr[2];
-}
-
-
-static const char *const kReferenceSaves[] = {
-  "Chapter 1 - Zelda's Rescue.sav",
-  "Chapter 2 - After Eastern Palace.sav",
-  "Chapter 3 - After Desert Palace.sav",
-  "Chapter 4 - After Tower of Hera.sav",
-  "Chapter 5 - After Hyrule Castle Tower.sav",
-  "Chapter 6 - After Dark Palace.sav",
-  "Chapter 7 - After Swamp Palace.sav",
-  "Chapter 8 - After Skull Woods.sav",
-  "Chapter 9 - After Gargoyle's Domain.sav",
-  "Chapter 10 - After Ice Palace.sav",
-  "Chapter 11 - After Misery Mire.sav",
-  "Chapter 12 - After Turtle Rock.sav",
-  "Chapter 13 - After Ganon's Tower.sav",
-};
-
-void SaveLoadSlot(int cmd, int which) {
-  char name[128];
-  if (which & 256) {
-    if (cmd == kSaveLoad_Save)
-      return;
-    sprintf(name, "saves/ref/%s", kReferenceSaves[which - 256]);
-  } else {
-    sprintf(name, "saves/save%d.sav", which);
-  }
-  FILE *f = fopen(name, cmd != kSaveLoad_Save ? "rb" : "wb");
-  if (f) {
-    printf("*** %s slot %d\n",
-      cmd == kSaveLoad_Save ? "Saving" : cmd == kSaveLoad_Load ? "Loading" : "Replaying", which);
-
-    if (cmd != kSaveLoad_Save)
-      StateRecorder_Load(&state_recorder, f, cmd == kSaveLoad_Replay);
-    else
-      StateRecorder_Save(&state_recorder, f);
-
-    fclose(f);
-  }
-}
-
-typedef struct StateRecoderMultiPatch {
-  uint32 count;
-  uint32 addr;
-  uint8 vals[256];
-} StateRecoderMultiPatch;
-
-
-void StateRecoderMultiPatch_Init(StateRecoderMultiPatch *mp) {
-  mp->count = mp->addr = 0;
-}
-
-void StateRecoderMultiPatch_Commit(StateRecoderMultiPatch *mp) {
-  if (mp->count)
-    StateRecorder_RecordPatchByte(&state_recorder, mp->addr, mp->vals, mp->count);
-}
-
-void StateRecoderMultiPatch_Patch(StateRecoderMultiPatch *mp, uint32 addr, uint8 value) {
-  if (mp->count >= 256 || addr != mp->addr + mp->count) {
-    StateRecoderMultiPatch_Commit(mp);
-    mp->addr = addr;
-    mp->count = 0;
-  }
-  mp->vals[mp->count++] = value;
-  g_ram[addr] = value;
-  EmuSyncMemoryRegion(&g_ram[addr], 1);
-}
-
-void PatchCommand(char c) {
-  StateRecoderMultiPatch mp;
-
-  StateRecoderMultiPatch_Init(&mp);
-  if (c == 'w') {
-    StateRecoderMultiPatch_Patch(&mp, 0xf372, 80);  // health filler
-    StateRecoderMultiPatch_Patch(&mp, 0xf373, 80);  // magic filler
-    //    b.Patch(0x1FE01, 25);
-  } else if (c == 'W') {
-    StateRecoderMultiPatch_Patch(&mp, 0xf375, 10);  // link_bomb_filler
-    StateRecoderMultiPatch_Patch(&mp, 0xf376, 10);  // link_arrow_filler
-    uint16 rupees = link_rupees_goal + 100;
-    StateRecoderMultiPatch_Patch(&mp, 0xf360, rupees);  // link_rupees_goal
-    StateRecoderMultiPatch_Patch(&mp, 0xf361, rupees >> 8);  // link_rupees_goal
-  } else if (c == 'k') {
-    StateRecorder_ClearKeyLog(&state_recorder);
-  } else if (c == 'o') {
-    StateRecoderMultiPatch_Patch(&mp, 0xf36f, 1);
-  } else if (c == 'l') {
-    StateRecorder_StopReplay(&state_recorder);
-  } else if (c == 'E') {
-    StateRecoderMultiPatch_Patch(&mp, 0x37f, g_ram[0x37f] ^ 1);
-  }
-  StateRecoderMultiPatch_Commit(&mp);
-}
-
-
-void ZeldaReadSram() {
-  FILE *f = fopen("saves/sram.dat", "rb");
-  if (f) {
-    if (fread(g_zenv.sram, 1, 8192, f) != 8192)
-      fprintf(stderr, "Error reading saves/sram.dat\n");
-    fclose(f);
-    EmuSynchronizeWholeState();
-  }
-}
-
-void ZeldaWriteSram() {
-  rename("saves/sram.dat", "saves/sram.bak");
-  FILE *f = fopen("saves/sram.dat", "wb");
-  if (f) {
-    fwrite(g_zenv.sram, 1, 8192, f);
-    fclose(f);
-  } else {
-    fprintf(stderr, "Unable to write saves/sram.dat\n");
-  }
-}
\ No newline at end of file
--- a/zelda_rtl.h
+++ /dev/null
@@ -1,97 +1,0 @@
-// This file defines various things related to the runtime environment
-// of the code
-#ifndef ZELDA3_ZELDA_RTL_H_
-#define ZELDA3_ZELDA_RTL_H_
-
-#include <stdio.h>
-#include <string.h>
-#include <stdbool.h>
-#include <assert.h>
-
-#include "types.h"
-#include "features.h"
-
-struct Snes;
-struct Dsp;
-
-typedef struct ZeldaEnv {
-  uint8 *ram;
-  uint8 *sram;
-  uint16 *vram;
-  struct Ppu *ppu;
-  struct SpcPlayer *player;
-  struct Dma *dma;
-  
-  MemBlk dialogue_blk;
-  MemBlk dialogue_font_blk;
-  uint8 dialogue_flags;
-} ZeldaEnv;
-extern ZeldaEnv g_zenv;
-extern int frame_ctr_dbg;
-
-typedef void PlayerHandlerFunc();
-typedef void HandlerFuncK(int k);
-
-static inline void zelda_snes_dummy_write(uint32 adr, uint8 val) {}
-
-void zelda_apu_write(uint32_t adr, uint8_t val);
-uint8_t zelda_read_apui00();
-uint8_t zelda_apu_read(uint32_t adr);
-void zelda_ppu_write(uint32_t adr, uint8_t val);
-void zelda_ppu_write_word(uint32_t adr, uint16_t val);
-
-
-// 512x480 32-bit pixels. Returns true if we instead draw 1024x960
-void HdmaSetup(uint32 addr6, uint32 addr7, uint8 transfer_unit, uint8 reg6, uint8 reg7, uint8 indirect_bank);
-
-void ZeldaInitialize();
-void ZeldaReset(bool preserve_sram);
-void ZeldaDrawPpuFrame(uint8 *pixel_buffer, size_t pitch, uint32 render_flags);
-void ZeldaRunFrameInternal(uint16 input, int run_what);
-bool ZeldaRunFrame(int input_state);
-void LoadSongBank(const uint8 *p);
-void ZeldaApuLock();
-void ZeldaApuUnlock();
-bool ZeldaIsPlayingMusicTrack(uint8 track);
-uint8 ZeldaGetEntranceMusicTrack(int track);
-void ZeldaSetLanguage(const char *language);
-void PatchCommand(char cmd);
-
-// Things for state management
-
-enum {
-  kSaveLoad_Save = 0,
-  kSaveLoad_Load = 1,
-  kSaveLoad_Replay = 2,
-};
-
-void SaveLoadSlot(int cmd, int which);
-void ZeldaWriteSram();
-void ZeldaReadSram();
-
-typedef void ZeldaRunFrameFunc(uint16 input, int run_what);
-typedef void ZeldaSyncAllFunc();
-
-void ZeldaSetupEmuCallbacks(uint8 *emu_ram, ZeldaRunFrameFunc *func, ZeldaSyncAllFunc *sync_all);
-
-// Button definitions, zelda splits them in separate 8-bit high/low
-enum {
-  kJoypadL_A = 0x80,
-  kJoypadL_X = 0x40,
-  kJoypadL_L = 0x20,
-  kJoypadL_R = 0x10,
-
-  kJoypadH_B = 0x80,
-  kJoypadH_Y = 0x40,
-  kJoypadH_Select = 0x20,
-  kJoypadH_Start = 0x10,
-
-  kJoypadH_Up = 0x8,
-  kJoypadH_Down = 0x4,
-  kJoypadH_Left = 0x2,
-  kJoypadH_Right = 0x1,
-
-  kJoypadH_AnyDir = 0xf,
-};
-
-#endif  // ZELDA3_ZELDA_RTL_H_